From 2e5140d67b58ffd7220e4417ccafe06bc812ff47 Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Wed, 12 Aug 2020 15:31:44 -0400 Subject: [PATCH 01/53] [Dashboard First] Decouple Attribute Service and By Value Embeddables (#74302) * Added an interface that determines if an embeddable can be treated as either by reference or by value --- examples/embeddable_examples/kibana.json | 2 +- .../book/add_book_to_library_action.tsx | 55 ++++++ .../public/book/book_component.tsx | 32 +++- .../public/book/book_embeddable.tsx | 22 ++- .../public/book/book_embeddable_factory.tsx | 17 +- .../public/book/edit_book_action.tsx | 9 +- .../book/unlink_book_from_library_action.tsx | 55 ++++++ examples/embeddable_examples/public/plugin.ts | 24 ++- .../attribute_service/attribute_service.tsx | 156 ++++++++++++++++++ src/plugins/dashboard/public/index.ts | 1 + src/plugins/dashboard/public/plugin.tsx | 23 ++- src/plugins/embeddable/public/index.ts | 3 +- .../lib/embeddables/attribute_service.ts | 68 -------- .../public/lib/embeddables/index.ts | 1 - src/plugins/embeddable/public/lib/index.ts | 1 + .../reference_or_value_embeddable/index.ts | 20 +++ .../reference_or_value_embeddable/types.ts | 56 +++++++ src/plugins/embeddable/public/mocks.tsx | 1 - src/plugins/embeddable/public/plugin.tsx | 11 -- 19 files changed, 453 insertions(+), 104 deletions(-) create mode 100644 examples/embeddable_examples/public/book/add_book_to_library_action.tsx create mode 100644 examples/embeddable_examples/public/book/unlink_book_from_library_action.tsx create mode 100644 src/plugins/dashboard/public/attribute_service/attribute_service.tsx delete mode 100644 src/plugins/embeddable/public/lib/embeddables/attribute_service.ts create mode 100644 src/plugins/embeddable/public/lib/reference_or_value_embeddable/index.ts create mode 100644 src/plugins/embeddable/public/lib/reference_or_value_embeddable/types.ts diff --git a/examples/embeddable_examples/kibana.json b/examples/embeddable_examples/kibana.json index 771c19cfdbd3d..0ac40ae1889de 100644 --- a/examples/embeddable_examples/kibana.json +++ b/examples/embeddable_examples/kibana.json @@ -4,7 +4,7 @@ "kibanaVersion": "kibana", "server": true, "ui": true, - "requiredPlugins": ["embeddable", "uiActions"], + "requiredPlugins": ["embeddable", "uiActions", "dashboard"], "optionalPlugins": [], "extraPublicDirs": ["public/todo", "public/hello_world", "public/todo/todo_ref_embeddable"], "requiredBundles": ["kibanaReact"] diff --git a/examples/embeddable_examples/public/book/add_book_to_library_action.tsx b/examples/embeddable_examples/public/book/add_book_to_library_action.tsx new file mode 100644 index 0000000000000..b74a1d5642982 --- /dev/null +++ b/examples/embeddable_examples/public/book/add_book_to_library_action.tsx @@ -0,0 +1,55 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { createAction, IncompatibleActionError } from '../../../../src/plugins/ui_actions/public'; +import { BookEmbeddable, BOOK_EMBEDDABLE } from './book_embeddable'; +import { ViewMode, isReferenceOrValueEmbeddable } from '../../../../src/plugins/embeddable/public'; + +interface ActionContext { + embeddable: BookEmbeddable; +} + +export const ACTION_ADD_BOOK_TO_LIBRARY = 'ACTION_ADD_BOOK_TO_LIBRARY'; + +export const createAddBookToLibraryAction = () => + createAction({ + getDisplayName: () => + i18n.translate('embeddableExamples.book.addToLibrary', { + defaultMessage: 'Add Book To Library', + }), + type: ACTION_ADD_BOOK_TO_LIBRARY, + order: 100, + getIconType: () => 'folderCheck', + isCompatible: async ({ embeddable }: ActionContext) => { + return ( + embeddable.type === BOOK_EMBEDDABLE && + embeddable.getInput().viewMode === ViewMode.EDIT && + isReferenceOrValueEmbeddable(embeddable) && + !embeddable.inputIsRefType(embeddable.getInput()) + ); + }, + execute: async ({ embeddable }: ActionContext) => { + if (!isReferenceOrValueEmbeddable(embeddable)) { + throw new IncompatibleActionError(); + } + const newInput = await embeddable.getInputAsRefType(); + embeddable.updateInput(newInput); + }, + }); diff --git a/examples/embeddable_examples/public/book/book_component.tsx b/examples/embeddable_examples/public/book/book_component.tsx index 064e13c131a0a..e46487641b913 100644 --- a/examples/embeddable_examples/public/book/book_component.tsx +++ b/examples/embeddable_examples/public/book/book_component.tsx @@ -20,7 +20,7 @@ import React from 'react'; import { EuiFlexItem, EuiFlexGroup, EuiIcon } from '@elastic/eui'; import { EuiText } from '@elastic/eui'; -import { EuiFlexGrid } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { withEmbeddableSubscription } from '../../../../src/plugins/embeddable/public'; import { BookEmbeddableInput, BookEmbeddableOutput, BookEmbeddable } from './book_embeddable'; @@ -44,26 +44,32 @@ function wrapSearchTerms(task?: string, search?: string) { ); } -export function BookEmbeddableComponentInner({ input: { search }, output: { attributes } }: Props) { +export function BookEmbeddableComponentInner({ + input: { search }, + output: { attributes }, + embeddable, +}: Props) { const title = attributes?.title; const author = attributes?.author; const readIt = attributes?.readIt; + const byReference = embeddable.inputIsRefType(embeddable.getInput()); + return ( - + {title ? ( -

{wrapSearchTerms(title, search)},

+

{wrapSearchTerms(title, search)}

) : null} {author ? ( -
-{wrapSearchTerms(author, search)}
+ -{wrapSearchTerms(author, search)}
) : null} @@ -76,7 +82,21 @@ export function BookEmbeddableComponentInner({ input: { search }, output: { attr
)} - +
+ + + + {' '} + + {byReference + ? i18n.translate('embeddableExamples.book.byReferenceLabel', { + defaultMessage: 'Book is By Reference', + }) + : i18n.translate('embeddableExamples.book.byValueLabel', { + defaultMessage: 'Book is By Value', + })} + + ); diff --git a/examples/embeddable_examples/public/book/book_embeddable.tsx b/examples/embeddable_examples/public/book/book_embeddable.tsx index d49bd3280d97d..dd9418c0e8596 100644 --- a/examples/embeddable_examples/public/book/book_embeddable.tsx +++ b/examples/embeddable_examples/public/book/book_embeddable.tsx @@ -25,10 +25,11 @@ import { IContainer, EmbeddableOutput, SavedObjectEmbeddableInput, - AttributeService, + ReferenceOrValueEmbeddable, } from '../../../../src/plugins/embeddable/public'; import { BookSavedObjectAttributes } from '../../common'; import { BookEmbeddableComponent } from './book_component'; +import { AttributeService } from '../../../../src/plugins/dashboard/public'; export const BOOK_EMBEDDABLE = 'book'; export type BookEmbeddableInput = BookByValueInput | BookByReferenceInput; @@ -59,7 +60,8 @@ function getHasMatch(search?: string, savedAttributes?: BookSavedObjectAttribute ); } -export class BookEmbeddable extends Embeddable { +export class BookEmbeddable extends Embeddable + implements ReferenceOrValueEmbeddable { public readonly type = BOOK_EMBEDDABLE; private subscription: Subscription; private node?: HTMLElement; @@ -96,6 +98,18 @@ export class BookEmbeddable extends Embeddable { + return this.attributeService.inputIsRefType(input); + }; + + getInputAsValueType = async (): Promise => { + return this.attributeService.getInputAsValueType(this.input); + }; + + getInputAsRefType = async (): Promise => { + return this.attributeService.getInputAsRefType(this.input, { showSaveModal: true }); + }; + public render(node: HTMLElement) { if (this.node) { ReactDOM.unmountComponentAtNode(this.node); @@ -113,6 +127,10 @@ export class BookEmbeddable extends Embeddable(this.type); } - return this.attributeService; + return this.attributeService!; } } diff --git a/examples/embeddable_examples/public/book/edit_book_action.tsx b/examples/embeddable_examples/public/book/edit_book_action.tsx index 222f70e0be60f..b31d69696598e 100644 --- a/examples/embeddable_examples/public/book/edit_book_action.tsx +++ b/examples/embeddable_examples/public/book/edit_book_action.tsx @@ -22,11 +22,7 @@ import { i18n } from '@kbn/i18n'; import { BookSavedObjectAttributes, BOOK_SAVED_OBJECT } from '../../common'; import { createAction } from '../../../../src/plugins/ui_actions/public'; import { toMountPoint } from '../../../../src/plugins/kibana_react/public'; -import { - ViewMode, - EmbeddableStart, - SavedObjectEmbeddableInput, -} from '../../../../src/plugins/embeddable/public'; +import { ViewMode, SavedObjectEmbeddableInput } from '../../../../src/plugins/embeddable/public'; import { BookEmbeddable, BOOK_EMBEDDABLE, @@ -34,10 +30,11 @@ import { BookByValueInput, } from './book_embeddable'; import { CreateEditBookComponent } from './create_edit_book_component'; +import { DashboardStart } from '../../../../src/plugins/dashboard/public'; interface StartServices { openModal: OverlayStart['openModal']; - getAttributeService: EmbeddableStart['getAttributeService']; + getAttributeService: DashboardStart['getAttributeService']; } interface ActionContext { diff --git a/examples/embeddable_examples/public/book/unlink_book_from_library_action.tsx b/examples/embeddable_examples/public/book/unlink_book_from_library_action.tsx new file mode 100644 index 0000000000000..cef77092a642a --- /dev/null +++ b/examples/embeddable_examples/public/book/unlink_book_from_library_action.tsx @@ -0,0 +1,55 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { createAction, IncompatibleActionError } from '../../../../src/plugins/ui_actions/public'; +import { BookEmbeddable, BOOK_EMBEDDABLE } from './book_embeddable'; +import { ViewMode, isReferenceOrValueEmbeddable } from '../../../../src/plugins/embeddable/public'; + +interface ActionContext { + embeddable: BookEmbeddable; +} + +export const ACTION_UNLINK_BOOK_FROM_LIBRARY = 'ACTION_UNLINK_BOOK_FROM_LIBRARY'; + +export const createUnlinkBookFromLibraryAction = () => + createAction({ + getDisplayName: () => + i18n.translate('embeddableExamples.book.unlinkFromLibrary', { + defaultMessage: 'Unlink Book from Library Item', + }), + type: ACTION_UNLINK_BOOK_FROM_LIBRARY, + order: 100, + getIconType: () => 'folderExclamation', + isCompatible: async ({ embeddable }: ActionContext) => { + return ( + embeddable.type === BOOK_EMBEDDABLE && + embeddable.getInput().viewMode === ViewMode.EDIT && + isReferenceOrValueEmbeddable(embeddable) && + embeddable.inputIsRefType(embeddable.getInput()) + ); + }, + execute: async ({ embeddable }: ActionContext) => { + if (!isReferenceOrValueEmbeddable(embeddable)) { + throw new IncompatibleActionError(); + } + const newInput = await embeddable.getInputAsValueType(); + embeddable.updateInput(newInput); + }, + }); diff --git a/examples/embeddable_examples/public/plugin.ts b/examples/embeddable_examples/public/plugin.ts index 95f4f5b41e198..0c6ed1eb3be48 100644 --- a/examples/embeddable_examples/public/plugin.ts +++ b/examples/embeddable_examples/public/plugin.ts @@ -58,6 +58,15 @@ import { BookEmbeddableFactoryDefinition, } from './book/book_embeddable_factory'; import { UiActionsStart } from '../../../src/plugins/ui_actions/public'; +import { + ACTION_ADD_BOOK_TO_LIBRARY, + createAddBookToLibraryAction, +} from './book/add_book_to_library_action'; +import { DashboardStart } from '../../../src/plugins/dashboard/public'; +import { + ACTION_UNLINK_BOOK_FROM_LIBRARY, + createUnlinkBookFromLibraryAction, +} from './book/unlink_book_from_library_action'; export interface EmbeddableExamplesSetupDependencies { embeddable: EmbeddableSetup; @@ -66,6 +75,7 @@ export interface EmbeddableExamplesSetupDependencies { export interface EmbeddableExamplesStartDependencies { embeddable: EmbeddableStart; + dashboard: DashboardStart; } interface ExampleEmbeddableFactories { @@ -86,6 +96,8 @@ export interface EmbeddableExamplesStart { declare module '../../../src/plugins/ui_actions/public' { export interface ActionContextMapping { [ACTION_EDIT_BOOK]: { embeddable: BookEmbeddable }; + [ACTION_ADD_BOOK_TO_LIBRARY]: { embeddable: BookEmbeddable }; + [ACTION_UNLINK_BOOK_FROM_LIBRARY]: { embeddable: BookEmbeddable }; } } @@ -144,17 +156,25 @@ export class EmbeddableExamplesPlugin this.exampleEmbeddableFactories.getBookEmbeddableFactory = deps.embeddable.registerEmbeddableFactory( BOOK_EMBEDDABLE, new BookEmbeddableFactoryDefinition(async () => ({ - getAttributeService: (await core.getStartServices())[1].embeddable.getAttributeService, + getAttributeService: (await core.getStartServices())[1].dashboard.getAttributeService, openModal: (await core.getStartServices())[0].overlays.openModal, })) ); const editBookAction = createEditBookAction(async () => ({ - getAttributeService: (await core.getStartServices())[1].embeddable.getAttributeService, + getAttributeService: (await core.getStartServices())[1].dashboard.getAttributeService, openModal: (await core.getStartServices())[0].overlays.openModal, })); deps.uiActions.registerAction(editBookAction); deps.uiActions.attachAction(CONTEXT_MENU_TRIGGER, editBookAction.id); + + const addBookToLibraryAction = createAddBookToLibraryAction(); + deps.uiActions.registerAction(addBookToLibraryAction); + deps.uiActions.attachAction(CONTEXT_MENU_TRIGGER, addBookToLibraryAction.id); + + const unlinkBookFromLibraryAction = createUnlinkBookFromLibraryAction(); + deps.uiActions.registerAction(unlinkBookFromLibraryAction); + deps.uiActions.attachAction(CONTEXT_MENU_TRIGGER, unlinkBookFromLibraryAction.id); } public start( diff --git a/src/plugins/dashboard/public/attribute_service/attribute_service.tsx b/src/plugins/dashboard/public/attribute_service/attribute_service.tsx new file mode 100644 index 0000000000000..c2f529fe399f3 --- /dev/null +++ b/src/plugins/dashboard/public/attribute_service/attribute_service.tsx @@ -0,0 +1,156 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { + EmbeddableInput, + SavedObjectEmbeddableInput, + isSavedObjectEmbeddableInput, + IEmbeddable, +} from '../embeddable_plugin'; +import { + SavedObjectsClientContract, + SimpleSavedObject, + I18nStart, + NotificationsStart, +} from '../../../../core/public'; +import { + SavedObjectSaveModal, + showSaveModal, + OnSaveProps, + SaveResult, +} from '../../../saved_objects/public'; + +/** + * The attribute service is a shared, generic service that embeddables can use to provide the functionality + * required to fulfill the requirements of the ReferenceOrValueEmbeddable interface. The attribute_service + * can also be used as a higher level wrapper to transform an embeddable input shape that references a saved object + * into an embeddable input shape that contains that saved object's attributes by value. + */ +export class AttributeService< + SavedObjectAttributes extends { title: string }, + ValType extends EmbeddableInput & { attributes: SavedObjectAttributes }, + RefType extends SavedObjectEmbeddableInput +> { + constructor( + private type: string, + private savedObjectsClient: SavedObjectsClientContract, + private i18nContext: I18nStart['Context'], + private toasts: NotificationsStart['toasts'] + ) {} + + public async unwrapAttributes(input: RefType | ValType): Promise { + if (this.inputIsRefType(input)) { + const savedObject: SimpleSavedObject = await this.savedObjectsClient.get< + SavedObjectAttributes + >(this.type, input.savedObjectId); + return savedObject.attributes; + } + return input.attributes; + } + + public async wrapAttributes( + newAttributes: SavedObjectAttributes, + useRefType: boolean, + embeddable?: IEmbeddable + ): Promise> { + const savedObjectId = + embeddable && isSavedObjectEmbeddableInput(embeddable.getInput()) + ? (embeddable.getInput() as SavedObjectEmbeddableInput).savedObjectId + : undefined; + if (!useRefType) { + return { attributes: newAttributes } as ValType; + } else { + try { + if (savedObjectId) { + await this.savedObjectsClient.update(this.type, savedObjectId, newAttributes); + return { savedObjectId } as RefType; + } else { + const savedItem = await this.savedObjectsClient.create(this.type, newAttributes); + return { savedObjectId: savedItem.id } as RefType; + } + } catch (error) { + this.toasts.addDanger({ + title: i18n.translate('dashboard.attributeService.saveToLibraryError', { + defaultMessage: `Panel was not saved to the library. Error: {errorMessage}`, + values: { + errorMessage: error.message, + }, + }), + 'data-test-subj': 'saveDashboardFailure', + }); + return Promise.reject({ error }); + } + } + } + + inputIsRefType = (input: ValType | RefType): input is RefType => { + return isSavedObjectEmbeddableInput(input); + }; + + getInputAsValueType = async (input: ValType | RefType): Promise => { + if (!this.inputIsRefType(input)) { + return input; + } + const attributes = await this.unwrapAttributes(input); + return { + ...input, + savedObjectId: undefined, + attributes, + }; + }; + + getInputAsRefType = async ( + input: ValType | RefType, + saveOptions?: { showSaveModal: boolean } | { title: string } + ): Promise => { + if (this.inputIsRefType(input)) { + return input; + } + + return new Promise((resolve, reject) => { + const onSave = async (props: OnSaveProps): Promise => { + try { + input.attributes.title = props.newTitle; + const wrappedInput = (await this.wrapAttributes(input.attributes, true)) as RefType; + resolve(wrappedInput); + return { id: wrappedInput.savedObjectId }; + } catch (error) { + reject(); + return { error }; + } + }; + + if (saveOptions && (saveOptions as { showSaveModal: boolean }).showSaveModal) { + showSaveModal( + reject()} + title={input.attributes.title} + showCopyOnSave={false} + objectType={this.type} + showDescription={false} + />, + this.i18nContext + ); + } + }); + }; +} diff --git a/src/plugins/dashboard/public/index.ts b/src/plugins/dashboard/public/index.ts index dcfde67cd9f13..8a9954cc77a2e 100644 --- a/src/plugins/dashboard/public/index.ts +++ b/src/plugins/dashboard/public/index.ts @@ -40,6 +40,7 @@ export { export { addEmbeddableToDashboardUrl } from './url_utils/url_helper'; export { SavedObjectDashboard } from './saved_dashboards'; export { SavedDashboardPanel } from './types'; +export { AttributeService } from './attribute_service/attribute_service'; export function plugin(initializerContext: PluginInitializerContext) { return new DashboardPlugin(initializerContext); diff --git a/src/plugins/dashboard/public/plugin.tsx b/src/plugins/dashboard/public/plugin.tsx index f1319665d258b..3b0863a9f4651 100644 --- a/src/plugins/dashboard/public/plugin.tsx +++ b/src/plugins/dashboard/public/plugin.tsx @@ -34,7 +34,13 @@ import { ScopedHistory, } from 'src/core/public'; import { UsageCollectionSetup } from '../../usage_collection/public'; -import { CONTEXT_MENU_TRIGGER, EmbeddableSetup, EmbeddableStart } from '../../embeddable/public'; +import { + CONTEXT_MENU_TRIGGER, + EmbeddableSetup, + EmbeddableStart, + SavedObjectEmbeddableInput, + EmbeddableInput, +} from '../../embeddable/public'; import { DataPublicPluginSetup, DataPublicPluginStart, esFilters } from '../../data/public'; import { SharePluginSetup, SharePluginStart, UrlGeneratorContract } from '../../share/public'; import { UiActionsSetup, UiActionsStart } from '../../ui_actions/public'; @@ -85,6 +91,7 @@ import { DashboardConstants } from './dashboard_constants'; import { addEmbeddableToDashboardUrl } from './url_utils/url_helper'; import { PlaceholderEmbeddableFactory } from './application/embeddable/placeholder'; import { UrlGeneratorState } from '../../share/public'; +import { AttributeService } from '.'; declare module '../../share/public' { export interface UrlGeneratorStateMapping { @@ -131,6 +138,13 @@ export interface DashboardStart { dashboardUrlGenerator?: DashboardUrlGenerator; dashboardFeatureFlagConfig: DashboardFeatureFlagConfig; DashboardContainerByValueRenderer: ReturnType; + getAttributeService: < + A extends { title: string }, + V extends EmbeddableInput & { attributes: A }, + R extends SavedObjectEmbeddableInput + >( + type: string + ) => AttributeService; } declare module '../../../plugins/ui_actions/public' { @@ -420,6 +434,13 @@ export class DashboardPlugin DashboardContainerByValueRenderer: createDashboardContainerByValueRenderer({ factory: dashboardContainerFactory, }), + getAttributeService: (type: string) => + new AttributeService( + type, + core.savedObjects.client, + core.i18n.Context, + core.notifications.toasts + ), }; } diff --git a/src/plugins/embeddable/public/index.ts b/src/plugins/embeddable/public/index.ts index fafbdda148de8..57253c1f741ab 100644 --- a/src/plugins/embeddable/public/index.ts +++ b/src/plugins/embeddable/public/index.ts @@ -28,7 +28,8 @@ export { ACTION_EDIT_PANEL, Adapters, AddPanelAction, - AttributeService, + ReferenceOrValueEmbeddable, + isReferenceOrValueEmbeddable, ChartActionContext, Container, ContainerInput, diff --git a/src/plugins/embeddable/public/lib/embeddables/attribute_service.ts b/src/plugins/embeddable/public/lib/embeddables/attribute_service.ts deleted file mode 100644 index a33f592350d9a..0000000000000 --- a/src/plugins/embeddable/public/lib/embeddables/attribute_service.ts +++ /dev/null @@ -1,68 +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 { SavedObjectsClientContract } from '../../../../../core/public'; -import { - SavedObjectEmbeddableInput, - isSavedObjectEmbeddableInput, - EmbeddableInput, - IEmbeddable, -} from '.'; -import { SimpleSavedObject } from '../../../../../core/public'; - -export class AttributeService< - SavedObjectAttributes, - ValType extends EmbeddableInput & { attributes: SavedObjectAttributes }, - RefType extends SavedObjectEmbeddableInput -> { - constructor(private type: string, private savedObjectsClient: SavedObjectsClientContract) {} - - public async unwrapAttributes(input: RefType | ValType): Promise { - if (isSavedObjectEmbeddableInput(input)) { - const savedObject: SimpleSavedObject = await this.savedObjectsClient.get< - SavedObjectAttributes - >(this.type, input.savedObjectId); - return savedObject.attributes; - } - return input.attributes; - } - - public async wrapAttributes( - newAttributes: SavedObjectAttributes, - useRefType: boolean, - embeddable?: IEmbeddable - ): Promise> { - const savedObjectId = - embeddable && isSavedObjectEmbeddableInput(embeddable.getInput()) - ? (embeddable.getInput() as SavedObjectEmbeddableInput).savedObjectId - : undefined; - - if (useRefType) { - if (savedObjectId) { - await this.savedObjectsClient.update(this.type, savedObjectId, newAttributes); - return { savedObjectId } as RefType; - } else { - const savedItem = await this.savedObjectsClient.create(this.type, newAttributes); - return { savedObjectId: savedItem.id } as RefType; - } - } else { - return { attributes: newAttributes } as ValType; - } - } -} diff --git a/src/plugins/embeddable/public/lib/embeddables/index.ts b/src/plugins/embeddable/public/lib/embeddables/index.ts index 06cb6e322acf3..5bab5ac27f3cc 100644 --- a/src/plugins/embeddable/public/lib/embeddables/index.ts +++ b/src/plugins/embeddable/public/lib/embeddables/index.ts @@ -25,5 +25,4 @@ export { ErrorEmbeddable, isErrorEmbeddable } from './error_embeddable'; export { withEmbeddableSubscription } from './with_subscription'; export { EmbeddableRoot } from './embeddable_root'; export * from './saved_object_embeddable'; -export { AttributeService } from './attribute_service'; export { EmbeddableRenderer, EmbeddableRendererProps } from './embeddable_renderer'; diff --git a/src/plugins/embeddable/public/lib/index.ts b/src/plugins/embeddable/public/lib/index.ts index b757fa59a7f3a..aef4c33ee1078 100644 --- a/src/plugins/embeddable/public/lib/index.ts +++ b/src/plugins/embeddable/public/lib/index.ts @@ -25,3 +25,4 @@ export * from './triggers'; export * from './containers'; export * from './panel'; export * from './state_transfer'; +export * from './reference_or_value_embeddable'; diff --git a/src/plugins/embeddable/public/lib/reference_or_value_embeddable/index.ts b/src/plugins/embeddable/public/lib/reference_or_value_embeddable/index.ts new file mode 100644 index 0000000000000..e9b8521a35ba5 --- /dev/null +++ b/src/plugins/embeddable/public/lib/reference_or_value_embeddable/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 { ReferenceOrValueEmbeddable, isReferenceOrValueEmbeddable } from './types'; diff --git a/src/plugins/embeddable/public/lib/reference_or_value_embeddable/types.ts b/src/plugins/embeddable/public/lib/reference_or_value_embeddable/types.ts new file mode 100644 index 0000000000000..eaf5c94a09138 --- /dev/null +++ b/src/plugins/embeddable/public/lib/reference_or_value_embeddable/types.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 { EmbeddableInput, SavedObjectEmbeddableInput } from '..'; + +/** + * Any embeddable that implements this interface will be able to use input that is + * either by reference (backed by a saved object) OR by value, (provided + * by the container). + * @public + */ +export interface ReferenceOrValueEmbeddable< + ValTypeInput extends EmbeddableInput = EmbeddableInput, + RefTypeInput extends SavedObjectEmbeddableInput = SavedObjectEmbeddableInput +> { + /** + * determines whether the input is by value or by reference. + */ + inputIsRefType: (input: ValTypeInput | RefTypeInput) => input is RefTypeInput; + + /** + * Gets the embeddable's current input as its Value type + */ + getInputAsValueType: () => Promise; + + /** + * Gets the embeddable's current input as its Reference type + */ + getInputAsRefType: () => Promise; +} + +export function isReferenceOrValueEmbeddable( + incoming: unknown +): incoming is ReferenceOrValueEmbeddable { + return ( + !!(incoming as ReferenceOrValueEmbeddable).inputIsRefType && + !!(incoming as ReferenceOrValueEmbeddable).getInputAsValueType && + !!(incoming as ReferenceOrValueEmbeddable).getInputAsRefType + ); +} diff --git a/src/plugins/embeddable/public/mocks.tsx b/src/plugins/embeddable/public/mocks.tsx index 94aa980e446ca..fa79af909a427 100644 --- a/src/plugins/embeddable/public/mocks.tsx +++ b/src/plugins/embeddable/public/mocks.tsx @@ -97,7 +97,6 @@ const createStartContract = (): Start => { getEmbeddableFactories: jest.fn(), getEmbeddableFactory: jest.fn(), EmbeddablePanel: jest.fn(), - getAttributeService: jest.fn(), getEmbeddablePanel: jest.fn(), getStateTransfer: jest.fn(() => createEmbeddableStateTransferMock() as EmbeddableStateTransfer), }; diff --git a/src/plugins/embeddable/public/plugin.tsx b/src/plugins/embeddable/public/plugin.tsx index 319cbf8ec44b4..3cbd49279564f 100644 --- a/src/plugins/embeddable/public/plugin.tsx +++ b/src/plugins/embeddable/public/plugin.tsx @@ -37,10 +37,8 @@ import { defaultEmbeddableFactoryProvider, IEmbeddable, EmbeddablePanel, - SavedObjectEmbeddableInput, } from './lib'; import { EmbeddableFactoryDefinition } from './lib/embeddables/embeddable_factory_definition'; -import { AttributeService } from './lib/embeddables/attribute_service'; import { EmbeddableStateTransfer } from './lib/state_transfer'; export interface EmbeddableSetupDependencies { @@ -75,14 +73,6 @@ export interface EmbeddableStart { embeddableFactoryId: string ) => EmbeddableFactory | undefined; getEmbeddableFactories: () => IterableIterator; - getAttributeService: < - A, - V extends EmbeddableInput & { attributes: A }, - R extends SavedObjectEmbeddableInput - >( - type: string - ) => AttributeService; - EmbeddablePanel: EmbeddablePanelHOC; getEmbeddablePanel: (stateTransfer?: EmbeddableStateTransfer) => EmbeddablePanelHOC; getStateTransfer: (history?: ScopedHistory) => EmbeddableStateTransfer; @@ -159,7 +149,6 @@ export class EmbeddablePublicPlugin implements Plugin new AttributeService(type, core.savedObjects.client), getStateTransfer: (history?: ScopedHistory) => { return history ? new EmbeddableStateTransfer(core.application.navigateToApp, history) From c97916ea81c47cf33b58c2c2dcce6912a86c1de6 Mon Sep 17 00:00:00 2001 From: Spencer Date: Wed, 12 Aug 2020 12:45:49 -0700 Subject: [PATCH 02/53] [babel] coalese some versions to prevent breaking yarn install (#74864) Co-authored-by: spalger Co-authored-by: Elastic Machine --- packages/kbn-pm/dist/index.js | 4 +- yarn.lock | 987 ++-------------------------------- 2 files changed, 53 insertions(+), 938 deletions(-) diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index ee141e1d8ab7a..9427cc57805e6 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -15108,7 +15108,7 @@ function getMarkerLines(loc, source, opts) { column: 0, line: -1 }, loc.start); - const endLoc = Object.assign({}, startLoc, {}, loc.end); + const endLoc = Object.assign({}, startLoc, loc.end); const { linesAbove = 2, linesBelow = 3 @@ -15530,7 +15530,7 @@ function isIdentifierName(name) { } } - return true; + return !isFirst; } /***/ }), diff --git a/yarn.lock b/yarn.lock index 7731d2f7a8ea1..4eac262ddfd2f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -25,14 +25,7 @@ dependencies: "@babel/highlight" "^7.0.0" -"@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.8.3" - -"@babel/code-frame@^7.10.4": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== @@ -48,38 +41,7 @@ invariant "^2.2.4" semver "^5.5.0" -"@babel/compat-data@^7.8.6", "@babel/compat-data@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.9.0.tgz#04815556fc90b0c174abd2c0c1bb966faa036a6c" - integrity sha512-zeFQrr+284Ekvd9e7KAX954LkapWiOmQtsfHirhxqfdlX6MEC32iRE+pqUGlYIBchdevaCwvzxWGSy/YBNI85g== - dependencies: - browserslist "^4.9.1" - invariant "^2.2.4" - semver "^5.5.0" - -"@babel/core@^7.0.1", "@babel/core@^7.1.0", "@babel/core@^7.4.3", "@babel/core@^7.7.5": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.0.tgz#ac977b538b77e132ff706f3b8a4dbad09c03c56e" - integrity sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.9.0" - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helpers" "^7.9.0" - "@babel/parser" "^7.9.0" - "@babel/template" "^7.8.6" - "@babel/traverse" "^7.9.0" - "@babel/types" "^7.9.0" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.2" - lodash "^4.17.13" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/core@^7.11.1": +"@babel/core@^7.0.1", "@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.4.3", "@babel/core@^7.7.5": version "7.11.1" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.11.1.tgz#2c55b604e73a40dc21b0e52650b11c65cf276643" integrity sha512-XqF7F6FWQdKGGWAzGELL+aCO1p+lRY5Tj5/tbT3St1G8NaH70jhhDIKknIZaDans0OQBG5wRAldROLHSt44BgQ== @@ -101,17 +63,7 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.0.0", "@babel/generator@^7.9.0": - version "7.9.4" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.4.tgz#12441e90c3b3c4159cdecf312075bf1a8ce2dbce" - integrity sha512-rjP8ahaDy/ouhrvCoU1E5mqaitWrxwuNGU+dy1EpaoK48jZay4MdkskKGIMHLZNewg8sAsqpGSREJwP0zH3YQA== - dependencies: - "@babel/types" "^7.9.0" - jsesc "^2.5.1" - lodash "^4.17.13" - source-map "^0.5.0" - -"@babel/generator@^7.11.0": +"@babel/generator@^7.0.0", "@babel/generator@^7.11.0": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.0.tgz#4b90c78d8c12825024568cbe83ee6c9af193585c" integrity sha512-fEm3Uzw7Mc9Xi//qU20cBKatTfs2aOtKqmvy/Vm7RkJEGFQ4xc9myCfbXxqK//ZS8MR/ciOHw6meGASJuKmDfQ== @@ -120,24 +72,7 @@ jsesc "^2.5.1" source-map "^0.5.0" -"@babel/generator@^7.9.5": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.5.tgz#27f0917741acc41e6eaaced6d68f96c3fa9afaf9" - integrity sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ== - dependencies: - "@babel/types" "^7.9.5" - jsesc "^2.5.1" - lodash "^4.17.13" - source-map "^0.5.0" - -"@babel/helper-annotate-as-pure@^7.0.0", "@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-annotate-as-pure@^7.10.4": +"@babel/helper-annotate-as-pure@^7.0.0", "@babel/helper-annotate-as-pure@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3" integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA== @@ -152,14 +87,6 @@ "@babel/helper-explode-assignable-expression" "^7.10.4" "@babel/types" "^7.10.4" -"@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.8.3" - "@babel/types" "^7.8.3" - "@babel/helper-builder-react-jsx-experimental@^7.10.4": version "7.10.5" resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx-experimental/-/helper-builder-react-jsx-experimental-7.10.5.tgz#f35e956a19955ff08c1258e44a515a6d6248646b" @@ -169,15 +96,6 @@ "@babel/helper-module-imports" "^7.10.4" "@babel/types" "^7.10.5" -"@babel/helper-builder-react-jsx-experimental@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx-experimental/-/helper-builder-react-jsx-experimental-7.9.0.tgz#066d80262ade488f9c1b1823ce5db88a4cedaa43" - integrity sha512-3xJEiyuYU4Q/Ar9BsHisgdxZsRlsShMe90URZ0e6przL26CCs8NJbDoxH94kKT17PcxlMhsCAwZd90evCo26VQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.8.3" - "@babel/helper-module-imports" "^7.8.3" - "@babel/types" "^7.9.0" - "@babel/helper-builder-react-jsx@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.10.4.tgz#8095cddbff858e6fa9c326daee54a2f2732c1d5d" @@ -186,14 +104,6 @@ "@babel/helper-annotate-as-pure" "^7.10.4" "@babel/types" "^7.10.4" -"@babel/helper-builder-react-jsx@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.9.0.tgz#16bf391990b57732700a3278d4d9a81231ea8d32" - integrity sha512-weiIo4gaoGgnhff54GQ3P5wsUQmnSwpkvU0r6ZHq6TzoSzKy4JxHEgnxNytaKbov2a9z/CVNyzliuCOUPEX3Jw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.8.3" - "@babel/types" "^7.9.0" - "@babel/helper-compilation-targets@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz#804ae8e3f04376607cc791b9d47d540276332bd2" @@ -205,17 +115,6 @@ levenary "^1.1.1" semver "^5.5.0" -"@babel/helper-compilation-targets@^7.8.7": - version "7.8.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.7.tgz#dac1eea159c0e4bd46e309b5a1b04a66b53c1dde" - integrity sha512-4mWm8DCK2LugIS+p1yArqvG1Pf162upsIsjE7cNBjez+NjliQpVhj20obE520nao0o14DaTnFJv+Fw5a0JpoUw== - dependencies: - "@babel/compat-data" "^7.8.6" - browserslist "^4.9.1" - invariant "^2.2.4" - levenary "^1.1.1" - semver "^5.5.0" - "@babel/helper-create-class-features-plugin@^7.10.4", "@babel/helper-create-class-features-plugin@^7.10.5": version "7.10.5" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz#9f61446ba80e8240b0a5c85c6fdac8459d6f259d" @@ -228,18 +127,6 @@ "@babel/helper-replace-supers" "^7.10.4" "@babel/helper-split-export-declaration" "^7.10.4" -"@babel/helper-create-class-features-plugin@^7.8.3": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.6.tgz#243a5b46e2f8f0f674dc1387631eb6b28b851de0" - integrity sha512-klTBDdsr+VFFqaDHm5rR69OpEQtO2Qv8ECxHS1mNhJJvaHArR6a1xTf5K/eZW7eZpJbhCx3NW1Yt/sKsLXLblg== - 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.6" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/helper-create-regexp-features-plugin@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz#fdd60d88524659a0b6959c0579925e425714f3b8" @@ -249,15 +136,6 @@ "@babel/helper-regex" "^7.10.4" regexpu-core "^4.7.0" -"@babel/helper-create-regexp-features-plugin@^7.8.3", "@babel/helper-create-regexp-features-plugin@^7.8.8": - version "7.8.8" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.8.tgz#5d84180b588f560b7864efaeea89243e58312087" - integrity sha512-LYVPdwkrQEiX9+1R29Ld/wTrmQu1SSKYnuOk3g0CkcZMA1p0gsNxJFj/3gBdaJ7Cg0Fnek5z0DsMULePP7Lrqg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.8.3" - "@babel/helper-regex" "^7.8.3" - regexpu-core "^4.7.0" - "@babel/helper-define-map@^7.10.4": version "7.10.5" resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz#b53c10db78a640800152692b13393147acb9bb30" @@ -267,15 +145,6 @@ "@babel/types" "^7.10.5" lodash "^4.17.19" -"@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.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.10.4.tgz#40a1cd917bff1288f699a94a75b37a1a2dbd8c7c" @@ -284,14 +153,6 @@ "@babel/traverse" "^7.10.4" "@babel/types" "^7.10.4" -"@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.8.3" - "@babel/types" "^7.8.3" - "@babel/helper-function-name@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a" @@ -301,24 +162,6 @@ "@babel/template" "^7.10.4" "@babel/types" "^7.10.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-function-name@^7.9.5": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz#2b53820d35275120e1874a82e5aabe1376920a5c" - integrity sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw== - dependencies: - "@babel/helper-get-function-arity" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/types" "^7.9.5" - "@babel/helper-get-function-arity@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2" @@ -326,13 +169,6 @@ dependencies: "@babel/types" "^7.10.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.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz#d49b001d1d5a68ca5e6604dda01a6297f7c9381e" @@ -340,13 +176,6 @@ dependencies: "@babel/types" "^7.10.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.10.4", "@babel/helper-member-expression-to-functions@^7.10.5": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz#ae69c83d84ee82f4b42f96e2a09410935a8f26df" @@ -354,21 +183,7 @@ dependencies: "@babel/types" "^7.11.0" -"@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", "@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-imports@^7.10.4": +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620" integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw== @@ -388,19 +203,6 @@ "@babel/types" "^7.11.0" lodash "^4.17.19" -"@babel/helper-module-transforms@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz#43b34dfe15961918707d247327431388e9fe96e5" - integrity sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA== - dependencies: - "@babel/helper-module-imports" "^7.8.3" - "@babel/helper-replace-supers" "^7.8.6" - "@babel/helper-simple-access" "^7.8.3" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/template" "^7.8.6" - "@babel/types" "^7.9.0" - lodash "^4.17.13" - "@babel/helper-optimise-call-expression@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673" @@ -408,19 +210,7 @@ dependencies: "@babel/types" "^7.10.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", "@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-plugin-utils@^7.10.4": +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== @@ -432,13 +222,6 @@ dependencies: lodash "^4.17.19" -"@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.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.10.4.tgz#fce8bea4e9690bbe923056ded21e54b4e8b68ed5" @@ -450,17 +233,6 @@ "@babel/traverse" "^7.10.4" "@babel/types" "^7.10.4" -"@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.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz#d585cd9388ea06e6031e4cd44b6713cbead9e6cf" @@ -471,16 +243,6 @@ "@babel/traverse" "^7.10.4" "@babel/types" "^7.10.4" -"@babel/helper-replace-supers@^7.8.3", "@babel/helper-replace-supers@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz#5ada744fd5ad73203bf1d67459a27dcba67effc8" - integrity sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.8.3" - "@babel/helper-optimise-call-expression" "^7.8.3" - "@babel/traverse" "^7.8.6" - "@babel/types" "^7.8.6" - "@babel/helper-simple-access@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461" @@ -489,14 +251,6 @@ "@babel/template" "^7.10.4" "@babel/types" "^7.10.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-skip-transparent-expression-wrappers@^7.11.0": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.11.0.tgz#eec162f112c2f58d3af0af125e3bb57665146729" @@ -511,28 +265,11 @@ dependencies: "@babel/types" "^7.11.0" -"@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-validator-identifier@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== -"@babel/helper-validator-identifier@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz#ad53562a7fc29b3b9a91bbf7d10397fd146346ed" - integrity sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw== - -"@babel/helper-validator-identifier@^7.9.5": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz#90977a8e6fbf6b431a7dc31752eee233bf052d80" - integrity sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g== - "@babel/helper-wrap-function@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87" @@ -543,16 +280,6 @@ "@babel/traverse" "^7.10.4" "@babel/types" "^7.10.4" -"@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.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.10.4.tgz#2abeb0d721aff7c0a97376b9e1f6f65d7a475044" @@ -562,25 +289,7 @@ "@babel/traverse" "^7.10.4" "@babel/types" "^7.10.4" -"@babel/helpers@^7.9.0": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.9.2.tgz#b42a81a811f1e7313b88cba8adc66b3d9ae6c09f" - integrity sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA== - dependencies: - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.9.0" - "@babel/types" "^7.9.0" - -"@babel/highlight@^7.0.0", "@babel/highlight@^7.8.3": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.9.0.tgz#4e9b45ccb82b79607271b2979ad82c7b68163079" - integrity sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ== - dependencies: - "@babel/helper-validator-identifier" "^7.9.0" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/highlight@^7.10.4": +"@babel/highlight@^7.0.0", "@babel/highlight@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== @@ -589,15 +298,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.2.0", "@babel/parser@^7.7.5", "@babel/parser@^7.8.6", "@babel/parser@^7.9.0": - version "7.9.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.9.4.tgz#68a35e6b0319bbc014465be43828300113f2f2e8" - integrity sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA== - -"@babel/parser@^7.10.4", "@babel/parser@^7.11.0", "@babel/parser@^7.11.1", "@babel/parser@^7.11.2": - version "7.11.2" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.2.tgz#0882ab8a455df3065ea2dcb4c753b2460a24bead" - integrity sha512-Vuj/+7vLo6l1Vi7uuO+1ngCDNeVmNbTngcJFKCR/oEtz8tKz0CJxZEGmPt9KcIloZhOZ3Zit6xbpXT2MDlS9Vw== +"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.11.0", "@babel/parser@^7.11.1", "@babel/parser@^7.11.2", "@babel/parser@^7.2.0", "@babel/parser@^7.7.5": + version "7.11.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.3.tgz#9e1eae46738bcd08e23e867bab43e7b95299a8f9" + integrity sha512-REo8xv7+sDxkKvoxEywIdsNFiZLybwdI7hcT5uEPyQrSMB4YQ973BfC9OOrD/81MaIjh6UxdulIQXkjmiH3PcA== "@babel/plugin-proposal-async-generator-functions@^7.10.4": version "7.10.5" @@ -608,16 +312,7 @@ "@babel/helper-remap-async-to-generator" "^7.10.4" "@babel/plugin-syntax-async-generators" "^7.8.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/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.10.4": +"@babel/plugin-proposal-class-properties@^7.10.4", "@babel/plugin-proposal-class-properties@^7.7.0": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz#a33bf632da390a59c7a8c570045d1115cd778807" integrity sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg== @@ -625,14 +320,6 @@ "@babel/helper-create-class-features-plugin" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4" -"@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-dynamic-import@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz#ba57a26cb98b37741e9d5bca1b8b0ddf8291f17e" @@ -641,14 +328,6 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-dynamic-import" "^7.8.0" -"@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/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-dynamic-import" "^7.8.0" - "@babel/plugin-proposal-export-namespace-from@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.10.4.tgz#570d883b91031637b3e2958eea3c438e62c05f54" @@ -665,14 +344,6 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-json-strings" "^7.8.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: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.0" - "@babel/plugin-proposal-logical-assignment-operators@^7.11.0": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.11.0.tgz#9f80e482c03083c87125dee10026b58527ea20c8" @@ -689,14 +360,6 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" -"@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-numeric-separator@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz#ce1590ff0a65ad12970a609d78855e9a4c1aef06" @@ -705,15 +368,7 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-proposal-numeric-separator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz#5d6769409699ec9b3b68684cd8116cedff93bad8" - integrity sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" - -"@babel/plugin-proposal-object-rest-spread@^7.11.0": +"@babel/plugin-proposal-object-rest-spread@^7.11.0", "@babel/plugin-proposal-object-rest-spread@^7.6.2": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz#bd81f95a1f746760ea43b6c2d3d62b11790ad0af" integrity sha512-wzch41N4yztwoRw0ak+37wxwJM2oiIiy6huGCoqkvSTA9acYWcPfn9Y4aJqmFFJ70KTJUu29f3DQ43uJ9HXzEA== @@ -722,14 +377,6 @@ "@babel/plugin-syntax-object-rest-spread" "^7.8.0" "@babel/plugin-transform-parameters" "^7.10.4" -"@babel/plugin-proposal-object-rest-spread@^7.6.2", "@babel/plugin-proposal-object-rest-spread@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.9.0.tgz#a28993699fc13df165995362693962ba6b061d6f" - integrity sha512-UgqBv6bjq4fDb8uku9f+wcm1J7YxJ5nT7WO/jBr0cl0PLKb7t1O6RNR1kZbjgx2LQtsDI9hwoQVmn0yhXeQyow== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-proposal-optional-catch-binding@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz#31c938309d24a78a49d68fdabffaa863758554dd" @@ -738,14 +385,6 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-optional-catch-binding" "^7.8.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.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" - "@babel/plugin-proposal-optional-chaining@^7.11.0": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.11.0.tgz#de5866d0646f6afdaab8a566382fe3a221755076" @@ -755,14 +394,6 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.11.0" "@babel/plugin-syntax-optional-chaining" "^7.8.0" -"@babel/plugin-proposal-optional-chaining@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz#31db16b154c39d6b8a645292472b98394c292a58" - integrity sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.0" - "@babel/plugin-proposal-private-methods@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz#b160d972b8fdba5c7d111a145fc8c421fc2a6909" @@ -771,7 +402,7 @@ "@babel/helper-create-class-features-plugin" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-proposal-unicode-property-regex@^7.10.4": +"@babel/plugin-proposal-unicode-property-regex@^7.10.4", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz#4483cda53041ce3413b7fe2f00022665ddfaa75d" integrity sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA== @@ -779,14 +410,6 @@ "@babel/helper-create-regexp-features-plugin" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-proposal-unicode-property-regex@^7.4.4", "@babel/plugin-proposal-unicode-property-regex@^7.8.3": - version "7.8.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.8.tgz#ee3a95e90cdc04fe8cd92ec3279fa017d68a0d1d" - integrity sha512-EVhjVsMpbhLw9ZfHWSx2iy13Q8Z/eg8e8ccVWt23sWQK5l1UdkoLJPN5w69UA4uITGBnEZD2JOe4QOHycYKv8A== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.8.8" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-async-generators@^7.8.0", "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" @@ -801,20 +424,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.10.4": +"@babel/plugin-syntax-class-properties@^7.10.4", "@babel/plugin-syntax-class-properties@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz#6644e6a0baa55a61f9e3231f6c9eeb6ee46c124c" integrity sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA== dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-class-properties@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.8.3.tgz#6cb933a8872c8d359bfde69bbeaae5162fd1e8f7" - integrity sha512-UcAyQWg2bAN647Q+O811tG9MrJ38Z10jjhQdKNAL8fsyPzE3cCN/uT+f55cFVY4aGO4jqJAvmqsuY3GQDwAoXg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-dynamic-import@^7.2.0", "@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" @@ -829,12 +445,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-flow@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.8.3.tgz#f2c883bd61a6316f2c89380ae5122f923ba4527f" - integrity sha512-innAx3bUbA0KSYj2E2MNFSn9hiCeowOFLxlsuhXzw8hMQnzkDomUr9QCD7E9VF60NmnG1sNTuuv6Qf4f8INYsg== +"@babel/plugin-syntax-flow@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.10.4.tgz#53351dd7ae01995e567d04ce42af1a6e0ba846a6" + integrity sha512-yxQsX1dJixF4qEEdzVbst3SZQ58Nrooz8NV9Z9GL4byTE25BvJgl5lf0RECUf0fh28rZBb/RYTWn/eeKwCMrZQ== dependencies: - "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-json-strings@^7.8.0", "@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" @@ -850,27 +466,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@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.8.3" - -"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.8.3.tgz#3995d7d7ffff432f6ddc742b47e730c054599897" - integrity sha512-Zpg2Sgc++37kuFl6ppq2Q7Awc6E6AIW671x5PY8E/f7MCIyPPGK/EoeZXvvY3P42exZ3Q4/t3YOzP/HiN79jDg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0", "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": 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" @@ -878,20 +480,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.10.4": +"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-numeric-separator@^7.8.0", "@babel/plugin-syntax-numeric-separator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz#0e3fb63e09bea1b11e96467271c8308007e7c41f" - integrity sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-object-rest-spread@^7.8.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": 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" @@ -920,13 +515,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@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.8.3" - "@babel/plugin-syntax-typescript@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.10.4.tgz#2f55e770d3501e83af217d782cb7517d7bb34d25" @@ -941,13 +529,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@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.8.3" - "@babel/plugin-transform-async-to-generator@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz#41a5017e49eb6f3cda9392a51eef29405b245a37" @@ -957,15 +538,6 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-remap-async-to-generator" "^7.10.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-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.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz#1afa595744f75e43a91af73b0d998ecfe4ebc2e8" @@ -973,13 +545,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@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.10.4": version "7.11.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.11.1.tgz#5b7efe98852bef8d652c0b28144cd93a9e4b5215" @@ -987,14 +552,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.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.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz#405136af2b3e218bc4a1926228bc917ab1a0adc7" @@ -1009,20 +566,6 @@ "@babel/helper-split-export-declaration" "^7.10.4" globals "^11.1.0" -"@babel/plugin-transform-classes@^7.9.0": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.9.2.tgz#8603fc3cc449e31fdbdbc257f67717536a11af8d" - integrity sha512-TC2p3bPzsfvSsqBZo0kJnuelnoK9O3welkUpqSqBQuBF6R5MN2rysopri8kNvtlGIb2jmUO7i15IooAZJjZuMQ== - 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.6" - "@babel/helper-split-export-declaration" "^7.8.3" - globals "^11.1.0" - "@babel/plugin-transform-computed-properties@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz#9ded83a816e82ded28d52d4b4ecbdd810cdfc0eb" @@ -1030,13 +573,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@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.8.3" - "@babel/plugin-transform-destructuring@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz#70ddd2b3d1bea83d01509e9bb25ddb3a74fc85e5" @@ -1044,14 +580,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-destructuring@^7.8.3": - version "7.8.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.8.tgz#fadb2bc8e90ccaf5658de6f8d4d22ff6272a2f4b" - integrity sha512-eRJu4Vs2rmttFCdhPUM3bV0Yo/xPSdPw6ML9KHs/bjB4bLA5HXlbvYXPOD5yASodGod+krjYx21xm1QmL8dCJQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-dotall-regex@^7.10.4": +"@babel/plugin-transform-dotall-regex@^7.10.4", "@babel/plugin-transform-dotall-regex@^7.4.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz#469c2062105c1eb6a040eaf4fac4b488078395ee" integrity sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA== @@ -1059,14 +588,6 @@ "@babel/helper-create-regexp-features-plugin" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4" -"@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-create-regexp-features-plugin" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-transform-duplicate-keys@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz#697e50c9fee14380fe843d1f306b295617431e47" @@ -1074,13 +595,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@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.8.3" - "@babel/plugin-transform-exponentiation-operator@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz#5ae338c57f8cf4001bdb35607ae66b92d665af2e" @@ -1089,21 +603,13 @@ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4" -"@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.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-flow-strip-types@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.9.0.tgz#8a3538aa40434e000b8f44a3c5c9ac7229bd2392" - integrity sha512-7Qfg0lKQhEHs93FChxVLAvhBshOPQDtJUTVHr/ZwQNRccCm4O9D79r9tVSoV8iNwjP1YgfD+e/fgHcPkN1qEQg== +"@babel/plugin-transform-flow-strip-types@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.10.4.tgz#c497957f09e86e3df7296271e9eb642876bf7788" + integrity sha512-XTadyuqNst88UWBTdLjM+wEY7BFnY2sYtPyAidfC7M/QaZnSuIZpMvLxqGT7phAcnGyWh/XQFLKcGf04CnvxSQ== dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-flow" "^7.8.3" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-flow" "^7.10.4" "@babel/plugin-transform-for-of@^7.10.4": version "7.10.4" @@ -1112,13 +618,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-for-of@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.9.0.tgz#0f260e27d3e29cd1bb3128da5e76c761aa6c108e" - integrity sha512-lTAnWOpMwOXpyDx06N+ywmF3jNbafZEqZ96CGYabxHrxNX8l5ny7dt4bK/rGwAh9utyP2b2Hv7PlZh1AAS54FQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-transform-function-name@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz#6a467880e0fc9638514ba369111811ddbe2644b7" @@ -1127,14 +626,6 @@ "@babel/helper-function-name" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.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.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-transform-literals@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz#9f42ba0841100a135f22712d0e391c462f571f3c" @@ -1142,13 +633,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@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.8.3" - "@babel/plugin-transform-member-expression-literals@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz#b1ec44fcf195afcb8db2c62cd8e551c881baf8b7" @@ -1156,13 +640,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@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.8.3" - "@babel/plugin-transform-modules-amd@^7.10.4": version "7.10.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.5.tgz#1b9cddaf05d9e88b3aad339cb3e445c4f020a9b1" @@ -1172,15 +649,6 @@ "@babel/helper-plugin-utils" "^7.10.4" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-amd@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.9.0.tgz#19755ee721912cf5bb04c07d50280af3484efef4" - integrity sha512-vZgDDF003B14O8zJy0XXLnPH4sg+9X5hFBBGN1V+B2rgrB+J2xIypSN6Rk9imB2hSTHQi5OHLrFWsZab1GMk+Q== - dependencies: - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helper-plugin-utils" "^7.8.3" - babel-plugin-dynamic-import-node "^2.3.0" - "@babel/plugin-transform-modules-commonjs@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz#66667c3eeda1ebf7896d41f1f16b17105a2fbca0" @@ -1191,16 +659,6 @@ "@babel/helper-simple-access" "^7.10.4" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-commonjs@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.9.0.tgz#e3e72f4cbc9b4a260e30be0ea59bdf5a39748940" - integrity sha512-qzlCrLnKqio4SlgJ6FMMLBe4bySNis8DFn1VkGmOcxG9gqEyPIOzeQrA//u0HAKrWpJlpZbZMPB1n/OPa4+n8g== - dependencies: - "@babel/helper-module-transforms" "^7.9.0" - "@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.10.4": version "7.10.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.5.tgz#6270099c854066681bae9e05f87e1b9cadbe8c85" @@ -1211,16 +669,6 @@ "@babel/helper-plugin-utils" "^7.10.4" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-systemjs@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.9.0.tgz#e9fd46a296fc91e009b64e07ddaa86d6f0edeb90" - integrity sha512-FsiAv/nao/ud2ZWy4wFacoLOm5uxl0ExSQ7ErvP7jpoihLR6Cq90ilOFyX9UXct3rbtKsAiZ9kFt5XGfPe/5SQ== - dependencies: - "@babel/helper-hoist-variables" "^7.8.3" - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helper-plugin-utils" "^7.8.3" - babel-plugin-dynamic-import-node "^2.3.0" - "@babel/plugin-transform-modules-umd@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz#9a8481fe81b824654b3a0b65da3df89f3d21839e" @@ -1229,14 +677,6 @@ "@babel/helper-module-transforms" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-modules-umd@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.9.0.tgz#e909acae276fec280f9b821a5f38e1f08b480697" - integrity sha512-uTWkXkIVtg/JGRSIABdBoMsoIeoHQHPTL0Y2E7xf5Oj7sLqwVsNXOkNk0VJc7vF0IMBsPeikHxFjGe+qmwPtTQ== - dependencies: - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-transform-named-capturing-groups-regex@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz#78b4d978810b6f3bcf03f9e318f2fc0ed41aecb6" @@ -1244,13 +684,6 @@ dependencies: "@babel/helper-create-regexp-features-plugin" "^7.10.4" -"@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: - "@babel/helper-create-regexp-features-plugin" "^7.8.3" - "@babel/plugin-transform-new-target@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz#9097d753cb7b024cb7381a3b2e52e9513a9c6888" @@ -1258,13 +691,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.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.8.3" - "@babel/plugin-transform-object-super@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz#d7146c4d139433e7a6526f888c667e314a093894" @@ -1273,14 +699,6 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-replace-supers" "^7.10.4" -"@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.8.3" - "@babel/helper-replace-supers" "^7.8.3" - "@babel/plugin-transform-parameters@^7.10.4": version "7.10.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz#59d339d58d0b1950435f4043e74e2510005e2c4a" @@ -1289,14 +707,6 @@ "@babel/helper-get-function-arity" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-parameters@^7.8.7": - version "7.9.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.9.3.tgz#3028d0cc20ddc733166c6e9c8534559cee09f54a" - integrity sha512-fzrQFQhp7mIhOzmOtPiKffvCYQSK10NR8t6BBz2yPbeUHb9OLW8RZGtgDRBn8z2hGcwvKDL3vC7ojPTLNxmqEg== - dependencies: - "@babel/helper-get-function-arity" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-transform-property-literals@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz#f6fe54b6590352298785b83edd815d214c42e3c0" @@ -1304,19 +714,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@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.8.3" - "@babel/plugin-transform-react-constant-elements@^7.0.0", "@babel/plugin-transform-react-constant-elements@^7.2.0", "@babel/plugin-transform-react-constant-elements@^7.6.3": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.9.0.tgz#a75abc936a3819edec42d3386d9f1c93f28d9d9e" - integrity sha512-wXMXsToAUOxJuBBEHajqKLFWcCkOSLshTI2ChCFFj1zDd7od4IOxiwLCOObNUvOpkxLpjIuaIdBMmNt6ocCPAw== + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.10.4.tgz#0f485260bf1c29012bb973e7e404749eaac12c9e" + integrity sha512-cYmQBW1pXrqBte1raMkAulXmi7rjg3VI6ZLg9QIic8Hq7BtYXaWuZSxsr2siOMI6SWwpxjWfnwhTUrd7JlAV7g== dependencies: - "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-transform-react-display-name@^7.10.4": version "7.10.4" @@ -1325,13 +728,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-react-display-name@^7.8.3": - 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-development@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.10.4.tgz#6ec90f244394604623880e15ebc3c34c356258ba" @@ -1341,15 +737,6 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-jsx" "^7.10.4" -"@babel/plugin-transform-react-jsx-development@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.9.0.tgz#3c2a130727caf00c2a293f0aed24520825dbf754" - integrity sha512-tK8hWKrQncVvrhvtOiPpKrQjfNX3DtkNLSX4ObuGcpS9p0QrGetKmlySIGR07y48Zft8WVgPakqd/bk46JrMSw== - dependencies: - "@babel/helper-builder-react-jsx-experimental" "^7.9.0" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-jsx" "^7.8.3" - "@babel/plugin-transform-react-jsx-self@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.10.4.tgz#cd301a5fed8988c182ed0b9d55e9bd6db0bd9369" @@ -1358,14 +745,6 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-jsx" "^7.10.4" -"@babel/plugin-transform-react-jsx-self@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.9.0.tgz#f4f26a325820205239bb915bad8e06fcadabb49b" - integrity sha512-K2ObbWPKT7KUTAoyjCsFilOkEgMvFG+y0FqOl6Lezd0/13kMkkjHskVsZvblRPj1PHA44PrToaZANrryppzTvQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-jsx" "^7.8.3" - "@babel/plugin-transform-react-jsx-source@^7.10.4": version "7.10.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.10.5.tgz#34f1779117520a779c054f2cdd9680435b9222b4" @@ -1374,14 +753,6 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-jsx" "^7.10.4" -"@babel/plugin-transform-react-jsx-source@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.9.0.tgz#89ef93025240dd5d17d3122294a093e5e0183de0" - integrity sha512-K6m3LlSnTSfRkM6FcRk8saNEeaeyG5k7AVkBU2bZK3+1zdkSED3qNdsWrUgQBeTVD2Tp3VMmerxVO2yM5iITmw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-jsx" "^7.8.3" - "@babel/plugin-transform-react-jsx@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.10.4.tgz#673c9f913948764a4421683b2bef2936968fddf2" @@ -1392,16 +763,6 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-jsx" "^7.10.4" -"@babel/plugin-transform-react-jsx@^7.9.4": - version "7.9.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.9.4.tgz#86f576c8540bd06d0e95e0b61ea76d55f6cbd03f" - integrity sha512-Mjqf3pZBNLt854CK0C/kRuXAnE6H/bo7xYojP+WGtX8glDGSibcwnsWwhwoSuRg0+EBnxPC1ouVnuetUIlPSAw== - dependencies: - "@babel/helper-builder-react-jsx" "^7.9.0" - "@babel/helper-builder-react-jsx-experimental" "^7.9.0" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-jsx" "^7.8.3" - "@babel/plugin-transform-react-pure-annotations@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.10.4.tgz#3eefbb73db94afbc075f097523e445354a1c6501" @@ -1417,13 +778,6 @@ dependencies: regenerator-transform "^0.14.2" -"@babel/plugin-transform-regenerator@^7.8.7": - version "7.8.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz#5e46a0dca2bee1ad8285eb0527e6abc9c37672f8" - integrity sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA== - dependencies: - regenerator-transform "^0.14.2" - "@babel/plugin-transform-reserved-words@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz#8f2682bcdcef9ed327e1b0861585d7013f8a54dd" @@ -1431,13 +785,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@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.8.3" - "@babel/plugin-transform-runtime@^7.11.0": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.11.0.tgz#e27f78eb36f19448636e05c33c90fd9ad9b8bccf" @@ -1455,13 +802,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@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.8.3" - "@babel/plugin-transform-spread@^7.11.0": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.11.0.tgz#fa84d300f5e4f57752fe41a6d1b3c554f13f17cc" @@ -1470,13 +810,6 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-skip-transparent-expression-wrappers" "^7.11.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.8.3" - "@babel/plugin-transform-sticky-regex@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz#8f3889ee8657581130a29d9cc91d7c73b7c4a28d" @@ -1485,14 +818,6 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-regex" "^7.10.4" -"@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-plugin-utils" "^7.8.3" - "@babel/helper-regex" "^7.8.3" - "@babel/plugin-transform-template-literals@^7.10.4": version "7.10.5" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz#78bc5d626a6642db3312d9d0f001f5e7639fde8c" @@ -1501,14 +826,6 @@ "@babel/helper-annotate-as-pure" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.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-annotate-as-pure" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-transform-typeof-symbol@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz#9509f1a7eec31c4edbffe137c16cc33ff0bc5bfc" @@ -1516,13 +833,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@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.8.3" - "@babel/plugin-transform-typescript@^7.10.4": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.11.0.tgz#2b4879676af37342ebb278216dd090ac67f13abb" @@ -1547,81 +857,7 @@ "@babel/helper-create-regexp-features-plugin" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.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.0.0", "@babel/preset-env@^7.4.3", "@babel/preset-env@^7.4.5": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.9.0.tgz#a5fc42480e950ae8f5d9f8f2bbc03f52722df3a8" - integrity sha512-712DeRXT6dyKAM/FMbQTV/FvRCms2hPCx+3weRjZ8iQVQWZejWWk1wwG6ViWMyqb/ouBbGOl5b6aCk0+j1NmsQ== - dependencies: - "@babel/compat-data" "^7.9.0" - "@babel/helper-compilation-targets" "^7.8.7" - "@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-numeric-separator" "^7.8.3" - "@babel/plugin-proposal-object-rest-spread" "^7.9.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.8.3" - "@babel/plugin-proposal-optional-chaining" "^7.9.0" - "@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-numeric-separator" "^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.9.0" - "@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.9.0" - "@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.9.0" - "@babel/plugin-transform-modules-commonjs" "^7.9.0" - "@babel/plugin-transform-modules-systemjs" "^7.9.0" - "@babel/plugin-transform-modules-umd" "^7.9.0" - "@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.7" - "@babel/plugin-transform-property-literals" "^7.8.3" - "@babel/plugin-transform-regenerator" "^7.8.7" - "@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/preset-modules" "^0.1.3" - "@babel/types" "^7.9.0" - browserslist "^4.9.1" - core-js-compat "^3.6.2" - invariant "^2.2.2" - levenary "^1.1.1" - semver "^5.5.0" - -"@babel/preset-env@^7.11.0": +"@babel/preset-env@^7.0.0", "@babel/preset-env@^7.11.0", "@babel/preset-env@^7.4.3", "@babel/preset-env@^7.4.5": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.11.0.tgz#860ee38f2ce17ad60480c2021ba9689393efb796" integrity sha512-2u1/k7rG/gTh02dylX2kL3S0IJNF+J6bfDSp4DI2Ma8QN6Y9x9pmAax59fsCk6QUQG0yqH47yJWA+u1I1LccAg== @@ -1696,12 +932,12 @@ semver "^5.5.0" "@babel/preset-flow@^7.0.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.9.0.tgz#fee847c3e090b0b2d9227c1949e4da1d1379280d" - integrity sha512-88uSmlshIrlmPkNkEcx3UpSZ6b8n0UGBq0/0ZMZCF/uxAW0XIAUuDHBhIOAh0pvweafH4RxOwi/H3rWhtqOYPA== + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.10.4.tgz#e0d9c72f8cb02d1633f6a5b7b16763aa2edf659f" + integrity sha512-XI6l1CptQCOBv+ZKYwynyswhtOKwpZZp5n0LG1QKCo8erRhqjoQV6nvx61Eg30JHpysWQSBwA2AWRU3pBbSY5g== dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-transform-flow-strip-types" "^7.9.0" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-flow-strip-types" "^7.10.4" "@babel/preset-modules@^0.1.3": version "0.1.3" @@ -1714,19 +950,7 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/preset-react@^7.0.0": - version "7.9.4" - resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.9.4.tgz#c6c97693ac65b6b9c0b4f25b948a8f665463014d" - integrity sha512-AxylVB3FXeOTQXNXyiuAQJSvss62FEotbX2Pzx3K/7c+MKJMdSg6Ose6QYllkdCFA8EInCJVw7M/o5QbLuA4ZQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-transform-react-display-name" "^7.8.3" - "@babel/plugin-transform-react-jsx" "^7.9.4" - "@babel/plugin-transform-react-jsx-development" "^7.9.0" - "@babel/plugin-transform-react-jsx-self" "^7.9.0" - "@babel/plugin-transform-react-jsx-source" "^7.9.0" - -"@babel/preset-react@^7.10.4": +"@babel/preset-react@^7.0.0", "@babel/preset-react@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.10.4.tgz#92e8a66d816f9911d11d4cc935be67adfc82dbcf" integrity sha512-BrHp4TgOIy4M19JAfO1LhycVXOPWdDbTRep7eVyatf174Hff+6Uk53sDyajqZPu8W1qXRBiYOfIamek6jA7YVw== @@ -1759,9 +983,9 @@ source-map-support "^0.5.16" "@babel/runtime-corejs2@^7.2.0", "@babel/runtime-corejs2@^7.6.3": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.9.2.tgz#f11d074ff99b9b4319b5ecf0501f12202bf2bf4d" - integrity sha512-ayjSOxuK2GaSDJFCtLgHnYjuMyIpViNujWrZo8GUpN60/n7juzJKK5yOo6RFVb0zdU9ACJFK+MsZrUnj3OmXMw== + version "7.11.2" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.11.2.tgz#700a03945ebad0d31ba6690fc8a6bcc9040faa47" + integrity sha512-AC/ciV28adSSpEkBglONBWq4/Lvm6GAZuxIoyVtsnUpZMl0bxLtoChEnYAkP+47KyOCayZanojtflUEUJtR/6Q== dependencies: core-js "^2.6.5" regenerator-runtime "^0.13.4" @@ -1773,42 +997,19 @@ dependencies: regenerator-runtime "^0.12.0" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@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.8.4", "@babel/runtime@^7.9.2": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06" - integrity sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/runtime@^7.11.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@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.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.11.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.3.1", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.7": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.5.tgz#303d8bd440ecd5a491eae6117fd3367698674c5c" - integrity sha512-otddXKhdNn7d0ptoFRHtMLa8LqDxLYwTjB4nYgM1yy5N6gU/MUf8zqyyLltCH3yAVitBzmwK4us+DD0l/MauAg== - dependencies: - regenerator-runtime "^0.13.4" - "@babel/standalone@^7.4.5": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.10.5.tgz#4ee38dc79fda10a2a0da0897f09e270310151314" - integrity sha512-PERGHqhQ7H3TrdglvSW4pEHULywMJEdytnzaR0VPF1HN45aS+3FcE62efb90XPKS9TlgrEUkYDvYMt+0m6G0YA== - -"@babel/template@^7.0.0", "@babel/template@^7.3.3", "@babel/template@^7.7.4", "@babel/template@^7.8.3", "@babel/template@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" - integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/parser" "^7.8.6" - "@babel/types" "^7.8.6" + version "7.11.3" + resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.11.3.tgz#043e6ff3b12226e41ed2013418b9a4c055d9c21e" + integrity sha512-rcoT32Hw0faYhmCDR0P84ODKL5kpEdhYPgdzlTKs7+v9oJaVLsGvq0xlkmLRj01F6LrItH3tY9eEoRsPLie4RQ== -"@babel/template@^7.10.4": +"@babel/template@^7.0.0", "@babel/template@^7.10.4", "@babel/template@^7.3.3", "@babel/template@^7.7.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA== @@ -1817,22 +1018,7 @@ "@babel/parser" "^7.10.4" "@babel/types" "^7.10.4" -"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.1.6", "@babel/traverse@^7.4.5", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.6", "@babel/traverse@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.0.tgz#d3882c2830e513f4fe4cec9fe76ea1cc78747892" - integrity sha512-jAZQj0+kn4WTHO5dUZkZKhbFrqZE7K5LAQ5JysMnmvGij+wOdr+8lWqPeW0BcF4wFwrEXXtdGO7wcV6YPJcf3w== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.9.0" - "@babel/helper-function-name" "^7.8.3" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/parser" "^7.9.0" - "@babel/types" "^7.9.0" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.13" - -"@babel/traverse@^7.10.4", "@babel/traverse@^7.11.0": +"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.1.6", "@babel/traverse@^7.10.4", "@babel/traverse@^7.11.0", "@babel/traverse@^7.4.5", "@babel/traverse@^7.7.4": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.11.0.tgz#9b996ce1b98f53f7c3e4175115605d56ed07dd24" integrity sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg== @@ -1847,31 +1033,7 @@ globals "^11.1.0" lodash "^4.17.19" -"@babel/traverse@^7.7.4": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.5.tgz#6e7c56b44e2ac7011a948c21e283ddd9d9db97a2" - integrity sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.9.5" - "@babel/helper-function-name" "^7.9.5" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/parser" "^7.9.0" - "@babel/types" "^7.9.5" - 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.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.0.tgz#00b064c3df83ad32b2dbf5ff07312b15c7f1efb5" - integrity sha512-BS9JKfXkzzJl8RluW4JGknzpiUV7ZrvTayM6yfqLTVBEnFtyowVIOu6rqxRd5cVO6yGoWf4T8u8dgK9oB+GCng== - dependencies: - "@babel/helper-validator-identifier" "^7.9.0" - lodash "^4.17.13" - to-fast-properties "^2.0.0" - -"@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0": +"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.2.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4", "@babel/types@^7.4.0", "@babel/types@^7.4.4": version "7.11.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.0.tgz#2ae6bf1ba9ae8c3c43824e5861269871b206e90d" integrity sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA== @@ -1880,24 +1042,6 @@ lodash "^4.17.19" to-fast-properties "^2.0.0" -"@babel/types@^7.3.3": - version "7.9.6" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.6.tgz#2c5502b427251e9de1bd2dff95add646d95cc9f7" - integrity sha512-qxXzvBO//jO9ZnoasKF1uJzHd2+M6Q2ZPIVfnFps8JJvXy0ZBbwbNOmE6SGIY5XOY6d1Bo5lb9d9RJ8nv3WSeA== - dependencies: - "@babel/helper-validator-identifier" "^7.9.5" - lodash "^4.17.13" - to-fast-properties "^2.0.0" - -"@babel/types@^7.4", "@babel/types@^7.9.5": - version "7.9.5" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.5.tgz#89231f82915a8a566a703b3b20133f73da6b9444" - integrity sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg== - dependencies: - "@babel/helper-validator-identifier" "^7.9.5" - lodash "^4.17.13" - to-fast-properties "^2.0.0" - "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -7695,13 +6839,6 @@ babel-plugin-add-react-displayname@^0.0.5: resolved "https://registry.yarnpkg.com/babel-plugin-add-react-displayname/-/babel-plugin-add-react-displayname-0.0.5.tgz#339d4cddb7b65fd62d1df9db9fe04de134122bd5" integrity sha1-M51M3be2X9YtHfnbn+BN4TQSK9U= -babel-plugin-dynamic-import-node@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f" - integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ== - dependencies: - object.assign "^4.1.0" - babel-plugin-dynamic-import-node@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" @@ -8653,16 +7790,6 @@ browserslist@^4.8.3: electron-to-chromium "^1.3.338" node-releases "^1.1.46" -browserslist@^4.9.1: - version "4.11.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.11.0.tgz#aef4357b10a8abda00f97aac7cd587b2082ba1ad" - integrity sha512-WqEC7Yr5wUH5sg6ruR++v2SGOQYpyUdYYd4tZoAq1F7y+QXoLoYGXVbxhtaIqWmAJjtNTRjVD3HuJc1OXTel2A== - dependencies: - caniuse-lite "^1.0.30001035" - electron-to-chromium "^1.3.380" - node-releases "^1.1.52" - pkg-up "^3.1.0" - bser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" @@ -9089,7 +8216,7 @@ can-use-dom@^0.1.0: resolved "https://registry.yarnpkg.com/can-use-dom/-/can-use-dom-0.1.0.tgz#22cc4a34a0abc43950f42c6411024a3f6366b45a" integrity sha1-IsxKNKCrxDlQ9CxkEQJKP2NmtFo= -caniuse-lite@^1.0.30000984, caniuse-lite@^1.0.30001020, caniuse-lite@^1.0.30001022, caniuse-lite@^1.0.30001035, caniuse-lite@^1.0.30001043: +caniuse-lite@^1.0.30000984, caniuse-lite@^1.0.30001020, caniuse-lite@^1.0.30001022, caniuse-lite@^1.0.30001043: version "1.0.30001094" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001094.tgz#0b11d02e1cdc201348dbd8e3e57bd9b6ce82b175" integrity sha512-ufHZNtMaDEuRBpTbqD93tIQnngmJ+oBknjvr0IbFympSdtFpAUFmNv4mVKbb53qltxFx0nK3iy32S9AqkLzUNA== @@ -12470,11 +11597,6 @@ electron-to-chromium@^1.3.191, electron-to-chromium@^1.3.338: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.340.tgz#5d4fe78e984d4211194cf5a52e08069543da146f" integrity sha512-hRFBAglhcj5iVYH+o8QU0+XId1WGoc0VGowJB1cuJAt3exHGrivZvWeAO5BRgBZqwZtwxjm8a5MQeGoT/Su3ww== -electron-to-chromium@^1.3.380: - version "1.3.382" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.382.tgz#cad02da655c33f7a3d6ca7525bd35c17e90f3a8f" - integrity sha512-gJfxOcgnBlXhfnUUObsq3n3ReU8CT6S8je97HndYRkKsNZMJJ38zO/pI5aqO7L3Myfq+E3pqPyKK/ynyLEQfBA== - electron-to-chromium@^1.3.413: version "1.3.465" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.465.tgz#d692e5c383317570c2bd82092a24a0308c6ccf29" @@ -22121,13 +21243,6 @@ node-releases@^1.1.25, node-releases@^1.1.46: dependencies: semver "^6.3.0" -node-releases@^1.1.52: - version "1.1.52" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.52.tgz#bcffee3e0a758e92e44ecfaecd0a47554b0bcba9" - integrity sha512-snSiT1UypkgGt2wxPqS6ImEUICbNCMb31yaxWrOLXjhlt2z2/IBpaOxzONExqSm4y5oLnAqjjRWu+wsDzK5yNQ== - dependencies: - semver "^6.3.0" - node-releases@^1.1.53: version "1.1.58" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.58.tgz#8ee20eef30fa60e52755fcc0942def5a734fe935" From 5b64a4cdfea92639ddf9e23c86c43dda5ea3ac68 Mon Sep 17 00:00:00 2001 From: Caroline Horn <549577+cchaos@users.noreply.github.com> Date: Wed, 12 Aug 2020 16:58:16 -0400 Subject: [PATCH 03/53] Empty index patterns page re-design (#68819) Empty index patterns page re-design --- .sass-lint.yml | 1 + ...-plugin-core-public.doclinksstart.links.md | 1 + docs/setup/connect-to-elasticsearch.asciidoc | 2 +- .../public/doc_links/doc_links_service.ts | 2 + src/core/public/public.api.md | 1 + .../redirect_no_index_pattern.tsx | 2 +- .../public/_templates.scss | 11 + .../public/_variables.scss | 1 + .../create_index_pattern_prompt/index.tsx | 108 ---- .../create_index_pattern_wizard.test.tsx.snap | 76 ++- .../__snapshots__/empty_state.test.tsx.snap | 66 --- .../components/empty_state/empty_state.tsx | 90 --- .../header/__snapshots__/header.test.tsx.snap | 4 +- .../components/header/header.tsx | 3 +- .../__snapshots__/indices_list.test.tsx.snap | 25 +- .../components/indices_list/indices_list.tsx | 2 +- .../loading_indices.test.tsx.snap | 46 +- .../loading_indices/loading_indices.tsx | 34 +- .../status_message/status_message.tsx | 2 +- .../step_index_pattern/step_index_pattern.tsx | 14 +- .../advanced_options.test.tsx.snap | 4 +- .../advanced_options/advanced_options.tsx | 4 +- .../header/__snapshots__/header.test.tsx.snap | 15 +- .../components/header/header.tsx | 9 +- .../components/time_field/time_field.scss | 7 - .../components/time_field/time_field.tsx | 2 - .../create_index_pattern_wizard.test.tsx | 1 - .../create_index_pattern_wizard.tsx | 44 +- .../lib/extract_time_fields.test.ts | 2 +- .../lib/extract_time_fields.ts | 2 +- .../lib/get_indices.test.ts | 25 +- .../lib/get_indices.ts | 8 +- .../edit_index_pattern/edit_index_pattern.tsx | 106 ++-- .../index_header/index_header.tsx | 28 +- .../edit_index_pattern/tabs/tabs.tsx | 1 + .../scripting_help/test_script.scss | 2 +- .../empty_index_pattern_prompt.test.tsx.snap | 99 ++++ .../assets/index_pattern_illustration.scss | 9 + .../assets/index_pattern_illustration.tsx | 551 ++++++++++++++++++ .../empty_index_pattern_prompt.scss | 31 + .../empty_index_pattern_prompt.test.tsx} | 32 +- .../empty_index_pattern_prompt.tsx | 111 ++++ .../empty_index_pattern_prompt/index.tsx | 20 + .../__snapshots__/empty_state.test.tsx.snap | 216 +++++++ .../empty_state/empty_state.scss | 23 + .../empty_state/empty_state.test.tsx | 74 +++ .../empty_state/empty_state.tsx | 234 ++++++++ .../empty_state/index.ts | 0 .../index_pattern_table.tsx | 114 +++- .../index_pattern_management/public/index.ts | 2 + .../mount_management_section.tsx | 6 +- .../index_pattern_management/public/mocks.ts | 3 + .../index_pattern_management/public/plugin.ts | 4 +- .../service/environment/environment.mock.ts | 44 ++ .../service/environment/environment.test.ts | 49 ++ .../public/service/environment/environment.ts | 52 ++ .../public/service/environment/index.ts | 20 + .../index_pattern_management_service.ts | 4 + .../index_pattern_management/public/types.ts | 7 + .../apps/management/_index_patterns_empty.ts | 66 +++ .../apps/management/_kibana_settings.js | 2 +- test/functional/apps/management/index.js | 1 + test/functional/page_objects/settings_page.ts | 13 +- x-pack/plugins/ml/kibana.json | 3 +- x-pack/plugins/ml/public/application/app.tsx | 3 +- x-pack/plugins/ml/public/plugin.ts | 14 +- .../translations/translations/ja-JP.json | 15 - .../translations/translations/zh-CN.json | 15 - .../index_patterns_security.ts | 2 +- 69 files changed, 2006 insertions(+), 584 deletions(-) create mode 100644 src/plugins/index_pattern_management/public/_templates.scss create mode 100644 src/plugins/index_pattern_management/public/_variables.scss delete mode 100644 src/plugins/index_pattern_management/public/components/create_index_pattern_prompt/index.tsx delete mode 100644 src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/empty_state/__snapshots__/empty_state.test.tsx.snap delete mode 100644 src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/empty_state/empty_state.tsx delete mode 100644 src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/time_field/time_field.scss create mode 100644 src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/__snapshots__/empty_index_pattern_prompt.test.tsx.snap create mode 100644 src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/assets/index_pattern_illustration.scss create mode 100644 src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/assets/index_pattern_illustration.tsx create mode 100644 src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/empty_index_pattern_prompt.scss rename src/plugins/index_pattern_management/public/components/{create_index_pattern_wizard/components/empty_state/empty_state.test.tsx => index_pattern_table/empty_index_pattern_prompt/empty_index_pattern_prompt.test.tsx} (57%) create mode 100644 src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/empty_index_pattern_prompt.tsx create mode 100644 src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/index.tsx create mode 100644 src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/__snapshots__/empty_state.test.tsx.snap create mode 100644 src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/empty_state.scss create mode 100644 src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/empty_state.test.tsx create mode 100644 src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/empty_state.tsx rename src/plugins/index_pattern_management/public/components/{create_index_pattern_wizard/components => index_pattern_table}/empty_state/index.ts (100%) create mode 100644 src/plugins/index_pattern_management/public/service/environment/environment.mock.ts create mode 100644 src/plugins/index_pattern_management/public/service/environment/environment.test.ts create mode 100644 src/plugins/index_pattern_management/public/service/environment/environment.ts create mode 100644 src/plugins/index_pattern_management/public/service/environment/index.ts create mode 100644 test/functional/apps/management/_index_patterns_empty.ts diff --git a/.sass-lint.yml b/.sass-lint.yml index d6eaaf391de1a..9eed50602f520 100644 --- a/.sass-lint.yml +++ b/.sass-lint.yml @@ -1,6 +1,7 @@ files: include: - 'src/legacy/core_plugins/metrics/**/*.s+(a|c)ss' + - 'src/plugins/index_pattern_management/**/*.s+(a|c)ss' - 'src/plugins/timelion/**/*.s+(a|c)ss' - 'src/plugins/vis_type_vislib/**/*.s+(a|c)ss' - 'src/plugins/vis_type_vega/**/*.s+(a|c)ss' diff --git a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md index a03b1b74fc1ac..842f90b7047c8 100644 --- a/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md +++ b/docs/development/core/public/kibana-plugin-core-public.doclinksstart.links.md @@ -81,6 +81,7 @@ readonly links: { readonly loadingData: string; readonly introduction: string; }; + readonly addData: string; readonly kibana: string; readonly siem: { readonly guide: string; diff --git a/docs/setup/connect-to-elasticsearch.asciidoc b/docs/setup/connect-to-elasticsearch.asciidoc index bffb3f97cd1b9..f750784c47043 100644 --- a/docs/setup/connect-to-elasticsearch.asciidoc +++ b/docs/setup/connect-to-elasticsearch.asciidoc @@ -97,7 +97,7 @@ Using a wildcard is the more popular approach. comparisons. + Kibana reads the index mapping and lists all fields that contain a timestamp. If your -index doesn't have time-based data, choose *I don't want to use the Time Filter*. +index doesn't have time-based data, choose *I don't want to use the time filter*. + You must select a time field to use global time filters on your dashboards. diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index eb54983d0be13..8853d95181994 100644 --- a/src/core/public/doc_links/doc_links_service.ts +++ b/src/core/public/doc_links/doc_links_service.ts @@ -109,6 +109,7 @@ export class DocLinksService { loadingData: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/tutorial-load-dataset.html`, introduction: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/index-patterns.html`, }, + addData: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/connect-to-elasticsearch.html`, kibana: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/index.html`, siem: { guide: `${ELASTIC_WEBSITE_URL}guide/en/security/${DOC_LINK_VERSION}/index.html`, @@ -209,6 +210,7 @@ export interface DocLinksStart { readonly loadingData: string; readonly introduction: string; }; + readonly addData: string; readonly kibana: string; readonly siem: { readonly guide: string; diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index 9b421e0172df0..0e879d16b4637 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -576,6 +576,7 @@ export interface DocLinksStart { readonly loadingData: string; readonly introduction: string; }; + readonly addData: string; readonly kibana: string; readonly siem: { readonly guide: string; diff --git a/src/plugins/data/public/index_patterns/index_patterns/redirect_no_index_pattern.tsx b/src/plugins/data/public/index_patterns/index_patterns/redirect_no_index_pattern.tsx index 7ed6525db6350..ac015f8dd33af 100644 --- a/src/plugins/data/public/index_patterns/index_patterns/redirect_no_index_pattern.tsx +++ b/src/plugins/data/public/index_patterns/index_patterns/redirect_no_index_pattern.tsx @@ -40,7 +40,7 @@ export const onRedirectNoIndexPattern = ( const bannerMessage = i18n.translate('data.indexPatterns.ensureDefaultIndexPattern.bannerLabel', { defaultMessage: - "In order to visualize and explore data in Kibana, you'll need to create an index pattern to retrieve data from Elasticsearch.", + 'To visualize and explore data in Kibana, you must create an index pattern to retrieve data from Elasticsearch.', }); // Avoid being hostile to new users who don't have an index pattern setup yet diff --git a/src/plugins/index_pattern_management/public/_templates.scss b/src/plugins/index_pattern_management/public/_templates.scss new file mode 100644 index 0000000000000..5303537bddabc --- /dev/null +++ b/src/plugins/index_pattern_management/public/_templates.scss @@ -0,0 +1,11 @@ +%inp-empty-state-footer { + background: $euiColorLightestShade; + margin: 0 (-$euiSizeL) (-$euiSizeL); + padding: $euiSizeL; + border-radius: 0 0 $euiBorderRadius $euiBorderRadius; + + // sass-lint:disable-block mixins-before-declarations + @include euiBreakpoint('xs', 's') { + text-align: center; + } +} diff --git a/src/plugins/index_pattern_management/public/_variables.scss b/src/plugins/index_pattern_management/public/_variables.scss new file mode 100644 index 0000000000000..5da25a91bd77c --- /dev/null +++ b/src/plugins/index_pattern_management/public/_variables.scss @@ -0,0 +1 @@ +$inpEmptyStateMaxWidth: $euiSizeXXL * 19; diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_prompt/index.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_prompt/index.tsx deleted file mode 100644 index ab3b90177bcfd..0000000000000 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_prompt/index.tsx +++ /dev/null @@ -1,108 +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 { - EuiDescriptionList, - EuiDescriptionListDescription, - EuiDescriptionListTitle, - EuiFlyout, - EuiFlyoutBody, - EuiFlyoutHeader, - EuiHorizontalRule, - EuiSpacer, - EuiText, -} from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import React from 'react'; - -export const CreateIndexPatternPrompt = ({ onClose }: { onClose: () => void }) => ( - - - -

- -

-
-
- - -

- -

-
- - -

- -

-
- - - - - - - - - - - - - - - - - - - - - -
-
-); diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/__snapshots__/create_index_pattern_wizard.test.tsx.snap b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/__snapshots__/create_index_pattern_wizard.test.tsx.snap index 6d79515c172fe..0e5fc0582f72c 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/__snapshots__/create_index_pattern_wizard.test.tsx.snap +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/__snapshots__/create_index_pattern_wizard.test.tsx.snap @@ -62,10 +62,37 @@ exports[`CreateIndexPatternWizard renders index pattern step when there are indi exports[`CreateIndexPatternWizard renders the empty state when there are no indices 1`] = ` - + +
+ + + - + +
+ + + - - } - > -

- - - , - "learnHowLink": - - , - "needToIndex": - - , - } - } - /> -

- - - -
- -`; diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/empty_state/empty_state.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/empty_state/empty_state.tsx deleted file mode 100644 index 43c3bf79026fe..0000000000000 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/empty_state/empty_state.tsx +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import React from 'react'; - -import { EuiCallOut, EuiTextColor, EuiLink, EuiButton } from '@elastic/eui'; - -import { FormattedMessage } from '@kbn/i18n/react'; -import { IBasePath } from 'kibana/public'; - -export const EmptyState = ({ - onRefresh, - prependBasePath, -}: { - onRefresh: () => void; - prependBasePath: IBasePath['prepend']; -}) => ( -
- - } - > -

- - - - ), - learnHowLink: ( - - - - ), - getStartedLink: ( - - - - ), - }} - /> -

- - - - -
-
-); diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/header/__snapshots__/header.test.tsx.snap b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/header/__snapshots__/header.test.tsx.snap index c4f735558b1f2..851e5cc4c2a76 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/header/__snapshots__/header.test.tsx.snap +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/header/__snapshots__/header.test.tsx.snap @@ -7,7 +7,7 @@ exports[`Header should mark the input as invalid 1`] = ` >

@@ -119,7 +119,7 @@ exports[`Header should render normally 1`] = ` >

diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/header/header.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/header/header.tsx index f1bf0d54a1cbf..8efa44decf3c6 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/header/header.tsx +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/header/header.tsx @@ -66,7 +66,7 @@ export const Header: React.FC = ({

@@ -127,6 +127,7 @@ export const Header: React.FC = ({ id="checkboxShowSystemIndices" checked={isIncludingSystemIndices} onChange={onChangeIncludingSystemIndices} + data-test-subj="showSystemAndHiddenIndices" /> ) : null} diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/indices_list/__snapshots__/indices_list.test.tsx.snap b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/indices_list/__snapshots__/indices_list.test.tsx.snap index 598de4d90e893..6631a9bbd1d02 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/indices_list/__snapshots__/indices_list.test.tsx.snap +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/indices_list/__snapshots__/indices_list.test.tsx.snap @@ -2,7 +2,10 @@ exports[`IndicesList should change pages 1`] = `
- + - + - + - + - + - + {rows} diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/loading_indices/__snapshots__/loading_indices.test.tsx.snap b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/loading_indices/__snapshots__/loading_indices.test.tsx.snap index 9d67ca913d415..a5517f6d4b616 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/loading_indices/__snapshots__/loading_indices.test.tsx.snap +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/loading_indices/__snapshots__/loading_indices.test.tsx.snap @@ -3,47 +3,33 @@ exports[`LoadingIndices should render normally 1`] = ` - - - - - - - - - - - - +

+ + + + `; diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/loading_indices/loading_indices.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/loading_indices/loading_indices.tsx index 16e8d1a9f3e98..82603fd598596 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/loading_indices/loading_indices.tsx +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/loading_indices/loading_indices.tsx @@ -19,34 +19,30 @@ import React from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiText, EuiTextColor, EuiLoadingSpinner } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiTitle, EuiLoadingSpinner } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; export const LoadingIndices = ({ ...rest }) => ( - + - - - - - - + +

- - - - - - - - +

+
+
+ +
); diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/status_message/status_message.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/status_message/status_message.tsx index 22b75071b93bb..c2c4c84b51683 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/status_message/status_message.tsx +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/components/status_message/status_message.tsx @@ -132,7 +132,7 @@ export const StatusMessage: React.FC = ({ /> ); - } else if (allIndicesLength) { + } else { statusIcon = undefined; statusColor = 'warning'; statusMessage = ( diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.tsx index fab638509313d..d8555d71d6ec0 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.tsx +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_index_pattern/step_index_pattern.tsx @@ -159,7 +159,7 @@ export class StepIndexPattern extends Component indexPatternCreationType.getIndexTags(indexName), query, this.state.isIncludingSystemIndices ) @@ -175,13 +175,13 @@ export class StepIndexPattern extends Component indexPatternCreationType.getIndexTags(indexName), `${query}*`, this.state.isIncludingSystemIndices ), getIndices( this.context.services.http, - indexPatternCreationType, + (indexName: string) => indexPatternCreationType.getIndexTags(indexName), query, this.state.isIncludingSystemIndices ), @@ -227,7 +227,13 @@ export class StepIndexPattern extends Component; + return ( + <> + + + + + ); } renderStatusMessage(matchedIndices: { diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/advanced_options/__snapshots__/advanced_options.test.tsx.snap b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/advanced_options/__snapshots__/advanced_options.test.tsx.snap index d1b10fb532020..a2d2023ea0601 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/advanced_options/__snapshots__/advanced_options.test.tsx.snap +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/advanced_options/__snapshots__/advanced_options.test.tsx.snap @@ -7,7 +7,7 @@ exports[`AdvancedOptions should hide if not showing 1`] = ` onClick={[Function]} > @@ -25,7 +25,7 @@ exports[`AdvancedOptions should render normally 1`] = ` onClick={[Function]} > diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/advanced_options/advanced_options.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/advanced_options/advanced_options.tsx index b8f34095743ba..752fcbcd42b5c 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/advanced_options/advanced_options.tsx +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/advanced_options/advanced_options.tsx @@ -45,12 +45,12 @@ export const AdvancedOptions: React.FC = ({ {isVisible ? ( ) : ( )} diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/header/__snapshots__/header.test.tsx.snap b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/header/__snapshots__/header.test.tsx.snap index 2ac243780b31d..9efda4fdac7f9 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/header/__snapshots__/header.test.tsx.snap +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/header/__snapshots__/header.test.tsx.snap @@ -17,9 +17,18 @@ exports[`Header should render normally 1`] = ` size="m" /> - - ki* - + + ki* + , + "indexPatternName": "ki*", + } + } + /> `; diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/header/header.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/header/header.tsx index c17b356e159f6..530d0688b61ca 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/header/header.tsx +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/header/header.tsx @@ -40,7 +40,14 @@ export const Header: React.FC = ({ indexPattern, indexPatternName } - {indexPattern} + {indexPattern}, + indexPatternName, + }} + /> ); diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/time_field/time_field.scss b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/time_field/time_field.scss deleted file mode 100644 index 5bd60e8b76afc..0000000000000 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/time_field/time_field.scss +++ /dev/null @@ -1,7 +0,0 @@ -/** - * 1. Bring the line-height down or else this link expands its container when it becomes visible. - */ - -.timeFieldRefreshButton { - line-height: 1 !important; /* 1 */ -} diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/time_field/time_field.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/time_field/time_field.tsx index 7a3d72551f464..1eae1055ac5ef 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/time_field/time_field.tsx +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/step_time_field/components/time_field/time_field.tsx @@ -17,8 +17,6 @@ * under the License. */ -import './time_field.scss'; - import React from 'react'; import { diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.test.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.test.tsx index b14cd526d7e27..af5618424bbc0 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.test.tsx +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.test.tsx @@ -27,7 +27,6 @@ jest.mock('./components/step_index_pattern', () => ({ StepIndexPattern: 'StepInd jest.mock('./components/step_time_field', () => ({ StepTimeField: 'StepTimeField' })); jest.mock('./components/header', () => ({ Header: 'Header' })); jest.mock('./components/loading_state', () => ({ LoadingState: 'LoadingState' })); -jest.mock('./components/empty_state', () => ({ EmptyState: 'EmptyState' })); jest.mock('./lib/get_indices', () => ({ getIndices: () => { return [{ name: 'kibana' }]; diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx index cd76ca09ccb74..a789ebbfadbce 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/create_index_pattern_wizard.tsx @@ -33,7 +33,6 @@ import { StepIndexPattern } from './components/step_index_pattern'; import { StepTimeField } from './components/step_time_field'; import { Header } from './components/header'; import { LoadingState } from './components/loading_state'; -import { EmptyState } from './components/empty_state'; import { context as contextType } from '../../../../kibana_react/public'; import { getCreateBreadcrumbs } from '../breadcrumbs'; @@ -125,7 +124,13 @@ export class CreateIndexPatternWizard extends Component< // query local and remote indices, updating state independently ensureMinimumTime( this.catchAndWarn( - getIndices(this.context.services.http, this.state.indexPatternCreationType, `*`, false), + getIndices( + this.context.services.http, + (indexName: string) => this.state.indexPatternCreationType.getIndexTags(indexName), + `*`, + false + ), + [], indicesFailMsg ) @@ -136,7 +141,13 @@ export class CreateIndexPatternWizard extends Component< this.catchAndWarn( // if we get an error from remote cluster query, supply fallback value that allows user entry. // ['a'] is fallback value - getIndices(this.context.services.http, this.state.indexPatternCreationType, `*:*`, false), + getIndices( + this.context.services.http, + (indexName: string) => this.state.indexPatternCreationType.getIndexTags(indexName), + `*:*`, + false + ), + ['a'], clustersFailMsg ).then((remoteIndices: string[] | MatchedItem[]) => @@ -200,39 +211,24 @@ export class CreateIndexPatternWizard extends Component< }; renderHeader() { + const { docLinks, indexPatternCreationType } = this.state; return (
); } renderContent() { - const { - allIndices, - isInitiallyLoadingIndices, - step, - indexPattern, - remoteClustersExist, - } = this.state; + const { allIndices, isInitiallyLoadingIndices, step, indexPattern } = this.state; if (isInitiallyLoadingIndices) { return ; } - const hasDataIndices = allIndices.some(({ name }: MatchedItem) => !name.startsWith('.')); - if (!hasDataIndices && !remoteClustersExist) { - return ( - - ); - } - const header = this.renderHeader(); if (step === 1) { diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/extract_time_fields.test.ts b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/extract_time_fields.test.ts index 4cd28090420a7..8f3765b7b5dcc 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/extract_time_fields.test.ts +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/extract_time_fields.test.ts @@ -37,7 +37,7 @@ describe('extractTimeFields', () => { expect(extractTimeFields(fields)).toEqual([ { display: '@timestamp', fieldName: '@timestamp' }, { isDisabled: true, display: '───', fieldName: '' }, - { display: `I don't want to use the Time Filter`, fieldName: undefined }, + { display: `I don't want to use the time filter`, fieldName: undefined }, ]); }); }); diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/extract_time_fields.ts b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/extract_time_fields.ts index b7056ad17343a..efac21245c257 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/extract_time_fields.ts +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/extract_time_fields.ts @@ -45,7 +45,7 @@ export function extractTimeFields(fields: IFieldType[]) { const noTimeFieldLabel = i18n.translate( 'indexPatternManagement.createIndexPattern.stepTime.noTimeFieldOptionLabel', { - defaultMessage: "I don't want to use the Time Filter", + defaultMessage: "I don't want to use the time filter", } ); const noTimeFieldOption = { diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_indices.test.ts b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_indices.test.ts index 8e4dd37284333..44a2d1a3be0d0 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_indices.test.ts +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_indices.test.ts @@ -18,7 +18,6 @@ */ import { getIndices, responseToItemArray } from './get_indices'; -import { IndexPatternCreationConfig } from '../../../../../index_pattern_management/public'; import { httpServiceMock } from '../../../../../../core/public/mocks'; import { ResolveIndexResponseItemIndexAttrs } from '../types'; @@ -44,33 +43,27 @@ export const successfulResponse = { ], }; -const mockIndexPatternCreationType = new IndexPatternCreationConfig({ - type: 'default', - name: 'name', - showSystemIndices: false, - httpClient: {}, - isBeta: false, -}); +const mockGetTags = () => []; const http = httpServiceMock.createStartContract(); http.get.mockResolvedValue(successfulResponse); describe('getIndices', () => { it('should work in a basic case', async () => { - const result = await getIndices(http, mockIndexPatternCreationType, 'kibana', false); + const result = await getIndices(http, mockGetTags, 'kibana', false); expect(result.length).toBe(3); expect(result[0].name).toBe('f-alias'); expect(result[1].name).toBe('foo'); }); it('should ignore ccs query-all', async () => { - expect((await getIndices(http, mockIndexPatternCreationType, '*:', false)).length).toBe(0); + expect((await getIndices(http, mockGetTags, '*:', false)).length).toBe(0); }); it('should ignore a single comma', async () => { - expect((await getIndices(http, mockIndexPatternCreationType, ',', false)).length).toBe(0); - expect((await getIndices(http, mockIndexPatternCreationType, ',*', false)).length).toBe(0); - expect((await getIndices(http, mockIndexPatternCreationType, ',foobar', false)).length).toBe(0); + expect((await getIndices(http, mockGetTags, ',', false)).length).toBe(0); + expect((await getIndices(http, mockGetTags, ',*', false)).length).toBe(0); + expect((await getIndices(http, mockGetTags, ',foobar', false)).length).toBe(0); }); it('response object to item array', () => { @@ -98,8 +91,8 @@ describe('getIndices', () => { }, ], }; - expect(responseToItemArray(result, mockIndexPatternCreationType)).toMatchSnapshot(); - expect(responseToItemArray({}, mockIndexPatternCreationType)).toEqual([]); + expect(responseToItemArray(result, mockGetTags)).toMatchSnapshot(); + expect(responseToItemArray({}, mockGetTags)).toEqual([]); }); describe('errors', () => { @@ -107,7 +100,7 @@ describe('getIndices', () => { http.get.mockImplementationOnce(() => { throw new Error('Test error'); }); - const result = await getIndices(http, mockIndexPatternCreationType, 'kibana', false); + const result = await getIndices(http, mockGetTags, 'kibana', false); expect(result.length).toBe(0); }); }); diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_indices.ts b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_indices.ts index c6a11de1bc4fc..6844e90316e22 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_indices.ts +++ b/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/lib/get_indices.ts @@ -38,7 +38,7 @@ const frozenLabel = i18n.translate('indexPatternManagement.frozenLabel', { export async function getIndices( http: HttpStart, - indexPatternCreationType: IndexPatternCreationConfig, + getIndexTags: IndexPatternCreationConfig['getIndexTags'], rawPattern: string, showAllIndices: boolean ): Promise { @@ -73,7 +73,7 @@ export async function getIndices( return []; } - return responseToItemArray(response, indexPatternCreationType); + return responseToItemArray(response, getIndexTags); } catch { return []; } @@ -81,7 +81,7 @@ export async function getIndices( export const responseToItemArray = ( response: ResolveIndexResponse, - indexPatternCreationType: IndexPatternCreationConfig + getIndexTags: IndexPatternCreationConfig['getIndexTags'] ): MatchedItem[] => { const source: MatchedItem[] = []; @@ -89,7 +89,7 @@ export const responseToItemArray = ( const tags: MatchedItem['tags'] = [{ key: 'index', name: indexLabel, color: 'default' }]; const isFrozen = (index.attributes || []).includes(ResolveIndexResponseItemIndexAttrs.FROZEN); - tags.push(...indexPatternCreationType.getIndexTags(index.name)); + tags.push(...getIndexTags(index.name)); if (isFrozen) { tags.push({ name: frozenLabel, key: 'frozen', color: 'danger' }); } diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx b/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx index 4b538af7c5fe7..987e8f0dae3a0 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx @@ -27,7 +27,6 @@ import { EuiBadge, EuiText, EuiLink, - EuiIcon, EuiCallOut, EuiPanel, } from '@elastic/eui'; @@ -162,7 +161,7 @@ export const EditIndexPattern = withRouter( const timeFilterHeader = i18n.translate( 'indexPatternManagement.editIndexPattern.timeFilterHeader', { - defaultMessage: "Time Filter field name: '{timeFieldName}'", + defaultMessage: "Time field: '{timeFieldName}'", values: { timeFieldName: indexPattern.timeFieldName }, } ); @@ -187,62 +186,55 @@ export const EditIndexPattern = withRouter( return (
- - - - - {showTagsSection && ( - - {Boolean(indexPattern.timeFieldName) && ( - - {timeFilterHeader} - - )} - {tags.map((tag: any) => ( - - {tag.name} - - ))} - + + + {showTagsSection && ( + + {Boolean(indexPattern.timeFieldName) && ( + + {timeFilterHeader} + )} - - -

- {indexPattern.title} }} - />{' '} - - {mappingAPILink} - - -

-
- {conflictedFields.length > 0 && ( - -

{mappingConflictLabel}

-
- )} -
- - - -
+ {tags.map((tag: any) => ( + + {tag.name} + + ))} + + )} + + +

+ {indexPattern.title} }} + />{' '} + + {mappingAPILink} + +

+
+ {conflictedFields.length > 0 && ( + <> + + +

{mappingConflictLabel}

+
+ + )} + +
); diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx b/src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx index 4cf43d63d5839..8ca8c6453c7e9 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/index_header/index_header.tsx @@ -19,14 +19,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { - EuiFlexGroup, - EuiToolTip, - EuiFlexItem, - EuiIcon, - EuiTitle, - EuiButtonIcon, -} from '@elastic/eui'; +import { EuiFlexGroup, EuiToolTip, EuiFlexItem, EuiTitle, EuiButtonIcon } from '@elastic/eui'; import { IIndexPattern } from 'src/plugins/data/public'; interface IndexHeaderProps { @@ -77,22 +70,13 @@ export function IndexHeader({ return ( - - {defaultIndex === indexPattern.id && ( - - - - )} - - -

{indexPattern.title}

-
-
-
+ +

{indexPattern.title}

+
- - {setDefault && ( + + {defaultIndex !== indexPattern.id && setDefault && ( setFieldFilter(e.target.value)} diff --git a/src/plugins/index_pattern_management/public/components/field_editor/components/scripting_help/test_script.scss b/src/plugins/index_pattern_management/public/components/field_editor/components/scripting_help/test_script.scss index 34e8a60d07074..ca230711827dc 100644 --- a/src/plugins/index_pattern_management/public/components/field_editor/components/scripting_help/test_script.scss +++ b/src/plugins/index_pattern_management/public/components/field_editor/components/scripting_help/test_script.scss @@ -1,5 +1,5 @@ .testScript__searchBar { - .globalQueryBar { + .globalQueryBar { padding: $euiSize 0 0; } } diff --git a/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/__snapshots__/empty_index_pattern_prompt.test.tsx.snap b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/__snapshots__/empty_index_pattern_prompt.test.tsx.snap new file mode 100644 index 0000000000000..c5e6d1220d8bf --- /dev/null +++ b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/__snapshots__/empty_index_pattern_prompt.test.tsx.snap @@ -0,0 +1,99 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`EmptyIndexPatternPrompt should render normally 1`] = ` + + + + + + + +

+ +
+ +

+

+ +

+ + + +
+
+
+ + + + + + + + + + + +
+`; diff --git a/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/assets/index_pattern_illustration.scss b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/assets/index_pattern_illustration.scss new file mode 100644 index 0000000000000..cd0477aba7adf --- /dev/null +++ b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/assets/index_pattern_illustration.scss @@ -0,0 +1,9 @@ +.indexPatternIllustration { + &__verticalStripes { + fill: $euiColorFullShade; + } + + &__dots { + fill: $euiColorLightShade; + } +} diff --git a/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/assets/index_pattern_illustration.tsx b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/assets/index_pattern_illustration.tsx new file mode 100644 index 0000000000000..2461c0f5df919 --- /dev/null +++ b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/assets/index_pattern_illustration.tsx @@ -0,0 +1,551 @@ +/* + * 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 './index_pattern_illustration.scss'; +import React from 'react'; + +const IndexPatternIllustration = () => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +); + +export const Illustration = IndexPatternIllustration; diff --git a/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/empty_index_pattern_prompt.scss b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/empty_index_pattern_prompt.scss new file mode 100644 index 0000000000000..11ac55b098a57 --- /dev/null +++ b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/empty_index_pattern_prompt.scss @@ -0,0 +1,31 @@ +@import '../../../variables'; +@import '../../../templates'; + +.inpEmptyIndexPatternPrompt { + // override EUI specificity + max-width: $inpEmptyStateMaxWidth !important; // sass-lint:disable-line no-important +} + +.inpEmptyIndexPatternPrompt__footer { + @extend %inp-empty-state-footer; + // override EUI specificity + align-items: baseline !important; // sass-lint:disable-line no-important +} + +.inpEmptyIndexPatternPrompt__title { + // override EUI specificity + width: auto !important; // sass-lint:disable-line no-important +} + +@include euiBreakpoint('xs', 's') { + .inpEmptyIndexPatternPrompt__illustration > svg { + width: $euiSize * 12; + height: auto; + margin: 0 auto; + } + + .inpEmptyIndexPatternPrompt__text { + text-align: center; + align-items: center; + } +} diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/empty_state/empty_state.test.tsx b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/empty_index_pattern_prompt.test.tsx similarity index 57% rename from src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/empty_state/empty_state.test.tsx rename to src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/empty_index_pattern_prompt.test.tsx index 7fa39363e3ef7..83eb803333afc 100644 --- a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/empty_state/empty_state.test.tsx +++ b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/empty_index_pattern_prompt.test.tsx @@ -18,30 +18,20 @@ */ import React from 'react'; -import { EmptyState } from '../empty_state'; -import { shallow } from 'enzyme'; -import sinon from 'sinon'; +import { EmptyIndexPatternPrompt } from '../empty_index_pattern_prompt'; +import { shallowWithI18nProvider } from 'test_utils/enzyme_helpers'; -describe('EmptyState', () => { +describe('EmptyIndexPatternPrompt', () => { it('should render normally', () => { - const component = shallow( {}} prependBasePath={(x) => x} />); + const component = shallowWithI18nProvider( + {} }]} + docLinksIndexPatternIntro={'testUrl'} + setBreadcrumbs={() => {}} + /> + ); expect(component).toMatchSnapshot(); }); - - describe('props', () => { - describe('onRefresh', () => { - it('is called when refresh button is clicked', () => { - const onRefreshHandler = sinon.stub(); - - const component = shallow( - x} /> - ); - - component.find('[data-test-subj="refreshIndicesButton"]').simulate('click'); - - sinon.assert.calledOnce(onRefreshHandler); - }); - }); - }); }); diff --git a/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/empty_index_pattern_prompt.tsx b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/empty_index_pattern_prompt.tsx new file mode 100644 index 0000000000000..de389097fd4ba --- /dev/null +++ b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/empty_index_pattern_prompt.tsx @@ -0,0 +1,111 @@ +/* + * 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 './empty_index_pattern_prompt.scss'; + +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { EuiPageContent, EuiSpacer, EuiText, EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; +import { EuiDescriptionListTitle } from '@elastic/eui'; +import { EuiDescriptionListDescription, EuiDescriptionList } from '@elastic/eui'; +import { EuiLink } from '@elastic/eui'; +import { getListBreadcrumbs } from '../../breadcrumbs'; +import { IndexPatternCreationOption } from '../../types'; +import { CreateButton } from '../../create_button'; +import { Illustration } from './assets/index_pattern_illustration'; +import { ManagementAppMountParams } from '../../../../../management/public'; + +interface Props { + canSave: boolean; + creationOptions: IndexPatternCreationOption[]; + docLinksIndexPatternIntro: string; + setBreadcrumbs: ManagementAppMountParams['setBreadcrumbs']; +} + +export const EmptyIndexPatternPrompt = ({ + canSave, + creationOptions, + docLinksIndexPatternIntro, + setBreadcrumbs, +}: Props) => { + setBreadcrumbs(getListBreadcrumbs()); + + return ( + + + + + + + +

+ +
+ +

+

+ +

+ {canSave && ( + + + + )} +
+
+
+ + + + + + + + + + + +
+ ); +}; diff --git a/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/index.tsx b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/index.tsx new file mode 100644 index 0000000000000..239bb272b23ab --- /dev/null +++ b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_index_pattern_prompt/index.tsx @@ -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 { EmptyIndexPatternPrompt } from './empty_index_pattern_prompt'; diff --git a/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/__snapshots__/empty_state.test.tsx.snap b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/__snapshots__/empty_state.test.tsx.snap new file mode 100644 index 0000000000000..645694371f905 --- /dev/null +++ b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/__snapshots__/empty_state.test.tsx.snap @@ -0,0 +1,216 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`EmptyState should render normally 1`] = ` + + + + + +

+ +

+
+
+
+ + + + + + } + icon={ + + } + onClick={[Function]} + title={ + + } + /> + + + + } + icon={ + + } + isDisabled={false} + onClick={[Function]} + title={ + + } + /> + + + + } + icon={ + + } + onClick={[Function]} + title={ + + } + /> + + + +
+ + + + + , + "title": , + }, + ] + } + /> + + + + + + + , + "title": , + }, + ] + } + /> + + +
+
+
+ + + + + , + } + } + /> + +
+`; diff --git a/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/empty_state.scss b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/empty_state.scss new file mode 100644 index 0000000000000..37889b9d7c483 --- /dev/null +++ b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/empty_state.scss @@ -0,0 +1,23 @@ +@import '../../../variables'; +@import '../../../templates'; + +.inpEmptyState { + // override EUI specificity + max-width: $inpEmptyStateMaxWidth !important; // sass-lint:disable-line no-important +} + +.inpEmptyState__cardGrid { + justify-content: center; +} + +.inpEmptyState__card { + min-width: $euiSizeXL * 6; +} + +.inpEmptyState__footer { + @extend %inp-empty-state-footer; +} + +.inpEmptyState__footerFlexItem { + min-width: $euiSizeXL * 7; +} diff --git a/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/empty_state.test.tsx b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/empty_state.test.tsx new file mode 100644 index 0000000000000..7b2cc0f4c3c60 --- /dev/null +++ b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/empty_state.test.tsx @@ -0,0 +1,74 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { EmptyState } from '../empty_state'; +import { shallow } from 'enzyme'; +import sinon from 'sinon'; +// @ts-expect-error +import { findTestSubject } from '@elastic/eui/lib/test'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { docLinksServiceMock } from '../../../../../../core/public/mocks'; +import { MlCardState } from '../../../types'; + +const docLinks = docLinksServiceMock.createStartContract(); + +jest.mock('react-router-dom', () => ({ + useHistory: () => ({ + createHref: jest.fn(), + }), +})); + +describe('EmptyState', () => { + it('should render normally', () => { + const component = shallow( + {}} + navigateToApp={async () => {}} + getMlCardState={() => MlCardState.ENABLED} + canSave={true} + /> + ); + + expect(component).toMatchSnapshot(); + }); + + describe('props', () => { + describe('onRefresh', () => { + it('is called when refresh button is clicked', () => { + const onRefreshHandler = sinon.stub(); + + const component = mountWithIntl( + {}} + getMlCardState={() => MlCardState.ENABLED} + canSave={true} + /> + ); + + findTestSubject(component, 'refreshIndicesButton').simulate('click'); + + sinon.assert.calledOnce(onRefreshHandler); + }); + }); + }); +}); diff --git a/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/empty_state.tsx b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/empty_state.tsx new file mode 100644 index 0000000000000..e758184f0f14b --- /dev/null +++ b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/empty_state.tsx @@ -0,0 +1,234 @@ +/* + * 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 './empty_state.scss'; +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { DocLinksStart, ApplicationStart } from 'kibana/public'; +import { + EuiPageContentHeader, + EuiPageContentHeaderSection, + EuiTitle, + EuiPageContentBody, + EuiPageContent, + EuiIcon, + EuiSpacer, + EuiFlexItem, + EuiDescriptionList, + EuiFlexGrid, + EuiCard, + EuiLink, + EuiText, +} from '@elastic/eui'; +import { useHistory } from 'react-router-dom'; +import { reactRouterNavigate } from '../../../../../../plugins/kibana_react/public'; +import { MlCardState } from '../../../types'; + +export const EmptyState = ({ + onRefresh, + navigateToApp, + docLinks, + getMlCardState, + canSave, +}: { + onRefresh: () => void; + navigateToApp: ApplicationStart['navigateToApp']; + docLinks: DocLinksStart; + getMlCardState: () => MlCardState; + canSave: boolean; +}) => { + const mlCard = ( + + navigateToApp('ml', { path: '#/filedatavisualizer' })} + className="inpEmptyState__card" + betaBadgeLabel={ + getMlCardState() === MlCardState.ENABLED + ? undefined + : i18n.translate( + 'indexPatternManagement.createIndexPattern.emptyState.basicLicenseLabel', + { + defaultMessage: 'Basic', + } + ) + } + betaBadgeTooltipContent={i18n.translate( + 'indexPatternManagement.createIndexPattern.emptyState.basicLicenseDescription', + { + defaultMessage: 'This feature requires a Basic license.', + } + )} + isDisabled={getMlCardState() === MlCardState.DISABLED} + icon={} + title={ + + } + description={ + + } + /> + + ); + + const createAnyway = ( + + + + + ), + }} + /> + + ); + + return ( + <> + + + + +

+ +

+
+
+
+ + + + + navigateToApp('home', { path: '#/tutorial_directory' })} + icon={} + title={ + + } + description={ + + } + /> + + {getMlCardState() !== MlCardState.HIDDEN ? mlCard : <>} + + navigateToApp('home', { path: '#/tutorial_directory/sampleData' })} + icon={} + title={ + + } + description={ + + } + /> + + + +
+ + + + ), + description: ( + + + + ), + }, + ]} + /> + + + + ), + description: ( + + {' '} + + + ), + }, + ]} + /> + + +
+
+
+ + {canSave && createAnyway} + + ); +}; diff --git a/src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/empty_state/index.ts b/src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/index.ts similarity index 100% rename from src/plugins/index_pattern_management/public/components/create_index_pattern_wizard/components/empty_state/index.ts rename to src/plugins/index_pattern_management/public/components/index_pattern_table/empty_state/index.ts diff --git a/src/plugins/index_pattern_management/public/components/index_pattern_table/index_pattern_table.tsx b/src/plugins/index_pattern_management/public/components/index_pattern_table/index_pattern_table.tsx index 947882b8df495..2768314a75860 100644 --- a/src/plugins/index_pattern_management/public/components/index_pattern_table/index_pattern_table.tsx +++ b/src/plugins/index_pattern_management/public/components/index_pattern_table/index_pattern_table.tsx @@ -20,14 +20,14 @@ import { EuiBadge, EuiButtonEmpty, - EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiInMemoryTable, - EuiPanel, EuiSpacer, EuiText, EuiBadgeGroup, + EuiPageContent, + EuiTitle, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { withRouter, RouteComponentProps } from 'react-router-dom'; @@ -36,10 +36,13 @@ import { i18n } from '@kbn/i18n'; import { reactRouterNavigate, useKibana } from '../../../../../plugins/kibana_react/public'; import { IndexPatternManagmentContext } from '../../types'; import { CreateButton } from '../create_button'; -import { CreateIndexPatternPrompt } from '../create_index_pattern_prompt'; import { IndexPatternTableItem, IndexPatternCreationOption } from '../types'; import { getIndexPatterns } from '../utils'; import { getListBreadcrumbs } from '../breadcrumbs'; +import { EmptyState } from './empty_state'; +import { MatchedItem, ResolveIndexResponseItemAlias } from '../create_index_pattern_wizard/types'; +import { EmptyIndexPatternPrompt } from './empty_index_pattern_prompt'; +import { getIndices } from '../create_index_pattern_wizard/lib'; const pagination = { initialPageSize: 10, @@ -81,13 +84,19 @@ export const IndexPatternTable = ({ canSave, history }: Props) => { uiSettings, indexPatternManagementStart, chrome, + docLinks, + application, + http, + getMlCardState, } = useKibana().services; - const [showFlyout, setShowFlyout] = useState(false); const [indexPatterns, setIndexPatterns] = useState([]); const [creationOptions, setCreationOptions] = useState([]); + const [sources, setSources] = useState([]); + const [remoteClustersExist, setRemoteClustersExist] = useState(false); + const [isLoadingSources, setIsLoadingSources] = useState(true); + const [isLoadingIndexPatterns, setIsLoadingIndexPatterns] = useState(true); setBreadcrumbs(getListBreadcrumbs()); - useEffect(() => { (async function () { const options = await indexPatternManagementStart.creation.getIndexPatternCreationOptions( @@ -98,9 +107,9 @@ export const IndexPatternTable = ({ canSave, history }: Props) => { uiSettings.get('defaultIndex'), indexPatternManagementStart ); + setIsLoadingIndexPatterns(false); setCreationOptions(options); setIndexPatterns(gettedIndexPatterns); - setShowFlyout(gettedIndexPatterns.length === 0); })(); }, [ history.push, @@ -110,6 +119,28 @@ export const IndexPatternTable = ({ canSave, history }: Props) => { savedObjects.client, ]); + const removeAliases = (item: MatchedItem) => + !((item as unknown) as ResolveIndexResponseItemAlias).indices; + + const loadSources = () => { + getIndices(http, () => [], '*', false).then((dataSources) => + setSources(dataSources.filter(removeAliases)) + ); + getIndices(http, () => [], '*:*', false).then((dataSources) => + setRemoteClustersExist(!!dataSources.filter(removeAliases).length) + ); + }; + + useEffect(() => { + getIndices(http, () => [], '*', false).then((dataSources) => { + setSources(dataSources.filter(removeAliases)); + setIsLoadingSources(false); + }); + getIndices(http, () => [], '*:*', false).then((dataSources) => + setRemoteClustersExist(!!dataSources.filter(removeAliases).length) + ); + }, [http, creationOptions]); + chrome.docTitle.change(title); const columns = [ @@ -130,12 +161,11 @@ export const IndexPatternTable = ({ canSave, history }: Props) => { {name} +   {index.tags && index.tags.map(({ key: tagKey, name: tagName }) => ( - - {tagName} - + {tagName} ))} @@ -156,31 +186,51 @@ export const IndexPatternTable = ({ canSave, history }: Props) => { <> ); + if (isLoadingSources || isLoadingIndexPatterns) { + return <>; + } + + const hasDataIndices = sources.some(({ name }: MatchedItem) => !name.startsWith('.')); + + if (!indexPatterns.length) { + if (!hasDataIndices && !remoteClustersExist) { + return ( + + ); + } else { + return ( + + ); + } + } + return ( - - {showFlyout && setShowFlyout(false)} />} + - - - - -

{title}

-
-
- - setShowFlyout(true)} - aria-label="Help" + + +

{title}

+
+ + +

+ - - +

+
{createButton}
@@ -195,7 +245,7 @@ export const IndexPatternTable = ({ canSave, history }: Props) => { sorting={sorting} search={search} /> -
+ ); }; diff --git a/src/plugins/index_pattern_management/public/index.ts b/src/plugins/index_pattern_management/public/index.ts index 2d6db13757eea..9a0fd39fb4fd9 100644 --- a/src/plugins/index_pattern_management/public/index.ts +++ b/src/plugins/index_pattern_management/public/index.ts @@ -41,3 +41,5 @@ export { IndexPatternCreationOption, IndexPatternListConfig, } from './service'; + +export { MlCardState } from './types'; diff --git a/src/plugins/index_pattern_management/public/management_app/mount_management_section.tsx b/src/plugins/index_pattern_management/public/management_app/mount_management_section.tsx index bcabd55c87975..add45a07e0c5f 100644 --- a/src/plugins/index_pattern_management/public/management_app/mount_management_section.tsx +++ b/src/plugins/index_pattern_management/public/management_app/mount_management_section.tsx @@ -34,7 +34,7 @@ import { CreateIndexPatternWizardWithRouter, } from '../components'; import { IndexPatternManagementStartDependencies, IndexPatternManagementStart } from '../plugin'; -import { IndexPatternManagmentContext } from '../types'; +import { IndexPatternManagmentContext, MlCardState } from '../types'; const readOnlyBadge = { text: i18n.translate('indexPatternManagement.indexPatterns.badge.readOnly.text', { @@ -48,7 +48,8 @@ const readOnlyBadge = { export async function mountManagementSection( getStartServices: StartServicesAccessor, - params: ManagementAppMountParams + params: ManagementAppMountParams, + getMlCardState: () => MlCardState ) { const [ { chrome, application, savedObjects, uiSettings, notifications, overlays, http, docLinks }, @@ -73,6 +74,7 @@ export async function mountManagementSection( data, indexPatternManagementStart: indexPatternManagementStart as IndexPatternManagementStart, setBreadcrumbs: params.setBreadcrumbs, + getMlCardState, }; ReactDOM.render( diff --git a/src/plugins/index_pattern_management/public/mocks.ts b/src/plugins/index_pattern_management/public/mocks.ts index ec8100db42085..6a9ef23e3732e 100644 --- a/src/plugins/index_pattern_management/public/mocks.ts +++ b/src/plugins/index_pattern_management/public/mocks.ts @@ -39,6 +39,9 @@ const createSetupContract = (): IndexPatternManagementSetup => ({ getAll: jest.fn(), getById: jest.fn(), } as any, + environment: { + update: jest.fn(), + }, }); const createStartContract = (): IndexPatternManagementStart => ({ diff --git a/src/plugins/index_pattern_management/public/plugin.ts b/src/plugins/index_pattern_management/public/plugin.ts index fe680eff8657e..ee1e00fcafd98 100644 --- a/src/plugins/index_pattern_management/public/plugin.ts +++ b/src/plugins/index_pattern_management/public/plugin.ts @@ -86,7 +86,9 @@ export class IndexPatternManagementPlugin mount: async (params) => { const { mountManagementSection } = await import('./management_app'); - return mountManagementSection(core.getStartServices, params); + return mountManagementSection(core.getStartServices, params, () => + this.indexPatternManagementService.environmentService.getEnvironment().ml() + ); }, }); diff --git a/src/plugins/index_pattern_management/public/service/environment/environment.mock.ts b/src/plugins/index_pattern_management/public/service/environment/environment.mock.ts new file mode 100644 index 0000000000000..2c2c68b8ead2d --- /dev/null +++ b/src/plugins/index_pattern_management/public/service/environment/environment.mock.ts @@ -0,0 +1,44 @@ +/* + * 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 { EnvironmentService, EnvironmentServiceSetup } from './environment'; +import { MlCardState } from '../../types'; + +const createSetupMock = (): jest.Mocked => { + const setup = { + update: jest.fn(), + }; + return setup; +}; + +const createMock = (): jest.Mocked> => { + const service = { + setup: jest.fn(), + getEnvironment: jest.fn(() => ({ + ml: () => MlCardState.ENABLED, + })), + }; + service.setup.mockImplementation(createSetupMock); + return service; +}; + +export const environmentServiceMock = { + createSetup: createSetupMock, + create: createMock, +}; diff --git a/src/plugins/index_pattern_management/public/service/environment/environment.test.ts b/src/plugins/index_pattern_management/public/service/environment/environment.test.ts new file mode 100644 index 0000000000000..1aa67ba751b81 --- /dev/null +++ b/src/plugins/index_pattern_management/public/service/environment/environment.test.ts @@ -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 { EnvironmentService } from './environment'; +import { MlCardState } from '../../types'; + +describe('EnvironmentService', () => { + describe('setup', () => { + test('allows multiple update calls', () => { + const setup = new EnvironmentService().setup(); + expect(() => { + setup.update({ ml: () => MlCardState.ENABLED }); + }).not.toThrow(); + }); + }); + + describe('getEnvironment', () => { + test('returns default values', () => { + const service = new EnvironmentService(); + expect(service.getEnvironment().ml()).toEqual(MlCardState.DISABLED); + }); + + test('returns last state of update calls', () => { + let cardState = MlCardState.DISABLED; + const service = new EnvironmentService(); + const setup = service.setup(); + setup.update({ ml: () => cardState }); + expect(service.getEnvironment().ml()).toEqual(MlCardState.DISABLED); + cardState = MlCardState.ENABLED; + expect(service.getEnvironment().ml()).toEqual(MlCardState.ENABLED); + }); + }); +}); diff --git a/src/plugins/index_pattern_management/public/service/environment/environment.ts b/src/plugins/index_pattern_management/public/service/environment/environment.ts new file mode 100644 index 0000000000000..f40ce3589fa76 --- /dev/null +++ b/src/plugins/index_pattern_management/public/service/environment/environment.ts @@ -0,0 +1,52 @@ +/* + * 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 { MlCardState } from '../../types'; + +/** @public */ +export interface Environment { + /** + * Flag whether ml features should be advertised + */ + readonly ml: () => MlCardState; +} + +export class EnvironmentService { + private environment = { + ml: () => MlCardState.DISABLED, + }; + + public setup() { + return { + /** + * Update the environment to influence how available features are presented. + * @param update + */ + update: (update: Partial) => { + this.environment = Object.assign({}, this.environment, update); + }, + }; + } + + public getEnvironment() { + return this.environment; + } +} + +export type EnvironmentServiceSetup = ReturnType; diff --git a/src/plugins/index_pattern_management/public/service/environment/index.ts b/src/plugins/index_pattern_management/public/service/environment/index.ts new file mode 100644 index 0000000000000..91d14c358e7db --- /dev/null +++ b/src/plugins/index_pattern_management/public/service/environment/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 { EnvironmentService, Environment, EnvironmentServiceSetup } from './environment'; diff --git a/src/plugins/index_pattern_management/public/service/index_pattern_management_service.ts b/src/plugins/index_pattern_management/public/service/index_pattern_management_service.ts index d4cc9c95e76a7..06b9b83b1b601 100644 --- a/src/plugins/index_pattern_management/public/service/index_pattern_management_service.ts +++ b/src/plugins/index_pattern_management/public/service/index_pattern_management_service.ts @@ -21,6 +21,7 @@ import { HttpSetup } from '../../../../core/public'; import { IndexPatternCreationManager, IndexPatternCreationConfig } from './creation'; import { IndexPatternListManager, IndexPatternListConfig } from './list'; import { FieldFormatEditors } from './field_format_editors'; +import { EnvironmentService } from './environment'; import { BytesFormatEditor, @@ -49,11 +50,13 @@ export class IndexPatternManagementService { indexPatternCreationManager: IndexPatternCreationManager; indexPatternListConfig: IndexPatternListManager; fieldFormatEditors: FieldFormatEditors; + environmentService: EnvironmentService; constructor() { this.indexPatternCreationManager = new IndexPatternCreationManager(); this.indexPatternListConfig = new IndexPatternListManager(); this.fieldFormatEditors = new FieldFormatEditors(); + this.environmentService = new EnvironmentService(); } public setup({ httpClient }: SetupDependencies) { @@ -83,6 +86,7 @@ export class IndexPatternManagementService { creation: creationManagerSetup, list: indexPatternListConfigSetup, fieldFormatEditors: fieldFormatEditorsSetup, + environment: this.environmentService.setup(), }; } diff --git a/src/plugins/index_pattern_management/public/types.ts b/src/plugins/index_pattern_management/public/types.ts index 97941687e652d..2876bd6227350 100644 --- a/src/plugins/index_pattern_management/public/types.ts +++ b/src/plugins/index_pattern_management/public/types.ts @@ -44,8 +44,15 @@ export interface IndexPatternManagmentContext { data: DataPublicPluginStart; indexPatternManagementStart: IndexPatternManagementStart; setBreadcrumbs: ManagementAppMountParams['setBreadcrumbs']; + getMlCardState: () => MlCardState; } export type IndexPatternManagmentContextValue = KibanaReactContextValue< IndexPatternManagmentContext >; + +export enum MlCardState { + HIDDEN, + DISABLED, + ENABLED, +} diff --git a/test/functional/apps/management/_index_patterns_empty.ts b/test/functional/apps/management/_index_patterns_empty.ts new file mode 100644 index 0000000000000..4ae2e7836ac37 --- /dev/null +++ b/test/functional/apps/management/_index_patterns_empty.ts @@ -0,0 +1,66 @@ +/* + * 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 { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects(['common', 'settings']); + const testSubjects = getService('testSubjects'); + const globalNav = getService('globalNav'); + const es = getService('legacyEs'); + + describe('index pattern empty view', () => { + before(async () => { + await esArchiver.load('empty_kibana'); + await kibanaServer.uiSettings.replace({}); + await PageObjects.settings.navigateTo(); + }); + + after(async () => { + await esArchiver.unload('empty_kibana'); + await esArchiver.loadIfNeeded('makelogs'); + }); + + // create index pattern and return to verify list + it(`shows empty views`, async () => { + // @ts-expect-error + await es.transport.request({ + path: '/_all', + method: 'DELETE', + }); + await PageObjects.settings.clickKibanaIndexPatterns(); + await testSubjects.existOrFail('createAnyway'); + // @ts-expect-error + await es.transport.request({ + path: '/logstash-a/_doc', + method: 'POST', + body: { user: 'matt', message: 20 }, + }); + await testSubjects.click('refreshIndicesButton'); + await testSubjects.existOrFail('createIndexPatternButton', { timeout: 5000 }); + await PageObjects.settings.createIndexPattern('logstash-*', ''); + }); + + it(`doesn't show read-only badge`, async () => { + await globalNav.badgeMissingOrFail(); + }); + }); +} diff --git a/test/functional/apps/management/_kibana_settings.js b/test/functional/apps/management/_kibana_settings.js index 2a488a94c6889..e2b20bacc0b39 100644 --- a/test/functional/apps/management/_kibana_settings.js +++ b/test/functional/apps/management/_kibana_settings.js @@ -28,7 +28,7 @@ export default function ({ getService, getPageObjects }) { before(async function () { // delete .kibana index and then wait for Kibana to re-create it await kibanaServer.uiSettings.replace({}); - await PageObjects.settings.createIndexPattern(); + await PageObjects.settings.createIndexPattern('logstash-*'); await PageObjects.settings.navigateTo(); }); diff --git a/test/functional/apps/management/index.js b/test/functional/apps/management/index.js index 97e7314f9678e..d5f0c286af7a5 100644 --- a/test/functional/apps/management/index.js +++ b/test/functional/apps/management/index.js @@ -43,6 +43,7 @@ export default function ({ getService, loadTestFile }) { loadTestFile(require.resolve('./_scripted_fields')); loadTestFile(require.resolve('./_scripted_fields_preview')); loadTestFile(require.resolve('./_mgmt_import_saved_objects')); + loadTestFile(require.resolve('./_index_patterns_empty')); }); describe('', function () { diff --git a/test/functional/page_objects/settings_page.ts b/test/functional/page_objects/settings_page.ts index 4b80647c8749d..a4285a5f94d51 100644 --- a/test/functional/page_objects/settings_page.ts +++ b/test/functional/page_objects/settings_page.ts @@ -55,15 +55,6 @@ export function SettingsPageProvider({ getService, getPageObjects }: FtrProvider await testSubjects.click('indexPatterns'); await PageObjects.header.waitUntilLoadingHasFinished(); - - // check for the index pattern info flyout that covers the - // create index pattern button on smaller screens - // @ts-ignore - await retry.waitFor('index pattern info flyout', async () => { - if (await testSubjects.exists('CreateIndexPatternPrompt')) { - await testSubjects.click('CreateIndexPatternPrompt > euiFlyoutCloseButton'); - } else return true; - }); } async getAdvancedSettings(propertyName: string) { @@ -311,9 +302,7 @@ export function SettingsPageProvider({ getService, getPageObjects }: FtrProvider } async isIndexPatternListEmpty() { - await testSubjects.existOrFail('indexPatternTable', { timeout: 5000 }); - const indexPatternList = await this.getIndexPatternList(); - return indexPatternList.length === 0; + return !(await testSubjects.exists('indexPatternTable', { timeout: 5000 })); } async removeLogstashIndexPatternIfExist() { diff --git a/x-pack/plugins/ml/kibana.json b/x-pack/plugins/ml/kibana.json index c61db9fb1ad8d..7b4ea5458f4a6 100644 --- a/x-pack/plugins/ml/kibana.json +++ b/x-pack/plugins/ml/kibana.json @@ -16,7 +16,8 @@ "share", "embeddable", "uiActions", - "kibanaLegacy" + "kibanaLegacy", + "indexPatternManagement" ], "optionalPlugins": [ "security", diff --git a/x-pack/plugins/ml/public/application/app.tsx b/x-pack/plugins/ml/public/application/app.tsx index 42c462fa9d869..c281dc4e9ae05 100644 --- a/x-pack/plugins/ml/public/application/app.tsx +++ b/x-pack/plugins/ml/public/application/app.tsx @@ -21,7 +21,8 @@ import { MlRouter } from './routing'; import { mlApiServicesProvider } from './services/ml_api_service'; import { HttpService } from './services/http_service'; -export type MlDependencies = Omit & MlStartDependencies; +export type MlDependencies = Omit & + MlStartDependencies; interface AppProps { coreStart: CoreStart; diff --git a/x-pack/plugins/ml/public/plugin.ts b/x-pack/plugins/ml/public/plugin.ts index aa6163379f9c0..ff59d46de758d 100644 --- a/x-pack/plugins/ml/public/plugin.ts +++ b/x-pack/plugins/ml/public/plugin.ts @@ -20,8 +20,10 @@ import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { DataPublicPluginStart } from 'src/plugins/data/public'; import { HomePublicPluginSetup } from 'src/plugins/home/public'; +import { IndexPatternManagementSetup } from 'src/plugins/index_pattern_management/public'; import { EmbeddableSetup } from 'src/plugins/embeddable/public'; import { AppStatus, AppUpdater, DEFAULT_APP_CATEGORIES } from '../../../../src/core/public'; +import { MlCardState } from '../../../../src/plugins/index_pattern_management/public'; import { SecurityPluginSetup } from '../../security/public'; import { LicensingPluginSetup } from '../../licensing/public'; import { registerManagementSection } from './application/management'; @@ -53,6 +55,7 @@ export interface MlSetupDependencies { uiActions: UiActionsSetup; kibanaVersion: string; share: SharePluginSetup; + indexPatternManagement: IndexPatternManagementSetup; } export type MlCoreSetup = CoreSetup; @@ -104,11 +107,20 @@ export class MlPlugin implements Plugin { }); const licensing = pluginsSetup.licensing.license$.pipe(take(1)); - licensing.subscribe((license) => { + licensing.subscribe(async (license) => { + const [coreStart] = await core.getStartServices(); if (isMlEnabled(license)) { // add ML to home page registerFeature(pluginsSetup.home); + // register ML for the index pattern management no data screen. + pluginsSetup.indexPatternManagement.environment.update({ + ml: () => + coreStart.application.capabilities.ml.canFindFileStructure + ? MlCardState.ENABLED + : MlCardState.HIDDEN, + }); + // register various ML plugin features which require a full license if (isFullLicense(license)) { registerManagementSection(pluginsSetup.management, core); diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index e5cd46b330ca8..55d1953247a93 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -2388,11 +2388,6 @@ "indexPatternManagement.createIndexPattern.description": "インデックスパターンは、{single}または{multiple}データソース、{star}と一致します。", "indexPatternManagement.createIndexPattern.documentation": "ドキュメンテーションを表示", "indexPatternManagement.createIndexPattern.emptyState.checkDataButton": "新規データを確認", - "indexPatternManagement.createIndexPattern.emptyStateHeader": "Elasticsearchデータが見つかりませんでした", - "indexPatternManagement.createIndexPattern.emptyStateLabel.emptyStateDetail": "{needToIndex} {learnHowLink}または{getStartedLink}", - "indexPatternManagement.createIndexPattern.emptyStateLabel.getStartedLink": "サンプルデータで始めましょう。", - "indexPatternManagement.createIndexPattern.emptyStateLabel.learnHowLink": "方法を学習", - "indexPatternManagement.createIndexPattern.emptyStateLabel.needToIndexLabel": "インデックスパターンを作成する前に、Elasticsearchへのデータのインデックスが必要です。", "indexPatternManagement.createIndexPattern.includeSystemIndicesToggleSwitchLabel": "システムと非表示のインデックスを含める", "indexPatternManagement.createIndexPattern.loadClustersFailMsg": "リモートクラスターの読み込みに失敗", "indexPatternManagement.createIndexPattern.loadIndicesFailMsg": "インデックスの読み込みに失敗", @@ -2403,7 +2398,6 @@ "indexPatternManagement.createIndexPattern.step.indexPatternPlaceholder": "index-name-*", "indexPatternManagement.createIndexPattern.step.invalidCharactersErrorMessage": "{indexPatternName}にはスペースや{characterList}は使えません。", "indexPatternManagement.createIndexPattern.step.loadingHeader": "一致するインデックスを検索中…", - "indexPatternManagement.createIndexPattern.step.loadingLabel": "お待ちください…", "indexPatternManagement.createIndexPattern.step.nextStepButton": "次のステップ", "indexPatternManagement.createIndexPattern.step.pagingLabel": "ページごとの行数: {perPage}", "indexPatternManagement.createIndexPattern.step.status.matchAnyLabel.matchAnyDetail": "インデックスパターンは、{sourceCount, plural, one {個のソース} other {個のソース} }と一致します。", @@ -2553,15 +2547,6 @@ "indexPatternManagement.indexPattern.sectionsHeader": "インデックスパターン", "indexPatternManagement.indexPattern.titleExistsLabel": "「{title}」というタイトルのインデックスパターンがすでに存在します。", "indexPatternManagement.indexPatternList.createButton.betaLabel": "ベータ", - "indexPatternManagement.indexPatternPrompt.exampleOne": "チャートを作成したりコンテンツを素早くクエリできるように log-west-001 という名前の単一のデータソースをインデックスします。", - "indexPatternManagement.indexPatternPrompt.exampleOneTitle": "単一のデータソース", - "indexPatternManagement.indexPatternPrompt.examplesTitle": "インデックスパターンの例", - "indexPatternManagement.indexPatternPrompt.exampleThree": "比較目的に履歴の動向を集約できるよう、これらのログのアーカイブされた月々のロールアップメトリックスを指定どおりに別々のインデックスパターンにグループ分けします。", - "indexPatternManagement.indexPatternPrompt.exampleThreeTitle": "カスタムグルーピング", - "indexPatternManagement.indexPatternPrompt.exampleTwo": "すべての西海岸のサーバーログに対してクエリを実行できるように、頭に「log-west」の付いたすべての受信データソースをグループ化します。", - "indexPatternManagement.indexPatternPrompt.exampleTwoTitle": "複数データソース", - "indexPatternManagement.indexPatternPrompt.subtitle": "インデックスパターンは、Kibanaで共有フィールドにクエリを実行できるよう、種類の異なるデータソースをバケットにまとめることができます。", - "indexPatternManagement.indexPatternPrompt.title": "インデックスパターンについて", "indexPatternManagement.indexPatterns.badge.readOnly.text": "読み取り専用", "indexPatternManagement.indexPatterns.badge.readOnly.tooltip": "インデックスパターンを保存できません", "indexPatternManagement.indexPatterns.createBreadcrumb": "インデックスパターンを作成", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index b273f6cc81baf..40f4c9c5897d8 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -2389,11 +2389,6 @@ "indexPatternManagement.createIndexPattern.description": "索引模式可以匹配单个源,例如 {single} 或 {multiple} 个数据源、{star}。", "indexPatternManagement.createIndexPattern.documentation": "阅读文档", "indexPatternManagement.createIndexPattern.emptyState.checkDataButton": "检查新数据", - "indexPatternManagement.createIndexPattern.emptyStateHeader": "找不到任何 Elasticsearch 数据", - "indexPatternManagement.createIndexPattern.emptyStateLabel.emptyStateDetail": "{needToIndex}{learnHowLink}或{getStartedLink}", - "indexPatternManagement.createIndexPattern.emptyStateLabel.getStartedLink": "开始使用一些样例数据集。", - "indexPatternManagement.createIndexPattern.emptyStateLabel.learnHowLink": "了解操作方法", - "indexPatternManagement.createIndexPattern.emptyStateLabel.needToIndexLabel": "您需要在 Elasticsearch 中索引一些数据后,才能创建索引模式。", "indexPatternManagement.createIndexPattern.includeSystemIndicesToggleSwitchLabel": "包括系统和隐藏索引", "indexPatternManagement.createIndexPattern.loadClustersFailMsg": "无法加载远程集群", "indexPatternManagement.createIndexPattern.loadIndicesFailMsg": "无法加载索引", @@ -2404,7 +2399,6 @@ "indexPatternManagement.createIndexPattern.step.indexPatternPlaceholder": "index-name-*", "indexPatternManagement.createIndexPattern.step.invalidCharactersErrorMessage": "{indexPatternName} 不能包含空格或字符:{characterList}", "indexPatternManagement.createIndexPattern.step.loadingHeader": "正在寻找匹配的索引......", - "indexPatternManagement.createIndexPattern.step.loadingLabel": "请稍候......", "indexPatternManagement.createIndexPattern.step.nextStepButton": "下一步", "indexPatternManagement.createIndexPattern.step.pagingLabel": "每页行数:{perPage}", "indexPatternManagement.createIndexPattern.step.status.matchAnyLabel.matchAnyDetail": "您的索引模式可以匹配{sourceCount, plural, one {您的 # 个源} other {您的 # 个源中的任何一个} }。", @@ -2554,15 +2548,6 @@ "indexPatternManagement.indexPattern.sectionsHeader": "索引模式", "indexPatternManagement.indexPattern.titleExistsLabel": "具有标题“{title}”的索引模式已存在。", "indexPatternManagement.indexPatternList.createButton.betaLabel": "公测版", - "indexPatternManagement.indexPatternPrompt.exampleOne": "索引单个称作 log-west-001 的数据源,以便可以快速地构建图表或查询其内容。", - "indexPatternManagement.indexPatternPrompt.exampleOneTitle": "单数据源", - "indexPatternManagement.indexPatternPrompt.examplesTitle": "索引模式示例", - "indexPatternManagement.indexPatternPrompt.exampleThree": "具体而言,将这些日志每月存档的汇总/打包指标分组成不同的索引模式,从而可以聚合历史趋势以进行比较。", - "indexPatternManagement.indexPatternPrompt.exampleThreeTitle": "定制分组", - "indexPatternManagement.indexPatternPrompt.exampleTwo": "分组以 log-west* 开头的所有传入数据源,以便可以查询所有西海岸服务器日志。", - "indexPatternManagement.indexPatternPrompt.exampleTwoTitle": "多数据源", - "indexPatternManagement.indexPatternPrompt.subtitle": "索引模式允许您将异类的数据源一起装入存储桶,从而可以在 Kibana 中查询它们共享的字段。", - "indexPatternManagement.indexPatternPrompt.title": "关于索引模式", "indexPatternManagement.indexPatterns.badge.readOnly.text": "只读", "indexPatternManagement.indexPatterns.badge.readOnly.tooltip": "无法保存索引模式", "indexPatternManagement.indexPatterns.createBreadcrumb": "创建索引模式", diff --git a/x-pack/test/functional/apps/index_patterns/feature_controls/index_patterns_security.ts b/x-pack/test/functional/apps/index_patterns/feature_controls/index_patterns_security.ts index bc36f70df3641..cedd96f147c2b 100644 --- a/x-pack/test/functional/apps/index_patterns/feature_controls/index_patterns_security.ts +++ b/x-pack/test/functional/apps/index_patterns/feature_controls/index_patterns_security.ts @@ -130,7 +130,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { it(`index pattern listing doesn't show create button`, async () => { await PageObjects.settings.clickKibanaIndexPatterns(); - await testSubjects.existOrFail('indexPatternTable'); + await testSubjects.existOrFail('emptyIndexPatternPrompt'); await testSubjects.missingOrFail('createIndexPatternButton'); }); From 124bd126f88b6ebb785ee7ef37d4e4c93e1f61c0 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 12 Aug 2020 14:08:02 -0700 Subject: [PATCH 04/53] Migrated last pieces of legacy fixture code (#74470) * Migrated last pieces of legacy fixture code * Implemented own server for webhook simulator * Fixed type checks. Moved slack simulator to own server * close server after tests run * Fixed due to comments * fixed failing tests --- x-pack/package.json | 4 +- .../actions/builtin_action_types/slack.ts | 25 ++-- .../actions/builtin_action_types/webhook.ts | 25 ++-- .../actions_simulators/server/plugin.ts | 11 ++ .../server/slack_simulation.ts | 69 +++++++++++ .../server/webhook_simulation.ts | 88 ++++++++++++++ .../actions_simulators_legacy/index.ts | 26 ---- .../actions_simulators_legacy/package.json | 7 -- .../slack_simulation.ts | 74 ------------ .../webhook_simulation.ts | 112 ------------------ .../actions/builtin_action_types/slack.ts | 25 ++-- .../actions/builtin_action_types/webhook.ts | 53 +++++++-- .../actions/builtin_action_types/webhook.ts | 30 ++--- yarn.lock | 2 +- 14 files changed, 269 insertions(+), 282 deletions(-) create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/slack_simulation.ts create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/webhook_simulation.ts delete mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/index.ts delete mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/package.json delete mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/slack_simulation.ts delete mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/webhook_simulation.ts diff --git a/x-pack/package.json b/x-pack/package.json index b426e790c2d47..2b52646e0f748 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -255,8 +255,8 @@ "cronstrue": "^1.51.0", "cytoscape": "^3.10.0", "d3": "3.5.17", - "d3-scale": "1.0.7", "d3-array": "1.2.4", + "d3-scale": "1.0.7", "dedent": "^0.7.0", "del": "^5.1.0", "dragselect": "1.13.1", @@ -267,7 +267,7 @@ "font-awesome": "4.7.0", "formsy-react": "^1.1.5", "fp-ts": "^2.3.1", - "get-port": "4.2.0", + "get-port": "^4.2.0", "getos": "^3.1.0", "git-url-parse": "11.1.2", "github-markdown-css": "^2.10.0", diff --git a/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/slack.ts b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/slack.ts index 90660cc99507d..91511b508aca6 100644 --- a/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/slack.ts +++ b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/slack.ts @@ -4,26 +4,25 @@ * you may not use this file except in compliance with the Elastic License. */ +import http from 'http'; +import getPort from 'get-port'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; -import { - getExternalServiceSimulatorPath, - ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; +import { getSlackServer } from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; // eslint-disable-next-line import/no-default-export export default function slackTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); - const kibanaServer = getService('kibanaServer'); describe('slack action', () => { - let slackSimulatorURL: string = ''; + let slackSimulatorURL: string = ''; + let slackServer: http.Server; - // need to wait for kibanaServer to settle ... - before(() => { - slackSimulatorURL = kibanaServer.resolveUrl( - getExternalServiceSimulatorPath(ExternalServiceSimulator.SLACK) - ); + before(async () => { + slackServer = await getSlackServer(); + const availablePort = await getPort({ port: 9000 }); + slackServer.listen(availablePort); + slackSimulatorURL = `http://localhost:${availablePort}`; }); it('should return 403 when creating a slack action', async () => { @@ -44,5 +43,9 @@ export default function slackTest({ getService }: FtrProviderContext) { 'Action type .slack is disabled because your basic license does not support it. Please upgrade your license.', }); }); + + after(() => { + slackServer.close(); + }); }); } diff --git a/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/webhook.ts b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/webhook.ts index af1d413ff3c46..039f1d4dd3275 100644 --- a/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/webhook.ts +++ b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/webhook.ts @@ -4,25 +4,24 @@ * you may not use this file except in compliance with the Elastic License. */ +import http from 'http'; +import getPort from 'get-port'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; -import { - getExternalServiceSimulatorPath, - ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; +import { getWebhookServer } from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; // eslint-disable-next-line import/no-default-export export default function webhookTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); - const kibanaServer = getService('kibanaServer'); describe('webhook action', () => { - let webhookSimulatorURL: string = ''; - + let webhookSimulatorURL: string = ''; + let webhookServer: http.Server; // need to wait for kibanaServer to settle ... - before(() => { - webhookSimulatorURL = kibanaServer.resolveUrl( - getExternalServiceSimulatorPath(ExternalServiceSimulator.WEBHOOK) - ); + before(async () => { + webhookServer = await getWebhookServer(); + const availablePort = await getPort({ port: 9000 }); + webhookServer.listen(availablePort); + webhookSimulatorURL = `http://localhost:${availablePort}`; }); it('should return 403 when creating a webhook action', async () => { @@ -47,5 +46,9 @@ export default function webhookTest({ getService }: FtrProviderContext) { 'Action type .webhook is disabled because your basic license does not support it. Please upgrade your license.', }); }); + + after(() => { + webhookServer.close(); + }); }); } diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/plugin.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/plugin.ts index cb1271494c294..0f7acf5ead1a1 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/plugin.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/plugin.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import http from 'http'; import { Plugin, CoreSetup, IRouter } from 'kibana/server'; import { EncryptedSavedObjectsPluginStart } from '../../../../../../../plugins/encrypted_saved_objects/server'; import { PluginSetupContract as FeaturesPluginSetup } from '../../../../../../../plugins/features/server'; @@ -13,6 +14,8 @@ import { initPlugin as initPagerduty } from './pagerduty_simulation'; import { initPlugin as initServiceNow } from './servicenow_simulation'; import { initPlugin as initJira } from './jira_simulation'; import { initPlugin as initResilient } from './resilient_simulation'; +import { initPlugin as initSlack } from './slack_simulation'; +import { initPlugin as initWebhook } from './webhook_simulation'; export const NAME = 'actions-FTS-external-service-simulators'; @@ -39,6 +42,14 @@ export function getAllExternalServiceSimulatorPaths(): string[] { return allPaths; } +export async function getWebhookServer(): Promise { + return await initWebhook(); +} + +export async function getSlackServer(): Promise { + return await initSlack(); +} + interface FixtureSetupDeps { actions: ActionsPluginSetupContract; features: FeaturesPluginSetup; diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/slack_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/slack_simulation.ts new file mode 100644 index 0000000000000..5032112e702e2 --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/slack_simulation.ts @@ -0,0 +1,69 @@ +/* + * 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 http from 'http'; + +export async function initPlugin() { + return http.createServer((request, response) => { + if (request.method === 'POST') { + let data = ''; + request.on('data', (chunk) => { + data += chunk; + }); + request.on('end', () => { + const body = JSON.parse(data); + const text = body && body.text; + + if (text == null) { + response.statusCode = 400; + response.end('bad request to slack simulator'); + return; + } + + switch (text) { + case 'success': { + response.statusCode = 200; + response.end('ok'); + return; + } + case 'no_text': + response.statusCode = 400; + response.end('no_text'); + return; + + case 'invalid_payload': + response.statusCode = 400; + response.end('invalid_payload'); + return; + + case 'invalid_token': + response.statusCode = 403; + response.end('invalid_token'); + return; + + case 'status_500': + response.statusCode = 500; + response.end('simulated slack 500 response'); + return; + + case 'rate_limit': + const res = { + retry_after: 1, + ok: false, + error: 'rate_limited', + }; + + response.writeHead(429, { 'Content-Type': 'application/json', 'Retry-After': '1' }); + response.write(JSON.stringify(res)); + response.end(); + return; + } + response.statusCode = 400; + response.end('unknown request to slack simulator'); + }); + } + }); +} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/webhook_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/webhook_simulation.ts new file mode 100644 index 0000000000000..44d8ea0c2da20 --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/webhook_simulation.ts @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import expect from '@kbn/expect'; +import http from 'http'; +import { fromNullable, map, filter, getOrElse } from 'fp-ts/lib/Option'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { constant } from 'fp-ts/lib/function'; + +export async function initPlugin() { + return http.createServer((request, response) => { + const credentials = pipe( + fromNullable(request.headers.authorization), + map((authorization) => authorization.split(/\s+/)), + filter((parts) => parts.length > 1), + map((parts) => Buffer.from(parts[1], 'base64').toString()), + filter((credentialsPart) => credentialsPart.indexOf(':') !== -1), + map((credentialsPart) => { + const [username, password] = credentialsPart.split(':'); + return { username, password }; + }), + getOrElse(constant({ username: '', password: '' })) + ); + + if (request.method === 'POST' || request.method === 'PUT') { + let data = ''; + request.on('data', (chunk) => { + data += chunk; + }); + request.on('end', () => { + switch (data) { + case 'success': + response.statusCode = 200; + response.end('OK'); + return; + case 'authenticate': + return validateAuthentication(credentials, response); + case 'success_post_method': + return validateRequestUsesMethod(request.method ?? '', 'post', response); + case 'success_put_method': + return validateRequestUsesMethod(request.method ?? '', 'put', response); + case 'failure': + response.statusCode = 500; + response.end('Error'); + return; + } + response.statusCode = 400; + response.end( + `unknown request to webhook simulator [${data ? `content: ${data}` : `no content`}]` + ); + return; + }); + } else { + request.on('end', () => { + response.statusCode = 400; + response.end('unknown request to webhook simulator [no content]'); + return; + }); + } + }); +} + +function validateAuthentication(credentials: any, res: any) { + try { + expect(credentials).to.eql({ + username: 'elastic', + password: 'changeme', + }); + res.statusCode = 200; + res.end('OK'); + } catch (ex) { + res.statusCode = 403; + res.end(`the validateAuthentication operation failed. ${ex.message}`); + } +} + +function validateRequestUsesMethod(requestMethod: string, method: string, res: any) { + try { + expect(requestMethod.toLowerCase()).to.eql(method); + res.statusCode = 200; + res.end('OK'); + } catch (ex) { + res.statusCode = 403; + res.end(`the validateAuthentication operation failed. ${ex.message}`); + } +} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/index.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/index.ts deleted file mode 100644 index 43e6a73673556..0000000000000 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/index.ts +++ /dev/null @@ -1,26 +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 Hapi from 'hapi'; -import { - getExternalServiceSimulatorPath, - NAME, - ExternalServiceSimulator, -} from '../actions_simulators/server/plugin'; - -import { initPlugin as initWebhook } from './webhook_simulation'; -import { initPlugin as initSlack } from './slack_simulation'; - -// eslint-disable-next-line import/no-default-export -export default function (kibana: any) { - return new kibana.Plugin({ - require: ['xpack_main'], - name: `${NAME}-legacy`, - init: (server: Hapi.Server) => { - initWebhook(server, getExternalServiceSimulatorPath(ExternalServiceSimulator.WEBHOOK)); - initSlack(server, getExternalServiceSimulatorPath(ExternalServiceSimulator.SLACK)); - }, - }); -} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/package.json b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/package.json deleted file mode 100644 index 644cd77d3be75..0000000000000 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "actions-fixtures-legacy", - "version": "0.0.0", - "kibana": { - "version": "kibana" - } -} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/slack_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/slack_simulation.ts deleted file mode 100644 index b914386b136cc..0000000000000 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/slack_simulation.ts +++ /dev/null @@ -1,74 +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 Joi from 'joi'; -import Hapi from 'hapi'; - -interface SlackRequest extends Hapi.Request { - payload: { - text: string; - }; -} -export function initPlugin(server: Hapi.Server, path: string) { - server.route({ - method: 'POST', - path, - options: { - auth: false, - validate: { - options: { abortEarly: false }, - payload: Joi.object().keys({ - text: Joi.string(), - }), - }, - }, - handler: slackHandler as Hapi.Lifecycle.Method, - }); -} -// Slack simulator: create a slack action pointing here, and you can get -// different responses based on the message posted. See the README.md for -// more info. - -function slackHandler(request: SlackRequest, h: any) { - const body = request.payload; - const text = body && body.text; - - if (text == null) { - return htmlResponse(h, 400, 'bad request to slack simulator'); - } - - switch (text) { - case 'success': - return htmlResponse(h, 200, 'ok'); - - case 'no_text': - return htmlResponse(h, 400, 'no_text'); - - case 'invalid_payload': - return htmlResponse(h, 400, 'invalid_payload'); - - case 'invalid_token': - return htmlResponse(h, 403, 'invalid_token'); - - case 'status_500': - return htmlResponse(h, 500, 'simulated slack 500 response'); - - case 'rate_limit': - const response = { - retry_after: 1, - ok: false, - error: 'rate_limited', - }; - - return h.response(response).type('application/json').header('retry-after', '1').code(429); - } - - return htmlResponse(h, 400, 'unknown request to slack simulator'); -} - -function htmlResponse(h: any, code: number, text: string) { - return h.response(text).type('text/html').code(code); -} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/webhook_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/webhook_simulation.ts deleted file mode 100644 index 44e1aff162c92..0000000000000 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators_legacy/webhook_simulation.ts +++ /dev/null @@ -1,112 +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 expect from '@kbn/expect'; -import Joi from 'joi'; -import Hapi, { Util } from 'hapi'; -import { fromNullable, map, filter, getOrElse } from 'fp-ts/lib/Option'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { constant } from 'fp-ts/lib/function'; - -interface WebhookRequest extends Hapi.Request { - payload: string; -} - -export async function initPlugin(server: Hapi.Server, path: string) { - server.auth.scheme('identifyCredentialsIfPresent', function identifyCredentialsIfPresent( - s: Hapi.Server, - options?: Hapi.ServerAuthSchemeOptions - ) { - const scheme = { - async authenticate(request: Hapi.Request, h: Hapi.ResponseToolkit) { - const credentials = pipe( - fromNullable(request.headers.authorization), - map((authorization) => authorization.split(/\s+/)), - filter((parts) => parts.length > 1), - map((parts) => Buffer.from(parts[1], 'base64').toString()), - filter((credentialsPart) => credentialsPart.indexOf(':') !== -1), - map((credentialsPart) => { - const [username, password] = credentialsPart.split(':'); - return { username, password }; - }), - getOrElse(constant({ username: '', password: '' })) - ); - - return h.authenticated({ credentials }); - }, - }; - - return scheme; - }); - server.auth.strategy('simple', 'identifyCredentialsIfPresent'); - - server.route({ - method: ['POST', 'PUT'], - path, - options: { - auth: 'simple', - validate: { - options: { abortEarly: false }, - payload: Joi.string(), - }, - }, - handler: webhookHandler as Hapi.Lifecycle.Method, - }); -} - -function webhookHandler(request: WebhookRequest, h: any) { - const body = request.payload; - - switch (body) { - case 'success': - return htmlResponse(h, 200, `OK`); - case 'authenticate': - return validateAuthentication(request, h); - case 'success_post_method': - return validateRequestUsesMethod(request, h, 'post'); - case 'success_put_method': - return validateRequestUsesMethod(request, h, 'put'); - case 'failure': - return htmlResponse(h, 500, `Error`); - } - - return htmlResponse( - h, - 400, - `unknown request to webhook simulator [${body ? `content: ${body}` : `no content`}]` - ); -} - -function validateAuthentication(request: WebhookRequest, h: any) { - const { - auth: { credentials }, - } = request; - try { - expect(credentials).to.eql({ - username: 'elastic', - password: 'changeme', - }); - return htmlResponse(h, 200, `OK`); - } catch (ex) { - return htmlResponse(h, 403, `the validateAuthentication operation failed. ${ex.message}`); - } -} - -function validateRequestUsesMethod( - request: WebhookRequest, - h: any, - method: Util.HTTP_METHODS_PARTIAL -) { - try { - expect(request.method).to.eql(method); - return htmlResponse(h, 200, `OK`); - } catch (ex) { - return htmlResponse(h, 403, `the validateAuthentication operation failed. ${ex.message}`); - } -} - -function htmlResponse(h: any, code: number, text: string) { - return h.response(text).type('text/html').code(code); -} diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts index f21bc8edeef1e..c68bcaa0ad4e8 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/slack.ts @@ -5,28 +5,27 @@ */ import expect from '@kbn/expect'; - +import http from 'http'; +import getPort from 'get-port'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; -import { - getExternalServiceSimulatorPath, - ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; +import { getSlackServer } from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; // eslint-disable-next-line import/no-default-export export default function slackTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); - const kibanaServer = getService('kibanaServer'); describe('slack action', () => { let simulatedActionId = ''; - let slackSimulatorURL: string = ''; + let slackSimulatorURL: string = ''; + let slackServer: http.Server; // need to wait for kibanaServer to settle ... - before(() => { - slackSimulatorURL = kibanaServer.resolveUrl( - getExternalServiceSimulatorPath(ExternalServiceSimulator.SLACK) - ); + before(async () => { + slackServer = await getSlackServer(); + const availablePort = await getPort({ port: 9000 }); + slackServer.listen(availablePort); + slackSimulatorURL = `http://localhost:${availablePort}`; }); it('should return 200 when creating a slack action successfully', async () => { @@ -220,5 +219,9 @@ export default function slackTest({ getService }: FtrProviderContext) { expect(result.message).to.match(/error posting a slack message, retry later/); expect(result.retry).to.equal(true); }); + + after(() => { + slackServer.close(); + }); }); } diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts index 7eba753d7e98b..8f17ab54184b5 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/webhook.ts @@ -4,12 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ +import http from 'http'; +import getPort from 'get-port'; import expect from '@kbn/expect'; import { URL, format as formatUrl } from 'url'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { getExternalServiceSimulatorPath, ExternalServiceSimulator, + getWebhookServer, } from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; const defaultValues: Record = { @@ -30,11 +33,13 @@ export default function webhookTest({ getService }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); async function createWebhookAction( - urlWithCreds: string, - config: Record> = {} + webhookSimulatorURL: string, + config: Record> = {}, + kibanaUrlWithCreds: string ): Promise { - const { url: fullUrl, user, password } = extractCredentialsFromUrl(urlWithCreds); - const url = config.url && typeof config.url === 'object' ? parsePort(config.url) : fullUrl; + const { user, password } = extractCredentialsFromUrl(kibanaUrlWithCreds); + const url = + config.url && typeof config.url === 'object' ? parsePort(config.url) : webhookSimulatorURL; const composedConfig = { headers: { 'Content-Type': 'text/plain', @@ -61,11 +66,17 @@ export default function webhookTest({ getService }: FtrProviderContext) { } describe('webhook action', () => { - let webhookSimulatorURL: string = ''; - + let webhookSimulatorURL: string = ''; + let webhookServer: http.Server; + let kibanaURL: string = ''; // need to wait for kibanaServer to settle ... - before(() => { - webhookSimulatorURL = kibanaServer.resolveUrl( + before(async () => { + webhookServer = await getWebhookServer(); + const availablePort = await getPort({ port: 9000 }); + webhookServer.listen(availablePort); + webhookSimulatorURL = `http://localhost:${availablePort}`; + + kibanaURL = kibanaServer.resolveUrl( getExternalServiceSimulatorPath(ExternalServiceSimulator.WEBHOOK) ); }); @@ -117,7 +128,7 @@ export default function webhookTest({ getService }: FtrProviderContext) { }); it('should send authentication to the webhook target', async () => { - const webhookActionId = await createWebhookAction(webhookSimulatorURL); + const webhookActionId = await createWebhookAction(webhookSimulatorURL, {}, kibanaURL); const { body: result } = await supertest .post(`/api/actions/action/${webhookActionId}/_execute`) .set('kbn-xsrf', 'test') @@ -132,7 +143,11 @@ export default function webhookTest({ getService }: FtrProviderContext) { }); it('should support the POST method against webhook target', async () => { - const webhookActionId = await createWebhookAction(webhookSimulatorURL, { method: 'post' }); + const webhookActionId = await createWebhookAction( + webhookSimulatorURL, + { method: 'post' }, + kibanaURL + ); const { body: result } = await supertest .post(`/api/actions/action/${webhookActionId}/_execute`) .set('kbn-xsrf', 'test') @@ -147,7 +162,11 @@ export default function webhookTest({ getService }: FtrProviderContext) { }); it('should support the PUT method against webhook target', async () => { - const webhookActionId = await createWebhookAction(webhookSimulatorURL, { method: 'put' }); + const webhookActionId = await createWebhookAction( + webhookSimulatorURL, + { method: 'put' }, + kibanaURL + ); const { body: result } = await supertest .post(`/api/actions/action/${webhookActionId}/_execute`) .set('kbn-xsrf', 'test') @@ -183,7 +202,11 @@ export default function webhookTest({ getService }: FtrProviderContext) { }); it('should handle unreachable webhook targets', async () => { - const webhookActionId = await createWebhookAction('http://some.non.existent.com/endpoint'); + const webhookActionId = await createWebhookAction( + 'http://some.non.existent.com/endpoint', + {}, + kibanaURL + ); const { body: result } = await supertest .post(`/api/actions/action/${webhookActionId}/_execute`) .set('kbn-xsrf', 'test') @@ -199,7 +222,7 @@ export default function webhookTest({ getService }: FtrProviderContext) { }); it('should handle failing webhook targets', async () => { - const webhookActionId = await createWebhookAction(webhookSimulatorURL); + const webhookActionId = await createWebhookAction(webhookSimulatorURL, {}, kibanaURL); const { body: result } = await supertest .post(`/api/actions/action/${webhookActionId}/_execute`) .set('kbn-xsrf', 'test') @@ -214,6 +237,10 @@ export default function webhookTest({ getService }: FtrProviderContext) { expect(result.message).to.match(/error calling webhook, retry later/); expect(result.serviceMessage).to.eql('[500] Internal Server Error'); }); + + after(() => { + webhookServer.close(); + }); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/builtin_action_types/webhook.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/builtin_action_types/webhook.ts index b3572978cee70..acfbad007d722 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/actions/builtin_action_types/webhook.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/actions/builtin_action_types/webhook.ts @@ -4,24 +4,22 @@ * you may not use this file except in compliance with the Elastic License. */ +import http from 'http'; +import getPort from 'get-port'; import expect from '@kbn/expect'; import { URL, format as formatUrl } from 'url'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; -import { - getExternalServiceSimulatorPath, - ExternalServiceSimulator, -} from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; +import { getWebhookServer } from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; // eslint-disable-next-line import/no-default-export export default function webhookTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); - const kibanaServer = getService('kibanaServer'); async function createWebhookAction( - urlWithCreds: string, + webhookSimulatorURL: string, config: Record> = {} ): Promise { - const url = formatUrl(new URL(urlWithCreds), { auth: false }); + const url = formatUrl(new URL(webhookSimulatorURL), { auth: false }); const composedConfig = { headers: { 'Content-Type': 'text/plain', @@ -45,13 +43,13 @@ export default function webhookTest({ getService }: FtrProviderContext) { } describe('webhook action', () => { - let webhookSimulatorURL: string = ''; - - // need to wait for kibanaServer to settle ... - before(() => { - webhookSimulatorURL = kibanaServer.resolveUrl( - getExternalServiceSimulatorPath(ExternalServiceSimulator.WEBHOOK) - ); + let webhookSimulatorURL: string = ''; + let webhookServer: http.Server; + before(async () => { + webhookServer = await getWebhookServer(); + const availablePort = await getPort({ port: 9000 }); + webhookServer.listen(availablePort); + webhookSimulatorURL = `http://localhost:${availablePort}`; }); it('webhook can be executed without username and password', async () => { @@ -68,5 +66,9 @@ export default function webhookTest({ getService }: FtrProviderContext) { expect(result.status).to.eql('ok'); }); + + after(() => { + webhookServer.close(); + }); }); } diff --git a/yarn.lock b/yarn.lock index 4eac262ddfd2f..332215a59e788 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14099,7 +14099,7 @@ get-own-enumerable-property-symbols@^3.0.0: resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz#b877b49a5c16aefac3655f2ed2ea5b684df8d203" integrity sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg== -get-port@4.2.0: +get-port@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/get-port/-/get-port-4.2.0.tgz#e37368b1e863b7629c43c5a323625f95cf24b119" integrity sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw== From 0eee111cf3969d706812f3e00d123a8dcf091e1a Mon Sep 17 00:00:00 2001 From: Josh Dover Date: Wed, 12 Aug 2020 15:24:29 -0600 Subject: [PATCH 05/53] [reporting] Pass along generic parameters in high-order route handler (#74892) --- .../plugins/reporting/server/routes/jobs.ts | 19 +++++-------------- .../routes/lib/authorized_user_pre_routing.ts | 4 ++-- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/x-pack/plugins/reporting/server/routes/jobs.ts b/x-pack/plugins/reporting/server/routes/jobs.ts index e8eac9e577beb..db62c0cc403fc 100644 --- a/x-pack/plugins/reporting/server/routes/jobs.ts +++ b/x-pack/plugins/reporting/server/routes/jobs.ts @@ -15,11 +15,6 @@ import { downloadJobResponseHandlerFactory, } from './lib/job_response_handler'; -interface ListQuery { - page: string; - size: string; - ids?: string; // optional field forbids us from extending RequestQuery -} const MAIN_ENTRY = `${API_BASE_URL}/jobs`; const handleUnavailable = (res: any) => { @@ -52,11 +47,7 @@ export function registerJobInfoRoutes(reporting: ReportingCore) { const { management: { jobTypes = [] }, } = await reporting.getLicenseInfo(); - const { - page: queryPage = '0', - size: querySize = '10', - ids: queryIds = null, - } = req.query as ListQuery; // NOTE: type inference is not working here. userHandler breaks it? + const { page: queryPage = '0', size: querySize = '10', ids: queryIds = null } = req.query; const page = parseInt(queryPage, 10) || 0; const size = Math.min(100, parseInt(querySize, 10) || 10); const jobIds = queryIds ? queryIds.split(',') : null; @@ -116,7 +107,7 @@ export function registerJobInfoRoutes(reporting: ReportingCore) { return handleUnavailable(res); } - const { docId } = req.params as { docId: string }; + const { docId } = req.params; const { management: { jobTypes = [] }, } = await reporting.getLicenseInfo(); @@ -161,7 +152,7 @@ export function registerJobInfoRoutes(reporting: ReportingCore) { return res.custom({ statusCode: 503 }); } - const { docId } = req.params as { docId: string }; + const { docId } = req.params; const { management: { jobTypes = [] }, } = await reporting.getLicenseInfo(); @@ -213,7 +204,7 @@ export function registerJobInfoRoutes(reporting: ReportingCore) { return handleUnavailable(res); } - const { docId } = req.params as { docId: string }; + const { docId } = req.params; const { management: { jobTypes = [] }, } = await reporting.getLicenseInfo(); @@ -239,7 +230,7 @@ export function registerJobInfoRoutes(reporting: ReportingCore) { return handleUnavailable(res); } - const { docId } = req.params as { docId: string }; + const { docId } = req.params; const { management: { jobTypes = [] }, } = await reporting.getLicenseInfo(); diff --git a/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.ts b/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.ts index 3758eafc6d718..e2f393aad57d2 100644 --- a/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.ts +++ b/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.ts @@ -12,7 +12,7 @@ import { getUserFactory } from './get_user'; type ReportingUser = AuthenticatedUser | null; const superuserRole = 'superuser'; -export type RequestHandlerUser = RequestHandler extends (...a: infer U) => infer R +export type RequestHandlerUser = RequestHandler extends (...a: infer U) => infer R ? (user: ReportingUser, ...a: U) => R : never; @@ -21,7 +21,7 @@ export const authorizedUserPreRoutingFactory = function authorizedUserPreRouting ) { const setupDeps = reporting.getPluginSetupDeps(); const getUser = getUserFactory(setupDeps.security); - return (handler: RequestHandlerUser): RequestHandler => { + return (handler: RequestHandlerUser): RequestHandler => { return (context, req, res) => { let user: ReportingUser = null; if (setupDeps.security && setupDeps.security.license.isEnabled()) { From 981fdda966d55295893e0cdf7cbe9384fab1fedb Mon Sep 17 00:00:00 2001 From: Matthew Kime Date: Wed, 12 Aug 2020 18:31:30 -0500 Subject: [PATCH 06/53] Reduce number of indexed fields in index pattern saved object (#74817) * reduce number of indexed fields in index pattern saved object --- src/plugins/data/server/saved_objects/index_patterns.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/plugins/data/server/saved_objects/index_patterns.ts b/src/plugins/data/server/saved_objects/index_patterns.ts index 44d2813f6e3e8..6aabcdf7c1c01 100644 --- a/src/plugins/data/server/saved_objects/index_patterns.ts +++ b/src/plugins/data/server/saved_objects/index_patterns.ts @@ -42,16 +42,10 @@ export const indexPatternSavedObjectType: SavedObjectsType = { }, }, mappings: { + dynamic: false, properties: { - fieldFormatMap: { type: 'text' }, - fields: { type: 'text' }, - intervalName: { type: 'keyword' }, - notExpandable: { type: 'boolean' }, - sourceFilters: { type: 'text' }, - timeFieldName: { type: 'keyword' }, title: { type: 'text' }, type: { type: 'keyword' }, - typeMeta: { type: 'keyword' }, }, }, migrations: indexPatternSavedObjectTypeMigrations as any, From a735a9f8259a30a790d07936caaf279e922ceb3b Mon Sep 17 00:00:00 2001 From: Spencer Date: Wed, 12 Aug 2020 16:38:08 -0700 Subject: [PATCH 07/53] [bin/kibana-plugin] support KP plugins instead (#74604) * [cli/kibana-plugin] support KP plugins instead * fix some Logger imports from cli/kibana_keystore Co-authored-by: spalger Co-authored-by: Elastic Machine --- package.json | 1 - packages/kbn-pm/dist/index.js | 72 ----- packages/kbn-pm/src/index.ts | 2 +- packages/kbn-pm/src/production/index.ts | 1 - .../prepare_project_dependencies.test.ts | 40 --- .../prepare_project_dependencies.ts | 59 ---- src/cli_keystore/add.js | 2 +- src/cli_keystore/add.test.js | 2 +- src/cli_keystore/create.js | 2 +- src/cli_keystore/create.test.js | 2 +- src/cli_keystore/get_keystore.js | 2 +- src/cli_keystore/get_keystore.test.js | 2 +- src/cli_keystore/list.js | 2 +- src/cli_keystore/list.test.js | 2 +- src/cli_plugin/cli.js | 15 +- .../__fixtures__/replies/invalid_name.zip | Bin 2333 -> 1295 bytes .../replies/package.no_version.json | 3 - .../__fixtures__/replies/test_plugin.zip | Bin 2988 -> 5382 bytes .../replies/test_plugin_different_version.zip | Bin 2326 -> 2951 bytes .../__fixtures__/replies/test_plugin_many.zip | Bin 421587 -> 413276 bytes src/cli_plugin/install/cleanup.js | 1 - src/cli_plugin/install/cleanup.test.js | 2 +- src/cli_plugin/install/download.js | 7 +- src/cli_plugin/install/download.test.js | 10 +- src/cli_plugin/install/downloaders/file.js | 5 +- src/cli_plugin/install/downloaders/http.js | 8 +- src/cli_plugin/install/index.js | 18 +- src/cli_plugin/install/index.test.js | 13 +- src/cli_plugin/install/install.js | 16 +- src/cli_plugin/install/kibana.js | 11 +- src/cli_plugin/install/kibana.test.js | 27 +- src/cli_plugin/install/pack.js | 19 +- src/cli_plugin/install/pack.test.js | 202 ++++++-------- src/cli_plugin/install/progress.js | 2 +- src/cli_plugin/install/progress.test.js | 5 +- src/cli_plugin/install/rename.js | 9 +- src/cli_plugin/install/rename.test.js | 3 +- src/cli_plugin/install/settings.js | 13 +- src/cli_plugin/install/settings.test.js | 261 +++++------------- src/cli_plugin/install/zip.js | 89 +++--- src/cli_plugin/install/zip.test.js | 106 +++---- src/cli_plugin/lib/error_if_x_pack.js | 6 +- src/cli_plugin/lib/is_oss.js | 2 +- src/cli_plugin/lib/is_oss.test.js | 4 +- src/cli_plugin/lib/log_warnings.js | 2 +- src/cli_plugin/lib/logger.js | 2 +- src/cli_plugin/lib/logger.test.js | 3 +- .../lib/warn_if_plugin_dir_option.js | 27 -- src/cli_plugin/list/index.js | 39 +-- src/cli_plugin/list/list.js | 17 +- src/cli_plugin/list/list.test.js | 91 +++--- src/cli_plugin/list/settings.js | 26 -- src/cli_plugin/list/settings.test.js | 50 ---- src/cli_plugin/remove/index.js | 24 +- src/cli_plugin/remove/remove.js | 5 +- src/cli_plugin/remove/remove.test.js | 10 +- src/cli_plugin/remove/settings.js | 4 +- src/cli_plugin/remove/settings.test.js | 116 +++----- yarn.lock | 12 - 59 files changed, 481 insertions(+), 995 deletions(-) delete mode 100644 packages/kbn-pm/src/production/prepare_project_dependencies.test.ts delete mode 100644 packages/kbn-pm/src/production/prepare_project_dependencies.ts delete mode 100644 src/cli_plugin/install/__fixtures__/replies/package.no_version.json delete mode 100644 src/cli_plugin/lib/warn_if_plugin_dir_option.js delete mode 100644 src/cli_plugin/list/settings.js delete mode 100644 src/cli_plugin/list/settings.test.js diff --git a/package.json b/package.json index becd670e4ddcf..200aa41743f51 100644 --- a/package.json +++ b/package.json @@ -276,7 +276,6 @@ "url-loader": "2.2.0", "uuid": "3.3.2", "val-loader": "^1.1.1", - "validate-npm-package-name": "2.2.2", "vega": "^5.13.0", "vega-lite": "^4.13.1", "vega-schema-url-parser": "^1.1.0", diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index 9427cc57805e6..e411dcd472768 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -97,8 +97,6 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(511); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["buildProductionProjects"]; }); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["prepareExternalProjectDependencies"]; }); - /* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(145); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "getProjects", function() { return _utils_projects__WEBPACK_IMPORTED_MODULE_2__["getProjects"]; }); @@ -59477,9 +59475,6 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _build_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(512); /* 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__(748); -/* 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 @@ -59500,7 +59495,6 @@ __webpack_require__.r(__webpack_exports__); */ - /***/ }), /* 512 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { @@ -90331,71 +90325,5 @@ NestedError.prototype.name = 'NestedError'; module.exports = NestedError; -/***/ }), -/* 748 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return prepareExternalProjectDependencies; }); -/* harmony import */ var _utils_package_json__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(164); -/* harmony import */ var _utils_project__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(163); -/* - * 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. - */ - - -/** - * All external projects are located within `./plugins/{plugin}` relative - * to the Kibana root directory or `../kibana-extra/{plugin}` relative - * to Kibana itself. - */ - -const isKibanaDep = depVersion => // For ../kibana-extra/ directory (legacy only) -depVersion.includes('../../kibana/packages/') || // For plugins/ directory -depVersion.includes('../../packages/'); -/** - * This prepares the dependencies for an _external_ project. - */ - - -async function prepareExternalProjectDependencies(projectPath) { - const project = await _utils_project__WEBPACK_IMPORTED_MODULE_1__["Project"].fromPath(projectPath); - - if (!project.hasDependencies()) { - return; - } - - const deps = project.allDependencies; - - for (const depName of Object.keys(deps)) { - const depVersion = deps[depName]; // Kibana currently only supports `link:` dependencies on Kibana's own - // packages, as these are packaged into the `node_modules` folder when - // Kibana is built, so we don't need to take any action to enable - // `require(...)` to resolve for these packages. - - if (Object(_utils_package_json__WEBPACK_IMPORTED_MODULE_0__["isLinkDependency"])(depVersion) && !isKibanaDep(depVersion)) { - // For non-Kibana packages we need to set up symlinks during the - // installation process, but this is not something we support yet. - throw new Error('This plugin is using `link:` dependencies for non-Kibana packages'); - } - } -} - /***/ }) /******/ ]); \ No newline at end of file diff --git a/packages/kbn-pm/src/index.ts b/packages/kbn-pm/src/index.ts index 0aa58adb4382f..27ce0a417fdeb 100644 --- a/packages/kbn-pm/src/index.ts +++ b/packages/kbn-pm/src/index.ts @@ -18,7 +18,7 @@ */ export { run } from './cli'; -export { buildProductionProjects, prepareExternalProjectDependencies } from './production'; +export { buildProductionProjects } from './production'; export { getProjects } from './utils/projects'; export { Project } from './utils/project'; export { copyWorkspacePackages } from './utils/workspaces'; diff --git a/packages/kbn-pm/src/production/index.ts b/packages/kbn-pm/src/production/index.ts index 493af2beb648d..f74ab8a4484f1 100644 --- a/packages/kbn-pm/src/production/index.ts +++ b/packages/kbn-pm/src/production/index.ts @@ -18,4 +18,3 @@ */ export { buildProductionProjects } from './build_production_projects'; -export { prepareExternalProjectDependencies } from './prepare_project_dependencies'; diff --git a/packages/kbn-pm/src/production/prepare_project_dependencies.test.ts b/packages/kbn-pm/src/production/prepare_project_dependencies.test.ts deleted file mode 100644 index 13ab8d56e0190..0000000000000 --- a/packages/kbn-pm/src/production/prepare_project_dependencies.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { join, resolve } from 'path'; - -import { prepareExternalProjectDependencies } from './prepare_project_dependencies'; - -const packagesFixtures = resolve(__dirname, '__fixtures__/external_packages'); - -test('does nothing when Kibana `link:` dependencies', async () => { - const projectPath = join(packagesFixtures, 'with_kibana_link_deps'); - - // We're checking for undefined, but we don't really care about what's - // returned, we only care about it resolving. - await expect(prepareExternalProjectDependencies(projectPath)).resolves.toBeUndefined(); -}); - -test('throws if non-Kibana `link` dependencies', async () => { - const projectPath = join(packagesFixtures, 'with_other_link_deps'); - - await expect(prepareExternalProjectDependencies(projectPath)).rejects.toThrow( - 'This plugin is using `link:` dependencies for non-Kibana packages' - ); -}); diff --git a/packages/kbn-pm/src/production/prepare_project_dependencies.ts b/packages/kbn-pm/src/production/prepare_project_dependencies.ts deleted file mode 100644 index 9817770166480..0000000000000 --- a/packages/kbn-pm/src/production/prepare_project_dependencies.ts +++ /dev/null @@ -1,59 +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 { isLinkDependency } from '../utils/package_json'; -import { Project } from '../utils/project'; - -/** - * All external projects are located within `./plugins/{plugin}` relative - * to the Kibana root directory or `../kibana-extra/{plugin}` relative - * to Kibana itself. - */ -const isKibanaDep = (depVersion: string) => - // For ../kibana-extra/ directory (legacy only) - depVersion.includes('../../kibana/packages/') || - // For plugins/ directory - depVersion.includes('../../packages/'); - -/** - * This prepares the dependencies for an _external_ project. - */ -export async function prepareExternalProjectDependencies(projectPath: string) { - const project = await Project.fromPath(projectPath); - - if (!project.hasDependencies()) { - return; - } - - const deps = project.allDependencies; - - for (const depName of Object.keys(deps)) { - const depVersion = deps[depName]; - - // Kibana currently only supports `link:` dependencies on Kibana's own - // packages, as these are packaged into the `node_modules` folder when - // Kibana is built, so we don't need to take any action to enable - // `require(...)` to resolve for these packages. - if (isLinkDependency(depVersion) && !isKibanaDep(depVersion)) { - // For non-Kibana packages we need to set up symlinks during the - // installation process, but this is not something we support yet. - throw new Error('This plugin is using `link:` dependencies for non-Kibana packages'); - } - } -} diff --git a/src/cli_keystore/add.js b/src/cli_keystore/add.js index 87266702a26cc..44737e387c2d2 100644 --- a/src/cli_keystore/add.js +++ b/src/cli_keystore/add.js @@ -17,7 +17,7 @@ * under the License. */ -import Logger from '../cli_plugin/lib/logger'; +import { Logger } from '../cli_plugin/lib/logger'; import { confirm, question } from '../legacy/server/utils'; import { createPromiseFromStreams, createConcatStream } from '../legacy/utils'; diff --git a/src/cli_keystore/add.test.js b/src/cli_keystore/add.test.js index 320581b470c2b..b5d5009667eb4 100644 --- a/src/cli_keystore/add.test.js +++ b/src/cli_keystore/add.test.js @@ -41,7 +41,7 @@ import { PassThrough } from 'stream'; import { Keystore } from '../legacy/server/keystore'; import { add } from './add'; -import Logger from '../cli_plugin/lib/logger'; +import { Logger } from '../cli_plugin/lib/logger'; import * as prompt from '../legacy/server/utils/prompt'; describe('Kibana keystore', () => { diff --git a/src/cli_keystore/create.js b/src/cli_keystore/create.js index 1af0959821f80..8be1eb36882f1 100644 --- a/src/cli_keystore/create.js +++ b/src/cli_keystore/create.js @@ -17,7 +17,7 @@ * under the License. */ -import Logger from '../cli_plugin/lib/logger'; +import { Logger } from '../cli_plugin/lib/logger'; import { confirm } from '../legacy/server/utils'; export async function create(keystore, command, options) { diff --git a/src/cli_keystore/create.test.js b/src/cli_keystore/create.test.js index 33b5aa4bd07d8..f48b3775ddfff 100644 --- a/src/cli_keystore/create.test.js +++ b/src/cli_keystore/create.test.js @@ -40,7 +40,7 @@ import sinon from 'sinon'; import { Keystore } from '../legacy/server/keystore'; import { create } from './create'; -import Logger from '../cli_plugin/lib/logger'; +import { Logger } from '../cli_plugin/lib/logger'; import * as prompt from '../legacy/server/utils/prompt'; describe('Kibana keystore', () => { diff --git a/src/cli_keystore/get_keystore.js b/src/cli_keystore/get_keystore.js index c8ff2555563ad..e181efe9196b8 100644 --- a/src/cli_keystore/get_keystore.js +++ b/src/cli_keystore/get_keystore.js @@ -20,7 +20,7 @@ import { existsSync } from 'fs'; import { join } from 'path'; -import Logger from '../cli_plugin/lib/logger'; +import { Logger } from '../cli_plugin/lib/logger'; import { getConfigDirectory, getDataPath } from '../core/server/path'; export function getKeystore() { diff --git a/src/cli_keystore/get_keystore.test.js b/src/cli_keystore/get_keystore.test.js index 88102b8f51d57..b1c42fca2f73c 100644 --- a/src/cli_keystore/get_keystore.test.js +++ b/src/cli_keystore/get_keystore.test.js @@ -18,7 +18,7 @@ */ import { getKeystore } from './get_keystore'; -import Logger from '../cli_plugin/lib/logger'; +import { Logger } from '../cli_plugin/lib/logger'; import fs from 'fs'; import sinon from 'sinon'; diff --git a/src/cli_keystore/list.js b/src/cli_keystore/list.js index e9158735a214f..4a99de271bc6a 100644 --- a/src/cli_keystore/list.js +++ b/src/cli_keystore/list.js @@ -17,7 +17,7 @@ * under the License. */ -import Logger from '../cli_plugin/lib/logger'; +import { Logger } from '../cli_plugin/lib/logger'; export function list(keystore, command, options = {}) { const logger = new Logger(options); diff --git a/src/cli_keystore/list.test.js b/src/cli_keystore/list.test.js index 857991b5ae3b9..11c474f908216 100644 --- a/src/cli_keystore/list.test.js +++ b/src/cli_keystore/list.test.js @@ -38,7 +38,7 @@ jest.mock('fs', () => ({ import sinon from 'sinon'; import { Keystore } from '../legacy/server/keystore'; import { list } from './list'; -import Logger from '../cli_plugin/lib/logger'; +import { Logger } from '../cli_plugin/lib/logger'; describe('Kibana keystore', () => { describe('list', () => { diff --git a/src/cli_plugin/cli.js b/src/cli_plugin/cli.js index da1068b54b4b5..e483385b5b9e8 100644 --- a/src/cli_plugin/cli.js +++ b/src/cli_plugin/cli.js @@ -17,12 +17,11 @@ * under the License. */ -import _ from 'lodash'; import { pkg } from '../core/server/utils'; import Command from '../cli/command'; -import listCommand from './list'; -import installCommand from './install'; -import removeCommand from './remove'; +import { listCommand } from './list'; +import { installCommand } from './install'; +import { removeCommand } from './remove'; const argv = process.env.kbnWorkerArgv ? JSON.parse(process.env.kbnWorkerArgv) @@ -44,8 +43,12 @@ program .command('help ') .description('get the help for a specific command') .action(function (cmdName) { - const cmd = _.find(program.commands, { _name: cmdName }); - if (!cmd) return program.error(`unknown command ${cmdName}`); + const cmd = program.commands.find((c) => c._name === cmdName); + + if (!cmd) { + return program.error(`unknown command ${cmdName}`); + } + cmd.help(); }); diff --git a/src/cli_plugin/install/__fixtures__/replies/invalid_name.zip b/src/cli_plugin/install/__fixtures__/replies/invalid_name.zip index 5de9a0677b6cb6681b890ca59cae3988cca1afd4..4d77ba0d389a699887e9706c134b82e7e98f1bba 100644 GIT binary patch literal 1295 zcmWIWW@Zs#0D*>Bwm>igO0Y91Fl1*YCFUjShlcPnuowF4#8(0_h%T+*W?*Fb%E-U~ z)*Jvgq!-N)5riR`d1Z+?nJKz?iMgo|6T5&W!7x@6IT$!loW&x+z#xDyQO_kfKDZ>m zC>8ELklV1h@9hk0zC#8AF6qu)9sxU+d|}nt(b)QcC8oh&V*-;1$E%Pz-HRulIPA{F zvBJT?KWeYi?y^f2dl?g&WACxcH1J%sc%Ub_*wHDvC##pq`^k&M-j{#3N?qAHcU4wz zZD?`y{zFRl&voBS3%=3a&8gTT@JKUfb>#2O>lIsmIKBFO@N%Qx;@n8nK$ZDzat&8*cN+i!ZpSGxxC^z%dc$VSczTGaeWB)?Yr?39mA3FRqp5x=;2rC(W z_8mMdyszS3ubyG>yh5+0K+xk6|6#p#l_33VPd5n6f4~yp&Ca2Fvx@H_Fz!Hs1c?yz z;Hv=2N&|y0KHk^S**`c!9~!-S@t7ew2N;qdj217+38KmA2}ubbe0{<`@P~B-G%!t& zU{)89X51(((ELNx;S59YLxlqk%oc4eERHip4Psw_T*J=6-EqLe6lg!l4G7mwL`p7( zKpA;N@MdHZVaA;wfJ(sNts{scI(Hxp z#g;!HMlvwGb#z4-isF5+pJ6!#M5Fl`=4@DmBPRt=eu04{jnfe}V8%I)+=Fg9a#Vtn z6AUbAyvE2tN#a7b2$V9AV+NEmU|>mO2@^c@Q38sDbQ0jr$_6r!6$oDg-Oa}g;sF3w CgHP1} literal 2333 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 O10N7d0^L>%<^cdfumkS^ diff --git a/src/cli_plugin/install/__fixtures__/replies/test_plugin_different_version.zip b/src/cli_plugin/install/__fixtures__/replies/test_plugin_different_version.zip index 12baa165fdb566d22237d72a9b0afb7d9c965219..b84473cebf954a4f5b186b8d92db55d7ad9da975 100644 GIT binary patch literal 2951 zcmWIWW@Zs#0D;Z1Y=K|~l#pXkU?@o~E{QM5DNWDJi%-c+OG_AzvQnIe;J4m1?t3?R&X;gvV3J^U;vvL05+S0frH^d9KviC2?hprf@bTv1jh%L zc{{_9>yU$h>;EGPjI(uhzjNJ75VUO+H^@?E3+|}ZI{);d&yDqL zlN!Rh{;?m{HrhPf#M+uM;q&J_HVX#HMTL&~l8c?4qI;@(l|S9hjLtc==|%i%=V0q& zjMX_4w!eORl(j{`iQ}VK&c>ThHm_G~`QbF{^TErF>lXE%7q-g1YHA1N%C!m zKl`q(XA4th?0T%F)kTW8EI%AQU+2hugRUaq|M5u$|HPgC7);X(>$a3*c5GjE{g>6X zGdu5bv+FT={zkd*Mj*C*@)e^^IA1JeWvW_1B+#*NYf%|ApP z&M*W&R5;MUY|+-j;y6>(Aoc~wk?b7Y9S1B-fzARs4dQ4Z10?}~_^JdGKz3$QVqPL7 zjlrTGM5DPAd$@o?OpjPAFvA39ADUfnXV`+0TI>BIBH*OPBnC-q0=*pqApyTb=AB+V zbHjQ0j>ZVhUv@KUT+`G%H}4i^FtdBAe1P$UK(BG!Btt2cEk{>W@oaQ&6ux$2&%3J& z*1dh)A(08_^3#qcZP#9ttgQ%4b0rPZ+1LKR$>vbpH=(NbL&<{E8IS+A_|4Cf zdHd2~`o&{=TKr!2lxp%J}KN5B3o>5D_!`{U9 zHSYE58OG0xv~w&uR6e#pWazg6CfS~Ai4Gn91+1XhbN*GDb{`l&_>-I^@ktIEjRTkR z)}s|`hQuZdP*&1~lzos?cp6yBT_;r19YQMUynz8}LymQjK-0@A&d&oEe`lb@ABaXv zldGQv1q7V(3EUJEpyjEn$9Y22_xzdQON^bI7aoO0H)ncwR(2+G zSOzbcvrs5pR~(#Mvl}+qTLYa5aw;M#A$wv2P{y6)_(l#qy?AW?A-UWslm(VM(h?m^ zeTs^X0csw{nH0nvf)8~FO!qo>{;Ic*#tF}>r#*G_GE~5#4cEEh+MXVYC{-U z(g<=Le!GY+uwWj9S&CdXgQ^V}SkkzHk%0!42+V$vJ;+S}5Fb>xT#9B#};06_$FtDUinuX}#CcOYf4s~p$AIuql9j^nOfj_B1ZAZ?| z;FONHEJVZrs31WuVnC%K3~Xt1Vd bAIKp>QUMp>%?h-Pfq@eUOM&742h0NiMn!Wx literal 2326 zcmWIWW@Zs#0D)}@J|18Ol;8u>sX2+oC7H>^sfk6&8TtWmwTji6p2%w1ft>8jq{O^L zBt_C_ii8o0N>YnUbPIAy(=+qH8o0oQeagP!wv=su2M>@3!m`*k=%r_tWTxlk7p3Oq zr=-T`=BJeAq!xo52QkLGt z%%2<#AQxF2dulruXv8}pmd0*WW?o8agQ=!+K3^&dkqu-EN!D>OYtO^;0$Wn^Gr zWny5E$L_0w#N_P6^i-g~^7CQ??&cj*5ZO1+|KN^7Z;|?4Gtcba+aBrk($hQD!J@=B zx#qj4&bW1R=k1QI5&apgE1JH2JhVmD zO)b)BbM@!I>6g5M=A`NON6w$J_2ClB^hAdD0q){$DrzkoEPmLmyf*QY(G}Lo6V%-H z$FHr@ILX|^5`1X~_i_oYzFSFC)T-C6ZqRK!J9YC59*)Pawlgn}mQ8untIMIh-b-76#23#i@?h!ybaODre=Mh5G_gS-t20xSpihpy3I z$fo@x&Inz8!vh7CD)1HZQm_?|U3UL$nu zc7d6_%X8Irm&LEkBeD!Aov+d7*A@cW55h9o-4W#K=;G_Dmz(0LkeI8Gr~t~w3Xp7! z2#cL)huXsM>uT;Fqh-@%=Yzs3W8ytu*7`d23 zw&dbhWlNAHFnVQK)mD&iAeP`N3}Kci04-?3ZV94jM7ECMOEbfobr%>bXF&V{qmiw{ zEHsg=JBi&o+(jsg^^4uUHUfiCbC=;nkS}30B1o|nw8++r01GN;TppY()ypE(M@nC3x+E6fnp(!jevOG{hztjhu8a3lC%)|6sQfUX)<7 z&5svi8;nK{OU&X0W*aChJy?(m8)Tzh!;|KN5+6Dp;LXYg)W^ULgcE_9^MROw0RX19 BoUi}@ diff --git a/src/cli_plugin/install/__fixtures__/replies/test_plugin_many.zip b/src/cli_plugin/install/__fixtures__/replies/test_plugin_many.zip index e4fc8d73feef86f0f34073e0597c6c2351dc4d05..bc58c2bdb9dd7e108ef80ddf6f7c189dc4b92e97 100644 GIT binary patch delta 296290 zcmZ^IV{qV2^KG2$#t&BT{N7_1 zDyCb2s?+L>jkJrZ4Jt1MK*Mn3j@8Wn!}-4?{dfA@{<$Uphdw<$89`w=C3VLCrz{M5 z4F3<2e*cj8um2Asjr7rt%=8WQuVtiFuMq*&P?!bb)aYr5&Pf zUvSRgKnTG!bS9nSe*=Stfer2EWcw$Sf5Z9z%LePe)!EYA(7?vvzo-ZJ|H zcm89c4B#NR{|)wEP#XgV3p=y_$cKA`w2zu*S> zknC;oAjm`hioL1K68k+5QeK8}aVjC2|3ZJ1R|9}D`3$RxvrZ%O_ADqx4t@!D+CR+a zCw%m4Gxu77r1G~2?~HdD-&dAl*iCJ$qZ)vN6qB~E>-Y)%@g*G1J|?`-A!m~z;*Wtr z6bI>^f<{3D_v;rR>F$C6MF#O@p!!g=I>r;!=rZ}V8_Z_b_U_gAik|@o^=T?=)p(z0t}d5$Z9lW_umxeNE=-G7K_e)01PKHSsZC z9cE+Qe&LKEzEHmseketDji>_&HDAO0{J?MiBj@AOn)f5R>#*>fFHh6YSx}JvDo~I} zjxINTZ;j6z37UtENlH4Z(J5$<_qLAF{umr^eT#^2ud9#AK}5buIoek4ZRkf&o2uQx z9H@7;zsIdx52;-b?`pGC??zO5HNZ&&s1yJ7vs&%N)H0_}w8nWA2IiUBx(ENmG5|Cz zoqVw|+-AG9XJ1TQU1YC&=>ZTCi#9fshVAXqmAr?^vUU(LK?&ehDJ?%3LqlRPiR_2Q zR@QqFcAx@D%dPOpHMSaDYQe1O$TgfH7oO)c4v-evpS zfwjAkVd3Gow>NjUcaD0*%{m?U8{-|#_&RBoyxQQO*TgY)4FW5iZ7ZBypZ7t{tBO86 zZ$sUkT0W8I;Rq0tURU8IX=}slhQu=g&EY<_sc zDfYheGXrX$zfQk63O)hh&ly2{>-B;}Jo<8=_sisE!k3eHgLgs!hT2h#))OLpZ3Ep8 z?EB3%=)%6qi-@w{yFO?&Q5O+XP_PU=3IY4Yp7m3 zxHveAeH1sW)+k_^8J zi6C5fi1?Hnw=F$a(XH6PL$0g@u%CV6dU(O~bArgL0=|7QVtx&NiWQEorhd&$be-PE zd`w{kHsj2xsCaKV7vw~{M9XGHcd_SnrGL`ldpfFFZUax+Jn8w`$lRNgFcOPbYr#CD zU_Gx*`(GfRQAfrGHdWzv^$vBNlC@0JJv*3}w!!?Udk9^lA2FhDOKqc763_WxJQ%kr zm#%T2>36noz|JT2#FyW@p2gD;5}S3q4}G=X$JQCry_xF^=DqEM?Uj>?@*xHcwc15n zZ5QoR6Y$7!8y;1?l+g8k;3fpNx|-;j@_nlaaJc`%dWM7y{FNrq{>lAH^dbG4aNs@v+<1K> z!#6bh51?|#f2O#!ItWi}X=8i&`zGP=MF%_(_$quI`G7v{S}2MqRiEw=oEh8{48P)s zy|-NiqBSPhU*2{sBeCX$*R5ibFB|<4o+x|%%JR$7k*kU zeN`=f#l4qRLp-a`7-g z+Z$g#6cz?!2l?=gaU7U7KHu${$JC(ldQgCFo%0WIJkk?da?;`a+ofKsrJNbqgZ)p-m&CqLil z{X#RsFDyDJ7{0q_pp9itcY}htv+hgVqv~=rRehPWc`F$NLXFqSFtSXGcQv6B^+~xr zwP@B6yb*#U;?o^mNMP@BkKkl! zny|yKsyQvTAr;$uB~)1ag&Sa}g7V=O{>=PV#h#8^Yo&-*+IpiPN8V?iF50mo3_&ss zOXVV_8!eK+%_IR$O@(4a1^hdSliFUJ8*Txg?>RhQX9yunVqcwMo| zk81FpgjOad%x#=V(LM>!%LC}^`5X9>nJmbFA-5Zead5&hWJ{7e);R#q_9<@NG@d>| zEy`@?$QQGvi-LHTP4F)s1A*#Meuw33vyE?O6O-jv^54vcK?e^rEkv4=bVHV)pQmDv z(kjU`%$>s$hdqW;Vi61$_;h`zI-{Kt@hL`BUU?5KWGn23f zi&H_lVqS3y7-w)A3NBFn4UAPwc6q3m|&y*C!!jG3a4xP2bSsAg+RetOl#&&1=qu}x46vDtF0W$n&eoWi7 zOc+D}-m7@`tM5VX%FbW<*j+TtUJ6(7EPNt^pZm9FKxT>DUsT-d@dM z?jAxukgF~!vtgE`gdIC^}$?t4TFFp&Nf5D z#;(hj?D{%V91Gls1id9zwqGxD(@_jvwxxdVF@mdpoBqOW_vY16AzX6x0Uk957YvmaKDc{FpEUA zbBVO?zpNL4^6Rp3K5H(Kojw)cMY;1B_6!|w8y|dfbZfmdjV@6Y2B&$618a1Z;mAqg@zdD(`zy7b--C>6IWYPy~t6X0t<@gt{= z#1|tJlhfd<7K(@vx`wJOl1+LFm)RuIyzRTZLP3UR1sY{2!eSMv;3k=Q2e;9=38>5P z@T^PPZs2`CM7^dj#wrrT+6G+{P3!u2laI^Z$?t$WN;xCg%{Rsj$=_Q6bI;OvqH(g2 zdJej&w$GJm-s|r6mxyD}r%xIQ6{iw9qFh50{WFR@pO3^16wY52eG%?o#rQQd9M7t`YHj-#g)ZRCUSDyWJ2N~-ylBuJGsx`@i4A=8)%U!+=g73TKH*~>9#6#EEilq3 zI3UVGcdg1hjM^;J8g-Ih4)@v~QZ#WSOeWK93GFtg6T~iyV%6&V5EEAOG7?Y3+#zx@ zwF0CD6?eBlVo~{T=ByqP)BJU%v9WYCw;zBtcZP%a4s}qvoSdVb(X}QH)ZOvZmP^?6 zJwiCXycX3VY@gm@87?F%32G$iU!RXit0QkK%3a#yRd>${agYUcU7zPZeV+p<;hCsI zF_bBb40@~#RWVb#c^*e}k&A0P9w--e(>HZfq?A(h*a0cB@lPpB$$D%(u91_xIEerr zc-B&MIQ;}`R0GPsx6f@mx{tp6)8+i`0km3Mbn$0Xrl=U0UY)Y2NSICdH@eu6?(vd% zVlei|p;_(eCsFN4EDI+QDB2Ag`MFPNxog$mR%14KsntWJy7fe8H$d0ennlIZsN3t>v zI~R>}el5uyba`QKR%=viL8+jJX^X4sY+|qf zz}BmVfKFIi;KaFukzT^x#BU+z8;TX@+01>v!PTd6shu;iRGam!+*dup@59*>OH83r zURUoVd#QA$>-!v3Id#EfOkMz*XAyg}^}^lCI-#P^fBI6a)AgXkk|Zx8`k^Yyt`k&S zOHH50Ly;ie6cd>5wS}cIOFVI{faBtYHD1cm4Q*08oQc-MUd%}Tlw7si@m|X^;`}tN zoqfY4I;xwG9yqfOv9cfN*~ddq8IsE66N5^a^W1i?TS8Ph=gel~Q8@s#8u}@wwdUc5 zzqi|uKE7x=iEKT`d(X5D)EgVj68}0Jm&(z6-89oxn+(EaHm`(+rq(S(g|$?0aX}!R zLI~1M_r^1T49Pp;p!I;|t0teYnU#7f_Fp3snay=iTm9`N3i`xSjT1g5_54Q!A68CN zauo_ABS>1|fkKt4_)Qb|5b8snERqbvr$>FLg;x5+>YzQ{0{OP7frGO-lS1g=#ii{H zhx(p3X;Y(I@e_83DKVWD&r)*d+2)y- zV!#*YWC!^`ASMMx$HUGuu1|} zn}e@)f-~`&-Ny@a4=`&qJWCi!iRerazDeqr>J#(%ok=~$m89q+N$wG4^1P3${ic#k zuVHS23CBa9?~MzfSU}+zqpu}M_#AIqX0yDfP^QlzZo96)Q7@M#^t(G1e&plH!&`=m z@?|wq#7EIqgr{LwC;cKmj23^Wwmelr8L9MQ^cEf7{9VMG(`F+7%67OZ7-Wl=f@!1U zncoxpd4X1RF;TWi_RJWCv~T9tR!ZL3eH;_b|s(Ve7eUz1;y#XlLO`?=@Q z9A4kCWw<}(<@_ix6sy|1ce|_f@k2)^W@xhJfowO!8qsYNt33sK5NENT?x1B0&FNv_ zmt%Bi&uj-aMMZ5HdhM-PX3G-0%TxS#q_d{2h7Nym?=I%O?VnQB9DU}@5v1+snrZEn z@s?FxG+M2kqNsH7XdL%^wbT~d*xU+M#>55Re;~fB=>=ue#ku@>LDF$;Wo2&Qe!!SA z2M#usS$Me{HjTIL4caCeg%3U`lM5KWSw#Q1cqjqr|B`JPCB_(ns%?x7CY-xZQe4c7 zDpU&>Z)*7d`H)Zz+#Fbqw9(1O7o6%h84!$H`DnRU%*N)X-2z`~Zs#z0(Kzz4SyifR zt(ITLiaTEtpKPLEsc?~7qJ$GS88XAAfkjeS?Q`UIaqt;qMjB&&yN|AC*}%G5sErQO zBG3bDE{(BmC3kt_n^&44%6NG>Z$4P}J|4~!7jO3QN1tBjCB`0Jon+rpeghwTkoW4O zE({BN{`E~zQASPSPY3B4<8n0h<2yV-doR?(pH70ph3ISE-}xJOt%_?Ztut5hBSv#s z4E@@Xbzo-^!!^V4$IL|`ybvUU0>=gs=f;3d_G7mZP*mN}4(UHOmsHDpnyR~s!WG# z>|Wx~G{QUX$vxo7ZpA0|I&8dsE9eD`Wi8wYc;E}AEIFyG#D8f*z%zN3PiimK^8@7x z4}CM1P3r7Y3$5oQUxRTCsebrjtACk3-cJw7-sUtgg~M*;&XHrX&yo3XpOBWNw$9_L zyDlD-`Gb{%S~t#u80uDAm^sJ~^C^uXh(kZc4K6V5>P?B6Ka$YWr=l}Yu3Uf$lhe{; zCzIo*1HWmp54D89)5`q1->n;Q_0&7n&sy41o&U@_#hZM#m!6I}mw-lz(EMff*%hzT zVcn0y4Z{AgW#qGd$xd5W8Rigy+S&})T|oNH;xX1PpPHANM0jZKe*at91-=i;TDStO zhL(?LBE!zefTp?NdV#(4QNI~rgeUR$TqJ~~m9WJShBrE6M5~F@yYP^{vaPA-{DUK# zmDzBO(QNjHrst7z9>Fuy=aPM^dm)*5Xf(#F+0b#hXnBPD*8rXJe&tA!qJ!zne~jt= zvlccDt;G?$QiO;YmxcrmoZ0)q!JK>M+h_OTst~cFhTc%7>MvQXkXBZ}^(kS+_LJn9 z1=s<-E4jIS+#yNdXjmu+X*g(zuryfw{!Qe`ZtM-WvDUhHW5V`$-md3Z-8v~=QCi$z z07G3mfeB?kbQvWHS z=(;^b5j}UuwW_@(kM1Xco3?|LSN@47TREM)Ea40ev$qLq-?qSVTTMF6pKrT0R0GXC z2{ViIPpL?W7u4UTXs9EyNcV%vboZ(b%Q%#EOu00>-xoX?xJ!Nbx5Zdwtj6wt(AG!! z^Adv5d=-%OixiXbs2U>qbpk^?6oqE%aYb_cPK0sCeu&Cw6|rOj!-5s`0aa}_K0FU7 zDYq@?tjjb-Gz5kp|>>3)yK zJ+Cbi?-=FbG!nhOO0=8!@M_Z@4-8?;Zh zAbKu|du{5G8;lv0W!RQj2)~?>%A^&@$&R>$<@fk9ME_p@lHkrJQ4WxX>Bw>lC073f zs?)0BW6x)J2rn0I9j-|mxiW~**yYr@=5TQFj^X#IN^X@%w5VodAB@>>4cVx-GCEZU z?Wmoa#hU|E6-W_Ke{i?DZxgm{?38*7H>Fb-;0(;Dtp-FVqXby9V`M4=VoxNVVsHLW zHYbC-I#(vP&?4m?6BbWiVzPt1W?y()G0eSF%2M8u@WoP^wxZv#yV9=6A5ovdf__HR}-rekgeq8Vm|KkK7+bx@_cz>nwjoz#!c-m>4S%#EO` z3xhU@7_z(BEvoZpm3*cU@XCmgji-Pcr$?YeX=G@Gy4B|H^3?ES*ulIe)FPJ(QcI!% z3wG;mL}r%sXT=)mZ4>rHnWajawj>S?4PLm*S>j>(!C#zlo=oWGN4Q5$^F#B;($b4$ zjrdW-E6PUrU3=w*$jbIRZ&pp84Y@GuQHB!c*YiyDsx*ti{!|0HKrV2vqmr&8`Y2#0 z!q%5F@YWCJQV2qug19wljoW`*9J^R5?Qo7|a#x|)P-!vVxPEYLWj-tMfpP(hxzkBvQ%Usl*A0+Cmf}o8soCJZnO2Nng~eTB=Sp|NZ`-Q08?*hG z+&wI`C@}nei0ayQ`CH{vnv~dUxwAOUUre%Sl68YQ=_$Q&mP-#uA^yU1teCFI-wY}R z&&r)ga;?fdm93PVTCHKdW`~A{isF3+Yt7Me`a?NoN%A#`C5$1VIn@1~e;)wJiE;ur zLtc9Eqwr&MlU#xh+XX$xs_aB=Mr|nJ_AB(^gwI`F^ z0NTxGb0bYUP35nrN<#w}|G6V`cqw?+5fcsz(?6sJP4AiU#PwF(1A*KDctX2%ai0(8 zhO={~b6B}ZJU`S1*<7J->D&S2iI;ZKfevF~c)7CJEaE4SAK@KnFa7d%asrm1pI}aX zEz#}mwGKqClGVMrD|EIYi;=mJzmqqovpN7 z(3c50*}TTz@5Q6noZ78JpG_rr%k@%Hn5(T!v);}nMzV6=N_AP_*cAa}1n~qp`sym7 zV%6s&Yo5+Fx1-Z`oAUyUxAm+#qnsM3V2e_USLxiB@n&*rwDT3)FtZLm%9UHl#*|vR zs~i;z7Uh({vSmHiy7{UFz$AuX)Dsxz8qefiCt-F=}H#>3_Iwo}fP z(?_3)&yi!?aPc8qkO$z6uy}<_V<@Vg)#M(0{b|{59_!`Jbc?m}cFOsO-YUd}J!iAzr08XeGYuK)(pgM7#o+pZYEmClpu<$g z+1R9@Dr-6$^7o%Y7t>e`C`WZ4u(PgCFdFI-#)>8RKiEBmOCSNSLhr0mgC1`1biuv;1vOi=!P zUEOX;Y!^{_o(yEzR|=JviCY~w%C{Ix^s7MR7^gD|9l4arz-Ko+B`=%}bcrW)nR^rr zgM?sq75eI=cu~N_f{o_@+(r!?IxfC7%wpGumJ~@Fjh@DDJl(`JD%!cZTjXx)z{xbI*f z#voE2x0sRxLG2=p5$*0_l9XP<H|NklFJC{TNRvWSZ*&@6XTY7g5Jk`lo<5oDyH2+ba8)8`?H`yqW$DXX zzNJg4Neg7n+iVd9wIh}ueBPScNN0ZHN)fZgH1>sCjr^KXGOAmZxa7L>P*C|a&RO0d ztK2XaOd_AfhH7&N)_#*;TWubG+6c2_P$-CkhNcN%pV}VCcsssGf7nyXkb<^IY6~fd zNf8pKu!hp)lNpp`hr4>5rO^2uwdm%{ba7_$0|nrIrYgn(jem$5P_#E|GZPpF(ZQ#C zr*ZNZ_kKL`+}q7qv&?+b?F5B3Fx5a(|*ZUr6N;YK)0s(q9H$8V^S76Uj(f@5iEd`K6{*dn}j#?$74$ z2{oSRTo3ZQS6hX$|mV+Rz97H{ZXmG1t>&pFtn49Kl-(5|&0s zNb0#yRN)?T8plG&+f~y4ezgv2%!1eu-$BR3XIDGWWOw-QOPEWEoR-=4nI>PDrS7~W zl0|saNaQl?M`Ky2{8V6`Vt!lvsnW7$e{zlBPh+wvC>x##D+%>bjc#a993l!e<~86a z+c_Jb-~5^IlBD^rEqjkD+j*y5^qQ-eN9Y7K%i}fkI1k$4!}tC2STHz&d8CMq`yz zPnsUe1CG7}f!w%Bhg&_i+MzTqRK>(=0`0GZ4E-tZ)4JC<`uyw_(8JPc()| z-i;3A@Y;Egq6F<;>bKOD6jAb=n-+!k1Rv*;6R8Hb?=>AiZ^GkUE3?^EI}m>zMU!Gd z_tQstf(rZ@W?vTV{*5P9LGlNs(;rSL@II2JW|QJ2kbu^ng(FPMcwXi_8cx>p7WpxJ zm6eS^&w%osLns7|a&5CZ4D$+z#pq-IRlJYWu59}*o`SDf^* zQz%5*K%zOdj~c5im2cuDjQ-r)usF2HYW&+#y8X9gYI4|8anQ}|{y+2g<(d@dyy!?o zD6#b@%EyZH;g$&RfuQfunzC;3+79LcseNLoJ9sCh){EK--{4Wck$LW)gsuIGuvk0s zH(6)vLkOvS@OX57LBu7;|2F1Qh$kl1tCC*9q%@&i%{D~(xR>Y&fAz%lI55^Yy;n0j zzRJwGf)?w$CbR5U-tThAe$DAO_8} z&HUAxs64Oh@``21G7_d^v=qEkCNQyV{;eC#pEf?5tT;1oxoX~U^iC@+N| zo`|px8=3;Eb%o}1dTYR8q3*(ah+MwV-aV}0!ahrAd)w%#mbA2LukR=XYE=1 zonI+l9c)%-0LV1A8;*v!}z29s(*JpomQug$d zn1C3dCNOWt_Uura<$;WW*#cT%+q%Tl)zi@P-(HEPhNA6=q`pl=770h9$d%C{A#P<rqOUe1C^hi;}&hP8_qNr?pw@re4kP zK`qnj^g*5A{HKE|t?dqnfECbY;c^2;z#cBAf=`AK1fKR0=oXuba9bR_GjF5IGi(5P zg5RvP6k*?0S*3sl!B0TfXU)xpPx~x(t+W`xfrmu@A5c!N6lTs z;c2nXapXY42VT`^0X8`CEsjdsqg%Ztc+yMNnpEYVVFos{pBI@IrI#KS*|es*dd}h* zC+X7k=8sxE6awu7b(!i2j2atJX^DMTzx&Zg%ehoX(8610(!g+XE6dF>&PpX#P1D%jGXv5<}p~=U2te9Hr|gd|7z=9 zuob9eZ0I6_E>I%cIA;D1$#P1wR+?|Pz!?3bq5-dtl0NIyG*4Tjku3Y z^9E;nyZ0=gmE*rj=cwf2yl&uQE7T@eL#meLyXF#KZGL-1om%G*c&e3fxmH~8N9xEn za}g1EpYXnSL!b$7q4+)GB=%||n>dN-G$Il-#%KGn!GbBPeGj7ToLq~wNy(;1?jEg^ z5zb47`Sa>G9u5wmu(Pe5PVfUK9mXL3^rp9*(h^qpZUaTs1N@b251fF%C5*bskOd1G z%t#k~zB5qnitcSqC9kw1sqa83J2j5c#APu4ILWOo{)wjU7{knfhjp5@t3Sl~HOS)K zFD9V!3VH7r9ptacJ#ASb1cH7`a-8_~RYpoxB#F|h45}Z%+|$JV6$aWJgC=#I!VR6a zrLQS5^cez&c5>i1S{<-gQBs|5WG%rpjG6ROEJ*KwKm9&zqy*(VBC6V`poyS<&?V)c zj68$EzPkN;TOdD9npihIxSu&*rq(i+l8me2(#h)8pC)jt(I=*PHINIK-MLVX)-CL5 zA&F;CZ{g*E9m{>}4Y_lPUnCoHi%nv69j|e%UyZfY$GVzmMY_c2p+$w^LGGl%B*Q)) ztweCR^SrfwVwohL+gwLV=q7-b58GD&VTTua`m2ih<}k|mnMv<-ZZEXc zkqkB%X$uNw-p#9rif{0Cmqa+vG^t&=RqDDF9~Z6at66Ke^<&CX6+{DZ`VBl`G!O~P zQgLxD9lJ)m4EYs!57=V7Hc=HyWOT9E7-k*4Dhg~JU(_Clv+`wM1M!{jBQnuEY|Hf+ z+e6I&o3K7#RZrUni4|qZkuk~2^?Xon4aG+9-`9%W)7=&K*g<4aLdU$o(D0*~r7Y?x zjwI!u%i2COlegSv+hwskJ+KL8&g@$tGBjp}uAQKl7+@sW-$GwlW*X2-3o)yK+JL+j5oZ1~3mvn{-@Mt+#o@0m0U?lM zvAtY}Rn%kf`X5bucaofnuR8Iw;z;~{$O7DM=eYWAXgVx~oKVubR0(}_>T#dp5~cSt zt;INrC%F1jyc>XmSz=U9;VuTYGNTUH_F{EU(N=JD;-BjogTRaVECy%M2Mz(Tg-tC$ z7N%f^7KF!QF!5vD8ekX7a!|q#OZCH0OFLZRnxMI}fyppS744lX$}@En<(KXZU|43) zSyjRd;Sa2Q@VfJjVN}a^Ofh>u%d5xs< zb0ES6xv&+lZzqECYK}K{weJ?~dHgq!{FHdQ5R|*?eER!>J0}M^-r)D;02_B4E}=|r zieGR0>SGH1Tjm^JqoYe_9RlN2L}#kVE`5p1+%Em;=k!@)_e*ehcTF_lzk?oLAh9w$YR3#Sza%20%TwQ79O@kxgDOm~m!dV3%57xjUEsOypqU)bUL=gyXA zVa;0;R~jX83a&PbiXu_Q;rj%ziL8thR`SkdU4~M(gBA(zNPJah!R~AzgJT4_G>s=- zitfcr#-sF%WiTKR?#E#YyHRc5Qo>O6M7Pl=qYrAc%5jyekF?0By2iNt>vFPaKv@2; zfgx(d9+6qd*l#9Bt zImpP#W*|+@g{&e%h*>%`Y__en_Q+wKeLVbS8c5x5-~M>p0~dY5ka;4ex`>Hy?}Jj8 zJ-1*%K%(c=sdY$|hOW3b;*6w(97?Yjcx*3&i|J-*c!of|gu#B_>I7f7b2qdNW+jLF zD62#?JY2N^QAnwoq@@ciWI?BumIO^!XHdnsBDjrN}5B@Xcg5?0szBrG(q!T}zan8l@gd-h4Z+WI< z;+RNBu73+Fl%qA*zU*(=0}9;>w~P~e31*~bMd1%%FCO2EZiur9Z>rQbS+6lOg0#X<7_nwWSl3|x zj3cn5B=;cjW4!`FJj%kdiv!N0^nF4O83HjuM0%UQ$t8#sxA_7FF%21G6HML9oEcPT zdiNZmaT(~?Q^KTf=h_y)g3;lH0`Lp6^{3#ton_cABJi?yOm*6>MAv58htjBJDux)n zuFtnwkne&&QU?@+P;N#?!A%w3`=R8BFLDQ+4{MQT3Sxl!RjiPuxM!&1oE=oY`;+`$ z65iiWXNT=N!o9OH;d`^f*Tya`E48gTYe)C7jq@AEL2BV#BazQ-Pg4HBwDw*4!=y|eE4rOd*1|qj2i8X*&Ypbg}Eu}sVrj?Iq`3(o98!^sQHzz zB|ZoQ&L2c`Y$1?$+hbeEZ!Oc<`IrgjdNYnB*DVHNQ2@amcQu=j)p>@Fj$5vl8bEH+ zr_|0nYdz0Wt6`66e<|pAs7xN{P^fqk+==iJPC0zaRT&S_j3Fe;i4-+{f*+|%l`v6@ zD{fcw)VNF7-b(}VA)gvmw^ZFtz1~R{Wz-f|)$oCQq}$a^`*%6{sP>DRMp}u`#Eds` zrTaq=DtLUz%WnM^1{Z-uBNAzKXu#djI?Ijf-i2qNzPj(yYeeU010`2E*d`_K+w$va z!!YUA`$2tWjXKD?M)&dx%-?%f@gyX#pJ;U0a2P5fWYHI)vV$e*=}Viu!@r`~1Q+Ib zDRW~)lOrtaL|9dR&f*RwOEIp`tnMlN84V*PPHH`aJo%-HaCVizJYPQSE(XvstB(K0 zYe2CjsOS!9N_?oC*QECZqhw&j<7;?pSFYO=PkYR* zv@Ix|bd$2S68tblpq{tER8Y7r{g$yxDoE8DyM0vPp&>ug z=#u1e!7}))Qf9_Sd1^kBWDmq>h_vx!869Mk+*^Iy$DnuwZvtQ_B%v%}<%dy;BXYRr-o; z=&Bo>?+7H|&mC_gXesCQBd*ueKdnSRSokShaQvex9`;0RF!zyP0)SgJi^j!r2D=}L zZoy3CuI`EojfT!V+q&phqy-V{2$4cNwLjON0MHv&r>+5f-fc;jwrwBd7HJ`jA<-3q zqJwmz}pPY7$2z~80r9`bNFAie7D}qM68t^6JnRIYBu2)E z0k3XghVy)2BSC*(swioxOQ1g@YrzHQnEg!!?NC_jF%{msWL}MFj5SiHP5nKF8MpDz zb})uiiiOu)3vlnK_Z@;JaV{PWA#U}X+}o|>ca?=p0al2rkWI!cV=UyDqAuGZgGmwB zC&Bv(g^@!%P#*Kplq{q30O*^aujC_*46IBq6sfSa)34?8f>#vTgb?|7!0xIt`DGOV+-o5&*YpIKO_98WpT3O^^lF=VV0M zsf#nucq(m4WO%gP6~qd-roiEb=NG=I^T<)s>%0VB==uubuQbN))c97;K!tr^Nh+&5 zay2mD7<`FS>R%okeDy(w$OI%QFnrEPZH*1)S0j8FPD`#8jn{f=n1Ac}hEdAG*bu7j z&S?Reg8)SPL{-Z2W?MjSx-BzTCJD_RWkq5lS5A@{6a4AI+WBN&IkuCyQ00#vDdsy4 zZqIV!+yn2=MUYB%(`936(|AD-ZMUp7=2^MA;7;d=42@evARQ|@w zr&=1S?%9%ds^Afj4^#5Fx**rDlcHKv=i9=G> zJa9Hq6bI97yoH!t;WSKmN7P&J@^TU+oLWFYzME_&j~5!XRrHx5U}kuAnEr1AX2jsd z_{B2}WjJvb73E6Mpq&k$mOiB$C1tb$)YI*^rSk8L5&EjaUI%?KcL6_W{8!P1M3JJ8 zlvs{2V6BXeZoQw66Y9$C(e)8D=z8L2H>RDMz)RN82f%(p(y#`lz?I*aN`5*=$T|ax zSOh^vyicPaE@+}u8$!z7dI~g#*QHBjceagg-NV=w{QXoEYi4g^~}xj#^FHEDDubv%TWY21`WXF)a}3vF!umod3ym=ms&zWgu@RMy(3#dI=A zNu-e{R`*X7KnbAK2)+uACzip=nUU=7m7|hqbl+UPs~#) z%5pJ~MR~zyc(ok2@u<8xQjYYmJN86f(w50nN_iHUmFyGx=%2_z0g-fH)oXrJq^B5a_VGc})m1 z-_UiKJ{xW6GBl6=)GFzN zn4n?cS&(J-``f8)qE^tQP$sud2Ki{?>}9oAs`L~6!Z7(?06{>$zln%d@E>r;&BiB& z^DgAX$DQ>80M%9OkNB#L+I?Yxs0c| zY9^&w9H!+ndxZ&AgP93KA_L_?G`TuGy-bDr!FY8N&i0Ow+tTX33O%nMLH(zr5rlW_ z!?2_=iLagY5IZk~iB=EvO@G^Z#W3%|;l_o!oy0OXWH{-2tJ|f0iKC@Kpk<0@Im_PSWo@?@CUz(|rCcD3)I9>0<>ac2RmlrP$(>(N2&t&V{?!jiH z*xUv1nE7kcmb^iKl9kueGoIPC3U&z()u5N}WEyQ_H!@e341dpAST-fcTa>MtXWrf7 zsuZ*wz<&I67GJ@`l2;Q6XCt{U|6ZMi_1&q&MQUnlrkNfLGt&x}j4TlR5FxOAElDxM zwMwnrEi>Re(TP$z^#8iY20b(<(M zX_8BWBq!=NiGObhQokR56jGh~iGF9E@R5YLZTiqGb~2>T5N5%|WYZuT;l$S7{R&r1 z(+oUDMi&gisop;W1W4CK^i-+n6SKNM)#-ccxl3raeBOEYL>vlmDeD<2^;Hui*Z&59 zKKq2P_ZZ1&K73!){a$IesM*ECejKv+tvGlxcrS2Nw0{qSwQc=YISxjy_|{+?u1u|W zB$)`y^}6bH6hDeVqiSGNFSkycQoo2?ar&5BKJR04YFII?e0Mf$Kp~R7PwFn@DyBek zG5Jh>SzK27`Jr8#aPWN7XK`fL-H$DD7V3`-vf9eGi3QVA%tAP-kfH`+u!C@$IOQ+1 zl!2pImw%C;EtWu+8|T}26W5=s)??kfW38wJ8SE98nJFKj%@PZ%Uc`@ z$c!9gxpquB^wFE5C{Z9lvzEF79kpGekOwx^D$*RsU=IjJBep>IyrYb5MgqiOB+AXK zA;C*;-%u%lvg%bAK86+-%z z#Z{an&{`}CzDYr1;1{$>67W2;D!h5?JZ)@(H6l|w{s^xR=wh-_DhuFHWg^}t7Rf9< z+M=!;dZo^QnS76U0v$29M1h;^v13xUYD6`%V ze=MD6I2&Hr#*+w12x7Fh1TkxuqE>8b)0X-xv1!$4wRXhbd(~xjM%gGY->|R zHTDi~-}ic-ujjhX^_+8_`#Hb+%Q^Wb(ZIH6JpSjsMJ0i@ISU(8+9kI!J|)Y9M4v31 z9{FM0{Ijt#_QF9w^@F3uFn8Ict>r0!e+3T9rZ(rI829h|(P_qIO~EY%xDR$e)p|~9 z0Wh>etU@j4ZhucUhwnN#Rl!Nj=e4Aa_5x=BZghT3C*%r&vun}oi;md;p`oVd-+a&T z_VOl6TO=g5LRyryd7TN^%bYycPnWbvTb0@*KGgY2`sUZCY83Ie`cEC zzsi|24%^K^YWkG??wrhA*ks6e^8bhGq@q+YpMM2hsKgk}a-PY-H+}SG^6SIXu=iU^ zLU;yA`v_MQi%GL$@rd0&RbKMQ3b{=l%_b0ZT8wlUnH^xSZ~e;G~;y03C{2xMJ;tDMBc(6rjaqnPz=@>7SFs9(Et z>JiHLE8)8ze=OA2Z-APc*4a);|T_oHWS z-(ddJo_SlO^e_Q)-uWU>rWp&9Ajof1sDyjR$yQ0|tP5mVvH4VG9{Va!Yw@({AD%aH^+!kq3M6qkJ18oj@{Z~mnf2-+<9?OF8^hc9y zvwD};hd1cXA0!^RL>SF)?B@vzG)It3rF2gz%61q4_GLt0`Od3s5aj7*8oJ_>WX|@$ zjoZbhKeX?E)k&?_4t%w{Y^}3SN$qEspPzahav;1c>$oAyWdBPGw=32+xTE9W?)p^e zFIUk$U`JYi#%B@=f2-}yR>H|%$PNgI%E63Q<$44iPwusaz9u!hiJk$Wq?`6t z4xUc`!c*X@r*O(v&zS2iuCTfeS~pwo2T}8^^3t6XJuD`-!4p}tp+acq<;znkK_Qz? zl}MpPb6FdOf4Y&!JcsWxz}`L*bJ1Ii27EB-=MK?7&Qx~qdGND-TsLoaxCT6JuIUV8 z$sQUxK6ZA>>dk3xxabj)?@f?*214ro8e~FmV*9z)IZ}x|l-7;qX}rpwgSMjI7Fh@{ zI{jB^iBa>mPQCsmh~W)*QC3lu6o2%B2MxqlqB6p7e+K$?E828NfVb>MRZ{y#>3-}; zSZ$z9uSC>h^9}rci;$X|MK5(BcT&&PaEqZ{Te&M%bPJ29MZWIJ8eb{F>Jx7nA~1QXZ;u@(A%J;z0MM3h9Dv^VEPp5FhRagFR2Nz$}l@waJ} z#A}18Roc&N+J*S6plPIjEHkcnHjb1e_^EPn3$QYi=J+H^&|JK*flLl5o; z)Sq2S{8|H0x2&Dl#Y&rZqel%lDfFZ({M3JI$n0#gl}fFW*Byv`93Wqgcw4~Y|ItWv ze?(P$n&Wwpp1F#)udP0A%oq99S%Irt%a>2Ki@nj|M?~i4NfAe`aHC!{)<}(_0$Fu^161Up+?7el)v9)kN4& zT}qw0g0`@`;bafBteY0ZicE~N4d1i|CS zSIMD!$h@0YAfUfLav&=V{`$zZD}ISTGFsw?+n6ve+Z1~0rlC94c29?JCkcsRf7f}o zz6zjVXD-k@PLmb&%rO))V4u(PVt=BvE1GclHecc6X#0b=6s9wg0$*Ck>oZ7P!bvm_ zeqIA!fTenAs~RPGiXWao_c6&&XSlGFr7zjIcd8zjat)aO%hSv&EBfTyYAMc=mpZC9 zVI59X$^C}wTwqOe>~j%ovB`fnf8;N(#rpbPbm%B5`0ye^vVp9D>Kc%x+{`ram9%2s`GjQoTz=j*>5@kq85^YCBhxA& z`o*TrCtaquy!QO;?4^`(F}{jE{1UWG)ll!p`)9I5-j+i#w`+~L^Ml#sf6*We4yn9X zVDQ0Zb3kbql$8F6oHr=*HMx#yNg?N+4xkKBc#>DVKc|{ESD+x#A+H`9K59>z>7cZi zwsH!9TQ)ndlv+vm+{~GPBUPUt1Qb>+6CqCt6!0AdCvvk;n5^WtALec{KET_S3Oybt zZtv__c=OvtWLdR*qcQZwe{uPi2^7$jcjBHB=Pn`&7EFG@itl~;8&-jB6?Go{1rrhC z>se_22C|`tc4S0Gn5f`2z?tQqG3hL2&ER=4oabIi(B!|95HL=+7n<0f6!{F0F_h zhx**2&V>$h_{z3{dVzEEYaN|bYKKh#=RmjCI0YHb=nOZuJ*CJ7eUe{|>~5pp;ItZ< zdTsUjrHS1$nu+Lje}mHMk96bDN+?~^UmiH-9t_m(G5PL@>}2SiMXm&bHEro#`TWZa1?W)`u2PC{fzqrVO*+>l7tMP){%7E zD_`O}gY3W~Gfu?)KbRf;&u1#l<$@UA`!;tscqEWCV=^3be?jGIRB`3Y6n|!i$hetr z=6MZ}&lGPZ{l~fc3>CX#p8H?A`9_xtpymd(3E#@s%3}V%4VUJF<29zAQU`6&Yl+zyy5}pNL2U9eRdkytyY?#BoY{kj~$7L7?jt-t3(Q zRN-5ZmOIn3e=lQ6em%bg!p$}hHW(sR3^|6OUq_JikK@I|<-ULq&0bIQ$IaSnt^+7R z2U#Ujggo@sgWz*b5jnFk)_KNnQzqED(0F9B@MLV)W9D-o1~5wgGzNaT6l%$=jSO0# zw1zuLZ0$01KRRg&7sn5eqov+E38{UIgTIYE)4bhze{P#v^(D1T*+*#q0WFPD%Ij}e z+2fC1;L{totP1b;w=@Lr^ahz9Cde;-;C}OHW0O{7H=gH3a0}5qV}EOLfi2etslCjm zP;8zbs1+f<@Yt}0XP7fNu+&}_dNU#a+Z#1H-;SCmhDPs=XA`1;_cAIFwO2}`dlaq{ zukf_5e@hV=IX~C>>bJ7qc5c};f@a#x0S6$ zxJL`Q3Ei$jeXAQrIA@4zyCX}v`Gx!Q{;09P6_5-0zBjeDAa3fV_f2Yf#7|YDA_YH7 zFT#Mn1{hJo_iqRL3_I*j3^1lYemcdLH4V&8e@?aCS$ol`%9Z`r(84Llf%XA#ENRlZgF%@o87k6KACe0kZl% z*0`m*x9eA~*js`KC6}!IVOqxnvd3p#y%lndzIIHS}&(lTB+{r_B31rnm_iWbIHzURY=v z0^46g?s`%raq733XBFl#7fO$?_~!ZJ+tY2{3f%{X$2Lo*dcl5 z@W+Wq8z8oyc;+sx@Y1y?saqgN{)|Op6{xzMZWo%du_T!oLAD@!s}55x)(aaDm1c+# zStkz2zi&?67!(RQ8aFEBf90z2f3kBxjJF-N;A#nzD2EKt!`kCYH}g-K-wufdywyxA z1&If2m$5et$lLelmc0I;#crcPWQYG498QfeO~;kN*K|#n`9iv`$}(_f0X90qytrpF zRV*xq9YAf{tglU|@v=x+<{O3-)REC~@`9Pe?ir`*d$tpvcsF+%zM%VUe@+9&82Dh* zQ`$NxQ9fUarSF~skGo0f2FL9Me7e|E?b+NN6G>N z$ENw>n!qfrA@^M4k7Hu88?AKug8|$R;`bsD0e0rOcWOI-_&ewS9zD~fJ&BhXmpis- z)^N%(~^dS66b1B~|_eDEkhafh<(!%1s=t&U05fO^l@t6z`Wy?y*?1B8XM-ThXJpWO|OE3hyuNK@jc`ENI_{QE|gxs78H6Yoxx}nGjE2`$MlDJx4Z??4)Vo^MpfOF zBm-(${~8HN&%fBiTfugJemd7I!;LB39trZf22|*2e<;-^kN9se1`fUqo~L;Yl5;F@})XMC3;1`cRlR!SFa|=V+c>Q-;?28`XUACq10`2puqU9bh?_) zV8_4P>;B>MwTZvHvSQzJeD1TY{*!H?7!cuwCmS*hUKRjkS-B+KW|g8yiLqp-;bdZyC{C=W&c3`RW0lv7v zo01?K^g|XXS9^@;9NGr!QtV~^P{qUDz033E+Q0q12Kd`;$(g`Rmr`>a-c1~-HYQW! zrG{=#s)|V{iKgDF-q@fhclGepnjmA!e+u1yRfSX&xSwUyd~y^rUGb}oR!*X%(CSN> z+pc3;Sk_gIyLk&AoAWRCPVRASdl-# z41ZqliDdS>|5a8&>VYPR@kR*jg~&ZM7x7E!uwWmArhQI(3?@}4y?c}2VX4&VeaWz9 zWM~hCE0z5FmjO8~rAGS9jrNY@f6pmksrrOT#8i)0FZ7<4H{ait)a8z3Tck`Mf@wQ#p^-(4gQ#DxJ2j^IsUeD>;Im(v0SXu$VK27yQ{Mos2(-I94(^6e*`VHI&atQ zU$ZKz&1jX5Z4i;$8V{OVii^!|;hS~g$P(Sw{ko*@u|Z>DBX#y)l=L{?VMp+xYf-03 zsn_9%fOHbrS>S1cg#WKLzr8c3i*9l1E53_fss*LAo?0KHw`o=Z0h~0CvwvguBugF_ zQG9A*nOgB3vQa2D{-CnBe?aL$b9Y_Z$`z1 zT?fa$7^%ZBD;i`iDOLI)wq;@D>CGU@gM+XynM|v5U$^#tdfv%-f8p)T&b9USD|;sX zXXi8@d&yJ&l|U{-RimG~dl6X%fTbP}w#XxA1NyxfpwML_Q6i^%^>&qQiBEg_vhaTs z%%+#!r4#|SZbb_IU!EQfpeZ03^*MUa5wNSukE145s=5JjxlaM}JH`uH*MRqwFvbCO z4%r!I@QHfliH=uaf13cgw5t9p$z(^S07BsrxR#86Q%?y7mg%+x7lYU$Z{G1t- zEXwK=UDBfF``d1LX8FyE2k=7w*VzlaDRC7>Kh5apqs*#Sse+c^XRq2logy~$Xs*VCi zXxIR{0i>NXHguwUDPm>PM}QB%Iq-e;U+(~mMW}b3gRkgi<1(zS@M(vI{EMEnN=u%P zXR^e%zG8PX|^9{z-Pp=cqdK zu;fK)-Mq6Ne{@=N+Du|vV+Dbv>vG@U!1V1?*p2^80TKmb+V)?b90X+L`V9k`Ef<`| z8`$>~ue$)e2mt6`0KsHHAmIN3NXI1sP%*ag3{EcEt!*D$-uwTDbb!iS!V(g_{n?Y3_IuD0GkYz^@y>I z*TYP~+2%J>R!(;AqNvq$K)s6)f{*Sebz)-40Rw)x{Th(398+7ne3LORus}NQ)@w~I zo~zRi>7x0Wq`zBB2KQ9%gxLLHt&q##_(->N-#GIr=MJ zq%ud^e@txI_`JBU=zUIst5|aSafENt=nGPEc%oU?VWJ@aQa8JEZ1A0Y4V-eUdbHbctoLyaqf`_9qA~(vIzIUgC8@$|I<=qn-zWZBI7f zY7*A~U)cf1-@EgYp%WO|@7-4amyn1-6N~{K*}A zk1wtP9{J;($)ktet|?P>LjkzEJxQ)gS4TTOEE|i&AF|rySD!axj@$2s9&BC%XonG{ zX6w&ayRhhgxGMi|a{KVd5=RG2tL!6%3H~cSp1N>k5A83d@-BKni2>awWbx0%GV@c7 ze{Hksz`q7EiIMAphdnN|?%lLKfZOd(BfWDSVJ?#tg@^u?4M-pVD{MA#SB}$HdiU_v zuhwfoR2(iY4T=LNe;9Xp zDJ-@zI~%5xLKiB0v6Z(@_$P@RYwv6T7o4SLRrEUA(2K5Xzyw`t&de7xyT5_rJXli8 z7w_dI35AFcW_{)uMwor~O~HN2#De9W;oYa-*Q|7 zeukX=cW|=G3=B|i99xCHyds4(cXq&daG2_rbU7OssT8=!nTb=!wO$$%V&l1S7Xz|h zwz3x^7a7-p;?*i)oClP)iT`B$qytQGb%lHC(`VSEtTd|zcz0!Z5{JI%e_G@~I!~=@ zV{yv0C#mu%WOsqu+TtUM?kmHwX#mh{t@y-q`d+YD>-q(@@HgA8J8{^9H?e2x>>6O; z%rKx3aP_b;D)uhd=`|pHU9-j7iX_ZCu7kr}EZzE`wMaX_10(CZQGJ2*y#d&sNC;f< zWYnd9DgSz7rk4ePcaVgTe+pWo9rMxuk|m=MxC(gDCf`XWI+3`~eGL!;Nb+rLU9fCW zrzn5BaI5R+RK3}F@?MrUdNFcZ2TBvhG!v-d_H>13EI=N$AfDGKV*r;QQfB(nXnG}nA;RIR> z?lwio71RzDsREgbk0SfA78Jg@9WMBpT~=*$$(&896%upQ$2?FK;&uMKi`wt_7hv&h zF&FSz$wctS;V)0jGX^EO%ycj22=mA}v6od!UULMaqa!NgUac5HROYh{i{nchJ%nBf zqeqMXu^OH7BIi~$e?MML<-ll%cPD}lep5kZ%6C^BEQoBY`!XKlNbbR`?qB6U43n9& z(tm1c1HI$!X;Jw^HR1g`{Yg;|ZdJwLvo=|EJ{xr-P(g2Jd-2a(_Y#-2YRvx{gSC%> z7n>_lWPIE{7HQW2tJyxP!x`e00$|E=F^DLOzPd+?#Cb%uf7uc({S+`CzjM%5v`U9< zX+0iXy&A4zpW#0^S@ij;{_P5pXtn?~WpAm!3hM94LM&^&u4?vM3mzF^Y#Ww+L7~)E zTghg9YIWlIqr*9&6?b-*z*QOv25SW-9 z0Bj^Me+2O2MHysM^gT-PL#wiW+}I?r5i)cFfBc~xHNOY2f6n%LbvF+i&TpwrB2IN- z{g`i8t6l@30n0q(CuAEV@o;hQyF=SVT-j8L?L^c(gVo|wI1l;n`_@@jW#sge(HCw_ z3#!=DEG0J-!@$wAIY>pJZjWRk)u~ypOq`jwf95hMDR~$WETHxyD(CoencMbB^y=>o zu{X%P7WaJhB|h*jYh%mVjqTUBO6o)-8CPimLCw zf0ghrQbE!GuJfiFWE7#*NB(~)C?q@Os}mY7vAkE-fe>QBKHTr!*K2@hm=g8g%MsEl z!>cP|?}?8+#nqnY?mpPC+`8}@KvM(8qv%O%y*A2i`89VbK_^H^G!ZZ$-P-b0Sm)AD zEAX_-UV|CAp!~@^FmmKn$)lZO1eXh3e_cds)86_Suq3R5G$SSu)jxo}_v(A+@Nq-c z8>Xpz^Fa{h#tpV&;8iUmp0;skTGB{n^YrYb2PW0?D?sb7bf`YLf$6KVyQV7l1Dgjtt4GN(&p=f$Fp8}sf0p9- zjCj%mrUG4_bKsPjCBfR1hkp$Vn6>5H#AZ%<)Nl2L9G&=}DurpQk3z6qy~;a*K7O3m zjDh@Cr#eaXBP;*BJ0m8igsbj?cIb&m@UVGb7d}sdf8tGHg!nA#y#UQvHz2o;JVHg4 zC+Rl|WA5Yx*8|a^^vFm1b-mJVe{28el++Bux1-_4c~ITOA9u+8ab~@VMt`VBDjIf> zO0%Z*319PpsKc?d2e&8$RX40wM>b$- zZASN^?p;<}qLPdOmKQ;pKx{lT{`QJ2heVp>w(h}6B@_d;K3nx9Yf8+$JyI0BO z+Fm$0_z51a%83}RSQkp(O^@SBaq~rXI#rU9)g)XNH1{BEwc=+MWdRX-dlOfmcf|qF z455~wJA2mkt1aH!F$Kz>?I*Sp%~gL>YMmXEemwxu2NiKF@wNg;WBzB|+Tm~C2H}Kl zjyb&oDTYA;_K8D>b@xO!e@-48y$CM}J*r1I%9|qiG9LH)~ zTkYg>&X(3<&_z0sc9FDk;=Zx6N^}Y)h)8dqPQF}7fS`=(3=`X!(Q7e`O0V;KH_yYH zqWVN--&eQl+k7OaJ3Id<&Kg6%Qk|f@wuAuouIePZzf6%xto{4he^(r+R$U+7;KE+r zO}j)OfYl3zd>240qr8t77kj{;xeKgJk3T#c;zcIY;T5KjXLbkWxMhuF@mRq+OE?Rl z<|bSpwvT!uG#IKBKcB%xPd9}+y(Qz|qX<=VYw_f=bd9uWGTyXH|1I2!QC z4XgzTfxSCq$YO}le^IMvyc4>FCFJ|wP!9AgIy)G;67PWHi@p&PRsmT0!2YYnd2BEm zXo5SbxU~5skgTKvs+}>=I4Gn>P^pf3wJDHx&!rI1vUNTq%)a zn>&>V`amyPF#a0AErv>i-*45bF5@B>Id_$y^A4~{{;vuZczkS>xrC`MXsVQ!qfxpL zgM6E1g==lvtaH)+$UgZKC&hY(0#;o}lEh(P+n?@ho?#RQZ38EXWpW5sj*7Kd5@O9b zl>>S2EW(f$e@M@dl=$+w0ME#HUQkBtC#WA?Y_gT_uc=WeuX>j~YUf`GXS{oM$e*IR zXZOu`0fb;URHZmWoSUOEr{XY3Cs^!? zbm^h;b8x2MT8{@=-4NGHUh`x6wM#Pj~XOpxIlCyK~L3x}y8)B5;ui zdq@B6%5a0pN_nxD#7`d4f}0G`1b}I)t=p&s2hNc=PJsyPd?nENDTY%~>C%>5-}4%v z=^ECXe^_O3BgvR&UpVz%Z>gm8Gr4dc3V~=W9CU$Dhp|PWL$&+c$BxAxNT_lrF@k6H zKf&a~oP4Ar1a#%2{V>8>#*_6RSv~Ts-*d2Nkdb@LS&{=i_`L`FZrmFf!dMsqCg6?o zc>~XD1QCUhmHrEl&k))XYs02eIf?*W%lTrJe>kP#RkeG4uxgCcf7?3`5gg6E1;|`X zj5&X`0mSFEq+P$L7&CYe@q*Af@r(J{dnkmVMtMg>4UZ?O;&8yB%!U*LBt{gAc4KY-1u zf1qc4Tr|I5Lb#*^_21C2)6p-*2!z4!$9|EG@~|89d&_?im#Rm)a@nRN>%VKQWz|XJ zN5icA3As}#oNB99Al<o8z$Ae#9K!Ljph*n>Y2x|GM4D=h9 z3w5i%A$z^sluOX)qsiMv!wQ7J?ThI>4Db`$l!PpZL(z_JZ=H15Jc`{5Iu?(Be={;I zwk-Grh}9`dlIdn%bP|8i$DH5YPVRZ~MX7D1g#sMTxEi^^8qiKqK`fjt1?4*SiMLx- zd@?=)Zq7ym4nO@1JKre{K=i{PqCX z;=PwZuOjsG>IP@v0U?a!)93K~55I^$7-4D7tExr=W7vvZRh4|zd_e^Sqlj#-(MW7H66=ONMozQi z$=(bkp%3&$O@^axm6UzSe;d<)uxZ;eNPt2xqo2$@ctSE|*FeG)Stvy^GEwd~d=~Mk zV6IA`bKxDdW-PtN!cBVOt2Se#tV1w6x6J`MP7UV2{Xo;my3WKJeFMC%SXugizHWP!kef=s{20l&I{u zphJZEHeInR0=%u$f44&flD*DZ_l|E0E(KZ#(Pf9fs5<+X%O}cEB(e7*=OG~Q;%X`7 zuC?yP**Dg_aU^cR&3X00DriVJUMO&+Eu0uXrr|<5uyTUuyuSv>_omabZdA951N#fC zlaFiREaZ3u{{ixVuIUX5hn(`Gf)GhcPVhcJbP^yLoefZSe;XD&14Fr|ylU;BP+mdl zpK)XW3gZ|{deB5_ZIy>Q7!Od1)k3`{2a}bf$s;rXyL2I%?DRY_5`5wKLeEgLM~0sn z?8*O7YyJ37oh4FxJyJt>;Va*R4wht|&?lwWfPkRnuzSy$l$(vHGS`u@c?T(lX4&Gn zP@=4JGSD4&e~>c3@rd>40)miIv9k(C660)YASbxlu66+HYfh;(222V})`QwPTFK{) zG8Fw})d1o&E=NcLdugHP*4+|w>8ce?E?HK5YC3G+7w=pgb~y4;S+EsR2jn&1{e(=e zVo=V7qC#%`?l01EorCS)W0f|L?(guTJa#T1?Z50)wfXNcdG^oeTJH4Kl5i$W-eHP+1k4ZKD9 zS<7O#>$2(?e3P=k>}w{*v7AO)Nb$XYMVEF8&vzHSe8pla<_6`>b!lcD)9QmCM={0? z!L2;@e||Q_VCjv;oh4A7FR}QbjhQ*|S>ioa>l4a%X{G9n$5)j}F-&w^-~8K{8FEa# z6v+ZeR*5ET=QT8-J9ZuWU&=S6zFZvj+*B9X2_PP<0(|(pwvSFU$b6Qx8hX!fk+ab- z(smNfaz$~Flf6I4n`?Jx{>fiFeJK!WEXQJYe`M+Z&;3IILg!a|cyqTmu;bznHgrg_ zhHb=X{fOh;e}gHlq}nS5u$s!niOq<5Hu7=nHQ*P7w}`7NPAKN$ZesYzD<@t$ zv)NXN;c^^1D4Z&MTUnXesv+w`KrjCcE3&lsWO?~>faGF>AIv`P7sX|S=Mpt-0%vuW z9iqLhI2kB+0h6{}F?wC?F`6*6U^EYgJnEiEdnTRGN8FJAxiXr0;5f5_BC zK-L4Z__hoShGe+795^*sFoyHEfnZFl4k{}VF|$I0;wUQW$mc`Q5iX{|X1Nt|p7)Ng}xi4Mu(AFKpvl+Ip zmP9dRp>!74fVNHOQw9$w(}l)Ke{68;alCToY5+DWf{tP02pO;(On+H%v`R-0qN!et zRGCI_Dsu;%UtmR(vi&1BXD$cygLSvm5+r786cr)X$mSDO#i!j*>%*8J7FkEud00?~ z8Lu+cYET0&Z|2E0px`H`R=?81>Ls%tIV)0Yb^tG4#W`t4vF#(kaOdFXk3swL4yBo?7%5bbWdOR2% zLdJ7O-1fOq*7=j>Yj}KLognG*Da*yfHvhH&HV|Zt75Op+a!@_Nf3>pqiF4!K;fxx) zgsW$_SleHHR3qL@V-KIhe>mxID;nC|j|MuxJ8{f>vmSlg3HDgW|NWvF^CS9BdoBck zA;Y&6VOd@j>ENT z&J8NxEem7*2D>K%^p<7)XaN;q`U>z$jHs~OEVsSc6>%eaPT4>Lf9=(V4EiL^^CxIn zygNz;^=b9oV?YJnYu(oD;q z()v_;>|8r+r0bN0GzrrCa`!f+t+|og*OwhVw(%EXKCIQ7zFa}a>VB6qw!rjqu3E>T%IVgN04d7C58U0k3ZiyJwSvk6~o$@ zj{>5`(tGCxfi{#5g`9S69&NHdBGofNalGLYd18%MOVo5^tup(&QW~x;q^lSBB5ab( z5GnVWWZaPRf8VzB>8Iji#0#R2M)1VX0Mb#^E$Z*gmRptkn2ngL2q|se=Jr(`R<$RoVUT+*0fEdaXxE;l zs$*vMf7g#>ZNX8r1B?7wc{Micy`+m#bh}7>P{7$VYGmwF9*LP(;N$=54ikKLDsP)~ zY1@IXk=ZIIEdcPzsPixQTl>4(KzV2Lt7E-wK2#W2$U|shy2htjLT1+yubvR0E189# z7u?5Xg2jve+Gx_G|4-e+eKz_iTowh37}Scie{h=07bhnMy=yFsgeEbiPW88ar$Sr< zzW%}(9tdZ5QqFp{P*yiGhnYxEsw|OqljTF#zRn~YH$y?No6cQDAg%nz3vjO60kp8~ z$8iXCR9~&aZE}C|;wbDLMn;~S!E=N-y;dW6P@k&Tqjnb8vTiKK(4Og*?epm;k%S0O ze>F3_1EZOy8i3=G9vj*we|Lki7bV4omgo>rSuXr?f2arZ0#{Mp(6o zN)(<&e40D*tCVy+?)iG*OZJ}Eqs4CFfAX0q?dA@#Qt(zl5zk5Y3U{HN`-;qC%Rd4_ z&IG0Wea*AVTw5>BZG}YlSV+zVJ7>#oW@qfppSYl`+N~MV5pZwzP1uYX>F5!p{3??lM%1RbGjAjF?5`7bb5X05<{=dEO)S6n7Vs&@;|dH*+EI_v0N&$ zz(Nd!QU}1NL(9dl$+T$1La)+ke>XIQJuc)F=EL1R><7DwlWU)7mKo?pdR(qZr8}HA zMv6^p6sU*A;Gf@O#|wRDU6PsiUJ&mDDHb1*{T|3m0=Knk(z+uHT4&omxPeu^1y6c; zG|;UDNZF(}-WRjDwi7-R_0gc2A*Etg$rsBV>n3J4_IQF+iuOB!H!Y{#e~mOe9K7r^ zZ?tF{X?w!+(eKZ>Fbl4 zTj;JrycU1s?7}p-@YyneD9R{4e5g2{QtX&@sL?s~#`o+>ixO8_}oeJq- zsng)0Zl(qRnJ(brXl_jj9Qfuw%}5PDc?>yF6op!jNG>6md4<@*`^*#3FH!S|h~Rl_ z9|S(C2BxbqVJ)OMf8Ke?Jn2tPsqxetq@z|8^m|qNd-L2@bDP^Le@vJDgIkwR!7!OV z>a1>55$Az`NIp$$TU&WxL97lkO(G*fdLOUWLhPsLE)S#GExy3hfu?ry4E;`4(S;tcn#s_NjNZzPf6h=F`UAjBKUGpZDbfk zu|zl4d5y})qq(uZgCAJo z$GF_RV3UU>zCs(zROnf_Gd(8UZu%L1?3N(YP1e-}&qg2!f0)nVV;xp+)IN}wX3n#O zO5n+B7GYKZywc(Rk3l>N4@!$(S5@~ci}_RDPbWm}!FWd-WvlS8l1!Y@xk(mbiZxU8 zRgwtSmDCoHW>^pe{5J?OSMvNJ$tG7A0{8rW8YjT>Ry%^7lvBu5|Te)t420%OC+k=mvfj3-K+s_pq;VcwKYaZ$m z26KJWf9+Zn9ZZj2kRB~fz{@7r*c=RrqFCtRb|VPd!Z6hm@OM5?PL}4=Y;*w{M*Zg& zJBw1I$h!apeP-PxZ@Vx8P@~HJ5_@#;p;A1Gg;6f&@?c*)?rugeGle?TMQg4{9pxZ= zW|h9t1E&eAQY4W^gU5hPL5c^R2_8@Z8l;JffBMr(R0@LZEf-n7?;*3uz{7rnU>O74lKn>+X{ zQz*`hB>oN;#Y4EMGFmXZ(rhFE!(-BX9RSay=EX5FO~y8M?I1a_WP6n?73cJ2ag9kp ze;7GlhepUzyFeXUtV%B-(q;|_1_uN1)GZ7ajF_)>s-9`d>W!p$c7foZ9}Z>rS4_Y4 zS^B&9?nUgt3*Ye1Oz)OPfd^3l7PWs+-xdt$4i3)L94{{5as9UVm)e6WLZ{@&pEo-vhmrJs69rM+ETFwjqLOfLQ803Dk7eYY`C>(vlnm|X`;*0R52=CyLf0X?B zJz8CY72E(jK*YcIMd5J{$IGjVcMMc|#=GEyTfg*@Gy}##xaSH|27;c>5J}v zP$D8qPVIY(o{7gLFyM?{p7z`MNa#dI3V+Ri_dmDH&S|3=&?x~PQUKYjaQiQe#e*WdysJBkiR`NfS2^Z}OoVRJ}km8?1Jx)G&L z$6dX!nl&^({SJy*<){5`_vH|lB=}n&I!WiQq-`nJP!LB6>Y45XScBwK7!7Ew?tjx8 zU4S`I_+Ac;=CIFFcw8w3jEAAzMCZSKD6N2=gewrNg8otL&U{0Dv_MHoraaon7OEb< zHM8x*kum2T$H?%ypiR5ed{Akz{Io}UiAI4`z-(Sf&h^iuw+*3-t=}3>uKGejz`v~t zZyLirS9^myF0r9*kxpkfMq2p*e}C>kvYv<+*3i?AV+16WiqlX47#a3q4wkOuSipP} z1_a{U(OK+|nA(eaLxfiZ$eDpQcf^|?7z?Yx<-&gQa95_n!Q9k%?Qm5}6|yjHHq}2N zPw1qKB!_J9yrIBa1ei=EJ?k6X1R!gKwG0!bH;4=dF41dfaxe8-z{tobFn{!I!S!=O z^TPO$wQPu{GUE9kx>py+s}t}WjJ~3J&Pgb>d>WPalokLWe+gUS;}uM(w&iD36f_KO zpodY%@Yd+11Crj0Gg5$HbJqYeNPf*DL6xqIc4FTpc$Z7lJ(;RW4XkLyCK)Z}Nu^aN zehqjv|E}CV4O%nU={Kkp^M8s|nj!sPJ+=5Wy-I+gY`{)tuq0+-z z9stSu?FzmxEC%)T^t3Y*f@K(Sx0_&xk^{z(S)VUWq8>>$-5#+=p2b-JD9-$pQ7T(OXS^~Y9ihs@c;237qc!wabE92*Q#oImg$$txFO^j0EgUwW; z9jMUDOTS!5uqKy<-Kg2Gnw{z{qOmvbRP_#-+C{4Js~2C6{)plVm_<_^YEz~#cK1SO z^QP)-7B>7A_|`a#4aVi!Q{XUET9JKWy^gxL07m}K4Xn|V4ot{Ovw~nYCGcfu$|Zdw zx=#Qk4?uqkq_)zeX@3{srVd;GPCu+I!t3!K&6#~e#|AG5dJE9s`%`|Om3*BHviNoh z!+uaG@{Csl^C#I@Ix4?`5r-iZb%kpy@Cv9G^5>GnLIqw@+5dI)Oq&LSP+`G+U9k&r z{d86;AT`+E`8Nt?q~_B{Cyr7drH@}kJx4<);%na(Vv0g7D1Sk4paQR5Q&@ZRC;F}m zOAR!o3YskoG4#l>00rX9+oHNz64?%Q0hz|3KL-!~iglr`Gs4c@1ox=Vl6kAg0eT`& zeN*0KszKjKvWWK7B$!4?#&8GFI0#cLgQl;F!liU2E&@-M zq7$nQ{*g)!XbAqpk&Sg$kSi15wf)x%5L8agra=f*^f$-%o#rNCRId&Z^~U2;Qb$-uW1$Wq%D;)ihMUl!hGJI5R)? zE((v%lD=cxI$u`{&lQ8_pSqpx6087TOk(fKtVU(BvL02K{~4^Ex7{+l!!dgM=>Vnp z4}UCPGK4dpg*X!ZX==ZO!zG?tF>%0(hQZn~eLo85RIy4sq#!A3DsyY`iQL>#>DT&O zFe7?dx!A!>v2U)j9YoQe&@+Eu=~mJ3>GsWXo93uMF`L(HLY%2P%hr|{>|`G$_*Sn1 zDgt%igjb$c5l=G}xwG7$?GOZz!EiJ(-hX*R#SlTjL4qMIgvF`Ea@CC}mA;gBJxU~4 znmaa6Kuz!rNiT)0_WFH(hlyMemdf}6LI?tM4?1XxI_mGR>n>XxMnS<($cSK~)fI7z zC!r7&D1sW3(ZeI*sIikZBxeYt4Jb;%8Kex6E9)t~RYbc%yM#{3OlCx1D5c|As(%|t zmZfvvaBAo+Yf*Ik_s6X zFgGef6JS87lorn=-kzK%(4ENSDZ$$oH1u8PNCd|Zw}W2(9_&h(l8u0=R*)>&@czWw zH>uKH;`#3Ol0>naU#yS5Z>^P)GxVXqv(yZE&Lu4~4OwEHcLT=SBow>H41c~rei3=) zEJ5_bh$p<#=M@4XDem{uYJ{#0iMK)g@8DFIuHla%q9JmNpvZz^w*Y<&rS+ZS`t~?9 z421w6g&yhZKmh8F7R#Y{QPP)%i#Oy;A{lrLe2*gW(Pveshc9Cht!)Svrv2m3xJ8sm z(fN~gtCUIgVCklt^?Uw%1AqU*4ym6$<+ul!lXgS-W(!BX@z*0I3@rW@CplN>r(#Fb z{ahlTWkMt}Lo^WqhmHp7`FJ3x-&zjU3WJongEx?==+CDdU^&-p1AlTzw7H2lIu=L1 zhgH~Sj%;=|;v#erH48n{D=am8*`chTmU$X)Z8CN(HV`XZ{pq49zkfUdqbGC$f{=jJ z?+5iU{*I8GgU`PQuM+;E2LTWW!DjZtT*l!D$I}hzS+wRrQ31(o<9~06s9EZ-uI22W z8xfZV>^*FR?JnN3<0S~~HHwPVwB1S)$uF9^m^ACZG;THYr`+wK2qP4C+013WTN>_W zL(0VI+77q#)D}U<%|C0j$fWmeGHcpd3YE~MNMftX-GI^ogd9fbCY#O4_-%4`T=sKQUC%XjV+W;(^7@#?ns+A@$O)k zotU;AQ(wf8l;)c^$@Kt0QBZiw4+7{RsP`)Hy&!*u9pA-nGX#;#0nP+l zcbnP<6tI-kFMs;U&I5oCw0ICUYA#BN0A&%7RXahJnJ$kmMk{m-mhZcpCu<|gUxA3rtJge_TmWbVW=p2xYx7BGCQ@^3 zpO!ya1b_T-x1cR^Du{u6Awr*7Y~04%NyhzeTTVk%zd;_2XMVx`ut2qp@R&`5O3e@B zr#wTdAm^a>c96lKL5qv(t5rQp=blX;?m_>*N$9hg7R1P(G~|uHDIBkop8`qLg|~k` z^Cufle7+aazUEhg1mte|#m0p20T$yQ@F?3aiGPlF_U}x3R)GBlD!_i!Rhi166XQ#@ z51d=xDv@WM8_nhEh)>XFyMX&wBr`91hYoI0V*5vAjzN#A;;jWcmjXG^)}v1jP|vCb zp|xP`UAd>7@b!=<6YrWu&b?-^sn+?YApyTSk3fzo{`qgB<*fpg1!@(U8y$;}ikcJY z27f{-O>O&E7jAq+u@o6$V~3G?WCWf8nF=6NWa-_ySk%-3N{v9RQIQH`H= z&tat*V=n-i@LP{`sC-X~^vOZHDlMSAYL@wOVLGvrzyoq0AmNE|eqSQGazy zKnFweA28-|5`uhXXNt8VlL$RRj6%z)Mg(Ej2>OA?Eyh(;m5{$5#j38*)3A=O>M6Tq&yutHv%l_zo_|0cmQEEA z8XjDqua!%RS2duCTF73>B-dymXyB)(e)!&`_@b{X@7%Sq^#@7(hpQakYnQy?XEmP% z&(b65-k$_peb2bFyQ{QAY*VgDBv$Zp?uk689yZ=_R-j7uc=c)ClEnC@N8sex16R*L zD~$aH+V#(WCIM{PpBu!w^MA+fp46vUcUc^L^7FGM?f%f;vW+Mu`rM(RE07n<9vBW zlz*7SQUPM9hCy-RtS!LRX!YriNh(kTRdc%E&NLNA7QKV$}rqNuw zB&@I;lG}_0u*&?j_?%HR3Cf(h7I}KK7tBkGH@Qrt?YDY6tRI6s!Ss<{M6w4q7IpR{ z8{YK^yz}Y0H=vL7`JViIBloQYm?Cig(FLFzw0dsn2I7iSd^ynWn4K2?Xg)7V=~!4C}jf zQ4`@VqJKo$zf69@cvr}<;M#*v*a8aBs3wPda#okQvZy~_3pLX#j^qtt)|2rbl`At%3O-S%a1m}*=L+d>g z^e^9re?bxR?6?8_3;(?bt$a=u$3oL*4$tkcN`F0|+%AH~I)390oZY#w3|eB*5*ybp zO{)*$O#cCl*uoM+UIKl!QDn~XFF{TBtd*4H@l%@}#r`O|bt3tPh-tUNA6&W*=NhYx zrNuR@w1WqX-EkMOo=6Fh7bm40#L*o>5e2W5E2(QGx(RvqcBl=NDCm9aQ7j5=O*=sQ zV1LkRc?tu~)PC|i#zqk&UI25wfldJ>i;9rj9OG^!v2&l5rhLL~eyuw>acGMreR{v! zn@eS!!X(-Nrqt|)`H3a^Db$(&xrGS*n-Jdk~n^48|HzUMDd@JIEnXV+JLNNP_ zMcwaAT3`CyAsyc9GObh4Z-4Z_tkGjkU4P5-16RZXijpXJKCLk{l6+BLo z*98LEb-{^J9CWz2&0_%f@-D5dLVKTZmV^C@T3(#>wzV06Yd*{YrV85x{uMT@=?kCB(V+|l}kH$XOMCFNZ zH_snBZGymdS&cf>b*rC45TMscn}4CB*%TX;&_GdULL8|s7`{O8$BH3x>jf%>a6o*f zrIIJU-&9_&X$v?nmp_5_xQG0srRG%A5Z$IyhD2op0}bA5=v3&Rm4VqElV|nA>K_h$ z(lWS_no;Z}fDd*RhJ2*NprDq5!Gc=+a+BE*HA$*yYR-Pey=0a(BJs+;+#?qPKyb6pBHwK$8fxi^gF)9+ zw`aSN-7U!6>EFrUg)j%nyK!*L;a|O8o%eHsU_h*`P#`>0%(TNr-ycSizBbjsVc2KC zpQ7~L?rKZ0b!tss3m7=<@_$piNm@`Bisr=OHX@mcJ#!S^^}? zOQGj`R`GuBt8O(CZtCwgzCjb63&OzuJV0DYzN)r%gN1CI7u>L-y! zT_|=_7kUZ$y^@^!NC0Jrg(oSJ<_MAHnfM1JJB>GtHW;%4;(xE94V|(|`%eJxDZ|H8 z1(9io1Je*60)((Y`D5Fo+srqz<%Kictb^gLLS#Qx%vp0}QwjW-vg$2MxyiY=($)yy z&Y#Pxs@SxxkhLdlRix3;Z;Ag?LIxTSj#-ND>yKRxKf9=qX5Ra5y#xnW%+Hm!)qir`43Kh(2~L1z_%T(n*RYM4V-~g zs_6Bx?Iu|ovs8M0ezm9-)|$i^QCPSn%9;g;cS-SwC%*bflB$HUD1^`>frJ!&KrhEh zjfo{;IX5$z^_mh9QV1Kc4pE3`#Q~`DP7Qj@h{2|J(|^pW?^UAV#d59;CHLL8+ppi# zj<%HxpKE+!uLF(z)6svSb2HRg(CK1J=O-A~GBwTcSMfp@z-_*yw`g(O7~Q0F-GF5SbQ_8oPHgJXB5f7A5JG-P&vE5UiF8 zDNCt+SbrSM_Y90qIef|o(tA(UhJIqvVT0>cn``ehoyB>T?DD-#%Pot#Xj^Be5TjDv zlRTs&j{DJR1DCl8xdymF767r)|E3}xB3@qIvthViF}=E z;B8p3@WAgnJk8}UwkvYzyh;QyuDM5nOxs5~h}_i>k$MLYdqXWE~~;>R|A`$I+g_l-K-F>Tv4UFA#qjh%wG7mw5Y-1 zAO2<{Lab2!{aukO+pE2z4(&>^^5|L(A%8M<55`PQFfudX9iFVItk)l*@&Zc%QM|98 z=rU`AQOCui_l>P=Idg<*HW?3G%?s!{?hIE1^zfc8bF}B~bPnKU!9CyQyk@!YTem)rf+{PODMFC)$Z8jD%chp;7c&> z5ByT88Y%iEMv{dAdHBGqV2&M5)^*Ms5WReqehvd_5KH0^6e^Niv`-SD?b4NGICKy+ z@y$FCrQ!HIXWtgxE*;XgUKG~5Ab&Kb*SYv5=|vI{*Yb4zJL<{F3Ak5q>?BqFiIgWX z@8V4OVfodTzhTme9~%<8<6L^7UZwwlSHf$(H%?iee&zH~z;avvqHlA;19yB-Zp$k9 zSeOiql+Ddv>-&Z0muaj*K3whge2|3wu!`R01N+hU^2on-9TnJncaQnVj(<;pDv#fX zntxSjv6_z*iut(&D$kCsMjml8?LfU-`ET_vhg30?n;pa4_D?a2&olBBOt7+wB6(fH z=JWz^OOoPK28G96AtkgJl%c|}^L`Yybs+6Y@zWP!lBc^<`=~HU_^z&9*Zlnfm zCizpq2rss;)Sx~0HEppdrGHQx(vYgj4rHWW>e>gY6~Qixar_}wviod46o1*bS19|^ z>Bn-*?EG}i-jE3c$aYy(l&MG=x)(Ma#YN#O409XUappL+9=)dr`m<5q!umWyQ#?~i zM6D@9s=W(RFUehcc?Y;5qPYdHxbv{>ghgrR1^3Y|d#OJI50OeH;(r(+UC8*UWSuVQ zr5U{*lDo4vQ+9#okFsQAG5#o{M5kzSjv3Par zTDXcl#D(*`>{5I}gnyCH&6{eo)ihsYVXL8sPc{OO!uJyuz$5GO0UeXO*Cx z=Vt=Su9|)ia8FH6srz>N9Kpr1=%f0Zs0EA$s0*vsC+7OVu)3*X`$VzsE{{thv`m+C zRyTu)BG-oEdiJOY(f%&p91v02x7`Y)ys4`@e~8p2bIQf?e}8+eT>tKO1I7nYU7o_t zQDH4Qsv0lAj)#J;t4VBQ0^NO6|LLS&rVJw3v!yupgqethWG**h6ov;2XXikOsi+dJ zIZ9h!Lb@4*^44#AsXuk`zVr`(v^k#X zxiV-PMab@HiGNKxSWoi+mEWC78ILR4HgwK1eduN-vbg=K{Ll1L6ADsvH!gkIQK~J$ z)Q!6^G7hI+7``p!bMfOZMBzEB9T|(*^>M|gap!{n2JEkhxdeF=@tKkG?dhl6_W*Ho z{SnF8XX|R0R)1P-%GCG2iBYX|x1B-c_>}ia^=%xqL4V`26L(|(<}YQ}%g3ykPF)nD z!`nD3Go2dWAk;T@>xZW))-!%DMU~D+@dwK@jApdnzIgP6N!O2AE8V(GADyl-9d6;S ze)V6+)BGi#BqzqY-8+Y?x9OT2);wjo@_oZaJW5wAI{unIRNys z%^VFXZ7IfF^i z?qc?gT}n8kGB+lq%usrqp5zG4y{G3aDOfIVB!4Jvr0Z%gDE;^rIU7m-FRhxpht{Mz zkaua-H_7mh4gH>GviiWD3QY>akTM26@YqUEa^W#7vu{4XnO@Q_zp$GHN}UUCb?BbKunhNn7E!Pk@s||7 zWAio)IPQC<2=GJY0Dj$YHm>-QRY(rg7k?^5h(`)b{J4rLM5VxOm|O@c6p0yyw$a}O zGZ77NfCQDCY8}ch{VsbRTLFoGLx_o&qjWtzfGbQHBn3Vb&X9URslW7bibF+U+vOtQ z(tn%U4ruI9ww`gviTxyj*a?(LQwQRbq^#2UWPkM+ zHnB=qkDhP&c{x9D_mWcDks$o1&`q3p%)NeuS^f4Zf{9zUkKQe>t?h@7J}z;v)~S(287~NL^}bjKqpqurPEh@UT(k7)_aBY2o@+eU zci<=(oz)cmYUR#6*v5Dqr3>n&DV&K4H3D=szw9wT9`!S-RhSh1;o+|MEq@N+M>_er zslGl`O~&d(;a3^-0#kfKMm*vH19ecZUEF!}@vQgGZyxY5xo~xB8vb78c3Jit-HR9j z2;rwIzP9s503SsJk@u8efgV?V^-~JVx^luo^wla;TM#=WQ~gmrPAgOtE})b-hb=9AqTVXP8*@E z_=Fx*e4vm5SokVs)geU``$K5#8|m=L+y>Wj*YMH}1pyT-x|xm9KZ5D_@6Fbjp=G_5 zShQ%Ei@<-J#Hk10Ny-^XQ{5`243|2Atbc%KhMEN&A%=w5D65F{vEeFP>sWi2EfLbH@XyNgJx=e;-ZBLdH`mK?WT=Nye?v5CMekuK; zz;I{T?Lx@8M~@rhGL&BKy*FO+W8ypz{a_?6jP9X4uDo8e46cntP9yq$BE1|LB+pKVXD9NCE^zXCxwZ~yUFUb2Df96`~V&WG;j$t@wn)h_t=DCmCC0wuhDp1JtCns#m9 zL-JGR=SNWVoGtJ6;dpAsz5(X>$KxW*A~}QPbKfXXK7S5f?TjN}j%b6-kpir7PH+N&mXMch{v0_8-^|p@&oIWKV+`sy~y^o2| zP(CF1xPKe0a`8YY^5(o))-*5qMweAIC2_8`f=nXhI$xCw8dmVTBOqePH_%M|2k0X_ z$vV{4Z-+;r&MW|QQ0|hrV(Nq^vY^1lylb|?-3)n2EY@TB-tBZ$-dIrX;@Vq15}+)g z^Z|gcMM1GOvR_5Tsz5e`B$49sJC-X;k`B)8dGMH!BtMas{Y#T z9{=@p2Gjl09UN5rsEms5kLHh>p(B2KS^B;TfB1Xk z+U}&CNTII1XCE3{f1Q3+e1A)+crxRwIsEYG+{>a?Jy-H6yDvXj--h6K z|Hj<%*nB(RTMRun^Sc8F8{D+XS-Z(&qC}Hy=goj^Y_Z-Xq%TLpCSL@uqIfn5lm1a& zLHGvR;H%78ZBA`$cb#6K*`V-*3Z0rL%>Nr=|L_;wN>TRE_mTKK8YvUzpVisla({=H zeiHZVmw3;My@#eV{{gSL$qd*~jFN*IQ(24_Ev-JVJxFSUlBYTl^0aV$no`hPS$X-f z+0#QW%61xeTL%_IAOKX2#NzOskIEdOz8B1eHLvl#g^nKOm|FNwz2UPwMirYMeonh0 zBY#!c>XgHCwI^(sJ*Jlywqq;j41Yy?J=c?j69=r8Y+Y?3xsz;qrXuJv@G?CooXWK8 z6<6)_(%>nir7MX?Ka}}QwIu+e1X1(@`8!E(+kM7Z$gl8ks{vS4klNVK5_A0BQ0k`s zZMVO^pd~5evKOR_X{0v{Kmm~bDDU(mMxtag0(Ys=%KI2ig03l6d01_Tu7CduX7zGb z`%9w~M&^{DYP#h+MLuDVA^C{IeD@j`4W5*cPm7u0x2x7;zSnYWUg{FNP}bV7)5_)- zYc(NYUEm`-13epq^*A!hKc`oSdq3@%9C- z=+OQ{xY8SlyDHGK=ZYMsE(N235Ct%+rrPrv%U|mSb4|U`_q6#51=l5&negLb3mLlY zw#iD$EsTO=mYVoZt3WaHn{5Yo8M3yPf@x$T@-*THBF|jv2pUE))qh01=C^)?sB%q6 zy^>m79*~mrQ*OrdrK5pRGqJxVNtCX3gNE9Bwfba{BE_GsK6l;DX|K5Pec&xK*zJoc zPxR3FmZ@FVO|#fCtL0OFQMyCO=oUA&;v-}H#e^^G*H(;?^_Si)#a^qGaUSJ9SA(s( z-hpR5ctN-$vx=DWrhhhtOW^`j2}ThLPN|Sry!ScMiPFD}`Z72`vIL8>I$FpQb?CY! zvF%%d7Y+`&A80QT4{auAP2cJaUAi-ng%Y^*dnF_1%HZ!;!uktlk}yd4bgO4Jp;r6& z)%B$rHKpI>M977hEI(R1AL^CC_1BJ6&ibr}qk{&XBZNvqynpev3+=RWTXF0GRW(4J zyDu>5wewsFjJ0>SxKSyVB#w5IusQOK9AV_uy7V8^$wTm0!v_ z^`6`f5t^1!;D7FYxHJDdL**j#-mB>O=ES|^lSELi;Z1dPCz4KLEyZH#Q+st;96!z> zl~tMw2f#W|BfoU|q0WTsi_R&57o z)ccg-JAbI$WNx+tN$8A}YkEjVxKT)|^4JW-GF0QxxkHaGdwG2YMwbO&hlnonNkCrU z+x4FMn*ox!nL%-T$uA=kzi@tRPU^r}F(kBK-{9!z-Tv&n50YhkBIRDz@0dX5y733`htw@qg2gpgFj*GL_vXJ_t zO@AxWr+@Hpof~;k5z4?(54lb$@9^$al^FVuuRPHsBIspJYbTl?kF}EOW(Yt39(YvJ zX!Z5Gb>^2ux`@5{JahI?;Vo30cr7RJMMR0O@bguXa{exGSzrX3j(2KKQV?m*Aqj`g z1vL(`%Y+D;CXgZi44kECJf;S$Z%k$%@2LBkiZx{S z#aoI+rE--d^5Vb0lk{GT@&i@%#d}(^>da`Jt8K@=)utzJUtI1tcjg`gGTv4|S?1m% zl+X@-|B8*{J@I{dp{f&#ieh5!k`C`025{TX;w9fjzloYXge1Qm!={YcLGG6S1D?in$!P*BEi%*@N#P~J%S7`*-fdAL zAqucPEo{79$!zqhL^jye!I~-oJx;r3m{bZ}NcRGA72n{LLDD=Yzys%35&_K$ma8oC z`x_fUpZ$3S`@Mye-!Xd_#8hX|0)MfMHV8ejPJQxkvoZFtrlfzJU@0bgDs+dDR&8<2 zA=c*&$OXkk-}13nFZGNg5^c;bN+JSU?xrrFKXZ~(al91R<(0pP;nr2tIIzuV-?Z+`+Cs+0?yZS-9aliM3g)J0du=`c=qFF_Vh== zS5aHp7M4eq)A}MaDemmm7g(4kG{^huqtAu|xRpWWqDu-iyCm1!{r~YHlRo9i@q`VWgG+>7 zS`1d_n*Qdi`YX1S;eUi({GJGU6#AVQd~JHrxNqFGDEkn~^Ja+$3iji9_}dx4fyB)} z0!_E{*6z;Z_j}h5;~+pW^=&{szanOIWn%^CNa^K;^IrfJXNlx=lLgz z6v|!1!OOAl9}teF(CxuOi;BB;1%t@t#xPve79J?}T;~!`5Py{u{2>jbTrQ7phH}yA zKSPqe#LR@zQt}!S{Z;d_xR5Q+X>%Mu|k)(6=r5nh?-PqRJ~g zxcO~go&KJ#-hcJg35}QQM}`(%%dsVrZzP3XzdJ1Kyh)~E%&#A)=?0EKzutWOLsKH0 zi-N!K6hD`DEnhUH@ij6%B-ApOLen!$@*n^=nijKM5Gm61#Dk9xyJ6pIGhOZdQOGO! zwah7+4vX<2p{k7j5U4jk16e+OEC>PI+CM+3(*ZqN{eJ;*kf~&)zHh&l)N{qBUupbk zytw(j384}=)FS7!-)}Za@qx9V=dS|L1*jDI>de-%E$cZPd1+UmHSQ^We%|KZ;#s{M zSt2HVdNJKx0U@U=cgVZm*7(q+ql?GVKb`a|;Cw0f8jki-zVq6LOn&wc$eGy5>xJ%I zJ9OiqCVwH4_5IoAqjl)9#qctdg?MGt_IOgcUlQ7D*H-=@97uIK{bfZHO7<01zIV8m zK!aHqER#%|xA}DSo=xlRs9!{%U_m*{CY@=a*zUW1V~^ylq9E$0{sEUqMmyWm;z^8F z!fkR`nlA~*7*BrONw(?`IqUjUXZMFnW(Cj&$$z&Uc!(A5db?rQB-Yync@u?xRR=O4SiIsK^KRaz!#=T+=si)pq5Z1hWu*?V3D z=x?iUFuJV$BvHeeTv76sEXuT1=`riZ3dp^k*|U@&&&Wdt}{|kD)7ufnh*a zB7eMO;(vXFU`Tpx^oC+H1G~hwK1JJ}NL^s#d0c5UWGOUfwwgr}6|-I}%zg42OL=QY zHw}QXq8;!M_Bx2(n=cdWlKw%6*c6}u3uJfyfq%PlM zq!lYHp00>{`Oy2B`1zDH5KQhm1+5mml1^804~K|MM?iHA%P=G5%jR~A3@9p2(-IDG zXecb5oF@3>-#id<`^-VjD1FrVMhCGjMLD?+Y>~jEp*#y-yZEizW!%LR3~jliiGTc1 zp-3J%$B`D^BcZ#$*8shwq78-eg%%q5Uu+R=#%|3Ci_x{AMMe?>XC-&@#3Yt1Eg=@- z@83ejp#Q_OGt%%7tVF=`vOk+ojj^gLyAhofZD$=WA|4t_Yiqoaz48s)_-5eU^@rc< zaCMHo9Fg$GthOX@E&F zvT1%wXiG?18hM_RzIx#Efnq|-t=8)@?{*{}p!cnG)KmHcA3piLX$-actumo6y!YDg zpx^s8E`+ioOLrA|zf>XiUJZWP*%dT`I})7RQn@i3X6WD^Gy8=z6P96g@qcBurueC1 zUiWjIMa7oS$eWJa*3nJ{F9rlsX8vxQ$Yk?I93-PYO=Ljl4vsHA+xdo-oITgO5`Sne z8=C(bXnHX!fdJOMe!YCianF7UmZSvs-2gI3f&#GmO+6ovo`jFTMxF&14ntZ`#U5-s zutHSPyW5E%8?1J<(a}NmAAc66Vlq(r-SMq}U<&AzS{3SDAR_p&a6MZFE0*Hq;9_d? zVrvSCVfNh(4hyIcMh5Q{<1Gy^`a?EQSuRJ*s3_Fikrp4-v_n+e(j{~LAR}~4x$D_2 znRY~Q%mq)_%c10(?U&;}Xt!f#G@YaM2*!4c?}cG>gG2_V78|ph#D9S|35_U1XH!YcG%eYoewm@spap0Mh-c5^-_Zy zOLMkU1kjWyo6db7Oj^gGXOhb*a!MWe_zU1Tq$2Zg!H-<1v*f7l#71eRCU#l7eI`eI zGGOk3vx$^?Eig!*tbcYwE^nK^!x8yM2?F5``v+QAdHTgmMIZlrGY^6u9r+AlE) zl`gcxwdrE#%X%{u0nyC}i))Y2sqhpj+r~-80{1#t=$LuyO@C2rp5!nIKc+)h_;o_} z01*W3(fJ;&K?3Ap?-w&W6K| z-0hwg0dA;5)QEphx#(vWo=j+M$=MK8U1n&g{FX<5KVH^7XJS$Orw#AE_t(m3mgi?1 z38`Nfy1ZgUpMUY6dk>_}UNvAy@US0aBBapu96eAAFS|mxUOM9?l%pLelgf8)?JDvW z2!~W#y$t1G>2LxE@=E=eu?gaVUGyXA$>pz37Sq>GjEGF_IbMHn>)|&bBL&}*J4nn5 zG$2h6UM%_t+-xg)(pO(0R72E$)8p_FEGB-bUcHt9sDB;Hvnv|A{g=JywY57^xd4Z0 zN$ebI*qvlpRG?9}8g=9=*QhWxZ>3Cw0WZS%Tj`1?YBCJGq83+y4!e+Z~z)?d+ zYDcPyOSDq_aAF9SArbAVuR8_&2vAHc$2{anCOJ2zF#Z8d`EKEm!_q|-$b*C>AXjie zwSVW65JSh0pi6PFxWRc+Ba_0_$w5b`Ma9&{AIU6VByyDBH(DP@sZ9KelNNr1wH2*b z>RDC?u!5BINrr+nYbnZXCLR2bP(-@#6U7!Lfc0q?j|jY40tu=59tvcQ|NeUhE2pa7 z(I14}4NAPgD!;5UHqs_TBbVM-e6Ly@H-FlkoD7sjnKvAFv^z`a4=eizjGSwivBS8C zMuNS22DVDim|6UkB2B+T8!bt%g0`sD!e7A+f?Ql)qAaE8GS@-Ye5NXY%9{WB1@ONZNeP6hmNcTuC(*;@1HdsGln=j;dVAg6|`1wjS z09?F{)4pT>1GP#jAY)ie zN4I}I@V#bd**q+LckSzua!abQF=nCCVWIA)%QeX~5 zC-2Wa+wUX+rISid=l4BfG!{$U{dQwzACz`+xUt>O!>RQBeH-UZe~yB{XQ$3C6k_xr&nS7eoZ+LVmQU2)VX2V4+{ z^b65Zmzh$n#8C{abQt0<2Y<5}FvRj#Wr`RE=gmyQh(6XgW2iE)<3BswZTY$(uNiCipz1*NfOy1MNQJ42{anQWP0$zCOQlpVot97tblBQRC>AXRnxh85a+eT&_1 zPv3vTa>}?fW2`vOhqyZvL5Hqe{4^0F$|BeIboRmAoYqoHw$DbzA65zByFk+Czwvc?+m6`08E13jNp-;HTQvK z+jPyB5i=^rvrulVgn)qlPo0Y(vs@SQ%88EIyUC&pn9x;Uc?jrQ*_`Fv#{Nl;q1?~= zQe(|3qb#W|o;vK71S_Sv+TUJhlpU>Z7cawa~hUK zQGnXa+aaf8t=#9J#>I-pmy~{!VCz*0i>{G}=YgXsDknOdEPvi7_bsU@6Ikn~{Kt3u zKh~UirTa^{q9FCa<_vof*`_xjVNv0N3ahV3we1yI(tHBF@i3L!@up;6#8?|7`x-rd~x^ATM=2NE&TesuhA#mT3WX)+*TitnVw$z z5|KzKdLrRvvC)=?B*JENA8wU~(y`7xa)_GygJR!9Pk%mZ%shptO3lz@&L)Id9kncj zTpdn{5%M+iS_p?jB&5+Kfv@BK1@0*aW$roElt%k*7KxBs+95m166!R^i8Eh)J#`Rf zqS`+;U9YO4Uz5Og34d3jgy?{NS2tGRK*-(}f7;|M8n0w|Sglt3sc{O%s2HhF}C?DOE#(F78vGBurV( zYe*3gfE2K9slRusl|>LJ4n?_|(oKu0x(J+o{C(9Wx1LnAe!!gE81R%T*~5De@iWb# z=2yJ;?8$AYx3w6 zK1-6GsSA~%r+i`?qeR7o=n*Qfwap;i*Rxz}MAaARJh95KcJ>>oSC0$NjI&95B2PYR z)o_0`bykTt{np`5{`M!@>RFR!&}wHc1~teNCm+;t$Ccfw@fRO?g|>gzzxVh;@Ml62D~$x1GbQf%k*x1-OZU{o zXdmS8URnn?80*|HdyV|0axiXdA8hBp%VWuQ?XX0{G=Jx$z`80J5^*0xTv8Nom6tu|D6Y8Ve7I`=WgS(ba!b zd(zbGK~F@IowcEzDYMfLdl+^0#6h)%eTo&D@UGx^Exo~>6NZv3nY53Wn~jgH5J{9h zBF4F^Ts|2~|JK$ca7D%&@6sn3Wd3mA8)BBv))f*{i;{Ve;r9k0l&e?(*N~m}9m_Fx z<3C$J+hL(XBxj`uy%O?v@elNF18IM7S247Pk0OkhYWjicPP&49gYLdEH}c>~GaFl< zR~@30FG>06Y#00!P}Y$#mh4O>xe0r-(Cr3L6g!;PBEoTRRU^^e{WDkHEs~T#*>fL@ zfLO&X5p$#G>)oQyRQ@A)U*<;zF_>Tz(X_k`er$0H=A+s}xQ50_L(6~6RJ4{6 zU+jR2qVn7JE*DjrMZM)H&2-d=v*^>O5gFW*zBT&d)OmY_MBt;~jt|s5e4cD6z+vcG zFDchqgeeHC0m@M0A1cCzDm1{5^q};B5hnn3jSgIz-7YBcaG#k(WMu<~WE4D%+P{OH zE@n$ISA(~;qhfg9jaL^JArgOxp`!`~_sy@il$s+n+-}0%Soel0@vz5{FG}^>$7Yqp zO7=h5bPHP66|+!%KK*`-RudAj&r?3-la)Bm0kLUK%d4H)4v{GoH7B6TlHMDkw5;9IsktkJr6OSm_{m_ zK#h{Vggo*Hut82)j9E49=@7SWIHS@iE4UT}g$!qS#aw)sg~U5;wpGO`M+F&3eNl5{ zjb|zpsXH8My?w6(Y&Ej~bKrW;d0HYtNbpkYpqbYs*G!v0k1XH5b5#^4cj?i^*(?FH zILvuScKPNvP*WBwfeL?q@FT7^1tno9MgKpF%srmz$NS^&U2P2S%`lhr-psAgTqD#r z!!Y+QE?q`w3b~Y&F53)qZ9{S`w@UYsimr2sxfSt6y15mVBHi!5&+qm3`Q!X?9tssquulSqXij}@zxsq8YwSciwxUPsset%G`ac)&yC1f zzaFEoK##4Db!ILfp{H{1VV+D^v#D3@0&jm;2AdGhpS2C^cxBC2CVUPCmf4{tSC8 zJIsj3biy$&Q~`#HsaesvBWUEbCaK0hRW*0{lYn^n3ccm$5oZFt9nlnC^Q;@_kW;fw zAMg9RRXKkrWO5_8pz#E@w#!RItVU$3LPmx)?(WRa`awba-Y{oscKg@BghxdkoxU;> zi&ZJAf$7IeCtbVdH1W!ypmzvy1%aUIgsat-*1F3xGTGD)Uj&^HSibX)YG__*>)_uQ ztUQ;b?4~sWDlz$?sgl9jg>@?x!tF{A`JO33A~}B#qK^VBFgV-znan+C*P*S^LLRMd zU5cpuo6OuojHJuLiXwLRV=%H1Sy_-S6FYN-%r*L<{|~Sm4<-_Hw00Hv&-E@kSzaF= zyZ<2p%Qk!1`tqE~=B3K?E%FR<$dA@>iTOAA%ma-%4}hh8zxYu0T%Hz{)?h%Yf=ZD+#wm~=cj8!!FnTz_0#{O?7!EGv)U|m-h1=MAzFn|dJpV@QSWwU zPJ7rf_1aT|Z6OslT)B(Ny{@J~qw5zjcL9pe ~%N`^ZJW#&H|R=s50E81?f{-bBH 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%0D{BxmKwG=BV)UvKoc7uRR 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%0AL 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

}$Ej$&^%9{5_hU;1 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 yeX)LL*6atv{b*(X@I(%r7EjZZiL diff --git a/src/cli_plugin/install/cleanup.js b/src/cli_plugin/install/cleanup.js index f31e028226c27..38354bac4a3df 100644 --- a/src/cli_plugin/install/cleanup.js +++ b/src/cli_plugin/install/cleanup.js @@ -45,6 +45,5 @@ export function cleanArtifacts(settings) { // At this point we're bailing, so swallow any errors on delete. try { del.sync(settings.workingPath); - del.sync(settings.plugins[0].path); } catch (e) {} // eslint-disable-line no-empty } diff --git a/src/cli_plugin/install/cleanup.test.js b/src/cli_plugin/install/cleanup.test.js index 46089f61d5e83..1a4cabbc82b5d 100644 --- a/src/cli_plugin/install/cleanup.test.js +++ b/src/cli_plugin/install/cleanup.test.js @@ -22,7 +22,7 @@ import fs from 'fs'; import del from 'del'; import { cleanPrevious, cleanArtifacts } from './cleanup'; -import Logger from '../lib/logger'; +import { Logger } from '../lib/logger'; describe('kibana cli', function () { describe('plugin installer', function () { diff --git a/src/cli_plugin/install/download.js b/src/cli_plugin/install/download.js index 10d20367c1b7b..b7f5fbec46edc 100644 --- a/src/cli_plugin/install/download.js +++ b/src/cli_plugin/install/download.js @@ -17,11 +17,12 @@ * under the License. */ -import downloadHttpFile from './downloaders/http'; -import downloadLocalFile from './downloaders/file'; -import { UnsupportedProtocolError } from '../lib/errors'; import { parse } from 'url'; +import { UnsupportedProtocolError } from '../lib/errors'; +import { downloadHttpFile } from './downloaders/http'; +import { downloadLocalFile } from './downloaders/file'; + function _isWindows() { return /^win/.test(process.platform); } diff --git a/src/cli_plugin/install/download.test.js b/src/cli_plugin/install/download.test.js index 93e5e414fed74..ae926b77f7d58 100644 --- a/src/cli_plugin/install/download.test.js +++ b/src/cli_plugin/install/download.test.js @@ -17,16 +17,18 @@ * under the License. */ +import Fs from 'fs'; +import { join } from 'path'; +import http from 'http'; + import sinon from 'sinon'; import nock from 'nock'; import glob from 'glob-all'; import del from 'del'; -import Fs from 'fs'; -import Logger from '../lib/logger'; + +import { Logger } from '../lib/logger'; import { UnsupportedProtocolError } from '../lib/errors'; import { download, _downloadSingle, _getFilePath, _checkFilePathDeprecation } from './download'; -import { join } from 'path'; -import http from 'http'; describe('kibana cli', function () { describe('plugin downloader', function () { diff --git a/src/cli_plugin/install/downloaders/file.js b/src/cli_plugin/install/downloaders/file.js index 56f83b03d5a90..c262f1010bbc8 100644 --- a/src/cli_plugin/install/downloaders/file.js +++ b/src/cli_plugin/install/downloaders/file.js @@ -17,9 +17,10 @@ * under the License. */ -import Progress from '../progress'; import { createWriteStream, createReadStream, statSync } from 'fs'; +import { Progress } from '../progress'; + function openSourceFile({ sourcePath }) { try { const fileInfo = statSync(sourcePath); @@ -58,7 +59,7 @@ async function copyFile({ readStream, writeStream, progress }) { /* // Responsible for managing local file transfers */ -export default async function copyLocalFile(logger, sourcePath, targetPath) { +export async function downloadLocalFile(logger, sourcePath, targetPath) { try { const { readStream, fileInfo } = openSourceFile({ sourcePath }); const writeStream = createWriteStream(targetPath); diff --git a/src/cli_plugin/install/downloaders/http.js b/src/cli_plugin/install/downloaders/http.js index 0fc01453f2b4c..e9eafe3737ccb 100644 --- a/src/cli_plugin/install/downloaders/http.js +++ b/src/cli_plugin/install/downloaders/http.js @@ -17,13 +17,15 @@ * under the License. */ -import Wreck from '@hapi/wreck'; -import Progress from '../progress'; import { createWriteStream } from 'fs'; + +import Wreck from '@hapi/wreck'; import HttpProxyAgent from 'http-proxy-agent'; import HttpsProxyAgent from 'https-proxy-agent'; import { getProxyForUrl } from 'proxy-from-env'; +import { Progress } from '../progress'; + function getProxyAgent(sourceUrl, logger) { const proxy = getProxyForUrl(sourceUrl); @@ -91,7 +93,7 @@ function downloadResponse({ resp, targetPath, progress }) { /* Responsible for managing http transfers */ -export default async function downloadUrl(logger, sourceUrl, targetPath, timeout) { +export async function downloadHttpFile(logger, sourceUrl, targetPath, timeout) { try { const { req, resp } = await sendRequest({ sourceUrl, timeout }, logger); diff --git a/src/cli_plugin/install/index.js b/src/cli_plugin/install/index.js index e3c465ea7a3f5..bc7e95b8489f0 100644 --- a/src/cli_plugin/install/index.js +++ b/src/cli_plugin/install/index.js @@ -17,13 +17,12 @@ * under the License. */ -import { fromRoot, pkg } from '../../core/server/utils'; -import install from './install'; -import Logger from '../lib/logger'; +import { pkg } from '../../core/server/utils'; +import { install } from './install'; +import { Logger } from '../lib/logger'; import { getConfigPath } from '../../core/server/path'; import { parse, parseMilliseconds } from './settings'; -import logWarnings from '../lib/log_warnings'; -import { warnIfUsingPluginDirOption } from '../lib/warn_if_plugin_dir_option'; +import { logWarnings } from '../lib/log_warnings'; function processCommand(command, options) { let settings; @@ -37,12 +36,11 @@ function processCommand(command, options) { const logger = new Logger(settings); - warnIfUsingPluginDirOption(settings, fromRoot('plugins'), logger); logWarnings(settings, logger); install(settings, logger); } -export default function pluginInstall(program) { +export function installCommand(program) { program .command('install ') .option('-q, --quiet', 'disable all process messaging except errors') @@ -53,15 +51,9 @@ export default function pluginInstall(program) { 'length of time before failing; 0 for never fail', parseMilliseconds ) - .option( - '-d, --plugin-dir ', - 'path to the directory where plugins are stored (DEPRECATED, known to not work for all plugins)', - fromRoot('plugins') - ) .description( 'install a plugin', `Common examples: - install x-pack install file:///Path/to/my/x-pack.zip install https://path.to/my/x-pack.zip` ) diff --git a/src/cli_plugin/install/index.test.js b/src/cli_plugin/install/index.test.js index 39352f52f20fd..657ca0904041a 100644 --- a/src/cli_plugin/install/index.test.js +++ b/src/cli_plugin/install/index.test.js @@ -18,7 +18,8 @@ */ import sinon from 'sinon'; -import index from './index'; + +import { installCommand } from './index'; describe('kibana cli', function () { describe('plugin installer', function () { @@ -41,7 +42,7 @@ describe('kibana cli', function () { it('should define the command', function () { sinon.spy(program, 'command'); - index(program); + installCommand(program); expect(program.command.calledWith('install ')).toBe(true); program.command.restore(); @@ -50,7 +51,7 @@ describe('kibana cli', function () { it('should define the description', function () { sinon.spy(program, 'description'); - index(program); + installCommand(program); expect(program.description.calledWith('install a plugin')).toBe(true); program.description.restore(); @@ -59,9 +60,9 @@ describe('kibana cli', function () { it('should define the command line options', function () { const spy = sinon.spy(program, 'option'); - const options = [/-q/, /-s/, /-c/, /-t/, /-d/]; + const options = [/-q/, /-s/, /-c/, /-t/]; - index(program); + installCommand(program); for (let i = 0; i < spy.callCount; i++) { const call = spy.getCall(i); @@ -80,7 +81,7 @@ describe('kibana cli', function () { it('should call the action function', function () { sinon.spy(program, 'action'); - index(program); + installCommand(program); expect(program.action.calledOnce).toBe(true); program.action.restore(); diff --git a/src/cli_plugin/install/install.js b/src/cli_plugin/install/install.js index 92be2ac250320..b74b589459112 100644 --- a/src/cli_plugin/install/install.js +++ b/src/cli_plugin/install/install.js @@ -19,20 +19,20 @@ import Fs from 'fs'; import { promisify } from 'util'; +import path from 'path'; + +import del from 'del'; import { download } from './download'; -import path from 'path'; import { cleanPrevious, cleanArtifacts } from './cleanup'; import { extract, getPackData } from './pack'; import { renamePlugin } from './rename'; -import del from 'del'; import { errorIfXPackInstall } from '../lib/error_if_x_pack'; import { existingInstall, assertVersion } from './kibana'; -import { prepareExternalProjectDependencies } from '@kbn/pm'; const mkdir = promisify(Fs.mkdir); -export default async function install(settings, logger) { +export async function install(settings, logger) { try { errorIfXPackInstall(settings, logger); @@ -52,12 +52,8 @@ export default async function install(settings, logger) { assertVersion(settings); - await prepareExternalProjectDependencies(settings.workingPath); - - await renamePlugin( - settings.workingPath, - path.join(settings.pluginDir, settings.plugins[0].name) - ); + const targetDir = path.join(settings.pluginDir, settings.plugins[0].id); + await renamePlugin(settings.workingPath, targetDir); logger.log('Plugin installation complete'); } catch (err) { diff --git a/src/cli_plugin/install/kibana.js b/src/cli_plugin/install/kibana.js index edbcef3e7fed0..f093c1eee3db0 100644 --- a/src/cli_plugin/install/kibana.js +++ b/src/cli_plugin/install/kibana.js @@ -18,15 +18,16 @@ */ import path from 'path'; -import { versionSatisfies, cleanVersion } from '../../legacy/utils/version'; import { statSync } from 'fs'; +import { versionSatisfies, cleanVersion } from '../../legacy/utils/version'; + export function existingInstall(settings, logger) { try { - statSync(path.join(settings.pluginDir, settings.plugins[0].name)); + statSync(path.join(settings.pluginDir, settings.plugins[0].id)); logger.error( - `Plugin ${settings.plugins[0].name} already exists, please remove before installing a new version` + `Plugin ${settings.plugins[0].id} already exists, please remove before installing a new version` ); process.exit(70); } catch (e) { @@ -37,7 +38,7 @@ export function existingInstall(settings, logger) { export function assertVersion(settings) { if (!settings.plugins[0].kibanaVersion) { throw new Error( - `Plugin package.json is missing both a version property (required) and a kibana.version property (optional).` + `Plugin kibana.json is missing both a version property (required) and a kibanaVersion property (optional).` ); } @@ -45,7 +46,7 @@ export function assertVersion(settings) { const expected = cleanVersion(settings.version); if (!versionSatisfies(actual, expected)) { throw new Error( - `Plugin ${settings.plugins[0].name} [${actual}] is incompatible with Kibana [${expected}]` + `Plugin ${settings.plugins[0].id} [${actual}] is incompatible with Kibana [${expected}]` ); } } diff --git a/src/cli_plugin/install/kibana.test.js b/src/cli_plugin/install/kibana.test.js index 8c5dd00d09953..ef3400be73069 100644 --- a/src/cli_plugin/install/kibana.test.js +++ b/src/cli_plugin/install/kibana.test.js @@ -17,12 +17,14 @@ * under the License. */ -import sinon from 'sinon'; -import Logger from '../lib/logger'; import { join } from 'path'; -import del from 'del'; import fs from 'fs'; + +import sinon from 'sinon'; +import del from 'del'; + import { existingInstall, assertVersion } from './kibana'; +import { Logger } from '../lib/logger'; jest.spyOn(fs, 'statSync'); @@ -42,7 +44,7 @@ describe('kibana cli', function () { tempArchiveFile: tempArchiveFilePath, plugin: 'test-plugin', version: '1.0.0', - plugins: [{ name: 'foo' }], + plugins: [{ id: 'foo' }], pluginDir, }; @@ -69,7 +71,10 @@ describe('kibana cli', function () { plugin: 'test-plugin', version: '5.0.0-SNAPSHOT', plugins: [ - { name: 'foo', path: join(testWorkingPath, 'foo'), kibanaVersion: '5.0.0-SNAPSHOT' }, + { + id: 'foo', + kibanaVersion: '5.0.0-SNAPSHOT', + }, ], }; @@ -77,15 +82,17 @@ describe('kibana cli', function () { }); it('should throw an error if plugin is missing a kibana version.', function () { - expect(() => assertVersion(settings)).toThrow( - /plugin package\.json is missing both a version property/i + expect(() => assertVersion(settings)).toThrowErrorMatchingInlineSnapshot( + `"Plugin kibana.json is missing both a version property (required) and a kibanaVersion property (optional)."` ); }); it('should throw an error if plugin kibanaVersion does not match kibana version', function () { settings.plugins[0].kibanaVersion = '1.2.3.4'; - expect(() => assertVersion(settings)).toThrow(/incompatible with Kibana/i); + expect(() => assertVersion(settings)).toThrowErrorMatchingInlineSnapshot( + `"Plugin foo [1.2.3] is incompatible with Kibana [1.0.0]"` + ); }); it('should not throw an error if plugin kibanaVersion matches kibana version', function () { @@ -103,7 +110,9 @@ describe('kibana cli', function () { it('should ignore version info after the dash in checks on invalid version', function () { settings.plugins[0].kibanaVersion = '2.0.0-foo-bar-version-1.2.3'; - expect(() => assertVersion(settings)).toThrow(/incompatible with Kibana/i); + expect(() => assertVersion(settings)).toThrowErrorMatchingInlineSnapshot( + `"Plugin foo [2.0.0] is incompatible with Kibana [1.0.0]"` + ); }); }); diff --git a/src/cli_plugin/install/pack.js b/src/cli_plugin/install/pack.js index 87c94fce2b677..56d7be78e44bc 100644 --- a/src/cli_plugin/install/pack.js +++ b/src/cli_plugin/install/pack.js @@ -18,7 +18,11 @@ */ import { analyzeArchive, extractArchive } from './zip'; -import validate from 'validate-npm-package-name'; + +const CAMEL_CASE_REG_EXP = /^[a-z]{1}([a-zA-Z0-9]{1,})$/; +export function isCamelCase(candidate) { + return CAMEL_CASE_REG_EXP.test(candidate); +} /** * Checks the plugin name. Will throw an exception if it does not meet @@ -27,9 +31,10 @@ import validate from 'validate-npm-package-name'; * @param {object} plugin - a package object from listPackages() */ function assertValidPackageName(plugin) { - const validation = validate(plugin.name); - if (!validation.validForNewPackages) { - throw new Error(`Invalid plugin name [${plugin.name}] in package.json`); + if (!isCamelCase(plugin.id)) { + throw new Error( + `Invalid plugin name [${plugin.id}] in kibana.json, expected it to be valid camelCase` + ); } } @@ -60,17 +65,13 @@ export async function getPackData(settings, logger) { /** * Extracts files from a zip archive to a file path using a filter function - * - * @param {string} archive - file path to a zip archive - * @param {string} targetDir - directory path to where the files should - * extracted */ export async function extract(settings, logger) { try { const plugin = settings.plugins[0]; logger.log('Extracting plugin archive'); - await extractArchive(settings.tempArchiveFile, settings.workingPath, plugin.archivePath); + await extractArchive(settings.tempArchiveFile, settings.workingPath, plugin.stripPrefix); logger.log('Extraction complete'); } catch (err) { logger.error(err.stack); diff --git a/src/cli_plugin/install/pack.test.js b/src/cli_plugin/install/pack.test.js index 05a60107f80ff..c31437e61bebf 100644 --- a/src/cli_plugin/install/pack.test.js +++ b/src/cli_plugin/install/pack.test.js @@ -18,14 +18,15 @@ */ import Fs from 'fs'; +import { join } from 'path'; import sinon from 'sinon'; import glob from 'glob-all'; import del from 'del'; -import Logger from '../lib/logger'; + +import { Logger } from '../lib/logger'; import { extract, getPackData } from './pack'; import { _downloadSingle } from './download'; -import { join } from 'path'; describe('kibana cli', function () { describe('pack', function () { @@ -73,133 +74,104 @@ describe('kibana cli', function () { return _downloadSingle(settings, logger, sourceUrl); } - function shouldReject() { - throw new Error('expected the promise to reject'); - } - describe('extract', function () { - //Also only extracts the content from the kibana folder. - //Ignores the others. - it('successfully extract a valid zip', function () { - return copyReplyFile('test_plugin.zip') - .then(() => { - return getPackData(settings, logger); - }) - .then(() => { - return extract(settings, logger); - }) - .then(() => { - const files = glob.sync('**/*', { cwd: testWorkingPath }); - const expected = [ - 'archive.part', - 'README.md', - 'index.js', - 'package.json', - 'public', - 'public/app.js', - 'extra file only in zip.txt', - ]; - expect(files.sort()).toEqual(expected.sort()); - }); + // Also only extracts the content from the kibana folder. + // Ignores the others. + it('successfully extract a valid zip', async () => { + await copyReplyFile('test_plugin.zip'); + await getPackData(settings, logger); + await extract(settings, logger); + + expect(glob.sync('**/*', { cwd: testWorkingPath })).toMatchInlineSnapshot(` + Array [ + "archive.part", + "bin", + "bin/executable", + "bin/not-executable", + "kibana.json", + "node_modules", + "node_modules/some-package", + "node_modules/some-package/index.js", + "node_modules/some-package/package.json", + "public", + "public/index.js", + ] + `); }); }); - describe('getPackData', function () { - it('populate settings.plugins', function () { - return copyReplyFile('test_plugin.zip') - .then(() => { - return getPackData(settings, logger); - }) - .then(() => { - expect(settings.plugins[0].name).toBe('test-plugin'); - expect(settings.plugins[0].archivePath).toBe('kibana/test-plugin'); - expect(settings.plugins[0].version).toBe('1.0.0'); - expect(settings.plugins[0].kibanaVersion).toBe('1.0.0'); - }); - }); - - it('populate settings.plugin.kibanaVersion', function () { - //kibana.version is defined in this package.json and is different than plugin version - return copyReplyFile('test_plugin_different_version.zip') - .then(() => { - return getPackData(settings, logger); - }) - .then(() => { - expect(settings.plugins[0].kibanaVersion).toBe('5.0.1'); - }); + describe('getPackData', () => { + it('populate settings.plugins', async () => { + await copyReplyFile('test_plugin.zip'); + await getPackData(settings, logger); + expect(settings.plugins).toMatchInlineSnapshot(` + Array [ + Object { + "id": "testPlugin", + "kibanaVersion": "1.0.0", + "stripPrefix": "kibana/test-plugin", + }, + ] + `); }); - it('populate settings.plugin.kibanaVersion (default to plugin version)', function () { - //kibana.version is not defined in this package.json, defaults to plugin version - return copyReplyFile('test_plugin.zip') - .then(() => { - return getPackData(settings, logger); - }) - .then(() => { - expect(settings.plugins[0].kibanaVersion).toBe('1.0.0'); - }); + it('populate settings.plugin.kibanaVersion', async () => { + await copyReplyFile('test_plugin_different_version.zip'); + await getPackData(settings, logger); + expect(settings.plugins).toMatchInlineSnapshot(` + Array [ + Object { + "id": "testPlugin", + "kibanaVersion": "5.0.1", + "stripPrefix": "kibana/test-plugin", + }, + ] + `); }); - it('populate settings.plugins with multiple plugins', function () { - return copyReplyFile('test_plugin_many.zip') - .then(() => { - return getPackData(settings, logger); - }) - .then(() => { - expect(settings.plugins[0].name).toBe('funger-plugin'); - expect(settings.plugins[0].archivePath).toBe('kibana/funger-plugin'); - expect(settings.plugins[0].version).toBe('1.0.0'); - - expect(settings.plugins[1].name).toBe('pdf'); - expect(settings.plugins[1].archivePath).toBe('kibana/pdf-linux'); - expect(settings.plugins[1].version).toBe('1.0.0'); - - expect(settings.plugins[2].name).toBe('pdf'); - expect(settings.plugins[2].archivePath).toBe('kibana/pdf-win32'); - expect(settings.plugins[2].version).toBe('1.0.0'); - - expect(settings.plugins[3].name).toBe('pdf'); - expect(settings.plugins[3].archivePath).toBe('kibana/pdf-win64'); - expect(settings.plugins[3].version).toBe('1.0.0'); - - expect(settings.plugins[4].name).toBe('pdf'); - expect(settings.plugins[4].archivePath).toBe('kibana/pdf'); - expect(settings.plugins[4].version).toBe('1.0.0'); - - expect(settings.plugins[5].name).toBe('test-plugin'); - expect(settings.plugins[5].archivePath).toBe('kibana/test-plugin'); - expect(settings.plugins[5].version).toBe('1.0.0'); - }); + it('populate settings.plugins with multiple plugins', async () => { + await copyReplyFile('test_plugin_many.zip'); + await getPackData(settings, logger); + expect(settings.plugins).toMatchInlineSnapshot(` + Array [ + Object { + "id": "fungerPlugin", + "kibanaVersion": "1.0.0", + "stripPrefix": "kibana/funger-plugin", + }, + Object { + "id": "pdf", + "kibanaVersion": "1.0.0", + "stripPrefix": "kibana/pdf", + }, + Object { + "id": "testPlugin", + "kibanaVersion": "1.0.0", + "stripPrefix": "kibana/test-plugin", + }, + ] + `); }); - it('throw an error if there is no kibana plugin', function () { - return copyReplyFile('test_plugin_no_kibana.zip') - .then(() => { - return getPackData(settings, logger); - }) - .then(shouldReject, (err) => { - expect(err.message).toMatch(/No kibana plugins found in archive/i); - }); + it('throw an error if there is no kibana plugin', async () => { + await copyReplyFile('test_plugin_no_kibana.zip'); + await expect(getPackData(settings, logger)).rejects.toThrowErrorMatchingInlineSnapshot( + `"No kibana plugins found in archive"` + ); }); - it('throw an error with a corrupt zip', function () { - return copyReplyFile('corrupt.zip') - .then(() => { - return getPackData(settings, logger); - }) - .then(shouldReject, (err) => { - expect(err.message).toMatch(/error retrieving/i); - }); + it('throw an error with a corrupt zip', async () => { + await copyReplyFile('corrupt.zip'); + await expect(getPackData(settings, logger)).rejects.toThrowErrorMatchingInlineSnapshot( + `"Error retrieving metadata from plugin archive"` + ); }); - it('throw an error if there an invalid plugin name', function () { - return copyReplyFile('invalid_name.zip') - .then(() => { - return getPackData(settings, logger); - }) - .then(shouldReject, (err) => { - expect(err.message).toMatch(/invalid plugin name/i); - }); + it('throw an error if there an invalid plugin name', async () => { + await copyReplyFile('invalid_name.zip'); + await expect(getPackData(settings, logger)).rejects.toThrowErrorMatchingInlineSnapshot( + `"Invalid plugin name [invalid name] in kibana.json, expected it to be valid camelCase"` + ); }); }); }); diff --git a/src/cli_plugin/install/progress.js b/src/cli_plugin/install/progress.js index e58e4472150b9..5c7d5074603dc 100644 --- a/src/cli_plugin/install/progress.js +++ b/src/cli_plugin/install/progress.js @@ -20,7 +20,7 @@ /** * Generates file transfer progress messages */ -export default class Progress { +export class Progress { constructor(logger) { const self = this; diff --git a/src/cli_plugin/install/progress.test.js b/src/cli_plugin/install/progress.test.js index 3b66e8b3dc86c..ef948bafca836 100644 --- a/src/cli_plugin/install/progress.test.js +++ b/src/cli_plugin/install/progress.test.js @@ -18,8 +18,9 @@ */ import sinon from 'sinon'; -import Progress from './progress'; -import Logger from '../lib/logger'; + +import { Progress } from './progress'; +import { Logger } from '../lib/logger'; describe('kibana cli', function () { describe('plugin installer', function () { diff --git a/src/cli_plugin/install/rename.js b/src/cli_plugin/install/rename.js index 1e5d94d474375..897222a579a4a 100644 --- a/src/cli_plugin/install/rename.js +++ b/src/cli_plugin/install/rename.js @@ -18,6 +18,7 @@ */ import { rename } from 'fs'; + import { delay } from 'lodash'; export function renamePlugin(workingPath, finalPath) { @@ -31,8 +32,12 @@ export function renamePlugin(workingPath, finalPath) { // Retry for up to retryTime seconds const windowsEPERM = process.platform === 'win32' && err.code === 'EPERM'; const retryAvailable = Date.now() - start < retryTime; - if (windowsEPERM && retryAvailable) - return delay(rename, retryDelay, workingPath, finalPath, retry); + + if (windowsEPERM && retryAvailable) { + delay(rename, retryDelay, workingPath, finalPath, retry); + return; + } + reject(err); } resolve(); diff --git a/src/cli_plugin/install/rename.test.js b/src/cli_plugin/install/rename.test.js index 40df75adc5efa..8525c367540f8 100644 --- a/src/cli_plugin/install/rename.test.js +++ b/src/cli_plugin/install/rename.test.js @@ -17,9 +17,10 @@ * under the License. */ -import sinon from 'sinon'; import fs from 'fs'; +import sinon from 'sinon'; + import { renamePlugin } from './rename'; describe('plugin folder rename', function () { diff --git a/src/cli_plugin/install/settings.js b/src/cli_plugin/install/settings.js index 40c845fc37a9e..20a11479321ee 100644 --- a/src/cli_plugin/install/settings.js +++ b/src/cli_plugin/install/settings.js @@ -17,9 +17,12 @@ * under the License. */ -import expiry from 'expiry-js'; import { resolve } from 'path'; +import expiry from 'expiry-js'; + +import { fromRoot } from '../../core/server/utils'; + function generateUrls({ version, plugin }) { return [ plugin, @@ -46,20 +49,14 @@ export function parse(command, options, kbnPackage) { quiet: options.quiet || false, silent: options.silent || false, config: options.config || '', - optimize: options.optimize, plugin: command, version: kbnPackage.version, - pluginDir: options.pluginDir || '', + pluginDir: fromRoot('plugins'), }; settings.urls = generateUrls(settings); settings.workingPath = resolve(settings.pluginDir, '.plugin.installing'); settings.tempArchiveFile = resolve(settings.workingPath, 'archive.part'); - settings.tempPackageFile = resolve(settings.workingPath, 'package.json'); - settings.setPlugin = function (plugin) { - settings.plugin = plugin; - settings.pluginPath = resolve(settings.pluginDir, settings.plugin.name); - }; return settings; } diff --git a/src/cli_plugin/install/settings.test.js b/src/cli_plugin/install/settings.test.js index 39ca07405ade2..54ad453de9ef8 100644 --- a/src/cli_plugin/install/settings.test.js +++ b/src/cli_plugin/install/settings.test.js @@ -17,199 +17,82 @@ * under the License. */ +import { createAbsolutePathSerializer } from '@kbn/dev-utils'; + import { fromRoot } from '../../core/server/utils'; -import { resolve } from 'path'; import { parseMilliseconds, parse } from './settings'; -describe('kibana cli', function () { - describe('plugin installer', function () { - describe('command line option parsing', function () { - describe('parseMilliseconds function', function () { - it('should return 0 for an empty string', function () { - const value = ''; - const result = parseMilliseconds(value); - - expect(result).toBe(0); - }); - - it('should return 0 for a number with an invalid unit of measure', function () { - const result = parseMilliseconds('1gigablasts'); - expect(result).toBe(0); - }); - - it('should assume a number with no unit of measure is specified as milliseconds', function () { - const result = parseMilliseconds(1); - expect(result).toBe(1); - - const result2 = parseMilliseconds('1'); - expect(result2).toBe(1); - }); - - it('should interpret a number with "s" as the unit of measure as seconds', function () { - const result = parseMilliseconds('5s'); - expect(result).toBe(5 * 1000); - }); - - it('should interpret a number with "second" as the unit of measure as seconds', function () { - const result = parseMilliseconds('5second'); - expect(result).toBe(5 * 1000); - }); - - it('should interpret a number with "seconds" as the unit of measure as seconds', function () { - const result = parseMilliseconds('5seconds'); - expect(result).toBe(5 * 1000); - }); - - it('should interpret a number with "m" as the unit of measure as minutes', function () { - const result = parseMilliseconds('9m'); - expect(result).toBe(9 * 1000 * 60); - }); - - it('should interpret a number with "minute" as the unit of measure as minutes', function () { - const result = parseMilliseconds('9minute'); - expect(result).toBe(9 * 1000 * 60); - }); - - it('should interpret a number with "minutes" as the unit of measure as minutes', function () { - const result = parseMilliseconds('9minutes'); - expect(result).toBe(9 * 1000 * 60); - }); - }); - - describe('parse function', function () { - const command = 'plugin name'; - let options = {}; - const kbnPackage = { version: 1234 }; - beforeEach(function () { - options = { pluginDir: fromRoot('plugins') }; - }); - - describe('timeout option', function () { - it('should default to 0 (milliseconds)', function () { - const settings = parse(command, options, kbnPackage); - - expect(settings.timeout).toBe(0); - }); - - it('should set settings.timeout property', function () { - options.timeout = 1234; - const settings = parse(command, options, kbnPackage); - - expect(settings.timeout).toBe(1234); - }); - }); - - describe('quiet option', function () { - it('should default to false', function () { - const settings = parse(command, options, kbnPackage); - - expect(settings.quiet).toBe(false); - }); - - it('should set settings.quiet property to true', function () { - options.quiet = true; - const settings = parse(command, options, kbnPackage); - - expect(settings.quiet).toBe(true); - }); - }); - - describe('silent option', function () { - it('should default to false', function () { - const settings = parse(command, options, kbnPackage); - - expect(settings.silent).toBe(false); - }); - - it('should set settings.silent property to true', function () { - options.silent = true; - const settings = parse(command, options, kbnPackage); - - expect(settings.silent).toBe(true); - }); - }); - - describe('config option', function () { - it('should default to ZLS', function () { - const settings = parse(command, options, kbnPackage); - - expect(settings.config).toBe(''); - }); - - it('should set settings.config property', function () { - options.config = 'foo bar baz'; - const settings = parse(command, options, kbnPackage); - - expect(settings.config).toBe('foo bar baz'); - }); - }); - - describe('pluginDir option', function () { - it('should default to plugins', function () { - const settings = parse(command, options, kbnPackage); - - expect(settings.pluginDir).toBe(fromRoot('plugins')); - }); - - it('should set settings.config property', function () { - options.pluginDir = 'foo bar baz'; - const settings = parse(command, options, kbnPackage); - - expect(settings.pluginDir).toBe('foo bar baz'); - }); - }); - - describe('command value', function () { - it('should set settings.plugin property', function () { - const settings = parse(command, options, kbnPackage); - - expect(settings.plugin).toBe(command); - }); - }); - - describe('urls collection', function () { - it('should populate the settings.urls property', function () { - const settings = parse(command, options, kbnPackage); - - const expected = [ - command, - `https://artifacts.elastic.co/downloads/kibana-plugins/${command}/${command}-1234.zip`, - ]; - - expect(settings.urls).toEqual(expected); - }); - }); - - describe('workingPath value', function () { - it('should set settings.workingPath property', function () { - options.pluginDir = 'foo/bar/baz'; - const settings = parse(command, options, kbnPackage); - const expected = resolve('foo/bar/baz', '.plugin.installing'); - - expect(settings.workingPath).toBe(expected); - }); - }); - - describe('tempArchiveFile value', function () { - it('should set settings.tempArchiveFile property', function () { - options.pluginDir = 'foo/bar/baz'; - const settings = parse(command, options, kbnPackage); - const expected = resolve('foo/bar/baz', '.plugin.installing', 'archive.part'); - - expect(settings.tempArchiveFile).toBe(expected); - }); - }); +const SECOND = 1000; +const MINUTE = SECOND * 60; + +expect.addSnapshotSerializer(createAbsolutePathSerializer()); + +describe('parseMilliseconds function', function () { + it.each([ + ['', 0], + ['1gigablasts', 0], + [1, 1], + ['1', 1], + ['5s', 5 * SECOND], + ['5second', 5 * SECOND], + ['5seconds', 5 * SECOND], + ['9m', 9 * MINUTE], + ['9minute', 9 * MINUTE], + ['9minutes', 9 * MINUTE], + ])('should parse %j to %j', (input, result) => { + expect(parseMilliseconds(input)).toBe(result); + }); +}); - describe('tempPackageFile value', function () { - it('should set settings.tempPackageFile property', function () { - options.pluginDir = 'foo/bar/baz'; - const settings = parse(command, options, kbnPackage); - const expected = resolve('foo/bar/baz', '.plugin.installing', 'package.json'); +describe('parse function', function () { + const command = 'plugin name'; + const defaultOptions = { pluginDir: fromRoot('plugins') }; + const kbnPackage = { version: 1234 }; + + it('produces expected defaults', function () { + expect(parse(command, { ...defaultOptions }, kbnPackage)).toMatchInlineSnapshot(` + Object { + "config": "", + "plugin": "plugin name", + "pluginDir": /plugins, + "quiet": false, + "silent": false, + "tempArchiveFile": /plugins/.plugin.installing/archive.part, + "timeout": 0, + "urls": Array [ + "plugin name", + "https://artifacts.elastic.co/downloads/kibana-plugins/plugin name/plugin name-1234.zip", + ], + "version": 1234, + "workingPath": /plugins/.plugin.installing, + } + `); + }); - expect(settings.tempPackageFile).toBe(expected); - }); - }); - }); - }); + it('consumes overrides', function () { + const options = { + quiet: true, + silent: true, + config: 'foo bar baz', + ...defaultOptions, + }; + + expect(parse(command, options, kbnPackage)).toMatchInlineSnapshot(` + Object { + "config": "foo bar baz", + "plugin": "plugin name", + "pluginDir": /plugins, + "quiet": true, + "silent": true, + "tempArchiveFile": /plugins/.plugin.installing/archive.part, + "timeout": 0, + "urls": Array [ + "plugin name", + "https://artifacts.elastic.co/downloads/kibana-plugins/plugin name/plugin name-1234.zip", + ], + "version": 1234, + "workingPath": /plugins/.plugin.installing, + } + `); }); }); diff --git a/src/cli_plugin/install/zip.js b/src/cli_plugin/install/zip.js index 52eba2ea239a2..b906dd59a302b 100644 --- a/src/cli_plugin/install/zip.js +++ b/src/cli_plugin/install/zip.js @@ -17,21 +17,24 @@ * under the License. */ -import yauzl from 'yauzl'; import path from 'path'; import { createWriteStream, mkdir } from 'fs'; -import { get } from 'lodash'; + +import yauzl from 'yauzl'; + +const isDirectoryRegex = /(\/|\\)$/; +function isDirectory(filename) { + return isDirectoryRegex.test(filename); +} /** * Returns an array of package objects. There will be one for each of - * package.json files in the archive - * - * @param {string} archive - path to plugin archive zip file + * package.json files in the archive */ export function analyzeArchive(archive) { const plugins = []; - const regExp = new RegExp('(kibana[\\\\/][^\\\\/]+)[\\\\/]package.json', 'i'); + const regExp = new RegExp('(kibana[\\\\/][^\\\\/]+)[\\\\/]kibana.json', 'i'); return new Promise((resolve, reject) => { yauzl.open(archive, { lazyEntries: true }, function (err, zipfile) { @@ -47,31 +50,32 @@ export function analyzeArchive(archive) { return zipfile.readEntry(); } - zipfile.openReadStream(entry, function (err, readable) { + zipfile.openReadStream(entry, function (error, readable) { const chunks = []; - if (err) { - return reject(err); + if (error) { + return reject(error); } readable.on('data', (chunk) => chunks.push(chunk)); readable.on('end', function () { - const contents = Buffer.concat(chunks).toString(); - const pkg = JSON.parse(contents); - - plugins.push( - Object.assign(pkg, { - archivePath: match[1], - archive: archive, - - // Plugins must specify their version, and by default that version should match - // the version of kibana down to the patch level. If these two versions need - // to diverge, they can specify a kibana.version to indicate the version of - // kibana the plugin is intended to work with. - kibanaVersion: get(pkg, 'kibana.version', pkg.version), - }) - ); + const manifestJson = Buffer.concat(chunks).toString(); + const manifest = JSON.parse(manifestJson); + + plugins.push({ + id: manifest.id, + stripPrefix: match[1], + + // Plugins must specify their version, and by default that version in the plugin + // manifest should match the version of kibana down to the patch level. If these + // two versions need plugins can specify a kibanaVersion to indicate the version + // of kibana the plugin is intended to work with. + kibanaVersion: + typeof manifest.kibanaVersion === 'string' && manifest.kibanaVersion + ? manifest.kibanaVersion + : manifest.version, + }); zipfile.readEntry(); }); @@ -85,12 +89,7 @@ export function analyzeArchive(archive) { }); } -const isDirectoryRegex = /(\/|\\)$/; -export function _isDirectory(filename) { - return isDirectoryRegex.test(filename); -} - -export function extractArchive(archive, targetDir, extractPath) { +export function extractArchive(archive, targetDir, stripPrefix) { return new Promise((resolve, reject) => { yauzl.open(archive, { lazyEntries: true }, function (err, zipfile) { if (err) { @@ -102,8 +101,8 @@ export function extractArchive(archive, targetDir, extractPath) { zipfile.on('entry', function (entry) { let fileName = entry.fileName; - if (extractPath && fileName.startsWith(extractPath)) { - fileName = fileName.substring(extractPath.length); + if (stripPrefix && fileName.startsWith(stripPrefix)) { + fileName = fileName.substring(stripPrefix.length); } else { return zipfile.readEntry(); } @@ -112,30 +111,34 @@ export function extractArchive(archive, targetDir, extractPath) { fileName = path.join(targetDir, fileName); } - if (_isDirectory(fileName)) { - mkdir(fileName, { recursive: true }, function (err) { - if (err) { - return reject(err); + if (isDirectory(fileName)) { + mkdir(fileName, { recursive: true }, function (error) { + if (error) { + return reject(error); } zipfile.readEntry(); }); } else { // file entry - zipfile.openReadStream(entry, function (err, readStream) { - if (err) { - return reject(err); + zipfile.openReadStream(entry, function (error, readStream) { + if (error) { + return reject(error); } // ensure parent directory exists - mkdir(path.dirname(fileName), { recursive: true }, function (err) { - if (err) { - return reject(err); + mkdir(path.dirname(fileName), { recursive: true }, function (error2) { + if (error2) { + return reject(error2); } readStream.pipe( - createWriteStream(fileName, { mode: entry.externalFileAttributes >>> 16 }) + createWriteStream(fileName, { + // eslint-disable-next-line no-bitwise + mode: entry.externalFileAttributes >>> 16, + }) ); + readStream.on('end', function () { zipfile.readEntry(); }); diff --git a/src/cli_plugin/install/zip.test.js b/src/cli_plugin/install/zip.test.js index 28367e9e24453..0f56c0d0322aa 100644 --- a/src/cli_plugin/install/zip.test.js +++ b/src/cli_plugin/install/zip.test.js @@ -17,12 +17,16 @@ * under the License. */ -import del from 'del'; import path from 'path'; import os from 'os'; -import glob from 'glob'; import fs from 'fs'; -import { analyzeArchive, extractArchive, _isDirectory } from './zip'; + +import del from 'del'; +import glob from 'glob'; + +import { analyzeArchive, extractArchive } from './zip'; + +const getMode = (path) => (fs.statSync(path).mode & parseInt('777', 8)).toString(8); describe('kibana cli', function () { describe('zip', function () { @@ -43,32 +47,37 @@ describe('kibana cli', function () { describe('analyzeArchive', function () { it('returns array of plugins', async () => { const packages = await analyzeArchive(archivePath); - const plugin = packages[0]; - - expect(packages).toBeInstanceOf(Array); - expect(plugin.name).toBe('test-plugin'); - expect(plugin.archivePath).toBe('kibana/test-plugin'); - expect(plugin.archive).toBe(archivePath); - expect(plugin.kibanaVersion).toBe('1.0.0'); + expect(packages).toMatchInlineSnapshot(` + Array [ + Object { + "id": "testPlugin", + "kibanaVersion": "1.0.0", + "stripPrefix": "kibana/test-plugin", + }, + ] + `); }); }); describe('extractArchive', () => { it('extracts files using the extractPath filter', async () => { - const archive = path.resolve(repliesPath, 'test_plugin_many.zip'); - + const archive = path.resolve(repliesPath, 'test_plugin.zip'); await extractArchive(archive, tempPath, 'kibana/test-plugin'); - const files = await glob.sync('**/*', { cwd: tempPath }); - - const expected = [ - 'extra file only in zip.txt', - 'index.js', - 'package.json', - 'public', - 'public/app.js', - 'README.md', - ]; - expect(files.sort()).toEqual(expected.sort()); + + expect(glob.sync('**/*', { cwd: tempPath })).toMatchInlineSnapshot(` + Array [ + "bin", + "bin/executable", + "bin/not-executable", + "kibana.json", + "node_modules", + "node_modules/some-package", + "node_modules/some-package/index.js", + "node_modules/some-package/package.json", + "public", + "public/index.js", + ] + `); }); }); @@ -76,49 +85,26 @@ describe('kibana cli', function () { it('verify consistency of modes of files', async () => { const archivePath = path.resolve(repliesPath, 'test_plugin.zip'); - await extractArchive(archivePath, tempPath, 'kibana/libs'); - const files = await glob.sync('**/*', { cwd: tempPath }); - - const expected = ['executable', 'unexecutable']; - expect(files.sort()).toEqual(expected.sort()); + await extractArchive(archivePath, tempPath, 'kibana/test-plugin/bin'); - const executableMode = - '0' + - (fs.statSync(path.resolve(tempPath, 'executable')).mode & parseInt('777', 8)).toString(8); - const unExecutableMode = - '0' + - (fs.statSync(path.resolve(tempPath, 'unexecutable')).mode & parseInt('777', 8)).toString( - 8 - ); + expect(glob.sync('**/*', { cwd: tempPath })).toMatchInlineSnapshot(` + Array [ + "executable", + "not-executable", + ] + `); - expect(executableMode).toEqual('0755'); - expect(unExecutableMode).toEqual('0644'); + expect(getMode(path.resolve(tempPath, 'executable'))).toEqual('755'); + expect(getMode(path.resolve(tempPath, 'not-executable'))).toEqual('644'); }); }); it('handles a corrupt zip archive', async () => { - try { - await extractArchive(path.resolve(repliesPath, 'corrupt.zip')); - throw new Error('This should have failed'); - } catch (e) { - return; - } - }); - }); - - describe('_isDirectory', () => { - it('should check for a forward slash', () => { - expect(_isDirectory('/foo/bar/')).toBe(true); - }); - - it('should check for a backslash', () => { - expect(_isDirectory('\\foo\\bar\\')).toBe(true); - }); - - it('should return false for files', () => { - expect(_isDirectory('foo.txt')).toBe(false); - expect(_isDirectory('\\path\\to\\foo.txt')).toBe(false); - expect(_isDirectory('/path/to/foo.txt')).toBe(false); + await expect( + extractArchive(path.resolve(repliesPath, 'corrupt.zip')) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"end of central directory record signature not found"` + ); }); }); }); diff --git a/src/cli_plugin/lib/error_if_x_pack.js b/src/cli_plugin/lib/error_if_x_pack.js index d6624f5308ec0..4ea7ceb37478e 100644 --- a/src/cli_plugin/lib/error_if_x_pack.js +++ b/src/cli_plugin/lib/error_if_x_pack.js @@ -17,7 +17,7 @@ * under the License. */ -import { isOSS } from './is_oss'; +import { isOss } from './is_oss'; function isXPack(plugin) { return /x-pack/.test(plugin); @@ -25,7 +25,7 @@ function isXPack(plugin) { export function errorIfXPackInstall(settings) { if (isXPack(settings.plugin)) { - if (isOSS()) { + if (isOss()) { throw new Error( 'You are using the OSS-only distribution of Kibana. ' + 'As of version 6.3+ X-Pack is bundled in the standard distribution of this software by default; ' + @@ -40,7 +40,7 @@ export function errorIfXPackInstall(settings) { } export function errorIfXPackRemove(settings) { - if (isXPack(settings.plugin) && !isOSS()) { + if (isXPack(settings.plugin) && !isOss()) { throw new Error( 'You are using the standard distribution of Kibana. Please install the OSS-only distribution to remove X-Pack features.' ); diff --git a/src/cli_plugin/lib/is_oss.js b/src/cli_plugin/lib/is_oss.js index 3f2190d8346ec..53f19a41228d6 100644 --- a/src/cli_plugin/lib/is_oss.js +++ b/src/cli_plugin/lib/is_oss.js @@ -20,6 +20,6 @@ import fs from 'fs'; import path from 'path'; -export function isOSS() { +export function isOss() { return !fs.existsSync(path.resolve(__dirname, '../../../x-pack')); } diff --git a/src/cli_plugin/lib/is_oss.test.js b/src/cli_plugin/lib/is_oss.test.js index a4673710c63ce..636e1616e7d3c 100644 --- a/src/cli_plugin/lib/is_oss.test.js +++ b/src/cli_plugin/lib/is_oss.test.js @@ -17,12 +17,12 @@ * under the License. */ -import { isOSS } from './is_oss'; +import { isOss } from './is_oss'; describe('is_oss', () => { describe('x-pack installed', () => { it('should return false', () => { - expect(isOSS()).toEqual(false); + expect(isOss()).toEqual(false); }); }); }); diff --git a/src/cli_plugin/lib/log_warnings.js b/src/cli_plugin/lib/log_warnings.js index b4542acecb305..f31c3d4bd2e9a 100644 --- a/src/cli_plugin/lib/log_warnings.js +++ b/src/cli_plugin/lib/log_warnings.js @@ -17,7 +17,7 @@ * under the License. */ -export default function (settings, logger) { +export function logWarnings(logger) { process.on('warning', (warning) => { // deprecation warnings do no reflect a current problem for // the user and therefor should be filtered out. diff --git a/src/cli_plugin/lib/logger.js b/src/cli_plugin/lib/logger.js index efd6130322c38..592618fbecfc8 100644 --- a/src/cli_plugin/lib/logger.js +++ b/src/cli_plugin/lib/logger.js @@ -20,7 +20,7 @@ /** * Logs messages and errors */ -export default class Logger { +export class Logger { constructor(settings = {}) { this.previousLineEnded = true; this.silent = !!settings.silent; diff --git a/src/cli_plugin/lib/logger.test.js b/src/cli_plugin/lib/logger.test.js index 00cad1a9bbb11..7ff683ea50c95 100644 --- a/src/cli_plugin/lib/logger.test.js +++ b/src/cli_plugin/lib/logger.test.js @@ -18,7 +18,8 @@ */ import sinon from 'sinon'; -import Logger from './logger'; + +import { Logger } from './logger'; describe('kibana cli', function () { describe('plugin installer', function () { diff --git a/src/cli_plugin/lib/warn_if_plugin_dir_option.js b/src/cli_plugin/lib/warn_if_plugin_dir_option.js deleted file mode 100644 index eb85ba063c3c9..0000000000000 --- a/src/cli_plugin/lib/warn_if_plugin_dir_option.js +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export function warnIfUsingPluginDirOption(options, defaultValue, logger) { - if (options && options.pluginDir !== defaultValue) { - logger.log( - 'Warning: Using the -d, --plugin-dir option is deprecated, and is ' + - 'known to not work for all plugins, including X-Pack.' - ); - } -} diff --git a/src/cli_plugin/list/index.js b/src/cli_plugin/list/index.js index c0f708b8ccf83..a3cf1a54a8a62 100644 --- a/src/cli_plugin/list/index.js +++ b/src/cli_plugin/list/index.js @@ -18,37 +18,16 @@ */ import { fromRoot } from '../../core/server/utils'; -import list from './list'; -import Logger from '../lib/logger'; -import { parse } from './settings'; -import logWarnings from '../lib/log_warnings'; -import { warnIfUsingPluginDirOption } from '../lib/warn_if_plugin_dir_option'; +import { list } from './list'; +import { Logger } from '../lib/logger'; +import { logWarnings } from '../lib/log_warnings'; -function processCommand(command, options) { - let settings; - try { - settings = parse(command, options); - } catch (ex) { - //The logger has not yet been initialized. - console.error(ex.message); - process.exit(64); // eslint-disable-line no-process-exit - } - - const logger = new Logger(settings); - - warnIfUsingPluginDirOption(settings, fromRoot('plugins'), logger); - logWarnings(settings, logger); - list(settings, logger); +function processCommand() { + const logger = new Logger(); + logWarnings(logger); + list(fromRoot('plugins'), logger); } -export default function pluginList(program) { - program - .command('list') - .option( - '-d, --plugin-dir ', - 'path to the directory where plugins are stored (DEPRECATED, known to not work for all plugins)', - fromRoot('plugins') - ) - .description('list installed plugins') - .action(processCommand); +export function listCommand(program) { + program.command('list').description('list installed plugins').action(processCommand); } diff --git a/src/cli_plugin/list/list.js b/src/cli_plugin/list/list.js index b34631e5dfd08..bf6a082a91878 100644 --- a/src/cli_plugin/list/list.js +++ b/src/cli_plugin/list/list.js @@ -20,19 +20,20 @@ import { statSync, readdirSync, readFileSync } from 'fs'; import { join } from 'path'; -export default function list(settings, logger) { - readdirSync(settings.pluginDir).forEach((filename) => { - const stat = statSync(join(settings.pluginDir, filename)); +export function list(pluginDir, logger) { + readdirSync(pluginDir).forEach((name) => { + const stat = statSync(join(pluginDir, name)); - if (stat.isDirectory() && filename[0] !== '.') { + if (stat.isDirectory() && name[0] !== '.') { try { - const packagePath = join(settings.pluginDir, filename, 'package.json'); - const { version } = JSON.parse(readFileSync(packagePath, 'utf8')); - logger.log(filename + '@' + version); + const packagePath = join(pluginDir, name, 'kibana.json'); + const pkg = JSON.parse(readFileSync(packagePath, 'utf8')); + logger.log(pkg.id + '@' + pkg.version); } catch (e) { - throw new Error('Unable to read package.json file for plugin ' + filename); + throw new Error('Unable to read kibana.json file for plugin ' + name); } } }); + logger.log(''); //intentional blank line for aesthetics } diff --git a/src/cli_plugin/list/list.test.js b/src/cli_plugin/list/list.test.js index 071a253fa87fe..b1b5d1cde6a35 100644 --- a/src/cli_plugin/list/list.test.js +++ b/src/cli_plugin/list/list.test.js @@ -17,78 +17,67 @@ * under the License. */ -import sinon from 'sinon'; -import del from 'del'; -import Logger from '../lib/logger'; -import list from './list'; import { join } from 'path'; -import { writeFileSync, appendFileSync, mkdirSync } from 'fs'; +import { writeFileSync, mkdirSync } from 'fs'; + +import del from 'del'; + +import { list } from './list'; function createPlugin(name, version, pluginBaseDir) { const pluginDir = join(pluginBaseDir, name); mkdirSync(pluginDir, { recursive: true }); - appendFileSync(join(pluginDir, 'package.json'), '{"version": "' + version + '"}'); + writeFileSync( + join(pluginDir, 'kibana.json'), + JSON.stringify({ + id: name, + version, + }) + ); } +const logger = { + messages: [], + log(msg) { + this.messages.push(`log: ${msg}`); + }, + error(msg) { + this.messages.push(`error: ${msg}`); + }, +}; + describe('kibana cli', function () { describe('plugin lister', function () { const pluginDir = join(__dirname, '.test.data.list'); - let logger; - - const settings = { - pluginDir: pluginDir, - }; beforeEach(function () { - logger = new Logger(settings); - sinon.stub(logger, 'log'); - sinon.stub(logger, 'error'); + logger.messages.length = 0; del.sync(pluginDir); mkdirSync(pluginDir, { recursive: true }); }); afterEach(function () { - logger.log.restore(); - logger.error.restore(); del.sync(pluginDir); }); - it('list all of the folders in the plugin folder', function () { - createPlugin('plugin1', '5.0.0-alpha2', pluginDir); - createPlugin('plugin2', '3.2.1', pluginDir); - createPlugin('plugin3', '1.2.3', pluginDir); - - list(settings, logger); - - expect(logger.log.calledWith('plugin1@5.0.0-alpha2')).toBe(true); - expect(logger.log.calledWith('plugin2@3.2.1')).toBe(true); - expect(logger.log.calledWith('plugin3@1.2.3')).toBe(true); - }); - - it('ignore folders that start with a period', function () { + it('list all of the folders in the plugin folder, ignoring dot prefixed plugins and regular files', function () { createPlugin('.foo', '1.0.0', pluginDir); createPlugin('plugin1', '5.0.0-alpha2', pluginDir); createPlugin('plugin2', '3.2.1', pluginDir); createPlugin('plugin3', '1.2.3', pluginDir); createPlugin('.bar', '1.0.0', pluginDir); - - list(settings, logger); - - expect(logger.log.calledWith('.foo@1.0.0')).toBe(false); - expect(logger.log.calledWith('.bar@1.0.0')).toBe(false); - }); - - it('list should only list folders', function () { - createPlugin('plugin1', '1.0.0', pluginDir); - createPlugin('plugin2', '1.0.0', pluginDir); - createPlugin('plugin3', '1.0.0', pluginDir); writeFileSync(join(pluginDir, 'plugin4'), 'This is a file, and not a folder.'); - list(settings, logger); + list(pluginDir, logger); - expect(logger.log.calledWith('plugin1@1.0.0')).toBe(true); - expect(logger.log.calledWith('plugin2@1.0.0')).toBe(true); - expect(logger.log.calledWith('plugin3@1.0.0')).toBe(true); + expect(logger.messages).toMatchInlineSnapshot(` + Array [ + "log: plugin1@5.0.0-alpha2", + "log: plugin2@3.2.1", + "log: plugin3@1.2.3", + "log: ", + ] + `); }); it('list should throw an exception if a plugin does not have a package.json', function () { @@ -96,19 +85,23 @@ describe('kibana cli', function () { mkdirSync(join(pluginDir, 'empty-plugin'), { recursive: true }); expect(function () { - list(settings, logger); - }).toThrowError('Unable to read package.json file for plugin empty-plugin'); + list(pluginDir, logger); + }).toThrowErrorMatchingInlineSnapshot( + `"Unable to read kibana.json file for plugin empty-plugin"` + ); }); it('list should throw an exception if a plugin have an empty package.json', function () { createPlugin('plugin1', '1.0.0', pluginDir); const invalidPluginDir = join(pluginDir, 'invalid-plugin'); mkdirSync(invalidPluginDir, { recursive: true }); - appendFileSync(join(invalidPluginDir, 'package.json'), ''); + writeFileSync(join(invalidPluginDir, 'package.json'), ''); expect(function () { - list(settings, logger); - }).toThrowError('Unable to read package.json file for plugin invalid-plugin'); + list(pluginDir, logger); + }).toThrowErrorMatchingInlineSnapshot( + `"Unable to read kibana.json file for plugin invalid-plugin"` + ); }); }); }); diff --git a/src/cli_plugin/list/settings.js b/src/cli_plugin/list/settings.js deleted file mode 100644 index d17ce5deaec30..0000000000000 --- a/src/cli_plugin/list/settings.js +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export function parse(command) { - const settings = { - pluginDir: command.pluginDir || '', - }; - - return settings; -} diff --git a/src/cli_plugin/list/settings.test.js b/src/cli_plugin/list/settings.test.js deleted file mode 100644 index 85e6cb88e82fd..0000000000000 --- a/src/cli_plugin/list/settings.test.js +++ /dev/null @@ -1,50 +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 { fromRoot } from '../../core/server/utils'; -import { parse } from './settings'; - -describe('kibana cli', function () { - describe('plugin installer', function () { - describe('command line option parsing', function () { - describe('parse function', function () { - let command; - const options = {}; - beforeEach(function () { - command = { pluginDir: fromRoot('plugins') }; - }); - - describe('pluginDir option', function () { - it('should default to plugins', function () { - const settings = parse(command, options); - - expect(settings.pluginDir).toBe(fromRoot('plugins')); - }); - - it('should set settings.config property', function () { - command.pluginDir = 'foo bar baz'; - const settings = parse(command, options); - - expect(settings.pluginDir).toBe('foo bar baz'); - }); - }); - }); - }); - }); -}); diff --git a/src/cli_plugin/remove/index.js b/src/cli_plugin/remove/index.js index 9ff06e0e760bf..c3bd96086db9b 100644 --- a/src/cli_plugin/remove/index.js +++ b/src/cli_plugin/remove/index.js @@ -17,46 +17,34 @@ * under the License. */ -import { fromRoot } from '../../core/server/utils'; -import remove from './remove'; -import Logger from '../lib/logger'; +import { remove } from './remove'; +import { Logger } from '../lib/logger'; import { parse } from './settings'; import { getConfigPath } from '../../core/server/path'; -import logWarnings from '../lib/log_warnings'; -import { warnIfUsingPluginDirOption } from '../lib/warn_if_plugin_dir_option'; +import { logWarnings } from '../lib/log_warnings'; function processCommand(command, options) { let settings; try { settings = parse(command, options); } catch (ex) { - //The logger has not yet been initialized. + // The logger has not yet been initialized. console.error(ex.message); process.exit(64); // eslint-disable-line no-process-exit } const logger = new Logger(settings); - warnIfUsingPluginDirOption(settings, fromRoot('plugins'), logger); logWarnings(settings, logger); remove(settings, logger); } -export default function pluginRemove(program) { +export function removeCommand(program) { program .command('remove ') .option('-q, --quiet', 'disable all process messaging except errors') .option('-s, --silent', 'disable all process messaging') .option('-c, --config ', 'path to the config file', getConfigPath()) - .option( - '-d, --plugin-dir ', - 'path to the directory where plugins are stored (DEPRECATED, known to not work for all plugins)', - fromRoot('plugins') - ) - .description( - 'remove a plugin', - `common examples: - remove x-pack` - ) + .description('remove a plugin') .action(processCommand); } diff --git a/src/cli_plugin/remove/remove.js b/src/cli_plugin/remove/remove.js index 353e592390ff4..0c218301242be 100644 --- a/src/cli_plugin/remove/remove.js +++ b/src/cli_plugin/remove/remove.js @@ -18,11 +18,12 @@ */ import { statSync } from 'fs'; -import { errorIfXPackRemove } from '../lib/error_if_x_pack'; import del from 'del'; -export default function remove(settings, logger) { +import { errorIfXPackRemove } from '../lib/error_if_x_pack'; + +export function remove(settings, logger) { try { let stat; try { diff --git a/src/cli_plugin/remove/remove.test.js b/src/cli_plugin/remove/remove.test.js index 4bf061820aa05..44c66468bbb55 100644 --- a/src/cli_plugin/remove/remove.test.js +++ b/src/cli_plugin/remove/remove.test.js @@ -17,13 +17,15 @@ * under the License. */ +import { join } from 'path'; +import { writeFileSync, existsSync, mkdirSync } from 'fs'; + import sinon from 'sinon'; import glob from 'glob-all'; import del from 'del'; -import Logger from '../lib/logger'; -import remove from './remove'; -import { join } from 'path'; -import { writeFileSync, existsSync, mkdirSync } from 'fs'; + +import { Logger } from '../lib/logger'; +import { remove } from './remove'; describe('kibana cli', function () { describe('plugin remover', function () { diff --git a/src/cli_plugin/remove/settings.js b/src/cli_plugin/remove/settings.js index dc8d3c87e6eab..8a7d41b35ae57 100644 --- a/src/cli_plugin/remove/settings.js +++ b/src/cli_plugin/remove/settings.js @@ -19,12 +19,14 @@ import { resolve } from 'path'; +import { fromRoot } from '../../core/server/utils'; + export function parse(command, options) { const settings = { quiet: options.quiet || false, silent: options.silent || false, config: options.config || '', - pluginDir: options.pluginDir || '', + pluginDir: fromRoot('plugins'), plugin: command, }; diff --git a/src/cli_plugin/remove/settings.test.js b/src/cli_plugin/remove/settings.test.js index b3110e1ff0499..9ae555d79cd1a 100644 --- a/src/cli_plugin/remove/settings.test.js +++ b/src/cli_plugin/remove/settings.test.js @@ -17,88 +17,42 @@ * under the License. */ -import { fromRoot } from '../../core/server/utils'; -import { parse } from './settings'; - -describe('kibana cli', function () { - describe('plugin installer', function () { - describe('command line option parsing', function () { - describe('parse function', function () { - const command = 'plugin name'; - let options = {}; - const kbnPackage = { version: 1234 }; - beforeEach(function () { - options = { pluginDir: fromRoot('plugins') }; - }); - - describe('quiet option', function () { - it('should default to false', function () { - const settings = parse(command, options, kbnPackage); - - expect(settings.quiet).toBe(false); - }); - - it('should set settings.quiet property to true', function () { - options.quiet = true; - const settings = parse(command, options, kbnPackage); - - expect(settings.quiet).toBe(true); - }); - }); - - describe('silent option', function () { - it('should default to false', function () { - const settings = parse(command, options, kbnPackage); - - expect(settings.silent).toBe(false); - }); - - it('should set settings.silent property to true', function () { - options.silent = true; - const settings = parse(command, options, kbnPackage); - - expect(settings.silent).toBe(true); - }); - }); +import { createAbsolutePathSerializer } from '@kbn/dev-utils'; - describe('config option', function () { - it('should default to ZLS', function () { - const settings = parse(command, options, kbnPackage); - - expect(settings.config).toBe(''); - }); - - it('should set settings.config property', function () { - options.config = 'foo bar baz'; - const settings = parse(command, options, kbnPackage); - - expect(settings.config).toBe('foo bar baz'); - }); - }); - - describe('pluginDir option', function () { - it('should default to plugins', function () { - const settings = parse(command, options, kbnPackage); - - expect(settings.pluginDir).toBe(fromRoot('plugins')); - }); - - it('should set settings.config property', function () { - options.pluginDir = 'foo bar baz'; - const settings = parse(command, options, kbnPackage); - - expect(settings.pluginDir).toBe('foo bar baz'); - }); - }); +import { parse } from './settings'; - describe('command value', function () { - it('should set settings.plugin property', function () { - const settings = parse(command, options, kbnPackage); +const command = 'plugin name'; + +expect.addSnapshotSerializer(createAbsolutePathSerializer()); + +it('produces the defaults', () => { + expect(parse(command, {})).toMatchInlineSnapshot(` + Object { + "config": "", + "plugin": "plugin name", + "pluginDir": /plugins, + "pluginPath": /plugins/plugin name, + "quiet": false, + "silent": false, + } + `); +}); - expect(settings.plugin).toBe(command); - }); - }); - }); - }); - }); +it('overrides the defaults with the parsed cli options', () => { + expect( + parse(command, { + quiet: true, + silent: true, + config: 'foo/bar', + }) + ).toMatchInlineSnapshot(` + Object { + "config": "foo/bar", + "plugin": "plugin name", + "pluginDir": /plugins, + "pluginPath": /plugins/plugin name, + "quiet": true, + "silent": true, + } + `); }); diff --git a/yarn.lock b/yarn.lock index 332215a59e788..42c4b800e6b0c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7878,11 +7878,6 @@ builtin-status-codes@^3.0.0: resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= -builtins@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-0.0.7.tgz#355219cd6cf18dbe7c01cc7fd2dce765cfdc549a" - integrity sha1-NVIZzWzxjb58Acx/0tznZc/cVJo= - bytes@1: version "1.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" @@ -29959,13 +29954,6 @@ validate-npm-package-license@^3.0.1: spdx-correct "~1.0.0" spdx-expression-parse "~1.0.0" -validate-npm-package-name@2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-2.2.2.tgz#f65695b22f7324442019a3c7fa39a6e7fd299085" - integrity sha1-9laVsi9zJEQgGaPH+jmm5/0pkIU= - dependencies: - builtins "0.0.7" - validator@^10.11.0: version "10.11.0" resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228" From 4ca52e678a86bc4c9ffef02a9886f6242fdb2273 Mon Sep 17 00:00:00 2001 From: Ryland Herrick Date: Wed, 12 Aug 2020 19:26:06 -0500 Subject: [PATCH 08/53] [Security Solution][Detections] Refactor ML calls for newest ML permissions (#74582) ## Summary Addresses https://github.com/elastic/kibana/issues/73567. ML Users (role: `machine_learning_user`) were previously able to invoke the ML Recognizer API, which we use to get not-yet-installed ML Jobs relevant to our index patterns. As of https://github.com/elastic/kibana/pull/64662 this is not true, and so we receive errors from components using the underlying hook, `useSiemJobs`. To solve this I've created two separate hooks to replace `useSiemJobs`: * `useSecurityJobs` * used on ML Popover * includes uninstalled ML Jobs * checks (and returns) `isMlAdmin` before fetching data * `useInstalledSecurityJobs` * used on ML Jobs Dropdown and Anomalies Table * includes only installed ML Jobs * checks (and returns) `isMlUser` before fetching data Note that we while we now receive the knowledge to do so, we do not always inform the user in the case of invalid permissions, and instead have the following behaviors: #### User has insufficient license * ML Popover: shows an upgrade CTA * Anomalies Tables: show no data * Rule Creation: ML Rule option is disabled, shows upgrade CTA * Rule Details: ML Job Id is displayed as text #### User is ML User * ML Popover: not shown * Anomalies Tables: show no data * Rule Creation: ML Rule option is disabled * Rule Details: ML Job Id is displayed as text #### User is ML Admin * ML Popover: shown * Anomalies Tables: show data __for installed ML Jobs__ * This is the same as previous logic, but worth calling out that you can't view historical anomalies * Rule Creation: ML Rule option is enabled, all ML Jobs available * Rule Details: ML Job Id is displayed as hyperlink, job status badge shown ### Checklist - [x] [Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process) --- .../anomaly_detection_jobs/summary_job.ts | 4 +- x-pack/plugins/ml/public/shared.ts | 1 + .../machine_learning/has_ml_license.test.ts | 20 ++++ .../common/machine_learning/has_ml_license.ts | 10 ++ .../machine_learning/is_security_job.ts | 3 +- .../ml/anomaly/use_anomalies_table_data.ts | 28 ++--- .../components/ml/api/get_jobs_summary.ts | 35 ++++++ .../components/ml/api/get_ml_capabilities.ts | 13 ++- .../ml/hooks/use_get_jobs_summary.ts | 12 ++ .../ml/hooks/use_get_ml_capabilities.ts | 12 ++ .../hooks/use_installed_security_jobs.test.ts | 99 ++++++++++++++++ .../ml/hooks/use_installed_security_jobs.ts | 63 ++++++++++ .../hooks/use_ml_capabilities.ts} | 2 +- .../permissions/ml_capabilities_provider.tsx | 47 +++----- .../ml/tables/anomalies_host_table.tsx | 2 +- .../ml/tables/anomalies_network_table.tsx | 2 +- .../{ml_popover/hooks => ml}/translations.ts | 0 .../{__mocks__/api.tsx => api.mock.ts} | 12 +- .../components/ml_popover/{api.tsx => api.ts} | 19 --- .../components/ml_popover/helpers.test.tsx | 12 +- .../common/components/ml_popover/helpers.tsx | 8 +- .../hooks/use_security_jobs.test.ts | 110 ++++++++++++++++++ .../ml_popover/hooks/use_security_jobs.ts | 95 +++++++++++++++ ...tsx => use_security_jobs_helpers.test.tsx} | 28 ++--- ...pers.tsx => use_security_jobs_helpers.tsx} | 71 +++++------ .../ml_popover/hooks/use_siem_jobs.tsx | 81 ------------- .../jobs_table_filters.test.tsx.snap | 2 +- .../filters/groups_filter_popover.test.tsx | 15 ++- .../filters/groups_filter_popover.tsx | 14 +-- .../filters/jobs_table_filters.test.tsx | 18 +-- .../jobs_table/filters/jobs_table_filters.tsx | 16 ++- .../ml_popover/jobs_table/job_switch.test.tsx | 24 ++-- .../ml_popover/jobs_table/job_switch.tsx | 12 +- .../ml_popover/jobs_table/jobs_table.test.tsx | 24 ++-- .../ml_popover/jobs_table/jobs_table.tsx | 27 +++-- .../components/ml_popover/ml_popover.tsx | 29 +++-- .../common/components/ml_popover/types.ts | 30 +---- .../anomalies_query_tab_body/index.tsx | 6 +- .../anomalies_query_tab_body/utils.ts | 9 +- .../common/hooks/use_app_toasts.mock.ts | 14 +++ .../common/lib/kibana/__mocks__/index.ts | 1 + .../public/common/mock/kibana_core.ts | 2 + .../public/common/mock/kibana_react.ts | 18 --- .../rules/description_step/index.tsx | 6 +- .../ml_job_description.test.tsx | 25 +--- .../description_step/ml_job_description.tsx | 14 +-- .../rules/ml_job_select/index.test.tsx | 6 +- .../components/rules/ml_job_select/index.tsx | 12 +- .../rules/step_define_rule/index.tsx | 5 +- .../detection_engine/rules/all/index.tsx | 6 +- .../detection_engine/rules/details/index.tsx | 6 +- .../public/hosts/pages/details/index.tsx | 2 +- .../public/hosts/pages/hosts.tsx | 2 +- .../network/components/ip_overview/index.tsx | 2 +- .../public/network/pages/index.tsx | 2 +- .../components/host_overview/index.tsx | 2 +- 56 files changed, 733 insertions(+), 407 deletions(-) create mode 100644 x-pack/plugins/security_solution/common/machine_learning/has_ml_license.test.ts create mode 100644 x-pack/plugins/security_solution/common/machine_learning/has_ml_license.ts create mode 100644 x-pack/plugins/security_solution/public/common/components/ml/api/get_jobs_summary.ts create mode 100644 x-pack/plugins/security_solution/public/common/components/ml/hooks/use_get_jobs_summary.ts create mode 100644 x-pack/plugins/security_solution/public/common/components/ml/hooks/use_get_ml_capabilities.ts create mode 100644 x-pack/plugins/security_solution/public/common/components/ml/hooks/use_installed_security_jobs.test.ts create mode 100644 x-pack/plugins/security_solution/public/common/components/ml/hooks/use_installed_security_jobs.ts rename x-pack/plugins/security_solution/public/common/components/{ml_popover/hooks/use_ml_capabilities.tsx => ml/hooks/use_ml_capabilities.ts} (80%) rename x-pack/plugins/security_solution/public/common/components/{ml_popover/hooks => ml}/translations.ts (100%) rename x-pack/plugins/security_solution/public/common/components/ml_popover/{__mocks__/api.tsx => api.mock.ts} (99%) rename x-pack/plugins/security_solution/public/common/components/ml_popover/{api.tsx => api.ts} (89%) create mode 100644 x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.test.ts create mode 100644 x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.ts rename x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/{use_siem_jobs_helpers.test.tsx => use_security_jobs_helpers.test.tsx} (83%) rename x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/{use_siem_jobs_helpers.tsx => use_security_jobs_helpers.tsx} (59%) delete mode 100644 x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_siem_jobs.tsx create mode 100644 x-pack/plugins/security_solution/public/common/hooks/use_app_toasts.mock.ts diff --git a/x-pack/plugins/ml/common/types/anomaly_detection_jobs/summary_job.ts b/x-pack/plugins/ml/common/types/anomaly_detection_jobs/summary_job.ts index 2102673060273..d0bce8508e82e 100644 --- a/x-pack/plugins/ml/common/types/anomaly_detection_jobs/summary_job.ts +++ b/x-pack/plugins/ml/common/types/anomaly_detection_jobs/summary_job.ts @@ -36,8 +36,8 @@ export interface MlSummaryJob { export interface AuditMessage { job_id: string; msgTime: number; - level: number; - highestLevel: number; + level: string; + highestLevel: string; highestLevelText: string; text: string; } diff --git a/x-pack/plugins/ml/public/shared.ts b/x-pack/plugins/ml/public/shared.ts index 4b1d7ee733dcf..ec884bfac5351 100644 --- a/x-pack/plugins/ml/public/shared.ts +++ b/x-pack/plugins/ml/public/shared.ts @@ -9,6 +9,7 @@ export * from '../common/constants/anomalies'; export * from '../common/types/data_recognizer'; export * from '../common/types/capabilities'; export * from '../common/types/anomalies'; +export * from '../common/types/anomaly_detection_jobs'; export * from '../common/types/modules'; export * from '../common/types/audit_message'; diff --git a/x-pack/plugins/security_solution/common/machine_learning/has_ml_license.test.ts b/x-pack/plugins/security_solution/common/machine_learning/has_ml_license.test.ts new file mode 100644 index 0000000000000..1ffc2e16b78f7 --- /dev/null +++ b/x-pack/plugins/security_solution/common/machine_learning/has_ml_license.test.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 { emptyMlCapabilities } from './empty_ml_capabilities'; +import { hasMlLicense } from './has_ml_license'; + +describe('hasMlLicense', () => { + test('it returns false when license is not platinum or trial', () => { + const capabilities = { ...emptyMlCapabilities, isPlatinumOrTrialLicense: false }; + expect(hasMlLicense(capabilities)).toEqual(false); + }); + + test('it returns true when license is platinum or trial', () => { + const capabilities = { ...emptyMlCapabilities, isPlatinumOrTrialLicense: true }; + expect(hasMlLicense(capabilities)).toEqual(true); + }); +}); diff --git a/x-pack/plugins/security_solution/common/machine_learning/has_ml_license.ts b/x-pack/plugins/security_solution/common/machine_learning/has_ml_license.ts new file mode 100644 index 0000000000000..c0b6862ac30fe --- /dev/null +++ b/x-pack/plugins/security_solution/common/machine_learning/has_ml_license.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. + */ + +import { MlCapabilitiesResponse } from '../../../ml/common/types/capabilities'; + +export const hasMlLicense = (capabilities: MlCapabilitiesResponse): boolean => + capabilities.isPlatinumOrTrialLicense; diff --git a/x-pack/plugins/security_solution/common/machine_learning/is_security_job.ts b/x-pack/plugins/security_solution/common/machine_learning/is_security_job.ts index 43cfa4ad59964..f5783fc9b3973 100644 --- a/x-pack/plugins/security_solution/common/machine_learning/is_security_job.ts +++ b/x-pack/plugins/security_solution/common/machine_learning/is_security_job.ts @@ -4,8 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { MlSummaryJob } from '../../../ml/common/types/anomaly_detection_jobs'; import { ML_GROUP_IDS } from '../constants'; -export const isSecurityJob = (job: MlSummaryJob): boolean => +export const isSecurityJob = (job: { groups: string[] }): boolean => job.groups.some((group) => ML_GROUP_IDS.includes(group)); diff --git a/x-pack/plugins/security_solution/public/common/components/ml/anomaly/use_anomalies_table_data.ts b/x-pack/plugins/security_solution/public/common/components/ml/anomaly/use_anomalies_table_data.ts index 6fbb308672e5d..e6597de892bff 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml/anomaly/use_anomalies_table_data.ts +++ b/x-pack/plugins/security_solution/public/common/components/ml/anomaly/use_anomalies_table_data.ts @@ -9,13 +9,11 @@ import { useState, useEffect, useMemo } from 'react'; import { DEFAULT_ANOMALY_SCORE } from '../../../../../common/constants'; import { anomaliesTableData } from '../api/anomalies_table_data'; import { InfluencerInput, Anomalies, CriteriaFields } from '../types'; -import { hasMlUserPermissions } from '../../../../../common/machine_learning/has_ml_user_permissions'; -import { useSiemJobs } from '../../ml_popover/hooks/use_siem_jobs'; -import { useMlCapabilities } from '../../ml_popover/hooks/use_ml_capabilities'; -import { useStateToaster, errorToToaster } from '../../toasters'; import * as i18n from './translations'; import { useTimeZone, useUiSetting$ } from '../../../lib/kibana'; +import { useAppToasts } from '../../../hooks/use_app_toasts'; +import { useInstalledSecurityJobs } from '../hooks/use_installed_security_jobs'; interface Args { influencers?: InfluencerInput[]; @@ -58,15 +56,13 @@ export const useAnomaliesTableData = ({ skip = false, }: Args): Return => { const [tableData, setTableData] = useState(null); - const [, siemJobs] = useSiemJobs(true); + const { isMlUser, jobs } = useInstalledSecurityJobs(); const [loading, setLoading] = useState(true); - const capabilities = useMlCapabilities(); - const userPermissions = hasMlUserPermissions(capabilities); - const [, dispatchToaster] = useStateToaster(); + const { addError } = useAppToasts(); const timeZone = useTimeZone(); const [anomalyScore] = useUiSetting$(DEFAULT_ANOMALY_SCORE); - const siemJobIds = siemJobs.filter((job) => job.isInstalled).map((job) => job.id); + const jobIds = jobs.map((job) => job.id); const startDateMs = useMemo(() => new Date(startDate).getTime(), [startDate]); const endDateMs = useMemo(() => new Date(endDate).getTime(), [endDate]); @@ -81,11 +77,11 @@ export const useAnomaliesTableData = ({ earliestMs: number, latestMs: number ) { - if (userPermissions && !skip && siemJobIds.length > 0) { + if (isMlUser && !skip && jobIds.length > 0) { try { const data = await anomaliesTableData( { - jobIds: siemJobIds, + jobIds, criteriaFields: criteriaFieldsInput, aggregationInterval: 'auto', threshold: getThreshold(anomalyScore, threshold), @@ -104,13 +100,13 @@ export const useAnomaliesTableData = ({ } } catch (error) { if (isSubscribed) { - errorToToaster({ title: i18n.SIEM_TABLE_FETCH_FAILURE, error, dispatchToaster }); + addError(error, { title: i18n.SIEM_TABLE_FETCH_FAILURE }); setLoading(false); } } - } else if (!userPermissions && isSubscribed) { + } else if (!isMlUser && isSubscribed) { setLoading(false); - } else if (siemJobIds.length === 0 && isSubscribed) { + } else if (jobIds.length === 0 && isSubscribed) { setLoading(false); } else if (isSubscribed) { setTableData(null); @@ -132,9 +128,9 @@ export const useAnomaliesTableData = ({ startDateMs, endDateMs, skip, - userPermissions, + isMlUser, // eslint-disable-next-line react-hooks/exhaustive-deps - siemJobIds.sort().join(), + jobIds.sort().join(), ]); return [loading, tableData]; diff --git a/x-pack/plugins/security_solution/public/common/components/ml/api/get_jobs_summary.ts b/x-pack/plugins/security_solution/public/common/components/ml/api/get_jobs_summary.ts new file mode 100644 index 0000000000000..15f823814d7fc --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/ml/api/get_jobs_summary.ts @@ -0,0 +1,35 @@ +/* + * 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 { HttpSetup } from '../../../../../../../../src/core/public'; +import { MlSummaryJob } from '../../../../../../ml/public'; + +export interface GetJobsSummaryArgs { + http: HttpSetup; + jobIds?: string[]; + signal: AbortSignal; +} + +/** + * Fetches a summary of all ML jobs currently installed + * + * @param http HTTP Service + * @param jobIds Array of job IDs to filter against + * @param signal to cancel request + * + * @throws An error if response is not OK + */ +export const getJobsSummary = async ({ + http, + jobIds, + signal, +}: GetJobsSummaryArgs): Promise => + http.fetch('/api/ml/jobs/jobs_summary', { + method: 'POST', + body: JSON.stringify({ jobIds: jobIds ?? [] }), + asSystemRequest: true, + signal, + }); diff --git a/x-pack/plugins/security_solution/public/common/components/ml/api/get_ml_capabilities.ts b/x-pack/plugins/security_solution/public/common/components/ml/api/get_ml_capabilities.ts index 32f6f888ab8d7..8ee765c1dea47 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml/api/get_ml_capabilities.ts +++ b/x-pack/plugins/security_solution/public/common/components/ml/api/get_ml_capabilities.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ +import { HttpSetup } from '../../../../../../../../src/core/public'; import { MlCapabilitiesResponse } from '../../../../../../ml/public'; -import { KibanaServices } from '../../../lib/kibana'; import { InfluencerInput } from '../types'; export interface Body { @@ -21,10 +21,15 @@ export interface Body { maxExamples: number; } -export const getMlCapabilities = async (signal: AbortSignal): Promise => { - return KibanaServices.get().http.fetch('/api/ml/ml_capabilities', { +export const getMlCapabilities = async ({ + http, + signal, +}: { + http: HttpSetup; + signal: AbortSignal; +}): Promise => + http.fetch('/api/ml/ml_capabilities', { method: 'GET', asSystemRequest: true, signal, }); -}; diff --git a/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_get_jobs_summary.ts b/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_get_jobs_summary.ts new file mode 100644 index 0000000000000..a80bfb59649cb --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_get_jobs_summary.ts @@ -0,0 +1,12 @@ +/* + * 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 { useAsync, withOptionalSignal } from '../../../../shared_imports'; +import { getJobsSummary } from '../api/get_jobs_summary'; + +const _getJobsSummary = withOptionalSignal(getJobsSummary); + +export const useGetJobsSummary = () => useAsync(_getJobsSummary); diff --git a/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_get_ml_capabilities.ts b/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_get_ml_capabilities.ts new file mode 100644 index 0000000000000..aabd8c7b62e85 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_get_ml_capabilities.ts @@ -0,0 +1,12 @@ +/* + * 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 { getMlCapabilities } from '../api/get_ml_capabilities'; +import { useAsync, withOptionalSignal } from '../../../../shared_imports'; + +const _getMlCapabilities = withOptionalSignal(getMlCapabilities); + +export const useGetMlCapabilities = () => useAsync(_getMlCapabilities); diff --git a/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_installed_security_jobs.test.ts b/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_installed_security_jobs.test.ts new file mode 100644 index 0000000000000..72690a1773926 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_installed_security_jobs.test.ts @@ -0,0 +1,99 @@ +/* + * 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 { renderHook } from '@testing-library/react-hooks'; + +import { hasMlUserPermissions } from '../../../../../common/machine_learning/has_ml_user_permissions'; +import { hasMlLicense } from '../../../../../common/machine_learning/has_ml_license'; +import { isSecurityJob } from '../../../../../common/machine_learning/is_security_job'; +import { useAppToasts } from '../../../hooks/use_app_toasts'; +import { useAppToastsMock } from '../../../hooks/use_app_toasts.mock'; +import { mockJobsSummaryResponse } from '../../ml_popover/api.mock'; +import { getJobsSummary } from '../api/get_jobs_summary'; +import { useInstalledSecurityJobs } from './use_installed_security_jobs'; + +jest.mock('../../../../../common/machine_learning/has_ml_user_permissions'); +jest.mock('../../../../../common/machine_learning/has_ml_license'); +jest.mock('../../../hooks/use_app_toasts'); +jest.mock('../api/get_jobs_summary'); + +describe('useInstalledSecurityJobs', () => { + let appToastsMock: jest.Mocked>; + + beforeEach(() => { + appToastsMock = useAppToastsMock.create(); + (useAppToasts as jest.Mock).mockReturnValue(appToastsMock); + (getJobsSummary as jest.Mock).mockResolvedValue(mockJobsSummaryResponse); + }); + + describe('when the user has permissions', () => { + beforeEach(() => { + (hasMlUserPermissions as jest.Mock).mockReturnValue(true); + (hasMlLicense as jest.Mock).mockReturnValue(true); + }); + + it('returns jobs and permissions', async () => { + const { result, waitForNextUpdate } = renderHook(() => useInstalledSecurityJobs()); + await waitForNextUpdate(); + + expect(result.current.jobs).toHaveLength(3); + expect(result.current.jobs).toEqual( + expect.arrayContaining([ + { + datafeedId: 'datafeed-siem-api-rare_process_linux_ecs', + datafeedIndices: ['auditbeat-*'], + datafeedState: 'stopped', + description: 'SIEM Auditbeat: Detect unusually rare processes on Linux (beta)', + earliestTimestampMs: 1557353420495, + groups: ['siem'], + hasDatafeed: true, + id: 'siem-api-rare_process_linux_ecs', + isSingleMetricViewerJob: true, + jobState: 'closed', + latestTimestampMs: 1557434782207, + memory_status: 'hard_limit', + processed_record_count: 582251, + }, + ]) + ); + expect(result.current.isMlUser).toEqual(true); + expect(result.current.isLicensed).toEqual(true); + }); + + it('filters out non-security jobs', async () => { + const { result, waitForNextUpdate } = renderHook(() => useInstalledSecurityJobs()); + await waitForNextUpdate(); + + expect(result.current.jobs.length).toBeGreaterThan(0); + expect(result.current.jobs.every(isSecurityJob)).toEqual(true); + }); + + it('renders a toast error if the ML call fails', async () => { + (getJobsSummary as jest.Mock).mockRejectedValue('whoops'); + const { waitForNextUpdate } = renderHook(() => useInstalledSecurityJobs()); + await waitForNextUpdate(); + + expect(appToastsMock.addError).toHaveBeenCalledWith('whoops', { + title: 'Security job fetch failure', + }); + }); + }); + + describe('when the user does not have valid permissions', () => { + beforeEach(() => { + (hasMlUserPermissions as jest.Mock).mockReturnValue(false); + (hasMlLicense as jest.Mock).mockReturnValue(false); + }); + + it('returns empty jobs and false predicates', () => { + const { result } = renderHook(() => useInstalledSecurityJobs()); + + expect(result.current.jobs).toEqual([]); + expect(result.current.isMlUser).toEqual(false); + expect(result.current.isLicensed).toEqual(false); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_installed_security_jobs.ts b/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_installed_security_jobs.ts new file mode 100644 index 0000000000000..a9a728f81cc6c --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_installed_security_jobs.ts @@ -0,0 +1,63 @@ +/* + * 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 { useEffect, useState } from 'react'; + +import { MlSummaryJob } from '../../../../../../ml/public'; +import { hasMlUserPermissions } from '../../../../../common/machine_learning/has_ml_user_permissions'; +import { hasMlLicense } from '../../../../../common/machine_learning/has_ml_license'; +import { isSecurityJob } from '../../../../../common/machine_learning/is_security_job'; +import { useAppToasts } from '../../../hooks/use_app_toasts'; +import { useHttp } from '../../../lib/kibana'; +import { useMlCapabilities } from './use_ml_capabilities'; +import * as i18n from '../translations'; +import { useGetJobsSummary } from './use_get_jobs_summary'; + +export interface UseInstalledSecurityJobsReturn { + loading: boolean; + jobs: MlSummaryJob[]; + isMlUser: boolean; + isLicensed: boolean; +} + +/** + * Returns a collection of installed ML jobs (MlSummaryJob) relevant to + * Security Solution, i.e. all installed jobs in the `security` ML group. + * Use the corresponding helper functions to filter the job list as + * necessary (running jobs, etc). + * + */ +export const useInstalledSecurityJobs = (): UseInstalledSecurityJobsReturn => { + const [jobs, setJobs] = useState([]); + const { addError } = useAppToasts(); + const mlCapabilities = useMlCapabilities(); + const http = useHttp(); + const { error, loading, result, start } = useGetJobsSummary(); + + const isMlUser = hasMlUserPermissions(mlCapabilities); + const isLicensed = hasMlLicense(mlCapabilities); + + useEffect(() => { + if (isMlUser && isLicensed) { + start({ http }); + } + }, [http, isMlUser, isLicensed, start]); + + useEffect(() => { + if (result) { + const securityJobs = result.filter(isSecurityJob); + setJobs(securityJobs); + } + }, [result]); + + useEffect(() => { + if (error) { + addError(error, { title: i18n.SIEM_JOB_FETCH_FAILURE }); + } + }, [addError, error]); + + return { isLicensed, isMlUser, jobs, loading }; +}; diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_ml_capabilities.tsx b/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_ml_capabilities.ts similarity index 80% rename from x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_ml_capabilities.tsx rename to x-pack/plugins/security_solution/public/common/components/ml/hooks/use_ml_capabilities.ts index d897b2554b4fd..4f804a355e4b5 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_ml_capabilities.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml/hooks/use_ml_capabilities.ts @@ -6,6 +6,6 @@ import { useContext } from 'react'; -import { MlCapabilitiesContext } from '../../ml/permissions/ml_capabilities_provider'; +import { MlCapabilitiesContext } from '../permissions/ml_capabilities_provider'; export const useMlCapabilities = () => useContext(MlCapabilitiesContext); diff --git a/x-pack/plugins/security_solution/public/common/components/ml/permissions/ml_capabilities_provider.tsx b/x-pack/plugins/security_solution/public/common/components/ml/permissions/ml_capabilities_provider.tsx index c83271a56be5a..c12c8d78da714 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml/permissions/ml_capabilities_provider.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml/permissions/ml_capabilities_provider.tsx @@ -8,9 +8,9 @@ import React, { useState, useEffect } from 'react'; import { MlCapabilitiesResponse } from '../../../../../../ml/public'; import { emptyMlCapabilities } from '../../../../../common/machine_learning/empty_ml_capabilities'; -import { getMlCapabilities } from '../api/get_ml_capabilities'; -import { errorToToaster, useStateToaster } from '../../toasters'; - +import { useAppToasts } from '../../../hooks/use_app_toasts'; +import { useHttp } from '../../../lib/kibana'; +import { useGetMlCapabilities } from '../hooks/use_get_ml_capabilities'; import * as i18n from './translations'; interface MlCapabilitiesProvider extends MlCapabilitiesResponse { @@ -32,36 +32,27 @@ export const MlCapabilitiesProvider = React.memo<{ children: JSX.Element }>(({ c const [capabilities, setCapabilities] = useState( emptyMlCapabilitiesProvider ); - const [, dispatchToaster] = useStateToaster(); + const http = useHttp(); + const { addError } = useAppToasts(); + const { start, result, error } = useGetMlCapabilities(); useEffect(() => { - let isSubscribed = true; - const abortCtrl = new AbortController(); + start({ http }); + }, [http, start]); - async function fetchMlCapabilities() { - try { - const mlCapabilities = await getMlCapabilities(abortCtrl.signal); - if (isSubscribed) { - setCapabilities({ ...mlCapabilities, capabilitiesFetched: true }); - } - } catch (error) { - if (isSubscribed) { - errorToToaster({ - title: i18n.MACHINE_LEARNING_PERMISSIONS_FAILURE, - error, - dispatchToaster, - }); - } - } + useEffect(() => { + if (result) { + setCapabilities({ ...result, capabilitiesFetched: true }); } + }, [result]); - fetchMlCapabilities(); - return () => { - isSubscribed = false; - abortCtrl.abort(); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + useEffect(() => { + if (error) { + addError(error, { + title: i18n.MACHINE_LEARNING_PERMISSIONS_FAILURE, + }); + } + }, [addError, error]); return ( {children} diff --git a/x-pack/plugins/security_solution/public/common/components/ml/tables/anomalies_host_table.tsx b/x-pack/plugins/security_solution/public/common/components/ml/tables/anomalies_host_table.tsx index 9bfae686b1a59..7fdf41e6b6500 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml/tables/anomalies_host_table.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml/tables/anomalies_host_table.tsx @@ -16,7 +16,7 @@ import { convertAnomaliesToHosts } from './convert_anomalies_to_hosts'; import { Loader } from '../../loader'; import { getIntervalFromAnomalies } from '../anomaly/get_interval_from_anomalies'; import { AnomaliesHostTableProps } from '../types'; -import { useMlCapabilities } from '../../ml_popover/hooks/use_ml_capabilities'; +import { useMlCapabilities } from '../hooks/use_ml_capabilities'; import { BasicTable } from './basic_table'; import { hostEquality } from './host_equality'; import { getCriteriaFromHostType } from '../criteria/get_criteria_from_host_type'; diff --git a/x-pack/plugins/security_solution/public/common/components/ml/tables/anomalies_network_table.tsx b/x-pack/plugins/security_solution/public/common/components/ml/tables/anomalies_network_table.tsx index af27d411b990d..124d8d9a794c1 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml/tables/anomalies_network_table.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml/tables/anomalies_network_table.tsx @@ -14,7 +14,7 @@ import { convertAnomaliesToNetwork } from './convert_anomalies_to_network'; import { Loader } from '../../loader'; import { AnomaliesNetworkTableProps } from '../types'; import { getAnomaliesNetworkTableColumnsCurated } from './get_anomalies_network_table_columns'; -import { useMlCapabilities } from '../../ml_popover/hooks/use_ml_capabilities'; +import { useMlCapabilities } from '../hooks/use_ml_capabilities'; import { BasicTable } from './basic_table'; import { networkEquality } from './network_equality'; import { getCriteriaFromNetworkType } from '../criteria/get_criteria_from_network_type'; diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/translations.ts b/x-pack/plugins/security_solution/public/common/components/ml/translations.ts similarity index 100% rename from x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/translations.ts rename to x-pack/plugins/security_solution/public/common/components/ml/translations.ts diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/__mocks__/api.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/api.mock.ts similarity index 99% rename from x-pack/plugins/security_solution/public/common/components/ml_popover/__mocks__/api.tsx rename to x-pack/plugins/security_solution/public/common/components/ml_popover/api.mock.ts index 54bb0a96207e1..0e8f033ff0cf3 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/__mocks__/api.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/api.mock.ts @@ -4,16 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ +import { MlSummaryJob } from '../../../../../ml/public'; import { Group, - JobSummary, Module, RecognizerModule, SetupMlResponse, - SiemJob, + SecurityJob, StartDatafeedResponse, StopDatafeedResponse, -} from '../types'; +} from './types'; export const mockGroupsResponse: Group[] = [ { @@ -31,7 +31,7 @@ export const mockGroupsResponse: Group[] = [ { id: 'suricata', jobIds: ['suricata_alert_rate'], calendarIds: [] }, ]; -export const mockOpenedJob: JobSummary = { +export const mockOpenedJob: MlSummaryJob = { datafeedId: 'datafeed-siem-api-rare_process_linux_ecs', datafeedIndices: ['auditbeat-*'], datafeedState: 'started', @@ -48,7 +48,7 @@ export const mockOpenedJob: JobSummary = { processed_record_count: 3425264, }; -export const mockJobsSummaryResponse: JobSummary[] = [ +export const mockJobsSummaryResponse: MlSummaryJob[] = [ { id: 'rc-rare-process-windows-5', description: @@ -491,7 +491,7 @@ export const mockStopDatafeedsSuccess: StopDatafeedResponse = { 'datafeed-linux_anomalous_network_service': { stopped: true }, }; -export const mockSiemJobs: SiemJob[] = [ +export const mockSecurityJobs: SecurityJob[] = [ { id: 'linux_anomalous_network_activity_ecs', description: diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/api.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/api.ts similarity index 89% rename from x-pack/plugins/security_solution/public/common/components/ml_popover/api.tsx rename to x-pack/plugins/security_solution/public/common/components/ml_popover/api.ts index 7c72098209a06..dd0fb33fd2bc6 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/api.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/api.ts @@ -9,7 +9,6 @@ import { CloseJobsResponse, ErrorResponse, GetModulesProps, - JobSummary, MlSetupArgs, Module, RecognizerModule, @@ -165,21 +164,3 @@ export const stopDatafeeds = async ({ return [stopDatafeedsResponse, closeJobsResponse]; }; - -/** - * Fetches a summary of all ML jobs currently installed - * - * NOTE: If not sending jobIds in the body, you must at least send an empty body or the server will - * return a 500 - * - * @param signal to cancel request - * - * @throws An error if response is not OK - */ -export const getJobsSummary = async (signal: AbortSignal): Promise => - KibanaServices.get().http.fetch('/api/ml/jobs/jobs_summary', { - method: 'POST', - body: JSON.stringify({}), - asSystemRequest: true, - signal, - }); diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/helpers.test.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/helpers.test.tsx index 0b8da6be57e1b..2a2db46d42307 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/helpers.test.tsx @@ -4,14 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { mockSiemJobs } from './__mocks__/api'; +import { mockSecurityJobs } from './api.mock'; import { filterJobs, getStablePatternTitles, searchFilter } from './helpers'; describe('helpers', () => { describe('filterJobs', () => { test('returns all jobs when no filter is suplied', () => { const filteredJobs = filterJobs({ - jobs: mockSiemJobs, + jobs: mockSecurityJobs, selectedGroups: [], showCustomJobs: false, showElasticJobs: false, @@ -23,17 +23,17 @@ describe('helpers', () => { describe('searchFilter', () => { test('returns all jobs when nullfilterQuery is provided', () => { - const jobsToDisplay = searchFilter(mockSiemJobs); - expect(jobsToDisplay.length).toEqual(mockSiemJobs.length); + const jobsToDisplay = searchFilter(mockSecurityJobs); + expect(jobsToDisplay.length).toEqual(mockSecurityJobs.length); }); test('returns correct DisplayJobs when filterQuery matches job.id', () => { - const jobsToDisplay = searchFilter(mockSiemJobs, 'rare_process'); + const jobsToDisplay = searchFilter(mockSecurityJobs, 'rare_process'); expect(jobsToDisplay.length).toEqual(2); }); test('returns correct DisplayJobs when filterQuery matches job.description', () => { - const jobsToDisplay = searchFilter(mockSiemJobs, 'Detect unusually'); + const jobsToDisplay = searchFilter(mockSecurityJobs, 'Detect unusually'); expect(jobsToDisplay.length).toEqual(2); }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/helpers.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/helpers.tsx index 5989d052f7cd2..daf9da855c0f9 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/helpers.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/helpers.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SiemJob } from './types'; +import { SecurityJob } from './types'; /** * Returns a filtered array of Jobs according to JobsTableFilters selections @@ -22,12 +22,12 @@ export const filterJobs = ({ showElasticJobs, filterQuery, }: { - jobs: SiemJob[]; + jobs: SecurityJob[]; selectedGroups: string[]; showCustomJobs: boolean; showElasticJobs: boolean; filterQuery: string; -}): SiemJob[] => +}): SecurityJob[] => searchFilter( jobs .filter((job) => !showCustomJobs || (showCustomJobs && !job.isElasticJob)) @@ -44,7 +44,7 @@ export const filterJobs = ({ * @param jobs to filter * @param filterQuery user-provided search string to filter for occurrence in job names/description */ -export const searchFilter = (jobs: SiemJob[], filterQuery?: string): SiemJob[] => +export const searchFilter = (jobs: SecurityJob[], filterQuery?: string): SecurityJob[] => jobs.filter((job) => filterQuery == null ? true diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.test.ts b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.test.ts new file mode 100644 index 0000000000000..80f50912a84f2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.test.ts @@ -0,0 +1,110 @@ +/* + * 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 { renderHook } from '@testing-library/react-hooks'; + +import { hasMlAdminPermissions } from '../../../../../common/machine_learning/has_ml_admin_permissions'; +import { hasMlLicense } from '../../../../../common/machine_learning/has_ml_license'; +import { useAppToasts } from '../../../hooks/use_app_toasts'; +import { useAppToastsMock } from '../../../hooks/use_app_toasts.mock'; +import { getJobsSummary } from '../../ml/api/get_jobs_summary'; +import { checkRecognizer, getModules } from '../api'; +import { SecurityJob } from '../types'; +import { + mockJobsSummaryResponse, + mockGetModuleResponse, + checkRecognizerSuccess, +} from '../api.mock'; +import { useSecurityJobs } from './use_security_jobs'; + +jest.mock('../../../../../common/machine_learning/has_ml_admin_permissions'); +jest.mock('../../../../../common/machine_learning/has_ml_license'); +jest.mock('../../../lib/kibana'); +jest.mock('../../../hooks/use_app_toasts'); +jest.mock('../../ml/hooks/use_ml_capabilities'); +jest.mock('../../ml/api/get_jobs_summary'); +jest.mock('../api'); + +describe('useSecurityJobs', () => { + let appToastsMock: jest.Mocked>; + + beforeEach(() => { + appToastsMock = useAppToastsMock.create(); + (useAppToasts as jest.Mock).mockReturnValue(appToastsMock); + }); + + describe('when user has valid permissions', () => { + beforeEach(() => { + (hasMlAdminPermissions as jest.Mock).mockReturnValue(true); + (hasMlLicense as jest.Mock).mockReturnValue(true); + (getJobsSummary as jest.Mock).mockResolvedValue(mockJobsSummaryResponse); + (getModules as jest.Mock).mockResolvedValue(mockGetModuleResponse); + (checkRecognizer as jest.Mock).mockResolvedValue(checkRecognizerSuccess); + }); + + it('combines multiple ML calls into an array of SecurityJobs', async () => { + const expectedSecurityJob: SecurityJob = { + datafeedId: 'datafeed-siem-api-rare_process_linux_ecs', + datafeedIndices: ['auditbeat-*'], + datafeedState: 'stopped', + defaultIndexPattern: '', + description: 'SIEM Auditbeat: Detect unusually rare processes on Linux (beta)', + earliestTimestampMs: 1557353420495, + groups: ['siem'], + hasDatafeed: true, + id: 'siem-api-rare_process_linux_ecs', + isCompatible: true, + isElasticJob: false, + isInstalled: true, + isSingleMetricViewerJob: true, + jobState: 'closed', + latestTimestampMs: 1557434782207, + memory_status: 'hard_limit', + moduleId: '', + processed_record_count: 582251, + }; + + const { result, waitForNextUpdate } = renderHook(() => useSecurityJobs(false)); + await waitForNextUpdate(); + + expect(result.current.jobs).toHaveLength(6); + expect(result.current.jobs).toEqual(expect.arrayContaining([expectedSecurityJob])); + }); + + it('returns those permissions', async () => { + const { result, waitForNextUpdate } = renderHook(() => useSecurityJobs(false)); + await waitForNextUpdate(); + + expect(result.current.isMlAdmin).toEqual(true); + expect(result.current.isLicensed).toEqual(true); + }); + + it('renders a toast error if an ML call fails', async () => { + (getModules as jest.Mock).mockRejectedValue('whoops'); + const { waitForNextUpdate } = renderHook(() => useSecurityJobs(false)); + await waitForNextUpdate(); + + expect(appToastsMock.addError).toHaveBeenCalledWith('whoops', { + title: 'Security job fetch failure', + }); + }); + }); + + describe('when the user does not have valid permissions', () => { + beforeEach(() => { + (hasMlAdminPermissions as jest.Mock).mockReturnValue(false); + (hasMlLicense as jest.Mock).mockReturnValue(false); + }); + + it('returns empty jobs and false predicates', () => { + const { result } = renderHook(() => useSecurityJobs(false)); + + expect(result.current.jobs).toEqual([]); + expect(result.current.isMlAdmin).toEqual(false); + expect(result.current.isLicensed).toEqual(false); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.ts b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.ts new file mode 100644 index 0000000000000..e8809e8366eed --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.ts @@ -0,0 +1,95 @@ +/* + * 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 { useEffect, useState } from 'react'; + +import { DEFAULT_INDEX_KEY } from '../../../../../common/constants'; +import { hasMlAdminPermissions } from '../../../../../common/machine_learning/has_ml_admin_permissions'; +import { hasMlLicense } from '../../../../../common/machine_learning/has_ml_license'; +import { useAppToasts } from '../../../hooks/use_app_toasts'; +import { useUiSetting$, useHttp } from '../../../lib/kibana'; +import { checkRecognizer, getModules } from '../api'; +import { SecurityJob } from '../types'; +import { createSecurityJobs } from './use_security_jobs_helpers'; +import { useMlCapabilities } from '../../ml/hooks/use_ml_capabilities'; +import * as i18n from '../../ml/translations'; +import { getJobsSummary } from '../../ml/api/get_jobs_summary'; + +export interface UseSecurityJobsReturn { + loading: boolean; + jobs: SecurityJob[]; + isMlAdmin: boolean; + isLicensed: boolean; +} + +/** + * Compiles a collection of SecurityJobs, which are a list of all jobs relevant to the Security Solution App. This + * includes all installed jobs in the `Security` ML group, and all jobs within ML Modules defined in + * ml_module (whether installed or not). Use the corresponding helper functions to filter the job + * list as necessary. E.g. installed jobs, running jobs, etc. + * + * NOTE: If the user is not an ml admin, jobs will be empty and isMlAdmin will be false. + * + * @param refetchData + */ +export const useSecurityJobs = (refetchData: boolean): UseSecurityJobsReturn => { + const [jobs, setJobs] = useState([]); + const [loading, setLoading] = useState(true); + const mlCapabilities = useMlCapabilities(); + const [siemDefaultIndex] = useUiSetting$(DEFAULT_INDEX_KEY); + const http = useHttp(); + const { addError } = useAppToasts(); + + const isMlAdmin = hasMlAdminPermissions(mlCapabilities); + const isLicensed = hasMlLicense(mlCapabilities); + + useEffect(() => { + let isSubscribed = true; + const abortCtrl = new AbortController(); + setLoading(true); + + async function fetchSecurityJobIdsFromGroupsData() { + if (isMlAdmin && isLicensed) { + try { + // Batch fetch all installed jobs, ML modules, and check which modules are compatible with siemDefaultIndex + const [jobSummaryData, modulesData, compatibleModules] = await Promise.all([ + getJobsSummary({ http, signal: abortCtrl.signal }), + getModules({ signal: abortCtrl.signal }), + checkRecognizer({ + indexPatternName: siemDefaultIndex, + signal: abortCtrl.signal, + }), + ]); + + const compositeSecurityJobs = createSecurityJobs( + jobSummaryData, + modulesData, + compatibleModules + ); + + if (isSubscribed) { + setJobs(compositeSecurityJobs); + } + } catch (error) { + if (isSubscribed) { + addError(error, { title: i18n.SIEM_JOB_FETCH_FAILURE }); + } + } + } + if (isSubscribed) { + setLoading(false); + } + } + + fetchSecurityJobIdsFromGroupsData(); + return () => { + isSubscribed = false; + abortCtrl.abort(); + }; + }, [refetchData, isMlAdmin, isLicensed, siemDefaultIndex, addError, http]); + + return { isLicensed, isMlAdmin, jobs, loading }; +}; diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_siem_jobs_helpers.test.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs_helpers.test.tsx similarity index 83% rename from x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_siem_jobs_helpers.test.tsx rename to x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs_helpers.test.tsx index fc9f369a305aa..7fb4e6f59d9f7 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_siem_jobs_helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs_helpers.test.tsx @@ -6,29 +6,29 @@ import { composeModuleAndInstalledJobs, - createSiemJobs, + createSecurityJobs, getAugmentedFields, getInstalledJobs, getModuleJobs, - moduleToSiemJob, -} from './use_siem_jobs_helpers'; + moduleToSecurityJob, +} from './use_security_jobs_helpers'; import { checkRecognizerSuccess, mockGetModuleResponse, mockJobsSummaryResponse, -} from '../__mocks__/api'; +} from '../api.mock'; // TODO: Expand test coverage -describe('useSiemJobsHelpers', () => { - describe('moduleToSiemJob', () => { - test('correctly converts module to SiemJob', () => { - const siemJob = moduleToSiemJob( +describe('useSecurityJobsHelpers', () => { + describe('moduleToSecurityJob', () => { + test('correctly converts module to SecurityJob', () => { + const securityJob = moduleToSecurityJob( mockGetModuleResponse[0], mockGetModuleResponse[0].jobs[0], false ); - expect(siemJob).toEqual({ + expect(securityJob).toEqual({ datafeedId: '', datafeedIndices: [], datafeedState: '', @@ -86,19 +86,19 @@ describe('useSiemJobsHelpers', () => { const installedJobs = getInstalledJobs(mockJobsSummaryResponse, moduleJobs, [ 'siem_auditbeat', ]); - const siemJobs = composeModuleAndInstalledJobs(installedJobs, moduleJobs); - expect(siemJobs.length).toEqual(6); + const securityJobs = composeModuleAndInstalledJobs(installedJobs, moduleJobs); + expect(securityJobs.length).toEqual(6); }); }); - describe('createSiemJobs', () => { + describe('createSecurityJobs', () => { test('returns correct number of jobs when creating jobs with successful responses', () => { - const siemJobs = createSiemJobs( + const securityJobs = createSecurityJobs( mockJobsSummaryResponse, mockGetModuleResponse, checkRecognizerSuccess ); - expect(siemJobs.length).toEqual(6); + expect(securityJobs.length).toEqual(6); }); }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_siem_jobs_helpers.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs_helpers.tsx similarity index 59% rename from x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_siem_jobs_helpers.tsx rename to x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs_helpers.tsx index adbd712ffeb3e..d0109fd29b5fb 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_siem_jobs_helpers.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs_helpers.tsx @@ -5,26 +5,26 @@ */ import { - AugmentedSiemJobFields, - JobSummary, + AugmentedSecurityJobFields, Module, ModuleJob, RecognizerModule, - SiemJob, + SecurityJob, } from '../types'; import { mlModules } from '../ml_modules'; +import { MlSummaryJob } from '../../../../../../ml/public'; /** - * Helper function for converting from ModuleJob -> SiemJob + * Helper function for converting from ModuleJob -> SecurityJob * @param module * @param moduleJob * @param isCompatible */ -export const moduleToSiemJob = ( +export const moduleToSecurityJob = ( module: Module, moduleJob: ModuleJob, isCompatible: boolean -): SiemJob => { +): SecurityJob => { return { datafeedId: '', datafeedIndices: [], @@ -46,7 +46,7 @@ export const moduleToSiemJob = ( }; /** - * Returns fields necessary to augment a ModuleJob to a SiemJob + * Returns fields necessary to augment a ModuleJob to a SecurityJob * * @param jobId * @param moduleJobs @@ -54,9 +54,9 @@ export const moduleToSiemJob = ( */ export const getAugmentedFields = ( jobId: string, - moduleJobs: SiemJob[], + moduleJobs: SecurityJob[], compatibleModuleIds: string[] -): AugmentedSiemJobFields => { +): AugmentedSecurityJobFields => { const moduleJob = moduleJobs.find((mj) => mj.id === jobId); return moduleJob !== undefined ? { @@ -74,24 +74,27 @@ export const getAugmentedFields = ( }; /** - * Process Modules[] from the `get_module` ML API into SiemJobs[] by filtering to SIEM specific + * Process Modules[] from the `get_module` ML API into SecurityJobs[] by filtering to Security specific * modules and unpacking jobs from each module * * @param modulesData * @param compatibleModuleIds */ -export const getModuleJobs = (modulesData: Module[], compatibleModuleIds: string[]): SiemJob[] => +export const getModuleJobs = ( + modulesData: Module[], + compatibleModuleIds: string[] +): SecurityJob[] => modulesData .filter((module) => mlModules.includes(module.id)) .map((module) => [ ...module.jobs.map((moduleJob) => - moduleToSiemJob(module, moduleJob, compatibleModuleIds.includes(module.id)) + moduleToSecurityJob(module, moduleJob, compatibleModuleIds.includes(module.id)) ), ]) .flat(); /** - * Process JobSummary[] from the `jobs_summary` ML API into SiemJobs[] by filtering to to SIEM jobs + * Process data from the `jobs_summary` ML API into SecurityJobs[] by filtering to Security jobs * and augmenting with moduleId/defaultIndexPattern/isCompatible * * @param jobSummaryData @@ -99,57 +102,57 @@ export const getModuleJobs = (modulesData: Module[], compatibleModuleIds: string * @param compatibleModuleIds */ export const getInstalledJobs = ( - jobSummaryData: JobSummary[], - moduleJobs: SiemJob[], + jobSummaryData: MlSummaryJob[], + moduleJobs: SecurityJob[], compatibleModuleIds: string[] -): SiemJob[] => +): SecurityJob[] => jobSummaryData .filter(({ groups }) => groups.includes('siem') || groups.includes('security')) - .map((jobSummary) => ({ + .map((jobSummary) => ({ ...jobSummary, ...getAugmentedFields(jobSummary.id, moduleJobs, compatibleModuleIds), isInstalled: true, })); /** - * Combines installed jobs + moduleSiemJobs that don't overlap and sorts by name asc + * Combines installed jobs + moduleSecurityJobs that don't overlap and sorts by name asc * * @param installedJobs - * @param moduleSiemJobs + * @param moduleSecurityJobs */ export const composeModuleAndInstalledJobs = ( - installedJobs: SiemJob[], - moduleSiemJobs: SiemJob[] -): SiemJob[] => { + installedJobs: SecurityJob[], + moduleSecurityJobs: SecurityJob[] +): SecurityJob[] => { const installedJobsIds = installedJobs.map((installedJob) => installedJob.id); return [ ...installedJobs, - ...moduleSiemJobs.filter((mj) => !installedJobsIds.includes(mj.id)), + ...moduleSecurityJobs.filter((mj) => !installedJobsIds.includes(mj.id)), ].sort((a, b) => a.id.localeCompare(b.id)); }; /** - * Creates a list of SiemJobs by composing JobSummary jobs (installed jobs) and Module - * jobs (pre-packaged SIEM jobs) into a single job object that can be used throughout the SIEM app + * Creates a list of SecurityJobs by composing jobs summaries (installed jobs) and Module + * jobs (pre-packaged Security jobs) into a single job object that can be used throughout the Security app * * @param jobSummaryData * @param modulesData * @param compatibleModules */ -export const createSiemJobs = ( - jobSummaryData: JobSummary[], +export const createSecurityJobs = ( + jobSummaryData: MlSummaryJob[], modulesData: Module[], compatibleModules: RecognizerModule[] -): SiemJob[] => { +): SecurityJob[] => { // Create lookup of compatible modules const compatibleModuleIds = compatibleModules.map((module) => module.id); - // Process modulesData: Filter to SIEM specific modules, and unpack jobs from modules - const moduleSiemJobs = getModuleJobs(modulesData, compatibleModuleIds); + // Process modulesData: Filter to Security specific modules, and unpack jobs from modules + const moduleSecurityJobs = getModuleJobs(modulesData, compatibleModuleIds); - // Process jobSummaryData: Filter to SIEM jobs, and augment with moduleId/defaultIndexPattern/isCompatible - const installedJobs = getInstalledJobs(jobSummaryData, moduleSiemJobs, compatibleModuleIds); + // Process jobSummaryData: Filter to Security jobs, and augment with moduleId/defaultIndexPattern/isCompatible + const installedJobs = getInstalledJobs(jobSummaryData, moduleSecurityJobs, compatibleModuleIds); - // Combine installed jobs + moduleSiemJobs that don't overlap, and sort by name asc - return composeModuleAndInstalledJobs(installedJobs, moduleSiemJobs); + // Combine installed jobs + moduleSecurityJobs that don't overlap, and sort by name asc + return composeModuleAndInstalledJobs(installedJobs, moduleSecurityJobs); }; diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_siem_jobs.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_siem_jobs.tsx deleted file mode 100644 index 7f0a8dea1913e..0000000000000 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_siem_jobs.tsx +++ /dev/null @@ -1,81 +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 { useEffect, useState } from 'react'; - -import { DEFAULT_INDEX_KEY } from '../../../../../common/constants'; -import { checkRecognizer, getJobsSummary, getModules } from '../api'; -import { SiemJob } from '../types'; -import { hasMlUserPermissions } from '../../../../../common/machine_learning/has_ml_user_permissions'; -import { errorToToaster, useStateToaster } from '../../toasters'; -import { useUiSetting$ } from '../../../lib/kibana'; - -import * as i18n from './translations'; -import { createSiemJobs } from './use_siem_jobs_helpers'; -import { useMlCapabilities } from './use_ml_capabilities'; - -type Return = [boolean, SiemJob[]]; - -/** - * Compiles a collection of SiemJobs, which are a list of all jobs relevant to the SIEM App. This - * includes all installed jobs in the `SIEM` ML group, and all jobs within ML Modules defined in - * ml_module (whether installed or not). Use the corresponding helper functions to filter the job - * list as necessary. E.g. installed jobs, running jobs, etc. - * - * @param refetchData - */ -export const useSiemJobs = (refetchData: boolean): Return => { - const [siemJobs, setSiemJobs] = useState([]); - const [loading, setLoading] = useState(true); - const mlCapabilities = useMlCapabilities(); - const userPermissions = hasMlUserPermissions(mlCapabilities); - const [siemDefaultIndex] = useUiSetting$(DEFAULT_INDEX_KEY); - const [, dispatchToaster] = useStateToaster(); - - useEffect(() => { - let isSubscribed = true; - const abortCtrl = new AbortController(); - setLoading(true); - - async function fetchSiemJobIdsFromGroupsData() { - if (userPermissions) { - try { - // Batch fetch all installed jobs, ML modules, and check which modules are compatible with siemDefaultIndex - const [jobSummaryData, modulesData, compatibleModules] = await Promise.all([ - getJobsSummary(abortCtrl.signal), - getModules({ signal: abortCtrl.signal }), - checkRecognizer({ - indexPatternName: siemDefaultIndex, - signal: abortCtrl.signal, - }), - ]); - - const compositeSiemJobs = createSiemJobs(jobSummaryData, modulesData, compatibleModules); - - if (isSubscribed) { - setSiemJobs(compositeSiemJobs); - } - } catch (error) { - if (isSubscribed) { - errorToToaster({ title: i18n.SIEM_JOB_FETCH_FAILURE, error, dispatchToaster }); - } - } - } - if (isSubscribed) { - setLoading(false); - } - } - - fetchSiemJobIdsFromGroupsData(); - return () => { - isSubscribed = false; - abortCtrl.abort(); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [refetchData, userPermissions]); - - return [loading, siemJobs]; -}; diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/__snapshots__/jobs_table_filters.test.tsx.snap b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/__snapshots__/jobs_table_filters.test.tsx.snap index 747ac63551b55..9bee321e9fbde 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/__snapshots__/jobs_table_filters.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/__snapshots__/jobs_table_filters.test.tsx.snap @@ -25,7 +25,7 @@ exports[`JobsTableFilters renders correctly against snapshot 1`] = ` { - let siemJobs: SiemJob[]; + let securityJobs: SecurityJob[]; beforeEach(() => { - siemJobs = cloneDeep(mockSiemJobs); + securityJobs = cloneDeep(mockSecurityJobs); }); test('renders correctly against snapshot', () => { const wrapper = shallow( - + ); expect(wrapper).toMatchSnapshot(); }); @@ -29,7 +32,7 @@ describe('GroupsFilterPopover', () => { const mockOnSelectedGroupsChanged = jest.fn(); const wrapper = mount( ); diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/groups_filter_popover.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/groups_filter_popover.tsx index d879942b8b101..362fb94dc1ec4 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/groups_filter_popover.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/groups_filter_popover.tsx @@ -15,30 +15,30 @@ import { EuiSpacer, } from '@elastic/eui'; import * as i18n from './translations'; -import { SiemJob } from '../../types'; +import { SecurityJob } from '../../types'; import { toggleSelectedGroup } from './toggle_selected_group'; interface GroupsFilterPopoverProps { - siemJobs: SiemJob[]; + securityJobs: SecurityJob[]; onSelectedGroupsChanged: Dispatch>; } /** - * Popover for selecting which SiemJob groups to filter on. Component extracts unique groups and - * their counts from the provided SiemJobs. The 'siem' & 'security' groups are filtered out as all jobs will be + * Popover for selecting which SecurityJob groups to filter on. Component extracts unique groups and + * their counts from the provided SecurityJobs. The 'siem' & 'security' groups are filtered out as all jobs will be * siem/security jobs * - * @param siemJobs jobs to fetch groups from to display for filtering + * @param securityJobs jobs to fetch groups from to display for filtering * @param onSelectedGroupsChanged change listener to be notified when group selection changes */ export const GroupsFilterPopoverComponent = ({ - siemJobs, + securityJobs, onSelectedGroupsChanged, }: GroupsFilterPopoverProps) => { const [isGroupPopoverOpen, setIsGroupPopoverOpen] = useState(false); const [selectedGroups, setSelectedGroups] = useState([]); - const groups = siemJobs + const groups = securityJobs .map((j) => j.groups) .flat() .filter((g) => g !== 'siem' && g !== 'security'); diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/jobs_table_filters.test.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/jobs_table_filters.test.tsx index 5b656adc3e581..6b7699d57aedf 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/jobs_table_filters.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/jobs_table_filters.test.tsx @@ -7,20 +7,20 @@ import { mount, shallow } from 'enzyme'; import React from 'react'; import { JobsTableFiltersComponent } from './jobs_table_filters'; -import { SiemJob } from '../../types'; +import { SecurityJob } from '../../types'; import { cloneDeep } from 'lodash/fp'; -import { mockSiemJobs } from '../../__mocks__/api'; +import { mockSecurityJobs } from '../../api.mock'; describe('JobsTableFilters', () => { - let siemJobs: SiemJob[]; + let securityJobs: SecurityJob[]; beforeEach(() => { - siemJobs = cloneDeep(mockSiemJobs); + securityJobs = cloneDeep(mockSecurityJobs); }); test('renders correctly against snapshot', () => { const wrapper = shallow( - + ); expect(wrapper).toMatchSnapshot(); }); @@ -28,7 +28,7 @@ describe('JobsTableFilters', () => { test('when you click Elastic Jobs filter, state is updated and it is selected', () => { const onFilterChanged = jest.fn(); const wrapper = mount( - + ); wrapper.find('[data-test-subj="show-elastic-jobs-filter-button"]').first().simulate('click'); @@ -45,7 +45,7 @@ describe('JobsTableFilters', () => { test('when you click Custom Jobs filter, state is updated and it is selected', () => { const onFilterChanged = jest.fn(); const wrapper = mount( - + ); wrapper.find('[data-test-subj="show-custom-jobs-filter-button"]').first().simulate('click'); @@ -62,7 +62,7 @@ describe('JobsTableFilters', () => { test('when you click Custom Jobs filter once, then Elastic Jobs filter, state is updated and selected changed', () => { const onFilterChanged = jest.fn(); const wrapper = mount( - + ); wrapper.find('[data-test-subj="show-custom-jobs-filter-button"]').first().simulate('click'); @@ -88,7 +88,7 @@ describe('JobsTableFilters', () => { test('when you click Custom Jobs filter twice, state is updated and it is revert', () => { const onFilterChanged = jest.fn(); const wrapper = mount( - + ); wrapper.find('[data-test-subj="show-custom-jobs-filter-button"]').first().simulate('click'); diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/jobs_table_filters.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/jobs_table_filters.tsx index 4cfb7f8ad2b5b..f25ea667b3411 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/jobs_table_filters.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/jobs_table_filters.tsx @@ -15,11 +15,11 @@ import { } from '@elastic/eui'; import { EuiSearchBarQuery } from '../../../../../timelines/components/open_timeline/types'; import * as i18n from './translations'; -import { JobsFilters, SiemJob } from '../../types'; +import { JobsFilters, SecurityJob } from '../../types'; import { GroupsFilterPopover } from './groups_filter_popover'; interface JobsTableFiltersProps { - siemJobs: SiemJob[]; + securityJobs: SecurityJob[]; onFilterChanged: Dispatch>; } @@ -27,10 +27,13 @@ interface JobsTableFiltersProps { * Collection of filters for filtering data within the JobsTable. Contains search bar, Elastic/Custom * Jobs filter button toggle, and groups selection * - * @param siemJobs jobs to fetch groups from to display for filtering + * @param securityJobs jobs to fetch groups from to display for filtering * @param onFilterChanged change listener to be notified on filter changes */ -export const JobsTableFiltersComponent = ({ siemJobs, onFilterChanged }: JobsTableFiltersProps) => { +export const JobsTableFiltersComponent = ({ + securityJobs, + onFilterChanged, +}: JobsTableFiltersProps) => { const [filterQuery, setFilterQuery] = useState(''); const [selectedGroups, setSelectedGroups] = useState([]); const [showCustomJobs, setShowCustomJobs] = useState(false); @@ -71,7 +74,10 @@ export const JobsTableFiltersComponent = ({ siemJobs, onFilterChanged }: JobsTab - + diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/job_switch.test.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/job_switch.test.tsx index ade8c6fe80525..e58d76bd1dde0 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/job_switch.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/job_switch.test.tsx @@ -9,22 +9,22 @@ import React from 'react'; import { JobSwitchComponent } from './job_switch'; import { cloneDeep } from 'lodash/fp'; -import { mockSiemJobs } from '../__mocks__/api'; -import { SiemJob } from '../types'; +import { mockSecurityJobs } from '../api.mock'; +import { SecurityJob } from '../types'; describe('JobSwitch', () => { - let siemJobs: SiemJob[]; + let securityJobs: SecurityJob[]; let onJobStateChangeMock = jest.fn(); beforeEach(() => { - siemJobs = cloneDeep(mockSiemJobs); + securityJobs = cloneDeep(mockSecurityJobs); onJobStateChangeMock = jest.fn(); }); test('renders correctly against snapshot', () => { const wrapper = shallow( ); @@ -34,8 +34,8 @@ describe('JobSwitch', () => { test('should call onJobStateChange when the switch is clicked to be true/open', () => { const wrapper = mount( ); @@ -57,8 +57,8 @@ describe('JobSwitch', () => { test('should have a switch when it is not in the loading state', () => { const wrapper = mount( ); @@ -68,8 +68,8 @@ describe('JobSwitch', () => { test('should not have a switch when it is in the loading state', () => { const wrapper = mount( ); diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/job_switch.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/job_switch.tsx index d370d475bd6e5..3ad71ee6b6919 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/job_switch.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/job_switch.tsx @@ -12,7 +12,7 @@ import { isJobFailed, isJobStarted, } from '../../../../../common/machine_learning/helpers'; -import { SiemJob } from '../types'; +import { SecurityJob } from '../types'; const StaticSwitch = styled(EuiSwitch)` .euiSwitch__thumb, @@ -24,14 +24,14 @@ const StaticSwitch = styled(EuiSwitch)` StaticSwitch.displayName = 'StaticSwitch'; export interface JobSwitchProps { - job: SiemJob; - isSiemJobsLoading: boolean; - onJobStateChange: (job: SiemJob, latestTimestampMs: number, enable: boolean) => Promise; + job: SecurityJob; + isSecurityJobsLoading: boolean; + onJobStateChange: (job: SecurityJob, latestTimestampMs: number, enable: boolean) => Promise; } export const JobSwitchComponent = ({ job, - isSiemJobsLoading, + isSecurityJobsLoading, onJobStateChange, }: JobSwitchProps) => { const [isLoading, setIsLoading] = useState(false); @@ -47,7 +47,7 @@ export const JobSwitchComponent = ({ return ( - {isSiemJobsLoading || isLoading || isJobLoading(job.jobState, job.datafeedState) ? ( + {isSecurityJobsLoading || isLoading || isJobLoading(job.jobState, job.datafeedState) ? ( ) : ( { - let siemJobs: SiemJob[]; + let securityJobs: SecurityJob[]; let onJobStateChangeMock = jest.fn(); beforeEach(() => { - siemJobs = cloneDeep(mockSiemJobs); + securityJobs = cloneDeep(mockSecurityJobs); onJobStateChangeMock = jest.fn(); }); @@ -25,7 +25,7 @@ describe('JobsTableComponent', () => { const wrapper = shallow( ); @@ -36,7 +36,7 @@ describe('JobsTableComponent', () => { const wrapper = mount( ); @@ -46,11 +46,11 @@ describe('JobsTableComponent', () => { }); test('should render the hyperlink with URI encodings which points specifically to the job id', () => { - siemJobs[0].id = 'job id with spaces'; + securityJobs[0].id = 'job id with spaces'; const wrapper = mount( ); @@ -63,7 +63,7 @@ describe('JobsTableComponent', () => { const wrapper = mount( ); @@ -73,14 +73,14 @@ describe('JobsTableComponent', () => { .simulate('click', { target: { checked: true }, }); - expect(onJobStateChangeMock.mock.calls[0]).toEqual([siemJobs[0], 1571022859393, true]); + expect(onJobStateChangeMock.mock.calls[0]).toEqual([securityJobs[0], 1571022859393, true]); }); test('should have a switch when it is not in the loading state', () => { const wrapper = mount( ); @@ -91,7 +91,7 @@ describe('JobsTableComponent', () => { const wrapper = mount( ); diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/jobs_table.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/jobs_table.tsx index f28a99c9947d5..be911a1cd8537 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/jobs_table.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/jobs_table.tsx @@ -25,7 +25,7 @@ import styled from 'styled-components'; import { useBasePath } from '../../../lib/kibana'; import * as i18n from './translations'; import { JobSwitch } from './job_switch'; -import { SiemJob } from '../types'; +import { SecurityJob } from '../types'; const JobNameWrapper = styled.div` margin: 5px 0; @@ -38,12 +38,12 @@ const truncateThreshold = 200; const getJobsTableColumns = ( isLoading: boolean, - onJobStateChange: (job: SiemJob, latestTimestampMs: number, enable: boolean) => Promise, + onJobStateChange: (job: SecurityJob, latestTimestampMs: number, enable: boolean) => Promise, basePath: string ) => [ { name: i18n.COLUMN_JOB_NAME, - render: ({ id, description }: SiemJob) => ( + render: ({ id, description }: SecurityJob) => ( ( + render: ({ groups }: SecurityJob) => ( {groups.map((group) => ( @@ -76,9 +76,13 @@ const getJobsTableColumns = ( { name: i18n.COLUMN_RUN_JOB, - render: (job: SiemJob) => + render: (job: SecurityJob) => job.isCompatible ? ( - + ) : ( ), @@ -87,13 +91,16 @@ const getJobsTableColumns = ( } as const, ]; -const getPaginatedItems = (items: SiemJob[], pageIndex: number, pageSize: number): SiemJob[] => - items.slice(pageIndex * pageSize, pageIndex * pageSize + pageSize); +const getPaginatedItems = ( + items: SecurityJob[], + pageIndex: number, + pageSize: number +): SecurityJob[] => items.slice(pageIndex * pageSize, pageIndex * pageSize + pageSize); export interface JobTableProps { isLoading: boolean; - jobs: SiemJob[]; - onJobStateChange: (job: SiemJob, latestTimestampMs: number, enable: boolean) => Promise; + jobs: SecurityJob[]; + onJobStateChange: (job: SecurityJob, latestTimestampMs: number, enable: boolean) => Promise; } export const JobsTableComponent = ({ isLoading, jobs, onJobStateChange }: JobTableProps) => { diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/ml_popover.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/ml_popover.tsx index 0ebf367471848..f2bf2273c4b3f 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/ml_popover.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/ml_popover.tsx @@ -12,19 +12,17 @@ import styled from 'styled-components'; import { useKibana } from '../../lib/kibana'; import { METRIC_TYPE, TELEMETRY_EVENT, track } from '../../lib/telemetry'; -import { hasMlAdminPermissions } from '../../../../common/machine_learning/has_ml_admin_permissions'; import { errorToToaster, useStateToaster, ActionToaster } from '../toasters'; import { setupMlJob, startDatafeeds, stopDatafeeds } from './api'; import { filterJobs } from './helpers'; -import { useSiemJobs } from './hooks/use_siem_jobs'; import { JobsTableFilters } from './jobs_table/filters/jobs_table_filters'; import { JobsTable } from './jobs_table/jobs_table'; import { ShowingCount } from './jobs_table/showing_count'; import { PopoverDescription } from './popover_description'; import * as i18n from './translations'; -import { JobsFilters, SiemJob } from './types'; +import { JobsFilters, SecurityJob } from './types'; import { UpgradeContents } from './upgrade_contents'; -import { useMlCapabilities } from './hooks/use_ml_capabilities'; +import { useSecurityJobs } from './hooks/use_security_jobs'; const PopoverContentsDiv = styled.div` max-width: 684px; @@ -87,24 +85,25 @@ export const MlPopover = React.memo(() => { const [isPopoverOpen, setIsPopoverOpen] = useState(false); const [filterProperties, setFilterProperties] = useState(defaultFilterProps); - const [isLoadingSiemJobs, siemJobs] = useSiemJobs(refreshToggle); + const { isMlAdmin, isLicensed, loading: isLoadingSecurityJobs, jobs } = useSecurityJobs( + refreshToggle + ); const [, dispatchToaster] = useStateToaster(); - const capabilities = useMlCapabilities(); const docLinks = useKibana().services.docLinks; const handleJobStateChange = useCallback( - (job: SiemJob, latestTimestampMs: number, enable: boolean) => + (job: SecurityJob, latestTimestampMs: number, enable: boolean) => enableDatafeed(job, latestTimestampMs, enable, dispatch, dispatchToaster), [dispatch, dispatchToaster] ); const filteredJobs = filterJobs({ - jobs: siemJobs, + jobs, ...filterProperties, }); - const incompatibleJobCount = siemJobs.filter((j) => !j.isCompatible).length; + const incompatibleJobCount = jobs.filter((j) => !j.isCompatible).length; - if (!capabilities.isPlatinumOrTrialLicense) { + if (!isLicensed) { // If the user does not have platinum show upgrade UI return ( { ); - } else if (hasMlAdminPermissions(capabilities)) { + } else if (isMlAdmin) { // If the user has Platinum License & ML Admin Permissions, show Anomaly Detection button & full config UI return ( { - + @@ -194,7 +193,7 @@ export const MlPopover = React.memo(() => { )} @@ -209,7 +208,7 @@ export const MlPopover = React.memo(() => { // Enable/Disable Job & Datafeed -- passed to JobsTable for use as callback on JobSwitch const enableDatafeed = async ( - job: SiemJob, + job: SecurityJob, latestTimestampMs: number, enable: boolean, dispatch: Dispatch, @@ -257,7 +256,7 @@ const enableDatafeed = async ( dispatch({ type: 'refresh' }); }; -const submitTelemetry = (job: SiemJob, enabled: boolean) => { +const submitTelemetry = (job: SecurityJob, enabled: boolean) => { // Report type of job enabled/disabled track( METRIC_TYPE.COUNT, diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/types.ts b/x-pack/plugins/security_solution/public/common/components/ml_popover/types.ts index f39daa0b9a7fb..c839f5110fe7f 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/types.ts +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/types.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { AuditMessageBase } from '../../../../../ml/public'; import { MlError } from '../ml/types'; +import { MlSummaryJob } from '../../../../../ml/public'; export interface Group { id: string; @@ -98,28 +98,6 @@ export interface MlSetupArgs { prefix?: string; } -/** - * Representation of an ML Job as returned from the `ml/jobs/jobs_summary` API - */ -export interface JobSummary { - auditMessage?: AuditMessageBase; - datafeedId: string; - datafeedIndices: string[]; - datafeedState: string; - description: string; - earliestTimestampMs?: number; - latestResultsTimestampMs?: number; - groups: string[]; - hasDatafeed: boolean; - id: string; - isSingleMetricViewerJob: boolean; - jobState: string; - latestTimestampMs?: number; - memory_status: string; - nodeName?: string; - processed_record_count: number; -} - export interface Detector { detector_description: string; function: string; @@ -133,10 +111,10 @@ export interface CustomURL { } /** - * Representation of an ML Job as used by the SIEM App -- a composition of ModuleJob and JobSummary + * Representation of an ML Job as used by the SIEM App -- a composition of ModuleJob and MlSummaryJob * that includes necessary metadata like moduleName, defaultIndexPattern, etc. */ -export interface SiemJob extends JobSummary { +export interface SecurityJob extends MlSummaryJob { moduleId: string; defaultIndexPattern: string; isCompatible: boolean; @@ -144,7 +122,7 @@ export interface SiemJob extends JobSummary { isElasticJob: boolean; } -export interface AugmentedSiemJobFields { +export interface AugmentedSecurityJobFields { moduleId: string; defaultIndexPattern: string; isCompatible: boolean; diff --git a/x-pack/plugins/security_solution/public/common/containers/anomalies/anomalies_query_tab_body/index.tsx b/x-pack/plugins/security_solution/public/common/containers/anomalies/anomalies_query_tab_body/index.tsx index 76270a7c08cd6..94019b26c180b 100644 --- a/x-pack/plugins/security_solution/public/common/containers/anomalies/anomalies_query_tab_body/index.tsx +++ b/x-pack/plugins/security_solution/public/common/containers/anomalies/anomalies_query_tab_body/index.tsx @@ -9,7 +9,7 @@ import React, { useEffect } from 'react'; import { DEFAULT_ANOMALY_SCORE } from '../../../../../common/constants'; import { AnomaliesQueryTabBodyProps } from './types'; import { getAnomaliesFilterQuery } from './utils'; -import { useSiemJobs } from '../../../components/ml_popover/hooks/use_siem_jobs'; +import { useInstalledSecurityJobs } from '../../../components/ml/hooks/use_installed_security_jobs'; import { useUiSetting$ } from '../../../lib/kibana'; import { MatrixHistogramContainer } from '../../../components/matrix_histogram'; import { histogramConfigs } from './histogram_configs'; @@ -38,13 +38,13 @@ export const AnomaliesQueryTabBody = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - const [, siemJobs] = useSiemJobs(true); + const { jobs } = useInstalledSecurityJobs(); const [anomalyScore] = useUiSetting$(DEFAULT_ANOMALY_SCORE); const mergedFilterQuery = getAnomaliesFilterQuery( filterQuery, anomaliesFilterQuery, - siemJobs, + jobs, anomalyScore, flowTarget, ip diff --git a/x-pack/plugins/security_solution/public/common/containers/anomalies/anomalies_query_tab_body/utils.ts b/x-pack/plugins/security_solution/public/common/containers/anomalies/anomalies_query_tab_body/utils.ts index 10d5d1c60a6c2..5248801d723b6 100644 --- a/x-pack/plugins/security_solution/public/common/containers/anomalies/anomalies_query_tab_body/utils.ts +++ b/x-pack/plugins/security_solution/public/common/containers/anomalies/anomalies_query_tab_body/utils.ts @@ -6,21 +6,20 @@ import deepmerge from 'deepmerge'; +import { MlSummaryJob } from '../../../../../../ml/public'; import { ESTermQuery } from '../../../../../common/typed_json'; import { createFilter } from '../../helpers'; -import { SiemJob } from '../../../components/ml_popover/types'; import { FlowTarget } from '../../../../graphql/types'; export const getAnomaliesFilterQuery = ( filterQuery: string | ESTermQuery | undefined, anomaliesFilterQuery: object = {}, - siemJobs: SiemJob[] = [], + securityJobs: MlSummaryJob[] = [], anomalyScore: number, flowTarget?: FlowTarget, ip?: string ): string => { - const siemJobIds = siemJobs - .filter((job) => job.isInstalled) + const securityJobIds = securityJobs .map((job) => job.id) .map((jobId) => ({ match_phrase: { @@ -38,7 +37,7 @@ export const getAnomaliesFilterQuery = ( filter: [ { bool: { - should: siemJobIds, + should: securityJobIds, minimum_should_match: 1, }, }, diff --git a/x-pack/plugins/security_solution/public/common/hooks/use_app_toasts.mock.ts b/x-pack/plugins/security_solution/public/common/hooks/use_app_toasts.mock.ts new file mode 100644 index 0000000000000..1af4ba3ba9233 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/hooks/use_app_toasts.mock.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. + */ + +const createAppToastsMock = () => ({ + addError: jest.fn(), + addSuccess: jest.fn(), +}); + +export const useAppToastsMock = { + create: createAppToastsMock, +}; diff --git a/x-pack/plugins/security_solution/public/common/lib/kibana/__mocks__/index.ts b/x-pack/plugins/security_solution/public/common/lib/kibana/__mocks__/index.ts index 2c52acd3ec747..5f4285f2747ae 100644 --- a/x-pack/plugins/security_solution/public/common/lib/kibana/__mocks__/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/kibana/__mocks__/index.ts @@ -17,6 +17,7 @@ export const KibanaServices = { get: jest.fn(), getKibanaVersion: jest.fn(() => export const useKibana = jest.fn(createUseKibanaMock()); export const useUiSetting = jest.fn(createUseUiSettingMock()); export const useUiSetting$ = jest.fn(createUseUiSetting$Mock()); +export const useHttp = jest.fn(() => useKibana().services.http); export const useTimeZone = jest.fn(); export const useDateFormat = jest.fn(); export const useBasePath = jest.fn(() => '/test/base/path'); diff --git a/x-pack/plugins/security_solution/public/common/mock/kibana_core.ts b/x-pack/plugins/security_solution/public/common/mock/kibana_core.ts index 13b3c4b249bfe..f8eed75cf9bf1 100644 --- a/x-pack/plugins/security_solution/public/common/mock/kibana_core.ts +++ b/x-pack/plugins/security_solution/public/common/mock/kibana_core.ts @@ -6,8 +6,10 @@ import { coreMock } from '../../../../../../src/core/public/mocks'; import { dataPluginMock } from '../../../../../../src/plugins/data/public/mocks'; +import { securityMock } from '../../../../../plugins/security/public/mocks'; export const createKibanaCoreStartMock = () => coreMock.createStart(); export const createKibanaPluginsStartMock = () => ({ data: dataPluginMock.createStartContract(), + security: securityMock.createSetup(), }); diff --git a/x-pack/plugins/security_solution/public/common/mock/kibana_react.ts b/x-pack/plugins/security_solution/public/common/mock/kibana_react.ts index c5d50e1379482..bdb8ca85b0d77 100644 --- a/x-pack/plugins/security_solution/public/common/mock/kibana_react.ts +++ b/x-pack/plugins/security_solution/public/common/mock/kibana_react.ts @@ -96,28 +96,10 @@ export const createUseKibanaMock = () => { export const createStartServices = () => { const core = createKibanaCoreStartMock(); const plugins = createKibanaPluginsStartMock(); - const security = { - authc: { - getCurrentUser: jest.fn(), - areAPIKeysEnabled: jest.fn(), - }, - sessionTimeout: { - start: jest.fn(), - stop: jest.fn(), - extend: jest.fn(), - }, - license: { - isEnabled: jest.fn(), - getFeatures: jest.fn(), - features$: jest.fn(), - }, - __legacyCompat: { logoutUrl: 'logoutUrl', tenant: 'tenant' }, - }; const services = ({ ...core, ...plugins, - security, } as unknown) as StartServices; return services; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.tsx index 47c12d1934174..00141c9a453d8 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.tsx @@ -38,7 +38,7 @@ import { buildRuleTypeDescription, buildThresholdDescription, } from './helpers'; -import { useSiemJobs } from '../../../../common/components/ml_popover/hooks/use_siem_jobs'; +import { useSecurityJobs } from '../../../../common/components/ml_popover/hooks/use_security_jobs'; import { buildMlJobDescription } from './ml_job_description'; import { buildActionsDescription } from './actions_description'; import { buildThrottleDescription } from './throttle_description'; @@ -67,7 +67,7 @@ export const StepRuleDescriptionComponent: React.FC = }) => { const kibana = useKibana(); const [filterManager] = useState(new FilterManager(kibana.services.uiSettings)); - const [, siemJobs] = useSiemJobs(true); + const { jobs } = useSecurityJobs(false); const keys = Object.keys(schema); const listItems = keys.reduce((acc: ListItems[], key: string) => { @@ -77,7 +77,7 @@ export const StepRuleDescriptionComponent: React.FC = buildMlJobDescription( get(key, data) as string, (get(key, schema) as { label: string }).label, - siemJobs + jobs ), ]; } diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/ml_job_description.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/ml_job_description.test.tsx index c82a465f08c3a..3152fef12c652 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/ml_job_description.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/ml_job_description.test.tsx @@ -7,31 +7,14 @@ import React from 'react'; import { shallow } from 'enzyme'; +import { mockOpenedJob } from '../../../../common/components/ml_popover/api.mock'; import { MlJobDescription, AuditIcon, JobStatusBadge } from './ml_job_description'; -jest.mock('../../../../common/lib/kibana'); -const job = { - moduleId: 'moduleId', - defaultIndexPattern: 'defaultIndexPattern', - isCompatible: true, - isInstalled: true, - isElasticJob: true, - datafeedId: 'datafeedId', - datafeedIndices: [], - datafeedState: 'datafeedState', - description: 'description', - groups: [], - hasDatafeed: true, - id: 'id', - isSingleMetricViewerJob: false, - jobState: 'jobState', - memory_status: 'memory_status', - processed_record_count: 0, -}; +jest.mock('../../../../common/lib/kibana'); describe('MlJobDescription', () => { it('renders correctly', () => { - const wrapper = shallow(); + const wrapper = shallow(); expect(wrapper.find('[data-test-subj="machineLearningJobId"]')).toHaveLength(1); }); @@ -47,7 +30,7 @@ describe('AuditIcon', () => { describe('JobStatusBadge', () => { it('renders correctly', () => { - const wrapper = shallow(); + const wrapper = shallow(); expect(wrapper.find('EuiBadge')).toHaveLength(1); }); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/ml_job_description.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/ml_job_description.tsx index d7e06511e7937..6baa2abab33d1 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/ml_job_description.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/ml_job_description.tsx @@ -8,9 +8,9 @@ import React from 'react'; import styled from 'styled-components'; import { EuiBadge, EuiIcon, EuiLink, EuiToolTip } from '@elastic/eui'; +import { MlSummaryJob } from '../../../../../../ml/public'; import { isJobStarted } from '../../../../../common/machine_learning/helpers'; import { useKibana } from '../../../../common/lib/kibana'; -import { SiemJob } from '../../../../common/components/ml_popover/types'; import { ListItems } from './types'; import { ML_JOB_STARTED, ML_JOB_STOPPED } from './translations'; @@ -21,7 +21,7 @@ enum MessageLevels { } const AuditIconComponent: React.FC<{ - message: SiemJob['auditMessage']; + message: MlSummaryJob['auditMessage']; }> = ({ message }) => { if (!message) { return null; @@ -47,7 +47,7 @@ const AuditIconComponent: React.FC<{ export const AuditIcon = React.memo(AuditIconComponent); -const JobStatusBadgeComponent: React.FC<{ job: SiemJob }> = ({ job }) => { +const JobStatusBadgeComponent: React.FC<{ job: MlSummaryJob }> = ({ job }) => { const isStarted = isJobStarted(job.jobState, job.datafeedState); const color = isStarted ? 'secondary' : 'danger'; const text = isStarted ? ML_JOB_STARTED : ML_JOB_STOPPED; @@ -69,7 +69,7 @@ const Wrapper = styled.div` overflow: hidden; `; -const MlJobDescriptionComponent: React.FC<{ job: SiemJob }> = ({ job }) => { +const MlJobDescriptionComponent: React.FC<{ job: MlSummaryJob }> = ({ job }) => { const jobUrl = useKibana().services.application.getUrlForApp( `ml#/jobs?mlManagement=(jobId:${encodeURI(job.id)})` ); @@ -92,12 +92,12 @@ export const MlJobDescription = React.memo(MlJobDescriptionComponent); export const buildMlJobDescription = ( jobId: string, label: string, - siemJobs: SiemJob[] + jobs: MlSummaryJob[] ): ListItems => { - const siemJob = siemJobs.find((job) => job.id === jobId); + const job = jobs.find(({ id }) => id === jobId); return { title: label, - description: siemJob ? : jobId, + description: job ? : jobId, }; }; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/ml_job_select/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/ml_job_select/index.test.tsx index 6f6581e4de1c3..4a08adbedab3f 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/ml_job_select/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/ml_job_select/index.test.tsx @@ -8,14 +8,14 @@ import React from 'react'; import { shallow } from 'enzyme'; import { MlJobSelect } from './index'; -import { useSiemJobs } from '../../../../common/components/ml_popover/hooks/use_siem_jobs'; +import { useSecurityJobs } from '../../../../common/components/ml_popover/hooks/use_security_jobs'; import { useFormFieldMock } from '../../../../common/mock'; -jest.mock('../../../../common/components/ml_popover/hooks/use_siem_jobs'); +jest.mock('../../../../common/components/ml_popover/hooks/use_security_jobs'); jest.mock('../../../../common/lib/kibana'); describe('MlJobSelect', () => { beforeAll(() => { - (useSiemJobs as jest.Mock).mockReturnValue([false, []]); + (useSecurityJobs as jest.Mock).mockReturnValue({ loading: false, jobs: [] }); }); it('renders correctly', () => { diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/ml_job_select/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/ml_job_select/index.tsx index cdfdf4ca6b66b..b0aa0329fe8f4 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/ml_job_select/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/ml_job_select/index.tsx @@ -19,7 +19,7 @@ import { import styled from 'styled-components'; import { isJobStarted } from '../../../../../common/machine_learning/helpers'; import { FieldHook, getFieldValidityAndErrorMessage } from '../../../../shared_imports'; -import { useSiemJobs } from '../../../../common/components/ml_popover/hooks/use_siem_jobs'; +import { useSecurityJobs } from '../../../../common/components/ml_popover/hooks/use_security_jobs'; import { useKibana } from '../../../../common/lib/kibana'; import { ML_JOB_SELECT_PLACEHOLDER_TEXT, @@ -81,7 +81,7 @@ interface MlJobSelectProps { export const MlJobSelect: React.FC = ({ describedByIds = [], field }) => { const jobId = field.value as string; const { isInvalid, errorMessage } = getFieldValidityAndErrorMessage(field); - const [isLoading, siemJobs] = useSiemJobs(false); + const { loading, jobs } = useSecurityJobs(false); const mlUrl = useKibana().services.application.getUrlForApp('ml'); const handleJobChange = useCallback( (machineLearningJobId: string) => { @@ -96,7 +96,7 @@ export const MlJobSelect: React.FC = ({ describedByIds = [], f disabled: true, }; - const jobOptions = siemJobs.map((job) => ({ + const jobOptions = jobs.map((job) => ({ value: job.id, inputDisplay: job.id, dropdownDisplay: , @@ -107,9 +107,9 @@ export const MlJobSelect: React.FC = ({ describedByIds = [], f const isJobRunning = useMemo(() => { // If the selected job is not found in the list, it means the placeholder is selected // and so we don't want to show the warning, thus isJobRunning will be true when 'job == null' - const job = siemJobs.find((j) => j.id === jobId); + const job = jobs.find(({ id }) => id === jobId); return job == null || isJobStarted(job.jobState, job.datafeedState); - }, [siemJobs, jobId]); + }, [jobs, jobId]); return ( @@ -126,7 +126,7 @@ export const MlJobSelect: React.FC = ({ describedByIds = [], f = ({ componentProps={{ describedByIds: ['detectionEngineStepDefineRuleType'], isReadOnly: isUpdateView, - hasValidLicense: mlCapabilities.isPlatinumOrTrialLicense, + hasValidLicense: hasMlLicense(mlCapabilities), isMlAdmin: hasMlAdminPermissions(mlCapabilities), }} /> diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.tsx index 85dce907084e8..110691328b13b 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.tsx @@ -47,8 +47,9 @@ import { getColumns, getMonitoringColumns } from './columns'; import { showRulesTable } from './helpers'; import { allRulesReducer, State } from './reducer'; import { RulesTableFilters } from './rules_table_filters/rules_table_filters'; -import { useMlCapabilities } from '../../../../../common/components/ml_popover/hooks/use_ml_capabilities'; +import { useMlCapabilities } from '../../../../../common/components/ml/hooks/use_ml_capabilities'; import { hasMlAdminPermissions } from '../../../../../../common/machine_learning/has_ml_admin_permissions'; +import { hasMlLicense } from '../../../../../../common/machine_learning/has_ml_license'; import { SecurityPageName } from '../../../../../app/types'; import { useFormatUrl } from '../../../../../common/components/link_to'; @@ -145,8 +146,7 @@ export const AllRules = React.memo( const { formatUrl } = useFormatUrl(SecurityPageName.detections); // TODO: Refactor license check + hasMlAdminPermissions to common check - const hasMlPermissions = - mlCapabilities.isPlatinumOrTrialLicense && hasMlAdminPermissions(mlCapabilities); + const hasMlPermissions = hasMlLicense(mlCapabilities) && hasMlAdminPermissions(mlCapabilities); const setRules = useCallback((newRules: Rule[], newPagination: Partial) => { dispatch({ diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx index 016d0c7c67a9e..8a969a4cf098c 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/details/index.tsx @@ -71,8 +71,9 @@ import { RuleActionsOverflow } from '../../../../components/rules/rule_actions_o import { RuleStatusFailedCallOut } from './status_failed_callout'; import { FailureHistory } from './failure_history'; import { RuleStatus } from '../../../../components/rules//rule_status'; -import { useMlCapabilities } from '../../../../../common/components/ml_popover/hooks/use_ml_capabilities'; +import { useMlCapabilities } from '../../../../../common/components/ml/hooks/use_ml_capabilities'; import { hasMlAdminPermissions } from '../../../../../../common/machine_learning/has_ml_admin_permissions'; +import { hasMlLicense } from '../../../../../../common/machine_learning/has_ml_license'; import { SecurityPageName } from '../../../../../app/types'; import { LinkButton } from '../../../../../common/components/links'; import { useFormatUrl } from '../../../../../common/components/link_to'; @@ -161,8 +162,7 @@ export const RuleDetailsPageComponent: FC = ({ const { globalFullScreen } = useFullScreen(); // TODO: Refactor license check + hasMlAdminPermissions to common check - const hasMlPermissions = - mlCapabilities.isPlatinumOrTrialLicense && hasMlAdminPermissions(mlCapabilities); + const hasMlPermissions = hasMlLicense(mlCapabilities) && hasMlAdminPermissions(mlCapabilities); const ruleDetailTabs = getRuleDetailsTabs(rule); // persist rule until refresh is complete diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx b/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx index 34840b2826626..67f563e944f42 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx @@ -17,7 +17,7 @@ import { LastEventTime } from '../../../common/components/last_event_time'; import { AnomalyTableProvider } from '../../../common/components/ml/anomaly/anomaly_table_provider'; import { hostToCriteria } from '../../../common/components/ml/criteria/host_to_criteria'; import { hasMlUserPermissions } from '../../../../common/machine_learning/has_ml_user_permissions'; -import { useMlCapabilities } from '../../../common/components/ml_popover/hooks/use_ml_capabilities'; +import { useMlCapabilities } from '../../../common/components/ml/hooks/use_ml_capabilities'; import { scoreIntervalToDateTime } from '../../../common/components/ml/score/score_interval_to_datetime'; import { SiemNavigation } from '../../../common/components/navigation'; import { KpiHostsComponent } from '../../components/kpi_hosts'; diff --git a/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx b/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx index e4e69443c510d..2b19249dc426f 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx @@ -34,7 +34,7 @@ import { setAbsoluteRangeDatePicker as dispatchSetAbsoluteRangeDatePicker } from import { SpyRoute } from '../../common/utils/route/spy_routes'; import { esQuery } from '../../../../../../src/plugins/data/public'; -import { useMlCapabilities } from '../../common/components/ml_popover/hooks/use_ml_capabilities'; +import { useMlCapabilities } from '../../common/components/ml/hooks/use_ml_capabilities'; import { OverviewEmpty } from '../../overview/components/overview_empty'; import { Display } from './display'; import { HostsTabs } from './hosts_tabs'; diff --git a/x-pack/plugins/security_solution/public/network/components/ip_overview/index.tsx b/x-pack/plugins/security_solution/public/network/components/ip_overview/index.tsx index cf08b084d2197..d6dfe1769308e 100644 --- a/x-pack/plugins/security_solution/public/network/components/ip_overview/index.tsx +++ b/x-pack/plugins/security_solution/public/network/components/ip_overview/index.tsx @@ -30,7 +30,7 @@ import { DescriptionListStyled, OverviewWrapper } from '../../../common/componen import { Loader } from '../../../common/components/loader'; import { Anomalies, NarrowDateRange } from '../../../common/components/ml/types'; import { AnomalyScores } from '../../../common/components/ml/score/anomaly_scores'; -import { useMlCapabilities } from '../../../common/components/ml_popover/hooks/use_ml_capabilities'; +import { useMlCapabilities } from '../../../common/components/ml/hooks/use_ml_capabilities'; import { hasMlUserPermissions } from '../../../../common/machine_learning/has_ml_user_permissions'; import { InspectButton, InspectButtonContainer } from '../../../common/components/inspect'; diff --git a/x-pack/plugins/security_solution/public/network/pages/index.tsx b/x-pack/plugins/security_solution/public/network/pages/index.tsx index 9ac05cc98bb45..07abe7bc8c209 100644 --- a/x-pack/plugins/security_solution/public/network/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/index.tsx @@ -7,7 +7,7 @@ import React, { useMemo } from 'react'; import { Route, Switch, RouteComponentProps, useHistory } from 'react-router-dom'; -import { useMlCapabilities } from '../../common/components/ml_popover/hooks/use_ml_capabilities'; +import { useMlCapabilities } from '../../common/components/ml/hooks/use_ml_capabilities'; import { hasMlUserPermissions } from '../../../common/machine_learning/has_ml_user_permissions'; import { FlowTarget } from '../../graphql/types'; diff --git a/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx b/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx index 0a15b039b96af..c7aba6fcc8a5b 100644 --- a/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx @@ -23,7 +23,7 @@ import { HostItem } from '../../../graphql/types'; import { Loader } from '../../../common/components/loader'; import { IPDetailsLink } from '../../../common/components/links'; import { hasMlUserPermissions } from '../../../../common/machine_learning/has_ml_user_permissions'; -import { useMlCapabilities } from '../../../common/components/ml_popover/hooks/use_ml_capabilities'; +import { useMlCapabilities } from '../../../common/components/ml/hooks/use_ml_capabilities'; import { AnomalyScores } from '../../../common/components/ml/score/anomaly_scores'; import { Anomalies, NarrowDateRange } from '../../../common/components/ml/types'; import { DescriptionListStyled, OverviewWrapper } from '../../../common/components/page'; From e2ef219a7cd0b1d492e5cb929b3a3891a92e8e2e Mon Sep 17 00:00:00 2001 From: Brent Kimmel Date: Wed, 12 Aug 2020 21:02:00 -0400 Subject: [PATCH 09/53] [Security Solution][Resolver] fix presentation role on edgeline (#74869) Co-authored-by: Elastic Machine --- .../plugins/security_solution/public/resolver/view/edge_line.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/resolver/view/edge_line.tsx b/x-pack/plugins/security_solution/public/resolver/view/edge_line.tsx index 9f310bb1cc0d6..061dfce64b4e4 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/edge_line.tsx +++ b/x-pack/plugins/security_solution/public/resolver/view/edge_line.tsx @@ -127,7 +127,6 @@ const EdgeLineComponent = React.memo( return ( Date: Wed, 12 Aug 2020 22:32:05 -0600 Subject: [PATCH 10/53] [Security Solution][lists] Adds tests for exception lists and items part 2 (#74815) ## Summary This is the basics of end to end tests, so there could be a lot more, but this ties to cover the basics of the tests. Test with: ```ts node scripts/functional_tests --config x-pack/test/lists_api_integration/security_and_spaces/config.ts ``` Adds these tests for the route counter parts: * create_exception_list_items.ts * create_exception_lists.ts * delete_exception_list_items.ts * delete_exception_lists.ts * find_exception_list_items.ts * find_exception_lists.ts * read_exception_list_items.ts * read_exception_lists.ts * update_exception_list_items.ts * update_exception_lists.ts Fixes a few minor strings, other tests, but no large bugs found with these tests ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --- .../create_exception_list_item_schema.mock.ts | 24 +++ .../create_exception_list_schema.mock.ts | 20 ++ .../update_exception_list_item_schema.mock.ts | 13 ++ .../update_exception_list_schema.mock.ts | 11 ++ .../exception_list_item_schema.mock.ts | 24 +++ .../response/exception_list_schema.mock.ts | 24 +++ .../create_exception_list_item_route.ts | 2 +- .../routes/find_exception_list_item_route.ts | 2 +- .../update_exception_list_item_route.ts | 69 ++++--- .../routes/update_exception_list_route.ts | 6 +- .../utils/get_error_message_exception_list.ts | 6 +- .../get_error_message_exception_list_item.ts | 6 +- .../tests/create_exception_list_items.ts | 119 ++++++++++++ .../tests/create_exception_lists.ts | 77 ++++++++ .../tests/delete_exception_list_items.ts | 119 ++++++++++++ .../tests/delete_exception_lists.ts | 98 ++++++++++ .../tests/export_list_items.ts | 5 +- .../tests/find_exception_list_items.ts | 105 ++++++++++ .../tests/find_exception_lists.ts | 67 +++++++ .../tests/import_list_items.ts | 2 +- .../security_and_spaces/tests/index.ts | 10 + .../tests/read_exception_list_items.ts | 159 +++++++++++++++ .../tests/read_exception_lists.ts | 112 +++++++++++ .../tests/update_exception_list_items.ts | 168 ++++++++++++++++ .../tests/update_exception_lists.ts | 182 ++++++++++++++++++ x-pack/test/lists_api_integration/utils.ts | 60 +++++- 26 files changed, 1444 insertions(+), 46 deletions(-) create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_list_items.ts create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_lists.ts create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_list_items.ts create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_lists.ts create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_list_items.ts create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_lists.ts create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_list_items.ts create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_lists.ts create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_list_items.ts create mode 100644 x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_lists.ts diff --git a/x-pack/plugins/lists/common/schemas/request/create_exception_list_item_schema.mock.ts b/x-pack/plugins/lists/common/schemas/request/create_exception_list_item_schema.mock.ts index 0450849931b30..da22e33dc7b52 100644 --- a/x-pack/plugins/lists/common/schemas/request/create_exception_list_item_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/request/create_exception_list_item_schema.mock.ts @@ -8,6 +8,7 @@ import { COMMENTS, DESCRIPTION, ENTRIES, + ITEM_ID, ITEM_TYPE, LIST_ID, META, @@ -32,3 +33,26 @@ export const getCreateExceptionListItemSchemaMock = (): CreateExceptionListItemS tags: TAGS, type: ITEM_TYPE, }); + +/** + * Useful for end to end testing + */ +export const getCreateExceptionListItemMinimalSchemaMock = (): CreateExceptionListItemSchema => ({ + description: DESCRIPTION, + entries: ENTRIES, + item_id: ITEM_ID, + list_id: LIST_ID, + name: NAME, + type: ITEM_TYPE, +}); + +/** + * Useful for end to end testing + */ +export const getCreateExceptionListItemMinimalSchemaMockWithoutId = (): CreateExceptionListItemSchema => ({ + description: DESCRIPTION, + entries: ENTRIES, + list_id: LIST_ID, + name: NAME, + type: ITEM_TYPE, +}); diff --git a/x-pack/plugins/lists/common/schemas/request/create_exception_list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/request/create_exception_list_schema.mock.ts index d9c0474610369..f8431fcce1bf7 100644 --- a/x-pack/plugins/lists/common/schemas/request/create_exception_list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/request/create_exception_list_schema.mock.ts @@ -7,6 +7,7 @@ import { DESCRIPTION, ENDPOINT_TYPE, + LIST_ID, META, NAME, NAMESPACE_TYPE, @@ -26,3 +27,22 @@ export const getCreateExceptionListSchemaMock = (): CreateExceptionListSchema => type: ENDPOINT_TYPE, version: VERSION, }); + +/** + * Useful for end to end testing + */ +export const getCreateExceptionListMinimalSchemaMock = (): CreateExceptionListSchema => ({ + description: DESCRIPTION, + list_id: LIST_ID, + name: NAME, + type: ENDPOINT_TYPE, +}); + +/** + * Useful for end to end testing + */ +export const getCreateExceptionListMinimalSchemaMockWithoutId = (): CreateExceptionListSchema => ({ + description: DESCRIPTION, + name: NAME, + type: ENDPOINT_TYPE, +}); diff --git a/x-pack/plugins/lists/common/schemas/request/update_exception_list_item_schema.mock.ts b/x-pack/plugins/lists/common/schemas/request/update_exception_list_item_schema.mock.ts index 90d70c273f490..4673c0fe7629d 100644 --- a/x-pack/plugins/lists/common/schemas/request/update_exception_list_item_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/request/update_exception_list_item_schema.mock.ts @@ -9,6 +9,7 @@ import { DESCRIPTION, ENTRIES, ID, + ITEM_ID, ITEM_TYPE, LIST_ITEM_ID, META, @@ -34,3 +35,15 @@ export const getUpdateExceptionListItemSchemaMock = (): UpdateExceptionListItemS tags: TAGS, type: ITEM_TYPE, }); + +/** + * Useful for end to end tests and other mechanisms which want to fill in the values + * after doing a get of the structure. + */ +export const getUpdateMinimalExceptionListItemSchemaMock = (): UpdateExceptionListItemSchema => ({ + description: DESCRIPTION, + entries: ENTRIES, + item_id: ITEM_ID, + name: NAME, + type: ITEM_TYPE, +}); diff --git a/x-pack/plugins/lists/common/schemas/request/update_exception_list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/request/update_exception_list_schema.mock.ts index 22af29e6af0b7..b7dc2d9e0c948 100644 --- a/x-pack/plugins/lists/common/schemas/request/update_exception_list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/request/update_exception_list_schema.mock.ts @@ -20,3 +20,14 @@ export const getUpdateExceptionListSchemaMock = (): UpdateExceptionListSchema => tags: ['malware'], type: 'endpoint', }); + +/** + * Useful for end to end tests and other mechanisms which want to fill in the values + * after doing a get of the structure. + */ +export const getUpdateMinimalExceptionListSchemaMock = (): UpdateExceptionListSchema => ({ + description: DESCRIPTION, + list_id: LIST_ID, + name: NAME, + type: 'endpoint', +}); diff --git a/x-pack/plugins/lists/common/schemas/response/exception_list_item_schema.mock.ts b/x-pack/plugins/lists/common/schemas/response/exception_list_item_schema.mock.ts index c0d04c9823ca3..1a8f21a5232f8 100644 --- a/x-pack/plugins/lists/common/schemas/response/exception_list_item_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/response/exception_list_item_schema.mock.ts @@ -7,8 +7,11 @@ import { COMMENTS, DATE_NOW, DESCRIPTION, + ELASTIC_USER, ENTRIES, + ITEM_ID, ITEM_TYPE, + LIST_ID, META, NAME, NAMESPACE_TYPE, @@ -38,3 +41,24 @@ export const getExceptionListItemSchemaMock = (): ExceptionListItemSchema => ({ updated_at: DATE_NOW, updated_by: USER, }); + +/** + * This is useful for end to end tests where we remove the auto generated parts for comparisons + * such as created_at, updated_at, and id. + */ +export const getExceptionListItemResponseMockWithoutAutoGeneratedValues = (): Partial< + ExceptionListItemSchema +> => ({ + _tags: [], + comments: [], + created_by: ELASTIC_USER, + description: DESCRIPTION, + entries: ENTRIES, + item_id: ITEM_ID, + list_id: LIST_ID, + name: NAME, + namespace_type: 'single', + tags: [], + type: ITEM_TYPE, + updated_by: ELASTIC_USER, +}); diff --git a/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts index 2655b09631b23..e2f0a7c06b400 100644 --- a/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts @@ -7,9 +7,12 @@ import { DATE_NOW, DESCRIPTION, + ELASTIC_USER, ENDPOINT_TYPE, IMMUTABLE, + LIST_ID, META, + NAME, TIE_BREAKER, USER, VERSION, @@ -18,6 +21,7 @@ import { import { ENDPOINT_LIST_ID } from '../..'; import { ExceptionListSchema } from './exception_list_schema'; + export const getExceptionListSchemaMock = (): ExceptionListSchema => ({ _tags: ['endpoint', 'process', 'malware', 'os:linux'], _version: _VERSION, @@ -37,3 +41,23 @@ export const getExceptionListSchemaMock = (): ExceptionListSchema => ({ updated_by: 'user_name', version: VERSION, }); + +/** + * This is useful for end to end tests where we remove the auto generated parts for comparisons + * such as created_at, updated_at, and id. + */ +export const getExceptionResponseMockWithoutAutoGeneratedValues = (): Partial< + ExceptionListSchema +> => ({ + _tags: [], + created_by: ELASTIC_USER, + description: DESCRIPTION, + immutable: IMMUTABLE, + list_id: LIST_ID, + name: NAME, + namespace_type: 'single', + tags: [], + type: ENDPOINT_TYPE, + updated_by: ELASTIC_USER, + version: VERSION, +}); diff --git a/x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts index fc0473b2b3704..f092aec82a8f3 100644 --- a/x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts @@ -57,7 +57,7 @@ export const createExceptionListItemRoute = (router: IRouter): void => { }); if (exceptionList == null) { return siemResponse.error({ - body: `list id: "${listId}" does not exist`, + body: `exception list id: "${listId}" does not exist`, statusCode: 404, }); } else { diff --git a/x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts index 88643e53ff0a7..103cba700013f 100644 --- a/x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts @@ -62,7 +62,7 @@ export const findExceptionListItemRoute = (router: IRouter): void => { }); if (exceptionListItems == null) { return siemResponse.error({ - body: `list id: "${listId}" does not exist`, + body: `exception list id: "${listId}" does not exist`, statusCode: 404, }); } diff --git a/x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts index 7e15f694aee13..745ad0735a174 100644 --- a/x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts @@ -54,39 +54,46 @@ export const updateExceptionListItemRoute = (router: IRouter): void => { namespace_type: namespaceType, tags, } = request.body; - const exceptionLists = getExceptionListClient(context); - const exceptionListItem = await exceptionLists.updateExceptionListItem({ - _tags, - _version, - comments, - description, - entries, - id, - itemId, - meta, - name, - namespaceType, - tags, - type, - }); - if (exceptionListItem == null) { - if (id != null) { - return siemResponse.error({ - body: `list item id: "${id}" not found`, - statusCode: 404, - }); - } else { - return siemResponse.error({ - body: `list item item_id: "${itemId}" not found`, - statusCode: 404, - }); - } + if (id == null && itemId == null) { + return siemResponse.error({ + body: 'either id or item_id need to be defined', + statusCode: 404, + }); } else { - const [validated, errors] = validate(exceptionListItem, exceptionListItemSchema); - if (errors != null) { - return siemResponse.error({ body: errors, statusCode: 500 }); + const exceptionLists = getExceptionListClient(context); + const exceptionListItem = await exceptionLists.updateExceptionListItem({ + _tags, + _version, + comments, + description, + entries, + id, + itemId, + meta, + name, + namespaceType, + tags, + type, + }); + if (exceptionListItem == null) { + if (id != null) { + return siemResponse.error({ + body: `exception list item id: "${id}" does not exist`, + statusCode: 404, + }); + } else { + return siemResponse.error({ + body: `exception list item item_id: "${itemId}" does not exist`, + statusCode: 404, + }); + } } else { - return response.ok({ body: validated ?? {} }); + const [validated, errors] = validate(exceptionListItem, exceptionListItemSchema); + if (errors != null) { + return siemResponse.error({ body: errors, statusCode: 500 }); + } else { + return response.ok({ body: validated ?? {} }); + } } } } catch (err) { diff --git a/x-pack/plugins/lists/server/routes/update_exception_list_route.ts b/x-pack/plugins/lists/server/routes/update_exception_list_route.ts index 8102210b8430d..1903d0f601d1d 100644 --- a/x-pack/plugins/lists/server/routes/update_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/update_exception_list_route.ts @@ -15,7 +15,7 @@ import { updateExceptionListSchema, } from '../../common/schemas'; -import { getExceptionListClient } from './utils'; +import { getErrorMessageExceptionList, getExceptionListClient } from './utils'; export const updateExceptionListRoute = (router: IRouter): void => { router.put( @@ -50,7 +50,7 @@ export const updateExceptionListRoute = (router: IRouter): void => { const exceptionLists = getExceptionListClient(context); if (id == null && listId == null) { return siemResponse.error({ - body: `either id or list_id need to be defined`, + body: 'either id or list_id need to be defined', statusCode: 404, }); } else { @@ -69,7 +69,7 @@ export const updateExceptionListRoute = (router: IRouter): void => { }); if (list == null) { return siemResponse.error({ - body: `exception list id: "${id}" not found`, + body: getErrorMessageExceptionList({ id, listId }), statusCode: 404, }); } else { diff --git a/x-pack/plugins/lists/server/routes/utils/get_error_message_exception_list.ts b/x-pack/plugins/lists/server/routes/utils/get_error_message_exception_list.ts index 665a7540184a0..7db3bedd9ec84 100644 --- a/x-pack/plugins/lists/server/routes/utils/get_error_message_exception_list.ts +++ b/x-pack/plugins/lists/server/routes/utils/get_error_message_exception_list.ts @@ -12,10 +12,10 @@ export const getErrorMessageExceptionList = ({ listId: string | undefined; }): string => { if (id != null) { - return `Exception list id: "${id}" does not exist`; + return `exception list id: "${id}" does not exist`; } else if (listId != null) { - return `Exception list list_id: "${listId}" does not exist`; + return `exception list list_id: "${listId}" does not exist`; } else { - return 'Exception list does not exist'; + return 'exception list does not exist'; } }; diff --git a/x-pack/plugins/lists/server/routes/utils/get_error_message_exception_list_item.ts b/x-pack/plugins/lists/server/routes/utils/get_error_message_exception_list_item.ts index 8e6730ef3db5c..efb6c0e59ade5 100644 --- a/x-pack/plugins/lists/server/routes/utils/get_error_message_exception_list_item.ts +++ b/x-pack/plugins/lists/server/routes/utils/get_error_message_exception_list_item.ts @@ -12,10 +12,10 @@ export const getErrorMessageExceptionListItem = ({ itemId: string | undefined; }): string => { if (id != null) { - return `Exception list item id: "${id}" does not exist`; + return `exception list item id: "${id}" does not exist`; } else if (itemId != null) { - return `Exception list item list_id: "${itemId}" does not exist`; + return `exception list item item_id: "${itemId}" does not exist`; } else { - return 'Exception list item does not exist'; + return 'exception list item does not exist'; } }; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_list_items.ts new file mode 100644 index 0000000000000..6148dbcc7090e --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_list_items.ts @@ -0,0 +1,119 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; + +import { ExceptionListItemSchema } from '../../../../plugins/lists/common'; +import { getExceptionListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/exception_list_item_schema.mock'; +import { getCreateExceptionListMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; +import { + getCreateExceptionListItemMinimalSchemaMock, + getCreateExceptionListItemMinimalSchemaMockWithoutId, +} from '../../../../plugins/lists/common/schemas/request/create_exception_list_item_schema.mock'; +import { + EXCEPTION_LIST_ITEM_URL, + EXCEPTION_LIST_URL, +} from '../../../../plugins/lists/common/constants'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; + +import { + removeListItemServerGeneratedProperties, + removeExceptionListItemServerGeneratedProperties, +} from '../../utils'; + +import { deleteAllExceptions } from '../../utils'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const es = getService('es'); + + describe('create_exception_list_items', () => { + describe('validation errors', () => { + it('should give a 404 error that the exception list must exist first before being able to add a list item to the exception list', async () => { + const { body } = await supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListItemMinimalSchemaMock()) + .expect(404); + + expect(body).to.eql({ + message: 'exception list id: "some-list-id" does not exist', + status_code: 404, + }); + }); + }); + + describe('creating exception list items', () => { + afterEach(async () => { + await deleteAllExceptions(es); + }); + + it('should create a simple exception list item with a list item id', async () => { + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + const { body } = await supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListItemMinimalSchemaMock()) + .expect(200); + + const bodyToCompare = removeExceptionListItemServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getExceptionListItemResponseMockWithoutAutoGeneratedValues()); + }); + + it('should create a simple exception list item without an id', async () => { + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + const { body } = await supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListItemMinimalSchemaMockWithoutId()) + .expect(200); + + const bodyToCompare = removeListItemServerGeneratedProperties(body); + const outputList: Partial = { + ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(), + item_id: body.item_id, + }; + expect(bodyToCompare).to.eql(outputList); + }); + + it('should cause a 409 conflict if we attempt to create the same exception list item twice', async () => { + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + await supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListItemMinimalSchemaMock()) + .expect(200); + + const { body } = await supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListItemMinimalSchemaMock()) + .expect(409); + + expect(body).to.eql({ + message: 'exception list item id: "some-list-item-id" already exists', + status_code: 409, + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_lists.ts new file mode 100644 index 0000000000000..2b654c72ae282 --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_lists.ts @@ -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 expect from '@kbn/expect'; + +import { ExceptionListSchema } from '../../../../plugins/lists/common'; +import { EXCEPTION_LIST_URL } from '../../../../plugins/lists/common/constants'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { getExceptionResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/exception_list_schema.mock'; +import { + getCreateExceptionListMinimalSchemaMock, + getCreateExceptionListMinimalSchemaMockWithoutId, +} from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; + +import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../utils'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const es = getService('es'); + + describe('create_exception_lists', () => { + describe('creating exception lists', () => { + afterEach(async () => { + await deleteAllExceptions(es); + }); + + it('should create a simple exception list', async () => { + const { body } = await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + const bodyToCompare = removeExceptionListServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getExceptionResponseMockWithoutAutoGeneratedValues()); + }); + + it('should create a simple exception list without a list_id', async () => { + const { body } = await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMockWithoutId()) + .expect(200); + + const bodyToCompare = removeExceptionListServerGeneratedProperties(body); + const outputtedList: Partial = { + ...getExceptionResponseMockWithoutAutoGeneratedValues(), + list_id: bodyToCompare.list_id, + }; + expect(bodyToCompare).to.eql(outputtedList); + }); + + it('should cause a 409 conflict if we attempt to create the same list_id twice', async () => { + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + const { body } = await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(409); + + expect(body).to.eql({ + message: 'exception list id: "some-list-id" already exists', + status_code: 409, + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_list_items.ts new file mode 100644 index 0000000000000..16bdd264dc546 --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_list_items.ts @@ -0,0 +1,119 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; + +import { ExceptionListItemSchema } from '../../../../plugins/lists/common'; +import { getExceptionListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/exception_list_item_schema.mock'; +import { + getCreateExceptionListItemMinimalSchemaMock, + getCreateExceptionListItemMinimalSchemaMockWithoutId, +} from '../../../../plugins/lists/common/schemas/request/create_exception_list_item_schema.mock'; +import { getCreateExceptionListMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { + EXCEPTION_LIST_URL, + EXCEPTION_LIST_ITEM_URL, +} from '../../../../plugins/lists/common/constants'; + +import { deleteAllExceptions, removeExceptionListItemServerGeneratedProperties } from '../../utils'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const es = getService('es'); + + describe('delete_exception_list_items', () => { + describe('delete exception list items', () => { + afterEach(async () => { + await deleteAllExceptions(es); + }); + + it('should delete a single exception list item by its item_id', async () => { + // create an exception list + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + // create an exception list item + await supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListItemMinimalSchemaMock()) + .expect(200); + + // delete the exception list item by its item_id + const { body } = await supertest + .delete( + `${EXCEPTION_LIST_ITEM_URL}?item_id=${ + getCreateExceptionListItemMinimalSchemaMock().item_id + }` + ) + .set('kbn-xsrf', 'true') + .expect(200); + + const bodyToCompare = removeExceptionListItemServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getExceptionListItemResponseMockWithoutAutoGeneratedValues()); + }); + + it('should delete a single exception list item using an auto generated id', async () => { + // create an exception list + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + // create an exception list item + const { body: bodyWithCreatedList } = await supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListItemMinimalSchemaMockWithoutId()) + .expect(200); + + // delete that exception list item by its auto-generated id + const { body } = await supertest + .delete(`${EXCEPTION_LIST_ITEM_URL}?id=${bodyWithCreatedList.id}`) + .set('kbn-xsrf', 'true') + .expect(200); + const outputtedList: Partial = { + ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(), + item_id: body.item_id, + }; + + const bodyToCompare = removeExceptionListItemServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(outputtedList); + }); + + it('should return an error if the id does not exist when trying to delete it', async () => { + const { body } = await supertest + .delete(`${EXCEPTION_LIST_ITEM_URL}?id=c1e1b359-7ac1-4e96-bc81-c683c092436f`) + .set('kbn-xsrf', 'true') + .expect(404); + + expect(body).to.eql({ + message: 'exception list item id: "c1e1b359-7ac1-4e96-bc81-c683c092436f" does not exist', + status_code: 404, + }); + }); + + it('should return an error if the item_id does not exist when trying to delete it', async () => { + const { body } = await supertest + .delete(`${EXCEPTION_LIST_ITEM_URL}?item_id=c1e1b359-7ac1-4e96-bc81-c683c092436f`) + .set('kbn-xsrf', 'true') + .expect(404); + + expect(body).to.eql({ + message: + 'exception list item item_id: "c1e1b359-7ac1-4e96-bc81-c683c092436f" does not exist', + status_code: 404, + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_lists.ts new file mode 100644 index 0000000000000..56e4bcd9641cf --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_lists.ts @@ -0,0 +1,98 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; + +import { ExceptionListSchema } from '../../../../plugins/lists/common'; +import { getExceptionResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/exception_list_schema.mock'; +import { + getCreateExceptionListMinimalSchemaMock, + getCreateExceptionListMinimalSchemaMockWithoutId, +} from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { EXCEPTION_LIST_URL } from '../../../../plugins/lists/common/constants'; + +import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../utils'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const es = getService('es'); + + describe('delete_exception_lists', () => { + describe('delete exception lists', () => { + afterEach(async () => { + await deleteAllExceptions(es); + }); + + it('should delete a single exception list by its list_id', async () => { + // create an exception list + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + // delete the exception list by its list id + const { body } = await supertest + .delete( + `${EXCEPTION_LIST_URL}?list_id=${getCreateExceptionListMinimalSchemaMock().list_id}` + ) + .set('kbn-xsrf', 'true') + .expect(200); + + const bodyToCompare = removeExceptionListServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getExceptionResponseMockWithoutAutoGeneratedValues()); + }); + + it('should delete a single exception list using an auto generated id', async () => { + // create an exception list + const { body: bodyWithCreatedList } = await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMockWithoutId()) + .expect(200); + + // delete that list by its auto-generated id + const { body } = await supertest + .delete(`${EXCEPTION_LIST_URL}?id=${bodyWithCreatedList.id}`) + .set('kbn-xsrf', 'true') + .expect(200); + + const outputtedList: Partial = { + ...getExceptionResponseMockWithoutAutoGeneratedValues(), + list_id: body.list_id, + }; + const bodyToCompare = removeExceptionListServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(outputtedList); + }); + + it('should return an error if the id does not exist when trying to delete it', async () => { + const { body } = await supertest + .delete(`${EXCEPTION_LIST_URL}?id=c1e1b359-7ac1-4e96-bc81-c683c092436f`) + .set('kbn-xsrf', 'true') + .expect(404); + + expect(body).to.eql({ + message: 'exception list id: "c1e1b359-7ac1-4e96-bc81-c683c092436f" does not exist', + status_code: 404, + }); + }); + + it('should return an error if the list_id does not exist when trying to delete it', async () => { + const { body } = await supertest + .delete(`${EXCEPTION_LIST_URL}?list_id=c1e1b359-7ac1-4e96-bc81-c683c092436f`) + .set('kbn-xsrf', 'true') + .expect(404); + + expect(body).to.eql({ + message: 'exception list list_id: "c1e1b359-7ac1-4e96-bc81-c683c092436f" does not exist', + status_code: 404, + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/export_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/export_list_items.ts index 6fe783fc497f2..74c28f5abdfc1 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/export_list_items.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/export_list_items.ts @@ -96,8 +96,9 @@ export default ({ getService }: FtrProviderContext): void => { .set('kbn-xsrf', 'true') .expect(200) .parse(binaryToString); - - expect(body.toString()).to.eql('127.0.0.2\n127.0.0.1\n'); + const bodyString = body.toString(); + expect(bodyString.includes('127.0.0.1')).to.be(true); + expect(bodyString.includes('127.0.0.2')).to.be(true); }); }); }); diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_list_items.ts new file mode 100644 index 0000000000000..a65e9f344986f --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_list_items.ts @@ -0,0 +1,105 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; + +import { getExceptionListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/exception_list_item_schema.mock'; +import { getCreateExceptionListItemMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_item_schema.mock'; +import { getCreateExceptionListMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { + EXCEPTION_LIST_URL, + EXCEPTION_LIST_ITEM_URL, +} from '../../../../plugins/lists/common/constants'; + +import { deleteAllExceptions, removeExceptionListItemServerGeneratedProperties } from '../../utils'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + const es = getService('es'); + + describe('find_exception_list_items', () => { + describe('find exception list items', () => { + afterEach(async () => { + await deleteAllExceptions(es); + }); + + it('should return an empty find body correctly if no exception list items are loaded', async () => { + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + const { body } = await supertest + .get( + `${EXCEPTION_LIST_ITEM_URL}/_find?list_id=${ + getCreateExceptionListMinimalSchemaMock().list_id + }` + ) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + + expect(body).to.eql({ + data: [], + page: 1, + per_page: 20, + total: 0, + }); + }); + + it('should return 404 if given a list_id that does not exist', async () => { + const { body } = await supertest + .get(`${EXCEPTION_LIST_ITEM_URL}/_find?list_id=non_exist`) + .set('kbn-xsrf', 'true') + .send() + .expect(404); + + expect(body).to.eql({ + message: 'exception list id: "non_exist" does not exist', + status_code: 404, + }); + }); + + it('should return a single exception list item when a single exception list item is loaded from a find with defaults added', async () => { + // add the exception list + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + // add a single exception list item + await supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListItemMinimalSchemaMock()) + .expect(200); + + // query the single exception list from _find + const { body } = await supertest + .get( + `${EXCEPTION_LIST_ITEM_URL}/_find?list_id=${ + getCreateExceptionListMinimalSchemaMock().list_id + }` + ) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + + body.data = [removeExceptionListItemServerGeneratedProperties(body.data[0])]; + expect(body).to.eql({ + data: [getExceptionListItemResponseMockWithoutAutoGeneratedValues()], + page: 1, + per_page: 20, + total: 1, + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_lists.ts new file mode 100644 index 0000000000000..c2328a7d112f4 --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_lists.ts @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; + +import { getExceptionResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/exception_list_schema.mock'; +import { getCreateExceptionListMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { EXCEPTION_LIST_URL } from '../../../../plugins/lists/common/constants'; + +import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../utils'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext): void => { + const supertest = getService('supertest'); + const es = getService('es'); + + describe('find_exception_lists', () => { + describe('find exception lists', () => { + afterEach(async () => { + await deleteAllExceptions(es); + }); + + it('should return an empty find body correctly if no exception lists are loaded', async () => { + const { body } = await supertest + .get(`${EXCEPTION_LIST_URL}/_find`) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + + expect(body).to.eql({ + data: [], + page: 1, + per_page: 20, + total: 0, + }); + }); + + it('should return a single exception list when a single exception list is loaded from a find with defaults added', async () => { + // add a single exception list + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + // query the single exception list from _find + const { body } = await supertest + .get(`${EXCEPTION_LIST_URL}/_find`) + .set('kbn-xsrf', 'true') + .send() + .expect(200); + + body.data = [removeExceptionListServerGeneratedProperties(body.data[0])]; + expect(body).to.eql({ + data: [getExceptionResponseMockWithoutAutoGeneratedValues()], + page: 1, + per_page: 20, + total: 1, + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/import_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/import_list_items.ts index 4befb6bbaf050..7b7a6173fb408 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/import_list_items.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/import_list_items.ts @@ -45,7 +45,7 @@ export default ({ getService }: FtrProviderContext): void => { }); }); - describe('importing rules with an index', () => { + describe('importing lists with an index', () => { beforeEach(async () => { await createListsIndex(supertest); }); diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts index 302877a680aa6..5458b4a9a7db2 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/index.ts @@ -23,5 +23,15 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./find_list_items')); loadTestFile(require.resolve('./import_list_items')); loadTestFile(require.resolve('./export_list_items')); + loadTestFile(require.resolve('./create_exception_lists')); + loadTestFile(require.resolve('./create_exception_list_items')); + loadTestFile(require.resolve('./read_exception_lists')); + loadTestFile(require.resolve('./read_exception_list_items')); + loadTestFile(require.resolve('./update_exception_lists')); + loadTestFile(require.resolve('./update_exception_list_items')); + loadTestFile(require.resolve('./delete_exception_lists')); + loadTestFile(require.resolve('./delete_exception_list_items')); + loadTestFile(require.resolve('./find_exception_lists')); + loadTestFile(require.resolve('./find_exception_list_items')); }); }; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_list_items.ts new file mode 100644 index 0000000000000..26b969e940a2b --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_list_items.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. + */ + +import expect from '@kbn/expect'; + +import { getExceptionListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/exception_list_item_schema.mock'; +import { + getCreateExceptionListItemMinimalSchemaMock, + getCreateExceptionListItemMinimalSchemaMockWithoutId, +} from '../../../../plugins/lists/common/schemas/request/create_exception_list_item_schema.mock'; +import { ExceptionListItemSchema } from '../../../../plugins/lists/common'; +import { getCreateExceptionListMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { + EXCEPTION_LIST_URL, + EXCEPTION_LIST_ITEM_URL, +} from '../../../../plugins/lists/common/constants'; + +import { deleteAllExceptions, removeExceptionListItemServerGeneratedProperties } from '../../utils'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const es = getService('es'); + + describe('read_exception_list_items', () => { + describe('reading exception list items', () => { + afterEach(async () => { + await deleteAllExceptions(es); + }); + + it('should be able to read a single exception list items using item_id', async () => { + // create a simple exception list to read + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + const { body } = await supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListItemMinimalSchemaMock()) + .expect(200); + + const bodyToCompare = removeExceptionListItemServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getExceptionListItemResponseMockWithoutAutoGeneratedValues()); + }); + + it('should be able to read a single exception list item using id', async () => { + // create a simple exception list to read + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + // create a simple exception list item to read + const { body: createListBody } = await supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListItemMinimalSchemaMock()) + .expect(200); + + const { body } = await supertest + .get(`${EXCEPTION_LIST_ITEM_URL}?id=${createListBody.id}`) + .set('kbn-xsrf', 'true') + .expect(200); + + const bodyToCompare = removeExceptionListItemServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getExceptionListItemResponseMockWithoutAutoGeneratedValues()); + }); + + it('should be able to read a single list item with an auto-generated id', async () => { + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + // create a simple exception list item to read + const { body: createListBody } = await supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListItemMinimalSchemaMockWithoutId()) + .expect(200); + + const { body } = await supertest + .get(`${EXCEPTION_LIST_ITEM_URL}?id=${createListBody.id}`) + .set('kbn-xsrf', 'true') + .expect(200); + + const outputtedList: Partial = { + ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(), + item_id: body.item_id, + }; + + const bodyToCompare = removeExceptionListItemServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(outputtedList); + }); + + it('should be able to read a single list item with an auto-generated item_id', async () => { + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + // create a simple exception list item to read + const { body: createListBody } = await supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListItemMinimalSchemaMockWithoutId()) + .expect(200); + + const { body } = await supertest + .get(`${EXCEPTION_LIST_ITEM_URL}?item_id=${createListBody.item_id}`) + .set('kbn-xsrf', 'true') + .expect(200); + + const outputtedList: Partial = { + ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(), + item_id: body.item_id, + }; + + const bodyToCompare = removeExceptionListItemServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(outputtedList); + }); + + it('should return 404 if given a fake id', async () => { + const { body } = await supertest + .get(`${EXCEPTION_LIST_ITEM_URL}?id=c1e1b359-7ac1-4e96-bc81-c683c092436f`) + .set('kbn-xsrf', 'true') + .expect(404); + + expect(body).to.eql({ + status_code: 404, + message: 'exception list item id: "c1e1b359-7ac1-4e96-bc81-c683c092436f" does not exist', + }); + }); + + it('should return 404 if given a fake list_id', async () => { + const { body } = await supertest + .get(`${EXCEPTION_LIST_ITEM_URL}?item_id=c1e1b359-7ac1-4e96-bc81-c683c092436f`) + .set('kbn-xsrf', 'true') + .expect(404); + + expect(body).to.eql({ + status_code: 404, + message: + 'exception list item item_id: "c1e1b359-7ac1-4e96-bc81-c683c092436f" does not exist', + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_lists.ts new file mode 100644 index 0000000000000..ee6bef3200f5c --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_lists.ts @@ -0,0 +1,112 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; + +import { ExceptionListSchema } from '../../../../plugins/lists/common'; +import { getExceptionResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/exception_list_schema.mock'; +import { + getCreateExceptionListMinimalSchemaMock, + getCreateExceptionListMinimalSchemaMockWithoutId, +} from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { EXCEPTION_LIST_URL } from '../../../../plugins/lists/common/constants'; + +import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../utils'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const es = getService('es'); + + describe('read_exception_lists', () => { + describe('reading exception lists', () => { + afterEach(async () => { + await deleteAllExceptions(es); + }); + + it('should be able to read a single exception list using list_id', async () => { + // create a simple exception list to read + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + const { body } = await supertest + .get(`${EXCEPTION_LIST_URL}?list_id=${getCreateExceptionListMinimalSchemaMock().list_id}`) + .set('kbn-xsrf', 'true') + .expect(200); + + const bodyToCompare = removeExceptionListServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getExceptionResponseMockWithoutAutoGeneratedValues()); + }); + + it('should be able to read a single exception list using id', async () => { + // create a simple exception list to read + const { body: createListBody } = await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + const { body } = await supertest + .get(`${EXCEPTION_LIST_URL}?id=${createListBody.id}`) + .set('kbn-xsrf', 'true') + .expect(200); + + const bodyToCompare = removeExceptionListServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(getExceptionResponseMockWithoutAutoGeneratedValues()); + }); + + it('should be able to read a single list with an auto-generated list_id', async () => { + // create a simple exception list to read + const { body: createListBody } = await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMockWithoutId()) + .expect(200); + + const { body } = await supertest + .get(`${EXCEPTION_LIST_URL}?list_id=${createListBody.list_id}`) + .set('kbn-xsrf', 'true') + .expect(200); + + const outputtedList: Partial = { + ...getExceptionResponseMockWithoutAutoGeneratedValues(), + list_id: body.list_id, + }; + + const bodyToCompare = removeExceptionListServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(outputtedList); + }); + + it('should return 404 if given a fake id', async () => { + const { body } = await supertest + .get(`${EXCEPTION_LIST_URL}?id=c1e1b359-7ac1-4e96-bc81-c683c092436f`) + .set('kbn-xsrf', 'true') + .expect(404); + + expect(body).to.eql({ + status_code: 404, + message: 'exception list id: "c1e1b359-7ac1-4e96-bc81-c683c092436f" does not exist', + }); + }); + + it('should return 404 if given a fake list_id', async () => { + const { body } = await supertest + .get(`${EXCEPTION_LIST_URL}?list_id=c1e1b359-7ac1-4e96-bc81-c683c092436f`) + .set('kbn-xsrf', 'true') + .expect(404); + + expect(body).to.eql({ + status_code: 404, + message: 'exception list list_id: "c1e1b359-7ac1-4e96-bc81-c683c092436f" does not exist', + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_list_items.ts new file mode 100644 index 0000000000000..40fb705620a19 --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_list_items.ts @@ -0,0 +1,168 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; + +import { getExceptionListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/exception_list_item_schema.mock'; +import { getCreateExceptionListItemMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_item_schema.mock'; +import { getCreateExceptionListMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { + EXCEPTION_LIST_URL, + EXCEPTION_LIST_ITEM_URL, +} from '../../../../plugins/lists/common/constants'; + +import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../utils'; +import { + UpdateExceptionListItemSchema, + ExceptionListItemSchema, +} from '../../../../plugins/lists/common/schemas'; + +import { getUpdateMinimalExceptionListItemSchemaMock } from '../../../../plugins/lists/common/schemas/request/update_exception_list_item_schema.mock'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const es = getService('es'); + + describe('update_exception_list_items', () => { + describe('update exception list items', () => { + afterEach(async () => { + await deleteAllExceptions(es); + }); + + it('should update a single exception list item property of name using an id', async () => { + // create a simple exception list + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + // create a simple exception list item + await supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListItemMinimalSchemaMock()) + .expect(200); + + // update a exception list item's name + const updatedList: UpdateExceptionListItemSchema = { + ...getUpdateMinimalExceptionListItemSchemaMock(), + name: 'some other name', + }; + + const { body } = await supertest + .put(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(updatedList) + .expect(200); + + const outputList: Partial = { + ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(), + name: 'some other name', + }; + + const bodyToCompare = removeExceptionListServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(outputList); + }); + + it('should update a single exception list item property of name using an auto-generated item_id', async () => { + // create a simple exception list + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + // eslint-disable-next-line @typescript-eslint/naming-convention + const { item_id, ...itemNoId } = getCreateExceptionListItemMinimalSchemaMock(); + + // create a simple exception list item + const { body: createListBody } = await supertest + .post(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(itemNoId) + .expect(200); + + // update a exception list item's name + const updatedList: UpdateExceptionListItemSchema = { + ...getUpdateMinimalExceptionListItemSchemaMock(), + item_id: createListBody.item_id, + name: 'some other name', + }; + + const { body } = await supertest + .put(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(updatedList) + .expect(200); + + const outputList: Partial = { + ...getExceptionListItemResponseMockWithoutAutoGeneratedValues(), + name: 'some other name', + item_id: body.item_id, + }; + const bodyToCompare = removeExceptionListServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(outputList); + }); + + it('should give a 404 if it is given a fake exception list item id', async () => { + const updatedList: UpdateExceptionListItemSchema = { + ...getUpdateMinimalExceptionListItemSchemaMock(), + id: '5096dec6-b6b9-4d8d-8f93-6c2602079d9d', + }; + delete updatedList.item_id; + + const { body } = await supertest + .put(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(updatedList) + .expect(404); + + expect(body).to.eql({ + status_code: 404, + message: 'exception list item id: "5096dec6-b6b9-4d8d-8f93-6c2602079d9d" does not exist', + }); + }); + + it('should give a 404 if it is given a fake item_id', async () => { + const updatedList: UpdateExceptionListItemSchema = { + ...getUpdateMinimalExceptionListItemSchemaMock(), + item_id: '5096dec6-b6b9-4d8d-8f93-6c2602079d9d', + }; + + const { body } = await supertest + .put(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(updatedList) + .expect(404); + + expect(body).to.eql({ + status_code: 404, + message: + 'exception list item item_id: "5096dec6-b6b9-4d8d-8f93-6c2602079d9d" does not exist', + }); + }); + + it('should give a 404 if both id and list_id is null', async () => { + // eslint-disable-next-line @typescript-eslint/naming-convention + const { item_id, ...listNoId } = getUpdateMinimalExceptionListItemSchemaMock(); + + const { body } = await supertest + .put(EXCEPTION_LIST_ITEM_URL) + .set('kbn-xsrf', 'true') + .send(listNoId) + .expect(404); + + expect(body).to.eql({ + status_code: 404, + message: 'either id or item_id need to be defined', + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_lists.ts new file mode 100644 index 0000000000000..bd30dd87963ed --- /dev/null +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_lists.ts @@ -0,0 +1,182 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; + +import { getExceptionResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/exception_list_schema.mock'; +import { getCreateExceptionListMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { EXCEPTION_LIST_URL } from '../../../../plugins/lists/common/constants'; + +import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../utils'; +import { + UpdateExceptionListSchema, + ExceptionListSchema, +} from '../../../../plugins/lists/common/schemas'; + +import { getUpdateMinimalExceptionListSchemaMock } from '../../../../plugins/lists/common/schemas/request/update_exception_list_schema.mock'; + +// eslint-disable-next-line import/no-default-export +export default ({ getService }: FtrProviderContext) => { + const supertest = getService('supertest'); + const es = getService('es'); + + describe('update_exception_lists', () => { + describe('update exception lists', () => { + afterEach(async () => { + await deleteAllExceptions(es); + }); + + it('should update a single exception list property of name using an id', async () => { + // create a simple exception list + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + // update a exception list's name + const updatedList: UpdateExceptionListSchema = { + ...getUpdateMinimalExceptionListSchemaMock(), + name: 'some other name', + }; + + const { body } = await supertest + .put(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(updatedList) + .expect(200); + + const outputList: Partial = { + ...getExceptionResponseMockWithoutAutoGeneratedValues(), + name: 'some other name', + version: 2, + }; + const bodyToCompare = removeExceptionListServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(outputList); + }); + + it('should update a single exception list property of name using an auto-generated list_id', async () => { + // eslint-disable-next-line @typescript-eslint/naming-convention + const { list_id, ...listNoId } = getCreateExceptionListMinimalSchemaMock(); + + // create a simple exception list + const { body: createListBody } = await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(listNoId) + .expect(200); + + // update a exception list's name + const updatedList: UpdateExceptionListSchema = { + ...getUpdateMinimalExceptionListSchemaMock(), + id: createListBody.id, + name: 'some other name', + }; + + const { body } = await supertest + .put(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(updatedList) + .expect(200); + + const outputList: Partial = { + ...getExceptionResponseMockWithoutAutoGeneratedValues(), + name: 'some other name', + list_id: body.list_id, + version: 2, + }; + const bodyToCompare = removeExceptionListServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(outputList); + }); + + it('should change the version of a list when it updates two properties', async () => { + // create a simple exception list + await supertest + .post(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(getCreateExceptionListMinimalSchemaMock()) + .expect(200); + + // update a simple exception list property of name and description + // update a exception list's name + const updatedList: UpdateExceptionListSchema = { + ...getUpdateMinimalExceptionListSchemaMock(), + name: 'some other name', + description: 'some other description', + }; + + const { body } = await supertest + .put(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(updatedList) + .expect(200); + + const outputList: Partial = { + ...getExceptionResponseMockWithoutAutoGeneratedValues(), + name: 'some other name', + description: 'some other description', + version: 2, + }; + const bodyToCompare = removeExceptionListServerGeneratedProperties(body); + expect(bodyToCompare).to.eql(outputList); + }); + + it('should give a 404 if it is given a fake id', async () => { + const updatedList: UpdateExceptionListSchema = { + ...getUpdateMinimalExceptionListSchemaMock(), + id: '5096dec6-b6b9-4d8d-8f93-6c2602079d9d', + }; + delete updatedList.list_id; + + const { body } = await supertest + .put(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(updatedList) + .expect(404); + + expect(body).to.eql({ + status_code: 404, + message: 'exception list id: "5096dec6-b6b9-4d8d-8f93-6c2602079d9d" does not exist', + }); + }); + + it('should give a 404 if it is given a fake list_id', async () => { + const updatedList: UpdateExceptionListSchema = { + ...getUpdateMinimalExceptionListSchemaMock(), + list_id: '5096dec6-b6b9-4d8d-8f93-6c2602079d9d', + }; + + const { body } = await supertest + .put(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(updatedList) + .expect(404); + + expect(body).to.eql({ + status_code: 404, + message: 'exception list list_id: "5096dec6-b6b9-4d8d-8f93-6c2602079d9d" does not exist', + }); + }); + + it('should give a 404 if both id and list_id is null', async () => { + // eslint-disable-next-line @typescript-eslint/naming-convention + const { list_id, ...listNoId } = getUpdateMinimalExceptionListSchemaMock(); + + const { body } = await supertest + .put(EXCEPTION_LIST_URL) + .set('kbn-xsrf', 'true') + .send(listNoId) + .expect(404); + + expect(body).to.eql({ + status_code: 404, + message: 'either id or list_id need to be defined', + }); + }); + }); + }); +}; diff --git a/x-pack/test/lists_api_integration/utils.ts b/x-pack/test/lists_api_integration/utils.ts index 272768fdf50b3..54a13fc027c99 100644 --- a/x-pack/test/lists_api_integration/utils.ts +++ b/x-pack/test/lists_api_integration/utils.ts @@ -6,8 +6,13 @@ import { SuperTest } from 'supertest'; import supertestAsPromised from 'supertest-as-promised'; +import { Client } from '@elastic/elasticsearch'; -import { ListItemSchema } from '../../plugins/lists/common/schemas'; +import { + ListItemSchema, + ExceptionListSchema, + ExceptionListItemSchema, +} from '../../plugins/lists/common/schemas'; import { ListSchema } from '../../plugins/lists/common'; import { LIST_INDEX } from '../../plugins/lists/common/constants'; @@ -83,6 +88,30 @@ export const removeListItemServerGeneratedProperties = ( return removedProperties; }; +/** + * This will remove server generated properties such as date times, etc... + * @param list List to pass in to remove typical server generated properties + */ +export const removeExceptionListItemServerGeneratedProperties = ( + list: Partial +): Partial => { + /* eslint-disable-next-line @typescript-eslint/naming-convention */ + const { created_at, updated_at, id, tie_breaker_id, _version, ...removedProperties } = list; + return removedProperties; +}; + +/** + * This will remove server generated properties such as date times, etc... + * @param list List to pass in to remove typical server generated properties + */ +export const removeExceptionListServerGeneratedProperties = ( + list: Partial +): Partial => { + /* eslint-disable-next-line @typescript-eslint/naming-convention */ + const { created_at, updated_at, id, tie_breaker_id, _version, ...removedProperties } = list; + return removedProperties; +}; + // Similar to ReactJs's waitFor from here: https://testing-library.com/docs/dom-testing-library/api-async#waitfor export const waitFor = async ( functionToTest: () => Promise, @@ -124,3 +153,32 @@ export const binaryToString = (res: any, callback: any): void => { callback(null, Buffer.from(res.data)); }); }; + +/** + * Remove all exceptions from the .kibana index + * This will retry 20 times before giving up and hopefully still not interfere with other tests + * @param es The ElasticSearch handle + */ +export const deleteAllExceptions = async (es: Client, retryCount = 20): Promise => { + if (retryCount > 0) { + try { + await es.deleteByQuery({ + index: '.kibana', + q: 'type:exception-list or type:exception-list-agnostic', + wait_for_completion: true, + refresh: true, + body: {}, + }); + } catch (err) { + // eslint-disable-next-line no-console + console.log( + `Failure trying to deleteAllExceptions, retries left are: ${retryCount - 1}`, + err + ); + await deleteAllExceptions(es, retryCount - 1); + } + } else { + // eslint-disable-next-line no-console + console.log('Could not deleteAllExceptions, no retries are left'); + } +}; From b249af128ee73a1be0669f77a1e5c6c8bbceefc2 Mon Sep 17 00:00:00 2001 From: Walter Rafelsberger Date: Thu, 13 Aug 2020 09:38:15 +0200 Subject: [PATCH 11/53] Use jest.useFakeTimers instead of hard coded timeout for tooltip tests. (#74642) Refactor to use jest.useFakeTimers(). --- .../field_title_bar/field_title_bar.test.js | 31 +++++++++++++------ .../field_type_icon/field_type_icon.test.js | 19 ++++++++++-- .../configure_cases/button.test.tsx | 18 +++++++---- 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/x-pack/plugins/ml/public/application/components/field_title_bar/field_title_bar.test.js b/x-pack/plugins/ml/public/application/components/field_title_bar/field_title_bar.test.js index 1b33d68042295..329863fdc9986 100644 --- a/x-pack/plugins/ml/public/application/components/field_title_bar/field_title_bar.test.js +++ b/x-pack/plugins/ml/public/application/components/field_title_bar/field_title_bar.test.js @@ -62,7 +62,10 @@ describe('FieldTitleBar', () => { expect(hasClassName).toBeTruthy(); }); - test(`tooltip hovering`, (done) => { + test(`tooltip hovering`, () => { + // Use fake timers so we don't have to wait for the EuiToolTip timeout + jest.useFakeTimers(); + const props = { card: { fieldName: 'foo', type: 'bar' } }; const wrapper = mountWithIntl(); const container = wrapper.find({ className: 'field-name' }); @@ -70,14 +73,22 @@ describe('FieldTitleBar', () => { expect(wrapper.find('EuiToolTip').children()).toHaveLength(1); container.simulate('mouseover'); - // EuiToolTip mounts children after a 250ms delay - setTimeout(() => { - wrapper.update(); - expect(wrapper.find('EuiToolTip').children()).toHaveLength(2); - container.simulate('mouseout'); - wrapper.update(); - expect(wrapper.find('EuiToolTip').children()).toHaveLength(1); - done(); - }, 250); + + // Run the timers so the EuiTooltip will be visible + jest.runAllTimers(); + + wrapper.update(); + expect(wrapper.find('EuiToolTip').children()).toHaveLength(2); + + container.simulate('mouseout'); + + // Run the timers so the EuiTooltip will be hidden again + jest.runAllTimers(); + + wrapper.update(); + expect(wrapper.find('EuiToolTip').children()).toHaveLength(1); + + // Clearing all mocks will also reset fake timers. + jest.clearAllMocks(); }); }); diff --git a/x-pack/plugins/ml/public/application/components/field_type_icon/field_type_icon.test.js b/x-pack/plugins/ml/public/application/components/field_type_icon/field_type_icon.test.js index 7e37dc10ade33..d4200c2f8366b 100644 --- a/x-pack/plugins/ml/public/application/components/field_type_icon/field_type_icon.test.js +++ b/x-pack/plugins/ml/public/application/components/field_type_icon/field_type_icon.test.js @@ -27,6 +27,9 @@ describe('FieldTypeIcon', () => { }); test(`render with tooltip and test hovering`, () => { + // Use fake timers so we don't have to wait for the EuiToolTip timeout + jest.useFakeTimers(); + const typeIconComponent = mount( ); @@ -35,11 +38,23 @@ describe('FieldTypeIcon', () => { expect(typeIconComponent.find('EuiToolTip').children()).toHaveLength(1); container.simulate('mouseover'); - // EuiToolTip mounts children after a 250ms delay - setTimeout(() => expect(typeIconComponent.find('EuiToolTip').children()).toHaveLength(2), 250); + + // Run the timers so the EuiTooltip will be visible + jest.runAllTimers(); + + typeIconComponent.update(); + expect(typeIconComponent.find('EuiToolTip').children()).toHaveLength(2); container.simulate('mouseout'); + + // Run the timers so the EuiTooltip will be hidden again + jest.runAllTimers(); + + typeIconComponent.update(); expect(typeIconComponent.find('EuiToolTip').children()).toHaveLength(1); + + // Clearing all mocks will also reset fake timers. + jest.clearAllMocks(); }); test(`update component`, () => { diff --git a/x-pack/plugins/security_solution/public/cases/components/configure_cases/button.test.tsx b/x-pack/plugins/security_solution/public/cases/components/configure_cases/button.test.tsx index 6fb693e47560d..56daa9a8364f6 100644 --- a/x-pack/plugins/security_solution/public/cases/components/configure_cases/button.test.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/configure_cases/button.test.tsx @@ -80,6 +80,9 @@ describe('Configuration button', () => { }); test('it shows the tooltip when hovering the button', () => { + // Use fake timers so we don't have to wait for the EuiToolTip timeout + jest.useFakeTimers(); + const msgTooltip = 'My message tooltip'; const titleTooltip = 'My title'; @@ -96,11 +99,14 @@ describe('Configuration button', () => { ); newWrapper.find('[data-test-subj="configure-case-button"]').first().simulate('mouseOver'); - // EuiToolTip mounts children after a 250ms delay - setTimeout( - () => - expect(newWrapper.find('.euiToolTipPopover').text()).toBe(`${titleTooltip}${msgTooltip}`), - 250 - ); + + // Run the timers so the EuiTooltip will be visible + jest.runAllTimers(); + + newWrapper.update(); + expect(newWrapper.find('.euiToolTipPopover').text()).toBe(`${titleTooltip}${msgTooltip}`); + + // Clearing all mocks will also reset fake timers. + jest.clearAllMocks(); }); }); From 290f9bfde20cc6f689803afd0efbc158fdbbc5d8 Mon Sep 17 00:00:00 2001 From: Liza Katz Date: Thu, 13 Aug 2020 11:28:39 +0300 Subject: [PATCH 12/53] Data plugin: Suggested enhance pattern (#74505) * improve test stability * Enhance pattern * fix tests * fix test * Rename enhance to __enhance * Deleted unnecessary attribute * ISearchInterceptor interface * docs * Clean up internal docs * jest Co-authored-by: Elastic Machine --- ...ublic.searchinterceptor.abortcontroller.md | 13 ----- ...blic.searchinterceptor.getpendingcount_.md | 8 ++- ...data-public.searchinterceptor.hidetoast.md | 11 ---- ...blic.searchinterceptor.longrunningtoast.md | 13 ----- ...n-plugins-data-public.searchinterceptor.md | 11 +--- ...a-public.searchinterceptor.pendingcount.md | 13 ----- ...-public.searchinterceptor.pendingcount_.md | 13 ----- ...ns-data-public.searchinterceptor.search.md | 2 +- ...data-public.searchinterceptor.showtoast.md | 11 ---- ....searchinterceptor.timeoutsubscriptions.md | 13 ----- ...-data-public.searchinterceptordeps.http.md | 2 +- ...ugins-data-public.searchinterceptordeps.md | 8 +-- ...ic.searchinterceptordeps.startservices.md} | 6 +-- ...ata-public.searchinterceptordeps.toasts.md | 2 +- ...public.searchinterceptordeps.uisettings.md | 2 +- src/plugins/data/public/mocks.ts | 1 + src/plugins/data/public/plugin.ts | 18 ++++--- src/plugins/data/public/public.api.md | 35 ++++++++----- src/plugins/data/public/search/index.ts | 9 +++- src/plugins/data/public/search/mocks.ts | 2 +- .../public/search/search_interceptor.test.ts | 28 +++++------ .../data/public/search/search_interceptor.ts | 50 ++++++++++++------- .../data/public/search/search_service.test.ts | 2 +- .../data/public/search/search_service.ts | 35 +++++++------ src/plugins/data/public/search/types.ts | 16 ++++-- src/plugins/data/public/types.ts | 10 +++- x-pack/plugins/data_enhanced/public/plugin.ts | 18 ++++--- .../public/search/search_interceptor.test.ts | 48 +++++++++++------- .../public/search/search_interceptor.ts | 7 ++- 29 files changed, 194 insertions(+), 213 deletions(-) delete mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.abortcontroller.md delete mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.hidetoast.md delete mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.longrunningtoast.md delete mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.pendingcount.md delete mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.pendingcount_.md delete mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.showtoast.md delete mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.timeoutsubscriptions.md rename docs/development/plugins/data/public/{kibana-plugin-plugins-data-public.searchinterceptordeps.application.md => kibana-plugin-plugins-data-public.searchinterceptordeps.startservices.md} (61%) diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.abortcontroller.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.abortcontroller.md deleted file mode 100644 index 0451a2254dc40..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.abortcontroller.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchInterceptor](./kibana-plugin-plugins-data-public.searchinterceptor.md) > [abortController](./kibana-plugin-plugins-data-public.searchinterceptor.abortcontroller.md) - -## SearchInterceptor.abortController property - -`abortController` used to signal all searches to abort. - -Signature: - -```typescript -protected abortController: AbortController; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.getpendingcount_.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.getpendingcount_.md index db2c5d6957ad7..ef36b3f37b0c7 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.getpendingcount_.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.getpendingcount_.md @@ -2,12 +2,16 @@ [Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchInterceptor](./kibana-plugin-plugins-data-public.searchinterceptor.md) > [getPendingCount$](./kibana-plugin-plugins-data-public.searchinterceptor.getpendingcount_.md) -## SearchInterceptor.getPendingCount$ property +## SearchInterceptor.getPendingCount$() method Returns an `Observable` over the current number of pending searches. This could mean that one of the search requests is still in flight, or that it has only received partial responses. Signature: ```typescript -getPendingCount$: () => Observable; +getPendingCount$(): Observable; ``` +Returns: + +`Observable` + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.hidetoast.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.hidetoast.md deleted file mode 100644 index 59938a755a99e..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.hidetoast.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchInterceptor](./kibana-plugin-plugins-data-public.searchinterceptor.md) > [hideToast](./kibana-plugin-plugins-data-public.searchinterceptor.hidetoast.md) - -## SearchInterceptor.hideToast property - -Signature: - -```typescript -protected hideToast: () => void; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.longrunningtoast.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.longrunningtoast.md deleted file mode 100644 index 5799039de91bc..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.longrunningtoast.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchInterceptor](./kibana-plugin-plugins-data-public.searchinterceptor.md) > [longRunningToast](./kibana-plugin-plugins-data-public.searchinterceptor.longrunningtoast.md) - -## SearchInterceptor.longRunningToast property - -The current long-running toast (if there is one). - -Signature: - -```typescript -protected longRunningToast?: Toast; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.md index b3b7da05326d0..32954927504ae 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.md @@ -20,22 +20,15 @@ export declare class SearchInterceptor | Property | Modifiers | Type | Description | | --- | --- | --- | --- | -| [abortController](./kibana-plugin-plugins-data-public.searchinterceptor.abortcontroller.md) | | AbortController | abortController used to signal all searches to abort. | | [deps](./kibana-plugin-plugins-data-public.searchinterceptor.deps.md) | | SearchInterceptorDeps | | -| [getPendingCount$](./kibana-plugin-plugins-data-public.searchinterceptor.getpendingcount_.md) | | () => Observable<number> | Returns an Observable over the current number of pending searches. This could mean that one of the search requests is still in flight, or that it has only received partial responses. | -| [hideToast](./kibana-plugin-plugins-data-public.searchinterceptor.hidetoast.md) | | () => void | | -| [longRunningToast](./kibana-plugin-plugins-data-public.searchinterceptor.longrunningtoast.md) | | Toast | The current long-running toast (if there is one). | -| [pendingCount](./kibana-plugin-plugins-data-public.searchinterceptor.pendingcount.md) | | number | The number of pending search requests. | -| [pendingCount$](./kibana-plugin-plugins-data-public.searchinterceptor.pendingcount_.md) | | BehaviorSubject<number> | Observable that emits when the number of pending requests changes. | | [requestTimeout](./kibana-plugin-plugins-data-public.searchinterceptor.requesttimeout.md) | | number | undefined | | -| [showToast](./kibana-plugin-plugins-data-public.searchinterceptor.showtoast.md) | | () => void | | -| [timeoutSubscriptions](./kibana-plugin-plugins-data-public.searchinterceptor.timeoutsubscriptions.md) | | Subscription | The subscriptions from scheduling the automatic timeout for each request. | ## Methods | Method | Modifiers | Description | | --- | --- | --- | +| [getPendingCount$()](./kibana-plugin-plugins-data-public.searchinterceptor.getpendingcount_.md) | | Returns an Observable over the current number of pending searches. This could mean that one of the search requests is still in flight, or that it has only received partial responses. | | [runSearch(request, signal, strategy)](./kibana-plugin-plugins-data-public.searchinterceptor.runsearch.md) | | | -| [search(request, options)](./kibana-plugin-plugins-data-public.searchinterceptor.search.md) | | Searches using the given search method. Overrides the AbortSignal with one that will abort either when cancelPending is called, when the request times out, or when the original AbortSignal is aborted. Updates the pendingCount when the request is started/finalized. | +| [search(request, options)](./kibana-plugin-plugins-data-public.searchinterceptor.search.md) | | Searches using the given search method. Overrides the AbortSignal with one that will abort either when cancelPending is called, when the request times out, or when the original AbortSignal is aborted. Updates pendingCount$ when the request is started/finalized. | | [setupTimers(options)](./kibana-plugin-plugins-data-public.searchinterceptor.setuptimers.md) | | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.pendingcount.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.pendingcount.md deleted file mode 100644 index 7dd2bd3e6703f..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.pendingcount.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchInterceptor](./kibana-plugin-plugins-data-public.searchinterceptor.md) > [pendingCount](./kibana-plugin-plugins-data-public.searchinterceptor.pendingcount.md) - -## SearchInterceptor.pendingCount property - -The number of pending search requests. - -Signature: - -```typescript -protected pendingCount: number; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.pendingcount_.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.pendingcount_.md deleted file mode 100644 index dad0fca0bfe08..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.pendingcount_.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchInterceptor](./kibana-plugin-plugins-data-public.searchinterceptor.md) > [pendingCount$](./kibana-plugin-plugins-data-public.searchinterceptor.pendingcount_.md) - -## SearchInterceptor.pendingCount$ property - -Observable that emits when the number of pending requests changes. - -Signature: - -```typescript -protected pendingCount$: BehaviorSubject; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.search.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.search.md index 38ddda7b4e184..1752d183a8737 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.search.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.search.md @@ -4,7 +4,7 @@ ## SearchInterceptor.search() method -Searches using the given `search` method. Overrides the `AbortSignal` with one that will abort either when `cancelPending` is called, when the request times out, or when the original `AbortSignal` is aborted. Updates the `pendingCount` when the request is started/finalized. +Searches using the given `search` method. Overrides the `AbortSignal` with one that will abort either when `cancelPending` is called, when the request times out, or when the original `AbortSignal` is aborted. Updates `pendingCount$` when the request is started/finalized. Signature: diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.showtoast.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.showtoast.md deleted file mode 100644 index e495c72b57215..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.showtoast.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchInterceptor](./kibana-plugin-plugins-data-public.searchinterceptor.md) > [showToast](./kibana-plugin-plugins-data-public.searchinterceptor.showtoast.md) - -## SearchInterceptor.showToast property - -Signature: - -```typescript -protected showToast: () => void; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.timeoutsubscriptions.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.timeoutsubscriptions.md deleted file mode 100644 index 12f200e037784..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.timeoutsubscriptions.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchInterceptor](./kibana-plugin-plugins-data-public.searchinterceptor.md) > [timeoutSubscriptions](./kibana-plugin-plugins-data-public.searchinterceptor.timeoutsubscriptions.md) - -## SearchInterceptor.timeoutSubscriptions property - -The subscriptions from scheduling the automatic timeout for each request. - -Signature: - -```typescript -protected timeoutSubscriptions: Subscription; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.http.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.http.md index 1146179c13d63..66c31bb6fcf80 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.http.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.http.md @@ -7,5 +7,5 @@ Signature: ```typescript -http: CoreStart['http']; +http: CoreSetup['http']; ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.md index 1291af5359887..63eb67ce48246 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.md @@ -14,9 +14,9 @@ export interface SearchInterceptorDeps | Property | Type | Description | | --- | --- | --- | -| [application](./kibana-plugin-plugins-data-public.searchinterceptordeps.application.md) | ApplicationStart | | -| [http](./kibana-plugin-plugins-data-public.searchinterceptordeps.http.md) | CoreStart['http'] | | -| [toasts](./kibana-plugin-plugins-data-public.searchinterceptordeps.toasts.md) | ToastsStart | | -| [uiSettings](./kibana-plugin-plugins-data-public.searchinterceptordeps.uisettings.md) | CoreStart['uiSettings'] | | +| [http](./kibana-plugin-plugins-data-public.searchinterceptordeps.http.md) | CoreSetup['http'] | | +| [startServices](./kibana-plugin-plugins-data-public.searchinterceptordeps.startservices.md) | Promise<[CoreStart, any, unknown]> | | +| [toasts](./kibana-plugin-plugins-data-public.searchinterceptordeps.toasts.md) | ToastsSetup | | +| [uiSettings](./kibana-plugin-plugins-data-public.searchinterceptordeps.uisettings.md) | CoreSetup['uiSettings'] | | | [usageCollector](./kibana-plugin-plugins-data-public.searchinterceptordeps.usagecollector.md) | SearchUsageCollector | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.application.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.startservices.md similarity index 61% rename from docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.application.md rename to docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.startservices.md index a8cd1b170a595..855d0652058b8 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.application.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.startservices.md @@ -1,11 +1,11 @@ -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchInterceptorDeps](./kibana-plugin-plugins-data-public.searchinterceptordeps.md) > [application](./kibana-plugin-plugins-data-public.searchinterceptordeps.application.md) +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchInterceptorDeps](./kibana-plugin-plugins-data-public.searchinterceptordeps.md) > [startServices](./kibana-plugin-plugins-data-public.searchinterceptordeps.startservices.md) -## SearchInterceptorDeps.application property +## SearchInterceptorDeps.startServices property Signature: ```typescript -application: ApplicationStart; +startServices: Promise<[CoreStart, any, unknown]>; ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.toasts.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.toasts.md index 0023b34af10c3..1f560dfa5cf7c 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.toasts.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.toasts.md @@ -7,5 +7,5 @@ Signature: ```typescript -toasts: ToastsStart; +toasts: ToastsSetup; ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.uisettings.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.uisettings.md index 425e177ec9300..a34d223c34ac2 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.uisettings.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptordeps.uisettings.md @@ -7,5 +7,5 @@ Signature: ```typescript -uiSettings: CoreStart['uiSettings']; +uiSettings: CoreSetup['uiSettings']; ``` diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts index 135b6121d1dd5..3fc1e6454829d 100644 --- a/src/plugins/data/public/mocks.ts +++ b/src/plugins/data/public/mocks.ts @@ -44,6 +44,7 @@ const createSetupContract = (): Setup => { search: searchServiceMock.createSetupContract(), fieldFormats: fieldFormatsServiceMock.createSetupContract(), query: querySetupMock, + __enhance: jest.fn(), }; }; diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 68c0f506f121d..e950434b287a7 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -34,6 +34,7 @@ import { DataSetupDependencies, DataStartDependencies, InternalStartServices, + DataPublicPluginEnhancements, } from './types'; import { AutocompleteService } from './autocomplete'; import { SearchService } from './search/search_service'; @@ -156,16 +157,21 @@ export class DataPublicPlugin })) ); + const searchService = this.searchService.setup(core, { + expressions, + usageCollection, + getInternalStartServices, + packageInfo: this.packageInfo, + }); + return { autocomplete: this.autocomplete.setup(core), - search: this.searchService.setup(core, { - expressions, - usageCollection, - getInternalStartServices, - packageInfo: this.packageInfo, - }), + search: searchService, fieldFormats: this.fieldFormatsService.setup(core), query: queryService, + __enhance: (enhancements: DataPublicPluginEnhancements) => { + searchService.__enhance(enhancements.search); + }, }; } diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 6225d74fb1b31..a61334905e9f5 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -8,12 +8,12 @@ import { $Values } from '@kbn/utility-types'; import _ from 'lodash'; import { Action } from 'history'; import { ApiResponse } from '@elastic/elasticsearch/lib/Transport'; -import { ApplicationStart } from 'kibana/public'; import { Assign } from '@kbn/utility-types'; import { BehaviorSubject } from 'rxjs'; import Boom from 'boom'; import { Component } from 'react'; import { CoreSetup } from 'src/core/public'; +import { CoreSetup as CoreSetup_2 } from 'kibana/public'; import { CoreStart } from 'kibana/public'; import { CoreStart as CoreStart_2 } from 'src/core/public'; import { Ensure } from '@kbn/utility-types'; @@ -65,7 +65,7 @@ import { SerializedFieldFormat as SerializedFieldFormat_2 } from 'src/plugins/ex import { Subscription } from 'rxjs'; import { Toast } from 'kibana/public'; import { ToastInputFields } from 'src/core/public/notifications'; -import { ToastsStart } from 'kibana/public'; +import { ToastsSetup } from 'kibana/public'; import { TransportRequestOptions } from '@elastic/elasticsearch/lib/Transport'; import { TransportRequestParams } from '@elastic/elasticsearch/lib/Transport'; import { TransportRequestPromise } from '@elastic/elasticsearch/lib/Transport'; @@ -222,6 +222,10 @@ export type CustomFilter = Filter & { // // @public (undocumented) export interface DataPublicPluginSetup { + // Warning: (ae-forgotten-export) The symbol "DataPublicPluginEnhancements" needs to be exported by the entry point index.d.ts + // + // @internal (undocumented) + __enhance: (enhancements: DataPublicPluginEnhancements) => void; // Warning: (ae-forgotten-export) The symbol "AutocompleteSetup" needs to be exported by the entry point index.d.ts // // (undocumented) @@ -1714,15 +1718,19 @@ export interface SearchError { // @public (undocumented) export class SearchInterceptor { constructor(deps: SearchInterceptorDeps, requestTimeout?: number | undefined); + // @internal protected abortController: AbortController; + // @internal (undocumented) + protected application: CoreStart['application']; // (undocumented) protected readonly deps: SearchInterceptorDeps; - getPendingCount$: () => Observable; - // (undocumented) + getPendingCount$(): Observable; + // @internal (undocumented) protected hideToast: () => void; + // @internal protected longRunningToast?: Toast; + // @internal protected pendingCount$: BehaviorSubject; - protected pendingCount: number; // (undocumented) protected readonly requestTimeout?: number | undefined; // (undocumented) @@ -1733,8 +1741,9 @@ export class SearchInterceptor { combinedSignal: AbortSignal; cleanup: () => void; }; - // (undocumented) + // @internal (undocumented) protected showToast: () => void; + // @internal protected timeoutSubscriptions: Subscription; } @@ -1743,13 +1752,13 @@ export class SearchInterceptor { // @public (undocumented) export interface SearchInterceptorDeps { // (undocumented) - application: ApplicationStart; + http: CoreSetup_2['http']; // (undocumented) - http: CoreStart['http']; + startServices: Promise<[CoreStart, any, unknown]>; // (undocumented) - toasts: ToastsStart; + toasts: ToastsSetup; // (undocumented) - uiSettings: CoreStart['uiSettings']; + uiSettings: CoreSetup_2['uiSettings']; // Warning: (ae-forgotten-export) The symbol "SearchUsageCollector" needs to be exported by the entry point index.d.ts // // (undocumented) @@ -1980,9 +1989,9 @@ export const UI_SETTINGS: { // src/plugins/data/public/index.ts:393:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:396:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:45:5 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/types.ts:54:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickAction" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/types.ts:55:5 - (ae-forgotten-export) The symbol "createFiltersFromRangeSelectAction" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/types.ts:63:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/types.ts:62:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickAction" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/types.ts:63:5 - (ae-forgotten-export) The symbol "createFiltersFromRangeSelectAction" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/types.ts:71:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/src/plugins/data/public/search/index.ts b/src/plugins/data/public/search/index.ts index 96445e5367147..ae028df31e401 100644 --- a/src/plugins/data/public/search/index.ts +++ b/src/plugins/data/public/search/index.ts @@ -21,7 +21,14 @@ export * from './aggs'; export * from './expressions'; export * from './tabify'; -export { ISearch, ISearchOptions, ISearchGeneric, ISearchSetup, ISearchStart } from './types'; +export { + ISearch, + ISearchOptions, + ISearchGeneric, + ISearchSetup, + ISearchStart, + SearchEnhancements, +} from './types'; export { IEsSearchResponse, IEsSearchRequest, ES_SEARCH_STRATEGY } from '../../common/search'; diff --git a/src/plugins/data/public/search/mocks.ts b/src/plugins/data/public/search/mocks.ts index c56331baffed2..8ccf46fe7c97d 100644 --- a/src/plugins/data/public/search/mocks.ts +++ b/src/plugins/data/public/search/mocks.ts @@ -26,13 +26,13 @@ export * from './search_source/mocks'; function createSetupContract(): jest.Mocked { return { aggs: searchAggsSetupMock(), + __enhance: jest.fn(), }; } function createStartContract(): jest.Mocked { return { aggs: searchAggsStartMock(), - setInterceptor: jest.fn(), search: jest.fn(), searchSource: searchSourceMock, __LEGACY: { diff --git a/src/plugins/data/public/search/search_interceptor.test.ts b/src/plugins/data/public/search/search_interceptor.test.ts index f4c5de2bcaf31..2eded17bda88c 100644 --- a/src/plugins/data/public/search/search_interceptor.test.ts +++ b/src/plugins/data/public/search/search_interceptor.test.ts @@ -17,27 +17,27 @@ * under the License. */ -import { CoreStart } from '../../../../core/public'; +import { CoreSetup } from '../../../../core/public'; import { coreMock } from '../../../../core/public/mocks'; import { IEsSearchRequest } from '../../common/search'; import { SearchInterceptor } from './search_interceptor'; import { AbortError } from '../../common'; let searchInterceptor: SearchInterceptor; -let mockCoreStart: MockedKeys; +let mockCoreSetup: MockedKeys; const flushPromises = () => new Promise((resolve) => setImmediate(resolve)); jest.useFakeTimers(); describe('SearchInterceptor', () => { beforeEach(() => { - mockCoreStart = coreMock.createStart(); + mockCoreSetup = coreMock.createSetup(); searchInterceptor = new SearchInterceptor( { - toasts: mockCoreStart.notifications.toasts, - application: mockCoreStart.application, - uiSettings: mockCoreStart.uiSettings, - http: mockCoreStart.http, + toasts: mockCoreSetup.notifications.toasts, + startServices: mockCoreSetup.getStartServices(), + uiSettings: mockCoreSetup.uiSettings, + http: mockCoreSetup.http, }, 1000 ); @@ -46,7 +46,7 @@ describe('SearchInterceptor', () => { describe('search', () => { test('Observable should resolve if fetch is successful', async () => { const mockResponse: any = { result: 200 }; - mockCoreStart.http.fetch.mockResolvedValueOnce(mockResponse); + mockCoreSetup.http.fetch.mockResolvedValueOnce(mockResponse); const mockRequest: IEsSearchRequest = { params: {}, }; @@ -58,7 +58,7 @@ describe('SearchInterceptor', () => { test('Observable should fail if fetch has an error', async () => { const mockResponse: any = { result: 500 }; - mockCoreStart.http.fetch.mockRejectedValueOnce(mockResponse); + mockCoreSetup.http.fetch.mockRejectedValueOnce(mockResponse); const mockRequest: IEsSearchRequest = { params: {}, }; @@ -72,7 +72,7 @@ describe('SearchInterceptor', () => { }); test('Observable should fail if fetch times out (test merged signal)', async () => { - mockCoreStart.http.fetch.mockImplementationOnce((options: any) => { + mockCoreSetup.http.fetch.mockImplementationOnce((options: any) => { return new Promise((resolve, reject) => { options.signal.addEventListener('abort', () => { reject(new AbortError()); @@ -100,7 +100,7 @@ describe('SearchInterceptor', () => { test('Observable should fail if user aborts (test merged signal)', async () => { const abortController = new AbortController(); - mockCoreStart.http.fetch.mockImplementationOnce((options: any) => { + mockCoreSetup.http.fetch.mockImplementationOnce((options: any) => { return new Promise((resolve, reject) => { options.signal.addEventListener('abort', () => { reject(new AbortError()); @@ -136,7 +136,7 @@ describe('SearchInterceptor', () => { const error = (e: any) => { expect(e).toBeInstanceOf(AbortError); - expect(mockCoreStart.http.fetch).not.toBeCalled(); + expect(mockCoreSetup.http.fetch).not.toBeCalled(); done(); }; response.subscribe({ error }); @@ -150,7 +150,7 @@ describe('SearchInterceptor', () => { pendingCount$.subscribe(pendingNext); const mockResponse: any = { result: 200 }; - mockCoreStart.http.fetch.mockResolvedValue(mockResponse); + mockCoreSetup.http.fetch.mockResolvedValue(mockResponse); const mockRequest: IEsSearchRequest = { params: {}, }; @@ -169,7 +169,7 @@ describe('SearchInterceptor', () => { pendingCount$.subscribe(pendingNext); const mockResponse: any = { result: 500 }; - mockCoreStart.http.fetch.mockRejectedValue(mockResponse); + mockCoreSetup.http.fetch.mockRejectedValue(mockResponse); const mockRequest: IEsSearchRequest = { params: {}, }; diff --git a/src/plugins/data/public/search/search_interceptor.ts b/src/plugins/data/public/search/search_interceptor.ts index d6fcde8e986f3..99fccda7fddf3 100644 --- a/src/plugins/data/public/search/search_interceptor.ts +++ b/src/plugins/data/public/search/search_interceptor.ts @@ -20,7 +20,7 @@ import { trimEnd } from 'lodash'; import { BehaviorSubject, throwError, timer, Subscription, defer, from, Observable } from 'rxjs'; import { finalize, filter } from 'rxjs/operators'; -import { ApplicationStart, Toast, ToastsStart, CoreStart } from 'kibana/public'; +import { Toast, CoreStart, ToastsSetup, CoreSetup } from 'kibana/public'; import { getCombinedSignal, AbortError } from '../../common/utils'; import { IEsSearchRequest, IEsSearchResponse, ES_SEARCH_STRATEGY } from '../../common/search'; import { ISearchOptions } from './types'; @@ -30,39 +30,43 @@ import { SearchUsageCollector } from './collectors'; const LONG_QUERY_NOTIFICATION_DELAY = 10000; export interface SearchInterceptorDeps { - toasts: ToastsStart; - application: ApplicationStart; - http: CoreStart['http']; - uiSettings: CoreStart['uiSettings']; + toasts: ToastsSetup; + http: CoreSetup['http']; + uiSettings: CoreSetup['uiSettings']; + startServices: Promise<[CoreStart, any, unknown]>; usageCollector?: SearchUsageCollector; } export class SearchInterceptor { /** * `abortController` used to signal all searches to abort. + * @internal */ protected abortController = new AbortController(); - /** - * The number of pending search requests. - */ - protected pendingCount = 0; - /** * Observable that emits when the number of pending requests changes. + * @internal */ - protected pendingCount$ = new BehaviorSubject(this.pendingCount); + protected pendingCount$ = new BehaviorSubject(0); /** * The subscriptions from scheduling the automatic timeout for each request. + * @internal */ protected timeoutSubscriptions: Subscription = new Subscription(); /** * The current long-running toast (if there is one). + * @internal */ protected longRunningToast?: Toast; + /** + * @internal + */ + protected application!: CoreStart['application']; + /** * This class should be instantiated with a `requestTimeout` corresponding with how many ms after * requests are initiated that they should automatically cancel. @@ -76,6 +80,10 @@ export class SearchInterceptor { ) { this.deps.http.addLoadingCountSource(this.pendingCount$); + this.deps.startServices.then(([coreStart]) => { + this.application = coreStart.application; + }); + // When search requests go out, a notification is scheduled allowing users to continue the // request past the timeout. When all search requests complete, we remove the notification. this.getPendingCount$() @@ -87,9 +95,9 @@ export class SearchInterceptor { * Returns an `Observable` over the current number of pending searches. This could mean that one * of the search requests is still in flight, or that it has only received partial responses. */ - public getPendingCount$ = () => { + public getPendingCount$() { return this.pendingCount$.asObservable(); - }; + } protected runSearch( request: IEsSearchRequest, @@ -112,7 +120,7 @@ export class SearchInterceptor { /** * Searches using the given `search` method. Overrides the `AbortSignal` with one that will abort * either when `cancelPending` is called, when the request times out, or when the original - * `AbortSignal` is aborted. Updates the `pendingCount` when the request is started/finalized. + * `AbortSignal` is aborted. Updates `pendingCount$` when the request is started/finalized. */ public search( request: IEsSearchRequest, @@ -125,11 +133,11 @@ export class SearchInterceptor { } const { combinedSignal, cleanup } = this.setupTimers(options); - this.pendingCount$.next(++this.pendingCount); + this.pendingCount$.next(this.pendingCount$.getValue() + 1); return this.runSearch(request, combinedSignal, options?.strategy).pipe( finalize(() => { - this.pendingCount$.next(--this.pendingCount); + this.pendingCount$.next(this.pendingCount$.getValue() - 1); cleanup(); }) ); @@ -173,13 +181,16 @@ export class SearchInterceptor { }; } + /** + * @internal + */ protected showToast = () => { if (this.longRunningToast) return; this.longRunningToast = this.deps.toasts.addInfo( { title: 'Your query is taking a while', text: getLongQueryNotification({ - application: this.deps.application, + application: this.application, }), }, { @@ -188,6 +199,9 @@ export class SearchInterceptor { ); }; + /** + * @internal + */ protected hideToast = () => { if (this.longRunningToast) { this.deps.toasts.remove(this.longRunningToast); @@ -198,3 +212,5 @@ export class SearchInterceptor { } }; } + +export type ISearchInterceptor = PublicMethodsOf; diff --git a/src/plugins/data/public/search/search_service.test.ts b/src/plugins/data/public/search/search_service.test.ts index 55d31db191733..f0a017847e06a 100644 --- a/src/plugins/data/public/search/search_service.test.ts +++ b/src/plugins/data/public/search/search_service.test.ts @@ -41,6 +41,7 @@ describe('Search service', () => { expressions: expressionsPluginMock.createSetupContract(), } as any); expect(setup).toHaveProperty('aggs'); + expect(setup).toHaveProperty('__enhance'); }); }); @@ -49,7 +50,6 @@ describe('Search service', () => { const start = searchService.start(mockCoreStart, { indexPatterns: {}, } as any); - expect(start).toHaveProperty('setInterceptor'); expect(start).toHaveProperty('search'); }); }); diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index 064e16014cb70..4c94925b66d6e 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -18,7 +18,7 @@ */ import { Plugin, CoreSetup, CoreStart, PackageInfo } from '../../../../core/public'; -import { ISearchSetup, ISearchStart } from './types'; +import { ISearchSetup, ISearchStart, SearchEnhancements } from './types'; import { ExpressionsSetup } from '../../../../plugins/expressions/public'; import { createSearchSource, SearchSource, SearchSourceDependencies } from './search_source'; @@ -28,7 +28,7 @@ import { calculateBounds, TimeRange } from '../../common/query'; import { IndexPatternsContract } from '../index_patterns/index_patterns'; import { GetInternalStartServicesFn } from '../types'; -import { SearchInterceptor } from './search_interceptor'; +import { ISearchInterceptor, SearchInterceptor } from './search_interceptor'; import { getAggTypes, getAggTypesFunctions, @@ -54,7 +54,7 @@ interface SearchServiceStartDependencies { export class SearchService implements Plugin { private esClient?: LegacyApiCaller; private readonly aggTypesRegistry = new AggTypesRegistry(); - private searchInterceptor!: SearchInterceptor; + private searchInterceptor!: ISearchInterceptor; private usageCollector?: SearchUsageCollector; /** @@ -91,15 +91,6 @@ export class SearchService implements Plugin { const aggFunctions = getAggTypesFunctions(); aggFunctions.forEach((fn) => expressions.registerFunction(fn)); - return { - aggs: { - calculateAutoTimeExpression: getCalculateAutoTimeExpression(core.uiSettings), - types: aggTypesSetup, - }, - }; - } - - public start(core: CoreStart, dependencies: SearchServiceStartDependencies): ISearchStart { /** * A global object that intercepts all searches and provides convenience methods for cancelling * all pending search requests, as well as getting the number of pending search requests. @@ -109,14 +100,27 @@ export class SearchService implements Plugin { this.searchInterceptor = new SearchInterceptor( { toasts: core.notifications.toasts, - application: core.application, http: core.http, uiSettings: core.uiSettings, + startServices: core.getStartServices(), usageCollector: this.usageCollector!, }, core.injectedMetadata.getInjectedVar('esRequestTimeout') as number ); + return { + usageCollector: this.usageCollector!, + __enhance: (enhancements: SearchEnhancements) => { + this.searchInterceptor = enhancements.searchInterceptor; + }, + aggs: { + calculateAutoTimeExpression: getCalculateAutoTimeExpression(core.uiSettings), + types: aggTypesSetup, + }, + }; + } + + public start(core: CoreStart, dependencies: SearchServiceStartDependencies): ISearchStart { const aggTypesStart = this.aggTypesRegistry.start(); const search: ISearchGeneric = (request, options) => { @@ -145,17 +149,12 @@ export class SearchService implements Plugin { types: aggTypesStart, }, search, - usageCollector: this.usageCollector!, searchSource: { create: createSearchSource(dependencies.indexPatterns, searchSourceDependencies), createEmpty: () => { return new SearchSource({}, searchSourceDependencies); }, }, - setInterceptor: (searchInterceptor: SearchInterceptor) => { - // TODO: should an intercepror have a destroy method? - this.searchInterceptor = searchInterceptor; - }, __LEGACY: legacySearch, }; } diff --git a/src/plugins/data/public/search/types.ts b/src/plugins/data/public/search/types.ts index f80a13d048a68..d85d4c4e5c935 100644 --- a/src/plugins/data/public/search/types.ts +++ b/src/plugins/data/public/search/types.ts @@ -21,7 +21,7 @@ import { Observable } from 'rxjs'; import { PackageInfo } from 'kibana/server'; import { SearchAggsSetup, SearchAggsStart } from './aggs'; import { LegacyApiCaller } from './legacy/es_client'; -import { SearchInterceptor } from './search_interceptor'; +import { ISearchInterceptor } from './search_interceptor'; import { ISearchSource, SearchSourceFields } from './search_source'; import { SearchUsageCollector } from './collectors'; import { @@ -54,23 +54,33 @@ export interface ISearchStartLegacy { esClient: LegacyApiCaller; } +export interface SearchEnhancements { + searchInterceptor: ISearchInterceptor; +} /** * The setup contract exposed by the Search plugin exposes the search strategy extension * point. */ export interface ISearchSetup { aggs: SearchAggsSetup; + usageCollector?: SearchUsageCollector; + /** + * @internal + */ + __enhance: (enhancements: SearchEnhancements) => void; } export interface ISearchStart { aggs: SearchAggsStart; - setInterceptor: (searchInterceptor: SearchInterceptor) => void; search: ISearchGeneric; searchSource: { create: (fields?: SearchSourceFields) => Promise; createEmpty: () => ISearchSource; }; - usageCollector?: SearchUsageCollector; + /** + * @deprecated + * @internal + */ __LEGACY: ISearchStartLegacy; } diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts index 6d67127251424..c39b7d355d495 100644 --- a/src/plugins/data/public/types.ts +++ b/src/plugins/data/public/types.ts @@ -25,13 +25,17 @@ import { UiActionsSetup, UiActionsStart } from 'src/plugins/ui_actions/public'; import { AutocompleteSetup, AutocompleteStart } from './autocomplete'; import { FieldFormatsSetup, FieldFormatsStart } from './field_formats'; import { createFiltersFromRangeSelectAction, createFiltersFromValueClickAction } from './actions'; -import { ISearchSetup, ISearchStart } from './search'; +import { ISearchSetup, ISearchStart, SearchEnhancements } from './search'; import { QuerySetup, QueryStart } from './query'; import { IndexPatternSelectProps } from './ui/index_pattern_select'; import { IndexPatternsContract } from './index_patterns'; import { StatefulSearchBarProps } from './ui/search_bar/create_search_bar'; import { UsageCollectionSetup } from '../../usage_collection/public'; +export interface DataPublicPluginEnhancements { + search: SearchEnhancements; +} + export interface DataSetupDependencies { expressions: ExpressionsSetup; uiActions: UiActionsSetup; @@ -47,6 +51,10 @@ export interface DataPublicPluginSetup { search: ISearchSetup; fieldFormats: FieldFormatsSetup; query: QuerySetup; + /** + * @internal + */ + __enhance: (enhancements: DataPublicPluginEnhancements) => void; } export interface DataPublicPluginStart { diff --git a/x-pack/plugins/data_enhanced/public/plugin.ts b/x-pack/plugins/data_enhanced/public/plugin.ts index bdf3f6a0acf90..7f6e3feac0671 100644 --- a/x-pack/plugins/data_enhanced/public/plugin.ts +++ b/x-pack/plugins/data_enhanced/public/plugin.ts @@ -31,20 +31,26 @@ export class DataEnhancedPlugin KUERY_LANGUAGE_NAME, setupKqlQuerySuggestionProvider(core) ); - } - public start(core: CoreStart, plugins: DataEnhancedStartDependencies) { - setAutocompleteService(plugins.data.autocomplete); const enhancedSearchInterceptor = new EnhancedSearchInterceptor( { toasts: core.notifications.toasts, - application: core.application, http: core.http, uiSettings: core.uiSettings, - usageCollector: plugins.data.search.usageCollector, + startServices: core.getStartServices(), + usageCollector: data.search.usageCollector, }, core.injectedMetadata.getInjectedVar('esRequestTimeout') as number ); - plugins.data.search.setInterceptor(enhancedSearchInterceptor); + + data.__enhance({ + search: { + searchInterceptor: enhancedSearchInterceptor, + }, + }); + } + + public start(core: CoreStart, plugins: DataEnhancedStartDependencies) { + setAutocompleteService(plugins.data.autocomplete); } } diff --git a/x-pack/plugins/data_enhanced/public/search/search_interceptor.test.ts b/x-pack/plugins/data_enhanced/public/search/search_interceptor.test.ts index d004511fa4674..fe954f1602cd3 100644 --- a/x-pack/plugins/data_enhanced/public/search/search_interceptor.test.ts +++ b/x-pack/plugins/data_enhanced/public/search/search_interceptor.test.ts @@ -6,7 +6,7 @@ import { coreMock } from '../../../../../src/core/public/mocks'; import { EnhancedSearchInterceptor } from './search_interceptor'; -import { CoreStart } from 'kibana/public'; +import { CoreSetup, CoreStart } from 'kibana/public'; import { AbortError } from '../../../../../src/plugins/data/common'; const timeTravel = (msToRun = 0) => { @@ -19,13 +19,14 @@ const error = jest.fn(); const complete = jest.fn(); let searchInterceptor: EnhancedSearchInterceptor; +let mockCoreSetup: MockedKeys; let mockCoreStart: MockedKeys; jest.useFakeTimers(); function mockFetchImplementation(responses: any[]) { let i = 0; - mockCoreStart.http.fetch.mockImplementation(() => { + mockCoreSetup.http.fetch.mockImplementation(() => { const { time = 0, value = {}, isError = false } = responses[i++]; return new Promise((resolve, reject) => setTimeout(() => { @@ -39,6 +40,7 @@ describe('EnhancedSearchInterceptor', () => { let mockUsageCollector: any; beforeEach(() => { + mockCoreSetup = coreMock.createSetup(); mockCoreStart = coreMock.createStart(); next.mockClear(); @@ -54,12 +56,20 @@ describe('EnhancedSearchInterceptor', () => { trackLongQueryRunBeyondTimeout: jest.fn(), }; + const mockPromise = new Promise((resolve) => { + resolve([ + { + application: mockCoreStart.application, + }, + ]); + }); + searchInterceptor = new EnhancedSearchInterceptor( { - toasts: mockCoreStart.notifications.toasts, - application: mockCoreStart.application, - http: mockCoreStart.http, - uiSettings: mockCoreStart.uiSettings, + toasts: mockCoreSetup.notifications.toasts, + startServices: mockPromise as any, + http: mockCoreSetup.http, + uiSettings: mockCoreSetup.uiSettings, usageCollector: mockUsageCollector, }, 1000 @@ -229,8 +239,8 @@ describe('EnhancedSearchInterceptor', () => { expect(error).toHaveBeenCalled(); expect(error.mock.calls[0][0]).toBeInstanceOf(AbortError); - expect(mockCoreStart.http.fetch).toHaveBeenCalledTimes(2); - expect(mockCoreStart.http.delete).toHaveBeenCalled(); + expect(mockCoreSetup.http.fetch).toHaveBeenCalledTimes(2); + expect(mockCoreSetup.http.delete).toHaveBeenCalled(); }); test('should not DELETE a running async search on async timeout prior to first response', async () => { @@ -253,8 +263,8 @@ describe('EnhancedSearchInterceptor', () => { expect(error).toHaveBeenCalled(); expect(error.mock.calls[0][0]).toBeInstanceOf(AbortError); - expect(mockCoreStart.http.fetch).toHaveBeenCalled(); - expect(mockCoreStart.http.delete).not.toHaveBeenCalled(); + expect(mockCoreSetup.http.fetch).toHaveBeenCalled(); + expect(mockCoreSetup.http.delete).not.toHaveBeenCalled(); }); test('should DELETE a running async search on async timeout after first response', async () => { @@ -285,16 +295,16 @@ describe('EnhancedSearchInterceptor', () => { expect(next).toHaveBeenCalled(); expect(error).not.toHaveBeenCalled(); - expect(mockCoreStart.http.fetch).toHaveBeenCalled(); - expect(mockCoreStart.http.delete).not.toHaveBeenCalled(); + expect(mockCoreSetup.http.fetch).toHaveBeenCalled(); + expect(mockCoreSetup.http.delete).not.toHaveBeenCalled(); // Long enough to reach the timeout but not long enough to reach the next response await timeTravel(1000); expect(error).toHaveBeenCalled(); expect(error.mock.calls[0][0]).toBeInstanceOf(AbortError); - expect(mockCoreStart.http.fetch).toHaveBeenCalledTimes(2); - expect(mockCoreStart.http.delete).toHaveBeenCalled(); + expect(mockCoreSetup.http.fetch).toHaveBeenCalledTimes(2); + expect(mockCoreSetup.http.delete).toHaveBeenCalled(); }); test('should DELETE a running async search on async timeout on error from fetch', async () => { @@ -327,16 +337,16 @@ describe('EnhancedSearchInterceptor', () => { expect(next).toHaveBeenCalled(); expect(error).not.toHaveBeenCalled(); - expect(mockCoreStart.http.fetch).toHaveBeenCalled(); - expect(mockCoreStart.http.delete).not.toHaveBeenCalled(); + expect(mockCoreSetup.http.fetch).toHaveBeenCalled(); + expect(mockCoreSetup.http.delete).not.toHaveBeenCalled(); // Long enough to reach the timeout but not long enough to reach the next response await timeTravel(10); expect(error).toHaveBeenCalled(); expect(error.mock.calls[0][0]).toBe(responses[1].value); - expect(mockCoreStart.http.fetch).toHaveBeenCalledTimes(2); - expect(mockCoreStart.http.delete).toHaveBeenCalled(); + expect(mockCoreSetup.http.fetch).toHaveBeenCalledTimes(2); + expect(mockCoreSetup.http.delete).toHaveBeenCalled(); }); }); @@ -367,7 +377,7 @@ describe('EnhancedSearchInterceptor', () => { await timeTravel(); - const areAllRequestsAborted = mockCoreStart.http.fetch.mock.calls.every( + const areAllRequestsAborted = mockCoreSetup.http.fetch.mock.calls.every( ([{ signal }]) => signal?.aborted ); expect(areAllRequestsAborted).toBe(true); diff --git a/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts b/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts index bff9e2cb9048c..ae6dddf33536f 100644 --- a/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts +++ b/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts @@ -20,8 +20,7 @@ export class EnhancedSearchInterceptor extends SearchInterceptor { /** * This class should be instantiated with a `requestTimeout` corresponding with how many ms after * requests are initiated that they should automatically cancel. - * @param toasts The `core.notifications.toasts` service - * @param application The `core.application` service + * @param deps `SearchInterceptorDeps` * @param requestTimeout Usually config value `elasticsearch.requestTimeout` */ constructor(deps: SearchInterceptorDeps, requestTimeout?: number) { @@ -78,7 +77,7 @@ export class EnhancedSearchInterceptor extends SearchInterceptor { const { combinedSignal, cleanup } = this.setupTimers(options); const aborted$ = from(toPromise(combinedSignal)); - this.pendingCount$.next(++this.pendingCount); + this.pendingCount$.next(this.pendingCount$.getValue() + 1); return this.runSearch(request, combinedSignal, options?.strategy).pipe( expand((response) => { @@ -113,7 +112,7 @@ export class EnhancedSearchInterceptor extends SearchInterceptor { }, }), finalize(() => { - this.pendingCount$.next(--this.pendingCount); + this.pendingCount$.next(this.pendingCount$.getValue() - 1); cleanup(); }) ); From 1a09c878b185b62ec72bf790d41f61a6e21f54c0 Mon Sep 17 00:00:00 2001 From: Angela Chuang <6295984+angorayc@users.noreply.github.com> Date: Thu, 13 Aug 2020 10:24:40 +0100 Subject: [PATCH 13/53] [Security Solution] Fix the status of timelines' bulk actions (#74560) * fix bulk actions * fix lint error Co-authored-by: Elastic Machine --- .../edit_timeline_batch_actions.tsx | 7 +- .../open_timeline/open_timeline.test.tsx | 83 ++++++++++++++++++- .../open_timeline/open_timeline.tsx | 1 - 3 files changed, 86 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/edit_timeline_batch_actions.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/edit_timeline_batch_actions.tsx index 27fda48b69598..cce4251135866 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/edit_timeline_batch_actions.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/edit_timeline_batch_actions.tsx @@ -7,7 +7,7 @@ import { EuiContextMenuPanel, EuiContextMenuItem, EuiBasicTable } from '@elastic/eui'; import React, { useCallback, useMemo } from 'react'; -import { TimelineType, TimelineStatus } from '../../../../common/types/timeline'; +import { TimelineType } from '../../../../common/types/timeline'; import * as i18n from './translations'; import { DeleteTimelines, OpenTimelineResult } from './types'; @@ -66,7 +66,7 @@ export const useEditTimelineBatchActions = ({ const getBatchItemsPopoverContent = useCallback( (closePopover: () => void) => { - const disabled = selectedItems?.some((item) => item.status === TimelineStatus.immutable); + const disabled = selectedItems == null || selectedItems.length === 0; return ( <> , ); }, - // eslint-disable-next-line react-hooks/exhaustive-deps [ selectedItems, deleteTimelines, diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline.test.tsx index 9de3242c5e303..3d5c5f60d1d9b 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline.test.tsx @@ -9,6 +9,7 @@ import { cloneDeep } from 'lodash/fp'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import React from 'react'; import { ThemeProvider } from 'styled-components'; +import { act } from '@testing-library/react'; import '../../../common/mock/match_media'; import { DEFAULT_SEARCH_RESULTS_PER_PAGE } from '../../pages/timelines_page'; @@ -51,7 +52,7 @@ describe('OpenTimeline', () => { title, timelineType: TimelineType.default, timelineStatus: TimelineStatus.active, - templateTimelineFilter: [

], + templateTimelineFilter: [
,
], totalSearchResultsCount: mockSearchResults.length, }); @@ -279,6 +280,86 @@ describe('OpenTimeline', () => { expect(wrapper.find('[data-test-subj="utility-bar-action"]').exists()).toEqual(true); }); + test('it should disable export-timeline if no timeline is selected', async () => { + const defaultProps = { + ...getDefaultTestProps(mockResults), + timelineStatus: null, + selectedItems: [], + }; + const wrapper = mountWithIntl( + + + + ); + + wrapper.find('[data-test-subj="utility-bar-action"]').find('EuiLink').simulate('click'); + await act(async () => { + expect( + wrapper.find('[data-test-subj="export-timeline-action"]').first().prop('disabled') + ).toEqual(true); + }); + }); + + test('it should disable delete timeline if no timeline is selected', async () => { + const defaultProps = { + ...getDefaultTestProps(mockResults), + timelineStatus: null, + selectedItems: [], + }; + const wrapper = mountWithIntl( + + + + ); + + wrapper.find('[data-test-subj="utility-bar-action"]').find('EuiLink').simulate('click'); + await act(async () => { + expect( + wrapper.find('[data-test-subj="delete-timeline-action"]').first().prop('disabled') + ).toEqual(true); + }); + }); + + test('it should enable export-timeline if a timeline is selected', async () => { + const defaultProps = { + ...getDefaultTestProps(mockResults), + timelineStatus: null, + selectedItems: [{}], + }; + const wrapper = mountWithIntl( + + + + ); + + wrapper.find('[data-test-subj="utility-bar-action"]').find('EuiLink').simulate('click'); + await act(async () => { + expect( + wrapper.find('[data-test-subj="export-timeline-action"]').first().prop('disabled') + ).toEqual(false); + }); + }); + + test('it should enable delete timeline if a timeline is selected', async () => { + const defaultProps = { + ...getDefaultTestProps(mockResults), + timelineStatus: null, + selectedItems: [{}], + }; + const wrapper = mountWithIntl( + + + + ); + + wrapper.find('[data-test-subj="utility-bar-action"]').find('EuiLink').simulate('click'); + await act(async () => { + expect( + wrapper.find('[data-test-subj="delete-timeline-action"]').first().prop('disabled') + ).toEqual(false); + }); + }); + test("it should render a selectable timeline table if timelineStatus is active (selecting custom templates' tab)", () => { const defaultProps = { ...getDefaultTestProps(mockResults), diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline.tsx index c9495c46d4acf..1f5f0ccca3b70 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/open_timeline.tsx @@ -160,7 +160,6 @@ export const OpenTimeline = React.memo( }, [onDeleteSelected, deleteTimelines, timelineStatus]); const SearchRowContent = useMemo(() => <>{templateTimelineFilter}, [templateTimelineFilter]); - return ( <> Date: Thu, 13 Aug 2020 12:20:38 +0100 Subject: [PATCH 14/53] [Task manager] Prevents edge case where already running tasks are reschedule every polling interval (#74606) Fixes flaky tests in Task Manager and Alerting. The fix in #73244 was correct, but it missed an edge case which causes the already running task to be rescheduled over and over. This prevents that edge case which was effecting both TM in general and Alerting specifically. --- .../task_manager/server/task_store.test.ts | 104 +++++++++++++++++- .../plugins/task_manager/server/task_store.ts | 55 ++++----- .../tests/alerting/update.ts | 3 +- .../task_manager/task_manager_integration.js | 3 +- 4 files changed, 125 insertions(+), 40 deletions(-) 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 d65c39f4f454d..a02123c4a3f8d 100644 --- a/x-pack/plugins/task_manager/server/task_store.test.ts +++ b/x-pack/plugins/task_manager/server/task_store.test.ts @@ -627,7 +627,7 @@ if (doc['task.runAt'].size()!=0) { }); }); - test('it returns task objects', async () => { + test('it filters out running tasks', async () => { const taskManagerId = uuid.v1(); const claimOwnershipUntil = new Date(Date.now()); const runAt = new Date(); @@ -641,7 +641,7 @@ if (doc['task.runAt'].size()!=0) { taskType: 'foo', schedule: undefined, attempts: 0, - status: 'idle', + status: 'claiming', params: '{ "hello": "world" }', state: '{ "baby": "Henhen" }', user: 'jimbo', @@ -715,7 +715,103 @@ if (doc['task.runAt'].size()!=0) { runAt, scope: ['reporting'], state: { baby: 'Henhen' }, - status: 'idle', + status: 'claiming', + taskType: 'foo', + user: 'jimbo', + ownerId: taskManagerId, + }, + ]); + }); + + test('it returns task objects', async () => { + const taskManagerId = uuid.v1(); + const claimOwnershipUntil = new Date(Date.now()); + const runAt = new Date(); + const tasks = [ + { + _id: 'aaa', + _source: { + type: 'task', + task: { + runAt, + taskType: 'foo', + schedule: undefined, + attempts: 0, + status: 'claiming', + params: '{ "hello": "world" }', + state: '{ "baby": "Henhen" }', + user: 'jimbo', + scope: ['reporting'], + ownerId: taskManagerId, + }, + }, + _seq_no: 1, + _primary_term: 2, + sort: ['a', 1], + }, + { + _id: 'bbb', + _source: { + type: 'task', + task: { + runAt, + taskType: 'bar', + schedule: { interval: '5m' }, + attempts: 2, + status: 'claiming', + params: '{ "shazm": 1 }', + state: '{ "henry": "The 8th" }', + user: 'dabo', + scope: ['reporting', 'ceo'], + ownerId: taskManagerId, + }, + }, + _seq_no: 3, + _primary_term: 4, + sort: ['b', 2], + }, + ]; + const { + result: { docs }, + args: { + search: { + body: { query }, + }, + }, + } = await testClaimAvailableTasks({ + opts: { + taskManagerId, + }, + claimingOpts: { + claimOwnershipUntil, + size: 10, + }, + hits: tasks, + }); + + expect(query.bool.must).toContainEqual({ + bool: { + must: [ + { + term: { + 'task.ownerId': taskManagerId, + }, + }, + { term: { 'task.status': 'claiming' } }, + ], + }, + }); + + expect(docs).toMatchObject([ + { + attempts: 0, + id: 'aaa', + schedule: undefined, + params: { hello: 'world' }, + runAt, + scope: ['reporting'], + state: { baby: 'Henhen' }, + status: 'claiming', taskType: 'foo', user: 'jimbo', ownerId: taskManagerId, @@ -728,7 +824,7 @@ if (doc['task.runAt'].size()!=0) { runAt, scope: ['reporting', 'ceo'], state: { henry: 'The 8th' }, - status: 'running', + status: 'claiming', taskType: 'bar', user: 'dabo', ownerId: taskManagerId, diff --git a/x-pack/plugins/task_manager/server/task_store.ts b/x-pack/plugins/task_manager/server/task_store.ts index a18fb57b35b3d..f2da41053e6ab 100644 --- a/x-pack/plugins/task_manager/server/task_store.ts +++ b/x-pack/plugins/task_manager/server/task_store.ts @@ -217,48 +217,39 @@ export class TaskStore { claimTasksByIdWithRawIds, size ); + const docs = numberOfTasksClaimed > 0 ? await this.sweepForClaimedTasks(claimTasksByIdWithRawIds, size) : []; - // emit success/fail events for claimed tasks by id - if (claimTasksById && claimTasksById.length) { - const [documentsReturnedById, documentsClaimedBySchedule] = partition(docs, (doc) => - claimTasksById.includes(doc.id) - ); - - const [documentsClaimedById, documentsRequestedButNotClaimed] = partition( - documentsReturnedById, - // we filter the schduled tasks down by status is 'claiming' in the esearch, - // but we do not apply this limitation on tasks claimed by ID so that we can - // provide more detailed error messages when we fail to claim them - (doc) => doc.status === TaskStatus.Claiming - ); - - const documentsRequestedButNotReturned = difference( - claimTasksById, - map(documentsReturnedById, 'id') - ); + const [documentsReturnedById, documentsClaimedBySchedule] = partition(docs, (doc) => + claimTasksById.includes(doc.id) + ); - this.emitEvents( - [...documentsClaimedById, ...documentsClaimedBySchedule].map((doc) => - asTaskClaimEvent(doc.id, asOk(doc)) - ) - ); + const [documentsClaimedById, documentsRequestedButNotClaimed] = partition( + documentsReturnedById, + // we filter the schduled tasks down by status is 'claiming' in the esearch, + // but we do not apply this limitation on tasks claimed by ID so that we can + // provide more detailed error messages when we fail to claim them + (doc) => doc.status === TaskStatus.Claiming + ); - this.emitEvents( - documentsRequestedButNotClaimed.map((doc) => asTaskClaimEvent(doc.id, asErr(some(doc)))) - ); + const documentsRequestedButNotReturned = difference( + claimTasksById, + map(documentsReturnedById, 'id') + ); - this.emitEvents( - documentsRequestedButNotReturned.map((id) => asTaskClaimEvent(id, asErr(none))) - ); - } + this.emitEvents([ + ...documentsClaimedById.map((doc) => asTaskClaimEvent(doc.id, asOk(doc))), + ...documentsClaimedBySchedule.map((doc) => asTaskClaimEvent(doc.id, asOk(doc))), + ...documentsRequestedButNotClaimed.map((doc) => asTaskClaimEvent(doc.id, asErr(some(doc)))), + ...documentsRequestedButNotReturned.map((id) => asTaskClaimEvent(id, asErr(none))), + ]); return { - claimedTasks: numberOfTasksClaimed, - docs, + claimedTasks: documentsClaimedById.length + documentsClaimedBySchedule.length, + docs: docs.filter((doc) => doc.status === TaskStatus.Claiming), }; }; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts index cac6355409ac9..ab3a92d0b3f70 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/update.ts @@ -31,8 +31,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { .then((response: SupertestResponse) => response.body); } - // FLAKY: https://github.com/elastic/kibana/issues/72803 - describe.skip('update', () => { + describe('update', () => { const objectRemover = new ObjectRemover(supertest); after(() => objectRemover.removeAll()); diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js index ea95eb42dd6ff..c87a5039360b8 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_manager_integration.js @@ -28,8 +28,7 @@ export default function ({ getService }) { const testHistoryIndex = '.kibana_task_manager_test_result'; const supertest = supertestAsPromised(url.format(config.get('servers.kibana'))); - // FLAKY: https://github.com/elastic/kibana/issues/71390 - describe.skip('scheduling and running tasks', () => { + describe('scheduling and running tasks', () => { beforeEach( async () => await supertest.delete('/api/sample_tasks').set('kbn-xsrf', 'xxx').expect(200) ); From c7a46d583a6f930641aa8ef6cc94fd94f5ab14a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Marcondes?= <55978943+cauemarcondes@users.noreply.github.com> Date: Thu, 13 Aug 2020 12:41:39 +0100 Subject: [PATCH 15/53] [Observability] change ingest manager link (#74928) * chaning ingest manager link * chaning ingest manager link --- .../components/app/ingest_manager_panel/index.tsx | 13 ++++++++----- x-pack/plugins/translations/translations/ja-JP.json | 4 ---- x-pack/plugins/translations/translations/zh-CN.json | 4 ---- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/observability/public/components/app/ingest_manager_panel/index.tsx b/x-pack/plugins/observability/public/components/app/ingest_manager_panel/index.tsx index 1ab9f75632d9d..5d0c8a40ed3de 100644 --- a/x-pack/plugins/observability/public/components/app/ingest_manager_panel/index.tsx +++ b/x-pack/plugins/observability/public/components/app/ingest_manager_panel/index.tsx @@ -11,13 +11,16 @@ import { EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { EuiText } from '@elastic/eui'; import { EuiLink } from '@elastic/eui'; +import { usePluginContext } from '../../../hooks/use_plugin_context'; export function IngestManagerPanel() { + const { core } = usePluginContext(); + return ( @@ -25,7 +28,7 @@ export function IngestManagerPanel() {

- {i18n.translate('xpack.observability.ingestManafer.title', { + {i18n.translate('xpack.observability.ingestManager.title', { defaultMessage: 'Have you seen our new Ingest Manager?', })}

@@ -33,15 +36,15 @@ export function IngestManagerPanel() {
- {i18n.translate('xpack.observability.ingestManafer.text', { + {i18n.translate('xpack.observability.ingestManager.text', { defaultMessage: 'The Elastic Agent provides a simple, unified way to add monitoring for logs, metrics, and other types of data to your hosts. You no longer need to install multiple Beats and other agents, making it easier and faster to deploy configurations across your infrastructure.', })} - - {i18n.translate('xpack.observability.ingestManafer.button', { + + {i18n.translate('xpack.observability.ingestManager.button', { defaultMessage: 'Try Ingest Manager Beta', })} diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 55d1953247a93..81c06cf5c381f 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -14047,10 +14047,6 @@ "xpack.observability.home.sectionsubtitle": "ログ、メトリック、トレースを大規模に、1つのスタックにまとめて、環境内のあらゆる場所で生じるイベントの監視、分析、対応を行います。", "xpack.observability.home.sectionTitle": "エコシステム全体の一元的な可視性", "xpack.observability.home.title": "オブザーバビリティ", - "xpack.observability.ingestManafer.beta": "ベータ", - "xpack.observability.ingestManafer.button": "Ingest Managerベータを試す", - "xpack.observability.ingestManafer.text": "Elasticエージェントでは、シンプルかつ統合された方法で、ログ、メトリック、他の種類のデータの監視をホストに追加することができます。複数のBeatsと他のエージェントをインストールする必要はありません。このため、インフラストラクチャ全体での構成のデプロイが簡単で高速になりました。", - "xpack.observability.ingestManafer.title": "新しいIngest Managerをご覧になりましたか?", "xpack.observability.landing.breadcrumb": "はじめて使う", "xpack.observability.news.readFullStory": "詳細なストーリーを読む", "xpack.observability.news.title": "新機能", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 40f4c9c5897d8..af5e68b7e44d7 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -14052,10 +14052,6 @@ "xpack.observability.home.sectionsubtitle": "通过根据需要将日志、指标和跟踪都置于单个堆栈上,来监测、分析和响应环境中任何位置发生的事件。", "xpack.observability.home.sectionTitle": "整个生态系统的统一可见性", "xpack.observability.home.title": "可观测性", - "xpack.observability.ingestManafer.beta": "公测版", - "xpack.observability.ingestManafer.button": "试用采集管理器公测版", - "xpack.observability.ingestManafer.text": "通过 Elastic 代理,您能够以简单统一的方式将日志、指标和其他类型数据的监测添加到主机。不再需要安装多个 Beats 和其他代理,这样在整个基础设施中部署配置会更轻松更快速。", - "xpack.observability.ingestManafer.title": "是否了解我们全新的采集管理器?", "xpack.observability.landing.breadcrumb": "入门", "xpack.observability.news.readFullStory": "详细了解", "xpack.observability.news.title": "最近的新闻", From 50f332867af9078f3b86085e96151b7854ee41d6 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Thu, 13 Aug 2020 14:57:04 +0200 Subject: [PATCH 16/53] [Ingest Pipelines] Processor forms for processors A-D (#72849) * First few processors of the first batch - Also refactored options to live in scoped objects to avoid overriding type (important fix!) - Have not polished copy or form layout. * add type to shared imports * Refactors for repeated fields and added forms - date_index_name - dissect - dot_expander - drop Fields refactored: - Field - Ignore missing * Fix broken imports and some other small refactors * added text editor field and updated pattern and if fields * Large copy improvements and updates and other small refactors - Added help text for all fields - Updated layout so that required fields are always on first - Replaced circle radio group with a select drop down * update circle shape type field to select * Added "long" option for convert type * fix path import * fix types and i18n * add validation for dot expander fix append value to be a combobox * fix i18n Co-authored-by: Elastic Machine --- .../field_components/index.ts | 3 +- .../field_components/text_editor.tsx | 38 +++ .../field_components/xjson_editor.tsx | 54 ++-- .../manage_processor_form.container.tsx | 7 +- .../manage_processor_form.tsx | 2 +- .../processor_settings_fields.tsx | 3 +- .../processors/append.tsx | 56 ++++ .../processors/bytes.tsx | 43 ++++ .../processors/circle.tsx | 140 ++++++++++ .../common_fields/common_processor_fields.tsx | 37 ++- .../common_fields/field_name_field.tsx | 58 +++++ .../common_fields/ignore_missing_field.tsx | 37 +++ .../common_fields/processor_type_field.tsx | 27 +- .../processors/convert.tsx | 136 ++++++++++ .../manage_processor_form/processors/csv.tsx | 164 ++++++++++++ .../manage_processor_form/processors/date.tsx | 122 +++++++++ .../processors/date_index_name.tsx | 242 ++++++++++++++++++ .../processors/dissect.tsx | 99 +++++++ .../processors/dot_expander.tsx | 55 ++++ .../manage_processor_form/processors/drop.tsx | 14 + .../manage_processor_form/processors/gsub.tsx | 21 +- .../manage_processor_form/processors/index.ts | 16 ++ .../manage_processor_form/processors/set.tsx | 6 +- .../processors/shared.ts | 16 ++ .../shared/map_processor_type_to_form.tsx | 33 ++- .../ingest_pipelines/public/shared_imports.ts | 5 + 26 files changed, 1347 insertions(+), 87 deletions(-) create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/text_editor.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/append.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/bytes.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/circle.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/field_name_field.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/ignore_missing_field.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/convert.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/csv.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/date.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/date_index_name.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/dissect.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/dot_expander.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/drop.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/shared.ts diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/index.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/index.ts index 6f7b55a3ea4b0..6ce9eefd26445 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/index.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/index.ts @@ -4,4 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export { OnXJsonEditorUpdateHandler, XJsonEditor } from './xjson_editor'; +export { XJsonEditor } from './xjson_editor'; +export { TextEditor } from './text_editor'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/text_editor.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/text_editor.tsx new file mode 100644 index 0000000000000..1d0e36c0d526c --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/text_editor.tsx @@ -0,0 +1,38 @@ +/* + * 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 { EuiPanel } from '@elastic/eui'; +import React, { FunctionComponent } from 'react'; +import { EuiFormRow } from '@elastic/eui'; +import { + CodeEditor, + FieldHook, + getFieldValidityAndErrorMessage, +} from '../../../../../../shared_imports'; + +interface Props { + field: FieldHook; + editorProps: { [key: string]: any }; +} + +export const TextEditor: FunctionComponent = ({ field, editorProps }) => { + const { value, helpText, setValue, label } = field; + const { errorMessage } = getFieldValidityAndErrorMessage(field); + + return ( + + + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/xjson_editor.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/xjson_editor.tsx index a8456ad0ffd72..228094c0dfac5 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/xjson_editor.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/field_components/xjson_editor.tsx @@ -4,25 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiPanel } from '@elastic/eui'; import { XJsonLang } from '@kbn/monaco'; import React, { FunctionComponent, useCallback } from 'react'; -import { EuiFormRow } from '@elastic/eui'; -import { - CodeEditor, - FieldHook, - getFieldValidityAndErrorMessage, - Monaco, -} from '../../../../../../shared_imports'; +import { FieldHook, Monaco } from '../../../../../../shared_imports'; -export type OnXJsonEditorUpdateHandler = (arg: { - data: { - raw: string; - format(): T; - }; - validate(): boolean; - isValid: boolean | undefined; -}) => void; +import { TextEditor } from './text_editor'; interface Props { field: FieldHook; @@ -30,9 +16,8 @@ interface Props { } export const XJsonEditor: FunctionComponent = ({ field, editorProps }) => { - const { value, helpText, setValue, label } = field; + const { value, setValue } = field; const { xJson, setXJson, convertToJson } = Monaco.useXJsonMode(value); - const { errorMessage } = getFieldValidityAndErrorMessage(field); const onChange = useCallback( (s) => { @@ -42,25 +27,18 @@ export const XJsonEditor: FunctionComponent = ({ field, editorProps }) => [setValue, setXJson, convertToJson] ); return ( - - - { - XJsonLang.registerGrammarChecker(m); - }} - options={{ minimap: { enabled: false } }} - onChange={onChange} - {...(editorProps as any)} - /> - - + { + XJsonLang.registerGrammarChecker(m); + }, + onChange, + ...editorProps, + }} + /> ); }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/manage_processor_form.container.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/manage_processor_form.container.tsx index ea137b87e66d5..84551ce152099 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/manage_processor_form.container.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/manage_processor_form.container.tsx @@ -40,18 +40,19 @@ export const ManageProcessorForm: FunctionComponent = ({ const handleSubmit = useCallback( async (data: FormData, isValid: boolean) => { if (isValid) { - const { type, customOptions, ...options } = data; + const { type, customOptions, fields } = data; onSubmit({ type, - options: customOptions ? customOptions : options, + options: customOptions ? customOptions : fields, }); } }, [onSubmit] ); + const maybeProcessorOptions = processor?.options; const { form } = useForm({ - defaultValue: processor?.options, + defaultValue: { fields: maybeProcessorOptions ?? {} }, onSubmit: handleSubmit, }); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/manage_processor_form.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/manage_processor_form.tsx index 4e172cce63027..ad6d191be802d 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/manage_processor_form.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/manage_processor_form.tsx @@ -14,12 +14,12 @@ import { EuiFlyoutHeader, EuiFlyoutBody, EuiFlyoutFooter, - EuiSpacer, EuiTabs, EuiTab, EuiTitle, EuiFlexGroup, EuiFlexItem, + EuiSpacer, } from '@elastic/eui'; import { Form, FormDataProvider, FormHook } from '../../../../../shared_imports'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processor_settings_fields.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processor_settings_fields.tsx index 6b2568bad3afc..a6447bc30ac00 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processor_settings_fields.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processor_settings_fields.tsx @@ -5,7 +5,7 @@ */ import React, { FunctionComponent } from 'react'; -import { EuiHorizontalRule } from '@elastic/eui'; +import { EuiHorizontalRule, EuiSpacer } from '@elastic/eui'; import { FormDataProvider } from '../../../../../shared_imports'; import { ProcessorInternal } from '../../types'; @@ -36,6 +36,7 @@ export const ProcessorSettingsFields: FunctionComponent = ({ processor }) return ( <> + ); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/append.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/append.tsx new file mode 100644 index 0000000000000..8eb484b56bafe --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/append.tsx @@ -0,0 +1,56 @@ +/* + * 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, { FunctionComponent } from 'react'; +import { i18n } from '@kbn/i18n'; + +import { + FIELD_TYPES, + fieldValidators, + UseField, + ComboBoxField, +} from '../../../../../../shared_imports'; + +import { FieldsConfig } from './shared'; +import { FieldNameField } from './common_fields/field_name_field'; + +const { emptyField } = fieldValidators; + +const fieldsConfig: FieldsConfig = { + value: { + type: FIELD_TYPES.COMBO_BOX, + deserializer: (v) => (Array.isArray(v) ? v : [String(v)]), + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.appendForm.valueFieldLabel', { + defaultMessage: 'Value', + }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.appendForm.valueFieldHelpText', { + defaultMessage: 'The value to be appended by this processor.', + }), + validations: [ + { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.appendForm.valueRequiredError', { + defaultMessage: 'A value to set is required.', + }) + ), + }, + ], + }, +}; + +export const Append: FunctionComponent = () => { + return ( + <> + + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/bytes.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/bytes.tsx new file mode 100644 index 0000000000000..64a501f03d454 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/bytes.tsx @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FunctionComponent } from 'react'; +import { i18n } from '@kbn/i18n'; + +import { FIELD_TYPES, UseField, Field } from '../../../../../../shared_imports'; + +import { FieldsConfig } from './shared'; +import { IgnoreMissingField } from './common_fields/ignore_missing_field'; +import { FieldNameField } from './common_fields/field_name_field'; + +const fieldsConfig: FieldsConfig = { + target_field: { + type: FIELD_TYPES.TEXT, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.bytesForm.targetFieldLabel', { + defaultMessage: 'Target field (optional)', + }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.bytesForm.targetFieldHelpText', { + defaultMessage: 'The field to assign the converted value to', + }), + }, +}; + +export const Bytes: FunctionComponent = () => { + return ( + <> + + + + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/circle.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/circle.tsx new file mode 100644 index 0000000000000..3a39e597cb8dc --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/circle.tsx @@ -0,0 +1,140 @@ +/* + * 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, { FunctionComponent } from 'react'; +import { i18n } from '@kbn/i18n'; + +import { + FIELD_TYPES, + fieldValidators, + UseField, + Field, + SelectField, + NumericField, +} from '../../../../../../shared_imports'; + +import { FieldsConfig } from './shared'; +import { IgnoreMissingField } from './common_fields/ignore_missing_field'; +import { FieldNameField } from './common_fields/field_name_field'; + +const { emptyField } = fieldValidators; + +const fieldsConfig: FieldsConfig = { + target_field: { + type: FIELD_TYPES.TEXT, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.circleForm.targetFieldLabel', { + defaultMessage: 'Target field (optional)', + }), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.circleForm.targetFieldHelpText', + { + defaultMessage: 'By default field is updated in-place.', + } + ), + }, + error_distance: { + type: FIELD_TYPES.NUMBER, + deserializer: (v) => (typeof v === 'number' && !isNaN(v) ? v : 1.0), + serializer: Number, + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.circleForm.errorDistanceFieldLabel', + { + defaultMessage: 'Error distance', + } + ), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.circleForm.errorDistanceHelpText', + { + defaultMessage: + 'The difference between the resulting inscribed distance from center to side and the circle’s radius (measured in meters for geo_shape, unit-less for shape).', + } + ), + validations: [ + { + validator: ({ value }) => { + return isNaN(Number(value)) + ? { + message: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.circleForm.errorDistanceError', + { + defaultMessage: 'An error distance value is required.', + } + ), + } + : undefined; + }, + }, + ], + }, + shape_type: { + type: FIELD_TYPES.SELECT, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.circleForm.shapeTypeFieldLabel', { + defaultMessage: 'Shape type', + }), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.circleForm.shapeTypeFieldHelpText', + { defaultMessage: 'Which field mapping type is to be used.' } + ), + validations: [ + { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.circleForm.shapeTypeRequiredError', { + defaultMessage: 'A shape type value is required.', + }) + ), + }, + ], + }, +}; + +export const Circle: FunctionComponent = () => { + return ( + <> + + + + + + + + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/common_processor_fields.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/common_processor_fields.tsx index 4802653f9e680..7ae7b82c31a43 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/common_processor_fields.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/common_processor_fields.tsx @@ -15,41 +15,64 @@ import { ToggleField, } from '../../../../../../../shared_imports'; +import { TextEditor } from '../../field_components'; + const ignoreFailureConfig: FieldConfig = { defaultValue: false, + serializer: (v) => (v === false ? undefined : v), + deserializer: (v) => (typeof v === 'boolean' ? v : undefined), label: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.commonFields.ignoreFailureFieldLabel', { defaultMessage: 'Ignore failure', } ), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.commonFields.ignoreFailureHelpText', + { defaultMessage: 'Ignore failures for this processor.' } + ), type: FIELD_TYPES.TOGGLE, }; const ifConfig: FieldConfig = { - defaultValue: undefined, label: i18n.translate('xpack.ingestPipelines.pipelineEditor.commonFields.ifFieldLabel', { defaultMessage: 'Condition (optional)', }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.commonFields.ifFieldHelpText', { + defaultMessage: 'Conditionally execute this processor.', + }), type: FIELD_TYPES.TEXT, }; const tagConfig: FieldConfig = { - defaultValue: undefined, label: i18n.translate('xpack.ingestPipelines.pipelineEditor.commonFields.tagFieldLabel', { defaultMessage: 'Tag (optional)', }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.commonFields.tagFieldHelpText', { + defaultMessage: 'An identifier for this processor. Useful for debugging and metrics.', + }), type: FIELD_TYPES.TEXT, }; export const CommonProcessorFields: FunctionComponent = () => { return ( - <> - +
+ - + - - + +
); }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/field_name_field.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/field_name_field.tsx new file mode 100644 index 0000000000000..7ef5ba6768c19 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/field_name_field.tsx @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React, { FunctionComponent } from 'react'; +import { i18n } from '@kbn/i18n'; +import { + FIELD_TYPES, + UseField, + Field, + fieldValidators, + ValidationConfig, +} from '../../../../../../../shared_imports'; + +import { FieldsConfig } from '../shared'; + +const { emptyField } = fieldValidators; + +export const fieldsConfig: FieldsConfig = { + field: { + type: FIELD_TYPES.TEXT, + deserializer: String, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.commonFields.fieldFieldLabel', { + defaultMessage: 'Field', + }), + validations: [ + { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.commonFields.fieldRequiredError', { + defaultMessage: 'A field value is required.', + }) + ), + }, + ], + }, +}; + +interface Props { + helpText?: React.ReactNode; + /** + * The field name requires a value. Processor specific validation + * checks can be added here. + */ + additionalValidations?: ValidationConfig[]; +} + +export const FieldNameField: FunctionComponent = ({ helpText, additionalValidations }) => ( + +); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/ignore_missing_field.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/ignore_missing_field.tsx new file mode 100644 index 0000000000000..08eb0a425ef33 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/ignore_missing_field.tsx @@ -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 React, { FunctionComponent } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FIELD_TYPES, UseField, ToggleField } from '../../../../../../../shared_imports'; + +import { FieldsConfig } from '../shared'; + +export const fieldsConfig: FieldsConfig = { + ignore_missing: { + type: FIELD_TYPES.TOGGLE, + defaultValue: false, + serializer: (v) => (v === false ? undefined : v), + deserializer: (v) => (typeof v === 'boolean' ? v : undefined), + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.commonFields.ignoreMissingFieldLabel', + { + defaultMessage: 'Ignore missing', + } + ), + }, +}; + +interface Props { + helpText?: string; +} + +export const IgnoreMissingField: FunctionComponent = ({ helpText }) => ( + +); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/processor_type_field.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/processor_type_field.tsx index 71ee4a714a28e..e4ad90f61af0a 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/processor_type_field.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/common_fields/processor_type_field.tsx @@ -46,20 +46,12 @@ interface Props { const { emptyField } = fieldValidators; -const typeConfig: FieldConfig = { +const typeConfig: FieldConfig = { type: FIELD_TYPES.COMBO_BOX, label: i18n.translate('xpack.ingestPipelines.pipelineEditor.typeField.typeFieldLabel', { defaultMessage: 'Processor', }), - deserializer: (value: string | undefined) => { - if (value) { - return [value]; - } - return []; - }, - serializer: (value: string[]) => { - return value[0]; - }, + deserializer: String, validations: [ { validator: emptyField( @@ -73,11 +65,11 @@ const typeConfig: FieldConfig = { export const ProcessorTypeField: FunctionComponent = ({ initialType }) => { return ( - + config={typeConfig} defaultValue={initialType} path="type"> {(typeField) => { let selectedOptions: ProcessorTypeAndLabel[]; - if ((typeField.value as string[]).length) { - const [type] = typeField.value as string[]; + if (typeField.value?.length) { + const type = typeField.value; const descriptor = getProcessorDescriptor(type); selectedOptions = descriptor ? [{ label: descriptor.label, value: type }] @@ -103,9 +95,7 @@ export const ProcessorTypeField: FunctionComponent = ({ initialType }) => return false; } - const newValue = [...(typeField.value as string[]), value]; - - typeField.setValue(newValue); + typeField.setValue(value); }; return ( @@ -131,8 +121,9 @@ export const ProcessorTypeField: FunctionComponent = ({ initialType }) => options={processorTypesAndLabels} selectedOptions={selectedOptions} onCreateOption={onCreateComboOption} - onChange={(options: EuiComboBoxOptionOption[]) => { - typeField.setValue(options.map(({ value }) => value)); + onChange={(options: Array>) => { + const [selection] = options; + typeField.setValue(selection?.value! ?? ''); }} noSuggestions={false} singleSelection={{ diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/convert.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/convert.tsx new file mode 100644 index 0000000000000..b45f589bf0f92 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/convert.tsx @@ -0,0 +1,136 @@ +/* + * 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, { FunctionComponent } from 'react'; +import { i18n } from '@kbn/i18n'; + +import { + FIELD_TYPES, + fieldValidators, + UseField, + Field, + SelectField, +} from '../../../../../../shared_imports'; + +import { FieldsConfig } from './shared'; +import { FieldNameField } from './common_fields/field_name_field'; +import { IgnoreMissingField } from './common_fields/ignore_missing_field'; + +const { emptyField } = fieldValidators; + +const fieldsConfig: FieldsConfig = { + /* Required fields config */ + type: { + type: FIELD_TYPES.TEXT, + defaultValue: '', + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.convertForm.typeFieldLabel', { + defaultMessage: 'Type', + }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.convertForm.typeFieldHelpText', { + defaultMessage: 'The type to convert the existing value to.', + }), + validations: [ + { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.convertForm.typeRequiredError', { + defaultMessage: 'A type value is required.', + }) + ), + }, + ], + }, + /* Optional fields config */ + target_field: { + type: FIELD_TYPES.TEXT, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.convertForm.targetFieldLabel', { + defaultMessage: 'Target field (optional)', + }), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.convertForm.targetFieldHelpText', + { + defaultMessage: 'The field to assign the converted value to.', + } + ), + }, +}; + +export const Convert: FunctionComponent = () => { + return ( + <> + + + + + + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/csv.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/csv.tsx new file mode 100644 index 0000000000000..3ac0179ca02a6 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/csv.tsx @@ -0,0 +1,164 @@ +/* + * 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, { FunctionComponent } from 'react'; +import { EuiCode } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { + FIELD_TYPES, + fieldValidators, + UseField, + Field, + ToggleField, + ComboBoxField, + ValidationFunc, +} from '../../../../../../shared_imports'; + +import { FieldsConfig } from './shared'; +import { IgnoreMissingField } from './common_fields/ignore_missing_field'; +import { FieldNameField } from './common_fields/field_name_field'; + +import { isArrayOfStrings } from './shared'; + +const { minLengthField } = fieldValidators; + +/** + * Allow empty strings ('') to pass this validation. + */ +const isStringLengthOne: ValidationFunc = ({ value }) => { + return typeof value === 'string' && value !== '' && value.length !== 1 + ? { + message: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.convertForm.separatorLengthError', + { + defaultMessage: 'A separator value must be 1 character.', + } + ), + } + : undefined; +}; + +const fieldsConfig: FieldsConfig = { + /* Required fields config */ + target_fields: { + type: FIELD_TYPES.COMBO_BOX, + deserializer: (v) => { + return isArrayOfStrings(v) ? v : []; + }, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.csvForm.targetFieldsFieldLabel', { + defaultMessage: 'Target fields', + }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.csvForm.targetFieldsHelpText', { + defaultMessage: 'The array of fields to assign extracted values to.', + }), + validations: [ + { + validator: minLengthField({ + length: 1, + message: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.csvForm.targetFieldRequiredError', + { + defaultMessage: 'A target fields value is required.', + } + ), + }), + }, + ], + }, + /* Optional fields config */ + separator: { + type: FIELD_TYPES.TEXT, + serializer: (v) => (v ? v : undefined), + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.convertForm.separatorFieldLabel', { + defaultMessage: 'Separator (optional)', + }), + validations: [ + { + validator: isStringLengthOne, + }, + ], + helpText: ( + {','} }} + /> + ), + }, + quote: { + type: FIELD_TYPES.TEXT, + serializer: (v) => (v ? v : undefined), + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.convertForm.quoteFieldLabel', { + defaultMessage: 'Quote (optional)', + }), + validations: [ + { + validator: isStringLengthOne, + }, + ], + helpText: ( + {'"'} }} + /> + ), + }, + trim: { + type: FIELD_TYPES.TOGGLE, + defaultValue: false, + deserializer: (v) => (typeof v === 'boolean' ? v : undefined), + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.csvForm.trimFieldLabel', { + defaultMessage: 'Trim', + }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.csvForm.trimFieldHelpText', { + defaultMessage: 'Trim whitespaces in unquoted fields', + }), + }, + empty_value: { + type: FIELD_TYPES.TEXT, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.convertForm.emptyValueFieldLabel', { + defaultMessage: 'Empty value (optional)', + }), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.convertForm.emptyValueFieldHelpText', + { + defaultMessage: + 'Value used to fill empty fields, empty fields will be skipped if this is not provided.', + } + ), + }, +}; + +export const CSV: FunctionComponent = () => { + return ( + <> + + + + + + + + + + + + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/date.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/date.tsx new file mode 100644 index 0000000000000..424e84058ac3f --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/date.tsx @@ -0,0 +1,122 @@ +/* + * 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, { FunctionComponent } from 'react'; +import { EuiCode } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { + FIELD_TYPES, + fieldValidators, + UseField, + Field, + ComboBoxField, +} from '../../../../../../shared_imports'; + +import { FieldsConfig, isArrayOfStrings } from './shared'; +import { FieldNameField } from './common_fields/field_name_field'; + +const { minLengthField } = fieldValidators; + +const fieldsConfig: FieldsConfig = { + /* Required fields config */ + formats: { + type: FIELD_TYPES.COMBO_BOX, + deserializer: (v) => { + return isArrayOfStrings(v) ? v : []; + }, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.dateForm.formatsFieldLabel', { + defaultMessage: 'Formats', + }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.dateForm.formatsFieldHelpText', { + defaultMessage: + 'An array of the expected date formats. Can be a java time pattern or one of the following formats: ISO8601, UNIX, UNIX_MS, or TAI64N.', + }), + validations: [ + { + validator: minLengthField({ + length: 1, + message: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dateForm.formatsRequiredError', + { + defaultMessage: 'A value for formats is required.', + } + ), + }), + }, + ], + }, + /* Optional fields config */ + target_field: { + type: FIELD_TYPES.TEXT, + serializer: (v) => (v ? undefined : v), + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.dateForm.targetFieldFieldLabel', { + defaultMessage: 'Target field (optional)', + }), + helpText: ( + {'@timestamp'}, + }} + /> + ), + }, + timezone: { + type: FIELD_TYPES.TEXT, + serializer: (v) => (v ? v : undefined), + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.dateForm.timezoneFieldLabel', { + defaultMessage: 'Timezone (optional)', + }), + helpText: ( + {'UTC'} }} + /> + ), + }, + locale: { + type: FIELD_TYPES.TEXT, + serializer: (v) => (v ? v : undefined), + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.dateForm.localeFieldLabel', { + defaultMessage: 'Locale (optional)', + }), + helpText: ( + {'ENGLISH'} }} + /> + ), + }, +}; + +/** + * Disambiguate from global Date object + */ +export const DateProcessor: FunctionComponent = () => { + return ( + <> + + + + + + + + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/date_index_name.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/date_index_name.tsx new file mode 100644 index 0000000000000..387c9ff4e0b46 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/date_index_name.tsx @@ -0,0 +1,242 @@ +/* + * 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, { FunctionComponent } from 'react'; +import { EuiCode } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { + FIELD_TYPES, + fieldValidators, + UseField, + Field, + ComboBoxField, + SelectField, +} from '../../../../../../shared_imports'; + +import { FieldsConfig, isArrayOfStrings } from './shared'; +import { FieldNameField } from './common_fields/field_name_field'; + +const { emptyField } = fieldValidators; + +const fieldsConfig: FieldsConfig = { + /* Required fields config */ + date_rounding: { + type: FIELD_TYPES.SELECT, + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dateIndexNameForm.dateRoundingFieldLabel', + { + defaultMessage: 'Date rounding', + } + ), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dateIndexNameForm.dateRoundingFieldHelpText', + { + defaultMessage: 'How to round the date when formatting the date into the index name.', + } + ), + validations: [ + { + validator: emptyField( + i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dateIndexNameForm.dateRoundingRequiredError', + { + defaultMessage: 'A field value is required.', + } + ) + ), + }, + ], + }, + /* Optional fields config */ + index_name_prefix: { + type: FIELD_TYPES.TEXT, + serializer: (v) => (v ? v : undefined), + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dateIndexNameForm.indexNamePrefixFieldLabel', + { + defaultMessage: 'Index name prefix (optional)', + } + ), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dateIndexNameForm.indexNamePrefixFieldHelpText', + { defaultMessage: 'A prefix of the index name to be prepended before the printed date.' } + ), + }, + index_name_format: { + type: FIELD_TYPES.TEXT, + serializer: (v) => (v ? v : undefined), + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dateIndexNameForm.indexNameFormatFieldLabel', + { + defaultMessage: 'Index name format (optional)', + } + ), + helpText: ( + {'yyyy-MM-dd'} }} + /> + ), + }, + date_formats: { + type: FIELD_TYPES.COMBO_BOX, + serializer: (v: string[]) => { + return v.length ? v : undefined; + }, + deserializer: (v) => { + return isArrayOfStrings(v) ? v : []; + }, + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dateIndexNameForm.dateFormatsFieldLabel', + { + defaultMessage: 'Date formats (optional)', + } + ), + helpText: ( + {"yyyy-MM-dd'T'HH:mm:ss.SSSXX"} }} + /> + ), + }, + timezone: { + type: FIELD_TYPES.TEXT, + serializer: (v) => (v ? v : undefined), + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dateIndexNameForm.timezoneFieldLabel', + { + defaultMessage: 'Timezone (optional)', + } + ), + helpText: ( + {'UTC'} }} + /> + ), + }, + locale: { + type: FIELD_TYPES.TEXT, + serializer: (v) => (v ? v : undefined), + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dateIndexNameForm.localeFieldLabel', + { + defaultMessage: 'Locale (optional)', + } + ), + helpText: ( + {'ENGLISH'} }} + /> + ), + }, +}; + +/** + * Disambiguate from global Date object + */ +export const DateIndexName: FunctionComponent = () => { + return ( + <> + + + + + + + + + + + + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/dissect.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/dissect.tsx new file mode 100644 index 0000000000000..5f9f55ced1a25 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/dissect.tsx @@ -0,0 +1,99 @@ +/* + * 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, { FunctionComponent } from 'react'; +import { EuiCode } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { TextEditor } from '../field_components'; + +import { + FieldConfig, + FIELD_TYPES, + fieldValidators, + UseField, + Field, +} from '../../../../../../shared_imports'; + +import { FieldNameField } from './common_fields/field_name_field'; +import { IgnoreMissingField } from './common_fields/ignore_missing_field'; + +const { emptyField } = fieldValidators; + +const fieldsConfig: Record = { + /* Required field config */ + pattern: { + type: FIELD_TYPES.TEXT, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.dissectForm.patternFieldLabel', { + defaultMessage: 'Pattern', + }), + helpText: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dissectForm.patternFieldHelpText', + { + defaultMessage: 'The pattern to apply to the field.', + } + ), + validations: [ + { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.pipelineEditor.dissectForm.patternRequiredError', { + defaultMessage: 'A pattern value is required.', + }) + ), + }, + ], + }, + /* Optional field config */ + append_separator: { + type: FIELD_TYPES.TEXT, + label: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dissectForm.appendSeparatorparaotrFieldLabel', + { + defaultMessage: 'Append separator (optional)', + } + ), + helpText: ( + {'""'} }} + /> + ), + }, +}; + +export const Dissect: FunctionComponent = () => { + return ( + <> + + + + + + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/dot_expander.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/dot_expander.tsx new file mode 100644 index 0000000000000..4e50c61ac930c --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/dot_expander.tsx @@ -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 React, { FunctionComponent } from 'react'; +import { i18n } from '@kbn/i18n'; + +import { FieldConfig, FIELD_TYPES, UseField, Field } from '../../../../../../shared_imports'; + +import { FieldNameField } from './common_fields/field_name_field'; + +const fieldsConfig: Record = { + path: { + type: FIELD_TYPES.TEXT, + label: i18n.translate('xpack.ingestPipelines.pipelineEditor.dotExpanderForm.pathFieldLabel', { + defaultMessage: 'Path', + }), + helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.dotExpanderForm.pathHelpText', { + defaultMessage: 'Only required if the field to expand is part another object field.', + }), + }, +}; + +export const DotExpander: FunctionComponent = () => { + return ( + <> + { + if (typeof value === 'string' && value.length) { + return !value.includes('.') + ? { + message: i18n.translate( + 'xpack.ingestPipelines.pipelineEditor.dotExpanderForm.fieldNameRequiresDotError', + { defaultMessage: 'A field value requires at least one dot character.' } + ), + } + : undefined; + } + }, + }, + ]} + /> + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/drop.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/drop.tsx new file mode 100644 index 0000000000000..87b6cb76cdcce --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/drop.tsx @@ -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 { FunctionComponent } from 'react'; + +/** + * This fields component has no unique fields + */ +export const Drop: FunctionComponent = () => { + return null; +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/gsub.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/gsub.tsx index 77f85e61eff6b..3148022adaa98 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/gsub.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/gsub.tsx @@ -15,6 +15,7 @@ import { UseField, Field, } from '../../../../../../shared_imports'; +import { TextEditor } from '../field_components'; const { emptyField } = fieldValidators; @@ -84,15 +85,25 @@ const ignoreMissingConfig: FieldConfig = { export const Gsub: FunctionComponent = () => { return ( <> - + - + - + - + - + ); }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/index.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/index.ts new file mode 100644 index 0000000000000..6996deb2d861c --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/index.ts @@ -0,0 +1,16 @@ +/* + * 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 { Append } from './append'; +export { Bytes } from './bytes'; +export { Circle } from './circle'; +export { Convert } from './convert'; +export { CSV } from './csv'; +export { DateProcessor } from './date'; +export { DateIndexName } from './date_index_name'; +export { Dissect } from './dissect'; +export { DotExpander } from './dot_expander'; +export { Drop } from './drop'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/set.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/set.tsx index 1ba6a14d0448d..88cea620ae804 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/set.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/set.tsx @@ -64,11 +64,11 @@ const overrideConfig: FieldConfig = { export const SetProcessor: FunctionComponent = () => { return ( <> - + - + - + ); }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/shared.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/shared.ts new file mode 100644 index 0000000000000..a0a31dd3a8e93 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/shared.ts @@ -0,0 +1,16 @@ +/* + * 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 rt from 'io-ts'; +import { isRight } from 'fp-ts/lib/Either'; +import { flow } from 'fp-ts/lib/function'; + +import { FieldConfig } from '../../../../../../shared_imports'; + +export const arrayOfStrings = rt.array(rt.string); +export const isArrayOfStrings = flow(arrayOfStrings.decode, isRight); + +export type FieldsConfig = Record; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/map_processor_type_to_form.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/map_processor_type_to_form.tsx index 7055721fc8b07..502045084b24d 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/map_processor_type_to_form.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/map_processor_type_to_form.tsx @@ -7,6 +7,19 @@ import { i18n } from '@kbn/i18n'; import { FunctionComponent } from 'react'; +import { + Append, + Bytes, + Circle, + Convert, + CSV, + DateProcessor, + DateIndexName, + Dissect, + DotExpander, + Drop, +} from '../manage_processor_form/processors'; + // import { SetProcessor } from './processors/set'; // import { Gsub } from './processors/gsub'; @@ -23,70 +36,70 @@ type MapProcessorTypeToDescriptor = Record; export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = { append: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: Append, docLinkPath: '/append-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.append', { defaultMessage: 'Append', }), }, bytes: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: Bytes, docLinkPath: '/bytes-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.bytes', { defaultMessage: 'Bytes', }), }, circle: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: Circle, docLinkPath: '/ingest-circle-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.circle', { defaultMessage: 'Circle', }), }, convert: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: Convert, docLinkPath: '/convert-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.convert', { defaultMessage: 'Convert', }), }, csv: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: CSV, docLinkPath: '/csv-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.csv', { defaultMessage: 'CSV', }), }, date: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: DateProcessor, docLinkPath: '/date-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.date', { defaultMessage: 'Date', }), }, date_index_name: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: DateIndexName, docLinkPath: '/date-index-name-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.dateIndexName', { defaultMessage: 'Date Index Name', }), }, dissect: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: Dissect, docLinkPath: '/dissect-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.dissect', { defaultMessage: 'Dissect', }), }, dot_expander: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: DotExpander, docLinkPath: '/dot-expand-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.dotExpander', { defaultMessage: 'Dot Expander', }), }, drop: { - FieldsComponent: undefined, // TODO: Implement + FieldsComponent: Drop, docLinkPath: '/drop-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.drop', { defaultMessage: 'Drop', diff --git a/x-pack/plugins/ingest_pipelines/public/shared_imports.ts b/x-pack/plugins/ingest_pipelines/public/shared_imports.ts index d2c4b73a48767..936db37f0c629 100644 --- a/x-pack/plugins/ingest_pipelines/public/shared_imports.ts +++ b/x-pack/plugins/ingest_pipelines/public/shared_imports.ts @@ -43,6 +43,8 @@ export { FieldConfig, FieldHook, getFieldValidityAndErrorMessage, + ValidationFunc, + ValidationConfig, } from '../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib'; export { @@ -57,6 +59,9 @@ export { FormRow, ToggleField, ComboBoxField, + RadioGroupField, + NumericField, + SelectField, } from '../../../../src/plugins/es_ui_shared/static/forms/components'; export { From acc8ffed299fbba5ede703c79429f8df8c9feec5 Mon Sep 17 00:00:00 2001 From: Uladzislau Lasitsa Date: Thu, 13 Aug 2020 16:38:57 +0300 Subject: [PATCH 17/53] Fixed tooltip (#74074) Co-authored-by: Elastic Machine --- src/plugins/vis_type_vega/public/_vega_vis.scss | 1 + src/plugins/vis_type_vega/public/vega_view/vega_tooltip.js | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/plugins/vis_type_vega/public/_vega_vis.scss b/src/plugins/vis_type_vega/public/_vega_vis.scss index f9468d677eeed..12108c7ba3de0 100644 --- a/src/plugins/vis_type_vega/public/_vega_vis.scss +++ b/src/plugins/vis_type_vega/public/_vega_vis.scss @@ -107,6 +107,7 @@ .vgaVis__tooltip { max-width: 100%; + position: fixed; h2 { margin-bottom: $euiSizeS; diff --git a/src/plugins/vis_type_vega/public/vega_view/vega_tooltip.js b/src/plugins/vis_type_vega/public/vega_view/vega_tooltip.js index 01386fd91abc5..7b0274478cea2 100644 --- a/src/plugins/vis_type_vega/public/vega_view/vega_tooltip.js +++ b/src/plugins/vis_type_vega/public/vega_view/vega_tooltip.js @@ -85,12 +85,12 @@ export class TooltipHandler { let anchorBounds; if (item.bounds.width() > this.centerOnMark || item.bounds.height() > this.centerOnMark) { // I would expect clientX/Y, but that shows incorrectly - anchorBounds = createRect(event.pageX, event.pageY, 0, 0); + anchorBounds = createRect(event.clientX, event.clientY, 0, 0); } else { const containerBox = this.container.getBoundingClientRect(); anchorBounds = createRect( - containerBox.left + view._origin[0] + item.bounds.x1 + window.pageXOffset, - containerBox.top + view._origin[1] + item.bounds.y1 + window.pageYOffset, + containerBox.left + view._origin[0] + item.bounds.x1, + containerBox.top + view._origin[1] + item.bounds.y1, item.bounds.width(), item.bounds.height() ); From 8095c7ba1575d85a98c79ef779864fe4795a4fa5 Mon Sep 17 00:00:00 2001 From: Zacqary Adam Xeper Date: Thu, 13 Aug 2020 09:32:14 -0500 Subject: [PATCH 18/53] [Metrics UI] Add Jest tests for alert previews (#74890) --- .../preview_metric_threshold_alert.test.ts | 133 ++++++++++++++++++ .../alerting/metric_threshold/test_mocks.ts | 54 +++++++ .../lib/alerting/metric_threshold/types.ts | 2 +- 3 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 x-pack/plugins/infra/server/lib/alerting/metric_threshold/preview_metric_threshold_alert.test.ts diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/preview_metric_threshold_alert.test.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/preview_metric_threshold_alert.test.ts new file mode 100644 index 0000000000000..c26b44dfe8ff8 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/preview_metric_threshold_alert.test.ts @@ -0,0 +1,133 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import * as mocks from './test_mocks'; +import { Comparator, Aggregators, MetricExpressionParams } from './types'; +import { alertsMock, AlertServicesMock } from '../../../../../alerts/server/mocks'; +import { previewMetricThresholdAlert } from './preview_metric_threshold_alert'; + +describe('Previewing the metric threshold alert type', () => { + describe('querying the entire infrastructure', () => { + test('returns the expected results using a bucket interval equal to the alert interval', async () => { + const [ungroupedResult] = await previewMetricThresholdAlert({ + ...baseParams, + lookback: 'h', + alertInterval: '1m', + }); + const [firedResults, noDataResults, errorResults] = ungroupedResult; + expect(firedResults).toBe(30); + expect(noDataResults).toBe(0); + expect(errorResults).toBe(0); + }); + + test('returns the expected results using a bucket interval shorter than the alert interval', async () => { + const [ungroupedResult] = await previewMetricThresholdAlert({ + ...baseParams, + lookback: 'h', + alertInterval: '3m', + }); + const [firedResults, noDataResults, errorResults] = ungroupedResult; + expect(firedResults).toBe(10); + expect(noDataResults).toBe(0); + expect(errorResults).toBe(0); + }); + test('returns the expected results using a bucket interval longer than the alert interval', async () => { + const [ungroupedResult] = await previewMetricThresholdAlert({ + ...baseParams, + lookback: 'h', + alertInterval: '30s', + }); + const [firedResults, noDataResults, errorResults] = ungroupedResult; + expect(firedResults).toBe(60); + expect(noDataResults).toBe(0); + expect(errorResults).toBe(0); + }); + }); + describe('querying with a groupBy parameter', () => { + test('returns the expected results', async () => { + const [resultA, resultB] = await previewMetricThresholdAlert({ + ...baseParams, + params: { + ...baseParams.params, + groupBy: ['something'], + }, + lookback: 'h', + alertInterval: '1m', + }); + const [firedResultsA, noDataResultsA, errorResultsA] = resultA; + expect(firedResultsA).toBe(30); + expect(noDataResultsA).toBe(0); + expect(errorResultsA).toBe(0); + const [firedResultsB, noDataResultsB, errorResultsB] = resultB; + expect(firedResultsB).toBe(60); + expect(noDataResultsB).toBe(0); + expect(errorResultsB).toBe(0); + }); + }); + describe('querying a data set with a period of No Data', () => { + test('returns the expected results', async () => { + const [ungroupedResult] = await previewMetricThresholdAlert({ + ...baseParams, + params: { + ...baseParams.params, + criteria: [ + { + ...baseCriterion, + metric: 'test.metric.2', + } as MetricExpressionParams, + ], + }, + lookback: 'h', + alertInterval: '1m', + }); + const [firedResults, noDataResults, errorResults] = ungroupedResult; + expect(firedResults).toBe(25); + expect(noDataResults).toBe(10); + expect(errorResults).toBe(0); + }); + }); +}); + +const services: AlertServicesMock = alertsMock.createAlertServices(); +services.callCluster.mockImplementation(async (_: string, { body, index }: any) => { + const metric = body.query.bool.filter[1]?.exists.field; + if (body.aggs.groupings) { + if (body.aggs.groupings.composite.after) { + return mocks.compositeEndResponse; + } + return mocks.basicCompositePreviewResponse; + } + if (metric === 'test.metric.2') { + return mocks.alternateMetricPreviewResponse; + } + return mocks.basicMetricPreviewResponse; +}); + +const baseCriterion = { + aggType: Aggregators.AVERAGE, + metric: 'test.metric.1', + timeSize: 1, + timeUnit: 'm', + comparator: Comparator.GT, + threshold: [0.75], +} as MetricExpressionParams; + +const config = { + metricAlias: 'metricbeat-*', + fields: { + timefield: '@timestamp', + }, +} as any; + +const baseParams = { + callCluster: services.callCluster, + params: { + criteria: [baseCriterion], + groupBy: undefined, + filterQuery: undefined, + }, + config, +}; diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/test_mocks.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/test_mocks.ts index 164f1ed6d18e5..d1178f6766979 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/test_mocks.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/test_mocks.ts @@ -38,6 +38,13 @@ const bucketsC = [ }, ]; +const previewBucketsA = Array.from(Array(60), (_, i) => bucketsA[i % 2]); // Repeat bucketsA to a total length of 60 +const previewBucketsB = Array.from(Array(60), (_, i) => bucketsB[i % 2]); +const previewBucketsWithNulls = [ + ...Array.from(Array(10), (_, i) => ({ aggregatedValue: { value: null } })), + ...previewBucketsA.slice(10), +]; + export const basicMetricResponse = { aggregations: { aggregatedIntervals: { @@ -150,3 +157,50 @@ export const changedSourceIdResponse = { }, }, }; + +export const basicMetricPreviewResponse = { + aggregations: { + aggregatedIntervals: { + buckets: previewBucketsA, + }, + }, +}; + +export const alternateMetricPreviewResponse = { + aggregations: { + aggregatedIntervals: { + buckets: previewBucketsWithNulls, + }, + }, +}; + +export const basicCompositePreviewResponse = { + aggregations: { + groupings: { + after_key: { groupBy0: 'foo' }, + buckets: [ + { + key: { + groupBy0: 'a', + }, + aggregatedIntervals: { + buckets: previewBucketsA, + }, + }, + { + key: { + groupBy0: 'b', + }, + aggregatedIntervals: { + buckets: previewBucketsB, + }, + }, + ], + }, + }, + hits: { + total: { + value: 2, + }, + }, +}; diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/types.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/types.ts index 62ab94b7d8c83..cbe4014b24348 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/types.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/types.ts @@ -35,7 +35,7 @@ interface NonCountMetricExpressionParams extends BaseMetricExpressionParams { } interface CountMetricExpressionParams extends BaseMetricExpressionParams { - aggType: 'count'; + aggType: Aggregators.COUNT; metric: never; } From 6a85e893f759f3c897c900e71352dbc93853c4a0 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Thu, 13 Aug 2020 10:30:13 -0500 Subject: [PATCH 19/53] skip test Reporting paginates content #74922 --- .../test/functional/apps/reporting_management/report_listing.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/functional/apps/reporting_management/report_listing.ts b/x-pack/test/functional/apps/reporting_management/report_listing.ts index 5bb36103fc6f6..476f3e73d0923 100644 --- a/x-pack/test/functional/apps/reporting_management/report_listing.ts +++ b/x-pack/test/functional/apps/reporting_management/report_listing.ts @@ -68,7 +68,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }); - it('Paginates content', async () => { + it.skip('Paginates content', async () => { const previousButton = await testSubjects.find('pagination-button-previous'); // previous CAN NOT be clicked From d21d10003001adfd2464c64bb655a0dae2a36939 Mon Sep 17 00:00:00 2001 From: Caroline Horn <549577+cchaos@users.noreply.github.com> Date: Thu, 13 Aug 2020 11:44:22 -0400 Subject: [PATCH 20/53] Update design-specific GH code-owners (#74877) * Update design-specific GH code-owners Created a `@elastic/stack-design` encompassing all product designers associated with the stack+solutions (Kibana repo contributors, not cloud). The `@elastic/kibana-design` team has been reduced to the actual Kibana design team. Then other individual design teams have been added as code-owners to their respective folders containing SASS changes. --- .github/CODEOWNERS | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 73fb10532fd8d..6863b91858ff6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -8,6 +8,7 @@ /x-pack/plugins/lens/ @elastic/kibana-app /x-pack/plugins/graph/ @elastic/kibana-app /src/plugins/dashboard/ @elastic/kibana-app +/src/plugins/dashboard/**/*.scss @elastic/kibana-core-ui /src/plugins/discover/ @elastic/kibana-app /src/plugins/input_control_vis/ @elastic/kibana-app /src/plugins/kibana_legacy/ @elastic/kibana-app @@ -58,6 +59,7 @@ # APM /x-pack/plugins/apm/ @elastic/apm-ui +/x-pack/plugins/apm/**/*.scss @elastic/observability-design /x-pack/test/functional/apps/apm/ @elastic/apm-ui /src/legacy/core_plugins/apm_oss/ @elastic/apm-ui /src/plugins/apm_oss/ @elastic/apm-ui @@ -68,6 +70,7 @@ # Canvas /x-pack/plugins/canvas/ @elastic/kibana-canvas +/x-pack/plugins/canvas/**/*.scss @elastic/kibana-core-ui /x-pack/test/functional/apps/canvas/ @elastic/kibana-canvas # Core UI @@ -77,15 +80,18 @@ /src/plugins/home/server/services/ @elastic/kibana-core-ui # Exclude tutorial resources folder for now because they are not owned by Kibana app and most will move out soon /src/legacy/core_plugins/kibana/public/home/*.ts @elastic/kibana-core-ui -/src/legacy/core_plugins/kibana/public/home/*.scss @elastic/kibana-core-ui +/src/legacy/core_plugins/kibana/public/home/**/*.scss @elastic/kibana-core-ui /src/legacy/core_plugins/kibana/public/home/np_ready/ @elastic/kibana-core-ui # Observability UIs /x-pack/legacy/plugins/infra/ @elastic/logs-metrics-ui /x-pack/plugins/infra/ @elastic/logs-metrics-ui +/x-pack/plugins/infra/**/*.scss @elastic/observability-design /x-pack/plugins/ingest_manager/ @elastic/ingest-management +/x-pack/plugins/ingest_manager/**/*.scss @elastic/observability-design /x-pack/legacy/plugins/ingest_manager/ @elastic/ingest-management /x-pack/plugins/observability/ @elastic/observability-ui +/x-pack/plugins/observability/**/*.scss @elastic/observability-design /x-pack/legacy/plugins/monitoring/ @elastic/stack-monitoring-ui /x-pack/plugins/monitoring/ @elastic/stack-monitoring-ui /x-pack/plugins/uptime @elastic/uptime @@ -159,10 +165,14 @@ # Security /src/core/server/csp/ @elastic/kibana-security @elastic/kibana-platform /x-pack/legacy/plugins/security/ @elastic/kibana-security +/x-pack/legacy/plugins/security/**/*.scss @elastic/kibana-core-ui /x-pack/legacy/plugins/spaces/ @elastic/kibana-security +/x-pack/legacy/plugins/spaces/**/*.scss @elastic/kibana-core-ui /x-pack/plugins/spaces/ @elastic/kibana-security +/x-pack/plugins/spaces/**/*.scss @elastic/kibana-core-ui /x-pack/plugins/encrypted_saved_objects/ @elastic/kibana-security /x-pack/plugins/security/ @elastic/kibana-security +/x-pack/plugins/security/**/*.scss @elastic/kibana-core-ui /x-pack/test/api_integration/apis/security/ @elastic/kibana-security # Kibana Localization @@ -234,6 +244,7 @@ x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @elastic/kib # Endpoint /x-pack/plugins/endpoint/ @elastic/endpoint-app-team @elastic/siem +/x-pack/plugins/endpoint/**/*.scss @elastic/security-design /x-pack/test/api_integration/apis/endpoint/ @elastic/endpoint-app-team @elastic/siem /x-pack/test/endpoint_api_integration_no_ingest/ @elastic/endpoint-app-team @elastic/siem /x-pack/test/security_solution_endpoint/ @elastic/endpoint-app-team @elastic/siem @@ -243,6 +254,7 @@ x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @elastic/kib # Security Solution /x-pack/plugins/security_solution/ @elastic/siem @elastic/endpoint-app-team +/x-pack/plugins/security_solution/**/*.scss @elastic/security-design /x-pack/test/detection_engine_api_integration @elastic/siem @elastic/endpoint-app-team /x-pack/test/api_integration/apis/security_solution @elastic/siem @elastic/endpoint-app-team /x-pack/plugins/case @elastic/siem @elastic/endpoint-app-team From 4c810be33595d478c6eb802170d0644b32e62898 Mon Sep 17 00:00:00 2001 From: Spencer Date: Thu, 13 Aug 2020 09:08:44 -0700 Subject: [PATCH 21/53] Remove legacy optimizer (#73154) Co-authored-by: spalger Co-authored-by: Elastic Machine --- .eslintignore | 7 +- .eslintrc.js | 6 +- README.md | 1 - STYLEGUIDE.md | 2 +- docs/setup/install/deb.asciidoc | 6 - docs/setup/install/rpm.asciidoc | 6 - docs/setup/install/targz.asciidoc | 6 - docs/setup/install/windows.asciidoc | 6 - package.json | 24 - packages/eslint-config-kibana/package.json | 2 +- packages/kbn-babel-preset/package.json | 4 +- .../import_resolver_kibana.js | 23 +- .../lib/get_plugins.js | 66 - .../lib/get_webpack_config.js | 40 +- .../lib/index.js | 1 - .../lib/is_probably_webpack_shim.js | 59 - packages/kbn-optimizer/package.json | 1 - .../plugins/bar/public/legacy/styles.scss | 1 - .../core_app}/styles/_globals_v7dark.scss | 0 .../core_app}/styles/_globals_v7light.scss | 0 .../core_app}/styles/_globals_v8dark.scss | 0 .../core_app}/styles/_globals_v8light.scss | 0 .../mock_repo/src/legacy/ui/public/icon.svg | 1 - .../basic_optimization.test.ts.snap | 2 +- .../basic_optimization.test.ts | 7 +- .../src/worker/webpack.config.ts | 38 +- packages/kbn-plugin-helpers/package.json | 2 - .../src/lib/plugin_config.ts | 2 +- .../src/tasks/build/create_build.ts | 17 - .../build_action_test_plugin/index.js | 7 +- .../build_action_test_plugin/public/hack.js | 20 - .../create_build_test_plugin/index.js | 7 +- .../public/styles.scss | 3 - .../create_package_test_plugin/index.js | 7 +- .../create_package_test_plugin/public/hack.js | 20 - .../integration_tests/create_build.test.js | 26 +- packages/kbn-pm/dist/index.js | 31235 +++++++--------- packages/kbn-storybook/index.js | 10 +- packages/kbn-storybook/lib/storybook_entry.js | 2 +- .../kbn-storybook/lib/webpack.dll.config.js | 17 - packages/kbn-storybook/package.json | 1 + .../storybook_config/webpack.config.js | 28 +- .../src/functional_tests/lib/paths.js | 1 - packages/kbn-test/src/index.ts | 2 +- scripts/build_sass.js | 21 - src/cli/cluster/cluster_manager.test.ts | 52 +- src/cli/cluster/cluster_manager.ts | 61 +- src/cli/cluster/run_kbn_optimizer.ts | 5 +- src/cli/serve/serve.js | 5 +- src/core/MIGRATION.md | 1 - .../core_app}/images/bg_bottom_branded.svg | 0 .../images/bg_bottom_branded_dark.svg | 0 .../core_app}/images/bg_top_branded.svg | 0 .../core_app}/images/bg_top_branded_dark.svg | 0 .../core_app}/styles/_globals_v7dark.scss | 3 +- .../core_app}/styles/_globals_v7light.scss | 3 +- .../core_app}/styles/_globals_v8dark.scss | 0 .../core_app}/styles/_globals_v8light.scss | 0 .../public/core_app}/styles/_mixins.scss | 4 +- src/core/server/bootstrap.ts | 11 +- src/core/server/config/__mocks__/env.ts | 4 +- .../config/__snapshots__/env.test.ts.snap | 24 +- .../config/deprecation/core_deprecations.ts | 29 +- src/core/server/config/env.ts | 6 +- .../config_deprecation.test.ts | 25 +- .../server/core_app/assets/fonts/readme.md | 5 - .../server/core_app/assets/images/kibana.svg | 9 - .../core_app/assets/legacy_dark_theme.css | 4419 +++ .../core_app/assets/legacy_light_theme.css | 4419 +++ .../rendering_service.test.ts.snap | 274 - .../rendering/rendering_service.test.ts | 57 - .../server/rendering/rendering_service.tsx | 4 +- src/core/server/uuid/resolve_uuid.test.ts | 147 +- src/core/server/uuid/resolve_uuid.ts | 12 +- src/core/server/uuid/uuid_service.test.ts | 20 - src/core/server/uuid/uuid_service.ts | 5 +- src/dev/build/build_distributables.ts | 2 - src/dev/build/tasks/copy_source_task.ts | 1 - src/dev/build/tasks/index.ts | 2 - src/dev/build/tasks/optimize_task.ts | 52 - src/dev/build/tasks/transpile_scss_task.ts | 33 - src/dev/i18n/README.md | 14 +- .../test_plugin_1/test_file_2.pug | 10 - .../extract_default_translations.test.js.snap | 7 - src/dev/i18n/extract_default_translations.js | 11 +- .../extractors/__snapshots__/pug.test.js.snap | 37 - src/dev/i18n/extractors/index.js | 1 - src/dev/i18n/extractors/pug.js | 74 - src/dev/i18n/extractors/pug.test.js | 64 - .../tasks/extract_untracked_translations.ts | 1 - src/dev/jest/config.js | 1 + src/dev/precommit_hook/casing_check_config.js | 28 +- src/dev/sass/build_sass.js | 94 - src/dev/sass/run_build_sass_cli.js | 47 - src/legacy/core_plugins/kibana/index.js | 2 - src/legacy/core_plugins/status_page/index.js | 31 - .../core_plugins/status_page/package.json | 4 - .../status_page/public/components/render.js | 41 - .../status_page/public/status_page.html | 1 - .../status_page/public/status_page.js | 33 - .../plugin_spec/plugin_spec_options.d.ts | 4 - src/legacy/plugin_discovery/types.ts | 2 - src/legacy/server/config/schema.js | 25 - src/legacy/server/http/index.js | 12 +- src/legacy/server/kbn_server.js | 10 +- .../server/sass/__fixtures__/images/img.png | Bin 3820 -> 0 bytes .../server/sass/__fixtures__/index.scss | 6 - src/legacy/server/sass/build.js | 194 - src/legacy/server/sass/build.test.js | 119 - src/legacy/server/sass/build_all.js | 45 - src/legacy/server/sass/index.js | 137 - src/legacy/server/views/index.pug | 6 - src/legacy/ui/public/UI_SYSTEMS.md | 8 - .../ui/public/chrome/__mocks__/index.js | 6 - src/legacy/ui/public/chrome/chrome.js | 6 - .../public/styles/bootstrap/_colors_dark.less | 20 - .../styles/bootstrap/_colors_light.less | 20 - .../styles/bootstrap/_custom_variables.less | 443 - .../_custom_variables_dark_overrides.less | 4 - .../public/styles/bootstrap/_overrides.less | 252 - .../ui/public/styles/bootstrap/alerts.less | 73 - .../styles/bootstrap/bootstrap_dark.less | 77 - .../styles/bootstrap/bootstrap_light.less | 76 - .../ui/public/styles/bootstrap/buttons.less | 69 - .../ui/public/styles/bootstrap/close.less | 34 - .../bootstrap/component-animations.less | 33 - .../ui/public/styles/bootstrap/dropdowns.less | 227 - .../ui/public/styles/bootstrap/forms.less | 470 - .../ui/public/styles/bootstrap/grid.less | 84 - .../public/styles/bootstrap/input-groups.less | 117 - .../ui/public/styles/bootstrap/labels.less | 58 - .../public/styles/bootstrap/list-group.less | 133 - .../ui/public/styles/bootstrap/mixins.less | 40 - .../styles/bootstrap/mixins/alerts.less | 14 - .../bootstrap/mixins/background-variant.less | 9 - .../bootstrap/mixins/border-radius.less | 18 - .../styles/bootstrap/mixins/buttons.less | 65 - .../styles/bootstrap/mixins/center-block.less | 7 - .../styles/bootstrap/mixins/clearfix.less | 22 - .../public/styles/bootstrap/mixins/forms.less | 85 - .../styles/bootstrap/mixins/gradients.less | 59 - .../bootstrap/mixins/grid-framework.less | 91 - .../public/styles/bootstrap/mixins/grid.less | 122 - .../styles/bootstrap/mixins/hide-text.less | 21 - .../public/styles/bootstrap/mixins/image.less | 33 - .../styles/bootstrap/mixins/labels.less | 12 - .../styles/bootstrap/mixins/list-group.less | 30 - .../styles/bootstrap/mixins/nav-divider.less | 10 - .../bootstrap/mixins/nav-vertical-align.less | 9 - .../styles/bootstrap/mixins/opacity.less | 8 - .../styles/bootstrap/mixins/pagination.less | 24 - .../styles/bootstrap/mixins/panels.less | 24 - .../styles/bootstrap/mixins/progress-bar.less | 10 - .../styles/bootstrap/mixins/reset-filter.less | 8 - .../styles/bootstrap/mixins/reset-text.less | 18 - .../styles/bootstrap/mixins/resize.less | 6 - .../mixins/responsive-visibility.less | 15 - .../public/styles/bootstrap/mixins/size.less | 10 - .../styles/bootstrap/mixins/tab-focus.less | 5 - .../styles/bootstrap/mixins/table-row.less | 28 - .../bootstrap/mixins/text-emphasis.less | 9 - .../bootstrap/mixins/text-overflow.less | 8 - .../bootstrap/mixins/vendor-prefixes.less | 227 - .../ui/public/styles/bootstrap/modals.less | 136 - .../ui/public/styles/bootstrap/navbar.less | 603 - .../ui/public/styles/bootstrap/navs.less | 243 - .../ui/public/styles/bootstrap/pager.less | 54 - .../public/styles/bootstrap/pagination.less | 89 - .../ui/public/styles/bootstrap/panels.less | 271 - .../ui/public/styles/bootstrap/popovers.less | 131 - .../styles/bootstrap/progress-bars.less | 86 - .../bootstrap/responsive-utilities.less | 173 - .../ui/public/styles/bootstrap/tables.less | 227 - .../ui/public/styles/bootstrap/tooltip.less | 101 - .../ui/public/styles/bootstrap/type.less | 63 - .../ui/public/styles/bootstrap/utilities.less | 55 - .../ui/public/styles/bootstrap/variables.less | 852 - .../ui/public/styles/bootstrap_dark.less | 4 - .../ui/public/styles/bootstrap_light.less | 5 - .../__tests__/app_entry_template.js | 45 - .../ui/ui_bundles/__tests__/ui_bundle.js | 50 - .../ui/ui_bundles/app_entry_template.js | 66 - src/legacy/ui/ui_bundles/ui_bundle.js | 125 - .../ui/ui_bundles/ui_bundles_controller.js | 255 - src/legacy/ui/ui_bundles/ui_bundles_mixin.js | 29 - .../__tests__/collect_ui_exports.js | 12 - .../ui/ui_exports/ui_export_defaults.js | 28 +- .../ui/ui_exports/ui_export_types/index.js | 38 - .../ui_export_types/style_sheet_paths.js | 97 - .../ui_export_types/style_sheet_paths.test.js | 139 - .../ui_export_types/ui_app_extensions.js | 66 - .../ui/ui_exports/ui_export_types/ui_apps.js | 70 - .../ui_export_types/webpack_customizations.js | 48 - src/legacy/ui/ui_mixin.js | 2 - .../ui/ui_render/bootstrap/template.js.hbs | 7 +- src/legacy/ui/ui_render/ui_render_mixin.js | 30 +- src/optimize/base_optimizer.js | 520 - .../outside_output.js | 0 .../plugin/foo}/image.png | Bin .../plugin/foo/plugin.js} | 0 .../bundles_route/__tests__/bundles_route.js | 440 - .../fixtures/output/no_placeholder.css | 3 - .../fixtures/output/no_placeholder.js | 20 - .../fixtures/output/with_placeholder.css | 3 - .../fixtures/output/with_placeholder.js | 20 - .../plugin/placeholder/placeholder.plugin.js | 20 - .../bundles_route/bundles_route.test.ts | 307 + src/optimize/bundles_route/bundles_route.ts | 36 +- .../bundles_route/dynamic_asset_response.ts | 10 +- .../bundles_route/proxy_bundles_route.ts | 5 +- src/optimize/create_ui_exports_module.js | 40 - src/optimize/fs_optimizer.js | 41 - src/optimize/index.js | 21 - .../public/hack.js => src/optimize/index.ts | 2 +- src/optimize/intentionally_empty_module.js | 18 - src/optimize/optimize_mixin.ts | 58 - src/optimize/postcss.config.js | 22 - src/optimize/public_path_placeholder.ts | 57 - src/optimize/watch/optmzr_role.js | 74 - src/optimize/watch/proxy_role.js | 57 - src/optimize/watch/watch.js | 51 - src/optimize/watch/watch_optimizer.js | 192 - src/optimize/watch/watch_server.js | 47 - src/plugins/timelion/public/flot.js | 26 - .../timelion/public/flot}/index.js | 8 +- .../jquery.flot.axislabels.js | 0 .../jquery.flot.crosshair.js | 0 .../{webpackShims => flot}/jquery.flot.js | 0 .../jquery.flot.selection.js | 0 .../jquery.flot.stack.js | 0 .../jquery.flot.symbol.js | 0 .../jquery.flot.time.js | 0 src/plugins/vis_type_timelion/public/flot.js | 26 - .../vis_type_timelion/public/flot}/index.js | 8 +- .../jquery.flot.axislabels.js | 0 .../jquery.flot.crosshair.js | 0 .../{webpackShims => flot}/jquery.flot.js | 0 .../jquery.flot.selection.js | 0 .../jquery.flot.stack.js | 0 .../jquery.flot.symbol.js | 0 .../jquery.flot.time.js | 0 src/test_utils/kbn_server.ts | 5 +- test/api_integration/config.js | 1 - test/common/config.js | 13 +- test/functional/apps/bundles/index.js | 7 - .../plugins/core_plugin_legacy/index.ts | 50 - .../plugins/core_plugin_legacy/package.json | 17 - .../core_plugin_legacy/public/application.tsx | 34 - .../core_plugin_legacy/public/index.ts | 29 - .../plugins/core_plugin_legacy/tsconfig.json | 15 - .../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 | 21 - .../test_suites/core_plugins/index.ts | 1 - .../core_plugins/legacy_plugins.ts | 52 - .../test_suites/core_plugins/rendering.ts | 36 - test/scripts/jenkins_xpack.sh | 6 - test/server_integration/config.js | 1 - test/server_integration/http/cache/index.js | 5 +- webpackShims/.eslintrc | 2 - webpackShims/ace.js | 24 - webpackShims/elasticsearch.js | 23 - webpackShims/lru-cache.js | 20 - webpackShims/mocha.js | 20 - webpackShims/sinon.js | 21 - x-pack/.kibana-plugin-helpers.json | 1 - x-pack/legacy/plugins/security/index.ts | 1 - .../plugins/security/public/hacks/legacy.ts | 64 - x-pack/legacy/plugins/spaces/index.ts | 4 - x-pack/legacy/plugins/spaces/public/legacy.ts | 18 - x-pack/legacy/plugins/xpack_main/index.js | 11 - .../xpack_main/public/components/index.js | 16 - .../public/hacks/check_xpack_info_change.js | 53 - .../xpack_main/public/jquery_flot/index.js | 7 - .../public/jquery_flot/jquery_flot.js | 19 - .../public/services/__tests__/_mock_window.js | 23 - .../public/services/__tests__/xpack_info.js | 46 - .../__tests__/xpack_info_signature.js | 24 - .../xpack_main/public/services/path.js | 19 - .../xpack_main/public/services/xpack_info.js | 76 - .../public/services/xpack_info_signature.js | 19 - .../datasource_preview/datasource_preview.js | 2 +- .../public/expression_types/arg_types/font.js | 2 +- .../canvas/scripts/shareable_runtime.js | 6 - x-pack/plugins/canvas/scripts/storybook.js | 17 - .../plugins/canvas/shareable_runtime/index.ts | 19 +- .../shareable_runtime/webpack.config.js | 40 +- x-pack/plugins/canvas/storybook/constants.js | 4 +- .../plugins/canvas/storybook/dll_contexts.js | 20 +- x-pack/plugins/canvas/storybook/preview.ts | 9 - .../canvas/storybook/webpack.config.js | 5 +- .../canvas/storybook/webpack.dll.config.js | 16 - x-pack/plugins/graph/public/application.ts | 6 +- x-pack/test/api_integration/config.ts | 1 - .../login_selector_api_integration/config.ts | 1 - x-pack/test/saml_api_integration/config.ts | 1 - .../common/config.ts | 1 - .../spaces_api_integration/common/config.ts | 1 - x-pack/test/token_api_integration/config.js | 1 - .../upgrade_assistant_integration/config.js | 8 +- yarn.lock | 805 +- 303 files changed, 23623 insertions(+), 30328 deletions(-) delete mode 100755 packages/kbn-eslint-import-resolver-kibana/lib/get_plugins.js delete mode 100644 packages/kbn-eslint-import-resolver-kibana/lib/is_probably_webpack_shim.js rename packages/kbn-optimizer/src/__fixtures__/mock_repo/src/{legacy/ui/public => core/public/core_app}/styles/_globals_v7dark.scss (100%) rename packages/kbn-optimizer/src/__fixtures__/mock_repo/src/{legacy/ui/public => core/public/core_app}/styles/_globals_v7light.scss (100%) rename packages/kbn-optimizer/src/__fixtures__/mock_repo/src/{legacy/ui/public => core/public/core_app}/styles/_globals_v8dark.scss (100%) rename packages/kbn-optimizer/src/__fixtures__/mock_repo/src/{legacy/ui/public => core/public/core_app}/styles/_globals_v8light.scss (100%) delete mode 100644 packages/kbn-optimizer/src/__fixtures__/mock_repo/src/legacy/ui/public/icon.svg delete mode 100644 packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/build_action_test_plugin/public/hack.js delete mode 100644 packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/create_build_test_plugin/public/styles.scss delete mode 100644 packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/create_package_test_plugin/public/hack.js delete mode 100644 scripts/build_sass.js rename src/core/{server/core_app/assets => public/core_app}/images/bg_bottom_branded.svg (100%) rename src/core/{server/core_app/assets => public/core_app}/images/bg_bottom_branded_dark.svg (100%) rename src/core/{server/core_app/assets => public/core_app}/images/bg_top_branded.svg (100%) rename src/core/{server/core_app/assets => public/core_app}/images/bg_top_branded_dark.svg (100%) rename src/{legacy/ui/public => core/public/core_app}/styles/_globals_v7dark.scss (81%) rename src/{legacy/ui/public => core/public/core_app}/styles/_globals_v7light.scss (80%) rename src/{legacy/ui/public => core/public/core_app}/styles/_globals_v8dark.scss (100%) rename src/{legacy/ui/public => core/public/core_app}/styles/_globals_v8light.scss (100%) rename src/{legacy/ui/public => core/public/core_app}/styles/_mixins.scss (88%) delete mode 100644 src/core/server/core_app/assets/images/kibana.svg create mode 100644 src/core/server/core_app/assets/legacy_dark_theme.css create mode 100644 src/core/server/core_app/assets/legacy_light_theme.css delete mode 100644 src/dev/build/tasks/optimize_task.ts delete mode 100644 src/dev/build/tasks/transpile_scss_task.ts delete mode 100644 src/dev/i18n/__fixtures__/extract_default_translations/test_plugin_1/test_file_2.pug delete mode 100644 src/dev/i18n/extractors/__snapshots__/pug.test.js.snap delete mode 100644 src/dev/i18n/extractors/pug.js delete mode 100644 src/dev/i18n/extractors/pug.test.js delete mode 100644 src/dev/sass/build_sass.js delete mode 100644 src/dev/sass/run_build_sass_cli.js delete mode 100644 src/legacy/core_plugins/status_page/index.js delete mode 100644 src/legacy/core_plugins/status_page/package.json delete mode 100644 src/legacy/core_plugins/status_page/public/components/render.js delete mode 100644 src/legacy/core_plugins/status_page/public/status_page.html delete mode 100644 src/legacy/core_plugins/status_page/public/status_page.js delete mode 100644 src/legacy/server/sass/__fixtures__/images/img.png delete mode 100644 src/legacy/server/sass/__fixtures__/index.scss delete mode 100644 src/legacy/server/sass/build.js delete mode 100644 src/legacy/server/sass/build.test.js delete mode 100644 src/legacy/server/sass/build_all.js delete mode 100644 src/legacy/server/sass/index.js delete mode 100644 src/legacy/server/views/index.pug delete mode 100644 src/legacy/ui/public/UI_SYSTEMS.md delete mode 100644 src/legacy/ui/public/styles/bootstrap/_colors_dark.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/_colors_light.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/_custom_variables.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/_custom_variables_dark_overrides.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/_overrides.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/alerts.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/bootstrap_dark.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/bootstrap_light.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/buttons.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/close.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/component-animations.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/dropdowns.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/forms.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/grid.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/input-groups.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/labels.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/list-group.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/alerts.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/background-variant.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/border-radius.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/buttons.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/center-block.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/clearfix.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/forms.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/gradients.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/grid-framework.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/grid.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/hide-text.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/image.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/labels.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/list-group.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/nav-divider.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/nav-vertical-align.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/opacity.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/pagination.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/panels.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/progress-bar.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/reset-filter.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/reset-text.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/resize.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/responsive-visibility.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/size.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/tab-focus.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/table-row.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/text-emphasis.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/text-overflow.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/mixins/vendor-prefixes.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/modals.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/navbar.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/navs.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/pager.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/pagination.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/panels.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/popovers.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/progress-bars.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/responsive-utilities.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/tables.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/tooltip.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/type.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/utilities.less delete mode 100644 src/legacy/ui/public/styles/bootstrap/variables.less delete mode 100644 src/legacy/ui/public/styles/bootstrap_dark.less delete mode 100644 src/legacy/ui/public/styles/bootstrap_light.less delete mode 100644 src/legacy/ui/ui_bundles/__tests__/app_entry_template.js delete mode 100644 src/legacy/ui/ui_bundles/__tests__/ui_bundle.js delete mode 100644 src/legacy/ui/ui_bundles/app_entry_template.js delete mode 100644 src/legacy/ui/ui_bundles/ui_bundle.js delete mode 100644 src/legacy/ui/ui_bundles/ui_bundles_controller.js delete mode 100644 src/legacy/ui/ui_bundles/ui_bundles_mixin.js delete mode 100644 src/legacy/ui/ui_exports/ui_export_types/style_sheet_paths.js delete mode 100644 src/legacy/ui/ui_exports/ui_export_types/style_sheet_paths.test.js delete mode 100644 src/legacy/ui/ui_exports/ui_export_types/ui_app_extensions.js delete mode 100644 src/legacy/ui/ui_exports/ui_export_types/ui_apps.js delete mode 100644 src/legacy/ui/ui_exports/ui_export_types/webpack_customizations.js delete mode 100644 src/optimize/base_optimizer.js rename src/optimize/bundles_route/{__tests__/fixtures => __fixtures__}/outside_output.js (100%) rename src/optimize/bundles_route/{__tests__/fixtures/output => __fixtures__/plugin/foo}/image.png (100%) rename src/optimize/bundles_route/{__tests__/fixtures/plugin/no_placeholder/no_placeholder.plugin.js => __fixtures__/plugin/foo/plugin.js} (100%) delete mode 100644 src/optimize/bundles_route/__tests__/bundles_route.js delete mode 100644 src/optimize/bundles_route/__tests__/fixtures/output/no_placeholder.css delete mode 100644 src/optimize/bundles_route/__tests__/fixtures/output/no_placeholder.js delete mode 100644 src/optimize/bundles_route/__tests__/fixtures/output/with_placeholder.css delete mode 100644 src/optimize/bundles_route/__tests__/fixtures/output/with_placeholder.js delete mode 100644 src/optimize/bundles_route/__tests__/fixtures/plugin/placeholder/placeholder.plugin.js create mode 100644 src/optimize/bundles_route/bundles_route.test.ts delete mode 100644 src/optimize/create_ui_exports_module.js delete mode 100644 src/optimize/fs_optimizer.js delete mode 100644 src/optimize/index.js rename packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/create_build_test_plugin/public/hack.js => src/optimize/index.ts (94%) delete mode 100644 src/optimize/intentionally_empty_module.js delete mode 100644 src/optimize/postcss.config.js delete mode 100644 src/optimize/public_path_placeholder.ts delete mode 100644 src/optimize/watch/optmzr_role.js delete mode 100644 src/optimize/watch/proxy_role.js delete mode 100644 src/optimize/watch/watch.js delete mode 100644 src/optimize/watch/watch_optimizer.js delete mode 100644 src/optimize/watch/watch_server.js delete mode 100644 src/plugins/timelion/public/flot.js rename src/{dev/sass => plugins/timelion/public/flot}/index.js (78%) rename src/plugins/timelion/public/{webpackShims => flot}/jquery.flot.axislabels.js (100%) rename src/plugins/timelion/public/{webpackShims => flot}/jquery.flot.crosshair.js (100%) rename src/plugins/timelion/public/{webpackShims => flot}/jquery.flot.js (100%) rename src/plugins/timelion/public/{webpackShims => flot}/jquery.flot.selection.js (100%) rename src/plugins/timelion/public/{webpackShims => flot}/jquery.flot.stack.js (100%) rename src/plugins/timelion/public/{webpackShims => flot}/jquery.flot.symbol.js (100%) rename src/plugins/timelion/public/{webpackShims => flot}/jquery.flot.time.js (100%) delete mode 100644 src/plugins/vis_type_timelion/public/flot.js rename src/{legacy/ui/ui_bundles => plugins/vis_type_timelion/public/flot}/index.js (78%) rename src/plugins/vis_type_timelion/public/{webpackShims => flot}/jquery.flot.axislabels.js (100%) rename src/plugins/vis_type_timelion/public/{webpackShims => flot}/jquery.flot.crosshair.js (100%) rename src/plugins/vis_type_timelion/public/{webpackShims => flot}/jquery.flot.js (100%) rename src/plugins/vis_type_timelion/public/{webpackShims => flot}/jquery.flot.selection.js (100%) rename src/plugins/vis_type_timelion/public/{webpackShims => flot}/jquery.flot.stack.js (100%) rename src/plugins/vis_type_timelion/public/{webpackShims => flot}/jquery.flot.symbol.js (100%) rename src/plugins/vis_type_timelion/public/{webpackShims => flot}/jquery.flot.time.js (100%) delete mode 100644 test/plugin_functional/plugins/core_plugin_legacy/index.ts delete mode 100644 test/plugin_functional/plugins/core_plugin_legacy/package.json delete mode 100644 test/plugin_functional/plugins/core_plugin_legacy/public/application.tsx delete mode 100644 test/plugin_functional/plugins/core_plugin_legacy/public/index.ts delete mode 100644 test/plugin_functional/plugins/core_plugin_legacy/tsconfig.json delete mode 100644 test/plugin_functional/plugins/legacy_plugin/index.ts delete mode 100644 test/plugin_functional/plugins/legacy_plugin/package.json delete mode 100644 test/plugin_functional/plugins/legacy_plugin/public/index.tsx delete mode 100644 test/plugin_functional/plugins/legacy_plugin/tsconfig.json delete mode 100644 test/plugin_functional/test_suites/core_plugins/legacy_plugins.ts delete mode 100644 webpackShims/.eslintrc delete mode 100644 webpackShims/ace.js delete mode 100644 webpackShims/elasticsearch.js delete mode 100644 webpackShims/lru-cache.js delete mode 100644 webpackShims/mocha.js delete mode 100644 webpackShims/sinon.js delete mode 100644 x-pack/legacy/plugins/security/public/hacks/legacy.ts delete mode 100644 x-pack/legacy/plugins/spaces/public/legacy.ts delete mode 100644 x-pack/legacy/plugins/xpack_main/public/components/index.js delete mode 100644 x-pack/legacy/plugins/xpack_main/public/hacks/check_xpack_info_change.js delete mode 100644 x-pack/legacy/plugins/xpack_main/public/jquery_flot/index.js delete mode 100644 x-pack/legacy/plugins/xpack_main/public/jquery_flot/jquery_flot.js delete mode 100644 x-pack/legacy/plugins/xpack_main/public/services/__tests__/_mock_window.js delete mode 100644 x-pack/legacy/plugins/xpack_main/public/services/__tests__/xpack_info.js delete mode 100644 x-pack/legacy/plugins/xpack_main/public/services/__tests__/xpack_info_signature.js delete mode 100644 x-pack/legacy/plugins/xpack_main/public/services/path.js delete mode 100644 x-pack/legacy/plugins/xpack_main/public/services/xpack_info.js delete mode 100644 x-pack/legacy/plugins/xpack_main/public/services/xpack_info_signature.js diff --git a/.eslintignore b/.eslintignore index 9263b483b8de9..2b291e1c19714 100644 --- a/.eslintignore +++ b/.eslintignore @@ -18,15 +18,12 @@ target # plugin overrides /src/core/lib/kbn_internal_native_observable -/src/legacy/core_plugins/console/public/tests/webpackShims -/src/legacy/core_plugins/console/public/webpackShims /src/legacy/plugin_discovery/plugin_pack/__tests__/fixtures/plugins/broken /src/legacy/ui/public/flot-charts -/src/legacy/ui/public/utils/decode_geo_hash.js /src/plugins/data/common/es_query/kuery/ast/_generated_/** /src/plugins/vis_type_timelion/public/_generated_/** -/src/plugins/vis_type_timelion/public/webpackShims/jquery.flot.* -/src/plugins/timelion/public/webpackShims/jquery.flot.* +/src/plugins/vis_type_timelion/public/flot/jquery.flot.* +/src/plugins/timelion/public/flot/jquery.flot.* /x-pack/legacy/plugins/**/__tests__/fixtures/** /x-pack/plugins/apm/e2e/**/snapshots.js /x-pack/plugins/apm/e2e/tmp/* diff --git a/.eslintrc.js b/.eslintrc.js index 5a03552ba3a51..5cd9809242bba 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -400,7 +400,7 @@ module.exports = { }, { target: ['(src|x-pack)/plugins/*/public/**/*'], - from: ['ui/**/*', 'uiExports/**/*'], + from: ['ui/**/*'], errorMessage: 'Plugins cannot import legacy UI code.', }, { @@ -457,14 +457,13 @@ module.exports = { { files: [ '**/public/**/*.js', - '**/webpackShims/**/*.js', 'packages/kbn-ui-framework/doc_site/src/**/*.js', 'src/fixtures/**/*.js', // TODO: this directory needs to be more obviously "public" (or go away) ], settings: { // instructs import/no-extraneous-dependencies to treat certain modules // as core modules, even if they aren't listed in package.json - 'import/core-modules': ['plugins', 'legacy/ui', 'uiExports'], + 'import/core-modules': ['plugins', 'legacy/ui'], 'import/resolver': { '@kbn/eslint-import-resolver-kibana': { @@ -605,7 +604,6 @@ module.exports = { { files: [ '.eslintrc.js', - '**/webpackShims/**/*.js', 'packages/kbn-plugin-generator/**/*.js', 'packages/kbn-eslint-import-resolver-kibana/**/*.js', 'packages/kbn-eslint-plugin-eslint/**/*', diff --git a/README.md b/README.md index 03ce6a6525873..b786d95ce2994 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,6 @@ out an open PR: - [CONTRIBUTING.md](CONTRIBUTING.md) will help you get Kibana up and running. - If you would like to contribute code, please follow our [STYLEGUIDE.md](STYLEGUIDE.md). -- Learn more about our UI code with [UI_SYSTEMS.md](src/legacy/ui/public/UI_SYSTEMS.md). - For all other questions, check out the [FAQ.md](FAQ.md) and [wiki](https://github.com/elastic/kibana/wiki). diff --git a/STYLEGUIDE.md b/STYLEGUIDE.md index 4ea7b04ebef6d..94bb40ab3ff2e 100644 --- a/STYLEGUIDE.md +++ b/STYLEGUIDE.md @@ -593,7 +593,7 @@ Do not use setters, they cause more problems than they can solve. When writing a new component, create a sibling SASS file of the same name and import directly into the **top** of the JS/TS component file. Doing so ensures the styles are never separated or lost on import and allows for better modularization (smaller individual plugin asset footprint). -All SASS (.scss) files will automatically build with the [EUI](https://elastic.github.io/eui/#/guidelines/sass) & Kibana invisibles (SASS variables, mixins, functions) from the [`globals_[theme].scss` file](src/legacy/ui/public/styles/_globals_v7light.scss). +All SASS (.scss) files will automatically build with the [EUI](https://elastic.github.io/eui/#/guidelines/sass) & Kibana invisibles (SASS variables, mixins, functions) from the [`globals_[theme].scss` file](src/core/public/core_app/styles/_globals_v7light.scss). While the styles for this component will only be loaded if the component exists on the page, the styles **will** be global and so it is recommended to use a three letter prefix on your diff --git a/docs/setup/install/deb.asciidoc b/docs/setup/install/deb.asciidoc index d24c1cf8ae9d1..234c02cee0be1 100644 --- a/docs/setup/install/deb.asciidoc +++ b/docs/setup/install/deb.asciidoc @@ -214,12 +214,6 @@ locations for a Debian-based system: | /var/log/kibana | path.logs -| optimize - | Transpiled source code. Certain administrative actions (e.g. plugin install) - result in the source code being retranspiled on the fly. - | /var/lib/kibana/optimize - d| - | plugins | Plugin files location. Each plugin will be contained in a subdirectory. | /usr/share/kibana/plugins diff --git a/docs/setup/install/rpm.asciidoc b/docs/setup/install/rpm.asciidoc index 5d4f47f300eac..1153353aa9a0f 100644 --- a/docs/setup/install/rpm.asciidoc +++ b/docs/setup/install/rpm.asciidoc @@ -206,12 +206,6 @@ locations for an RPM-based system: | /var/log/kibana | path.logs -| optimize - | Transpiled source code. Certain administrative actions (e.g. plugin install) - result in the source code being retranspiled on the fly. - | /var/lib/kibana/optimize - d| - | plugins | Plugin files location. Each plugin will be contained in a subdirectory. | /usr/share/kibana/plugins diff --git a/docs/setup/install/targz.asciidoc b/docs/setup/install/targz.asciidoc index 14ee1b297ffc6..c7e784186da09 100644 --- a/docs/setup/install/targz.asciidoc +++ b/docs/setup/install/targz.asciidoc @@ -149,12 +149,6 @@ important data later on. | $KIBANA_HOME\data d| -| optimize - | Transpiled source code. Certain administrative actions (e.g. plugin install) - result in the source code being retranspiled on the fly. - | $KIBANA_HOME\data\optimize - d| - | plugins | Plugin files location. Each plugin will be contained in a subdirectory. | $KIBANA_HOME\plugins diff --git a/docs/setup/install/windows.asciidoc b/docs/setup/install/windows.asciidoc index 0d467f2fa7dd9..ce6bf3766fa20 100644 --- a/docs/setup/install/windows.asciidoc +++ b/docs/setup/install/windows.asciidoc @@ -96,12 +96,6 @@ important data later on. | $KIBANA_HOME\data d| -| optimize - | Transpiled source code. Certain administrative actions (e.g. plugin install) - result in the source code being retranspiled on the fly. - | $KIBANA_HOME\data\optimize - d| - | plugins | Plugin files location. Each plugin will be contained in a subdirectory. | $KIBANA_HOME\plugins diff --git a/package.json b/package.json index 200aa41743f51..df35e5901159b 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,6 @@ }, "dependencies": { "@babel/core": "^7.11.1", - "@babel/plugin-transform-modules-commonjs": "^7.10.4", "@babel/register": "^7.10.5", "@elastic/apm-rum": "^5.4.0", "@elastic/charts": "19.8.1", @@ -154,12 +153,9 @@ "angular-route": "^1.8.0", "angular-sanitize": "^1.8.0", "angular-sortable-view": "^0.0.17", - "autoprefixer": "^9.7.4", - "babel-loader": "^8.0.6", "bluebird": "3.5.5", "boom": "^7.2.0", "brace": "0.11.1", - "cache-loader": "^4.1.0", "chalk": "^2.4.2", "check-disk-space": "^2.1.0", "chokidar": "3.2.1", @@ -167,7 +163,6 @@ "commander": "3.0.2", "compare-versions": "3.5.1", "core-js": "^3.6.4", - "css-loader": "^3.4.2", "d3": "3.5.17", "d3-cloud": "1.2.5", "deep-freeze-strict": "^1.1.1", @@ -179,7 +174,6 @@ "execa": "^4.0.2", "expiry-js": "0.1.7", "fast-deep-equal": "^3.1.1", - "file-loader": "4.2.0", "font-awesome": "4.7.0", "fp-ts": "^2.3.1", "getos": "^3.1.0", @@ -211,11 +205,9 @@ "leaflet-vega": "^0.8.6", "leaflet.heat": "0.2.0", "less": "npm:@elastic/less@2.7.3-kibana", - "less-loader": "5.0.0", "lodash": "^4.17.15", "lru-cache": "4.1.5", "markdown-it": "^10.0.0", - "mini-css-extract-plugin": "0.8.0", "minimatch": "^3.0.4", "moment": "^2.24.0", "moment-timezone": "^0.5.27", @@ -227,12 +219,9 @@ "opn": "^5.5.0", "oppsy": "^2.0.0", "pegjs": "0.10.0", - "postcss-loader": "^3.0.0", "prop-types": "15.6.0", "proxy-from-env": "1.0.0", - "pug": "^2.0.4", "query-string": "5.1.1", - "raw-loader": "3.1.0", "re2": "^1.15.4", "react": "^16.12.0", "react-color": "^2.13.8", @@ -258,33 +247,24 @@ "resize-observer-polyfill": "^1.5.0", "rison-node": "1.0.2", "rxjs": "^6.5.5", - "script-loader": "0.7.2", "seedrandom": "^3.0.5", "semver": "^5.5.0", "style-it": "^2.1.3", - "style-loader": "^1.1.3", "symbol-observable": "^1.2.0", "tar": "4.4.13", - "terser-webpack-plugin": "^2.3.4", - "thread-loader": "^2.1.3", "tinygradient": "0.4.3", "tinymath": "1.2.1", "topojson-client": "3.0.0", "tslib": "^2.0.0", "type-detect": "^4.0.8", "ui-select": "0.19.8", - "url-loader": "2.2.0", "uuid": "3.3.2", - "val-loader": "^1.1.1", "vega": "^5.13.0", "vega-lite": "^4.13.1", "vega-schema-url-parser": "^1.1.0", "vega-tooltip": "^0.12.0", "vision": "^5.3.3", - "webpack": "^4.41.5", - "webpack-merge": "4.2.2", "whatwg-fetch": "^3.0.0", - "wrapper-webpack-plugin": "^2.1.0", "yauzl": "2.10.0" }, "devDependencies": { @@ -450,8 +430,6 @@ "has-ansi": "^3.0.0", "iedriver": "^3.14.2", "intl-messageformat-parser": "^1.4.0", - "is-path-inside": "^2.1.0", - "istanbul-instrumenter-loader": "3.0.1", "jest": "^25.5.4", "jest-canvas-mock": "^2.2.0", "jest-circus": "^25.5.4", @@ -472,14 +450,12 @@ "murmurhash3js": "3.0.1", "mutation-observer": "^1.0.3", "nock": "12.0.3", - "node-sass": "^4.13.1", "normalize-path": "^3.0.0", "nyc": "^15.0.1", "pixelmatch": "^5.1.0", "pkg-up": "^2.0.0", "pngjs": "^3.4.0", "postcss": "^7.0.32", - "postcss-url": "^8.0.0", "prettier": "^2.0.5", "proxyquire": "1.8.0", "react-popper-tooltip": "^2.10.1", diff --git a/packages/eslint-config-kibana/package.json b/packages/eslint-config-kibana/package.json index 967e53249da75..618f71daf0339 100644 --- a/packages/eslint-config-kibana/package.json +++ b/packages/eslint-config-kibana/package.json @@ -29,6 +29,6 @@ "eslint-plugin-no-unsanitized": "^3.0.2", "eslint-plugin-prefer-object-spread": "^1.2.1", "eslint-plugin-react": "^7.17.0", - "eslint-plugin-react-hooks": "^2.3.0" + "eslint-plugin-react-hooks": "^4.0.4" } } diff --git a/packages/kbn-babel-preset/package.json b/packages/kbn-babel-preset/package.json index db1f2161b6e38..d73294b4cf873 100644 --- a/packages/kbn-babel-preset/package.json +++ b/packages/kbn-babel-preset/package.json @@ -16,6 +16,8 @@ "babel-plugin-filter-imports": "^3.0.0", "babel-plugin-styled-components": "^1.10.7", "babel-plugin-transform-define": "^1.3.1", - "babel-plugin-transform-imports": "^2.0.0" + "babel-plugin-transform-imports": "^2.0.0", + "react-is": "^16.8.0", + "styled-components": "^5.1.0" } } diff --git a/packages/kbn-eslint-import-resolver-kibana/import_resolver_kibana.js b/packages/kbn-eslint-import-resolver-kibana/import_resolver_kibana.js index 5c409ade260b1..c2a28ef23a1d1 100755 --- a/packages/kbn-eslint-import-resolver-kibana/import_resolver_kibana.js +++ b/packages/kbn-eslint-import-resolver-kibana/import_resolver_kibana.js @@ -27,7 +27,6 @@ const { getProjectRoot, getWebpackConfig, isFile, - isProbablyWebpackShim, getIsPathRequest, resolveWebpackAlias, } = require('./lib'); @@ -73,15 +72,6 @@ exports.resolve = function resolveKibanaPath(importRequest, file, config) { return tryNodeResolver(importRequest, file, config); } - // these modules are simulated by webpack, so there is no - // path to resolve to and no reason to do any more work - if (importRequest.startsWith('uiExports/')) { - return { - found: true, - path: null, - }; - } - const { webpackConfig, aliasEntries } = initContext(file, config); let isPathRequest = getIsPathRequest(importRequest); @@ -110,16 +100,9 @@ exports.resolve = function resolveKibanaPath(importRequest, file, config) { } } - // only use the node resolver if the importRequest is a path, or is - // a module request but not one that's probably a webpackShim. This - // prevents false positives as webpackShims are likely to be resolved - // to the node_modules directory by the node resolver, but we want - // them to resolve to the actual shim - if (isPathRequest || !isProbablyWebpackShim(importRequest, file)) { - const nodeResult = tryNodeResolver(importRequest, file, config); - if (nodeResult && nodeResult.found) { - return nodeResult; - } + const nodeResult = tryNodeResolver(importRequest, file, config); + if (nodeResult && nodeResult.found) { + return nodeResult; } return webpackResolver.resolve(importRequest, file, { diff --git a/packages/kbn-eslint-import-resolver-kibana/lib/get_plugins.js b/packages/kbn-eslint-import-resolver-kibana/lib/get_plugins.js deleted file mode 100755 index 84481783b22fc..0000000000000 --- a/packages/kbn-eslint-import-resolver-kibana/lib/get_plugins.js +++ /dev/null @@ -1,66 +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. - */ - -const { dirname, resolve } = require('path'); - -const glob = require('glob-all'); - -exports.getPlugins = function (config, kibanaPath, projectRoot) { - const resolveToRoot = (path) => resolve(projectRoot, path); - - const pluginDirs = [ - ...(config.pluginDirs || []).map(resolveToRoot), - resolve(kibanaPath, 'plugins'), - resolve(kibanaPath, 'src/legacy/core_plugins'), - ]; - - const pluginPaths = [ - ...(config.pluginPaths || []).map(resolveToRoot), - - // when the rootPackageName is specified we assume that the root of the project - // is not a plugin, so don't include it automatically - ...(config.rootPackageName ? [] : [projectRoot]), - ]; - - const globPatterns = [ - ...pluginDirs.map((dir) => resolve(dir, '*/package.json')), - ...pluginPaths.map((path) => resolve(path, 'package.json')), - ]; - - const pluginsFromMap = Object.keys(config.pluginMap || {}).map((name) => { - const directory = resolveToRoot(config.pluginMap[name]); - return { - name, - directory, - publicDirectory: resolve(directory, 'public'), - }; - }); - - return pluginsFromMap.concat( - glob.sync(globPatterns).map((pkgJsonPath) => { - const path = dirname(pkgJsonPath); - const pkg = require(pkgJsonPath); // eslint-disable-line import/no-dynamic-require - return { - name: pkg.name, - directory: path, - publicDirectory: resolve(path, 'public'), - }; - }) - ); -}; diff --git a/packages/kbn-eslint-import-resolver-kibana/lib/get_webpack_config.js b/packages/kbn-eslint-import-resolver-kibana/lib/get_webpack_config.js index baf5baaf916aa..d4e234e3a6a2e 100755 --- a/packages/kbn-eslint-import-resolver-kibana/lib/get_webpack_config.js +++ b/packages/kbn-eslint-import-resolver-kibana/lib/get_webpack_config.js @@ -19,40 +19,22 @@ const { resolve } = require('path'); -const { debug } = require('./debug'); -const { getPlugins } = require('./get_plugins'); - -exports.getWebpackConfig = function (kibanaPath, projectRoot, config) { - const fromKibana = (...path) => resolve(kibanaPath, ...path); - - const alias = { - // Kibana defaults https://github.com/elastic/kibana/blob/6998f074542e8c7b32955db159d15661aca253d7/src/legacy/ui/ui_bundler_env.js#L30-L36 - ui: fromKibana('src/legacy/ui/public'), - - // Dev defaults for test bundle https://github.com/elastic/kibana/blob/6998f074542e8c7b32955db159d15661aca253d7/src/core_plugins/tests_bundle/index.js#L73-L78 - ng_mock$: fromKibana('src/test_utils/public/ng_mock'), - fixtures: fromKibana('src/fixtures'), - test_utils: fromKibana('src/test_utils/public'), - }; - - getPlugins(config, kibanaPath, projectRoot).forEach((plugin) => { - alias[`plugins/${plugin.name}`] = plugin.publicDirectory; - }); - - debug('Webpack resolved aliases', alias); - +exports.getWebpackConfig = function (kibanaPath) { return { context: kibanaPath, resolve: { extensions: ['.js', '.json', '.ts', '.tsx'], mainFields: ['browser', 'main'], - modules: [ - 'webpackShims', - 'node_modules', - fromKibana('webpackShims'), - fromKibana('node_modules'), - ], - alias, + modules: ['node_modules', resolve(kibanaPath, 'node_modules')], + alias: { + // Kibana defaults https://github.com/elastic/kibana/blob/6998f074542e8c7b32955db159d15661aca253d7/src/legacy/ui/ui_bundler_env.js#L30-L36 + ui: resolve(kibanaPath, 'src/legacy/ui/public'), + + // Dev defaults for test bundle https://github.com/elastic/kibana/blob/6998f074542e8c7b32955db159d15661aca253d7/src/core_plugins/tests_bundle/index.js#L73-L78 + ng_mock$: resolve(kibanaPath, 'src/test_utils/public/ng_mock'), + fixtures: resolve(kibanaPath, 'src/fixtures'), + test_utils: resolve(kibanaPath, 'src/test_utils/public'), + }, unsafeCache: true, }, }; diff --git a/packages/kbn-eslint-import-resolver-kibana/lib/index.js b/packages/kbn-eslint-import-resolver-kibana/lib/index.js index 465ba2f740ac3..54ada9a76b20f 100644 --- a/packages/kbn-eslint-import-resolver-kibana/lib/index.js +++ b/packages/kbn-eslint-import-resolver-kibana/lib/index.js @@ -23,7 +23,6 @@ module.exports = Object.assign( require('./get_project_root'), require('./get_webpack_config'), require('./get_path_type'), - require('./is_probably_webpack_shim'), require('./get_is_path_request'), require('./resolve_webpack_alias') ); diff --git a/packages/kbn-eslint-import-resolver-kibana/lib/is_probably_webpack_shim.js b/packages/kbn-eslint-import-resolver-kibana/lib/is_probably_webpack_shim.js deleted file mode 100644 index 9eb3234fca7b4..0000000000000 --- a/packages/kbn-eslint-import-resolver-kibana/lib/is_probably_webpack_shim.js +++ /dev/null @@ -1,59 +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. - */ - -const { readdirSync } = require('fs'); -const { join, dirname } = require('path'); - -const LRU = require('lru-cache'); - -const { isDirectory } = require('./get_path_type'); - -const cache = process.env.KIBANA_RESOLVER_HARD_CACHE ? new Map() : new LRU({ max: 1000 }); - -function readShimNames(shimDirectory) { - if (!isDirectory(shimDirectory)) { - return []; - } - - return readdirSync(shimDirectory) - .filter((name) => !name.startsWith('.') && !name.startsWith('_')) - .map((name) => (name.endsWith('.js') ? name.slice(0, -3) : name)); -} - -function findRelativeWebpackShims(directory) { - const cached = cache.get(directory); - if (cached) { - return cached; - } - - const ownShims = readShimNames(join(directory, 'webpackShims')); - - const parent = dirname(directory); - const parentShims = parent !== directory ? findRelativeWebpackShims(parent) : []; - - const allShims = !ownShims.length ? parentShims : ownShims.concat(parentShims); - - cache.set(directory, allShims); - return allShims; -} - -exports.isProbablyWebpackShim = function (source, file) { - const shims = findRelativeWebpackShims(dirname(file)); - return shims.some((shim) => source === shim || source.startsWith(shim + '/')); -}; diff --git a/packages/kbn-optimizer/package.json b/packages/kbn-optimizer/package.json index 84e5c79e2e358..740555fd87897 100644 --- a/packages/kbn-optimizer/package.json +++ b/packages/kbn-optimizer/package.json @@ -36,7 +36,6 @@ "postcss": "^7.0.32", "postcss-loader": "^3.0.0", "raw-loader": "^3.1.0", - "resolve-url-loader": "^3.1.1", "rxjs": "^6.5.5", "sass-loader": "^8.0.2", "style-loader": "^1.1.3", diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/legacy/styles.scss b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/legacy/styles.scss index 1dc7bbe9daeb0..7fa8383ec239c 100644 --- a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/legacy/styles.scss +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/legacy/styles.scss @@ -2,5 +2,4 @@ body { width: $globalStyleConstant; - background-image: url("ui/icon.svg"); } diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/src/legacy/ui/public/styles/_globals_v7dark.scss b/packages/kbn-optimizer/src/__fixtures__/mock_repo/src/core/public/core_app/styles/_globals_v7dark.scss similarity index 100% rename from packages/kbn-optimizer/src/__fixtures__/mock_repo/src/legacy/ui/public/styles/_globals_v7dark.scss rename to packages/kbn-optimizer/src/__fixtures__/mock_repo/src/core/public/core_app/styles/_globals_v7dark.scss diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/src/legacy/ui/public/styles/_globals_v7light.scss b/packages/kbn-optimizer/src/__fixtures__/mock_repo/src/core/public/core_app/styles/_globals_v7light.scss similarity index 100% rename from packages/kbn-optimizer/src/__fixtures__/mock_repo/src/legacy/ui/public/styles/_globals_v7light.scss rename to packages/kbn-optimizer/src/__fixtures__/mock_repo/src/core/public/core_app/styles/_globals_v7light.scss diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/src/legacy/ui/public/styles/_globals_v8dark.scss b/packages/kbn-optimizer/src/__fixtures__/mock_repo/src/core/public/core_app/styles/_globals_v8dark.scss similarity index 100% rename from packages/kbn-optimizer/src/__fixtures__/mock_repo/src/legacy/ui/public/styles/_globals_v8dark.scss rename to packages/kbn-optimizer/src/__fixtures__/mock_repo/src/core/public/core_app/styles/_globals_v8dark.scss diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/src/legacy/ui/public/styles/_globals_v8light.scss b/packages/kbn-optimizer/src/__fixtures__/mock_repo/src/core/public/core_app/styles/_globals_v8light.scss similarity index 100% rename from packages/kbn-optimizer/src/__fixtures__/mock_repo/src/legacy/ui/public/styles/_globals_v8light.scss rename to packages/kbn-optimizer/src/__fixtures__/mock_repo/src/core/public/core_app/styles/_globals_v8light.scss diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/src/legacy/ui/public/icon.svg b/packages/kbn-optimizer/src/__fixtures__/mock_repo/src/legacy/ui/public/icon.svg deleted file mode 100644 index ae7d5b958bbad..0000000000000 --- a/packages/kbn-optimizer/src/__fixtures__/mock_repo/src/legacy/ui/public/icon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap index 5f44d8068e694..79442c35df265 100644 --- a/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap +++ b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap @@ -98,7 +98,7 @@ OptimizerConfig { } `; -exports[`prepares assets for distribution: bar bundle 1`] = `"(function(modules){var installedModules={};function __webpack_require__(moduleId){if(installedModules[moduleId]){return installedModules[moduleId].exports}var module=installedModules[moduleId]={i:moduleId,l:false,exports:{}};modules[moduleId].call(module.exports,module,module.exports,__webpack_require__);module.l=true;return module.exports}__webpack_require__.m=modules;__webpack_require__.c=installedModules;__webpack_require__.d=function(exports,name,getter){if(!__webpack_require__.o(exports,name)){Object.defineProperty(exports,name,{enumerable:true,get:getter})}};__webpack_require__.r=function(exports){if(typeof Symbol!==\\"undefined\\"&&Symbol.toStringTag){Object.defineProperty(exports,Symbol.toStringTag,{value:\\"Module\\"})}Object.defineProperty(exports,\\"__esModule\\",{value:true})};__webpack_require__.t=function(value,mode){if(mode&1)value=__webpack_require__(value);if(mode&8)return value;if(mode&4&&typeof value===\\"object\\"&&value&&value.__esModule)return value;var ns=Object.create(null);__webpack_require__.r(ns);Object.defineProperty(ns,\\"default\\",{enumerable:true,value:value});if(mode&2&&typeof value!=\\"string\\")for(var key in value)__webpack_require__.d(ns,key,function(key){return value[key]}.bind(null,key));return ns};__webpack_require__.n=function(module){var getter=module&&module.__esModule?function getDefault(){return module[\\"default\\"]}:function getModuleExports(){return module};__webpack_require__.d(getter,\\"a\\",getter);return getter};__webpack_require__.o=function(object,property){return Object.prototype.hasOwnProperty.call(object,property)};__webpack_require__.p=\\"\\";return __webpack_require__(__webpack_require__.s=5)})([function(module,exports,__webpack_require__){\\"use strict\\";var isOldIE=function isOldIE(){var memo;return function memorize(){if(typeof memo===\\"undefined\\"){memo=Boolean(window&&document&&document.all&&!window.atob)}return memo}}();var getTarget=function getTarget(){var memo={};return function memorize(target){if(typeof memo[target]===\\"undefined\\"){var styleTarget=document.querySelector(target);if(window.HTMLIFrameElement&&styleTarget instanceof window.HTMLIFrameElement){try{styleTarget=styleTarget.contentDocument.head}catch(e){styleTarget=null}}memo[target]=styleTarget}return memo[target]}}();var stylesInDom=[];function getIndexByIdentifier(identifier){var result=-1;for(var i=0;i { bar.cache.refresh(); expect(bar.cache.getModuleCount()).toBe( // code + styles + style/css-loader runtimes + public path updater - 18 + 16 ); expect(bar.cache.getReferencedFiles()).toMatchInlineSnapshot(` @@ -168,9 +168,8 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/legacy/_other_styles.scss, /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/legacy/styles.scss, /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/public/lib.ts, - /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/src/legacy/ui/public/icon.svg, - /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/src/legacy/ui/public/styles/_globals_v7dark.scss, - /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/src/legacy/ui/public/styles/_globals_v7light.scss, + /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/src/core/public/core_app/styles/_globals_v7dark.scss, + /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/src/core/public/core_app/styles/_globals_v7light.scss, /packages/kbn-optimizer/target/worker/entry_point_creator.js, /packages/kbn-ui-shared-deps/public_path_module_creator.js, ] diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts index 820b13629697d..6b07384910abb 100644 --- a/packages/kbn-optimizer/src/worker/webpack.config.ts +++ b/packages/kbn-optimizer/src/worker/webpack.config.ts @@ -29,7 +29,7 @@ import { CleanWebpackPlugin } from 'clean-webpack-plugin'; import CompressionPlugin from 'compression-webpack-plugin'; import * as UiSharedDeps from '@kbn/ui-shared-deps'; -import { Bundle, BundleRefs, WorkerConfig, parseDirPath } from '../common'; +import { Bundle, BundleRefs, WorkerConfig } from '../common'; import { BundleRefsPlugin } from './bundle_refs_plugin'; const IS_CODE_COVERAGE = !!process.env.CODE_COVERAGE; @@ -155,48 +155,15 @@ export function getWebpackConfig(bundle: Bundle, bundleRefs: BundleRefs, worker: }, }, }, - { - loader: 'resolve-url-loader', - options: { - join: (_: string, __: any) => (uri: string, base?: string) => { - // apply only to legacy platform styles - if (!base || !parseDirPath(base).dirs.includes('legacy')) { - return null; - } - - if (uri.startsWith('ui/assets')) { - return Path.resolve( - worker.repoRoot, - 'src/core/server/core_app/', - uri.replace('ui/', '') - ); - } - - // manually force ui/* urls in legacy styles to resolve to ui/legacy/public - if (uri.startsWith('ui/')) { - return Path.resolve( - worker.repoRoot, - 'src/legacy/ui/public', - uri.replace('ui/', '') - ); - } - - return null; - }, - }, - }, { loader: 'sass-loader', options: { - // must always be enabled as long as we're using the `resolve-url-loader` to - // rewrite `ui/*` urls. They're dropped by subsequent loaders though - sourceMap: true, prependData(loaderContext: webpack.loader.LoaderContext) { return `@import ${stringifyRequest( loaderContext, Path.resolve( worker.repoRoot, - `src/legacy/ui/public/styles/_globals_${theme}.scss` + `src/core/public/core_app/styles/_globals_${theme}.scss` ) )};\n`; }, @@ -254,6 +221,7 @@ export function getWebpackConfig(bundle: Bundle, bundleRefs: BundleRefs, worker: mainFields: ['browser', 'main'], alias: { tinymath: require.resolve('tinymath/lib/tinymath.es5.js'), + core_app_image_assets: Path.resolve(worker.repoRoot, 'src/core/public/core_app/images'), }, }, diff --git a/packages/kbn-plugin-helpers/package.json b/packages/kbn-plugin-helpers/package.json index 45582ad2af97a..9cc34bcda1af4 100644 --- a/packages/kbn-plugin-helpers/package.json +++ b/packages/kbn-plugin-helpers/package.json @@ -23,7 +23,6 @@ "gulp-zip": "5.0.1", "inquirer": "^1.2.2", "minimatch": "^3.0.4", - "node-sass": "^4.13.1", "through2": "^2.0.3", "through2-map": "^3.0.0", "vinyl": "^2.2.0", @@ -33,7 +32,6 @@ "@types/gulp-rename": "^0.0.33", "@types/gulp-zip": "^4.0.1", "@types/inquirer": "^6.5.0", - "@types/node-sass": "^4.11.0", "@types/through2": "^2.0.35", "@types/through2-map": "^3.0.0", "@types/vinyl": "^2.0.4", diff --git a/packages/kbn-plugin-helpers/src/lib/plugin_config.ts b/packages/kbn-plugin-helpers/src/lib/plugin_config.ts index dc3ef936e2164..c186bc3275a05 100644 --- a/packages/kbn-plugin-helpers/src/lib/plugin_config.ts +++ b/packages/kbn-plugin-helpers/src/lib/plugin_config.ts @@ -43,7 +43,7 @@ export function pluginConfig(root: string = process.cwd()): PluginConfig { 'tsconfig.json', 'package.json', 'index.{js,ts}', - '{lib,public,server,webpackShims,translations}/**/*', + '{lib,public,server,translations}/**/*', ]; const kibanaExtraDir = resolve(root, '../../kibana'); diff --git a/packages/kbn-plugin-helpers/src/tasks/build/create_build.ts b/packages/kbn-plugin-helpers/src/tasks/build/create_build.ts index a469e4fe67390..1681c7cfdcf90 100644 --- a/packages/kbn-plugin-helpers/src/tasks/build/create_build.ts +++ b/packages/kbn-plugin-helpers/src/tasks/build/create_build.ts @@ -22,7 +22,6 @@ import path from 'path'; import { readFileSync, writeFileSync, unlinkSync, existsSync } from 'fs'; import execa from 'execa'; -import sass from 'node-sass'; import del from 'del'; import File from 'vinyl'; import vfs from 'vinyl-fs'; @@ -135,22 +134,6 @@ export async function createBuild( }); } - // compile stylesheet - if (typeof plugin.styleSheetToCompile === 'string') { - const file = path.resolve(plugin.root, plugin.styleSheetToCompile); - if (!existsSync(file)) { - throw new Error(`Path provided for styleSheetToCompile does not exist: ${file}`); - } - - const outputFileName = path.basename(file, path.extname(file)) + '.css'; - const output = path.join(buildRoot, path.dirname(plugin.styleSheetToCompile), outputFileName); - - const rendered = sass.renderSync({ file, output }); - writeFileSync(output, rendered.css); - - del.sync([path.join(buildRoot, '**', '*.s{a,c}ss')]); - } - // transform typescript to js and clean out typescript const tsConfigPath = path.join(buildRoot, 'tsconfig.json'); if (existsSync(tsConfigPath)) { diff --git a/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/build_action_test_plugin/index.js b/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/build_action_test_plugin/index.js index 052d224b662e2..e6a975e75ed2d 100644 --- a/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/build_action_test_plugin/index.js +++ b/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/build_action_test_plugin/index.js @@ -17,9 +17,4 @@ * under the License. */ -module.exports = (kibana) => - new kibana.Plugin({ - uiExports: { - hacks: ['plugins/test_plugin/hack.js'], - }, - }); +module.exports = (kibana) => new kibana.Plugin({}); diff --git a/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/build_action_test_plugin/public/hack.js b/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/build_action_test_plugin/public/hack.js deleted file mode 100644 index dbeba25f9dfec..0000000000000 --- a/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/build_action_test_plugin/public/hack.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. - */ - -console.log('this is my hack'); diff --git a/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/create_build_test_plugin/index.js b/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/create_build_test_plugin/index.js index 052d224b662e2..e6a975e75ed2d 100644 --- a/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/create_build_test_plugin/index.js +++ b/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/create_build_test_plugin/index.js @@ -17,9 +17,4 @@ * under the License. */ -module.exports = (kibana) => - new kibana.Plugin({ - uiExports: { - hacks: ['plugins/test_plugin/hack.js'], - }, - }); +module.exports = (kibana) => new kibana.Plugin({}); diff --git a/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/create_build_test_plugin/public/styles.scss b/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/create_build_test_plugin/public/styles.scss deleted file mode 100644 index 88cb00c52437f..0000000000000 --- a/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/create_build_test_plugin/public/styles.scss +++ /dev/null @@ -1,3 +0,0 @@ -body { - background-color: red; -} \ No newline at end of file diff --git a/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/create_package_test_plugin/index.js b/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/create_package_test_plugin/index.js index 052d224b662e2..e6a975e75ed2d 100644 --- a/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/create_package_test_plugin/index.js +++ b/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/create_package_test_plugin/index.js @@ -17,9 +17,4 @@ * under the License. */ -module.exports = (kibana) => - new kibana.Plugin({ - uiExports: { - hacks: ['plugins/test_plugin/hack.js'], - }, - }); +module.exports = (kibana) => new kibana.Plugin({}); diff --git a/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/create_package_test_plugin/public/hack.js b/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/create_package_test_plugin/public/hack.js deleted file mode 100644 index dbeba25f9dfec..0000000000000 --- a/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/create_package_test_plugin/public/hack.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. - */ - -console.log('this is my hack'); diff --git a/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/create_build.test.js b/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/create_build.test.js index 8a4a5a55ce237..6662de24a3e03 100644 --- a/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/create_build.test.js +++ b/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/create_build.test.js @@ -18,7 +18,7 @@ */ import { resolve } from 'path'; -import { readdirSync, existsSync, unlinkSync } from 'fs'; +import { readdirSync } from 'fs'; import del from 'del'; import { createBuild } from '../create_build'; import { pluginConfig } from '../../../lib'; @@ -84,28 +84,4 @@ describe('creating the build', () => { expect(readdirSync(resolve(PLUGIN_BUILD_TARGET))).not.toContain('node_modules'); }); }); - - describe('with styleSheetToCompile', () => { - const sassPath = 'public/styles.scss'; - const cssPath = resolve(PLUGIN_BUILD_TARGET, 'public/styles.css'); - - beforeEach(() => { - PLUGIN.skipInstallDependencies = true; - PLUGIN.styleSheetToCompile = sassPath; - }); - - afterEach(() => { - PLUGIN.skipInstallDependencies = false; - PLUGIN.styleSheetToCompile = undefined; - unlinkSync(cssPath); - }); - - it('produces CSS', async () => { - expect(PLUGIN.styleSheetToCompile).toBe(sassPath); - - await createBuild(PLUGIN, buildTarget, buildVersion, kibanaVersion, buildFiles); - - expect(existsSync(cssPath)).toBe(true); - }); - }); }); diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index e411dcd472768..339f16eaf8593 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__(511); +/* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(505); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["buildProductionProjects"]; }); /* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(145); @@ -150,7 +150,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _kbn_dev_utils_tooling_log__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(5); /* harmony import */ var _kbn_dev_utils_tooling_log__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_kbn_dev_utils_tooling_log__WEBPACK_IMPORTED_MODULE_3__); /* harmony import */ var _commands__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(127); -/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(503); +/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(498); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(143); /* * Licensed to Elasticsearch B.V. under one or more contributor @@ -8763,8 +8763,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__(128); /* harmony import */ var _clean__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(295); -/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(402); -/* harmony import */ var _watch__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(403); +/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(397); +/* harmony import */ var _watch__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(398); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -30015,12 +30015,21 @@ module.exports = function (args, opts) { function setKey (obj, keys, value) { var o = obj; - keys.slice(0,-1).forEach(function (key) { + for (var i = 0; i < keys.length-1; i++) { + var key = keys[i]; + if (key === '__proto__') return; if (o[key] === undefined) o[key] = {}; + if (o[key] === Object.prototype || o[key] === Number.prototype + || o[key] === String.prototype) o[key] = {}; + if (o[key] === Array.prototype) o[key] = []; o = o[key]; - }); + } var key = keys[keys.length - 1]; + if (key === '__proto__') return; + if (o === Object.prototype || o === Number.prototype + || o === String.prototype) o = {}; + if (o === Array.prototype) o = []; if (o[key] === undefined || flags.bools[key] || typeof o[key] === 'boolean') { o[key] = value; } @@ -30118,7 +30127,7 @@ module.exports = function (args, opts) { setArg(key, args[i+1], arg); i++; } - else if (args[i+1] && /true|false/.test(args[i+1])) { + else if (args[i+1] && /^(true|false)$/.test(args[i+1])) { setArg(key, args[i+1] === 'true', arg); i++; } @@ -41056,7 +41065,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CleanCommand", function() { return CleanCommand; }); /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(296); /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(del__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(388); +/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(383); /* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(ora__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__); @@ -41164,13 +41173,13 @@ const CleanCommand = { const {promisify} = __webpack_require__(111); const path = __webpack_require__(4); const globby = __webpack_require__(297); -const isGlob = __webpack_require__(380); -const slash = __webpack_require__(378); +const isGlob = __webpack_require__(375); +const slash = __webpack_require__(373); const gracefulFs = __webpack_require__(132); -const isPathCwd = __webpack_require__(381); -const isPathInside = __webpack_require__(382); -const rimraf = __webpack_require__(383); -const pMap = __webpack_require__(384); +const isPathCwd = __webpack_require__(376); +const isPathInside = __webpack_require__(377); +const rimraf = __webpack_require__(378); +const pMap = __webpack_require__(379); const rimrafP = promisify(rimraf); @@ -41292,11 +41301,11 @@ module.exports.sync = (patterns, {force, dryRun, cwd = process.cwd(), ...options const fs = __webpack_require__(133); const arrayUnion = __webpack_require__(298); const merge2 = __webpack_require__(299); -const glob = __webpack_require__(300); -const fastGlob = __webpack_require__(305); -const dirGlob = __webpack_require__(374); -const gitignore = __webpack_require__(376); -const {FilterStream, UniqueStream} = __webpack_require__(379); +const glob = __webpack_require__(146); +const fastGlob = __webpack_require__(300); +const dirGlob = __webpack_require__(369); +const gitignore = __webpack_require__(371); +const {FilterStream, UniqueStream} = __webpack_require__(374); const DEFAULT_FILTER = () => false; @@ -41635,15122 +41644,10930 @@ function pauseStreams (streams, options) { /* 300 */ /***/ (function(module, exports, __webpack_require__) { -// Approach: -// -// 1. Get the minimatch set -// 2. For each pattern in the set, PROCESS(pattern, false) -// 3. Store matches per-set, then uniq them -// -// PROCESS(pattern, inGlobStar) -// Get the first [n] items from pattern that are all strings -// Join these together. This is PREFIX. -// If there is no more remaining, then stat(PREFIX) and -// add to matches if it succeeds. END. -// -// If inGlobStar and PREFIX is symlink and points to dir -// set ENTRIES = [] -// else readdir(PREFIX) as ENTRIES -// If fail, END -// -// with ENTRIES -// If pattern[n] is GLOBSTAR -// // handle the case where the globstar match is empty -// // by pruning it out, and testing the resulting pattern -// PROCESS(pattern[0..n] + pattern[n+1 .. $], false) -// // handle other cases. -// for ENTRY in ENTRIES (not dotfiles) -// // attach globstar + tail onto the entry -// // Mark that this entry is a globstar match -// PROCESS(pattern[0..n] + ENTRY + pattern[n .. $], true) -// -// else // not globstar -// for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot) -// Test ENTRY against pattern[n] -// If fails, continue -// If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $]) -// -// Caveat: -// Cache all stats and readdirs results to minimize syscall. Since all -// we ever care about is existence and directory-ness, we can just keep -// `true` for files, and [children,...] for directories, or `false` for -// things that don't exist. +"use strict"; + +const taskManager = __webpack_require__(301); +const async_1 = __webpack_require__(330); +const stream_1 = __webpack_require__(365); +const sync_1 = __webpack_require__(366); +const settings_1 = __webpack_require__(368); +const utils = __webpack_require__(302); +async function FastGlob(source, options) { + assertPatternsInput(source); + const works = getWorks(source, async_1.default, options); + const result = await Promise.all(works); + return utils.array.flatten(result); +} +// https://github.com/typescript-eslint/typescript-eslint/issues/60 +// eslint-disable-next-line no-redeclare +(function (FastGlob) { + function sync(source, options) { + assertPatternsInput(source); + const works = getWorks(source, sync_1.default, options); + return utils.array.flatten(works); + } + FastGlob.sync = sync; + function stream(source, options) { + assertPatternsInput(source); + const works = getWorks(source, stream_1.default, options); + /** + * The stream returned by the provider cannot work with an asynchronous iterator. + * To support asynchronous iterators, regardless of the number of tasks, we always multiplex streams. + * This affects performance (+25%). I don't see best solution right now. + */ + return utils.stream.merge(works); + } + FastGlob.stream = stream; + function generateTasks(source, options) { + assertPatternsInput(source); + const patterns = [].concat(source); + const settings = new settings_1.default(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); + const settings = new settings_1.default(options); + const tasks = taskManager.generate(patterns, settings); + const provider = new _Provider(settings); + return tasks.map(provider.read, provider); +} +function assertPatternsInput(input) { + const source = [].concat(input); + const isValidSource = source.every((item) => utils.string.isString(item) && !utils.string.isEmpty(item)); + if (!isValidSource) { + throw new TypeError('Patterns must be a string (non empty) or an array of strings'); + } +} +module.exports = FastGlob; -module.exports = glob -var fs = __webpack_require__(133) -var rp = __webpack_require__(147) -var minimatch = __webpack_require__(149) -var Minimatch = minimatch.Minimatch -var inherits = __webpack_require__(301) -var EE = __webpack_require__(155).EventEmitter -var path = __webpack_require__(4) -var assert = __webpack_require__(139) -var isAbsolute = __webpack_require__(156) -var globSync = __webpack_require__(303) -var common = __webpack_require__(304) -var alphasort = common.alphasort -var alphasorti = common.alphasorti -var setopts = common.setopts -var ownProp = common.ownProp -var inflight = __webpack_require__(159) -var util = __webpack_require__(111) -var childrenIgnored = common.childrenIgnored -var isIgnored = common.isIgnored +/***/ }), +/* 301 */ +/***/ (function(module, exports, __webpack_require__) { -var once = __webpack_require__(161) +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const utils = __webpack_require__(302); +function generate(patterns, settings) { + const positivePatterns = getPositivePatterns(patterns); + const negativePatterns = getNegativePatternsAsPositive(patterns, settings.ignore); + 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); +} +exports.generate = generate; +function convertPatternsToTasks(positive, negative, dynamic) { + const 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) { + const task = convertPatternGroupToTask('.', positive, negative, dynamic); + return [task]; + } + return convertPatternGroupsToTasks(positivePatternsGroup, negative, dynamic); +} +exports.convertPatternsToTasks = convertPatternsToTasks; +function getPositivePatterns(patterns) { + return utils.pattern.getPositivePatterns(patterns); +} +exports.getPositivePatterns = getPositivePatterns; +function getNegativePatternsAsPositive(patterns, ignore) { + const negative = utils.pattern.getNegativePatterns(patterns).concat(ignore); + const positive = negative.map(utils.pattern.convertToPositivePattern); + return positive; +} +exports.getNegativePatternsAsPositive = getNegativePatternsAsPositive; +function groupPatternsByBaseDirectory(patterns) { + const group = {}; + return patterns.reduce((collection, pattern) => { + const base = utils.pattern.getBaseDirectory(pattern); + if (base in collection) { + collection[base].push(pattern); + } + else { + collection[base] = [pattern]; + } + return collection; + }, group); +} +exports.groupPatternsByBaseDirectory = groupPatternsByBaseDirectory; +function convertPatternGroupsToTasks(positive, negative, dynamic) { + return Object.keys(positive).map((base) => { + return convertPatternGroupToTask(base, positive[base], negative, dynamic); + }); +} +exports.convertPatternGroupsToTasks = convertPatternGroupsToTasks; +function convertPatternGroupToTask(base, positive, negative, dynamic) { + return { + dynamic, + positive, + negative, + base, + patterns: [].concat(positive, negative.map(utils.pattern.convertToNegativePattern)) + }; +} +exports.convertPatternGroupToTask = convertPatternGroupToTask; -function glob (pattern, options, cb) { - if (typeof options === 'function') cb = options, options = {} - if (!options) options = {} - if (options.sync) { - if (cb) - throw new TypeError('callback provided to sync glob') - return globSync(pattern, options) - } +/***/ }), +/* 302 */ +/***/ (function(module, exports, __webpack_require__) { - return new Glob(pattern, options, cb) -} +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const array = __webpack_require__(303); +exports.array = array; +const errno = __webpack_require__(304); +exports.errno = errno; +const fs = __webpack_require__(305); +exports.fs = fs; +const path = __webpack_require__(306); +exports.path = path; +const pattern = __webpack_require__(307); +exports.pattern = pattern; +const stream = __webpack_require__(328); +exports.stream = stream; +const string = __webpack_require__(329); +exports.string = string; -glob.sync = globSync -var GlobSync = glob.GlobSync = globSync.GlobSync -// old api surface -glob.glob = glob +/***/ }), +/* 303 */ +/***/ (function(module, exports, __webpack_require__) { -function extend (origin, add) { - if (add === null || typeof add !== 'object') { - return origin - } +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function flatten(items) { + return items.reduce((collection, item) => [].concat(collection, item), []); +} +exports.flatten = flatten; +function splitWhen(items, predicate) { + const result = [[]]; + let groupIndex = 0; + for (const item of items) { + if (predicate(item)) { + groupIndex++; + result[groupIndex] = []; + } + else { + result[groupIndex].push(item); + } + } + return result; +} +exports.splitWhen = splitWhen; - var keys = Object.keys(add) - var i = keys.length - while (i--) { - origin[keys[i]] = add[keys[i]] - } - return origin -} -glob.hasMagic = function (pattern, options_) { - var options = extend({}, options_) - options.noprocess = true +/***/ }), +/* 304 */ +/***/ (function(module, exports, __webpack_require__) { - var g = new Glob(pattern, options) - var set = g.minimatch.set +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function isEnoentCodeError(error) { + return error.code === 'ENOENT'; +} +exports.isEnoentCodeError = isEnoentCodeError; - if (!pattern) - return false - if (set.length > 1) - return true +/***/ }), +/* 305 */ +/***/ (function(module, exports, __webpack_require__) { - for (var j = 0; j < set[0].length; j++) { - if (typeof set[0][j] !== 'string') - return true - } +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +class DirentFromStats { + constructor(name, stats) { + this.name = name; + this.isBlockDevice = stats.isBlockDevice.bind(stats); + this.isCharacterDevice = stats.isCharacterDevice.bind(stats); + this.isDirectory = stats.isDirectory.bind(stats); + this.isFIFO = stats.isFIFO.bind(stats); + this.isFile = stats.isFile.bind(stats); + this.isSocket = stats.isSocket.bind(stats); + this.isSymbolicLink = stats.isSymbolicLink.bind(stats); + } +} +function createDirentFromStats(name, stats) { + return new DirentFromStats(name, stats); +} +exports.createDirentFromStats = createDirentFromStats; - return false -} -glob.Glob = Glob -inherits(Glob, EE) -function Glob (pattern, options, cb) { - if (typeof options === 'function') { - cb = options - options = null - } +/***/ }), +/* 306 */ +/***/ (function(module, exports, __webpack_require__) { - if (options && options.sync) { - if (cb) - throw new TypeError('callback provided to sync glob') - return new GlobSync(pattern, options) - } +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const path = __webpack_require__(4); +const LEADING_DOT_SEGMENT_CHARACTERS_COUNT = 2; // ./ or .\\ +const UNESCAPED_GLOB_SYMBOLS_RE = /(\\?)([()*?[\]{|}]|^!|[!+@](?=\())/g; +/** + * Designed to work only with simple paths: `dir\\file`. + */ +function unixify(filepath) { + return filepath.replace(/\\/g, '/'); +} +exports.unixify = unixify; +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; +function removeLeadingDotSegment(entry) { + // We do not use `startsWith` because this is 10x slower than current implementation for some cases. + // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with + if (entry.charAt(0) === '.') { + const secondCharactery = entry.charAt(1); + if (secondCharactery === '/' || secondCharactery === '\\') { + return entry.slice(LEADING_DOT_SEGMENT_CHARACTERS_COUNT); + } + } + return entry; +} +exports.removeLeadingDotSegment = removeLeadingDotSegment; - if (!(this instanceof Glob)) - return new Glob(pattern, options, cb) - setopts(this, pattern, options) - this._didRealPath = false +/***/ }), +/* 307 */ +/***/ (function(module, exports, __webpack_require__) { - // process each pattern in the minimatch set - var n = this.minimatch.set.length +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const path = __webpack_require__(4); +const globParent = __webpack_require__(308); +const micromatch = __webpack_require__(311); +const picomatch = __webpack_require__(322); +const GLOBSTAR = '**'; +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, 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) { + return isNegativePattern(pattern) ? pattern.slice(1) : pattern; +} +exports.convertToPositivePattern = convertToPositivePattern; +function convertToNegativePattern(pattern) { + return '!' + pattern; +} +exports.convertToNegativePattern = convertToNegativePattern; +function isNegativePattern(pattern) { + return pattern.startsWith('!') && pattern[1] !== '('; +} +exports.isNegativePattern = isNegativePattern; +function isPositivePattern(pattern) { + return !isNegativePattern(pattern); +} +exports.isPositivePattern = isPositivePattern; +function getNegativePatterns(patterns) { + return patterns.filter(isNegativePattern); +} +exports.getNegativePatterns = getNegativePatterns; +function getPositivePatterns(patterns) { + return patterns.filter(isPositivePattern); +} +exports.getPositivePatterns = getPositivePatterns; +function getBaseDirectory(pattern) { + return globParent(pattern, { flipBackslashes: false }); +} +exports.getBaseDirectory = getBaseDirectory; +function hasGlobStar(pattern) { + return pattern.includes(GLOBSTAR); +} +exports.hasGlobStar = hasGlobStar; +function endsWithSlashGlobStar(pattern) { + return pattern.endsWith('/' + GLOBSTAR); +} +exports.endsWithSlashGlobStar = endsWithSlashGlobStar; +function isAffectDepthOfReadingPattern(pattern) { + const basename = path.basename(pattern); + return endsWithSlashGlobStar(pattern) || isStaticPattern(basename); +} +exports.isAffectDepthOfReadingPattern = isAffectDepthOfReadingPattern; +function expandPatternsWithBraceExpansion(patterns) { + return patterns.reduce((collection, pattern) => { + return collection.concat(expandBraceExpansion(pattern)); + }, []); +} +exports.expandPatternsWithBraceExpansion = expandPatternsWithBraceExpansion; +function expandBraceExpansion(pattern) { + return micromatch.braces(pattern, { + expand: true, + nodupes: true + }); +} +exports.expandBraceExpansion = expandBraceExpansion; +function getPatternParts(pattern, options) { + const info = picomatch.scan(pattern, Object.assign(Object.assign({}, options), { parts: true })); + // See micromatch/picomatch#58 for more details + if (info.parts.length === 0) { + return [pattern]; + } + return info.parts; +} +exports.getPatternParts = getPatternParts; +function makeRe(pattern, options) { + return micromatch.makeRe(pattern, options); +} +exports.makeRe = makeRe; +function convertPatternsToRe(patterns, options) { + return patterns.map((pattern) => makeRe(pattern, options)); +} +exports.convertPatternsToRe = convertPatternsToRe; +function matchAny(entry, patternsRe) { + return patternsRe.some((patternRe) => patternRe.test(entry)); +} +exports.matchAny = matchAny; - // The matches are stored as {: true,...} so that - // duplicates are automagically pruned. - // Later, we do an Object.keys() on these. - // Keep them as a list so we can fill in when nonull is set. - this.matches = new Array(n) - if (typeof cb === 'function') { - cb = once(cb) - this.on('error', cb) - this.on('end', function (matches) { - cb(null, matches) - }) - } +/***/ }), +/* 308 */ +/***/ (function(module, exports, __webpack_require__) { - var self = this - this._processing = 0 +"use strict"; - this._emitQueue = [] - this._processQueue = [] - this.paused = false - if (this.noprocess) - return this +var isGlob = __webpack_require__(309); +var pathPosixDirname = __webpack_require__(4).posix.dirname; +var isWin32 = __webpack_require__(120).platform() === 'win32'; - if (n === 0) - return done() +var slash = '/'; +var backslash = /\\/g; +var enclosure = /[\{\[].*[\/]*.*[\}\]]$/; +var globby = /(^|[^\\])([\{\[]|\([^\)]+$)/; +var escaped = /\\([\!\*\?\|\[\]\(\)\{\}])/g; - var sync = true - for (var i = 0; i < n; i ++) { - this._process(this.minimatch.set[i], i, false, done) +/** + * @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 (options.flipBackslashes && isWin32 && str.indexOf(slash) < 0) { + str = str.replace(backslash, slash); } - sync = false - function done () { - --self._processing - if (self._processing <= 0) { - if (sync) { - process.nextTick(function () { - self._finish() - }) - } else { - self._finish() - } - } + // special case for strings ending in enclosure containing path separator + if (enclosure.test(str)) { + str += slash; } -} -Glob.prototype._finish = function () { - assert(this instanceof Glob) - if (this.aborted) - return + // preserves full path in case of trailing path separator + str += 'a'; - if (this.realpath && !this._didRealpath) - return this._realpath() + // remove path parts that are globby + do { + str = pathPosixDirname(str); + } while (isGlob(str) || globby.test(str)); - common.finish(this) - this.emit('end', this.found) -} + // remove escape chars and return result + return str.replace(escaped, '$1'); +}; -Glob.prototype._realpath = function () { - if (this._didRealpath) - return - this._didRealpath = true +/***/ }), +/* 309 */ +/***/ (function(module, exports, __webpack_require__) { - var n = this.matches.length - if (n === 0) - return this._finish() +/*! + * is-glob + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. + */ - var self = this - for (var i = 0; i < this.matches.length; i++) - this._realpathSet(i, next) +var isExtglob = __webpack_require__(310); +var chars = { '{': '}', '(': ')', '[': ']'}; +var strictRegex = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/; +var relaxedRegex = /\\(.)|(^!|[*?{}()[\]]|\(\?)/; - function next () { - if (--n === 0) - self._finish() +module.exports = function isGlob(str, options) { + if (typeof str !== 'string' || str === '') { + return false; } -} -Glob.prototype._realpathSet = function (index, cb) { - var matchset = this.matches[index] - if (!matchset) - return cb() + if (isExtglob(str)) { + return true; + } - var found = Object.keys(matchset) - var self = this - var n = found.length + var regex = strictRegex; + var match; - if (n === 0) - return cb() + // optionally relax regex + if (options && options.strict === false) { + regex = relaxedRegex; + } - var set = this.matches[index] = Object.create(null) - found.forEach(function (p, i) { - // If there's a problem with the stat, then it means that - // one or more of the links in the realpath couldn't be - // resolved. just return the abs value in that case. - p = self._makeAbs(p) - rp.realpath(p, self.realpathCache, function (er, real) { - if (!er) - set[real] = true - else if (er.syscall === 'stat') - set[p] = true - else - self.emit('error', er) // srsly wtf right here + while ((match = regex.exec(str))) { + if (match[2]) return true; + var idx = match.index + match[0].length; - if (--n === 0) { - self.matches[index] = set - cb() + // 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; } - }) - }) -} - -Glob.prototype._mark = function (p) { - return common.mark(this, p) -} - -Glob.prototype._makeAbs = function (f) { - return common.makeAbs(this, f) -} - -Glob.prototype.abort = function () { - this.aborted = true - this.emit('abort') -} + } -Glob.prototype.pause = function () { - if (!this.paused) { - this.paused = true - this.emit('pause') + str = str.slice(idx); } -} + return false; +}; -Glob.prototype.resume = function () { - if (this.paused) { - this.emit('resume') - this.paused = false - if (this._emitQueue.length) { - var eq = this._emitQueue.slice(0) - this._emitQueue.length = 0 - for (var i = 0; i < eq.length; i ++) { - var e = eq[i] - this._emitMatch(e[0], e[1]) - } - } - if (this._processQueue.length) { - var pq = this._processQueue.slice(0) - this._processQueue.length = 0 - for (var i = 0; i < pq.length; i ++) { - var p = pq[i] - this._processing-- - this._process(p[0], p[1], p[2], p[3]) - } - } - } -} -Glob.prototype._process = function (pattern, index, inGlobStar, cb) { - assert(this instanceof Glob) - assert(typeof cb === 'function') +/***/ }), +/* 310 */ +/***/ (function(module, exports) { - if (this.aborted) - return +/*! + * is-extglob + * + * Copyright (c) 2014-2016, Jon Schlinkert. + * Licensed under the MIT License. + */ - this._processing++ - if (this.paused) { - this._processQueue.push([pattern, index, inGlobStar, cb]) - return +module.exports = function isExtglob(str) { + if (typeof str !== 'string' || str === '') { + return false; } - //console.error('PROCESS %d', this._processing, pattern) - - // Get the first [n] parts of pattern that are all strings. - var n = 0 - while (typeof pattern[n] === 'string') { - n ++ + var match; + while ((match = /(\\).|([@?!+*]\(.*\))/g.exec(str))) { + if (match[2]) return true; + str = str.slice(match.index + match[0].length); } - // now n is the index of the first one that is *not* a string. - // see if there's anything else - var prefix - switch (n) { - // if not, then this is rather simple - case pattern.length: - this._processSimple(pattern.join('/'), index, cb) - return + return false; +}; - case 0: - // pattern *starts* with some non-trivial item. - // going to readdir(cwd), but not include the prefix in matches. - prefix = null - break - default: - // pattern has some string bits in the front. - // whatever it starts with, whether that's 'absolute' like /foo/bar, - // or 'relative' like '../baz' - prefix = pattern.slice(0, n).join('/') - break - } +/***/ }), +/* 311 */ +/***/ (function(module, exports, __webpack_require__) { - var remain = pattern.slice(n) +"use strict"; - // get the list of entries. - var read - if (prefix === null) - read = '.' - else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) { - if (!prefix || !isAbsolute(prefix)) - prefix = '/' + prefix - read = prefix - } else - read = prefix - var abs = this._makeAbs(read) +const util = __webpack_require__(111); +const braces = __webpack_require__(312); +const picomatch = __webpack_require__(322); +const utils = __webpack_require__(325); +const isEmptyString = val => typeof val === 'string' && (val === '' || val === './'); - //if ignored, skip _processing - if (childrenIgnored(this, read)) - return cb() +/** + * Returns an array of strings that match one or more glob patterns. + * + * ```js + * const mm = require('micromatch'); + * // mm(list, patterns[, options]); + * + * console.log(mm(['a.js', 'a.txt'], ['*.js'])); + * //=> [ 'a.js' ] + * ``` + * @param {String|Array} list 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) + * @return {Array} Returns an array of matches + * @summary false + * @api public + */ - var isGlobStar = remain[0] === minimatch.GLOBSTAR - if (isGlobStar) - this._processGlobStar(prefix, read, abs, remain, index, inGlobStar, cb) - else - this._processReaddir(prefix, read, abs, remain, index, inGlobStar, cb) -} +const micromatch = (list, patterns, options) => { + patterns = [].concat(patterns); + list = [].concat(list); -Glob.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar, cb) { - var self = this - this._readdir(abs, inGlobStar, function (er, entries) { - return self._processReaddir2(prefix, read, abs, remain, index, inGlobStar, entries, cb) - }) -} + let omit = new Set(); + let keep = new Set(); + let items = new Set(); + let negatives = 0; -Glob.prototype._processReaddir2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { + let onResult = state => { + items.add(state.output); + if (options && options.onResult) { + options.onResult(state); + } + }; - // if the abs isn't a dir, then nothing can match! - if (!entries) - return cb() + for (let i = 0; i < patterns.length; i++) { + let isMatch = picomatch(String(patterns[i]), { ...options, onResult }, true); + let negated = isMatch.state.negated || isMatch.state.negatedExtglob; + if (negated) negatives++; - // It will only match dot entries if it starts with a dot, or if - // dot is set. Stuff like @(.foo|.bar) isn't allowed. - var pn = remain[0] - var negate = !!this.minimatch.negate - var rawGlob = pn._glob - var dotOk = this.dot || rawGlob.charAt(0) === '.' + for (let item of list) { + let matched = isMatch(item, true); - var matchedEntries = [] - for (var i = 0; i < entries.length; i++) { - var e = entries[i] - if (e.charAt(0) !== '.' || dotOk) { - var m - if (negate && !prefix) { - m = !e.match(pn) + let match = negated ? !matched.isMatch : matched.isMatch; + if (!match) continue; + + if (negated) { + omit.add(matched.output); } else { - m = e.match(pn) + omit.delete(matched.output); + keep.add(matched.output); } - if (m) - matchedEntries.push(e) } } - //console.error('prd2', prefix, entries, remain[0]._glob, matchedEntries) - - var len = matchedEntries.length - // If there are no matched entries, then nothing matches. - if (len === 0) - return cb() - - // if this is the last remaining pattern bit, then no need for - // an additional stat *unless* the user has specified mark or - // stat explicitly. We know they exist, since readdir returned - // them. - - if (remain.length === 1 && !this.mark && !this.stat) { - if (!this.matches[index]) - this.matches[index] = Object.create(null) - - for (var i = 0; i < len; i ++) { - var e = matchedEntries[i] - if (prefix) { - if (prefix !== '/') - e = prefix + '/' + e - else - e = prefix + e - } + let result = negatives === patterns.length ? [...items] : [...keep]; + let matches = result.filter(item => !omit.has(item)); - if (e.charAt(0) === '/' && !this.nomount) { - e = path.join(this.root, e) - } - this._emitMatch(index, e) + if (options && matches.length === 0) { + if (options.failglob === true) { + throw new Error(`No matches found for "${patterns.join(', ')}"`); } - // This was the last one, and no stats were needed - return cb() - } - // now test all matched entries as stand-ins for that part - // of the pattern. - remain.shift() - for (var i = 0; i < len; i ++) { - var e = matchedEntries[i] - var newPattern - if (prefix) { - if (prefix !== '/') - e = prefix + '/' + e - else - e = prefix + e + if (options.nonull === true || options.nullglob === true) { + return options.unescape ? patterns.map(p => p.replace(/\\/g, '')) : patterns; } - this._process([e].concat(remain), index, inGlobStar, cb) } - cb() -} - -Glob.prototype._emitMatch = function (index, e) { - if (this.aborted) - return - if (isIgnored(this, e)) - return + return matches; +}; - if (this.paused) { - this._emitQueue.push([index, e]) - return - } +/** + * Backwards compatibility + */ - var abs = isAbsolute(e) ? e : this._makeAbs(e) +micromatch.match = micromatch; - if (this.mark) - e = this._mark(e) +/** + * Returns a 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 + * const mm = require('micromatch'); + * // mm.matcher(pattern[, options]); + * + * const isMatch = mm.matcher('*.!(*a)'); + * console.log(isMatch('a.a')); //=> false + * console.log(isMatch('a.b')); //=> true + * ``` + * @param {String} `pattern` Glob pattern + * @param {Object} `options` + * @return {Function} Returns a matcher function. + * @api public + */ - if (this.absolute) - e = abs +micromatch.matcher = (pattern, options) => picomatch(pattern, options); - if (this.matches[index][e]) - return +/** + * Returns true if **any** of the given glob `patterns` match the specified `string`. + * + * ```js + * const mm = require('micromatch'); + * // mm.isMatch(string, patterns[, options]); + * + * console.log(mm.isMatch('a.a', ['b.*', '*.a'])); //=> true + * console.log(mm.isMatch('a.a', 'b.*')); //=> false + * ``` + * @param {String} 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). + * @return {Boolean} Returns true if any patterns match `str` + * @api public + */ - if (this.nodir) { - var c = this.cache[abs] - if (c === 'DIR' || Array.isArray(c)) - return - } +micromatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str); - this.matches[index][e] = true +/** + * Backwards compatibility + */ - var st = this.statCache[abs] - if (st) - this.emit('stat', e, st) +micromatch.any = micromatch.isMatch; - this.emit('match', e) -} +/** + * Returns a list of strings that _**do not match any**_ of the given `patterns`. + * + * ```js + * const 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 + */ -Glob.prototype._readdirInGlobStar = function (abs, cb) { - if (this.aborted) - return +micromatch.not = (list, patterns, options = {}) => { + patterns = [].concat(patterns).map(String); + let result = new Set(); + let items = []; - // follow all symlinked directories forever - // just proceed as if this is a non-globstar situation - if (this.follow) - return this._readdir(abs, false, cb) + let onResult = state => { + if (options.onResult) options.onResult(state); + items.push(state.output); + }; - var lstatkey = 'lstat\0' + abs - var self = this - var lstatcb = inflight(lstatkey, lstatcb_) + let matches = micromatch(list, patterns, { ...options, onResult }); - if (lstatcb) - fs.lstat(abs, lstatcb) + for (let item of items) { + if (!matches.includes(item)) { + result.add(item); + } + } + return [...result]; +}; - function lstatcb_ (er, lstat) { - if (er && er.code === 'ENOENT') - return cb() +/** + * 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 + */ - var isSym = lstat && lstat.isSymbolicLink() - self.symlinks[abs] = isSym +micromatch.contains = (str, pattern, options) => { + if (typeof str !== 'string') { + throw new TypeError(`Expected a string: "${util.inspect(str)}"`); + } - // If it's not a symlink or a dir, then it's definitely a regular file. - // don't bother doing a readdir in that case. - if (!isSym && lstat && !lstat.isDirectory()) { - self.cache[abs] = 'FILE' - cb() - } else - self._readdir(abs, false, cb) + if (Array.isArray(pattern)) { + return pattern.some(p => micromatch.contains(str, p, options)); } -} -Glob.prototype._readdir = function (abs, inGlobStar, cb) { - if (this.aborted) - return + if (typeof pattern === 'string') { + if (isEmptyString(str) || isEmptyString(pattern)) { + return false; + } - cb = inflight('readdir\0'+abs+'\0'+inGlobStar, cb) - if (!cb) - return + if (str.includes(pattern) || (str.startsWith('./') && str.slice(2).includes(pattern))) { + return true; + } + } - //console.error('RD %j %j', +inGlobStar, abs) - if (inGlobStar && !ownProp(this.symlinks, abs)) - return this._readdirInGlobStar(abs, cb) + return micromatch.isMatch(str, pattern, { ...options, contains: true }); +}; - if (ownProp(this.cache, abs)) { - var c = this.cache[abs] - if (!c || c === 'FILE') - return cb() +/** + * 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 + * const mm = require('micromatch'); + * // mm.matchKeys(object, patterns[, options]); + * + * const 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 + */ - if (Array.isArray(c)) - return cb(null, c) +micromatch.matchKeys = (obj, patterns, options) => { + if (!utils.isObject(obj)) { + throw new TypeError('Expected the first argument to be an object'); } + let keys = micromatch(Object.keys(obj), patterns, options); + let res = {}; + for (let key of keys) res[key] = obj[key]; + return res; +}; - var self = this - fs.readdir(abs, readdirCb(this, abs, cb)) -} - -function readdirCb (self, abs, cb) { - return function (er, entries) { - if (er) - self._readdirError(abs, er, cb) - else - self._readdirEntries(abs, entries, cb) - } -} +/** + * Returns true if some of the strings in the given `list` match any of the given glob `patterns`. + * + * ```js + * const 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 + */ -Glob.prototype._readdirEntries = function (abs, entries, cb) { - if (this.aborted) - return +micromatch.some = (list, patterns, options) => { + let items = [].concat(list); - // if we haven't asked to stat everything, then just - // assume that everything in there exists, so we can avoid - // having to stat it a second time. - if (!this.mark && !this.stat) { - for (var i = 0; i < entries.length; i ++) { - var e = entries[i] - if (abs === '/') - e = abs + e - else - e = abs + '/' + e - this.cache[e] = true + for (let pattern of [].concat(patterns)) { + let isMatch = picomatch(String(pattern), options); + if (items.some(item => isMatch(item))) { + return true; } } + return false; +}; - this.cache[abs] = entries - return cb(null, entries) -} - -Glob.prototype._readdirError = function (f, er, cb) { - if (this.aborted) - return - - // handle errors, and cache the information - switch (er.code) { - case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205 - case 'ENOTDIR': // totally normal. means it *does* exist. - var abs = this._makeAbs(f) - this.cache[abs] = 'FILE' - if (abs === this.cwdAbs) { - var error = new Error(er.code + ' invalid cwd ' + this.cwd) - error.path = this.cwd - error.code = er.code - this.emit('error', error) - this.abort() - } - break +/** + * Returns true if every string in the given `list` matches + * any of the given glob `patterns`. + * + * ```js + * const 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 + */ - case 'ENOENT': // not terribly unusual - case 'ELOOP': - case 'ENAMETOOLONG': - case 'UNKNOWN': - this.cache[this._makeAbs(f)] = false - break +micromatch.every = (list, patterns, options) => { + let items = [].concat(list); - default: // some unusual error. Treat as failure. - this.cache[this._makeAbs(f)] = false - if (this.strict) { - this.emit('error', er) - // If the error is handled, then we abort - // if not, we threw out of here - this.abort() - } - if (!this.silent) - console.error('glob error', er) - break + for (let pattern of [].concat(patterns)) { + let isMatch = picomatch(String(pattern), options); + if (!items.every(item => isMatch(item))) { + return false; + } } + return true; +}; - return cb() -} +/** + * Returns true if **all** of the given `patterns` match + * the specified string. + * + * ```js + * const 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 + */ -Glob.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar, cb) { - var self = this - this._readdir(abs, inGlobStar, function (er, entries) { - self._processGlobStar2(prefix, read, abs, remain, index, inGlobStar, entries, cb) - }) -} +micromatch.all = (str, patterns, options) => { + if (typeof str !== 'string') { + throw new TypeError(`Expected a string: "${util.inspect(str)}"`); + } + return [].concat(patterns).every(p => picomatch(p, options)(str)); +}; -Glob.prototype._processGlobStar2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { - //console.error('pgs2', prefix, remain[0], entries) +/** + * Returns an array of matches captured by `pattern` in `string, or `null` if the pattern did not match. + * + * ```js + * const 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} `glob` Glob pattern to use for matching. + * @param {String} `input` 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 input matches the glob pattern, otherwise `null`. + * @api public + */ - // no entries means not a dir, so it can never have matches - // foo.txt/** doesn't match foo.txt - if (!entries) - return cb() +micromatch.capture = (glob, input, options) => { + let posix = utils.isWindows(options); + let regex = picomatch.makeRe(String(glob), { ...options, capture: true }); + let match = regex.exec(posix ? utils.toPosixSlashes(input) : input); - // test without the globstar, and with every child both below - // and replacing the globstar. - var remainWithoutGlobStar = remain.slice(1) - var gspref = prefix ? [ prefix ] : [] - var noGlobStar = gspref.concat(remainWithoutGlobStar) + if (match) { + return match.slice(1).map(v => v === void 0 ? '' : v); + } +}; - // the noGlobStar pattern exits the inGlobStar state - this._process(noGlobStar, index, false, cb) +/** + * Create a regular expression from the given glob `pattern`. + * + * ```js + * const 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` + * @return {RegExp} Returns a regex created from the given pattern. + * @api public + */ - var isSym = this.symlinks[abs] - var len = entries.length +micromatch.makeRe = (...args) => picomatch.makeRe(...args); - // If it's a symlink, and we're in a globstar, then stop - if (isSym && inGlobStar) - return cb() +/** + * Scan a glob pattern to separate the pattern into segments. Used + * by the [split](#split) method. + * + * ```js + * const mm = require('micromatch'); + * const state = mm.scan(pattern[, options]); + * ``` + * @param {String} `pattern` + * @param {Object} `options` + * @return {Object} Returns an object with + * @api public + */ - for (var i = 0; i < len; i++) { - var e = entries[i] - if (e.charAt(0) === '.' && !this.dot) - continue +micromatch.scan = (...args) => picomatch.scan(...args); - // these two cases enter the inGlobStar state - var instead = gspref.concat(entries[i], remainWithoutGlobStar) - this._process(instead, index, true, cb) +/** + * Parse a glob pattern to create the source string for a regular + * expression. + * + * ```js + * const mm = require('micromatch'); + * const state = mm(pattern[, options]); + * ``` + * @param {String} `glob` + * @param {Object} `options` + * @return {Object} Returns an object with useful properties and output to be used as regex source string. + * @api public + */ - var below = gspref.concat(entries[i], remain) - this._process(below, index, true, cb) +micromatch.parse = (patterns, options) => { + let res = []; + for (let pattern of [].concat(patterns || [])) { + for (let str of braces(String(pattern), options)) { + res.push(picomatch.parse(str, options)); + } } + return res; +}; - cb() -} - -Glob.prototype._processSimple = function (prefix, index, cb) { - // XXX review this. Shouldn't it be doing the mounting etc - // before doing stat? kinda weird? - var self = this - this._stat(prefix, function (er, exists) { - self._processSimple2(prefix, index, er, exists, cb) - }) -} -Glob.prototype._processSimple2 = function (prefix, index, er, exists, cb) { - - //console.error('ps2', prefix, exists) - - if (!this.matches[index]) - this.matches[index] = Object.create(null) - - // If it doesn't exist, then just mark the lack of results - if (!exists) - return cb() +/** + * Process the given brace `pattern`. + * + * ```js + * const { braces } = require('micromatch'); + * console.log(braces('foo/{a,b,c}/bar')); + * //=> [ 'foo/(a|b|c)/bar' ] + * + * console.log(braces('foo/{a,b,c}/bar', { expand: true })); + * //=> [ 'foo/a/bar', 'foo/b/bar', 'foo/c/bar' ] + * ``` + * @param {String} `pattern` String with brace pattern to process. + * @param {Object} `options` Any [options](#options) to change how expansion is performed. See the [braces][] library for all available options. + * @return {Array} + * @api public + */ - if (prefix && isAbsolute(prefix) && !this.nomount) { - var trail = /[\/\\]$/.test(prefix) - if (prefix.charAt(0) === '/') { - prefix = path.join(this.root, prefix) - } else { - prefix = path.resolve(this.root, prefix) - if (trail) - prefix += '/' - } +micromatch.braces = (pattern, options) => { + if (typeof pattern !== 'string') throw new TypeError('Expected a string'); + if ((options && options.nobrace === true) || !/\{.*\}/.test(pattern)) { + return [pattern]; } + return braces(pattern, options); +}; - if (process.platform === 'win32') - prefix = prefix.replace(/\\/g, '/') +/** + * Expand braces + */ - // Mark this as a match - this._emitMatch(index, prefix) - cb() -} +micromatch.braceExpand = (pattern, options) => { + if (typeof pattern !== 'string') throw new TypeError('Expected a string'); + return micromatch.braces(pattern, { ...options, expand: true }); +}; -// Returns either 'DIR', 'FILE', or false -Glob.prototype._stat = function (f, cb) { - var abs = this._makeAbs(f) - var needDir = f.slice(-1) === '/' +/** + * Expose micromatch + */ - if (f.length > this.maxLength) - return cb() +module.exports = micromatch; - if (!this.stat && ownProp(this.cache, abs)) { - var c = this.cache[abs] - if (Array.isArray(c)) - c = 'DIR' +/***/ }), +/* 312 */ +/***/ (function(module, exports, __webpack_require__) { - // It exists, but maybe not how we need it - if (!needDir || c === 'DIR') - return cb(null, c) +"use strict"; - if (needDir && c === 'FILE') - return cb() - // otherwise we have to stat, because maybe c=true - // if we know it exists, but not what it is. - } +const stringify = __webpack_require__(313); +const compile = __webpack_require__(315); +const expand = __webpack_require__(319); +const parse = __webpack_require__(320); - var exists - var stat = this.statCache[abs] - if (stat !== undefined) { - if (stat === false) - return cb(null, stat) - else { - var type = stat.isDirectory() ? 'DIR' : 'FILE' - if (needDir && type === 'FILE') - return cb() - else - return cb(null, type, stat) - } - } +/** + * Expand the given pattern or create a regex-compatible string. + * + * ```js + * const braces = require('braces'); + * console.log(braces('{a,b,c}', { compile: true })); //=> ['(a|b|c)'] + * console.log(braces('{a,b,c}')); //=> ['a', 'b', 'c'] + * ``` + * @param {String} `str` + * @param {Object} `options` + * @return {String} + * @api public + */ - var self = this - var statcb = inflight('stat\0' + abs, lstatcb_) - if (statcb) - fs.lstat(abs, statcb) +const braces = (input, options = {}) => { + let output = []; - function lstatcb_ (er, lstat) { - if (lstat && lstat.isSymbolicLink()) { - // If it's a symlink, then treat it as the target, unless - // the target does not exist, then treat it as a file. - return fs.stat(abs, function (er, stat) { - if (er) - self._stat2(f, abs, null, lstat, cb) - else - self._stat2(f, abs, er, stat, cb) - }) - } else { - self._stat2(f, abs, er, lstat, cb) + if (Array.isArray(input)) { + for (let pattern of input) { + let result = braces.create(pattern, options); + if (Array.isArray(result)) { + output.push(...result); + } else { + output.push(result); + } } + } else { + output = [].concat(braces.create(input, options)); } -} -Glob.prototype._stat2 = function (f, abs, er, stat, cb) { - if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) { - this.statCache[abs] = false - return cb() + if (options && options.expand === true && options.nodupes === true) { + output = [...new Set(output)]; } + return output; +}; - var needDir = f.slice(-1) === '/' - this.statCache[abs] = stat - - if (abs.slice(-1) === '/' && stat && !stat.isDirectory()) - return cb(null, false, stat) +/** + * Parse the given `str` with the given `options`. + * + * ```js + * // braces.parse(pattern, [, options]); + * const ast = braces.parse('a/{b,c}/d'); + * console.log(ast); + * ``` + * @param {String} pattern Brace pattern to parse + * @param {Object} options + * @return {Object} Returns an AST + * @api public + */ - var c = true - if (stat) - c = stat.isDirectory() ? 'DIR' : 'FILE' - this.cache[abs] = this.cache[abs] || c +braces.parse = (input, options = {}) => parse(input, options); - if (needDir && c === 'FILE') - return cb() +/** + * Creates a braces string from an AST, or an AST node. + * + * ```js + * const braces = require('braces'); + * let ast = braces.parse('foo/{a,b}/bar'); + * console.log(stringify(ast.nodes[2])); //=> '{a,b}' + * ``` + * @param {String} `input` Brace pattern or AST. + * @param {Object} `options` + * @return {Array} Returns an array of expanded values. + * @api public + */ - return cb(null, c, stat) -} +braces.stringify = (input, options = {}) => { + if (typeof input === 'string') { + return stringify(braces.parse(input, options), options); + } + return stringify(input, options); +}; + +/** + * Compiles a brace pattern into a regex-compatible, optimized string. + * This method is called by the main [braces](#braces) function by default. + * + * ```js + * const braces = require('braces'); + * console.log(braces.compile('a/{b,c}/d')); + * //=> ['a/(b|c)/d'] + * ``` + * @param {String} `input` Brace pattern or AST. + * @param {Object} `options` + * @return {Array} Returns an array of expanded values. + * @api public + */ + +braces.compile = (input, options = {}) => { + if (typeof input === 'string') { + input = braces.parse(input, options); + } + return compile(input, options); +}; + +/** + * 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 [.compile](#compile) instead. + * + * ```js + * const 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 = (input, options = {}) => { + if (typeof input === 'string') { + input = braces.parse(input, options); + } + + let result = expand(input, options); + + // filter out empty strings if specified + if (options.noempty === true) { + result = result.filter(Boolean); + } + + // filter out duplicates if specified + if (options.nodupes === true) { + result = [...new Set(result)]; + } + + return result; +}; + +/** + * 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 + * const 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 = (input, options = {}) => { + if (input === '' || input.length < 3) { + return [input]; + } + + return options.expand !== true + ? braces.compile(input, options) + : braces.expand(input, options); +}; + +/** + * Expose "braces" + */ + +module.exports = braces; /***/ }), -/* 301 */ +/* 313 */ /***/ (function(module, exports, __webpack_require__) { -try { - var util = __webpack_require__(111); - /* istanbul ignore next */ - if (typeof util.inherits !== 'function') throw ''; - module.exports = util.inherits; -} catch (e) { - /* istanbul ignore next */ - module.exports = __webpack_require__(302); -} +"use strict"; -/***/ }), -/* 302 */ -/***/ (function(module, exports) { +const utils = __webpack_require__(314); -if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - if (superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }) +module.exports = (ast, options = {}) => { + let stringify = (node, parent = {}) => { + let invalidBlock = options.escapeInvalid && utils.isInvalidBrace(parent); + let invalidNode = node.invalid === true && options.escapeInvalid === true; + let output = ''; + + if (node.value) { + if ((invalidBlock || invalidNode) && utils.isOpenOrClose(node)) { + return '\\' + node.value; + } + return node.value; } - }; -} else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - if (superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor + + if (node.value) { + return node.value; } - } -} + + if (node.nodes) { + for (let child of node.nodes) { + output += stringify(child); + } + } + return output; + }; + + return stringify(ast); +}; + /***/ }), -/* 303 */ +/* 314 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = globSync -globSync.GlobSync = GlobSync +"use strict"; -var fs = __webpack_require__(133) -var rp = __webpack_require__(147) -var minimatch = __webpack_require__(149) -var Minimatch = minimatch.Minimatch -var Glob = __webpack_require__(300).Glob -var util = __webpack_require__(111) -var path = __webpack_require__(4) -var assert = __webpack_require__(139) -var isAbsolute = __webpack_require__(156) -var common = __webpack_require__(304) -var alphasort = common.alphasort -var alphasorti = common.alphasorti -var setopts = common.setopts -var ownProp = common.ownProp -var childrenIgnored = common.childrenIgnored -var isIgnored = common.isIgnored -function globSync (pattern, options) { - if (typeof options === 'function' || arguments.length === 3) - throw new TypeError('callback provided to sync glob\n'+ - 'See: https://github.com/isaacs/node-glob/issues/167') +exports.isInteger = num => { + if (typeof num === 'number') { + return Number.isInteger(num); + } + if (typeof num === 'string' && num.trim() !== '') { + return Number.isInteger(Number(num)); + } + return false; +}; - return new GlobSync(pattern, options).found -} +/** + * Find a node of the given type + */ -function GlobSync (pattern, options) { - if (!pattern) - throw new Error('must provide pattern') +exports.find = (node, type) => node.nodes.find(node => node.type === type); - if (typeof options === 'function' || arguments.length === 3) - throw new TypeError('callback provided to sync glob\n'+ - 'See: https://github.com/isaacs/node-glob/issues/167') +/** + * Find a node of the given type + */ - if (!(this instanceof GlobSync)) - return new GlobSync(pattern, options) +exports.exceedsLimit = (min, max, step = 1, limit) => { + if (limit === false) return false; + if (!exports.isInteger(min) || !exports.isInteger(max)) return false; + return ((Number(max) - Number(min)) / Number(step)) >= limit; +}; - setopts(this, pattern, options) +/** + * Escape the given node with '\\' before node.value + */ - if (this.noprocess) - return this +exports.escapeNode = (block, n = 0, type) => { + let node = block.nodes[n]; + if (!node) return; - var n = this.minimatch.set.length - this.matches = new Array(n) - for (var i = 0; i < n; i ++) { - this._process(this.minimatch.set[i], i, false) + if ((type && node.type === type) || node.type === 'open' || node.type === 'close') { + if (node.escaped !== true) { + node.value = '\\' + node.value; + node.escaped = true; + } } - this._finish() -} +}; -GlobSync.prototype._finish = function () { - assert(this instanceof GlobSync) - if (this.realpath) { - var self = this - this.matches.forEach(function (matchset, index) { - var set = self.matches[index] = Object.create(null) - for (var p in matchset) { - try { - p = self._makeAbs(p) - var real = rp.realpathSync(p, self.realpathCache) - set[real] = true - } catch (er) { - if (er.syscall === 'stat') - set[self._makeAbs(p)] = true - else - throw er - } - } - }) +/** + * Returns true if the given brace node should be enclosed in literal braces + */ + +exports.encloseBrace = node => { + if (node.type !== 'brace') return false; + if ((node.commas >> 0 + node.ranges >> 0) === 0) { + node.invalid = true; + return true; } - common.finish(this) -} + return false; +}; +/** + * Returns true if a brace node is invalid. + */ -GlobSync.prototype._process = function (pattern, index, inGlobStar) { - assert(this instanceof GlobSync) +exports.isInvalidBrace = block => { + if (block.type !== 'brace') return false; + if (block.invalid === true || block.dollar) return true; + if ((block.commas >> 0 + block.ranges >> 0) === 0) { + block.invalid = true; + return true; + } + if (block.open !== true || block.close !== true) { + block.invalid = true; + return true; + } + return false; +}; - // Get the first [n] parts of pattern that are all strings. - var n = 0 - while (typeof pattern[n] === 'string') { - n ++ +/** + * Returns true if a node is an open or close node + */ + +exports.isOpenOrClose = node => { + if (node.type === 'open' || node.type === 'close') { + return true; } - // now n is the index of the first one that is *not* a string. + return node.open === true || node.close === true; +}; - // See if there's anything else - var prefix - switch (n) { - // if not, then this is rather simple - case pattern.length: - this._processSimple(pattern.join('/'), index) - return +/** + * Reduce an array of text nodes. + */ - case 0: - // pattern *starts* with some non-trivial item. - // going to readdir(cwd), but not include the prefix in matches. - prefix = null - break +exports.reduce = nodes => nodes.reduce((acc, node) => { + if (node.type === 'text') acc.push(node.value); + if (node.type === 'range') node.type = 'text'; + return acc; +}, []); - default: - // pattern has some string bits in the front. - // whatever it starts with, whether that's 'absolute' like /foo/bar, - // or 'relative' like '../baz' - prefix = pattern.slice(0, n).join('/') - break - } +/** + * Flatten an array + */ - var remain = pattern.slice(n) +exports.flatten = (...args) => { + const result = []; + const flat = arr => { + for (let i = 0; i < arr.length; i++) { + let ele = arr[i]; + Array.isArray(ele) ? flat(ele, result) : ele !== void 0 && result.push(ele); + } + return result; + }; + flat(args); + return result; +}; - // get the list of entries. - var read - if (prefix === null) - read = '.' - else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) { - if (!prefix || !isAbsolute(prefix)) - prefix = '/' + prefix - read = prefix - } else - read = prefix - var abs = this._makeAbs(read) +/***/ }), +/* 315 */ +/***/ (function(module, exports, __webpack_require__) { - //if ignored, skip processing - if (childrenIgnored(this, read)) - return +"use strict"; - var isGlobStar = remain[0] === minimatch.GLOBSTAR - if (isGlobStar) - this._processGlobStar(prefix, read, abs, remain, index, inGlobStar) - else - this._processReaddir(prefix, read, abs, remain, index, inGlobStar) -} +const fill = __webpack_require__(316); +const utils = __webpack_require__(314); -GlobSync.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar) { - var entries = this._readdir(abs, inGlobStar) +const compile = (ast, options = {}) => { + let walk = (node, parent = {}) => { + let invalidBlock = utils.isInvalidBrace(parent); + let invalidNode = node.invalid === true && options.escapeInvalid === true; + let invalid = invalidBlock === true || invalidNode === true; + let prefix = options.escapeInvalid === true ? '\\' : ''; + let output = ''; - // if the abs isn't a dir, then nothing can match! - if (!entries) - return + if (node.isOpen === true) { + return prefix + node.value; + } + if (node.isClose === true) { + return prefix + node.value; + } - // It will only match dot entries if it starts with a dot, or if - // dot is set. Stuff like @(.foo|.bar) isn't allowed. - var pn = remain[0] - var negate = !!this.minimatch.negate - var rawGlob = pn._glob - var dotOk = this.dot || rawGlob.charAt(0) === '.' + if (node.type === 'open') { + return invalid ? (prefix + node.value) : '('; + } - var matchedEntries = [] - for (var i = 0; i < entries.length; i++) { - var e = entries[i] - if (e.charAt(0) !== '.' || dotOk) { - var m - if (negate && !prefix) { - m = !e.match(pn) - } else { - m = e.match(pn) - } - if (m) - matchedEntries.push(e) + if (node.type === 'close') { + return invalid ? (prefix + node.value) : ')'; } - } - var len = matchedEntries.length - // If there are no matched entries, then nothing matches. - if (len === 0) - return + if (node.type === 'comma') { + return node.prev.type === 'comma' ? '' : (invalid ? node.value : '|'); + } - // if this is the last remaining pattern bit, then no need for - // an additional stat *unless* the user has specified mark or - // stat explicitly. We know they exist, since readdir returned - // them. + if (node.value) { + return node.value; + } - if (remain.length === 1 && !this.mark && !this.stat) { - if (!this.matches[index]) - this.matches[index] = Object.create(null) + if (node.nodes && node.ranges > 0) { + let args = utils.reduce(node.nodes); + let range = fill(...args, { ...options, wrap: false, toRegex: true }); - for (var i = 0; i < len; i ++) { - var e = matchedEntries[i] - if (prefix) { - if (prefix.slice(-1) !== '/') - e = prefix + '/' + e - else - e = prefix + e + if (range.length !== 0) { + return args.length > 1 && range.length > 1 ? `(${range})` : range; } + } - if (e.charAt(0) === '/' && !this.nomount) { - e = path.join(this.root, e) + if (node.nodes) { + for (let child of node.nodes) { + output += walk(child, node); } - this._emitMatch(index, e) } - // This was the last one, and no stats were needed - return - } + return output; + }; - // now test all matched entries as stand-ins for that part - // of the pattern. - remain.shift() - for (var i = 0; i < len; i ++) { - var e = matchedEntries[i] - var newPattern - if (prefix) - newPattern = [prefix, e] - else - newPattern = [e] - this._process(newPattern.concat(remain), index, inGlobStar) - } -} + return walk(ast); +}; +module.exports = compile; -GlobSync.prototype._emitMatch = function (index, e) { - if (isIgnored(this, e)) - return - var abs = this._makeAbs(e) +/***/ }), +/* 316 */ +/***/ (function(module, exports, __webpack_require__) { - if (this.mark) - e = this._mark(e) +"use strict"; +/*! + * fill-range + * + * Copyright (c) 2014-present, Jon Schlinkert. + * Licensed under the MIT License. + */ - if (this.absolute) { - e = abs - } - if (this.matches[index][e]) - return - if (this.nodir) { - var c = this.cache[abs] - if (c === 'DIR' || Array.isArray(c)) - return - } +const util = __webpack_require__(111); +const toRegexRange = __webpack_require__(317); - this.matches[index][e] = true +const isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); - if (this.stat) - this._stat(e) -} +const transform = toNumber => { + return value => toNumber === true ? Number(value) : String(value); +}; +const isValidValue = value => { + return typeof value === 'number' || (typeof value === 'string' && value !== ''); +}; -GlobSync.prototype._readdirInGlobStar = function (abs) { - // follow all symlinked directories forever - // just proceed as if this is a non-globstar situation - if (this.follow) - return this._readdir(abs, false) +const isNumber = num => Number.isInteger(+num); - var entries - var lstat - var stat - try { - lstat = fs.lstatSync(abs) - } catch (er) { - if (er.code === 'ENOENT') { - // lstat failed, doesn't exist - return null - } - } +const zeros = input => { + let value = `${input}`; + let index = -1; + if (value[0] === '-') value = value.slice(1); + if (value === '0') return false; + while (value[++index] === '0'); + return index > 0; +}; - var isSym = lstat && lstat.isSymbolicLink() - this.symlinks[abs] = isSym +const stringify = (start, end, options) => { + if (typeof start === 'string' || typeof end === 'string') { + return true; + } + return options.stringify === true; +}; - // If it's not a symlink or a dir, then it's definitely a regular file. - // don't bother doing a readdir in that case. - if (!isSym && lstat && !lstat.isDirectory()) - this.cache[abs] = 'FILE' - else - entries = this._readdir(abs, false) +const pad = (input, maxLength, toNumber) => { + if (maxLength > 0) { + let dash = input[0] === '-' ? '-' : ''; + if (dash) input = input.slice(1); + input = (dash + input.padStart(dash ? maxLength - 1 : maxLength, '0')); + } + if (toNumber === false) { + return String(input); + } + return input; +}; - return entries -} +const toMaxLen = (input, maxLength) => { + let negative = input[0] === '-' ? '-' : ''; + if (negative) { + input = input.slice(1); + maxLength--; + } + while (input.length < maxLength) input = '0' + input; + return negative ? ('-' + input) : input; +}; -GlobSync.prototype._readdir = function (abs, inGlobStar) { - var entries +const toSequence = (parts, options) => { + parts.negatives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0); + parts.positives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0); - if (inGlobStar && !ownProp(this.symlinks, abs)) - return this._readdirInGlobStar(abs) + let prefix = options.capture ? '' : '?:'; + let positives = ''; + let negatives = ''; + let result; - if (ownProp(this.cache, abs)) { - var c = this.cache[abs] - if (!c || c === 'FILE') - return null + if (parts.positives.length) { + positives = parts.positives.join('|'); + } - if (Array.isArray(c)) - return c + if (parts.negatives.length) { + negatives = `-(${prefix}${parts.negatives.join('|')})`; } - try { - return this._readdirEntries(abs, fs.readdirSync(abs)) - } catch (er) { - this._readdirError(abs, er) - return null + if (positives && negatives) { + result = `${positives}|${negatives}`; + } else { + result = positives || negatives; } -} -GlobSync.prototype._readdirEntries = function (abs, entries) { - // if we haven't asked to stat everything, then just - // assume that everything in there exists, so we can avoid - // having to stat it a second time. - if (!this.mark && !this.stat) { - for (var i = 0; i < entries.length; i ++) { - var e = entries[i] - if (abs === '/') - e = abs + e - else - e = abs + '/' + e - this.cache[e] = true - } + if (options.wrap) { + return `(${prefix}${result})`; } - this.cache[abs] = entries + return result; +}; - // mark and cache dir-ness - return entries -} +const toRange = (a, b, isNumbers, options) => { + if (isNumbers) { + return toRegexRange(a, b, { wrap: false, ...options }); + } -GlobSync.prototype._readdirError = function (f, er) { - // handle errors, and cache the information - switch (er.code) { - case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205 - case 'ENOTDIR': // totally normal. means it *does* exist. - var abs = this._makeAbs(f) - this.cache[abs] = 'FILE' - if (abs === this.cwdAbs) { - var error = new Error(er.code + ' invalid cwd ' + this.cwd) - error.path = this.cwd - error.code = er.code - throw error - } - break + let start = String.fromCharCode(a); + if (a === b) return start; - case 'ENOENT': // not terribly unusual - case 'ELOOP': - case 'ENAMETOOLONG': - case 'UNKNOWN': - this.cache[this._makeAbs(f)] = false - break + let stop = String.fromCharCode(b); + return `[${start}-${stop}]`; +}; - default: // some unusual error. Treat as failure. - this.cache[this._makeAbs(f)] = false - if (this.strict) - throw er - if (!this.silent) - console.error('glob error', er) - break +const toRegex = (start, end, options) => { + if (Array.isArray(start)) { + let wrap = options.wrap === true; + let prefix = options.capture ? '' : '?:'; + return wrap ? `(${prefix}${start.join('|')})` : start.join('|'); } -} - -GlobSync.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar) { + return toRegexRange(start, end, options); +}; - var entries = this._readdir(abs, inGlobStar) +const rangeError = (...args) => { + return new RangeError('Invalid range arguments: ' + util.inspect(...args)); +}; - // no entries means not a dir, so it can never have matches - // foo.txt/** doesn't match foo.txt - if (!entries) - return +const invalidRange = (start, end, options) => { + if (options.strictRanges === true) throw rangeError([start, end]); + return []; +}; - // test without the globstar, and with every child both below - // and replacing the globstar. - var remainWithoutGlobStar = remain.slice(1) - var gspref = prefix ? [ prefix ] : [] - var noGlobStar = gspref.concat(remainWithoutGlobStar) +const invalidStep = (step, options) => { + if (options.strictRanges === true) { + throw new TypeError(`Expected step "${step}" to be a number`); + } + return []; +}; - // the noGlobStar pattern exits the inGlobStar state - this._process(noGlobStar, index, false) +const fillNumbers = (start, end, step = 1, options = {}) => { + let a = Number(start); + let b = Number(end); - var len = entries.length - var isSym = this.symlinks[abs] + if (!Number.isInteger(a) || !Number.isInteger(b)) { + if (options.strictRanges === true) throw rangeError([start, end]); + return []; + } - // If it's a symlink, and we're in a globstar, then stop - if (isSym && inGlobStar) - return + // fix negative zero + if (a === 0) a = 0; + if (b === 0) b = 0; - for (var i = 0; i < len; i++) { - var e = entries[i] - if (e.charAt(0) === '.' && !this.dot) - continue + let descending = a > b; + let startString = String(start); + let endString = String(end); + let stepString = String(step); + step = Math.max(Math.abs(step), 1); - // these two cases enter the inGlobStar state - var instead = gspref.concat(entries[i], remainWithoutGlobStar) - this._process(instead, index, true) + let padded = zeros(startString) || zeros(endString) || zeros(stepString); + let maxLen = padded ? Math.max(startString.length, endString.length, stepString.length) : 0; + let toNumber = padded === false && stringify(start, end, options) === false; + let format = options.transform || transform(toNumber); - var below = gspref.concat(entries[i], remain) - this._process(below, index, true) + if (options.toRegex && step === 1) { + return toRange(toMaxLen(start, maxLen), toMaxLen(end, maxLen), true, options); } -} - -GlobSync.prototype._processSimple = function (prefix, index) { - // XXX review this. Shouldn't it be doing the mounting etc - // before doing stat? kinda weird? - var exists = this._stat(prefix) - if (!this.matches[index]) - this.matches[index] = Object.create(null) - - // If it doesn't exist, then just mark the lack of results - if (!exists) - return + let parts = { negatives: [], positives: [] }; + let push = num => parts[num < 0 ? 'negatives' : 'positives'].push(Math.abs(num)); + let range = []; + let index = 0; - if (prefix && isAbsolute(prefix) && !this.nomount) { - var trail = /[\/\\]$/.test(prefix) - if (prefix.charAt(0) === '/') { - prefix = path.join(this.root, prefix) + while (descending ? a >= b : a <= b) { + if (options.toRegex === true && step > 1) { + push(a); } else { - prefix = path.resolve(this.root, prefix) - if (trail) - prefix += '/' + range.push(pad(format(a, index), maxLen, toNumber)); } + a = descending ? a - step : a + step; + index++; } - if (process.platform === 'win32') - prefix = prefix.replace(/\\/g, '/') + if (options.toRegex === true) { + return step > 1 + ? toSequence(parts, options) + : toRegex(range, null, { wrap: false, ...options }); + } - // Mark this as a match - this._emitMatch(index, prefix) -} + return range; +}; -// Returns either 'DIR', 'FILE', or false -GlobSync.prototype._stat = function (f) { - var abs = this._makeAbs(f) - var needDir = f.slice(-1) === '/' +const fillLetters = (start, end, step = 1, options = {}) => { + if ((!isNumber(start) && start.length > 1) || (!isNumber(end) && end.length > 1)) { + return invalidRange(start, end, options); + } - if (f.length > this.maxLength) - return false - if (!this.stat && ownProp(this.cache, abs)) { - var c = this.cache[abs] + let format = options.transform || (val => String.fromCharCode(val)); + let a = `${start}`.charCodeAt(0); + let b = `${end}`.charCodeAt(0); - if (Array.isArray(c)) - c = 'DIR' + let descending = a > b; + let min = Math.min(a, b); + let max = Math.max(a, b); - // It exists, but maybe not how we need it - if (!needDir || c === 'DIR') - return c + if (options.toRegex && step === 1) { + return toRange(min, max, false, options); + } - if (needDir && c === 'FILE') - return false + let range = []; + let index = 0; - // otherwise we have to stat, because maybe c=true - // if we know it exists, but not what it is. + while (descending ? a >= b : a <= b) { + range.push(format(a, index)); + a = descending ? a - step : a + step; + index++; } - 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 (options.toRegex === true) { + return toRegex(range, null, { wrap: false, options }); + } - if (lstat && lstat.isSymbolicLink()) { - try { - stat = fs.statSync(abs) - } catch (er) { - stat = lstat - } - } else { - stat = lstat - } + return range; +}; + +const fill = (start, end, step, options = {}) => { + if (end == null && isValidValue(start)) { + return [start]; } - this.statCache[abs] = stat + if (!isValidValue(start) || !isValidValue(end)) { + return invalidRange(start, end, options); + } - var c = true - if (stat) - c = stat.isDirectory() ? 'DIR' : 'FILE' + if (typeof step === 'function') { + return fill(start, end, 1, { transform: step }); + } - this.cache[abs] = this.cache[abs] || c + if (isObject(step)) { + return fill(start, end, 0, step); + } - if (needDir && c === 'FILE') - return false + let opts = { ...options }; + if (opts.capture === true) opts.wrap = true; + step = step || opts.step || 1; - return c -} + if (!isNumber(step)) { + if (step != null && !isObject(step)) return invalidStep(step, opts); + return fill(start, end, 1, step); + } -GlobSync.prototype._mark = function (p) { - return common.mark(this, p) -} + if (isNumber(start) && isNumber(end)) { + return fillNumbers(start, end, step, opts); + } -GlobSync.prototype._makeAbs = function (f) { - return common.makeAbs(this, f) -} + return fillLetters(start, end, Math.max(Math.abs(step), 1), opts); +}; + +module.exports = fill; /***/ }), -/* 304 */ +/* 317 */ /***/ (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) -} +"use strict"; +/*! + * to-regex-range + * + * Copyright (c) 2015-present, Jon Schlinkert. + * Released under the MIT License. + */ -var path = __webpack_require__(4) -var minimatch = __webpack_require__(149) -var isAbsolute = __webpack_require__(156) -var Minimatch = minimatch.Minimatch -function alphasorti (a, b) { - return a.toLowerCase().localeCompare(b.toLowerCase()) -} -function alphasort (a, b) { - return a.localeCompare(b) -} +const isNumber = __webpack_require__(318); -function setupIgnores (self, options) { - self.ignore = options.ignore || [] +const toRegexRange = (min, max, options) => { + if (isNumber(min) === false) { + throw new TypeError('toRegexRange: expected the first argument to be a number'); + } - if (!Array.isArray(self.ignore)) - self.ignore = [self.ignore] + if (max === void 0 || min === max) { + return String(min); + } - if (self.ignore.length) { - self.ignore = self.ignore.map(ignoreMap) + if (isNumber(max) === false) { + throw new TypeError('toRegexRange: expected the second argument to be a number.'); } -} -// 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 }) + let opts = { relaxZeros: true, ...options }; + if (typeof opts.strictZeros === 'boolean') { + opts.relaxZeros = opts.strictZeros === false; } - return { - matcher: new Minimatch(pattern, { dot: true }), - gmatcher: gmatcher + let relax = String(opts.relaxZeros); + let shorthand = String(opts.shorthand); + let capture = String(opts.capture); + let wrap = String(opts.wrap); + let cacheKey = min + ':' + max + '=' + relax + shorthand + capture + wrap; + + if (toRegexRange.cache.hasOwnProperty(cacheKey)) { + return toRegexRange.cache[cacheKey].result; } -} -function setopts (self, pattern, options) { - if (!options) - options = {} + let a = Math.min(min, max); + let b = Math.max(min, max); - // base-matching: just use globstar for that. - if (options.matchBase && -1 === pattern.indexOf("/")) { - if (options.noglobstar) { - throw new Error("base matching requires globstar") + if (Math.abs(a - b) === 1) { + let result = min + '|' + max; + if (opts.capture) { + return `(${result})`; } - pattern = "**/" + pattern + if (opts.wrap === false) { + return result; + } + return `(?:${result})`; } - 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 + let isPadded = hasPadding(min) || hasPadding(max); + let state = { min, max, a, b }; + let positives = []; + let negatives = []; - 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) + if (isPadded) { + state.isPadded = isPadded; + state.maxLen = String(state.max).length; + } - setupIgnores(self, options) + if (a < 0) { + let newMin = b < 0 ? Math.abs(b) : 1; + negatives = splitToPatterns(newMin, Math.abs(a), state, opts); + a = state.a = 0; + } - 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 + if (b >= 0) { + positives = splitToPatterns(a, b, state, opts); } - self.root = options.root || path.resolve(self.cwd, "/") - self.root = path.resolve(self.root) - if (process.platform === "win32") - self.root = self.root.replace(/\\/g, "/") + state.negatives = negatives; + state.positives = positives; + state.result = collatePatterns(negatives, positives, opts); - // 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 + if (opts.capture === true) { + state.result = `(${state.result})`; + } else if (opts.wrap !== false && (positives.length + negatives.length) > 1) { + state.result = `(?:${state.result})`; + } - // disable comments and negation in Minimatch. - // Note that they are not supported in Glob itself anyway. - options.nonegate = true - options.nocomment = true + toRegexRange.cache[cacheKey] = state; + return state.result; +}; - self.minimatch = new Minimatch(pattern, options) - self.options = self.minimatch.options +function collatePatterns(neg, pos, options) { + let onlyNegative = filterPatterns(neg, pos, '-', false, options) || []; + let onlyPositive = filterPatterns(pos, neg, '', false, options) || []; + let intersected = filterPatterns(neg, pos, '-?', true, options) || []; + let subpatterns = onlyNegative.concat(intersected).concat(onlyPositive); + return subpatterns.join('|'); } -function finish (self) { - var nou = self.nounique - var all = nou ? [] : Object.create(null) +function splitToRanges(min, max) { + let nines = 1; + let zeros = 1; - 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 - }) - } + let stop = countNines(min, nines); + let stops = new Set([max]); + + while (min <= stop && stop <= max) { + stops.add(stop); + nines += 1; + stop = countNines(min, nines); } - if (!nou) - all = Object.keys(all) + stop = countZeros(max + 1, zeros) - 1; - if (!self.nosort) - all = all.sort(self.nocase ? alphasorti : alphasort) + while (min < stop && stop <= max) { + stops.add(stop); + zeros += 1; + stop = countZeros(max + 1, zeros) - 1; + } - // 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 - }) + stops = [...stops]; + 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: start, count: [], digits: 0 }; + } + + let zipped = zip(start, stop); + let digits = zipped.length; + let pattern = ''; + let count = 0; + + for (let i = 0; i < digits; i++) { + let [startDigit, stopDigit] = zipped[i]; + + if (startDigit === stopDigit) { + pattern += startDigit; + + } else if (startDigit !== '0' || stopDigit !== '9') { + pattern += toCharacterClass(startDigit, stopDigit, options); + + } else { + count++; } } - if (self.ignore.length) - all = all.filter(function(m) { - return !isIgnored(self, m) - }) + if (count) { + pattern += options.shorthand === true ? '\\d' : '[0-9]'; + } - self.found = all + return { pattern, count: [count], digits }; } -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) === '/' +function splitToPatterns(min, max, tok, options) { + let ranges = splitToRanges(min, max); + let tokens = []; + let start = min; + let prev; - if (isDir && !slash) - m += '/' - else if (!isDir && slash) - m = m.slice(0, -1) + for (let i = 0; i < ranges.length; i++) { + let max = ranges[i]; + let obj = rangeToPattern(String(start), String(max), options); + let zeros = ''; - if (m !== p) { - var mabs = makeAbs(self, m) - self.statCache[mabs] = self.statCache[abs] - self.cache[mabs] = self.cache[abs] + if (!tok.isPadded && prev && prev.pattern === obj.pattern) { + if (prev.count.length > 1) { + prev.count.pop(); + } + + prev.count.push(obj.count[0]); + prev.string = prev.pattern + toQuantifier(prev.count); + start = max + 1; + continue; + } + + if (tok.isPadded) { + zeros = padZeros(max, tok, options); } + + obj.string = zeros + obj.pattern + toQuantifier(obj.count); + tokens.push(obj); + start = max + 1; + prev = obj; } - return m + return tokens; } -// 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) +function filterPatterns(arr, comparison, prefix, intersection, options) { + let result = []; + + for (let ele of arr) { + let { string } = ele; + + // only push if _both_ are negative... + if (!intersection && !contains(comparison, 'string', string)) { + result.push(prefix + string); + } + + // or _both_ are positive + if (intersection && contains(comparison, 'string', string)) { + result.push(prefix + string); + } } + return result; +} - if (process.platform === 'win32') - abs = abs.replace(/\\/g, '/') +/** + * Zip strings + */ - return abs +function zip(a, b) { + let arr = []; + for (let i = 0; i < a.length; i++) arr.push([a[i], b[i]]); + return arr; } +function compare(a, b) { + return a > b ? 1 : b > a ? -1 : 0; +} -// 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 +function contains(arr, key, val) { + return arr.some(ele => ele[key] === val); +} - return self.ignore.some(function(item) { - return item.matcher.match(path) || !!(item.gmatcher && item.gmatcher.match(path)) - }) +function countNines(min, len) { + return Number(String(min).slice(0, -len) + '9'.repeat(len)); } -function childrenIgnored (self, path) { - if (!self.ignore.length) - return false +function countZeros(integer, zeros) { + return integer - (integer % Math.pow(10, zeros)); +} - return self.ignore.some(function(item) { - return !!(item.gmatcher && item.gmatcher.match(path)) - }) +function toQuantifier(digits) { + let [start = 0, stop = ''] = digits; + if (stop || start > 1) { + return `{${start + (stop ? ',' + stop : '')}}`; + } + return ''; } +function toCharacterClass(a, b, options) { + return `[${a}${(b - a === 1) ? '' : '-'}${b}]`; +} -/***/ }), -/* 305 */ -/***/ (function(module, exports, __webpack_require__) { +function hasPadding(str) { + return /^-?(0+)\d/.test(str); +} -"use strict"; - -const taskManager = __webpack_require__(306); -const async_1 = __webpack_require__(335); -const stream_1 = __webpack_require__(370); -const sync_1 = __webpack_require__(371); -const settings_1 = __webpack_require__(373); -const utils = __webpack_require__(307); -async function FastGlob(source, options) { - assertPatternsInput(source); - const works = getWorks(source, async_1.default, options); - const result = await Promise.all(works); - return utils.array.flatten(result); -} -// https://github.com/typescript-eslint/typescript-eslint/issues/60 -// eslint-disable-next-line no-redeclare -(function (FastGlob) { - function sync(source, options) { - assertPatternsInput(source); - const works = getWorks(source, sync_1.default, options); - return utils.array.flatten(works); - } - FastGlob.sync = sync; - function stream(source, options) { - assertPatternsInput(source); - const works = getWorks(source, stream_1.default, options); - /** - * The stream returned by the provider cannot work with an asynchronous iterator. - * To support asynchronous iterators, regardless of the number of tasks, we always multiplex streams. - * This affects performance (+25%). I don't see best solution right now. - */ - return utils.stream.merge(works); - } - FastGlob.stream = stream; - function generateTasks(source, options) { - assertPatternsInput(source); - const patterns = [].concat(source); - const settings = new settings_1.default(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); - const settings = new settings_1.default(options); - const tasks = taskManager.generate(patterns, settings); - const provider = new _Provider(settings); - return tasks.map(provider.read, provider); -} -function assertPatternsInput(input) { - const source = [].concat(input); - const isValidSource = source.every((item) => utils.string.isString(item) && !utils.string.isEmpty(item)); - if (!isValidSource) { - throw new TypeError('Patterns must be a string (non empty) or an array of strings'); - } -} -module.exports = FastGlob; +function padZeros(value, tok, options) { + if (!tok.isPadded) { + return value; + } + let diff = Math.abs(tok.maxLen - String(value).length); + let relax = options.relaxZeros !== false; -/***/ }), -/* 306 */ -/***/ (function(module, exports, __webpack_require__) { + switch (diff) { + case 0: + return ''; + case 1: + return relax ? '0?' : '0'; + case 2: + return relax ? '0{0,2}' : '00'; + default: { + return relax ? `0{0,${diff}}` : `0{${diff}}`; + } + } +} -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(307); -function generate(patterns, settings) { - const positivePatterns = getPositivePatterns(patterns); - const negativePatterns = getNegativePatternsAsPositive(patterns, settings.ignore); - 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); -} -exports.generate = generate; -function convertPatternsToTasks(positive, negative, dynamic) { - const 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) { - const task = convertPatternGroupToTask('.', positive, negative, dynamic); - return [task]; - } - return convertPatternGroupsToTasks(positivePatternsGroup, negative, dynamic); -} -exports.convertPatternsToTasks = convertPatternsToTasks; -function getPositivePatterns(patterns) { - return utils.pattern.getPositivePatterns(patterns); -} -exports.getPositivePatterns = getPositivePatterns; -function getNegativePatternsAsPositive(patterns, ignore) { - const negative = utils.pattern.getNegativePatterns(patterns).concat(ignore); - const positive = negative.map(utils.pattern.convertToPositivePattern); - return positive; -} -exports.getNegativePatternsAsPositive = getNegativePatternsAsPositive; -function groupPatternsByBaseDirectory(patterns) { - const group = {}; - return patterns.reduce((collection, pattern) => { - const base = utils.pattern.getBaseDirectory(pattern); - if (base in collection) { - collection[base].push(pattern); - } - else { - collection[base] = [pattern]; - } - return collection; - }, group); -} -exports.groupPatternsByBaseDirectory = groupPatternsByBaseDirectory; -function convertPatternGroupsToTasks(positive, negative, dynamic) { - return Object.keys(positive).map((base) => { - return convertPatternGroupToTask(base, positive[base], negative, dynamic); - }); -} -exports.convertPatternGroupsToTasks = convertPatternGroupsToTasks; -function convertPatternGroupToTask(base, positive, negative, dynamic) { - return { - dynamic, - positive, - negative, - base, - patterns: [].concat(positive, negative.map(utils.pattern.convertToNegativePattern)) - }; -} -exports.convertPatternGroupToTask = convertPatternGroupToTask; +/** + * Cache + */ +toRegexRange.cache = {}; +toRegexRange.clearCache = () => (toRegexRange.cache = {}); -/***/ }), -/* 307 */ -/***/ (function(module, exports, __webpack_require__) { +/** + * Expose `toRegexRange` + */ -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const array = __webpack_require__(308); -exports.array = array; -const errno = __webpack_require__(309); -exports.errno = errno; -const fs = __webpack_require__(310); -exports.fs = fs; -const path = __webpack_require__(311); -exports.path = path; -const pattern = __webpack_require__(312); -exports.pattern = pattern; -const stream = __webpack_require__(333); -exports.stream = stream; -const string = __webpack_require__(334); -exports.string = string; +module.exports = toRegexRange; /***/ }), -/* 308 */ +/* 318 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -function flatten(items) { - return items.reduce((collection, item) => [].concat(collection, item), []); -} -exports.flatten = flatten; -function splitWhen(items, predicate) { - const result = [[]]; - let groupIndex = 0; - for (const item of items) { - if (predicate(item)) { - groupIndex++; - result[groupIndex] = []; - } - else { - result[groupIndex].push(item); - } - } - return result; -} -exports.splitWhen = splitWhen; +/*! + * is-number + * + * Copyright (c) 2014-present, Jon Schlinkert. + * Released under the MIT License. + */ -/***/ }), -/* 309 */ -/***/ (function(module, exports, __webpack_require__) { -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -function isEnoentCodeError(error) { - return error.code === 'ENOENT'; -} -exports.isEnoentCodeError = isEnoentCodeError; +module.exports = function(num) { + if (typeof num === 'number') { + return num - num === 0; + } + if (typeof num === 'string' && num.trim() !== '') { + return Number.isFinite ? Number.isFinite(+num) : isFinite(+num); + } + return false; +}; /***/ }), -/* 310 */ +/* 319 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -class DirentFromStats { - constructor(name, stats) { - this.name = name; - this.isBlockDevice = stats.isBlockDevice.bind(stats); - this.isCharacterDevice = stats.isCharacterDevice.bind(stats); - this.isDirectory = stats.isDirectory.bind(stats); - this.isFIFO = stats.isFIFO.bind(stats); - this.isFile = stats.isFile.bind(stats); - this.isSocket = stats.isSocket.bind(stats); - this.isSymbolicLink = stats.isSymbolicLink.bind(stats); - } -} -function createDirentFromStats(name, stats) { - return new DirentFromStats(name, stats); -} -exports.createDirentFromStats = createDirentFromStats; -/***/ }), -/* 311 */ -/***/ (function(module, exports, __webpack_require__) { +const fill = __webpack_require__(316); +const stringify = __webpack_require__(313); +const utils = __webpack_require__(314); -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const path = __webpack_require__(4); -const LEADING_DOT_SEGMENT_CHARACTERS_COUNT = 2; // ./ or .\\ -const UNESCAPED_GLOB_SYMBOLS_RE = /(\\?)([()*?[\]{|}]|^!|[!+@](?=\())/g; -/** - * Designed to work only with simple paths: `dir\\file`. - */ -function unixify(filepath) { - return filepath.replace(/\\/g, '/'); -} -exports.unixify = unixify; -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; -function removeLeadingDotSegment(entry) { - // We do not use `startsWith` because this is 10x slower than current implementation for some cases. - // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with - if (entry.charAt(0) === '.') { - const secondCharactery = entry.charAt(1); - if (secondCharactery === '/' || secondCharactery === '\\') { - return entry.slice(LEADING_DOT_SEGMENT_CHARACTERS_COUNT); - } - } - return entry; -} -exports.removeLeadingDotSegment = removeLeadingDotSegment; +const append = (queue = '', stash = '', enclose = false) => { + let result = []; + queue = [].concat(queue); + stash = [].concat(stash); -/***/ }), -/* 312 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const path = __webpack_require__(4); -const globParent = __webpack_require__(313); -const micromatch = __webpack_require__(316); -const picomatch = __webpack_require__(327); -const GLOBSTAR = '**'; -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, 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) { - return isNegativePattern(pattern) ? pattern.slice(1) : pattern; -} -exports.convertToPositivePattern = convertToPositivePattern; -function convertToNegativePattern(pattern) { - return '!' + pattern; -} -exports.convertToNegativePattern = convertToNegativePattern; -function isNegativePattern(pattern) { - return pattern.startsWith('!') && pattern[1] !== '('; -} -exports.isNegativePattern = isNegativePattern; -function isPositivePattern(pattern) { - return !isNegativePattern(pattern); -} -exports.isPositivePattern = isPositivePattern; -function getNegativePatterns(patterns) { - return patterns.filter(isNegativePattern); -} -exports.getNegativePatterns = getNegativePatterns; -function getPositivePatterns(patterns) { - return patterns.filter(isPositivePattern); -} -exports.getPositivePatterns = getPositivePatterns; -function getBaseDirectory(pattern) { - return globParent(pattern, { flipBackslashes: false }); -} -exports.getBaseDirectory = getBaseDirectory; -function hasGlobStar(pattern) { - return pattern.includes(GLOBSTAR); -} -exports.hasGlobStar = hasGlobStar; -function endsWithSlashGlobStar(pattern) { - return pattern.endsWith('/' + GLOBSTAR); -} -exports.endsWithSlashGlobStar = endsWithSlashGlobStar; -function isAffectDepthOfReadingPattern(pattern) { - const basename = path.basename(pattern); - return endsWithSlashGlobStar(pattern) || isStaticPattern(basename); -} -exports.isAffectDepthOfReadingPattern = isAffectDepthOfReadingPattern; -function expandPatternsWithBraceExpansion(patterns) { - return patterns.reduce((collection, pattern) => { - return collection.concat(expandBraceExpansion(pattern)); - }, []); -} -exports.expandPatternsWithBraceExpansion = expandPatternsWithBraceExpansion; -function expandBraceExpansion(pattern) { - return micromatch.braces(pattern, { - expand: true, - nodupes: true - }); -} -exports.expandBraceExpansion = expandBraceExpansion; -function getPatternParts(pattern, options) { - const info = picomatch.scan(pattern, Object.assign(Object.assign({}, options), { parts: true })); - // See micromatch/picomatch#58 for more details - if (info.parts.length === 0) { - return [pattern]; - } - return info.parts; -} -exports.getPatternParts = getPatternParts; -function makeRe(pattern, options) { - return micromatch.makeRe(pattern, options); -} -exports.makeRe = makeRe; -function convertPatternsToRe(patterns, options) { - return patterns.map((pattern) => makeRe(pattern, options)); -} -exports.convertPatternsToRe = convertPatternsToRe; -function matchAny(entry, patternsRe) { - return patternsRe.some((patternRe) => patternRe.test(entry)); -} -exports.matchAny = matchAny; - - -/***/ }), -/* 313 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isGlob = __webpack_require__(314); -var pathPosixDirname = __webpack_require__(4).posix.dirname; -var isWin32 = __webpack_require__(120).platform() === 'win32'; - -var slash = '/'; -var backslash = /\\/g; -var enclosure = /[\{\[].*[\/]*.*[\}\]]$/; -var globby = /(^|[^\\])([\{\[]|\([^\)]+$)/; -var escaped = /\\([\!\*\?\|\[\]\(\)\{\}])/g; - -/** - * @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 (options.flipBackslashes && isWin32 && str.indexOf(slash) < 0) { - str = str.replace(backslash, slash); + if (!stash.length) return queue; + if (!queue.length) { + return enclose ? utils.flatten(stash).map(ele => `{${ele}}`) : stash; } - // special case for strings ending in enclosure containing path separator - if (enclosure.test(str)) { - str += slash; + for (let item of queue) { + if (Array.isArray(item)) { + for (let value of item) { + result.push(append(value, stash, enclose)); + } + } else { + for (let ele of stash) { + if (enclose === true && typeof ele === 'string') ele = `{${ele}}`; + result.push(Array.isArray(ele) ? append(item, ele, enclose) : (item + ele)); + } + } } + return utils.flatten(result); +}; - // preserves full path in case of trailing path separator - str += 'a'; - - // remove path parts that are globby - do { - str = pathPosixDirname(str); - } while (isGlob(str) || globby.test(str)); +const expand = (ast, options = {}) => { + let rangeLimit = options.rangeLimit === void 0 ? 1000 : options.rangeLimit; - // remove escape chars and return result - return str.replace(escaped, '$1'); -}; + let walk = (node, parent = {}) => { + node.queue = []; + let p = parent; + let q = parent.queue; -/***/ }), -/* 314 */ -/***/ (function(module, exports, __webpack_require__) { + while (p.type !== 'brace' && p.type !== 'root' && p.parent) { + p = p.parent; + q = p.queue; + } -/*! - * is-glob - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ + if (node.invalid || node.dollar) { + q.push(append(q.pop(), stringify(node, options))); + return; + } -var isExtglob = __webpack_require__(315); -var chars = { '{': '}', '(': ')', '[': ']'}; -var strictRegex = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/; -var relaxedRegex = /\\(.)|(^!|[*?{}()[\]]|\(\?)/; + if (node.type === 'brace' && node.invalid !== true && node.nodes.length === 2) { + q.push(append(q.pop(), ['{}'])); + return; + } -module.exports = function isGlob(str, options) { - if (typeof str !== 'string' || str === '') { - return false; - } + if (node.nodes && node.ranges > 0) { + let args = utils.reduce(node.nodes); - if (isExtglob(str)) { - return true; - } + if (utils.exceedsLimit(...args, options.step, rangeLimit)) { + throw new RangeError('expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.'); + } - var regex = strictRegex; - var match; + let range = fill(...args, options); + if (range.length === 0) { + range = stringify(node, options); + } - // optionally relax regex - if (options && options.strict === false) { - regex = relaxedRegex; - } + q.push(append(q.pop(), range)); + node.nodes = []; + return; + } - while ((match = regex.exec(str))) { - if (match[2]) return true; - var idx = match.index + match[0].length; + let enclose = utils.encloseBrace(node); + let queue = node.queue; + let block = node; - // 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; - } + while (block.type !== 'brace' && block.type !== 'root' && block.parent) { + block = block.parent; + queue = block.queue; } - str = str.slice(idx); - } - return false; -}; + for (let i = 0; i < node.nodes.length; i++) { + let child = node.nodes[i]; + if (child.type === 'comma' && node.type === 'brace') { + if (i === 1) queue.push(''); + queue.push(''); + continue; + } -/***/ }), -/* 315 */ -/***/ (function(module, exports) { + if (child.type === 'close') { + q.push(append(q.pop(), queue, enclose)); + continue; + } -/*! - * is-extglob - * - * Copyright (c) 2014-2016, Jon Schlinkert. - * Licensed under the MIT License. - */ + if (child.value && child.type !== 'open') { + queue.push(append(queue.pop(), child.value)); + continue; + } -module.exports = function isExtglob(str) { - if (typeof str !== 'string' || str === '') { - return false; - } + if (child.nodes) { + walk(child, node); + } + } - var match; - while ((match = /(\\).|([@?!+*]\(.*\))/g.exec(str))) { - if (match[2]) return true; - str = str.slice(match.index + match[0].length); - } + return queue; + }; - return false; + return utils.flatten(walk(ast)); }; +module.exports = expand; + /***/ }), -/* 316 */ +/* 320 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const util = __webpack_require__(111); -const braces = __webpack_require__(317); -const picomatch = __webpack_require__(327); -const utils = __webpack_require__(330); -const isEmptyString = val => typeof val === 'string' && (val === '' || val === './'); +const stringify = __webpack_require__(313); /** - * Returns an array of strings that match one or more glob patterns. - * - * ```js - * const mm = require('micromatch'); - * // mm(list, patterns[, options]); - * - * console.log(mm(['a.js', 'a.txt'], ['*.js'])); - * //=> [ 'a.js' ] - * ``` - * @param {String|Array} list 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) - * @return {Array} Returns an array of matches - * @summary false - * @api public + * Constants */ -const micromatch = (list, patterns, options) => { - patterns = [].concat(patterns); - list = [].concat(list); +const { + MAX_LENGTH, + CHAR_BACKSLASH, /* \ */ + CHAR_BACKTICK, /* ` */ + CHAR_COMMA, /* , */ + CHAR_DOT, /* . */ + CHAR_LEFT_PARENTHESES, /* ( */ + CHAR_RIGHT_PARENTHESES, /* ) */ + CHAR_LEFT_CURLY_BRACE, /* { */ + CHAR_RIGHT_CURLY_BRACE, /* } */ + CHAR_LEFT_SQUARE_BRACKET, /* [ */ + CHAR_RIGHT_SQUARE_BRACKET, /* ] */ + CHAR_DOUBLE_QUOTE, /* " */ + CHAR_SINGLE_QUOTE, /* ' */ + CHAR_NO_BREAK_SPACE, + CHAR_ZERO_WIDTH_NOBREAK_SPACE +} = __webpack_require__(321); - let omit = new Set(); - let keep = new Set(); - let items = new Set(); - let negatives = 0; +/** + * parse + */ - let onResult = state => { - items.add(state.output); - if (options && options.onResult) { - options.onResult(state); - } - }; +const parse = (input, options = {}) => { + if (typeof input !== 'string') { + throw new TypeError('Expected a string'); + } - for (let i = 0; i < patterns.length; i++) { - let isMatch = picomatch(String(patterns[i]), { ...options, onResult }, true); - let negated = isMatch.state.negated || isMatch.state.negatedExtglob; - if (negated) negatives++; + let opts = options || {}; + let max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; + if (input.length > max) { + throw new SyntaxError(`Input length (${input.length}), exceeds max characters (${max})`); + } - for (let item of list) { - let matched = isMatch(item, true); + let ast = { type: 'root', input, nodes: [] }; + let stack = [ast]; + let block = ast; + let prev = ast; + let brackets = 0; + let length = input.length; + let index = 0; + let depth = 0; + let value; + let memo = {}; - let match = negated ? !matched.isMatch : matched.isMatch; - if (!match) continue; + /** + * Helpers + */ - if (negated) { - omit.add(matched.output); - } else { - omit.delete(matched.output); - keep.add(matched.output); - } + const advance = () => input[index++]; + const push = node => { + if (node.type === 'text' && prev.type === 'dot') { + prev.type = 'text'; } - } - - let result = negatives === patterns.length ? [...items] : [...keep]; - let matches = result.filter(item => !omit.has(item)); - if (options && matches.length === 0) { - if (options.failglob === true) { - throw new Error(`No matches found for "${patterns.join(', ')}"`); + if (prev && prev.type === 'text' && node.type === 'text') { + prev.value += node.value; + return; } - if (options.nonull === true || options.nullglob === true) { - return options.unescape ? patterns.map(p => p.replace(/\\/g, '')) : patterns; - } - } + block.nodes.push(node); + node.parent = block; + node.prev = prev; + prev = node; + return node; + }; - return matches; -}; + push({ type: 'bos' }); -/** - * Backwards compatibility - */ + while (index < length) { + block = stack[stack.length - 1]; + value = advance(); -micromatch.match = micromatch; + /** + * Invalid chars + */ -/** - * Returns a 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 - * const mm = require('micromatch'); - * // mm.matcher(pattern[, options]); - * - * const isMatch = mm.matcher('*.!(*a)'); - * console.log(isMatch('a.a')); //=> false - * console.log(isMatch('a.b')); //=> true - * ``` - * @param {String} `pattern` Glob pattern - * @param {Object} `options` - * @return {Function} Returns a matcher function. - * @api public - */ + if (value === CHAR_ZERO_WIDTH_NOBREAK_SPACE || value === CHAR_NO_BREAK_SPACE) { + continue; + } -micromatch.matcher = (pattern, options) => picomatch(pattern, options); + /** + * Escaped chars + */ -/** - * Returns true if **any** of the given glob `patterns` match the specified `string`. - * - * ```js - * const mm = require('micromatch'); - * // mm.isMatch(string, patterns[, options]); - * - * console.log(mm.isMatch('a.a', ['b.*', '*.a'])); //=> true - * console.log(mm.isMatch('a.a', 'b.*')); //=> false - * ``` - * @param {String} 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). - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ + if (value === CHAR_BACKSLASH) { + push({ type: 'text', value: (options.keepEscaping ? value : '') + advance() }); + continue; + } -micromatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str); + /** + * Right square bracket (literal): ']' + */ -/** - * Backwards compatibility - */ + if (value === CHAR_RIGHT_SQUARE_BRACKET) { + push({ type: 'text', value: '\\' + value }); + continue; + } -micromatch.any = micromatch.isMatch; + /** + * Left square bracket: '[' + */ -/** - * Returns a list of strings that _**do not match any**_ of the given `patterns`. - * - * ```js - * const 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 - */ + if (value === CHAR_LEFT_SQUARE_BRACKET) { + brackets++; -micromatch.not = (list, patterns, options = {}) => { - patterns = [].concat(patterns).map(String); - let result = new Set(); - let items = []; + let closed = true; + let next; - let onResult = state => { - if (options.onResult) options.onResult(state); - items.push(state.output); - }; + while (index < length && (next = advance())) { + value += next; - let matches = micromatch(list, patterns, { ...options, onResult }); + if (next === CHAR_LEFT_SQUARE_BRACKET) { + brackets++; + continue; + } - for (let item of items) { - if (!matches.includes(item)) { - result.add(item); + if (next === CHAR_BACKSLASH) { + value += advance(); + continue; + } + + if (next === CHAR_RIGHT_SQUARE_BRACKET) { + brackets--; + + if (brackets === 0) { + break; + } + } + } + + push({ type: 'text', value }); + continue; + } + + /** + * Parentheses + */ + + if (value === CHAR_LEFT_PARENTHESES) { + block = push({ type: 'paren', nodes: [] }); + stack.push(block); + push({ type: 'text', value }); + continue; + } + + if (value === CHAR_RIGHT_PARENTHESES) { + if (block.type !== 'paren') { + push({ type: 'text', value }); + continue; + } + block = stack.pop(); + push({ type: 'text', value }); + block = stack[stack.length - 1]; + continue; + } + + /** + * Quotes: '|"|` + */ + + if (value === CHAR_DOUBLE_QUOTE || value === CHAR_SINGLE_QUOTE || value === CHAR_BACKTICK) { + let open = value; + let next; + + if (options.keepQuotes !== true) { + value = ''; + } + + while (index < length && (next = advance())) { + if (next === CHAR_BACKSLASH) { + value += next + advance(); + continue; + } + + if (next === open) { + if (options.keepQuotes === true) value += next; + break; + } + + value += next; + } + + push({ type: 'text', value }); + continue; + } + + /** + * Left curly brace: '{' + */ + + if (value === CHAR_LEFT_CURLY_BRACE) { + depth++; + + let dollar = prev.value && prev.value.slice(-1) === '$' || block.dollar === true; + let brace = { + type: 'brace', + open: true, + close: false, + dollar, + depth, + commas: 0, + ranges: 0, + nodes: [] + }; + + block = push(brace); + stack.push(block); + push({ type: 'open', value }); + continue; + } + + /** + * Right curly brace: '}' + */ + + if (value === CHAR_RIGHT_CURLY_BRACE) { + if (block.type !== 'brace') { + push({ type: 'text', value }); + continue; + } + + let type = 'close'; + block = stack.pop(); + block.close = true; + + push({ type, value }); + depth--; + + block = stack[stack.length - 1]; + continue; + } + + /** + * Comma: ',' + */ + + if (value === CHAR_COMMA && depth > 0) { + if (block.ranges > 0) { + block.ranges = 0; + let open = block.nodes.shift(); + block.nodes = [open, { type: 'text', value: stringify(block) }]; + } + + push({ type: 'comma', value }); + block.commas++; + continue; + } + + /** + * Dot: '.' + */ + + if (value === CHAR_DOT && depth > 0 && block.commas === 0) { + let siblings = block.nodes; + + if (depth === 0 || siblings.length === 0) { + push({ type: 'text', value }); + continue; + } + + if (prev.type === 'dot') { + block.range = []; + prev.value += value; + prev.type = 'range'; + + if (block.nodes.length !== 3 && block.nodes.length !== 5) { + block.invalid = true; + block.ranges = 0; + prev.type = 'text'; + continue; + } + + block.ranges++; + block.args = []; + continue; + } + + if (prev.type === 'range') { + siblings.pop(); + + let before = siblings[siblings.length - 1]; + before.value += prev.value + value; + prev = before; + block.ranges--; + continue; + } + + push({ type: 'dot', value }); + continue; } + + /** + * Text + */ + + push({ type: 'text', value }); } - return [...result]; + + // Mark imbalanced braces and brackets as invalid + do { + block = stack.pop(); + + if (block.type !== 'root') { + block.nodes.forEach(node => { + if (!node.nodes) { + if (node.type === 'open') node.isOpen = true; + if (node.type === 'close') node.isClose = true; + if (!node.nodes) node.type = 'text'; + node.invalid = true; + } + }); + + // get the location of the block on parent.nodes (block's siblings) + let parent = stack[stack.length - 1]; + let index = parent.nodes.indexOf(block); + // replace the (invalid) block with it's nodes + parent.nodes.splice(index, 1, ...block.nodes); + } + } while (stack.length > 0); + + push({ type: 'eos' }); + return ast; +}; + +module.exports = parse; + + +/***/ }), +/* 321 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = { + MAX_LENGTH: 1024 * 64, + + // Digits + CHAR_0: '0', /* 0 */ + CHAR_9: '9', /* 9 */ + + // Alphabet chars. + CHAR_UPPERCASE_A: 'A', /* A */ + CHAR_LOWERCASE_A: 'a', /* a */ + CHAR_UPPERCASE_Z: 'Z', /* Z */ + CHAR_LOWERCASE_Z: 'z', /* z */ + + CHAR_LEFT_PARENTHESES: '(', /* ( */ + CHAR_RIGHT_PARENTHESES: ')', /* ) */ + + CHAR_ASTERISK: '*', /* * */ + + // Non-alphabetic chars. + CHAR_AMPERSAND: '&', /* & */ + CHAR_AT: '@', /* @ */ + CHAR_BACKSLASH: '\\', /* \ */ + CHAR_BACKTICK: '`', /* ` */ + CHAR_CARRIAGE_RETURN: '\r', /* \r */ + CHAR_CIRCUMFLEX_ACCENT: '^', /* ^ */ + CHAR_COLON: ':', /* : */ + CHAR_COMMA: ',', /* , */ + CHAR_DOLLAR: '$', /* . */ + CHAR_DOT: '.', /* . */ + CHAR_DOUBLE_QUOTE: '"', /* " */ + CHAR_EQUAL: '=', /* = */ + CHAR_EXCLAMATION_MARK: '!', /* ! */ + CHAR_FORM_FEED: '\f', /* \f */ + CHAR_FORWARD_SLASH: '/', /* / */ + CHAR_HASH: '#', /* # */ + CHAR_HYPHEN_MINUS: '-', /* - */ + CHAR_LEFT_ANGLE_BRACKET: '<', /* < */ + CHAR_LEFT_CURLY_BRACE: '{', /* { */ + CHAR_LEFT_SQUARE_BRACKET: '[', /* [ */ + CHAR_LINE_FEED: '\n', /* \n */ + CHAR_NO_BREAK_SPACE: '\u00A0', /* \u00A0 */ + CHAR_PERCENT: '%', /* % */ + CHAR_PLUS: '+', /* + */ + CHAR_QUESTION_MARK: '?', /* ? */ + CHAR_RIGHT_ANGLE_BRACKET: '>', /* > */ + CHAR_RIGHT_CURLY_BRACE: '}', /* } */ + CHAR_RIGHT_SQUARE_BRACKET: ']', /* ] */ + CHAR_SEMICOLON: ';', /* ; */ + CHAR_SINGLE_QUOTE: '\'', /* ' */ + CHAR_SPACE: ' ', /* */ + CHAR_TAB: '\t', /* \t */ + CHAR_UNDERSCORE: '_', /* _ */ + CHAR_VERTICAL_LINE: '|', /* | */ + CHAR_ZERO_WIDTH_NOBREAK_SPACE: '\uFEFF' /* \uFEFF */ }; + +/***/ }), +/* 322 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = __webpack_require__(323); + + +/***/ }), +/* 323 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +const path = __webpack_require__(4); +const scan = __webpack_require__(324); +const parse = __webpack_require__(327); +const utils = __webpack_require__(325); +const constants = __webpack_require__(326); +const isObject = val => val && typeof val === 'object' && !Array.isArray(val); + /** - * Returns true if the given `string` contains the given pattern. Similar - * to [.isMatch](#isMatch) but the pattern can match any part of the string. + * Creates a matcher function from one or more glob patterns. The + * returned function takes a string to match as its first argument, + * and returns true if the string is a match. The returned matcher + * function also takes a boolean as the second argument that, when true, + * returns an object with additional information. * * ```js - * var mm = require('micromatch'); - * // mm.contains(string, pattern[, options]); + * const picomatch = require('picomatch'); + * // picomatch(glob[, options]); * - * console.log(mm.contains('aa/bb/cc', '*b')); - * //=> true - * console.log(mm.contains('aa/bb/cc', '*d')); - * //=> false + * const isMatch = picomatch('*.!(*a)'); + * console.log(isMatch('a.a')); //=> false + * console.log(isMatch('a.b')); //=> true * ``` - * @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`. + * @name picomatch + * @param {String|Array} `globs` One or more glob patterns. + * @param {Object=} `options` + * @return {Function=} Returns a matcher function. * @api public */ -micromatch.contains = (str, pattern, options) => { - if (typeof str !== 'string') { - throw new TypeError(`Expected a string: "${util.inspect(str)}"`); +const picomatch = (glob, options, returnState = false) => { + if (Array.isArray(glob)) { + const fns = glob.map(input => picomatch(input, options, returnState)); + const arrayMatcher = str => { + for (const isMatch of fns) { + const state = isMatch(str); + if (state) return state; + } + return false; + }; + return arrayMatcher; } - if (Array.isArray(pattern)) { - return pattern.some(p => micromatch.contains(str, p, options)); + const isState = isObject(glob) && glob.tokens && glob.input; + + if (glob === '' || (typeof glob !== 'string' && !isState)) { + throw new TypeError('Expected pattern to be a non-empty string'); } - if (typeof pattern === 'string') { - if (isEmptyString(str) || isEmptyString(pattern)) { - return false; + const opts = options || {}; + const posix = utils.isWindows(options); + const regex = isState + ? picomatch.compileRe(glob, options) + : picomatch.makeRe(glob, options, false, true); + + const state = regex.state; + delete regex.state; + + let isIgnored = () => false; + if (opts.ignore) { + const ignoreOpts = { ...options, ignore: null, onMatch: null, onResult: null }; + isIgnored = picomatch(opts.ignore, ignoreOpts, returnState); + } + + const matcher = (input, returnObject = false) => { + const { isMatch, match, output } = picomatch.test(input, regex, options, { glob, posix }); + const result = { glob, state, regex, posix, input, output, match, isMatch }; + + if (typeof opts.onResult === 'function') { + opts.onResult(result); } - if (str.includes(pattern) || (str.startsWith('./') && str.slice(2).includes(pattern))) { - return true; + if (isMatch === false) { + result.isMatch = false; + return returnObject ? result : false; + } + + if (isIgnored(input)) { + if (typeof opts.onIgnore === 'function') { + opts.onIgnore(result); + } + result.isMatch = false; + return returnObject ? result : false; + } + + if (typeof opts.onMatch === 'function') { + opts.onMatch(result); } + return returnObject ? result : true; + }; + + if (returnState) { + matcher.state = state; } - return micromatch.isMatch(str, pattern, { ...options, contains: true }); + return matcher; }; /** - * 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. + * Test `input` with the given `regex`. This is used by the main + * `picomatch()` function to test the input string. * * ```js - * const mm = require('micromatch'); - * // mm.matchKeys(object, patterns[, options]); + * const picomatch = require('picomatch'); + * // picomatch.test(input, regex[, options]); * - * const obj = { aa: 'a', ab: 'b', ac: 'c' }; - * console.log(mm.matchKeys(obj, '*b')); - * //=> { ab: 'b' } + * console.log(picomatch.test('foo/bar', /^(?:([^/]*?)\/([^/]*?))$/)); + * // { isMatch: true, match: [ 'foo/', 'foo', 'bar' ], output: 'foo/bar' } * ``` - * @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. + * @param {String} `input` String to test. + * @param {RegExp} `regex` + * @return {Object} Returns an object with matching info. * @api public */ -micromatch.matchKeys = (obj, patterns, options) => { - if (!utils.isObject(obj)) { - throw new TypeError('Expected the first argument to be an object'); +picomatch.test = (input, regex, options, { glob, posix } = {}) => { + if (typeof input !== 'string') { + throw new TypeError('Expected input to be a string'); } - let keys = micromatch(Object.keys(obj), patterns, options); - let res = {}; - for (let key of keys) res[key] = obj[key]; - return res; + + if (input === '') { + return { isMatch: false, output: '' }; + } + + const opts = options || {}; + const format = opts.format || (posix ? utils.toPosixSlashes : null); + let match = input === glob; + let output = (match && format) ? format(input) : input; + + if (match === false) { + output = format ? format(input) : input; + match = output === glob; + } + + if (match === false || opts.capture === true) { + if (opts.matchBase === true || opts.basename === true) { + match = picomatch.matchBase(input, regex, options, posix); + } else { + match = regex.exec(output); + } + } + + return { isMatch: Boolean(match), match, output }; }; /** - * Returns true if some of the strings in the given `list` match any of the given glob `patterns`. + * Match the basename of a filepath. * * ```js - * const 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 + * const picomatch = require('picomatch'); + * // picomatch.matchBase(input, glob[, options]); + * console.log(picomatch.matchBase('foo/bar.js', '*.js'); // true * ``` - * @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` + * @param {String} `input` String to test. + * @param {RegExp|String} `glob` Glob pattern or regex created by [.makeRe](#makeRe). + * @return {Boolean} * @api public */ -micromatch.some = (list, patterns, options) => { - let items = [].concat(list); - - for (let pattern of [].concat(patterns)) { - let isMatch = picomatch(String(pattern), options); - if (items.some(item => isMatch(item))) { - return true; - } - } - return false; +picomatch.matchBase = (input, glob, options, posix = utils.isWindows(options)) => { + const regex = glob instanceof RegExp ? glob : picomatch.makeRe(glob, options); + return regex.test(path.basename(input)); }; /** - * Returns true if every string in the given `list` matches - * any of the given glob `patterns`. + * Returns true if **any** of the given glob `patterns` match the specified `string`. * * ```js - * const mm = require('micromatch'); - * // mm.every(list, patterns[, options]); + * const picomatch = require('picomatch'); + * // picomatch.isMatch(string, 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 + * console.log(picomatch.isMatch('a.a', ['b.*', '*.a'])); //=> true + * console.log(picomatch.isMatch('a.a', 'b.*')); //=> 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 + * @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). * @return {Boolean} Returns true if any patterns match `str` * @api public */ -micromatch.every = (list, patterns, options) => { - let items = [].concat(list); - - for (let pattern of [].concat(patterns)) { - let isMatch = picomatch(String(pattern), options); - if (!items.every(item => isMatch(item))) { - return false; - } - } - return true; -}; +picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str); /** - * Returns true if **all** of the given `patterns` match - * the specified string. + * Parse a glob pattern to create the source string for a regular + * expression. * * ```js - * const 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 + * const picomatch = require('picomatch'); + * const result = picomatch.parse(pattern[, options]); * ``` - * @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` + * @param {String} `pattern` + * @param {Object} `options` + * @return {Object} Returns an object with useful properties and output to be used as a regex source string. * @api public */ -micromatch.all = (str, patterns, options) => { - if (typeof str !== 'string') { - throw new TypeError(`Expected a string: "${util.inspect(str)}"`); - } - - return [].concat(patterns).every(p => picomatch(p, options)(str)); +picomatch.parse = (pattern, options) => { + if (Array.isArray(pattern)) return pattern.map(p => picomatch.parse(p, options)); + return parse(pattern, { ...options, fastpaths: false }); }; /** - * Returns an array of matches captured by `pattern` in `string, or `null` if the pattern did not match. + * Scan a glob pattern to separate the pattern into segments. * * ```js - * const mm = require('micromatch'); - * // mm.capture(pattern, string[, options]); + * const picomatch = require('picomatch'); + * // picomatch.scan(input[, options]); * - * console.log(mm.capture('test/*.js', 'test/foo.js')); - * //=> ['foo'] - * console.log(mm.capture('test/*.js', 'foo/bar.css')); - * //=> null + * const result = picomatch.scan('!./foo/*.js'); + * console.log(result); + * { prefix: '!./', + * input: '!./foo/*.js', + * start: 3, + * base: 'foo', + * glob: '*.js', + * isBrace: false, + * isBracket: false, + * isGlob: true, + * isExtglob: false, + * isGlobstar: false, + * negated: true } * ``` - * @param {String} `glob` Glob pattern to use for matching. - * @param {String} `input` 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 input matches the glob pattern, otherwise `null`. + * @param {String} `input` Glob pattern to scan. + * @param {Object} `options` + * @return {Object} Returns an object with * @api public */ -micromatch.capture = (glob, input, options) => { - let posix = utils.isWindows(options); - let regex = picomatch.makeRe(String(glob), { ...options, capture: true }); - let match = regex.exec(posix ? utils.toPosixSlashes(input) : input); - - if (match) { - return match.slice(1).map(v => v === void 0 ? '' : v); - } -}; +picomatch.scan = (input, options) => scan(input, options); /** - * Create a regular expression from the given glob `pattern`. + * Create a regular expression from a parsed glob pattern. * * ```js - * const mm = require('micromatch'); - * // mm.makeRe(pattern[, options]); + * const picomatch = require('picomatch'); + * const state = picomatch.parse('*.js'); + * // picomatch.compileRe(state[, options]); * - * console.log(mm.makeRe('*.js')); - * //=> /^(?:(\.[\\\/])?(?!\.)(?=.)[^\/]*?\.js)$/ + * console.log(picomatch.compileRe(state)); + * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/ * ``` - * @param {String} `pattern` A glob pattern to convert to regex. + * @param {String} `state` The object returned from the `.parse` method. * @param {Object} `options` * @return {RegExp} Returns a regex created from the given pattern. * @api public */ -micromatch.makeRe = (...args) => picomatch.makeRe(...args); +picomatch.compileRe = (parsed, options, returnOutput = false, returnState = false) => { + if (returnOutput === true) { + return parsed.output; + } -/** - * Scan a glob pattern to separate the pattern into segments. Used - * by the [split](#split) method. - * - * ```js - * const mm = require('micromatch'); - * const state = mm.scan(pattern[, options]); - * ``` - * @param {String} `pattern` - * @param {Object} `options` - * @return {Object} Returns an object with - * @api public - */ + const opts = options || {}; + const prepend = opts.contains ? '' : '^'; + const append = opts.contains ? '' : '$'; -micromatch.scan = (...args) => picomatch.scan(...args); + let source = `${prepend}(?:${parsed.output})${append}`; + if (parsed && parsed.negated === true) { + source = `^(?!${source}).*$`; + } -/** - * Parse a glob pattern to create the source string for a regular - * expression. - * - * ```js - * const mm = require('micromatch'); - * const state = mm(pattern[, options]); - * ``` - * @param {String} `glob` - * @param {Object} `options` - * @return {Object} Returns an object with useful properties and output to be used as regex source string. - * @api public - */ + const regex = picomatch.toRegex(source, options); + if (returnState === true) { + regex.state = parsed; + } -micromatch.parse = (patterns, options) => { - let res = []; - for (let pattern of [].concat(patterns || [])) { - for (let str of braces(String(pattern), options)) { - res.push(picomatch.parse(str, options)); - } + return regex; +}; + +picomatch.makeRe = (input, options, returnOutput = false, returnState = false) => { + if (!input || typeof input !== 'string') { + throw new TypeError('Expected a non-empty string'); } - return res; + + const opts = options || {}; + let parsed = { negated: false, fastpaths: true }; + let prefix = ''; + let output; + + if (input.startsWith('./')) { + input = input.slice(2); + prefix = parsed.prefix = './'; + } + + if (opts.fastpaths !== false && (input[0] === '.' || input[0] === '*')) { + output = parse.fastpaths(input, options); + } + + if (output === undefined) { + parsed = parse(input, options); + parsed.prefix = prefix + (parsed.prefix || ''); + } else { + parsed.output = output; + } + + return picomatch.compileRe(parsed, options, returnOutput, returnState); }; /** - * Process the given brace `pattern`. + * Create a regular expression from the given regex source string. * * ```js - * const { braces } = require('micromatch'); - * console.log(braces('foo/{a,b,c}/bar')); - * //=> [ 'foo/(a|b|c)/bar' ] + * const picomatch = require('picomatch'); + * // picomatch.toRegex(source[, options]); * - * console.log(braces('foo/{a,b,c}/bar', { expand: true })); - * //=> [ 'foo/a/bar', 'foo/b/bar', 'foo/c/bar' ] + * const { output } = picomatch.parse('*.js'); + * console.log(picomatch.toRegex(output)); + * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/ * ``` - * @param {String} `pattern` String with brace pattern to process. - * @param {Object} `options` Any [options](#options) to change how expansion is performed. See the [braces][] library for all available options. - * @return {Array} + * @param {String} `source` Regular expression source string. + * @param {Object} `options` + * @return {RegExp} * @api public */ -micromatch.braces = (pattern, options) => { - if (typeof pattern !== 'string') throw new TypeError('Expected a string'); - if ((options && options.nobrace === true) || !/\{.*\}/.test(pattern)) { - return [pattern]; +picomatch.toRegex = (source, options) => { + try { + const opts = options || {}; + return new RegExp(source, opts.flags || (opts.nocase ? 'i' : '')); + } catch (err) { + if (options && options.debug === true) throw err; + return /$^/; } - return braces(pattern, options); }; /** - * Expand braces + * Picomatch constants. + * @return {Object} */ -micromatch.braceExpand = (pattern, options) => { - if (typeof pattern !== 'string') throw new TypeError('Expected a string'); - return micromatch.braces(pattern, { ...options, expand: true }); -}; +picomatch.constants = constants; /** - * Expose micromatch + * Expose "picomatch" */ -module.exports = micromatch; +module.exports = picomatch; /***/ }), -/* 317 */ +/* 324 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const stringify = __webpack_require__(318); -const compile = __webpack_require__(320); -const expand = __webpack_require__(324); -const parse = __webpack_require__(325); - -/** - * Expand the given pattern or create a regex-compatible string. - * - * ```js - * const braces = require('braces'); - * console.log(braces('{a,b,c}', { compile: true })); //=> ['(a|b|c)'] - * console.log(braces('{a,b,c}')); //=> ['a', 'b', 'c'] - * ``` - * @param {String} `str` - * @param {Object} `options` - * @return {String} - * @api public - */ - -const braces = (input, options = {}) => { - let output = []; - - if (Array.isArray(input)) { - for (let pattern of input) { - let result = braces.create(pattern, options); - if (Array.isArray(result)) { - output.push(...result); - } else { - output.push(result); - } - } - } else { - output = [].concat(braces.create(input, options)); - } +const utils = __webpack_require__(325); +const { + CHAR_ASTERISK, /* * */ + CHAR_AT, /* @ */ + CHAR_BACKWARD_SLASH, /* \ */ + CHAR_COMMA, /* , */ + CHAR_DOT, /* . */ + CHAR_EXCLAMATION_MARK, /* ! */ + CHAR_FORWARD_SLASH, /* / */ + CHAR_LEFT_CURLY_BRACE, /* { */ + CHAR_LEFT_PARENTHESES, /* ( */ + CHAR_LEFT_SQUARE_BRACKET, /* [ */ + CHAR_PLUS, /* + */ + CHAR_QUESTION_MARK, /* ? */ + CHAR_RIGHT_CURLY_BRACE, /* } */ + CHAR_RIGHT_PARENTHESES, /* ) */ + CHAR_RIGHT_SQUARE_BRACKET /* ] */ +} = __webpack_require__(326); - if (options && options.expand === true && options.nodupes === true) { - output = [...new Set(output)]; - } - return output; +const isPathSeparator = code => { + return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; }; -/** - * Parse the given `str` with the given `options`. - * - * ```js - * // braces.parse(pattern, [, options]); - * const ast = braces.parse('a/{b,c}/d'); - * console.log(ast); - * ``` - * @param {String} pattern Brace pattern to parse - * @param {Object} options - * @return {Object} Returns an AST - * @api public - */ - -braces.parse = (input, options = {}) => parse(input, options); - -/** - * Creates a braces string from an AST, or an AST node. - * - * ```js - * const braces = require('braces'); - * let ast = braces.parse('foo/{a,b}/bar'); - * console.log(stringify(ast.nodes[2])); //=> '{a,b}' - * ``` - * @param {String} `input` Brace pattern or AST. - * @param {Object} `options` - * @return {Array} Returns an array of expanded values. - * @api public - */ - -braces.stringify = (input, options = {}) => { - if (typeof input === 'string') { - return stringify(braces.parse(input, options), options); +const depth = token => { + if (token.isPrefix !== true) { + token.depth = token.isGlobstar ? Infinity : 1; } - return stringify(input, options); }; /** - * Compiles a brace pattern into a regex-compatible, optimized string. - * This method is called by the main [braces](#braces) function by default. + * Quickly scans a glob pattern and returns an object with a handful of + * useful properties, like `isGlob`, `path` (the leading non-glob, if it exists), + * `glob` (the actual pattern), and `negated` (true if the path starts with `!`). * * ```js - * const braces = require('braces'); - * console.log(braces.compile('a/{b,c}/d')); - * //=> ['a/(b|c)/d'] + * const pm = require('picomatch'); + * console.log(pm.scan('foo/bar/*.js')); + * { isGlob: true, input: 'foo/bar/*.js', base: 'foo/bar', glob: '*.js' } * ``` - * @param {String} `input` Brace pattern or AST. + * @param {String} `str` * @param {Object} `options` - * @return {Array} Returns an array of expanded values. + * @return {Object} Returns an object with tokens and regex source string. * @api public */ -braces.compile = (input, options = {}) => { - if (typeof input === 'string') { - input = braces.parse(input, options); - } - return compile(input, options); -}; +const scan = (input, options) => { + const opts = options || {}; -/** - * 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 [.compile](#compile) instead. - * - * ```js - * const 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 - */ + const length = input.length - 1; + const scanToEnd = opts.parts === true || opts.scanToEnd === true; + const slashes = []; + const tokens = []; + const parts = []; -braces.expand = (input, options = {}) => { - if (typeof input === 'string') { - input = braces.parse(input, options); - } + let str = input; + let index = -1; + let start = 0; + let lastIndex = 0; + let isBrace = false; + let isBracket = false; + let isGlob = false; + let isExtglob = false; + let isGlobstar = false; + let braceEscaped = false; + let backslashes = false; + let negated = false; + let finished = false; + let braces = 0; + let prev; + let code; + let token = { value: '', depth: 0, isGlob: false }; - let result = expand(input, options); + const eos = () => index >= length; + const peek = () => str.charCodeAt(index + 1); + const advance = () => { + prev = code; + return str.charCodeAt(++index); + }; - // filter out empty strings if specified - if (options.noempty === true) { - result = result.filter(Boolean); - } + while (index < length) { + code = advance(); + let next; - // filter out duplicates if specified - if (options.nodupes === true) { - result = [...new Set(result)]; - } + if (code === CHAR_BACKWARD_SLASH) { + backslashes = token.backslashes = true; + code = advance(); - return result; -}; + if (code === CHAR_LEFT_CURLY_BRACE) { + braceEscaped = true; + } + continue; + } -/** - * 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 - * const 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 - */ + if (braceEscaped === true || code === CHAR_LEFT_CURLY_BRACE) { + braces++; -braces.create = (input, options = {}) => { - if (input === '' || input.length < 3) { - return [input]; - } + while (eos() !== true && (code = advance())) { + if (code === CHAR_BACKWARD_SLASH) { + backslashes = token.backslashes = true; + advance(); + continue; + } - return options.expand !== true - ? braces.compile(input, options) - : braces.expand(input, options); -}; + if (code === CHAR_LEFT_CURLY_BRACE) { + braces++; + continue; + } -/** - * Expose "braces" - */ + if (braceEscaped !== true && code === CHAR_DOT && (code = advance()) === CHAR_DOT) { + isBrace = token.isBrace = true; + isGlob = token.isGlob = true; + finished = true; -module.exports = braces; + if (scanToEnd === true) { + continue; + } + break; + } -/***/ }), -/* 318 */ -/***/ (function(module, exports, __webpack_require__) { + if (braceEscaped !== true && code === CHAR_COMMA) { + isBrace = token.isBrace = true; + isGlob = token.isGlob = true; + finished = true; -"use strict"; + if (scanToEnd === true) { + continue; + } + break; + } -const utils = __webpack_require__(319); + if (code === CHAR_RIGHT_CURLY_BRACE) { + braces--; -module.exports = (ast, options = {}) => { - let stringify = (node, parent = {}) => { - let invalidBlock = options.escapeInvalid && utils.isInvalidBrace(parent); - let invalidNode = node.invalid === true && options.escapeInvalid === true; - let output = ''; + if (braces === 0) { + braceEscaped = false; + isBrace = token.isBrace = true; + finished = true; + break; + } + } + } - if (node.value) { - if ((invalidBlock || invalidNode) && utils.isOpenOrClose(node)) { - return '\\' + node.value; + if (scanToEnd === true) { + continue; } - return node.value; - } - if (node.value) { - return node.value; + break; } - if (node.nodes) { - for (let child of node.nodes) { - output += stringify(child); + if (code === CHAR_FORWARD_SLASH) { + slashes.push(index); + tokens.push(token); + token = { value: '', depth: 0, isGlob: false }; + + if (finished === true) continue; + if (prev === CHAR_DOT && index === (start + 1)) { + start += 2; + continue; } - } - return output; - }; - return stringify(ast); -}; + lastIndex = index + 1; + continue; + } + if (opts.noext !== true) { + const isExtglobChar = code === CHAR_PLUS + || code === CHAR_AT + || code === CHAR_ASTERISK + || code === CHAR_QUESTION_MARK + || code === CHAR_EXCLAMATION_MARK; + if (isExtglobChar === true && peek() === CHAR_LEFT_PARENTHESES) { + isGlob = token.isGlob = true; + isExtglob = token.isExtglob = true; + finished = true; -/***/ }), -/* 319 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -exports.isInteger = num => { - if (typeof num === 'number') { - return Number.isInteger(num); - } - if (typeof num === 'string' && num.trim() !== '') { - return Number.isInteger(Number(num)); - } - return false; -}; - -/** - * Find a node of the given type - */ - -exports.find = (node, type) => node.nodes.find(node => node.type === type); + if (scanToEnd === true) { + while (eos() !== true && (code = advance())) { + if (code === CHAR_BACKWARD_SLASH) { + backslashes = token.backslashes = true; + code = advance(); + continue; + } -/** - * Find a node of the given type - */ + if (code === CHAR_RIGHT_PARENTHESES) { + isGlob = token.isGlob = true; + finished = true; + break; + } + } + continue; + } + break; + } + } -exports.exceedsLimit = (min, max, step = 1, limit) => { - if (limit === false) return false; - if (!exports.isInteger(min) || !exports.isInteger(max)) return false; - return ((Number(max) - Number(min)) / Number(step)) >= limit; -}; + if (code === CHAR_ASTERISK) { + if (prev === CHAR_ASTERISK) isGlobstar = token.isGlobstar = true; + isGlob = token.isGlob = true; + finished = true; -/** - * Escape the given node with '\\' before node.value - */ + if (scanToEnd === true) { + continue; + } + break; + } -exports.escapeNode = (block, n = 0, type) => { - let node = block.nodes[n]; - if (!node) return; + if (code === CHAR_QUESTION_MARK) { + isGlob = token.isGlob = true; + finished = true; - if ((type && node.type === type) || node.type === 'open' || node.type === 'close') { - if (node.escaped !== true) { - node.value = '\\' + node.value; - node.escaped = true; + if (scanToEnd === true) { + continue; + } + break; } - } -}; -/** - * Returns true if the given brace node should be enclosed in literal braces - */ + if (code === CHAR_LEFT_SQUARE_BRACKET) { + while (eos() !== true && (next = advance())) { + if (next === CHAR_BACKWARD_SLASH) { + backslashes = token.backslashes = true; + advance(); + continue; + } -exports.encloseBrace = node => { - if (node.type !== 'brace') return false; - if ((node.commas >> 0 + node.ranges >> 0) === 0) { - node.invalid = true; - return true; - } - return false; -}; + if (next === CHAR_RIGHT_SQUARE_BRACKET) { + isBracket = token.isBracket = true; + isGlob = token.isGlob = true; + finished = true; -/** - * Returns true if a brace node is invalid. - */ + if (scanToEnd === true) { + continue; + } + break; + } + } + } -exports.isInvalidBrace = block => { - if (block.type !== 'brace') return false; - if (block.invalid === true || block.dollar) return true; - if ((block.commas >> 0 + block.ranges >> 0) === 0) { - block.invalid = true; - return true; - } - if (block.open !== true || block.close !== true) { - block.invalid = true; - return true; - } - return false; -}; + if (opts.nonegate !== true && code === CHAR_EXCLAMATION_MARK && index === start) { + negated = token.negated = true; + start++; + continue; + } -/** - * Returns true if a node is an open or close node - */ + if (opts.noparen !== true && code === CHAR_LEFT_PARENTHESES) { + isGlob = token.isGlob = true; -exports.isOpenOrClose = node => { - if (node.type === 'open' || node.type === 'close') { - return true; - } - return node.open === true || node.close === true; -}; + if (scanToEnd === true) { + while (eos() !== true && (code = advance())) { + if (code === CHAR_LEFT_PARENTHESES) { + backslashes = token.backslashes = true; + code = advance(); + continue; + } -/** - * Reduce an array of text nodes. - */ + if (code === CHAR_RIGHT_PARENTHESES) { + finished = true; + break; + } + } + continue; + } + break; + } -exports.reduce = nodes => nodes.reduce((acc, node) => { - if (node.type === 'text') acc.push(node.value); - if (node.type === 'range') node.type = 'text'; - return acc; -}, []); + if (isGlob === true) { + finished = true; -/** - * Flatten an array - */ + if (scanToEnd === true) { + continue; + } -exports.flatten = (...args) => { - const result = []; - const flat = arr => { - for (let i = 0; i < arr.length; i++) { - let ele = arr[i]; - Array.isArray(ele) ? flat(ele, result) : ele !== void 0 && result.push(ele); + break; } - return result; - }; - flat(args); - return result; -}; - - -/***/ }), -/* 320 */ -/***/ (function(module, exports, __webpack_require__) { + } -"use strict"; + if (opts.noext === true) { + isExtglob = false; + isGlob = false; + } + let base = str; + let prefix = ''; + let glob = ''; -const fill = __webpack_require__(321); -const utils = __webpack_require__(319); + if (start > 0) { + prefix = str.slice(0, start); + str = str.slice(start); + lastIndex -= start; + } -const compile = (ast, options = {}) => { - let walk = (node, parent = {}) => { - let invalidBlock = utils.isInvalidBrace(parent); - let invalidNode = node.invalid === true && options.escapeInvalid === true; - let invalid = invalidBlock === true || invalidNode === true; - let prefix = options.escapeInvalid === true ? '\\' : ''; - let output = ''; + if (base && isGlob === true && lastIndex > 0) { + base = str.slice(0, lastIndex); + glob = str.slice(lastIndex); + } else if (isGlob === true) { + base = ''; + glob = str; + } else { + base = str; + } - if (node.isOpen === true) { - return prefix + node.value; - } - if (node.isClose === true) { - return prefix + node.value; + if (base && base !== '' && base !== '/' && base !== str) { + if (isPathSeparator(base.charCodeAt(base.length - 1))) { + base = base.slice(0, -1); } + } - if (node.type === 'open') { - return invalid ? (prefix + node.value) : '('; - } + if (opts.unescape === true) { + if (glob) glob = utils.removeBackslashes(glob); - if (node.type === 'close') { - return invalid ? (prefix + node.value) : ')'; + if (base && backslashes === true) { + base = utils.removeBackslashes(base); } + } - if (node.type === 'comma') { - return node.prev.type === 'comma' ? '' : (invalid ? node.value : '|'); - } + const state = { + prefix, + input, + start, + base, + glob, + isBrace, + isBracket, + isGlob, + isExtglob, + isGlobstar, + negated + }; - if (node.value) { - return node.value; + if (opts.tokens === true) { + state.maxDepth = 0; + if (!isPathSeparator(code)) { + tokens.push(token); } + state.tokens = tokens; + } - if (node.nodes && node.ranges > 0) { - let args = utils.reduce(node.nodes); - let range = fill(...args, { ...options, wrap: false, toRegex: true }); + if (opts.parts === true || opts.tokens === true) { + let prevIndex; - if (range.length !== 0) { - return args.length > 1 && range.length > 1 ? `(${range})` : range; + for (let idx = 0; idx < slashes.length; idx++) { + const n = prevIndex ? prevIndex + 1 : start; + const i = slashes[idx]; + const value = input.slice(n, i); + if (opts.tokens) { + if (idx === 0 && start !== 0) { + tokens[idx].isPrefix = true; + tokens[idx].value = prefix; + } else { + tokens[idx].value = value; + } + depth(tokens[idx]); + state.maxDepth += tokens[idx].depth; } + if (idx !== 0 || value !== '') { + parts.push(value); + } + prevIndex = i; } - if (node.nodes) { - for (let child of node.nodes) { - output += walk(child, node); + if (prevIndex && prevIndex + 1 < input.length) { + const value = input.slice(prevIndex + 1); + parts.push(value); + + if (opts.tokens) { + tokens[tokens.length - 1].value = value; + depth(tokens[tokens.length - 1]); + state.maxDepth += tokens[tokens.length - 1].depth; } } - return output; - }; - return walk(ast); + state.slashes = slashes; + state.parts = parts; + } + + return state; }; -module.exports = compile; +module.exports = scan; /***/ }), -/* 321 */ +/* 325 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -/*! - * fill-range - * - * Copyright (c) 2014-present, Jon Schlinkert. - * Licensed under the MIT License. - */ - - - -const util = __webpack_require__(111); -const toRegexRange = __webpack_require__(322); - -const isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); -const transform = toNumber => { - return value => toNumber === true ? Number(value) : String(value); -}; -const isValidValue = value => { - return typeof value === 'number' || (typeof value === 'string' && value !== ''); -}; +const path = __webpack_require__(4); +const win32 = process.platform === 'win32'; +const { + REGEX_BACKSLASH, + REGEX_REMOVE_BACKSLASH, + REGEX_SPECIAL_CHARS, + REGEX_SPECIAL_CHARS_GLOBAL +} = __webpack_require__(326); -const isNumber = num => Number.isInteger(+num); +exports.isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); +exports.hasRegexChars = str => REGEX_SPECIAL_CHARS.test(str); +exports.isRegexChar = str => str.length === 1 && exports.hasRegexChars(str); +exports.escapeRegex = str => str.replace(REGEX_SPECIAL_CHARS_GLOBAL, '\\$1'); +exports.toPosixSlashes = str => str.replace(REGEX_BACKSLASH, '/'); -const zeros = input => { - let value = `${input}`; - let index = -1; - if (value[0] === '-') value = value.slice(1); - if (value === '0') return false; - while (value[++index] === '0'); - return index > 0; +exports.removeBackslashes = str => { + return str.replace(REGEX_REMOVE_BACKSLASH, match => { + return match === '\\' ? '' : match; + }); }; -const stringify = (start, end, options) => { - if (typeof start === 'string' || typeof end === 'string') { +exports.supportsLookbehinds = () => { + const segs = process.version.slice(1).split('.').map(Number); + if (segs.length === 3 && segs[0] >= 9 || (segs[0] === 8 && segs[1] >= 10)) { return true; } - return options.stringify === true; + return false; }; -const pad = (input, maxLength, toNumber) => { - if (maxLength > 0) { - let dash = input[0] === '-' ? '-' : ''; - if (dash) input = input.slice(1); - input = (dash + input.padStart(dash ? maxLength - 1 : maxLength, '0')); - } - if (toNumber === false) { - return String(input); +exports.isWindows = options => { + if (options && typeof options.windows === 'boolean') { + return options.windows; } - return input; + return win32 === true || path.sep === '\\'; }; -const toMaxLen = (input, maxLength) => { - let negative = input[0] === '-' ? '-' : ''; - if (negative) { - input = input.slice(1); - maxLength--; - } - while (input.length < maxLength) input = '0' + input; - return negative ? ('-' + input) : input; +exports.escapeLast = (input, char, lastIdx) => { + const idx = input.lastIndexOf(char, lastIdx); + if (idx === -1) return input; + if (input[idx - 1] === '\\') return exports.escapeLast(input, char, idx - 1); + return `${input.slice(0, idx)}\\${input.slice(idx)}`; }; -const toSequence = (parts, options) => { - parts.negatives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0); - parts.positives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0); +exports.removePrefix = (input, state = {}) => { + let output = input; + if (output.startsWith('./')) { + output = output.slice(2); + state.prefix = './'; + } + return output; +}; - let prefix = options.capture ? '' : '?:'; - let positives = ''; - let negatives = ''; - let result; +exports.wrapOutput = (input, state = {}, options = {}) => { + const prepend = options.contains ? '' : '^'; + const append = options.contains ? '' : '$'; - if (parts.positives.length) { - positives = parts.positives.join('|'); + let output = `${prepend}(?:${input})${append}`; + if (state.negated === true) { + output = `(?:^(?!${output}).*$)`; } + return output; +}; - if (parts.negatives.length) { - negatives = `-(${prefix}${parts.negatives.join('|')})`; - } - if (positives && negatives) { - result = `${positives}|${negatives}`; - } else { - result = positives || negatives; - } +/***/ }), +/* 326 */ +/***/ (function(module, exports, __webpack_require__) { - if (options.wrap) { - return `(${prefix}${result})`; - } +"use strict"; - return result; -}; -const toRange = (a, b, isNumbers, options) => { - if (isNumbers) { - return toRegexRange(a, b, { wrap: false, ...options }); - } +const path = __webpack_require__(4); +const WIN_SLASH = '\\\\/'; +const WIN_NO_SLASH = `[^${WIN_SLASH}]`; - let start = String.fromCharCode(a); - if (a === b) return start; +/** + * Posix glob regex + */ - let stop = String.fromCharCode(b); - return `[${start}-${stop}]`; -}; +const DOT_LITERAL = '\\.'; +const PLUS_LITERAL = '\\+'; +const QMARK_LITERAL = '\\?'; +const SLASH_LITERAL = '\\/'; +const ONE_CHAR = '(?=.)'; +const QMARK = '[^/]'; +const END_ANCHOR = `(?:${SLASH_LITERAL}|$)`; +const START_ANCHOR = `(?:^|${SLASH_LITERAL})`; +const DOTS_SLASH = `${DOT_LITERAL}{1,2}${END_ANCHOR}`; +const NO_DOT = `(?!${DOT_LITERAL})`; +const NO_DOTS = `(?!${START_ANCHOR}${DOTS_SLASH})`; +const NO_DOT_SLASH = `(?!${DOT_LITERAL}{0,1}${END_ANCHOR})`; +const NO_DOTS_SLASH = `(?!${DOTS_SLASH})`; +const QMARK_NO_DOT = `[^.${SLASH_LITERAL}]`; +const STAR = `${QMARK}*?`; -const toRegex = (start, end, options) => { - if (Array.isArray(start)) { - let wrap = options.wrap === true; - let prefix = options.capture ? '' : '?:'; - return wrap ? `(${prefix}${start.join('|')})` : start.join('|'); - } - return toRegexRange(start, end, options); +const POSIX_CHARS = { + DOT_LITERAL, + PLUS_LITERAL, + QMARK_LITERAL, + SLASH_LITERAL, + ONE_CHAR, + QMARK, + END_ANCHOR, + DOTS_SLASH, + NO_DOT, + NO_DOTS, + NO_DOT_SLASH, + NO_DOTS_SLASH, + QMARK_NO_DOT, + STAR, + START_ANCHOR }; -const rangeError = (...args) => { - return new RangeError('Invalid range arguments: ' + util.inspect(...args)); -}; +/** + * Windows glob regex + */ -const invalidRange = (start, end, options) => { - if (options.strictRanges === true) throw rangeError([start, end]); - return []; -}; +const WINDOWS_CHARS = { + ...POSIX_CHARS, -const invalidStep = (step, options) => { - if (options.strictRanges === true) { - throw new TypeError(`Expected step "${step}" to be a number`); - } - return []; + SLASH_LITERAL: `[${WIN_SLASH}]`, + QMARK: WIN_NO_SLASH, + STAR: `${WIN_NO_SLASH}*?`, + DOTS_SLASH: `${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$)`, + NO_DOT: `(?!${DOT_LITERAL})`, + NO_DOTS: `(?!(?:^|[${WIN_SLASH}])${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`, + NO_DOT_SLASH: `(?!${DOT_LITERAL}{0,1}(?:[${WIN_SLASH}]|$))`, + NO_DOTS_SLASH: `(?!${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`, + QMARK_NO_DOT: `[^.${WIN_SLASH}]`, + START_ANCHOR: `(?:^|[${WIN_SLASH}])`, + END_ANCHOR: `(?:[${WIN_SLASH}]|$)` }; -const fillNumbers = (start, end, step = 1, options = {}) => { - let a = Number(start); - let b = Number(end); +/** + * POSIX Bracket Regex + */ - if (!Number.isInteger(a) || !Number.isInteger(b)) { - if (options.strictRanges === true) throw rangeError([start, end]); - return []; - } - - // fix negative zero - if (a === 0) a = 0; - if (b === 0) b = 0; - - let descending = a > b; - let startString = String(start); - let endString = String(end); - let stepString = String(step); - step = Math.max(Math.abs(step), 1); - - let padded = zeros(startString) || zeros(endString) || zeros(stepString); - let maxLen = padded ? Math.max(startString.length, endString.length, stepString.length) : 0; - let toNumber = padded === false && stringify(start, end, options) === false; - let format = options.transform || transform(toNumber); - - if (options.toRegex && step === 1) { - return toRange(toMaxLen(start, maxLen), toMaxLen(end, maxLen), true, options); - } - - let parts = { negatives: [], positives: [] }; - let push = num => parts[num < 0 ? 'negatives' : 'positives'].push(Math.abs(num)); - let range = []; - let index = 0; - - while (descending ? a >= b : a <= b) { - if (options.toRegex === true && step > 1) { - push(a); - } else { - range.push(pad(format(a, index), maxLen, toNumber)); - } - a = descending ? a - step : a + step; - index++; - } - - if (options.toRegex === true) { - return step > 1 - ? toSequence(parts, options) - : toRegex(range, null, { wrap: false, ...options }); - } - - return range; +const POSIX_REGEX_SOURCE = { + 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' }; -const fillLetters = (start, end, step = 1, options = {}) => { - if ((!isNumber(start) && start.length > 1) || (!isNumber(end) && end.length > 1)) { - return invalidRange(start, end, options); - } - - - let format = options.transform || (val => String.fromCharCode(val)); - let a = `${start}`.charCodeAt(0); - let b = `${end}`.charCodeAt(0); - - let descending = a > b; - let min = Math.min(a, b); - let max = Math.max(a, b); +module.exports = { + MAX_LENGTH: 1024 * 64, + POSIX_REGEX_SOURCE, - if (options.toRegex && step === 1) { - return toRange(min, max, false, options); - } + // regular expressions + REGEX_BACKSLASH: /\\(?![*+?^${}(|)[\]])/g, + REGEX_NON_SPECIAL_CHARS: /^[^@![\].,$*+?^{}()|\\/]+/, + REGEX_SPECIAL_CHARS: /[-*+?.^${}(|)[\]]/, + REGEX_SPECIAL_CHARS_BACKREF: /(\\?)((\W)(\3*))/g, + REGEX_SPECIAL_CHARS_GLOBAL: /([-*+?.^${}(|)[\]])/g, + REGEX_REMOVE_BACKSLASH: /(?:\[.*?[^\\]\]|\\(?=.))/g, - let range = []; - let index = 0; + // Replace globs with equivalent patterns to reduce parsing time. + REPLACEMENTS: { + '***': '*', + '**/**': '**', + '**/**/**': '**' + }, - while (descending ? a >= b : a <= b) { - range.push(format(a, index)); - a = descending ? a - step : a + step; - index++; - } + // Digits + CHAR_0: 48, /* 0 */ + CHAR_9: 57, /* 9 */ - if (options.toRegex === true) { - return toRegex(range, null, { wrap: false, options }); - } + // Alphabet chars. + CHAR_UPPERCASE_A: 65, /* A */ + CHAR_LOWERCASE_A: 97, /* a */ + CHAR_UPPERCASE_Z: 90, /* Z */ + CHAR_LOWERCASE_Z: 122, /* z */ - return range; -}; + CHAR_LEFT_PARENTHESES: 40, /* ( */ + CHAR_RIGHT_PARENTHESES: 41, /* ) */ -const fill = (start, end, step, options = {}) => { - if (end == null && isValidValue(start)) { - return [start]; - } + CHAR_ASTERISK: 42, /* * */ - if (!isValidValue(start) || !isValidValue(end)) { - return invalidRange(start, end, options); - } + // Non-alphabetic chars. + CHAR_AMPERSAND: 38, /* & */ + CHAR_AT: 64, /* @ */ + CHAR_BACKWARD_SLASH: 92, /* \ */ + CHAR_CARRIAGE_RETURN: 13, /* \r */ + CHAR_CIRCUMFLEX_ACCENT: 94, /* ^ */ + CHAR_COLON: 58, /* : */ + CHAR_COMMA: 44, /* , */ + CHAR_DOT: 46, /* . */ + CHAR_DOUBLE_QUOTE: 34, /* " */ + CHAR_EQUAL: 61, /* = */ + CHAR_EXCLAMATION_MARK: 33, /* ! */ + CHAR_FORM_FEED: 12, /* \f */ + CHAR_FORWARD_SLASH: 47, /* / */ + CHAR_GRAVE_ACCENT: 96, /* ` */ + CHAR_HASH: 35, /* # */ + CHAR_HYPHEN_MINUS: 45, /* - */ + CHAR_LEFT_ANGLE_BRACKET: 60, /* < */ + CHAR_LEFT_CURLY_BRACE: 123, /* { */ + CHAR_LEFT_SQUARE_BRACKET: 91, /* [ */ + CHAR_LINE_FEED: 10, /* \n */ + CHAR_NO_BREAK_SPACE: 160, /* \u00A0 */ + CHAR_PERCENT: 37, /* % */ + CHAR_PLUS: 43, /* + */ + CHAR_QUESTION_MARK: 63, /* ? */ + CHAR_RIGHT_ANGLE_BRACKET: 62, /* > */ + CHAR_RIGHT_CURLY_BRACE: 125, /* } */ + CHAR_RIGHT_SQUARE_BRACKET: 93, /* ] */ + CHAR_SEMICOLON: 59, /* ; */ + CHAR_SINGLE_QUOTE: 39, /* ' */ + CHAR_SPACE: 32, /* */ + CHAR_TAB: 9, /* \t */ + CHAR_UNDERSCORE: 95, /* _ */ + CHAR_VERTICAL_LINE: 124, /* | */ + CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279, /* \uFEFF */ - if (typeof step === 'function') { - return fill(start, end, 1, { transform: step }); - } + SEP: path.sep, - if (isObject(step)) { - return fill(start, end, 0, step); - } + /** + * Create EXTGLOB_CHARS + */ - let opts = { ...options }; - if (opts.capture === true) opts.wrap = true; - step = step || opts.step || 1; + extglobChars(chars) { + return { + '!': { type: 'negate', open: '(?:(?!(?:', close: `))${chars.STAR})` }, + '?': { type: 'qmark', open: '(?:', close: ')?' }, + '+': { type: 'plus', open: '(?:', close: ')+' }, + '*': { type: 'star', open: '(?:', close: ')*' }, + '@': { type: 'at', open: '(?:', close: ')' } + }; + }, - if (!isNumber(step)) { - if (step != null && !isObject(step)) return invalidStep(step, opts); - return fill(start, end, 1, step); - } + /** + * Create GLOB_CHARS + */ - if (isNumber(start) && isNumber(end)) { - return fillNumbers(start, end, step, opts); + globChars(win32) { + return win32 === true ? WINDOWS_CHARS : POSIX_CHARS; } - - return fillLetters(start, end, Math.max(Math.abs(step), 1), opts); }; -module.exports = fill; - /***/ }), -/* 322 */ +/* 327 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -/*! - * to-regex-range - * - * Copyright (c) 2015-present, Jon Schlinkert. - * Released under the MIT License. - */ - -const isNumber = __webpack_require__(323); +const constants = __webpack_require__(326); +const utils = __webpack_require__(325); -const toRegexRange = (min, max, options) => { - if (isNumber(min) === false) { - throw new TypeError('toRegexRange: expected the first argument to be a number'); - } +/** + * Constants + */ - if (max === void 0 || min === max) { - return String(min); - } +const { + MAX_LENGTH, + POSIX_REGEX_SOURCE, + REGEX_NON_SPECIAL_CHARS, + REGEX_SPECIAL_CHARS_BACKREF, + REPLACEMENTS +} = constants; - if (isNumber(max) === false) { - throw new TypeError('toRegexRange: expected the second argument to be a number.'); - } +/** + * Helpers + */ - let opts = { relaxZeros: true, ...options }; - if (typeof opts.strictZeros === 'boolean') { - opts.relaxZeros = opts.strictZeros === false; +const expandRange = (args, options) => { + if (typeof options.expandRange === 'function') { + return options.expandRange(...args, options); } - let relax = String(opts.relaxZeros); - let shorthand = String(opts.shorthand); - let capture = String(opts.capture); - let wrap = String(opts.wrap); - let cacheKey = min + ':' + max + '=' + relax + shorthand + capture + wrap; + args.sort(); + const value = `[${args.join('-')}]`; - if (toRegexRange.cache.hasOwnProperty(cacheKey)) { - return toRegexRange.cache[cacheKey].result; + try { + /* eslint-disable-next-line no-new */ + new RegExp(value); + } catch (ex) { + return args.map(v => utils.escapeRegex(v)).join('..'); } - let a = Math.min(min, max); - let b = Math.max(min, max); + return value; +}; - if (Math.abs(a - b) === 1) { - let result = min + '|' + max; - if (opts.capture) { - return `(${result})`; - } - if (opts.wrap === false) { - return result; - } - return `(?:${result})`; - } +/** + * Create the message for a syntax error + */ - let isPadded = hasPadding(min) || hasPadding(max); - let state = { min, max, a, b }; - let positives = []; - let negatives = []; +const syntaxError = (type, char) => { + return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`; +}; - if (isPadded) { - state.isPadded = isPadded; - state.maxLen = String(state.max).length; - } +/** + * Parse the given input string. + * @param {String} input + * @param {Object} options + * @return {Object} + */ - if (a < 0) { - let newMin = b < 0 ? Math.abs(b) : 1; - negatives = splitToPatterns(newMin, Math.abs(a), state, opts); - a = state.a = 0; +const parse = (input, options) => { + if (typeof input !== 'string') { + throw new TypeError('Expected a string'); } - if (b >= 0) { - positives = splitToPatterns(a, b, state, opts); - } + input = REPLACEMENTS[input] || input; - state.negatives = negatives; - state.positives = positives; - state.result = collatePatterns(negatives, positives, opts); + const opts = { ...options }; + const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; - if (opts.capture === true) { - state.result = `(${state.result})`; - } else if (opts.wrap !== false && (positives.length + negatives.length) > 1) { - state.result = `(?:${state.result})`; + let len = input.length; + if (len > max) { + throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`); } - toRegexRange.cache[cacheKey] = state; - return state.result; -}; + const bos = { type: 'bos', value: '', output: opts.prepend || '' }; + const tokens = [bos]; -function collatePatterns(neg, pos, options) { - let onlyNegative = filterPatterns(neg, pos, '-', false, options) || []; - let onlyPositive = filterPatterns(pos, neg, '', false, options) || []; - let intersected = filterPatterns(neg, pos, '-?', true, options) || []; - let subpatterns = onlyNegative.concat(intersected).concat(onlyPositive); - return subpatterns.join('|'); -} + const capture = opts.capture ? '' : '?:'; + const win32 = utils.isWindows(options); -function splitToRanges(min, max) { - let nines = 1; - let zeros = 1; + // create constants based on platform, for windows or posix + const PLATFORM_CHARS = constants.globChars(win32); + const EXTGLOB_CHARS = constants.extglobChars(PLATFORM_CHARS); - let stop = countNines(min, nines); - let stops = new Set([max]); + const { + DOT_LITERAL, + PLUS_LITERAL, + SLASH_LITERAL, + ONE_CHAR, + DOTS_SLASH, + NO_DOT, + NO_DOT_SLASH, + NO_DOTS_SLASH, + QMARK, + QMARK_NO_DOT, + STAR, + START_ANCHOR + } = PLATFORM_CHARS; - while (min <= stop && stop <= max) { - stops.add(stop); - nines += 1; - stop = countNines(min, nines); - } + const globstar = (opts) => { + return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`; + }; - stop = countZeros(max + 1, zeros) - 1; + const nodot = opts.dot ? '' : NO_DOT; + const qmarkNoDot = opts.dot ? QMARK : QMARK_NO_DOT; + let star = opts.bash === true ? globstar(opts) : STAR; - while (min < stop && stop <= max) { - stops.add(stop); - zeros += 1; - stop = countZeros(max + 1, zeros) - 1; + if (opts.capture) { + star = `(${star})`; } - stops = [...stops]; - stops.sort(compare); - return stops; -} + // minimatch options support + if (typeof opts.noext === 'boolean') { + opts.noextglob = opts.noext; + } -/** - * Convert a range to a regex pattern - * @param {Number} `start` - * @param {Number} `stop` - * @return {String} - */ + const state = { + input, + index: -1, + start: 0, + dot: opts.dot === true, + consumed: '', + output: '', + prefix: '', + backtrack: false, + negated: false, + brackets: 0, + braces: 0, + parens: 0, + quotes: 0, + globstar: false, + tokens + }; -function rangeToPattern(start, stop, options) { - if (start === stop) { - return { pattern: start, count: [], digits: 0 }; - } + input = utils.removePrefix(input, state); + len = input.length; - let zipped = zip(start, stop); - let digits = zipped.length; - let pattern = ''; - let count = 0; + const extglobs = []; + const braces = []; + const stack = []; + let prev = bos; + let value; - for (let i = 0; i < digits; i++) { - let [startDigit, stopDigit] = zipped[i]; + /** + * Tokenizing helpers + */ - if (startDigit === stopDigit) { - pattern += startDigit; + const eos = () => state.index === len - 1; + const peek = state.peek = (n = 1) => input[state.index + n]; + const advance = state.advance = () => input[++state.index]; + const remaining = () => input.slice(state.index + 1); + const consume = (value = '', num = 0) => { + state.consumed += value; + state.index += num; + }; + const append = token => { + state.output += token.output != null ? token.output : token.value; + consume(token.value); + }; - } else if (startDigit !== '0' || stopDigit !== '9') { - pattern += toCharacterClass(startDigit, stopDigit, options); + const negate = () => { + let count = 1; - } else { + while (peek() === '!' && (peek(2) !== '(' || peek(3) === '?')) { + advance(); + state.start++; count++; } - } - if (count) { - pattern += options.shorthand === true ? '\\d' : '[0-9]'; - } + if (count % 2 === 0) { + return false; + } - return { pattern, count: [count], digits }; -} + state.negated = true; + state.start++; + return true; + }; -function splitToPatterns(min, max, tok, options) { - let ranges = splitToRanges(min, max); - let tokens = []; - let start = min; - let prev; + const increment = type => { + state[type]++; + stack.push(type); + }; - for (let i = 0; i < ranges.length; i++) { - let max = ranges[i]; - let obj = rangeToPattern(String(start), String(max), options); - let zeros = ''; + const decrement = type => { + state[type]--; + stack.pop(); + }; - if (!tok.isPadded && prev && prev.pattern === obj.pattern) { - if (prev.count.length > 1) { - prev.count.pop(); + /** + * Push tokens onto the tokens array. This helper speeds up + * tokenizing by 1) helping us avoid backtracking as much as possible, + * and 2) helping us avoid creating extra tokens when consecutive + * characters are plain text. This improves performance and simplifies + * lookbehinds. + */ + + const push = tok => { + if (prev.type === 'globstar') { + const isBrace = state.braces > 0 && (tok.type === 'comma' || tok.type === 'brace'); + const isExtglob = tok.extglob === true || (extglobs.length && (tok.type === 'pipe' || tok.type === 'paren')); + + if (tok.type !== 'slash' && tok.type !== 'paren' && !isBrace && !isExtglob) { + state.output = state.output.slice(0, -prev.output.length); + prev.type = 'star'; + prev.value = '*'; + prev.output = star; + state.output += prev.output; } + } - prev.count.push(obj.count[0]); - prev.string = prev.pattern + toQuantifier(prev.count); - start = max + 1; - continue; + if (extglobs.length && tok.type !== 'paren' && !EXTGLOB_CHARS[tok.value]) { + extglobs[extglobs.length - 1].inner += tok.value; } - if (tok.isPadded) { - zeros = padZeros(max, tok, options); + if (tok.value || tok.output) append(tok); + if (prev && prev.type === 'text' && tok.type === 'text') { + prev.value += tok.value; + prev.output = (prev.output || '') + tok.value; + return; } - obj.string = zeros + obj.pattern + toQuantifier(obj.count); - tokens.push(obj); - start = max + 1; - prev = obj; - } + tok.prev = prev; + tokens.push(tok); + prev = tok; + }; - return tokens; -} + const extglobOpen = (type, value) => { + const token = { ...EXTGLOB_CHARS[value], conditions: 1, inner: '' }; -function filterPatterns(arr, comparison, prefix, intersection, options) { - let result = []; + token.prev = prev; + token.parens = state.parens; + token.output = state.output; + const output = (opts.capture ? '(' : '') + token.open; - for (let ele of arr) { - let { string } = ele; - - // only push if _both_ are negative... - if (!intersection && !contains(comparison, 'string', string)) { - result.push(prefix + string); - } - - // or _both_ are positive - if (intersection && contains(comparison, 'string', string)) { - result.push(prefix + string); - } - } - return result; -} - -/** - * Zip strings - */ - -function zip(a, b) { - let arr = []; - for (let i = 0; i < a.length; i++) arr.push([a[i], b[i]]); - return arr; -} - -function compare(a, b) { - return a > b ? 1 : b > a ? -1 : 0; -} - -function contains(arr, key, val) { - return arr.some(ele => ele[key] === val); -} - -function countNines(min, len) { - return Number(String(min).slice(0, -len) + '9'.repeat(len)); -} - -function countZeros(integer, zeros) { - return integer - (integer % Math.pow(10, zeros)); -} - -function toQuantifier(digits) { - let [start = 0, stop = ''] = digits; - if (stop || start > 1) { - return `{${start + (stop ? ',' + stop : '')}}`; - } - return ''; -} + increment('parens'); + push({ type, value, output: state.output ? '' : ONE_CHAR }); + push({ type: 'paren', extglob: true, value: advance(), output }); + extglobs.push(token); + }; -function toCharacterClass(a, b, options) { - return `[${a}${(b - a === 1) ? '' : '-'}${b}]`; -} + const extglobClose = token => { + let output = token.close + (opts.capture ? ')' : ''); -function hasPadding(str) { - return /^-?(0+)\d/.test(str); -} + if (token.type === 'negate') { + let extglobStar = star; -function padZeros(value, tok, options) { - if (!tok.isPadded) { - return value; - } + if (token.inner && token.inner.length > 1 && token.inner.includes('/')) { + extglobStar = globstar(opts); + } - let diff = Math.abs(tok.maxLen - String(value).length); - let relax = options.relaxZeros !== false; + if (extglobStar !== star || eos() || /^\)+$/.test(remaining())) { + output = token.close = `)$))${extglobStar}`; + } - switch (diff) { - case 0: - return ''; - case 1: - return relax ? '0?' : '0'; - case 2: - return relax ? '0{0,2}' : '00'; - default: { - return relax ? `0{0,${diff}}` : `0{${diff}}`; + if (token.prev.type === 'bos' && eos()) { + state.negatedExtglob = true; + } } - } -} - -/** - * Cache - */ - -toRegexRange.cache = {}; -toRegexRange.clearCache = () => (toRegexRange.cache = {}); - -/** - * Expose `toRegexRange` - */ - -module.exports = toRegexRange; - - -/***/ }), -/* 323 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-number - * - * Copyright (c) 2014-present, Jon Schlinkert. - * Released under the MIT License. - */ - - - -module.exports = function(num) { - if (typeof num === 'number') { - return num - num === 0; - } - if (typeof num === 'string' && num.trim() !== '') { - return Number.isFinite ? Number.isFinite(+num) : isFinite(+num); - } - return false; -}; + push({ type: 'paren', extglob: true, value, output }); + decrement('parens'); + }; -/***/ }), -/* 324 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const fill = __webpack_require__(321); -const stringify = __webpack_require__(318); -const utils = __webpack_require__(319); - -const append = (queue = '', stash = '', enclose = false) => { - let result = []; - - queue = [].concat(queue); - stash = [].concat(stash); + /** + * Fast paths + */ - if (!stash.length) return queue; - if (!queue.length) { - return enclose ? utils.flatten(stash).map(ele => `{${ele}}`) : stash; - } + if (opts.fastpaths !== false && !/(^[*!]|[/()[\]{}"])/.test(input)) { + let backslashes = false; - for (let item of queue) { - if (Array.isArray(item)) { - for (let value of item) { - result.push(append(value, stash, enclose)); - } - } else { - for (let ele of stash) { - if (enclose === true && typeof ele === 'string') ele = `{${ele}}`; - result.push(Array.isArray(ele) ? append(item, ele, enclose) : (item + ele)); + let output = input.replace(REGEX_SPECIAL_CHARS_BACKREF, (m, esc, chars, first, rest, index) => { + if (first === '\\') { + backslashes = true; + return m; } - } - } - return utils.flatten(result); -}; - -const expand = (ast, options = {}) => { - let rangeLimit = options.rangeLimit === void 0 ? 1000 : options.rangeLimit; - let walk = (node, parent = {}) => { - node.queue = []; + if (first === '?') { + if (esc) { + return esc + first + (rest ? QMARK.repeat(rest.length) : ''); + } + if (index === 0) { + return qmarkNoDot + (rest ? QMARK.repeat(rest.length) : ''); + } + return QMARK.repeat(chars.length); + } - let p = parent; - let q = parent.queue; + if (first === '.') { + return DOT_LITERAL.repeat(chars.length); + } - while (p.type !== 'brace' && p.type !== 'root' && p.parent) { - p = p.parent; - q = p.queue; - } + if (first === '*') { + if (esc) { + return esc + first + (rest ? star : ''); + } + return star; + } + return esc ? m : `\\${m}`; + }); - if (node.invalid || node.dollar) { - q.push(append(q.pop(), stringify(node, options))); - return; + if (backslashes === true) { + if (opts.unescape === true) { + output = output.replace(/\\/g, ''); + } else { + output = output.replace(/\\+/g, m => { + return m.length % 2 === 0 ? '\\\\' : (m ? '\\' : ''); + }); + } } - if (node.type === 'brace' && node.invalid !== true && node.nodes.length === 2) { - q.push(append(q.pop(), ['{}'])); - return; + if (output === input && opts.contains === true) { + state.output = input; + return state; } - if (node.nodes && node.ranges > 0) { - let args = utils.reduce(node.nodes); + state.output = utils.wrapOutput(output, state, options); + return state; + } - if (utils.exceedsLimit(...args, options.step, rangeLimit)) { - throw new RangeError('expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.'); - } + /** + * Tokenize input until we reach end-of-string + */ - let range = fill(...args, options); - if (range.length === 0) { - range = stringify(node, options); - } + while (!eos()) { + value = advance(); - q.push(append(q.pop(), range)); - node.nodes = []; - return; + if (value === '\u0000') { + continue; } - let enclose = utils.encloseBrace(node); - let queue = node.queue; - let block = node; - - while (block.type !== 'brace' && block.type !== 'root' && block.parent) { - block = block.parent; - queue = block.queue; - } + /** + * Escaped characters + */ - for (let i = 0; i < node.nodes.length; i++) { - let child = node.nodes[i]; + if (value === '\\') { + const next = peek(); - if (child.type === 'comma' && node.type === 'brace') { - if (i === 1) queue.push(''); - queue.push(''); + if (next === '/' && opts.bash !== true) { continue; } - if (child.type === 'close') { - q.push(append(q.pop(), queue, enclose)); + if (next === '.' || next === ';') { continue; } - if (child.value && child.type !== 'open') { - queue.push(append(queue.pop(), child.value)); + if (!next) { + value += '\\'; + push({ type: 'text', value }); continue; } - if (child.nodes) { - walk(child, node); - } - } - - return queue; - }; - - return utils.flatten(walk(ast)); -}; - -module.exports = expand; - - -/***/ }), -/* 325 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; + // collapse slashes to reduce potential for exploits + const match = /^\\+/.exec(remaining()); + let slashes = 0; + if (match && match[0].length > 2) { + slashes = match[0].length; + state.index += slashes; + if (slashes % 2 !== 0) { + value += '\\'; + } + } -const stringify = __webpack_require__(318); + if (opts.unescape === true) { + value = advance() || ''; + } else { + value += advance() || ''; + } -/** - * Constants - */ + if (state.brackets === 0) { + push({ type: 'text', value }); + continue; + } + } -const { - MAX_LENGTH, - CHAR_BACKSLASH, /* \ */ - CHAR_BACKTICK, /* ` */ - CHAR_COMMA, /* , */ - CHAR_DOT, /* . */ - CHAR_LEFT_PARENTHESES, /* ( */ - CHAR_RIGHT_PARENTHESES, /* ) */ - CHAR_LEFT_CURLY_BRACE, /* { */ - CHAR_RIGHT_CURLY_BRACE, /* } */ - CHAR_LEFT_SQUARE_BRACKET, /* [ */ - CHAR_RIGHT_SQUARE_BRACKET, /* ] */ - CHAR_DOUBLE_QUOTE, /* " */ - CHAR_SINGLE_QUOTE, /* ' */ - CHAR_NO_BREAK_SPACE, - CHAR_ZERO_WIDTH_NOBREAK_SPACE -} = __webpack_require__(326); + /** + * If we're inside a regex character class, continue + * until we reach the closing bracket. + */ -/** - * parse - */ + if (state.brackets > 0 && (value !== ']' || prev.value === '[' || prev.value === '[^')) { + if (opts.posix !== false && value === ':') { + const inner = prev.value.slice(1); + if (inner.includes('[')) { + prev.posix = true; -const parse = (input, options = {}) => { - if (typeof input !== 'string') { - throw new TypeError('Expected a string'); - } + if (inner.includes(':')) { + const idx = prev.value.lastIndexOf('['); + const pre = prev.value.slice(0, idx); + const rest = prev.value.slice(idx + 2); + const posix = POSIX_REGEX_SOURCE[rest]; + if (posix) { + prev.value = pre + posix; + state.backtrack = true; + advance(); - let opts = options || {}; - let max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; - if (input.length > max) { - throw new SyntaxError(`Input length (${input.length}), exceeds max characters (${max})`); - } + if (!bos.output && tokens.indexOf(prev) === 1) { + bos.output = ONE_CHAR; + } + continue; + } + } + } + } - let ast = { type: 'root', input, nodes: [] }; - let stack = [ast]; - let block = ast; - let prev = ast; - let brackets = 0; - let length = input.length; - let index = 0; - let depth = 0; - let value; - let memo = {}; + if ((value === '[' && peek() !== ':') || (value === '-' && peek() === ']')) { + value = `\\${value}`; + } - /** - * Helpers - */ + if (value === ']' && (prev.value === '[' || prev.value === '[^')) { + value = `\\${value}`; + } - const advance = () => input[index++]; - const push = node => { - if (node.type === 'text' && prev.type === 'dot') { - prev.type = 'text'; - } + if (opts.posix === true && value === '!' && prev.value === '[') { + value = '^'; + } - if (prev && prev.type === 'text' && node.type === 'text') { - prev.value += node.value; - return; + prev.value += value; + append({ value }); + continue; } - block.nodes.push(node); - node.parent = block; - node.prev = prev; - prev = node; - return node; - }; - - push({ type: 'bos' }); - - while (index < length) { - block = stack[stack.length - 1]; - value = advance(); - /** - * Invalid chars + * If we're inside a quoted string, continue + * until we reach the closing double quote. */ - if (value === CHAR_ZERO_WIDTH_NOBREAK_SPACE || value === CHAR_NO_BREAK_SPACE) { + if (state.quotes === 1 && value !== '"') { + value = utils.escapeRegex(value); + prev.value += value; + append({ value }); continue; } /** - * Escaped chars + * Double quotes */ - if (value === CHAR_BACKSLASH) { - push({ type: 'text', value: (options.keepEscaping ? value : '') + advance() }); + if (value === '"') { + state.quotes = state.quotes === 1 ? 0 : 1; + if (opts.keepQuotes === true) { + push({ type: 'text', value }); + } continue; } /** - * Right square bracket (literal): ']' + * Parentheses */ - if (value === CHAR_RIGHT_SQUARE_BRACKET) { - push({ type: 'text', value: '\\' + value }); + if (value === '(') { + increment('parens'); + push({ type: 'paren', value }); continue; } - /** - * Left square bracket: '[' - */ - - if (value === CHAR_LEFT_SQUARE_BRACKET) { - brackets++; - - let closed = true; - let next; - - while (index < length && (next = advance())) { - value += next; - - if (next === CHAR_LEFT_SQUARE_BRACKET) { - brackets++; - continue; - } - - if (next === CHAR_BACKSLASH) { - value += advance(); - continue; - } - - if (next === CHAR_RIGHT_SQUARE_BRACKET) { - brackets--; + if (value === ')') { + if (state.parens === 0 && opts.strictBrackets === true) { + throw new SyntaxError(syntaxError('opening', '(')); + } - if (brackets === 0) { - break; - } - } + const extglob = extglobs[extglobs.length - 1]; + if (extglob && state.parens === extglob.parens + 1) { + extglobClose(extglobs.pop()); + continue; } - push({ type: 'text', value }); + push({ type: 'paren', value, output: state.parens ? ')' : '\\)' }); + decrement('parens'); continue; } /** - * Parentheses + * Square brackets */ - if (value === CHAR_LEFT_PARENTHESES) { - block = push({ type: 'paren', nodes: [] }); - stack.push(block); - push({ type: 'text', value }); + if (value === '[') { + if (opts.nobracket === true || !remaining().includes(']')) { + if (opts.nobracket !== true && opts.strictBrackets === true) { + throw new SyntaxError(syntaxError('closing', ']')); + } + + value = `\\${value}`; + } else { + increment('brackets'); + } + + push({ type: 'bracket', value }); continue; } - if (value === CHAR_RIGHT_PARENTHESES) { - if (block.type !== 'paren') { - push({ type: 'text', value }); + if (value === ']') { + if (opts.nobracket === true || (prev && prev.type === 'bracket' && prev.value.length === 1)) { + push({ type: 'text', value, output: `\\${value}` }); continue; } - block = stack.pop(); - push({ type: 'text', value }); - block = stack[stack.length - 1]; - continue; - } - /** - * Quotes: '|"|` - */ + if (state.brackets === 0) { + if (opts.strictBrackets === true) { + throw new SyntaxError(syntaxError('opening', '[')); + } - if (value === CHAR_DOUBLE_QUOTE || value === CHAR_SINGLE_QUOTE || value === CHAR_BACKTICK) { - let open = value; - let next; + push({ type: 'text', value, output: `\\${value}` }); + continue; + } - if (options.keepQuotes !== true) { - value = ''; + decrement('brackets'); + + const prevValue = prev.value.slice(1); + if (prev.posix !== true && prevValue[0] === '^' && !prevValue.includes('/')) { + value = `/${value}`; } - while (index < length && (next = advance())) { - if (next === CHAR_BACKSLASH) { - value += next + advance(); - continue; - } + prev.value += value; + append({ value }); - if (next === open) { - if (options.keepQuotes === true) value += next; - break; - } + // when literal brackets are explicitly disabled + // assume we should match with a regex character class + if (opts.literalBrackets === false || utils.hasRegexChars(prevValue)) { + continue; + } - value += next; + const escaped = utils.escapeRegex(prev.value); + state.output = state.output.slice(0, -prev.value.length); + + // when literal brackets are explicitly enabled + // assume we should escape the brackets to match literal characters + if (opts.literalBrackets === true) { + state.output += escaped; + prev.value = escaped; + continue; } - push({ type: 'text', value }); + // when the user specifies nothing, try to match both + prev.value = `(${capture}${escaped}|${prev.value})`; + state.output += prev.value; continue; } /** - * Left curly brace: '{' + * Braces */ - if (value === CHAR_LEFT_CURLY_BRACE) { - depth++; + if (value === '{' && opts.nobrace !== true) { + increment('braces'); - let dollar = prev.value && prev.value.slice(-1) === '$' || block.dollar === true; - let brace = { + const open = { type: 'brace', - open: true, - close: false, - dollar, - depth, - commas: 0, - ranges: 0, - nodes: [] + value, + output: '(', + outputIndex: state.output.length, + tokensIndex: state.tokens.length }; - block = push(brace); - stack.push(block); - push({ type: 'open', value }); + braces.push(open); + push(open); continue; } - /** - * Right curly brace: '}' - */ + if (value === '}') { + const brace = braces[braces.length - 1]; - if (value === CHAR_RIGHT_CURLY_BRACE) { - if (block.type !== 'brace') { - push({ type: 'text', value }); + if (opts.nobrace === true || !brace) { + push({ type: 'text', value, output: value }); continue; } - let type = 'close'; - block = stack.pop(); - block.close = true; + let output = ')'; - push({ type, value }); - depth--; + if (brace.dots === true) { + const arr = tokens.slice(); + const range = []; - block = stack[stack.length - 1]; + for (let i = arr.length - 1; i >= 0; i--) { + tokens.pop(); + if (arr[i].type === 'brace') { + break; + } + if (arr[i].type !== 'dots') { + range.unshift(arr[i].value); + } + } + + output = expandRange(range, opts); + state.backtrack = true; + } + + if (brace.comma !== true && brace.dots !== true) { + const out = state.output.slice(0, brace.outputIndex); + const toks = state.tokens.slice(brace.tokensIndex); + brace.value = brace.output = '\\{'; + value = output = '\\}'; + state.output = out; + for (const t of toks) { + state.output += (t.output || t.value); + } + } + + push({ type: 'brace', value, output }); + decrement('braces'); + braces.pop(); continue; } /** - * Comma: ',' + * Pipes */ - if (value === CHAR_COMMA && depth > 0) { - if (block.ranges > 0) { - block.ranges = 0; - let open = block.nodes.shift(); - block.nodes = [open, { type: 'text', value: stringify(block) }]; + if (value === '|') { + if (extglobs.length > 0) { + extglobs[extglobs.length - 1].conditions++; } - - push({ type: 'comma', value }); - block.commas++; + push({ type: 'text', value }); continue; } /** - * Dot: '.' + * Commas */ - if (value === CHAR_DOT && depth > 0 && block.commas === 0) { - let siblings = block.nodes; + if (value === ',') { + let output = value; - if (depth === 0 || siblings.length === 0) { - push({ type: 'text', value }); - continue; + const brace = braces[braces.length - 1]; + if (brace && stack[stack.length - 1] === 'braces') { + brace.comma = true; + output = '|'; } - if (prev.type === 'dot') { - block.range = []; - prev.value += value; - prev.type = 'range'; + push({ type: 'comma', value, output }); + continue; + } - if (block.nodes.length !== 3 && block.nodes.length !== 5) { - block.invalid = true; - block.ranges = 0; - prev.type = 'text'; - continue; - } + /** + * Slashes + */ - block.ranges++; - block.args = []; + if (value === '/') { + // if the beginning of the glob is "./", advance the start + // to the current index, and don't add the "./" characters + // to the state. This greatly simplifies lookbehinds when + // checking for BOS characters like "!" and "." (not "./") + if (prev.type === 'dot' && state.index === state.start + 1) { + state.start = state.index + 1; + state.consumed = ''; + state.output = ''; + tokens.pop(); + prev = bos; // reset "prev" to the first token continue; } - if (prev.type === 'range') { - siblings.pop(); + push({ type: 'slash', value, output: SLASH_LITERAL }); + continue; + } - let before = siblings[siblings.length - 1]; - before.value += prev.value + value; - prev = before; - block.ranges--; + /** + * Dots + */ + + if (value === '.') { + if (state.braces > 0 && prev.type === 'dot') { + if (prev.value === '.') prev.output = DOT_LITERAL; + const brace = braces[braces.length - 1]; + prev.type = 'dots'; + prev.output += value; + prev.value += value; + brace.dots = true; continue; } - push({ type: 'dot', value }); + if ((state.braces + state.parens) === 0 && prev.type !== 'bos' && prev.type !== 'slash') { + push({ type: 'text', value, output: DOT_LITERAL }); + continue; + } + + push({ type: 'dot', value, output: DOT_LITERAL }); continue; } /** - * Text + * Question marks */ - push({ type: 'text', value }); - } + if (value === '?') { + const isGroup = prev && prev.value === '('; + if (!isGroup && opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { + extglobOpen('qmark', value); + continue; + } - // Mark imbalanced braces and brackets as invalid - do { - block = stack.pop(); + if (prev && prev.type === 'paren') { + const next = peek(); + let output = value; - if (block.type !== 'root') { - block.nodes.forEach(node => { - if (!node.nodes) { - if (node.type === 'open') node.isOpen = true; - if (node.type === 'close') node.isClose = true; - if (!node.nodes) node.type = 'text'; - node.invalid = true; + if (next === '<' && !utils.supportsLookbehinds()) { + throw new Error('Node.js v10 or higher is required for regex lookbehinds'); } - }); - // get the location of the block on parent.nodes (block's siblings) - let parent = stack[stack.length - 1]; - let index = parent.nodes.indexOf(block); - // replace the (invalid) block with it's nodes - parent.nodes.splice(index, 1, ...block.nodes); - } - } while (stack.length > 0); + if ((prev.value === '(' && !/[!=<:]/.test(next)) || (next === '<' && !/<([!=]|\w+>)/.test(remaining()))) { + output = `\\${value}`; + } - push({ type: 'eos' }); - return ast; -}; + push({ type: 'text', value, output }); + continue; + } -module.exports = parse; + if (opts.dot !== true && (prev.type === 'slash' || prev.type === 'bos')) { + push({ type: 'qmark', value, output: QMARK_NO_DOT }); + continue; + } + push({ type: 'qmark', value, output: QMARK }); + continue; + } -/***/ }), -/* 326 */ -/***/ (function(module, exports, __webpack_require__) { + /** + * Exclamation + */ -"use strict"; + if (value === '!') { + if (opts.noextglob !== true && peek() === '(') { + if (peek(2) !== '?' || !/[!=<:]/.test(peek(3))) { + extglobOpen('negate', value); + continue; + } + } + if (opts.nonegate !== true && state.index === 0) { + negate(); + continue; + } + } -module.exports = { - MAX_LENGTH: 1024 * 64, + /** + * Plus + */ - // Digits - CHAR_0: '0', /* 0 */ - CHAR_9: '9', /* 9 */ + if (value === '+') { + if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { + extglobOpen('plus', value); + continue; + } - // Alphabet chars. - CHAR_UPPERCASE_A: 'A', /* A */ - CHAR_LOWERCASE_A: 'a', /* a */ - CHAR_UPPERCASE_Z: 'Z', /* Z */ - CHAR_LOWERCASE_Z: 'z', /* z */ + if ((prev && prev.value === '(') || opts.regex === false) { + push({ type: 'plus', value, output: PLUS_LITERAL }); + continue; + } - CHAR_LEFT_PARENTHESES: '(', /* ( */ - CHAR_RIGHT_PARENTHESES: ')', /* ) */ + if ((prev && (prev.type === 'bracket' || prev.type === 'paren' || prev.type === 'brace')) || state.parens > 0) { + push({ type: 'plus', value }); + continue; + } - CHAR_ASTERISK: '*', /* * */ + push({ type: 'plus', value: PLUS_LITERAL }); + continue; + } - // Non-alphabetic chars. - CHAR_AMPERSAND: '&', /* & */ - CHAR_AT: '@', /* @ */ - CHAR_BACKSLASH: '\\', /* \ */ - CHAR_BACKTICK: '`', /* ` */ - CHAR_CARRIAGE_RETURN: '\r', /* \r */ - CHAR_CIRCUMFLEX_ACCENT: '^', /* ^ */ - CHAR_COLON: ':', /* : */ - CHAR_COMMA: ',', /* , */ - CHAR_DOLLAR: '$', /* . */ - CHAR_DOT: '.', /* . */ - CHAR_DOUBLE_QUOTE: '"', /* " */ - CHAR_EQUAL: '=', /* = */ - CHAR_EXCLAMATION_MARK: '!', /* ! */ - CHAR_FORM_FEED: '\f', /* \f */ - CHAR_FORWARD_SLASH: '/', /* / */ - CHAR_HASH: '#', /* # */ - CHAR_HYPHEN_MINUS: '-', /* - */ - CHAR_LEFT_ANGLE_BRACKET: '<', /* < */ - CHAR_LEFT_CURLY_BRACE: '{', /* { */ - CHAR_LEFT_SQUARE_BRACKET: '[', /* [ */ - CHAR_LINE_FEED: '\n', /* \n */ - CHAR_NO_BREAK_SPACE: '\u00A0', /* \u00A0 */ - CHAR_PERCENT: '%', /* % */ - CHAR_PLUS: '+', /* + */ - CHAR_QUESTION_MARK: '?', /* ? */ - CHAR_RIGHT_ANGLE_BRACKET: '>', /* > */ - CHAR_RIGHT_CURLY_BRACE: '}', /* } */ - CHAR_RIGHT_SQUARE_BRACKET: ']', /* ] */ - CHAR_SEMICOLON: ';', /* ; */ - CHAR_SINGLE_QUOTE: '\'', /* ' */ - CHAR_SPACE: ' ', /* */ - CHAR_TAB: '\t', /* \t */ - CHAR_UNDERSCORE: '_', /* _ */ - CHAR_VERTICAL_LINE: '|', /* | */ - CHAR_ZERO_WIDTH_NOBREAK_SPACE: '\uFEFF' /* \uFEFF */ -}; + /** + * Plain text + */ + if (value === '@') { + if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { + push({ type: 'at', extglob: true, value, output: '' }); + continue; + } -/***/ }), -/* 327 */ -/***/ (function(module, exports, __webpack_require__) { + push({ type: 'text', value }); + continue; + } -"use strict"; + /** + * Plain text + */ + if (value !== '*') { + if (value === '$' || value === '^') { + value = `\\${value}`; + } -module.exports = __webpack_require__(328); + const match = REGEX_NON_SPECIAL_CHARS.exec(remaining()); + if (match) { + value += match[0]; + state.index += match[0].length; + } + push({ type: 'text', value }); + continue; + } -/***/ }), -/* 328 */ -/***/ (function(module, exports, __webpack_require__) { + /** + * Stars + */ -"use strict"; + if (prev && (prev.type === 'globstar' || prev.star === true)) { + prev.type = 'star'; + prev.star = true; + prev.value += value; + prev.output = star; + state.backtrack = true; + state.globstar = true; + consume(value); + continue; + } + let rest = remaining(); + if (opts.noextglob !== true && /^\([^?]/.test(rest)) { + extglobOpen('star', value); + continue; + } -const path = __webpack_require__(4); -const scan = __webpack_require__(329); -const parse = __webpack_require__(332); -const utils = __webpack_require__(330); -const constants = __webpack_require__(331); -const isObject = val => val && typeof val === 'object' && !Array.isArray(val); + if (prev.type === 'star') { + if (opts.noglobstar === true) { + consume(value); + continue; + } -/** - * Creates a matcher function from one or more glob patterns. The - * returned function takes a string to match as its first argument, - * and returns true if the string is a match. The returned matcher - * function also takes a boolean as the second argument that, when true, - * returns an object with additional information. - * - * ```js - * const picomatch = require('picomatch'); - * // picomatch(glob[, options]); - * - * const isMatch = picomatch('*.!(*a)'); - * console.log(isMatch('a.a')); //=> false - * console.log(isMatch('a.b')); //=> true - * ``` - * @name picomatch - * @param {String|Array} `globs` One or more glob patterns. - * @param {Object=} `options` - * @return {Function=} Returns a matcher function. - * @api public - */ + const prior = prev.prev; + const before = prior.prev; + const isStart = prior.type === 'slash' || prior.type === 'bos'; + const afterStar = before && (before.type === 'star' || before.type === 'globstar'); -const picomatch = (glob, options, returnState = false) => { - if (Array.isArray(glob)) { - const fns = glob.map(input => picomatch(input, options, returnState)); - const arrayMatcher = str => { - for (const isMatch of fns) { - const state = isMatch(str); - if (state) return state; + if (opts.bash === true && (!isStart || (rest[0] && rest[0] !== '/'))) { + push({ type: 'star', value, output: '' }); + continue; } - return false; - }; - return arrayMatcher; - } - const isState = isObject(glob) && glob.tokens && glob.input; + const isBrace = state.braces > 0 && (prior.type === 'comma' || prior.type === 'brace'); + const isExtglob = extglobs.length && (prior.type === 'pipe' || prior.type === 'paren'); + if (!isStart && prior.type !== 'paren' && !isBrace && !isExtglob) { + push({ type: 'star', value, output: '' }); + continue; + } - if (glob === '' || (typeof glob !== 'string' && !isState)) { - throw new TypeError('Expected pattern to be a non-empty string'); - } + // strip consecutive `/**/` + while (rest.slice(0, 3) === '/**') { + const after = input[state.index + 4]; + if (after && after !== '/') { + break; + } + rest = rest.slice(3); + consume('/**', 3); + } - const opts = options || {}; - const posix = utils.isWindows(options); - const regex = isState - ? picomatch.compileRe(glob, options) - : picomatch.makeRe(glob, options, false, true); + if (prior.type === 'bos' && eos()) { + prev.type = 'globstar'; + prev.value += value; + prev.output = globstar(opts); + state.output = prev.output; + state.globstar = true; + consume(value); + continue; + } - const state = regex.state; - delete regex.state; + if (prior.type === 'slash' && prior.prev.type !== 'bos' && !afterStar && eos()) { + state.output = state.output.slice(0, -(prior.output + prev.output).length); + prior.output = `(?:${prior.output}`; - let isIgnored = () => false; - if (opts.ignore) { - const ignoreOpts = { ...options, ignore: null, onMatch: null, onResult: null }; - isIgnored = picomatch(opts.ignore, ignoreOpts, returnState); - } + prev.type = 'globstar'; + prev.output = globstar(opts) + (opts.strictSlashes ? ')' : '|$)'); + prev.value += value; + state.globstar = true; + state.output += prior.output + prev.output; + consume(value); + continue; + } - const matcher = (input, returnObject = false) => { - const { isMatch, match, output } = picomatch.test(input, regex, options, { glob, posix }); - const result = { glob, state, regex, posix, input, output, match, isMatch }; + if (prior.type === 'slash' && prior.prev.type !== 'bos' && rest[0] === '/') { + const end = rest[1] !== void 0 ? '|$' : ''; - if (typeof opts.onResult === 'function') { - opts.onResult(result); - } + state.output = state.output.slice(0, -(prior.output + prev.output).length); + prior.output = `(?:${prior.output}`; - if (isMatch === false) { - result.isMatch = false; - return returnObject ? result : false; - } + prev.type = 'globstar'; + prev.output = `${globstar(opts)}${SLASH_LITERAL}|${SLASH_LITERAL}${end})`; + prev.value += value; - if (isIgnored(input)) { - if (typeof opts.onIgnore === 'function') { - opts.onIgnore(result); - } - result.isMatch = false; - return returnObject ? result : false; - } + state.output += prior.output + prev.output; + state.globstar = true; - if (typeof opts.onMatch === 'function') { - opts.onMatch(result); - } - return returnObject ? result : true; - }; - - if (returnState) { - matcher.state = state; - } - - return matcher; -}; - -/** - * Test `input` with the given `regex`. This is used by the main - * `picomatch()` function to test the input string. - * - * ```js - * const picomatch = require('picomatch'); - * // picomatch.test(input, regex[, options]); - * - * console.log(picomatch.test('foo/bar', /^(?:([^/]*?)\/([^/]*?))$/)); - * // { isMatch: true, match: [ 'foo/', 'foo', 'bar' ], output: 'foo/bar' } - * ``` - * @param {String} `input` String to test. - * @param {RegExp} `regex` - * @return {Object} Returns an object with matching info. - * @api public - */ + consume(value + advance()); -picomatch.test = (input, regex, options, { glob, posix } = {}) => { - if (typeof input !== 'string') { - throw new TypeError('Expected input to be a string'); - } + push({ type: 'slash', value: '/', output: '' }); + continue; + } - if (input === '') { - return { isMatch: false, output: '' }; - } + if (prior.type === 'bos' && rest[0] === '/') { + prev.type = 'globstar'; + prev.value += value; + prev.output = `(?:^|${SLASH_LITERAL}|${globstar(opts)}${SLASH_LITERAL})`; + state.output = prev.output; + state.globstar = true; + consume(value + advance()); + push({ type: 'slash', value: '/', output: '' }); + continue; + } - const opts = options || {}; - const format = opts.format || (posix ? utils.toPosixSlashes : null); - let match = input === glob; - let output = (match && format) ? format(input) : input; + // remove single star from output + state.output = state.output.slice(0, -prev.output.length); - if (match === false) { - output = format ? format(input) : input; - match = output === glob; - } + // reset previous token to globstar + prev.type = 'globstar'; + prev.output = globstar(opts); + prev.value += value; - if (match === false || opts.capture === true) { - if (opts.matchBase === true || opts.basename === true) { - match = picomatch.matchBase(input, regex, options, posix); - } else { - match = regex.exec(output); + // reset output with globstar + state.output += prev.output; + state.globstar = true; + consume(value); + continue; } - } - - return { isMatch: Boolean(match), match, output }; -}; - -/** - * Match the basename of a filepath. - * - * ```js - * const picomatch = require('picomatch'); - * // picomatch.matchBase(input, glob[, options]); - * console.log(picomatch.matchBase('foo/bar.js', '*.js'); // true - * ``` - * @param {String} `input` String to test. - * @param {RegExp|String} `glob` Glob pattern or regex created by [.makeRe](#makeRe). - * @return {Boolean} - * @api public - */ - -picomatch.matchBase = (input, glob, options, posix = utils.isWindows(options)) => { - const regex = glob instanceof RegExp ? glob : picomatch.makeRe(glob, options); - return regex.test(path.basename(input)); -}; -/** - * Returns true if **any** of the given glob `patterns` match the specified `string`. - * - * ```js - * const picomatch = require('picomatch'); - * // picomatch.isMatch(string, patterns[, options]); - * - * console.log(picomatch.isMatch('a.a', ['b.*', '*.a'])); //=> true - * console.log(picomatch.isMatch('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). - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ + const token = { type: 'star', value, output: star }; -picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str); + if (opts.bash === true) { + token.output = '.*?'; + if (prev.type === 'bos' || prev.type === 'slash') { + token.output = nodot + token.output; + } + push(token); + continue; + } -/** - * Parse a glob pattern to create the source string for a regular - * expression. - * - * ```js - * const picomatch = require('picomatch'); - * const result = picomatch.parse(pattern[, options]); - * ``` - * @param {String} `pattern` - * @param {Object} `options` - * @return {Object} Returns an object with useful properties and output to be used as a regex source string. - * @api public - */ + if (prev && (prev.type === 'bracket' || prev.type === 'paren') && opts.regex === true) { + token.output = value; + push(token); + continue; + } -picomatch.parse = (pattern, options) => { - if (Array.isArray(pattern)) return pattern.map(p => picomatch.parse(p, options)); - return parse(pattern, { ...options, fastpaths: false }); -}; + if (state.index === state.start || prev.type === 'slash' || prev.type === 'dot') { + if (prev.type === 'dot') { + state.output += NO_DOT_SLASH; + prev.output += NO_DOT_SLASH; -/** - * Scan a glob pattern to separate the pattern into segments. - * - * ```js - * const picomatch = require('picomatch'); - * // picomatch.scan(input[, options]); - * - * const result = picomatch.scan('!./foo/*.js'); - * console.log(result); - * { prefix: '!./', - * input: '!./foo/*.js', - * start: 3, - * base: 'foo', - * glob: '*.js', - * isBrace: false, - * isBracket: false, - * isGlob: true, - * isExtglob: false, - * isGlobstar: false, - * negated: true } - * ``` - * @param {String} `input` Glob pattern to scan. - * @param {Object} `options` - * @return {Object} Returns an object with - * @api public - */ + } else if (opts.dot === true) { + state.output += NO_DOTS_SLASH; + prev.output += NO_DOTS_SLASH; -picomatch.scan = (input, options) => scan(input, options); + } else { + state.output += nodot; + prev.output += nodot; + } -/** - * Create a regular expression from a parsed glob pattern. - * - * ```js - * const picomatch = require('picomatch'); - * const state = picomatch.parse('*.js'); - * // picomatch.compileRe(state[, options]); - * - * console.log(picomatch.compileRe(state)); - * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/ - * ``` - * @param {String} `state` The object returned from the `.parse` method. - * @param {Object} `options` - * @return {RegExp} Returns a regex created from the given pattern. - * @api public - */ + if (peek() !== '*') { + state.output += ONE_CHAR; + prev.output += ONE_CHAR; + } + } -picomatch.compileRe = (parsed, options, returnOutput = false, returnState = false) => { - if (returnOutput === true) { - return parsed.output; + push(token); } - const opts = options || {}; - const prepend = opts.contains ? '' : '^'; - const append = opts.contains ? '' : '$'; - - let source = `${prepend}(?:${parsed.output})${append}`; - if (parsed && parsed.negated === true) { - source = `^(?!${source}).*$`; + while (state.brackets > 0) { + if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ']')); + state.output = utils.escapeLast(state.output, '['); + decrement('brackets'); } - const regex = picomatch.toRegex(source, options); - if (returnState === true) { - regex.state = parsed; + while (state.parens > 0) { + if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ')')); + state.output = utils.escapeLast(state.output, '('); + decrement('parens'); } - return regex; -}; - -picomatch.makeRe = (input, options, returnOutput = false, returnState = false) => { - if (!input || typeof input !== 'string') { - throw new TypeError('Expected a non-empty string'); + while (state.braces > 0) { + if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', '}')); + state.output = utils.escapeLast(state.output, '{'); + decrement('braces'); } - const opts = options || {}; - let parsed = { negated: false, fastpaths: true }; - let prefix = ''; - let output; - - if (input.startsWith('./')) { - input = input.slice(2); - prefix = parsed.prefix = './'; + if (opts.strictSlashes !== true && (prev.type === 'star' || prev.type === 'bracket')) { + push({ type: 'maybe_slash', value: '', output: `${SLASH_LITERAL}?` }); } - if (opts.fastpaths !== false && (input[0] === '.' || input[0] === '*')) { - output = parse.fastpaths(input, options); - } + // rebuild the output if we had to backtrack at any point + if (state.backtrack === true) { + state.output = ''; - if (output === undefined) { - parsed = parse(input, options); - parsed.prefix = prefix + (parsed.prefix || ''); - } else { - parsed.output = output; + for (const token of state.tokens) { + state.output += token.output != null ? token.output : token.value; + + if (token.suffix) { + state.output += token.suffix; + } + } } - return picomatch.compileRe(parsed, options, returnOutput, returnState); + return state; }; /** - * Create a regular expression from the given regex source string. - * - * ```js - * const picomatch = require('picomatch'); - * // picomatch.toRegex(source[, options]); - * - * const { output } = picomatch.parse('*.js'); - * console.log(picomatch.toRegex(output)); - * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/ - * ``` - * @param {String} `source` Regular expression source string. - * @param {Object} `options` - * @return {RegExp} - * @api public + * Fast paths for creating regular expressions for common glob patterns. + * This can significantly speed up processing and has very little downside + * impact when none of the fast paths match. */ -picomatch.toRegex = (source, options) => { - try { - const opts = options || {}; - return new RegExp(source, opts.flags || (opts.nocase ? 'i' : '')); - } catch (err) { - if (options && options.debug === true) throw err; - return /$^/; +parse.fastpaths = (input, options) => { + const opts = { ...options }; + const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; + const len = input.length; + if (len > max) { + throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`); } -}; -/** - * Picomatch constants. - * @return {Object} - */ + input = REPLACEMENTS[input] || input; + const win32 = utils.isWindows(options); -picomatch.constants = constants; + // create constants based on platform, for windows or posix + const { + DOT_LITERAL, + SLASH_LITERAL, + ONE_CHAR, + DOTS_SLASH, + NO_DOT, + NO_DOTS, + NO_DOTS_SLASH, + STAR, + START_ANCHOR + } = constants.globChars(win32); -/** - * Expose "picomatch" - */ + const nodot = opts.dot ? NO_DOTS : NO_DOT; + const slashDot = opts.dot ? NO_DOTS_SLASH : NO_DOT; + const capture = opts.capture ? '' : '?:'; + const state = { negated: false, prefix: '' }; + let star = opts.bash === true ? '.*?' : STAR; -module.exports = picomatch; + if (opts.capture) { + star = `(${star})`; + } + const globstar = (opts) => { + if (opts.noglobstar === true) return star; + return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`; + }; -/***/ }), -/* 329 */ -/***/ (function(module, exports, __webpack_require__) { + const create = str => { + switch (str) { + case '*': + return `${nodot}${ONE_CHAR}${star}`; -"use strict"; + case '.*': + return `${DOT_LITERAL}${ONE_CHAR}${star}`; + case '*.*': + return `${nodot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`; -const utils = __webpack_require__(330); -const { - CHAR_ASTERISK, /* * */ - CHAR_AT, /* @ */ - CHAR_BACKWARD_SLASH, /* \ */ - CHAR_COMMA, /* , */ - CHAR_DOT, /* . */ - CHAR_EXCLAMATION_MARK, /* ! */ - CHAR_FORWARD_SLASH, /* / */ - CHAR_LEFT_CURLY_BRACE, /* { */ - CHAR_LEFT_PARENTHESES, /* ( */ - CHAR_LEFT_SQUARE_BRACKET, /* [ */ - CHAR_PLUS, /* + */ - CHAR_QUESTION_MARK, /* ? */ - CHAR_RIGHT_CURLY_BRACE, /* } */ - CHAR_RIGHT_PARENTHESES, /* ) */ - CHAR_RIGHT_SQUARE_BRACKET /* ] */ -} = __webpack_require__(331); + case '*/*': + return `${nodot}${star}${SLASH_LITERAL}${ONE_CHAR}${slashDot}${star}`; -const isPathSeparator = code => { - return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; -}; + case '**': + return nodot + globstar(opts); -const depth = token => { - if (token.isPrefix !== true) { - token.depth = token.isGlobstar ? Infinity : 1; - } -}; + case '**/*': + return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${ONE_CHAR}${star}`; -/** - * Quickly scans a glob pattern and returns an object with a handful of - * useful properties, like `isGlob`, `path` (the leading non-glob, if it exists), - * `glob` (the actual pattern), and `negated` (true if the path starts with `!`). - * - * ```js - * const pm = require('picomatch'); - * console.log(pm.scan('foo/bar/*.js')); - * { isGlob: true, input: 'foo/bar/*.js', base: 'foo/bar', glob: '*.js' } - * ``` - * @param {String} `str` - * @param {Object} `options` - * @return {Object} Returns an object with tokens and regex source string. - * @api public - */ + case '**/*.*': + return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`; -const scan = (input, options) => { - const opts = options || {}; + case '**/.*': + return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${DOT_LITERAL}${ONE_CHAR}${star}`; - const length = input.length - 1; - const scanToEnd = opts.parts === true || opts.scanToEnd === true; - const slashes = []; - const tokens = []; - const parts = []; + default: { + const match = /^(.*?)\.(\w+)$/.exec(str); + if (!match) return; - let str = input; - let index = -1; - let start = 0; - let lastIndex = 0; - let isBrace = false; - let isBracket = false; - let isGlob = false; - let isExtglob = false; - let isGlobstar = false; - let braceEscaped = false; - let backslashes = false; - let negated = false; - let finished = false; - let braces = 0; - let prev; - let code; - let token = { value: '', depth: 0, isGlob: false }; + const source = create(match[1]); + if (!source) return; - const eos = () => index >= length; - const peek = () => str.charCodeAt(index + 1); - const advance = () => { - prev = code; - return str.charCodeAt(++index); + return source + DOT_LITERAL + match[2]; + } + } }; - while (index < length) { - code = advance(); - let next; + const output = utils.removePrefix(input, state); + let source = create(output); - if (code === CHAR_BACKWARD_SLASH) { - backslashes = token.backslashes = true; - code = advance(); + if (source && opts.strictSlashes !== true) { + source += `${SLASH_LITERAL}?`; + } - if (code === CHAR_LEFT_CURLY_BRACE) { - braceEscaped = true; - } - continue; - } + return source; +}; - if (braceEscaped === true || code === CHAR_LEFT_CURLY_BRACE) { - braces++; +module.exports = parse; - while (eos() !== true && (code = advance())) { - if (code === CHAR_BACKWARD_SLASH) { - backslashes = token.backslashes = true; - advance(); - continue; - } - if (code === CHAR_LEFT_CURLY_BRACE) { - braces++; - continue; - } +/***/ }), +/* 328 */ +/***/ (function(module, exports, __webpack_require__) { - if (braceEscaped !== true && code === CHAR_DOT && (code = advance()) === CHAR_DOT) { - isBrace = token.isBrace = true; - isGlob = token.isGlob = true; - finished = true; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const merge2 = __webpack_require__(299); +function merge(streams) { + const mergedStream = merge2(streams); + streams.forEach((stream) => { + 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')); +} - if (scanToEnd === true) { - continue; - } - break; - } +/***/ }), +/* 329 */ +/***/ (function(module, exports, __webpack_require__) { - if (braceEscaped !== true && code === CHAR_COMMA) { - isBrace = token.isBrace = true; - isGlob = token.isGlob = true; - finished = true; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function isString(input) { + return typeof input === 'string'; +} +exports.isString = isString; +function isEmpty(input) { + return input === ''; +} +exports.isEmpty = isEmpty; - if (scanToEnd === true) { - continue; - } - break; - } - - if (code === CHAR_RIGHT_CURLY_BRACE) { - braces--; - - if (braces === 0) { - braceEscaped = false; - isBrace = token.isBrace = true; - finished = true; - break; - } - } - } - - if (scanToEnd === true) { - continue; - } - - break; - } - - if (code === CHAR_FORWARD_SLASH) { - slashes.push(index); - tokens.push(token); - token = { value: '', depth: 0, isGlob: false }; - - if (finished === true) continue; - if (prev === CHAR_DOT && index === (start + 1)) { - start += 2; - continue; - } - - lastIndex = index + 1; - continue; - } - - if (opts.noext !== true) { - const isExtglobChar = code === CHAR_PLUS - || code === CHAR_AT - || code === CHAR_ASTERISK - || code === CHAR_QUESTION_MARK - || code === CHAR_EXCLAMATION_MARK; - - if (isExtglobChar === true && peek() === CHAR_LEFT_PARENTHESES) { - isGlob = token.isGlob = true; - isExtglob = token.isExtglob = true; - finished = true; - - if (scanToEnd === true) { - while (eos() !== true && (code = advance())) { - if (code === CHAR_BACKWARD_SLASH) { - backslashes = token.backslashes = true; - code = advance(); - continue; - } - - if (code === CHAR_RIGHT_PARENTHESES) { - isGlob = token.isGlob = true; - finished = true; - break; - } - } - continue; - } - break; - } - } - - if (code === CHAR_ASTERISK) { - if (prev === CHAR_ASTERISK) isGlobstar = token.isGlobstar = true; - isGlob = token.isGlob = true; - finished = true; - - if (scanToEnd === true) { - continue; - } - break; - } - - if (code === CHAR_QUESTION_MARK) { - isGlob = token.isGlob = true; - finished = true; - - if (scanToEnd === true) { - continue; - } - break; - } - - if (code === CHAR_LEFT_SQUARE_BRACKET) { - while (eos() !== true && (next = advance())) { - if (next === CHAR_BACKWARD_SLASH) { - backslashes = token.backslashes = true; - advance(); - continue; - } +/***/ }), +/* 330 */ +/***/ (function(module, exports, __webpack_require__) { - if (next === CHAR_RIGHT_SQUARE_BRACKET) { - isBracket = token.isBracket = true; - isGlob = token.isGlob = true; - finished = true; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const stream_1 = __webpack_require__(331); +const provider_1 = __webpack_require__(358); +class ProviderAsync extends provider_1.default { + constructor() { + super(...arguments); + this._reader = new stream_1.default(this._settings); + } + read(task) { + const root = this._getRootDirectory(task); + const options = this._getReaderOptions(task); + const entries = []; + return new Promise((resolve, reject) => { + const stream = this.api(root, task, options); + stream.once('error', reject); + stream.on('data', (entry) => entries.push(options.transform(entry))); + stream.once('end', () => resolve(entries)); + }); + } + api(root, task, options) { + if (task.dynamic) { + return this._reader.dynamic(root, options); + } + return this._reader.static(task.patterns, options); + } +} +exports.default = ProviderAsync; - if (scanToEnd === true) { - continue; - } - break; - } - } - } - if (opts.nonegate !== true && code === CHAR_EXCLAMATION_MARK && index === start) { - negated = token.negated = true; - start++; - continue; - } +/***/ }), +/* 331 */ +/***/ (function(module, exports, __webpack_require__) { - if (opts.noparen !== true && code === CHAR_LEFT_PARENTHESES) { - isGlob = token.isGlob = true; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const stream_1 = __webpack_require__(137); +const fsStat = __webpack_require__(332); +const fsWalk = __webpack_require__(337); +const reader_1 = __webpack_require__(357); +class ReaderStream extends reader_1.default { + constructor() { + super(...arguments); + this._walkStream = fsWalk.walkStream; + this._stat = fsStat.stat; + } + dynamic(root, options) { + return this._walkStream(root, options); + } + static(patterns, options) { + const filepaths = patterns.map(this._getFullEntryPath, this); + const stream = new stream_1.PassThrough({ objectMode: true }); + stream._write = (index, _enc, done) => { + return this._getEntry(filepaths[index], patterns[index], options) + .then((entry) => { + if (entry !== null && options.entryFilter(entry)) { + stream.push(entry); + } + if (index === filepaths.length - 1) { + stream.end(); + } + done(); + }) + .catch(done); + }; + for (let i = 0; i < filepaths.length; i++) { + stream.write(i); + } + return stream; + } + _getEntry(filepath, pattern, options) { + return this._getStat(filepath) + .then((stats) => this._makeEntry(stats, pattern)) + .catch((error) => { + if (options.errorFilter(error)) { + return null; + } + throw error; + }); + } + _getStat(filepath) { + return new Promise((resolve, reject) => { + this._stat(filepath, this._fsStatSettings, (error, stats) => { + return error === null ? resolve(stats) : reject(error); + }); + }); + } +} +exports.default = ReaderStream; - if (scanToEnd === true) { - while (eos() !== true && (code = advance())) { - if (code === CHAR_LEFT_PARENTHESES) { - backslashes = token.backslashes = true; - code = advance(); - continue; - } - if (code === CHAR_RIGHT_PARENTHESES) { - finished = true; - break; - } - } - continue; - } - break; - } +/***/ }), +/* 332 */ +/***/ (function(module, exports, __webpack_require__) { - if (isGlob === true) { - finished = true; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const async = __webpack_require__(333); +const sync = __webpack_require__(334); +const settings_1 = __webpack_require__(335); +exports.Settings = settings_1.default; +function stat(path, optionsOrSettingsOrCallback, callback) { + if (typeof optionsOrSettingsOrCallback === 'function') { + return async.read(path, getSettings(), optionsOrSettingsOrCallback); + } + async.read(path, getSettings(optionsOrSettingsOrCallback), callback); +} +exports.stat = stat; +function statSync(path, optionsOrSettings) { + const settings = getSettings(optionsOrSettings); + return sync.read(path, settings); +} +exports.statSync = statSync; +function getSettings(settingsOrOptions = {}) { + if (settingsOrOptions instanceof settings_1.default) { + return settingsOrOptions; + } + return new settings_1.default(settingsOrOptions); +} - if (scanToEnd === true) { - continue; - } - break; - } - } +/***/ }), +/* 333 */ +/***/ (function(module, exports, __webpack_require__) { - if (opts.noext === true) { - isExtglob = false; - isGlob = false; - } +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function read(path, settings, callback) { + settings.fs.lstat(path, (lstatError, lstat) => { + if (lstatError !== null) { + return callFailureCallback(callback, lstatError); + } + if (!lstat.isSymbolicLink() || !settings.followSymbolicLink) { + return callSuccessCallback(callback, lstat); + } + settings.fs.stat(path, (statError, stat) => { + if (statError !== null) { + if (settings.throwErrorOnBrokenSymbolicLink) { + return callFailureCallback(callback, statError); + } + return callSuccessCallback(callback, lstat); + } + if (settings.markSymbolicLink) { + stat.isSymbolicLink = () => true; + } + callSuccessCallback(callback, stat); + }); + }); +} +exports.read = read; +function callFailureCallback(callback, error) { + callback(error); +} +function callSuccessCallback(callback, result) { + callback(null, result); +} - let base = str; - let prefix = ''; - let glob = ''; - if (start > 0) { - prefix = str.slice(0, start); - str = str.slice(start); - lastIndex -= start; - } +/***/ }), +/* 334 */ +/***/ (function(module, exports, __webpack_require__) { - if (base && isGlob === true && lastIndex > 0) { - base = str.slice(0, lastIndex); - glob = str.slice(lastIndex); - } else if (isGlob === true) { - base = ''; - glob = str; - } else { - base = str; - } +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function read(path, settings) { + const lstat = settings.fs.lstatSync(path); + if (!lstat.isSymbolicLink() || !settings.followSymbolicLink) { + return lstat; + } + try { + const stat = settings.fs.statSync(path); + if (settings.markSymbolicLink) { + stat.isSymbolicLink = () => true; + } + return stat; + } + catch (error) { + if (!settings.throwErrorOnBrokenSymbolicLink) { + return lstat; + } + throw error; + } +} +exports.read = read; - if (base && base !== '' && base !== '/' && base !== str) { - if (isPathSeparator(base.charCodeAt(base.length - 1))) { - base = base.slice(0, -1); - } - } - if (opts.unescape === true) { - if (glob) glob = utils.removeBackslashes(glob); +/***/ }), +/* 335 */ +/***/ (function(module, exports, __webpack_require__) { - if (base && backslashes === true) { - base = utils.removeBackslashes(base); - } - } +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const fs = __webpack_require__(336); +class Settings { + constructor(_options = {}) { + this._options = _options; + this.followSymbolicLink = this._getValue(this._options.followSymbolicLink, true); + this.fs = fs.createFileSystemAdapter(this._options.fs); + this.markSymbolicLink = this._getValue(this._options.markSymbolicLink, false); + this.throwErrorOnBrokenSymbolicLink = this._getValue(this._options.throwErrorOnBrokenSymbolicLink, true); + } + _getValue(option, value) { + return option === undefined ? value : option; + } +} +exports.default = Settings; - const state = { - prefix, - input, - start, - base, - glob, - isBrace, - isBracket, - isGlob, - isExtglob, - isGlobstar, - negated - }; - if (opts.tokens === true) { - state.maxDepth = 0; - if (!isPathSeparator(code)) { - tokens.push(token); - } - state.tokens = tokens; - } +/***/ }), +/* 336 */ +/***/ (function(module, exports, __webpack_require__) { - if (opts.parts === true || opts.tokens === true) { - let prevIndex; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const fs = __webpack_require__(133); +exports.FILE_SYSTEM_ADAPTER = { + lstat: fs.lstat, + stat: fs.stat, + lstatSync: fs.lstatSync, + statSync: fs.statSync +}; +function createFileSystemAdapter(fsMethods) { + if (fsMethods === undefined) { + return exports.FILE_SYSTEM_ADAPTER; + } + return Object.assign(Object.assign({}, exports.FILE_SYSTEM_ADAPTER), fsMethods); +} +exports.createFileSystemAdapter = createFileSystemAdapter; - for (let idx = 0; idx < slashes.length; idx++) { - const n = prevIndex ? prevIndex + 1 : start; - const i = slashes[idx]; - const value = input.slice(n, i); - if (opts.tokens) { - if (idx === 0 && start !== 0) { - tokens[idx].isPrefix = true; - tokens[idx].value = prefix; - } else { - tokens[idx].value = value; - } - depth(tokens[idx]); - state.maxDepth += tokens[idx].depth; - } - if (idx !== 0 || value !== '') { - parts.push(value); - } - prevIndex = i; - } - if (prevIndex && prevIndex + 1 < input.length) { - const value = input.slice(prevIndex + 1); - parts.push(value); +/***/ }), +/* 337 */ +/***/ (function(module, exports, __webpack_require__) { - if (opts.tokens) { - tokens[tokens.length - 1].value = value; - depth(tokens[tokens.length - 1]); - state.maxDepth += tokens[tokens.length - 1].depth; - } - } +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const async_1 = __webpack_require__(338); +const stream_1 = __webpack_require__(353); +const sync_1 = __webpack_require__(354); +const settings_1 = __webpack_require__(356); +exports.Settings = settings_1.default; +function walk(directory, optionsOrSettingsOrCallback, callback) { + if (typeof optionsOrSettingsOrCallback === 'function') { + return new async_1.default(directory, getSettings()).read(optionsOrSettingsOrCallback); + } + new async_1.default(directory, getSettings(optionsOrSettingsOrCallback)).read(callback); +} +exports.walk = walk; +function walkSync(directory, optionsOrSettings) { + const settings = getSettings(optionsOrSettings); + const provider = new sync_1.default(directory, settings); + return provider.read(); +} +exports.walkSync = walkSync; +function walkStream(directory, optionsOrSettings) { + const settings = getSettings(optionsOrSettings); + const provider = new stream_1.default(directory, settings); + return provider.read(); +} +exports.walkStream = walkStream; +function getSettings(settingsOrOptions = {}) { + if (settingsOrOptions instanceof settings_1.default) { + return settingsOrOptions; + } + return new settings_1.default(settingsOrOptions); +} - state.slashes = slashes; - state.parts = parts; - } - return state; -}; +/***/ }), +/* 338 */ +/***/ (function(module, exports, __webpack_require__) { -module.exports = scan; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const async_1 = __webpack_require__(339); +class AsyncProvider { + constructor(_root, _settings) { + this._root = _root; + this._settings = _settings; + this._reader = new async_1.default(this._root, this._settings); + this._storage = new Set(); + } + read(callback) { + this._reader.onError((error) => { + callFailureCallback(callback, error); + }); + this._reader.onEntry((entry) => { + this._storage.add(entry); + }); + this._reader.onEnd(() => { + callSuccessCallback(callback, [...this._storage]); + }); + this._reader.read(); + } +} +exports.default = AsyncProvider; +function callFailureCallback(callback, error) { + callback(error); +} +function callSuccessCallback(callback, entries) { + callback(null, entries); +} /***/ }), -/* 330 */ +/* 339 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - - -const path = __webpack_require__(4); -const win32 = process.platform === 'win32'; -const { - REGEX_BACKSLASH, - REGEX_REMOVE_BACKSLASH, - REGEX_SPECIAL_CHARS, - REGEX_SPECIAL_CHARS_GLOBAL -} = __webpack_require__(331); - -exports.isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); -exports.hasRegexChars = str => REGEX_SPECIAL_CHARS.test(str); -exports.isRegexChar = str => str.length === 1 && exports.hasRegexChars(str); -exports.escapeRegex = str => str.replace(REGEX_SPECIAL_CHARS_GLOBAL, '\\$1'); -exports.toPosixSlashes = str => str.replace(REGEX_BACKSLASH, '/'); - -exports.removeBackslashes = str => { - return str.replace(REGEX_REMOVE_BACKSLASH, match => { - return match === '\\' ? '' : match; - }); -}; - -exports.supportsLookbehinds = () => { - const segs = process.version.slice(1).split('.').map(Number); - if (segs.length === 3 && segs[0] >= 9 || (segs[0] === 8 && segs[1] >= 10)) { - return true; - } - return false; -}; - -exports.isWindows = options => { - if (options && typeof options.windows === 'boolean') { - return options.windows; - } - return win32 === true || path.sep === '\\'; -}; - -exports.escapeLast = (input, char, lastIdx) => { - const idx = input.lastIndexOf(char, lastIdx); - if (idx === -1) return input; - if (input[idx - 1] === '\\') return exports.escapeLast(input, char, idx - 1); - return `${input.slice(0, idx)}\\${input.slice(idx)}`; -}; - -exports.removePrefix = (input, state = {}) => { - let output = input; - if (output.startsWith('./')) { - output = output.slice(2); - state.prefix = './'; - } - return output; -}; - -exports.wrapOutput = (input, state = {}, options = {}) => { - const prepend = options.contains ? '' : '^'; - const append = options.contains ? '' : '$'; - - let output = `${prepend}(?:${input})${append}`; - if (state.negated === true) { - output = `(?:^(?!${output}).*$)`; - } - return output; -}; + +Object.defineProperty(exports, "__esModule", { value: true }); +const events_1 = __webpack_require__(155); +const fsScandir = __webpack_require__(340); +const fastq = __webpack_require__(349); +const common = __webpack_require__(351); +const reader_1 = __webpack_require__(352); +class AsyncReader extends reader_1.default { + constructor(_root, _settings) { + super(_root, _settings); + this._settings = _settings; + this._scandir = fsScandir.scandir; + this._emitter = new events_1.EventEmitter(); + this._queue = fastq(this._worker.bind(this), this._settings.concurrency); + this._isFatalError = false; + this._isDestroyed = false; + this._queue.drain = () => { + if (!this._isFatalError) { + this._emitter.emit('end'); + } + }; + } + read() { + this._isFatalError = false; + this._isDestroyed = false; + setImmediate(() => { + this._pushToQueue(this._root, this._settings.basePath); + }); + return this._emitter; + } + destroy() { + if (this._isDestroyed) { + throw new Error('The reader is already destroyed'); + } + this._isDestroyed = true; + this._queue.killAndDrain(); + } + onEntry(callback) { + this._emitter.on('entry', callback); + } + onError(callback) { + this._emitter.once('error', callback); + } + onEnd(callback) { + this._emitter.once('end', callback); + } + _pushToQueue(directory, base) { + const queueItem = { directory, base }; + this._queue.push(queueItem, (error) => { + if (error !== null) { + this._handleError(error); + } + }); + } + _worker(item, done) { + this._scandir(item.directory, this._settings.fsScandirSettings, (error, entries) => { + if (error !== null) { + return done(error, undefined); + } + for (const entry of entries) { + this._handleEntry(entry, item.base); + } + done(null, undefined); + }); + } + _handleError(error) { + if (!common.isFatalError(this._settings, error)) { + return; + } + this._isFatalError = true; + this._isDestroyed = true; + this._emitter.emit('error', error); + } + _handleEntry(entry, base) { + if (this._isDestroyed || this._isFatalError) { + return; + } + const fullpath = entry.path; + if (base !== undefined) { + entry.path = common.joinPathSegments(base, entry.name, this._settings.pathSegmentSeparator); + } + if (common.isAppliedFilter(this._settings.entryFilter, entry)) { + this._emitEntry(entry); + } + if (entry.dirent.isDirectory() && common.isAppliedFilter(this._settings.deepFilter, entry)) { + this._pushToQueue(fullpath, entry.path); + } + } + _emitEntry(entry) { + this._emitter.emit('entry', entry); + } +} +exports.default = AsyncReader; /***/ }), -/* 331 */ +/* 340 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const async = __webpack_require__(341); +const sync = __webpack_require__(346); +const settings_1 = __webpack_require__(347); +exports.Settings = settings_1.default; +function scandir(path, optionsOrSettingsOrCallback, callback) { + if (typeof optionsOrSettingsOrCallback === 'function') { + return async.read(path, getSettings(), optionsOrSettingsOrCallback); + } + async.read(path, getSettings(optionsOrSettingsOrCallback), callback); +} +exports.scandir = scandir; +function scandirSync(path, optionsOrSettings) { + const settings = getSettings(optionsOrSettings); + return sync.read(path, settings); +} +exports.scandirSync = scandirSync; +function getSettings(settingsOrOptions = {}) { + if (settingsOrOptions instanceof settings_1.default) { + return settingsOrOptions; + } + return new settings_1.default(settingsOrOptions); +} -const path = __webpack_require__(4); -const WIN_SLASH = '\\\\/'; -const WIN_NO_SLASH = `[^${WIN_SLASH}]`; - -/** - * Posix glob regex - */ - -const DOT_LITERAL = '\\.'; -const PLUS_LITERAL = '\\+'; -const QMARK_LITERAL = '\\?'; -const SLASH_LITERAL = '\\/'; -const ONE_CHAR = '(?=.)'; -const QMARK = '[^/]'; -const END_ANCHOR = `(?:${SLASH_LITERAL}|$)`; -const START_ANCHOR = `(?:^|${SLASH_LITERAL})`; -const DOTS_SLASH = `${DOT_LITERAL}{1,2}${END_ANCHOR}`; -const NO_DOT = `(?!${DOT_LITERAL})`; -const NO_DOTS = `(?!${START_ANCHOR}${DOTS_SLASH})`; -const NO_DOT_SLASH = `(?!${DOT_LITERAL}{0,1}${END_ANCHOR})`; -const NO_DOTS_SLASH = `(?!${DOTS_SLASH})`; -const QMARK_NO_DOT = `[^.${SLASH_LITERAL}]`; -const STAR = `${QMARK}*?`; - -const POSIX_CHARS = { - DOT_LITERAL, - PLUS_LITERAL, - QMARK_LITERAL, - SLASH_LITERAL, - ONE_CHAR, - QMARK, - END_ANCHOR, - DOTS_SLASH, - NO_DOT, - NO_DOTS, - NO_DOT_SLASH, - NO_DOTS_SLASH, - QMARK_NO_DOT, - STAR, - START_ANCHOR -}; - -/** - * Windows glob regex - */ - -const WINDOWS_CHARS = { - ...POSIX_CHARS, +/***/ }), +/* 341 */ +/***/ (function(module, exports, __webpack_require__) { - SLASH_LITERAL: `[${WIN_SLASH}]`, - QMARK: WIN_NO_SLASH, - STAR: `${WIN_NO_SLASH}*?`, - DOTS_SLASH: `${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$)`, - NO_DOT: `(?!${DOT_LITERAL})`, - NO_DOTS: `(?!(?:^|[${WIN_SLASH}])${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`, - NO_DOT_SLASH: `(?!${DOT_LITERAL}{0,1}(?:[${WIN_SLASH}]|$))`, - NO_DOTS_SLASH: `(?!${DOT_LITERAL}{1,2}(?:[${WIN_SLASH}]|$))`, - QMARK_NO_DOT: `[^.${WIN_SLASH}]`, - START_ANCHOR: `(?:^|[${WIN_SLASH}])`, - END_ANCHOR: `(?:[${WIN_SLASH}]|$)` -}; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const fsStat = __webpack_require__(332); +const rpl = __webpack_require__(342); +const constants_1 = __webpack_require__(343); +const utils = __webpack_require__(344); +function read(directory, settings, callback) { + if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { + return readdirWithFileTypes(directory, settings, callback); + } + return readdir(directory, settings, callback); +} +exports.read = read; +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: `${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 !== null) { + return callFailureCallback(callback, rplError); + } + callSuccessCallback(callback, rplEntries); + }); + }); +} +exports.readdirWithFileTypes = readdirWithFileTypes; +function makeRplTaskEntry(entry, settings) { + return (done) => { + if (!entry.dirent.isSymbolicLink()) { + return done(null, entry); + } + settings.fs.stat(entry.path, (statError, stats) => { + if (statError !== null) { + if (settings.throwErrorOnBrokenSymbolicLink) { + return done(statError); + } + return done(null, entry); + } + entry.dirent = utils.fs.createDirentFromStats(entry.name, stats); + return done(null, entry); + }); + }; +} +function readdir(directory, settings, callback) { + settings.fs.readdir(directory, (readdirError, names) => { + if (readdirError !== null) { + return callFailureCallback(callback, readdirError); + } + 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 !== null) { + return callFailureCallback(callback, rplError); + } + const entries = []; + names.forEach((name, index) => { + const stats = results[index]; + const entry = { + name, + path: filepaths[index], + dirent: utils.fs.createDirentFromStats(name, stats) + }; + if (settings.stats) { + entry.stats = stats; + } + entries.push(entry); + }); + callSuccessCallback(callback, entries); + }); + }); +} +exports.readdir = readdir; +function callFailureCallback(callback, error) { + callback(error); +} +function callSuccessCallback(callback, result) { + callback(null, result); +} -/** - * POSIX Bracket Regex - */ -const POSIX_REGEX_SOURCE = { - 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' -}; +/***/ }), +/* 342 */ +/***/ (function(module, exports) { -module.exports = { - MAX_LENGTH: 1024 * 64, - POSIX_REGEX_SOURCE, +module.exports = runParallel - // regular expressions - REGEX_BACKSLASH: /\\(?![*+?^${}(|)[\]])/g, - REGEX_NON_SPECIAL_CHARS: /^[^@![\].,$*+?^{}()|\\/]+/, - REGEX_SPECIAL_CHARS: /[-*+?.^${}(|)[\]]/, - REGEX_SPECIAL_CHARS_BACKREF: /(\\?)((\W)(\3*))/g, - REGEX_SPECIAL_CHARS_GLOBAL: /([-*+?.^${}(|)[\]])/g, - REGEX_REMOVE_BACKSLASH: /(?:\[.*?[^\\]\]|\\(?=.))/g, +function runParallel (tasks, cb) { + var results, pending, keys + var isSync = true - // Replace globs with equivalent patterns to reduce parsing time. - REPLACEMENTS: { - '***': '*', - '**/**': '**', - '**/**/**': '**' - }, + if (Array.isArray(tasks)) { + results = [] + pending = tasks.length + } else { + keys = Object.keys(tasks) + results = {} + pending = keys.length + } - // Digits - CHAR_0: 48, /* 0 */ - CHAR_9: 57, /* 9 */ + function done (err) { + function end () { + if (cb) cb(err, results) + cb = null + } + if (isSync) process.nextTick(end) + else end() + } - // Alphabet chars. - CHAR_UPPERCASE_A: 65, /* A */ - CHAR_LOWERCASE_A: 97, /* a */ - CHAR_UPPERCASE_Z: 90, /* Z */ - CHAR_LOWERCASE_Z: 122, /* z */ + function each (i, err, result) { + results[i] = result + if (--pending === 0 || err) { + done(err) + } + } - CHAR_LEFT_PARENTHESES: 40, /* ( */ - CHAR_RIGHT_PARENTHESES: 41, /* ) */ + if (!pending) { + // empty + done(null) + } else if (keys) { + // object + keys.forEach(function (key) { + tasks[key](function (err, result) { each(key, err, result) }) + }) + } else { + // array + tasks.forEach(function (task, i) { + task(function (err, result) { each(i, err, result) }) + }) + } - CHAR_ASTERISK: 42, /* * */ + isSync = false +} - // Non-alphabetic chars. - CHAR_AMPERSAND: 38, /* & */ - CHAR_AT: 64, /* @ */ - CHAR_BACKWARD_SLASH: 92, /* \ */ - CHAR_CARRIAGE_RETURN: 13, /* \r */ - CHAR_CIRCUMFLEX_ACCENT: 94, /* ^ */ - CHAR_COLON: 58, /* : */ - CHAR_COMMA: 44, /* , */ - CHAR_DOT: 46, /* . */ - CHAR_DOUBLE_QUOTE: 34, /* " */ - CHAR_EQUAL: 61, /* = */ - CHAR_EXCLAMATION_MARK: 33, /* ! */ - CHAR_FORM_FEED: 12, /* \f */ - CHAR_FORWARD_SLASH: 47, /* / */ - CHAR_GRAVE_ACCENT: 96, /* ` */ - CHAR_HASH: 35, /* # */ - CHAR_HYPHEN_MINUS: 45, /* - */ - CHAR_LEFT_ANGLE_BRACKET: 60, /* < */ - CHAR_LEFT_CURLY_BRACE: 123, /* { */ - CHAR_LEFT_SQUARE_BRACKET: 91, /* [ */ - CHAR_LINE_FEED: 10, /* \n */ - CHAR_NO_BREAK_SPACE: 160, /* \u00A0 */ - CHAR_PERCENT: 37, /* % */ - CHAR_PLUS: 43, /* + */ - CHAR_QUESTION_MARK: 63, /* ? */ - CHAR_RIGHT_ANGLE_BRACKET: 62, /* > */ - CHAR_RIGHT_CURLY_BRACE: 125, /* } */ - CHAR_RIGHT_SQUARE_BRACKET: 93, /* ] */ - CHAR_SEMICOLON: 59, /* ; */ - CHAR_SINGLE_QUOTE: 39, /* ' */ - CHAR_SPACE: 32, /* */ - CHAR_TAB: 9, /* \t */ - CHAR_UNDERSCORE: 95, /* _ */ - CHAR_VERTICAL_LINE: 124, /* | */ - CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279, /* \uFEFF */ - SEP: path.sep, +/***/ }), +/* 343 */ +/***/ (function(module, exports, __webpack_require__) { - /** - * Create EXTGLOB_CHARS - */ +"use strict"; + +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 = IS_MATCHED_BY_MAJOR || IS_MATCHED_BY_MAJOR_AND_MINOR; - extglobChars(chars) { - return { - '!': { type: 'negate', open: '(?:(?!(?:', close: `))${chars.STAR})` }, - '?': { type: 'qmark', open: '(?:', close: ')?' }, - '+': { type: 'plus', open: '(?:', close: ')+' }, - '*': { type: 'star', open: '(?:', close: ')*' }, - '@': { type: 'at', open: '(?:', close: ')' } - }; - }, - /** - * Create GLOB_CHARS - */ +/***/ }), +/* 344 */ +/***/ (function(module, exports, __webpack_require__) { - globChars(win32) { - return win32 === true ? WINDOWS_CHARS : POSIX_CHARS; - } -}; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const fs = __webpack_require__(345); +exports.fs = fs; /***/ }), -/* 332 */ +/* 345 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +class DirentFromStats { + constructor(name, stats) { + this.name = name; + this.isBlockDevice = stats.isBlockDevice.bind(stats); + this.isCharacterDevice = stats.isCharacterDevice.bind(stats); + this.isDirectory = stats.isDirectory.bind(stats); + this.isFIFO = stats.isFIFO.bind(stats); + this.isFile = stats.isFile.bind(stats); + this.isSocket = stats.isSocket.bind(stats); + this.isSymbolicLink = stats.isSymbolicLink.bind(stats); + } +} +function createDirentFromStats(name, stats) { + return new DirentFromStats(name, stats); +} +exports.createDirentFromStats = createDirentFromStats; -const constants = __webpack_require__(331); -const utils = __webpack_require__(330); +/***/ }), +/* 346 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Constants - */ - -const { - MAX_LENGTH, - POSIX_REGEX_SOURCE, - REGEX_NON_SPECIAL_CHARS, - REGEX_SPECIAL_CHARS_BACKREF, - REPLACEMENTS -} = constants; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const fsStat = __webpack_require__(332); +const constants_1 = __webpack_require__(343); +const utils = __webpack_require__(344); +function read(directory, settings) { + if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { + return readdirWithFileTypes(directory, settings); + } + return readdir(directory, settings); +} +exports.read = read; +function readdirWithFileTypes(directory, settings) { + const dirents = settings.fs.readdirSync(directory, { withFileTypes: true }); + return dirents.map((dirent) => { + const entry = { + dirent, + name: dirent.name, + path: `${directory}${settings.pathSegmentSeparator}${dirent.name}` + }; + if (entry.dirent.isSymbolicLink() && settings.followSymbolicLinks) { + try { + const stats = settings.fs.statSync(entry.path); + entry.dirent = utils.fs.createDirentFromStats(entry.name, stats); + } + catch (error) { + if (settings.throwErrorOnBrokenSymbolicLink) { + throw error; + } + } + } + return entry; + }); +} +exports.readdirWithFileTypes = readdirWithFileTypes; +function readdir(directory, settings) { + const names = settings.fs.readdirSync(directory); + return names.map((name) => { + const entryPath = `${directory}${settings.pathSegmentSeparator}${name}`; + const stats = fsStat.statSync(entryPath, settings.fsStatSettings); + const entry = { + name, + path: entryPath, + dirent: utils.fs.createDirentFromStats(name, stats) + }; + if (settings.stats) { + entry.stats = stats; + } + return entry; + }); +} +exports.readdir = readdir; -/** - * Helpers - */ -const expandRange = (args, options) => { - if (typeof options.expandRange === 'function') { - return options.expandRange(...args, options); - } +/***/ }), +/* 347 */ +/***/ (function(module, exports, __webpack_require__) { - args.sort(); - const value = `[${args.join('-')}]`; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const path = __webpack_require__(4); +const fsStat = __webpack_require__(332); +const fs = __webpack_require__(348); +class Settings { + constructor(_options = {}) { + this._options = _options; + this.followSymbolicLinks = this._getValue(this._options.followSymbolicLinks, false); + this.fs = fs.createFileSystemAdapter(this._options.fs); + this.pathSegmentSeparator = this._getValue(this._options.pathSegmentSeparator, path.sep); + this.stats = this._getValue(this._options.stats, false); + this.throwErrorOnBrokenSymbolicLink = this._getValue(this._options.throwErrorOnBrokenSymbolicLink, true); + this.fsStatSettings = new fsStat.Settings({ + followSymbolicLink: this.followSymbolicLinks, + fs: this.fs, + throwErrorOnBrokenSymbolicLink: this.throwErrorOnBrokenSymbolicLink + }); + } + _getValue(option, value) { + return option === undefined ? value : option; + } +} +exports.default = Settings; - try { - /* eslint-disable-next-line no-new */ - new RegExp(value); - } catch (ex) { - return args.map(v => utils.escapeRegex(v)).join('..'); - } - return value; -}; +/***/ }), +/* 348 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Create the message for a syntax error - */ +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const fs = __webpack_require__(133); +exports.FILE_SYSTEM_ADAPTER = { + lstat: fs.lstat, + stat: fs.stat, + lstatSync: fs.lstatSync, + statSync: fs.statSync, + readdir: fs.readdir, + readdirSync: fs.readdirSync +}; +function createFileSystemAdapter(fsMethods) { + if (fsMethods === undefined) { + return exports.FILE_SYSTEM_ADAPTER; + } + return Object.assign(Object.assign({}, exports.FILE_SYSTEM_ADAPTER), fsMethods); +} +exports.createFileSystemAdapter = createFileSystemAdapter; -const syntaxError = (type, char) => { - return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`; -}; -/** - * Parse the given input string. - * @param {String} input - * @param {Object} options - * @return {Object} - */ +/***/ }), +/* 349 */ +/***/ (function(module, exports, __webpack_require__) { -const parse = (input, options) => { - if (typeof input !== 'string') { - throw new TypeError('Expected a string'); - } +"use strict"; - input = REPLACEMENTS[input] || input; - const opts = { ...options }; - const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; +var reusify = __webpack_require__(350) - let len = input.length; - if (len > max) { - throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`); +function fastqueue (context, worker, concurrency) { + if (typeof context === 'function') { + concurrency = worker + worker = context + context = null } - const bos = { type: 'bos', value: '', output: opts.prepend || '' }; - const tokens = [bos]; - - const capture = opts.capture ? '' : '?:'; - const win32 = utils.isWindows(options); - - // create constants based on platform, for windows or posix - const PLATFORM_CHARS = constants.globChars(win32); - const EXTGLOB_CHARS = constants.extglobChars(PLATFORM_CHARS); - - const { - DOT_LITERAL, - PLUS_LITERAL, - SLASH_LITERAL, - ONE_CHAR, - DOTS_SLASH, - NO_DOT, - NO_DOT_SLASH, - NO_DOTS_SLASH, - QMARK, - QMARK_NO_DOT, - STAR, - START_ANCHOR - } = PLATFORM_CHARS; + var cache = reusify(Task) + var queueHead = null + var queueTail = null + var _running = 0 - const globstar = (opts) => { - return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`; - }; + var self = { + push: push, + drain: noop, + saturated: noop, + pause: pause, + paused: false, + concurrency: concurrency, + running: running, + resume: resume, + idle: idle, + length: length, + unshift: unshift, + empty: noop, + kill: kill, + killAndDrain: killAndDrain + } - const nodot = opts.dot ? '' : NO_DOT; - const qmarkNoDot = opts.dot ? QMARK : QMARK_NO_DOT; - let star = opts.bash === true ? globstar(opts) : STAR; + return self - if (opts.capture) { - star = `(${star})`; + function running () { + return _running } - // minimatch options support - if (typeof opts.noext === 'boolean') { - opts.noextglob = opts.noext; + function pause () { + self.paused = true } - const state = { - input, - index: -1, - start: 0, - dot: opts.dot === true, - consumed: '', - output: '', - prefix: '', - backtrack: false, - negated: false, - brackets: 0, - braces: 0, - parens: 0, - quotes: 0, - globstar: false, - tokens - }; - - input = utils.removePrefix(input, state); - len = input.length; - - const extglobs = []; - const braces = []; - const stack = []; - let prev = bos; - let value; - - /** - * Tokenizing helpers - */ + function length () { + var current = queueHead + var counter = 0 - const eos = () => state.index === len - 1; - const peek = state.peek = (n = 1) => input[state.index + n]; - const advance = state.advance = () => input[++state.index]; - const remaining = () => input.slice(state.index + 1); - const consume = (value = '', num = 0) => { - state.consumed += value; - state.index += num; - }; - const append = token => { - state.output += token.output != null ? token.output : token.value; - consume(token.value); - }; + while (current) { + current = current.next + counter++ + } - const negate = () => { - let count = 1; + return counter + } - while (peek() === '!' && (peek(2) !== '(' || peek(3) === '?')) { - advance(); - state.start++; - count++; + function resume () { + if (!self.paused) return + self.paused = false + for (var i = 0; i < self.concurrency; i++) { + _running++ + release() } + } - if (count % 2 === 0) { - return false; - } + function idle () { + return _running === 0 && self.length() === 0 + } - state.negated = true; - state.start++; - return true; - }; + function push (value, done) { + var current = cache.get() - const increment = type => { - state[type]++; - stack.push(type); - }; + current.context = context + current.release = release + current.value = value + current.callback = done || noop - const decrement = type => { - state[type]--; - stack.pop(); - }; + if (_running === self.concurrency || self.paused) { + if (queueTail) { + queueTail.next = current + queueTail = current + } else { + queueHead = current + queueTail = current + self.saturated() + } + } else { + _running++ + worker.call(context, current.value, current.worked) + } + } - /** - * Push tokens onto the tokens array. This helper speeds up - * tokenizing by 1) helping us avoid backtracking as much as possible, - * and 2) helping us avoid creating extra tokens when consecutive - * characters are plain text. This improves performance and simplifies - * lookbehinds. - */ + function unshift (value, done) { + var current = cache.get() - const push = tok => { - if (prev.type === 'globstar') { - const isBrace = state.braces > 0 && (tok.type === 'comma' || tok.type === 'brace'); - const isExtglob = tok.extglob === true || (extglobs.length && (tok.type === 'pipe' || tok.type === 'paren')); + current.context = context + current.release = release + current.value = value + current.callback = done || noop - if (tok.type !== 'slash' && tok.type !== 'paren' && !isBrace && !isExtglob) { - state.output = state.output.slice(0, -prev.output.length); - prev.type = 'star'; - prev.value = '*'; - prev.output = star; - state.output += prev.output; + if (_running === self.concurrency || self.paused) { + if (queueHead) { + current.next = queueHead + queueHead = current + } else { + queueHead = current + queueTail = current + self.saturated() } + } else { + _running++ + worker.call(context, current.value, current.worked) } + } - if (extglobs.length && tok.type !== 'paren' && !EXTGLOB_CHARS[tok.value]) { - extglobs[extglobs.length - 1].inner += tok.value; + function release (holder) { + if (holder) { + cache.release(holder) } - - if (tok.value || tok.output) append(tok); - if (prev && prev.type === 'text' && tok.type === 'text') { - prev.value += tok.value; - prev.output = (prev.output || '') + tok.value; - return; + var next = queueHead + if (next) { + if (!self.paused) { + if (queueTail === queueHead) { + queueTail = null + } + queueHead = next.next + next.next = null + worker.call(context, next.value, next.worked) + if (queueTail === null) { + self.empty() + } + } else { + _running-- + } + } else if (--_running === 0) { + self.drain() } + } - tok.prev = prev; - tokens.push(tok); - prev = tok; - }; - - const extglobOpen = (type, value) => { - const token = { ...EXTGLOB_CHARS[value], conditions: 1, inner: '' }; - - token.prev = prev; - token.parens = state.parens; - token.output = state.output; - const output = (opts.capture ? '(' : '') + token.open; - - increment('parens'); - push({ type, value, output: state.output ? '' : ONE_CHAR }); - push({ type: 'paren', extglob: true, value: advance(), output }); - extglobs.push(token); - }; + function kill () { + queueHead = null + queueTail = null + self.drain = noop + } - const extglobClose = token => { - let output = token.close + (opts.capture ? ')' : ''); + function killAndDrain () { + queueHead = null + queueTail = null + self.drain() + self.drain = noop + } +} - if (token.type === 'negate') { - let extglobStar = star; +function noop () {} - if (token.inner && token.inner.length > 1 && token.inner.includes('/')) { - extglobStar = globstar(opts); - } +function Task () { + this.value = null + this.callback = noop + this.next = null + this.release = noop + this.context = null - if (extglobStar !== star || eos() || /^\)+$/.test(remaining())) { - output = token.close = `)$))${extglobStar}`; - } + var self = this - if (token.prev.type === 'bos' && eos()) { - state.negatedExtglob = true; - } - } + this.worked = function worked (err, result) { + var callback = self.callback + self.value = null + self.callback = noop + callback.call(self.context, err, result) + self.release(self) + } +} - push({ type: 'paren', extglob: true, value, output }); - decrement('parens'); - }; +module.exports = fastqueue - /** - * Fast paths - */ - if (opts.fastpaths !== false && !/(^[*!]|[/()[\]{}"])/.test(input)) { - let backslashes = false; +/***/ }), +/* 350 */ +/***/ (function(module, exports, __webpack_require__) { - let output = input.replace(REGEX_SPECIAL_CHARS_BACKREF, (m, esc, chars, first, rest, index) => { - if (first === '\\') { - backslashes = true; - return m; - } +"use strict"; - if (first === '?') { - if (esc) { - return esc + first + (rest ? QMARK.repeat(rest.length) : ''); - } - if (index === 0) { - return qmarkNoDot + (rest ? QMARK.repeat(rest.length) : ''); - } - return QMARK.repeat(chars.length); - } - if (first === '.') { - return DOT_LITERAL.repeat(chars.length); - } +function reusify (Constructor) { + var head = new Constructor() + var tail = head - if (first === '*') { - if (esc) { - return esc + first + (rest ? star : ''); - } - return star; - } - return esc ? m : `\\${m}`; - }); + function get () { + var current = head - if (backslashes === true) { - if (opts.unescape === true) { - output = output.replace(/\\/g, ''); - } else { - output = output.replace(/\\+/g, m => { - return m.length % 2 === 0 ? '\\\\' : (m ? '\\' : ''); - }); - } + if (current.next) { + head = current.next + } else { + head = new Constructor() + tail = head } - if (output === input && opts.contains === true) { - state.output = input; - return state; - } + current.next = null - state.output = utils.wrapOutput(output, state, options); - return state; + return current } - /** - * Tokenize input until we reach end-of-string - */ + function release (obj) { + tail.next = obj + tail = obj + } - while (!eos()) { - value = advance(); + return { + get: get, + release: release + } +} - if (value === '\u0000') { - continue; - } +module.exports = reusify - /** - * Escaped characters - */ - if (value === '\\') { - const next = peek(); +/***/ }), +/* 351 */ +/***/ (function(module, exports, __webpack_require__) { - if (next === '/' && opts.bash !== true) { - continue; - } +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function isFatalError(settings, error) { + if (settings.errorFilter === null) { + return true; + } + return !settings.errorFilter(error); +} +exports.isFatalError = isFatalError; +function isAppliedFilter(filter, value) { + return filter === null || filter(value); +} +exports.isAppliedFilter = isAppliedFilter; +function replacePathSegmentSeparator(filepath, separator) { + return filepath.split(/[\\/]/).join(separator); +} +exports.replacePathSegmentSeparator = replacePathSegmentSeparator; +function joinPathSegments(a, b, separator) { + if (a === '') { + return b; + } + return a + separator + b; +} +exports.joinPathSegments = joinPathSegments; - if (next === '.' || next === ';') { - continue; - } - if (!next) { - value += '\\'; - push({ type: 'text', value }); - continue; - } +/***/ }), +/* 352 */ +/***/ (function(module, exports, __webpack_require__) { - // collapse slashes to reduce potential for exploits - const match = /^\\+/.exec(remaining()); - let slashes = 0; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const common = __webpack_require__(351); +class Reader { + constructor(_root, _settings) { + this._root = _root; + this._settings = _settings; + this._root = common.replacePathSegmentSeparator(_root, _settings.pathSegmentSeparator); + } +} +exports.default = Reader; - if (match && match[0].length > 2) { - slashes = match[0].length; - state.index += slashes; - if (slashes % 2 !== 0) { - value += '\\'; - } - } - if (opts.unescape === true) { - value = advance() || ''; - } else { - value += advance() || ''; - } +/***/ }), +/* 353 */ +/***/ (function(module, exports, __webpack_require__) { - if (state.brackets === 0) { - push({ type: 'text', value }); - continue; - } - } +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const stream_1 = __webpack_require__(137); +const async_1 = __webpack_require__(339); +class StreamProvider { + constructor(_root, _settings) { + this._root = _root; + this._settings = _settings; + this._reader = new async_1.default(this._root, this._settings); + this._stream = new stream_1.Readable({ + objectMode: true, + read: () => { }, + destroy: this._reader.destroy.bind(this._reader) + }); + } + read() { + this._reader.onError((error) => { + this._stream.emit('error', error); + }); + this._reader.onEntry((entry) => { + this._stream.push(entry); + }); + this._reader.onEnd(() => { + this._stream.push(null); + }); + this._reader.read(); + return this._stream; + } +} +exports.default = StreamProvider; - /** - * If we're inside a regex character class, continue - * until we reach the closing bracket. - */ - if (state.brackets > 0 && (value !== ']' || prev.value === '[' || prev.value === '[^')) { - if (opts.posix !== false && value === ':') { - const inner = prev.value.slice(1); - if (inner.includes('[')) { - prev.posix = true; +/***/ }), +/* 354 */ +/***/ (function(module, exports, __webpack_require__) { - if (inner.includes(':')) { - const idx = prev.value.lastIndexOf('['); - const pre = prev.value.slice(0, idx); - const rest = prev.value.slice(idx + 2); - const posix = POSIX_REGEX_SOURCE[rest]; - if (posix) { - prev.value = pre + posix; - state.backtrack = true; - advance(); +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const sync_1 = __webpack_require__(355); +class SyncProvider { + constructor(_root, _settings) { + this._root = _root; + this._settings = _settings; + this._reader = new sync_1.default(this._root, this._settings); + } + read() { + return this._reader.read(); + } +} +exports.default = SyncProvider; - if (!bos.output && tokens.indexOf(prev) === 1) { - bos.output = ONE_CHAR; - } - continue; - } - } - } - } - if ((value === '[' && peek() !== ':') || (value === '-' && peek() === ']')) { - value = `\\${value}`; - } +/***/ }), +/* 355 */ +/***/ (function(module, exports, __webpack_require__) { - if (value === ']' && (prev.value === '[' || prev.value === '[^')) { - value = `\\${value}`; - } +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const fsScandir = __webpack_require__(340); +const common = __webpack_require__(351); +const reader_1 = __webpack_require__(352); +class SyncReader extends reader_1.default { + constructor() { + super(...arguments); + this._scandir = fsScandir.scandirSync; + this._storage = new Set(); + this._queue = new Set(); + } + read() { + this._pushToQueue(this._root, this._settings.basePath); + this._handleQueue(); + return [...this._storage]; + } + _pushToQueue(directory, base) { + this._queue.add({ directory, base }); + } + _handleQueue() { + for (const item of this._queue.values()) { + this._handleDirectory(item.directory, item.base); + } + } + _handleDirectory(directory, base) { + try { + const entries = this._scandir(directory, this._settings.fsScandirSettings); + for (const entry of entries) { + this._handleEntry(entry, base); + } + } + catch (error) { + this._handleError(error); + } + } + _handleError(error) { + if (!common.isFatalError(this._settings, error)) { + return; + } + throw error; + } + _handleEntry(entry, base) { + const fullpath = entry.path; + if (base !== undefined) { + entry.path = common.joinPathSegments(base, entry.name, this._settings.pathSegmentSeparator); + } + if (common.isAppliedFilter(this._settings.entryFilter, entry)) { + this._pushToStorage(entry); + } + if (entry.dirent.isDirectory() && common.isAppliedFilter(this._settings.deepFilter, entry)) { + this._pushToQueue(fullpath, entry.path); + } + } + _pushToStorage(entry) { + this._storage.add(entry); + } +} +exports.default = SyncReader; - if (opts.posix === true && value === '!' && prev.value === '[') { - value = '^'; - } - prev.value += value; - append({ value }); - continue; - } +/***/ }), +/* 356 */ +/***/ (function(module, exports, __webpack_require__) { - /** - * If we're inside a quoted string, continue - * until we reach the closing double quote. - */ +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const path = __webpack_require__(4); +const fsScandir = __webpack_require__(340); +class Settings { + constructor(_options = {}) { + this._options = _options; + this.basePath = this._getValue(this._options.basePath, undefined); + this.concurrency = this._getValue(this._options.concurrency, Infinity); + this.deepFilter = this._getValue(this._options.deepFilter, null); + this.entryFilter = this._getValue(this._options.entryFilter, null); + this.errorFilter = this._getValue(this._options.errorFilter, null); + this.pathSegmentSeparator = this._getValue(this._options.pathSegmentSeparator, path.sep); + this.fsScandirSettings = new fsScandir.Settings({ + followSymbolicLinks: this._options.followSymbolicLinks, + fs: this._options.fs, + pathSegmentSeparator: this._options.pathSegmentSeparator, + stats: this._options.stats, + throwErrorOnBrokenSymbolicLink: this._options.throwErrorOnBrokenSymbolicLink + }); + } + _getValue(option, value) { + return option === undefined ? value : option; + } +} +exports.default = Settings; - if (state.quotes === 1 && value !== '"') { - value = utils.escapeRegex(value); - prev.value += value; - append({ value }); - continue; - } - /** - * Double quotes - */ +/***/ }), +/* 357 */ +/***/ (function(module, exports, __webpack_require__) { - if (value === '"') { - state.quotes = state.quotes === 1 ? 0 : 1; - if (opts.keepQuotes === true) { - push({ type: 'text', value }); - } - continue; - } +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const path = __webpack_require__(4); +const fsStat = __webpack_require__(332); +const utils = __webpack_require__(302); +class Reader { + constructor(_settings) { + this._settings = _settings; + this._fsStatSettings = new fsStat.Settings({ + followSymbolicLink: this._settings.followSymbolicLinks, + fs: this._settings.fs, + throwErrorOnBrokenSymbolicLink: this._settings.followSymbolicLinks + }); + } + _getFullEntryPath(filepath) { + return path.resolve(this._settings.cwd, filepath); + } + _makeEntry(stats, pattern) { + const entry = { + name: pattern, + path: pattern, + dirent: utils.fs.createDirentFromStats(pattern, stats) + }; + if (this._settings.stats) { + entry.stats = stats; + } + return entry; + } + _isFatalError(error) { + return !utils.errno.isEnoentCodeError(error) && !this._settings.suppressErrors; + } +} +exports.default = Reader; - /** - * Parentheses - */ - if (value === '(') { - increment('parens'); - push({ type: 'paren', value }); - continue; - } +/***/ }), +/* 358 */ +/***/ (function(module, exports, __webpack_require__) { - if (value === ')') { - if (state.parens === 0 && opts.strictBrackets === true) { - throw new SyntaxError(syntaxError('opening', '(')); - } +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const path = __webpack_require__(4); +const deep_1 = __webpack_require__(359); +const entry_1 = __webpack_require__(362); +const error_1 = __webpack_require__(363); +const entry_2 = __webpack_require__(364); +class Provider { + constructor(_settings) { + this._settings = _settings; + this.errorFilter = new error_1.default(this._settings); + this.entryFilter = new entry_1.default(this._settings, this._getMicromatchOptions()); + this.deepFilter = new deep_1.default(this._settings, this._getMicromatchOptions()); + this.entryTransformer = new entry_2.default(this._settings); + } + _getRootDirectory(task) { + return path.resolve(this._settings.cwd, task.base); + } + _getReaderOptions(task) { + const basePath = task.base === '.' ? '' : task.base; + return { + basePath, + pathSegmentSeparator: '/', + concurrency: this._settings.concurrency, + deepFilter: this.deepFilter.getFilter(basePath, task.positive, task.negative), + entryFilter: this.entryFilter.getFilter(task.positive, task.negative), + errorFilter: this.errorFilter.getFilter(), + followSymbolicLinks: this._settings.followSymbolicLinks, + fs: this._settings.fs, + stats: this._settings.stats, + throwErrorOnBrokenSymbolicLink: this._settings.throwErrorOnBrokenSymbolicLink, + transform: this.entryTransformer.getTransformer() + }; + } + _getMicromatchOptions() { + return { + dot: this._settings.dot, + matchBase: this._settings.baseNameMatch, + nobrace: !this._settings.braceExpansion, + nocase: !this._settings.caseSensitiveMatch, + noext: !this._settings.extglob, + noglobstar: !this._settings.globstar, + posix: true, + strictSlashes: false + }; + } +} +exports.default = Provider; - const extglob = extglobs[extglobs.length - 1]; - if (extglob && state.parens === extglob.parens + 1) { - extglobClose(extglobs.pop()); - continue; - } - push({ type: 'paren', value, output: state.parens ? ')' : '\\)' }); - decrement('parens'); - continue; - } +/***/ }), +/* 359 */ +/***/ (function(module, exports, __webpack_require__) { - /** - * Square brackets - */ +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const utils = __webpack_require__(302); +const partial_1 = __webpack_require__(360); +class DeepFilter { + constructor(_settings, _micromatchOptions) { + this._settings = _settings; + this._micromatchOptions = _micromatchOptions; + } + getFilter(basePath, positive, negative) { + const matcher = this._getMatcher(positive); + const negativeRe = this._getNegativePatternsRe(negative); + return (entry) => this._filter(basePath, entry, matcher, negativeRe); + } + _getMatcher(patterns) { + return new partial_1.default(patterns, this._settings, this._micromatchOptions); + } + _getNegativePatternsRe(patterns) { + const affectDepthOfReadingPatterns = patterns.filter(utils.pattern.isAffectDepthOfReadingPattern); + return utils.pattern.convertPatternsToRe(affectDepthOfReadingPatterns, this._micromatchOptions); + } + _filter(basePath, entry, matcher, negativeRe) { + const depth = this._getEntryLevel(basePath, entry.path); + if (this._isSkippedByDeep(depth)) { + return false; + } + if (this._isSkippedSymbolicLink(entry)) { + return false; + } + const filepath = utils.path.removeLeadingDotSegment(entry.path); + if (this._isSkippedByPositivePatterns(filepath, matcher)) { + return false; + } + return this._isSkippedByNegativePatterns(filepath, negativeRe); + } + _isSkippedByDeep(entryDepth) { + return entryDepth >= this._settings.deep; + } + _isSkippedSymbolicLink(entry) { + return !this._settings.followSymbolicLinks && entry.dirent.isSymbolicLink(); + } + _getEntryLevel(basePath, entryPath) { + const basePathDepth = basePath.split('/').length; + const entryPathDepth = entryPath.split('/').length; + return entryPathDepth - (basePath === '' ? 0 : basePathDepth); + } + _isSkippedByPositivePatterns(entryPath, matcher) { + return !this._settings.baseNameMatch && !matcher.match(entryPath); + } + _isSkippedByNegativePatterns(entryPath, negativeRe) { + return !utils.pattern.matchAny(entryPath, negativeRe); + } +} +exports.default = DeepFilter; - if (value === '[') { - if (opts.nobracket === true || !remaining().includes(']')) { - if (opts.nobracket !== true && opts.strictBrackets === true) { - throw new SyntaxError(syntaxError('closing', ']')); - } - value = `\\${value}`; - } else { - increment('brackets'); - } +/***/ }), +/* 360 */ +/***/ (function(module, exports, __webpack_require__) { - push({ type: 'bracket', value }); - continue; - } +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const matcher_1 = __webpack_require__(361); +class PartialMatcher extends matcher_1.default { + match(filepath) { + const parts = filepath.split('/'); + const levels = parts.length; + const patterns = this._storage.filter((info) => !info.complete || info.segments.length > levels); + for (const pattern of patterns) { + const section = pattern.sections[0]; + /** + * In this case, the pattern has a globstar and we must read all directories unconditionally, + * but only if the level has reached the end of the first group. + * + * fixtures/{a,b}/** + * ^ true/false ^ always true + */ + if (!pattern.complete && levels > section.length) { + return true; + } + const match = parts.every((part, index) => { + const segment = pattern.segments[index]; + if (segment.dynamic && segment.patternRe.test(part)) { + return true; + } + if (!segment.dynamic && segment.pattern === part) { + return true; + } + return false; + }); + if (match) { + return true; + } + } + return false; + } +} +exports.default = PartialMatcher; - if (value === ']') { - if (opts.nobracket === true || (prev && prev.type === 'bracket' && prev.value.length === 1)) { - push({ type: 'text', value, output: `\\${value}` }); - continue; - } - if (state.brackets === 0) { - if (opts.strictBrackets === true) { - throw new SyntaxError(syntaxError('opening', '[')); - } - - push({ type: 'text', value, output: `\\${value}` }); - continue; - } - - decrement('brackets'); - - const prevValue = prev.value.slice(1); - if (prev.posix !== true && prevValue[0] === '^' && !prevValue.includes('/')) { - value = `/${value}`; - } - - prev.value += value; - append({ value }); - - // when literal brackets are explicitly disabled - // assume we should match with a regex character class - if (opts.literalBrackets === false || utils.hasRegexChars(prevValue)) { - continue; - } - - const escaped = utils.escapeRegex(prev.value); - state.output = state.output.slice(0, -prev.value.length); - - // when literal brackets are explicitly enabled - // assume we should escape the brackets to match literal characters - if (opts.literalBrackets === true) { - state.output += escaped; - prev.value = escaped; - continue; - } - - // when the user specifies nothing, try to match both - prev.value = `(${capture}${escaped}|${prev.value})`; - state.output += prev.value; - continue; - } - - /** - * Braces - */ - - if (value === '{' && opts.nobrace !== true) { - increment('braces'); - - const open = { - type: 'brace', - value, - output: '(', - outputIndex: state.output.length, - tokensIndex: state.tokens.length - }; - - braces.push(open); - push(open); - continue; - } - - if (value === '}') { - const brace = braces[braces.length - 1]; - - if (opts.nobrace === true || !brace) { - push({ type: 'text', value, output: value }); - continue; - } - - let output = ')'; - - if (brace.dots === true) { - const arr = tokens.slice(); - const range = []; - - for (let i = arr.length - 1; i >= 0; i--) { - tokens.pop(); - if (arr[i].type === 'brace') { - break; - } - if (arr[i].type !== 'dots') { - range.unshift(arr[i].value); - } - } - - output = expandRange(range, opts); - state.backtrack = true; - } - - if (brace.comma !== true && brace.dots !== true) { - const out = state.output.slice(0, brace.outputIndex); - const toks = state.tokens.slice(brace.tokensIndex); - brace.value = brace.output = '\\{'; - value = output = '\\}'; - state.output = out; - for (const t of toks) { - state.output += (t.output || t.value); - } - } - - push({ type: 'brace', value, output }); - decrement('braces'); - braces.pop(); - continue; - } - - /** - * Pipes - */ - - if (value === '|') { - if (extglobs.length > 0) { - extglobs[extglobs.length - 1].conditions++; - } - push({ type: 'text', value }); - continue; - } - - /** - * Commas - */ - - if (value === ',') { - let output = value; - - const brace = braces[braces.length - 1]; - if (brace && stack[stack.length - 1] === 'braces') { - brace.comma = true; - output = '|'; - } - - push({ type: 'comma', value, output }); - continue; - } - - /** - * Slashes - */ - - if (value === '/') { - // if the beginning of the glob is "./", advance the start - // to the current index, and don't add the "./" characters - // to the state. This greatly simplifies lookbehinds when - // checking for BOS characters like "!" and "." (not "./") - if (prev.type === 'dot' && state.index === state.start + 1) { - state.start = state.index + 1; - state.consumed = ''; - state.output = ''; - tokens.pop(); - prev = bos; // reset "prev" to the first token - continue; - } - - push({ type: 'slash', value, output: SLASH_LITERAL }); - continue; - } - - /** - * Dots - */ - - if (value === '.') { - if (state.braces > 0 && prev.type === 'dot') { - if (prev.value === '.') prev.output = DOT_LITERAL; - const brace = braces[braces.length - 1]; - prev.type = 'dots'; - prev.output += value; - prev.value += value; - brace.dots = true; - continue; - } - - if ((state.braces + state.parens) === 0 && prev.type !== 'bos' && prev.type !== 'slash') { - push({ type: 'text', value, output: DOT_LITERAL }); - continue; - } - - push({ type: 'dot', value, output: DOT_LITERAL }); - continue; - } - - /** - * Question marks - */ - - if (value === '?') { - const isGroup = prev && prev.value === '('; - if (!isGroup && opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { - extglobOpen('qmark', value); - continue; - } - - if (prev && prev.type === 'paren') { - const next = peek(); - let output = value; - - if (next === '<' && !utils.supportsLookbehinds()) { - throw new Error('Node.js v10 or higher is required for regex lookbehinds'); - } - - if ((prev.value === '(' && !/[!=<:]/.test(next)) || (next === '<' && !/<([!=]|\w+>)/.test(remaining()))) { - output = `\\${value}`; - } - - push({ type: 'text', value, output }); - continue; - } - - if (opts.dot !== true && (prev.type === 'slash' || prev.type === 'bos')) { - push({ type: 'qmark', value, output: QMARK_NO_DOT }); - continue; - } - - push({ type: 'qmark', value, output: QMARK }); - continue; - } - - /** - * Exclamation - */ - - if (value === '!') { - if (opts.noextglob !== true && peek() === '(') { - if (peek(2) !== '?' || !/[!=<:]/.test(peek(3))) { - extglobOpen('negate', value); - continue; - } - } - - if (opts.nonegate !== true && state.index === 0) { - negate(); - continue; - } - } - - /** - * Plus - */ - - if (value === '+') { - if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { - extglobOpen('plus', value); - continue; - } - - if ((prev && prev.value === '(') || opts.regex === false) { - push({ type: 'plus', value, output: PLUS_LITERAL }); - continue; - } - - if ((prev && (prev.type === 'bracket' || prev.type === 'paren' || prev.type === 'brace')) || state.parens > 0) { - push({ type: 'plus', value }); - continue; - } - - push({ type: 'plus', value: PLUS_LITERAL }); - continue; - } - - /** - * Plain text - */ - - if (value === '@') { - if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { - push({ type: 'at', extglob: true, value, output: '' }); - continue; - } - - push({ type: 'text', value }); - continue; - } - - /** - * Plain text - */ - - if (value !== '*') { - if (value === '$' || value === '^') { - value = `\\${value}`; - } - - const match = REGEX_NON_SPECIAL_CHARS.exec(remaining()); - if (match) { - value += match[0]; - state.index += match[0].length; - } - - push({ type: 'text', value }); - continue; - } - - /** - * Stars - */ - - if (prev && (prev.type === 'globstar' || prev.star === true)) { - prev.type = 'star'; - prev.star = true; - prev.value += value; - prev.output = star; - state.backtrack = true; - state.globstar = true; - consume(value); - continue; - } - - let rest = remaining(); - if (opts.noextglob !== true && /^\([^?]/.test(rest)) { - extglobOpen('star', value); - continue; - } - - if (prev.type === 'star') { - if (opts.noglobstar === true) { - consume(value); - continue; - } - - const prior = prev.prev; - const before = prior.prev; - const isStart = prior.type === 'slash' || prior.type === 'bos'; - const afterStar = before && (before.type === 'star' || before.type === 'globstar'); - - if (opts.bash === true && (!isStart || (rest[0] && rest[0] !== '/'))) { - push({ type: 'star', value, output: '' }); - continue; - } - - const isBrace = state.braces > 0 && (prior.type === 'comma' || prior.type === 'brace'); - const isExtglob = extglobs.length && (prior.type === 'pipe' || prior.type === 'paren'); - if (!isStart && prior.type !== 'paren' && !isBrace && !isExtglob) { - push({ type: 'star', value, output: '' }); - continue; - } - - // strip consecutive `/**/` - while (rest.slice(0, 3) === '/**') { - const after = input[state.index + 4]; - if (after && after !== '/') { - break; - } - rest = rest.slice(3); - consume('/**', 3); - } - - if (prior.type === 'bos' && eos()) { - prev.type = 'globstar'; - prev.value += value; - prev.output = globstar(opts); - state.output = prev.output; - state.globstar = true; - consume(value); - continue; - } - - if (prior.type === 'slash' && prior.prev.type !== 'bos' && !afterStar && eos()) { - state.output = state.output.slice(0, -(prior.output + prev.output).length); - prior.output = `(?:${prior.output}`; - - prev.type = 'globstar'; - prev.output = globstar(opts) + (opts.strictSlashes ? ')' : '|$)'); - prev.value += value; - state.globstar = true; - state.output += prior.output + prev.output; - consume(value); - continue; - } - - if (prior.type === 'slash' && prior.prev.type !== 'bos' && rest[0] === '/') { - const end = rest[1] !== void 0 ? '|$' : ''; - - state.output = state.output.slice(0, -(prior.output + prev.output).length); - prior.output = `(?:${prior.output}`; - - prev.type = 'globstar'; - prev.output = `${globstar(opts)}${SLASH_LITERAL}|${SLASH_LITERAL}${end})`; - prev.value += value; - - state.output += prior.output + prev.output; - state.globstar = true; - - consume(value + advance()); - - push({ type: 'slash', value: '/', output: '' }); - continue; - } - - if (prior.type === 'bos' && rest[0] === '/') { - prev.type = 'globstar'; - prev.value += value; - prev.output = `(?:^|${SLASH_LITERAL}|${globstar(opts)}${SLASH_LITERAL})`; - state.output = prev.output; - state.globstar = true; - consume(value + advance()); - push({ type: 'slash', value: '/', output: '' }); - continue; - } - - // remove single star from output - state.output = state.output.slice(0, -prev.output.length); - - // reset previous token to globstar - prev.type = 'globstar'; - prev.output = globstar(opts); - prev.value += value; - - // reset output with globstar - state.output += prev.output; - state.globstar = true; - consume(value); - continue; - } - - const token = { type: 'star', value, output: star }; - - if (opts.bash === true) { - token.output = '.*?'; - if (prev.type === 'bos' || prev.type === 'slash') { - token.output = nodot + token.output; - } - push(token); - continue; - } - - if (prev && (prev.type === 'bracket' || prev.type === 'paren') && opts.regex === true) { - token.output = value; - push(token); - continue; - } - - if (state.index === state.start || prev.type === 'slash' || prev.type === 'dot') { - if (prev.type === 'dot') { - state.output += NO_DOT_SLASH; - prev.output += NO_DOT_SLASH; - - } else if (opts.dot === true) { - state.output += NO_DOTS_SLASH; - prev.output += NO_DOTS_SLASH; - - } else { - state.output += nodot; - prev.output += nodot; - } - - if (peek() !== '*') { - state.output += ONE_CHAR; - prev.output += ONE_CHAR; - } - } - - push(token); - } - - while (state.brackets > 0) { - if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ']')); - state.output = utils.escapeLast(state.output, '['); - decrement('brackets'); - } - - while (state.parens > 0) { - if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ')')); - state.output = utils.escapeLast(state.output, '('); - decrement('parens'); - } - - while (state.braces > 0) { - if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', '}')); - state.output = utils.escapeLast(state.output, '{'); - decrement('braces'); - } - - if (opts.strictSlashes !== true && (prev.type === 'star' || prev.type === 'bracket')) { - push({ type: 'maybe_slash', value: '', output: `${SLASH_LITERAL}?` }); - } - - // rebuild the output if we had to backtrack at any point - if (state.backtrack === true) { - state.output = ''; - - for (const token of state.tokens) { - state.output += token.output != null ? token.output : token.value; - - if (token.suffix) { - state.output += token.suffix; - } - } - } - - return state; -}; - -/** - * Fast paths for creating regular expressions for common glob patterns. - * This can significantly speed up processing and has very little downside - * impact when none of the fast paths match. - */ - -parse.fastpaths = (input, options) => { - const opts = { ...options }; - const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH, opts.maxLength) : MAX_LENGTH; - const len = input.length; - if (len > max) { - throw new SyntaxError(`Input length: ${len}, exceeds maximum allowed length: ${max}`); - } - - input = REPLACEMENTS[input] || input; - const win32 = utils.isWindows(options); - - // create constants based on platform, for windows or posix - const { - DOT_LITERAL, - SLASH_LITERAL, - ONE_CHAR, - DOTS_SLASH, - NO_DOT, - NO_DOTS, - NO_DOTS_SLASH, - STAR, - START_ANCHOR - } = constants.globChars(win32); - - const nodot = opts.dot ? NO_DOTS : NO_DOT; - const slashDot = opts.dot ? NO_DOTS_SLASH : NO_DOT; - const capture = opts.capture ? '' : '?:'; - const state = { negated: false, prefix: '' }; - let star = opts.bash === true ? '.*?' : STAR; - - if (opts.capture) { - star = `(${star})`; - } - - const globstar = (opts) => { - if (opts.noglobstar === true) return star; - return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`; - }; - - const create = str => { - switch (str) { - case '*': - return `${nodot}${ONE_CHAR}${star}`; - - case '.*': - return `${DOT_LITERAL}${ONE_CHAR}${star}`; - - case '*.*': - return `${nodot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`; - - case '*/*': - return `${nodot}${star}${SLASH_LITERAL}${ONE_CHAR}${slashDot}${star}`; - - case '**': - return nodot + globstar(opts); - - case '**/*': - return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${ONE_CHAR}${star}`; - - case '**/*.*': - return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`; - - case '**/.*': - return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${DOT_LITERAL}${ONE_CHAR}${star}`; - - default: { - const match = /^(.*?)\.(\w+)$/.exec(str); - if (!match) return; - - const source = create(match[1]); - if (!source) return; - - return source + DOT_LITERAL + match[2]; - } - } - }; - - const output = utils.removePrefix(input, state); - let source = create(output); - - if (source && opts.strictSlashes !== true) { - source += `${SLASH_LITERAL}?`; - } - - return source; -}; - -module.exports = parse; - - -/***/ }), -/* 333 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const merge2 = __webpack_require__(299); -function merge(streams) { - const mergedStream = merge2(streams); - streams.forEach((stream) => { - 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')); -} - - -/***/ }), -/* 334 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -function isString(input) { - return typeof input === 'string'; -} -exports.isString = isString; -function isEmpty(input) { - return input === ''; -} -exports.isEmpty = isEmpty; - - -/***/ }), -/* 335 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const stream_1 = __webpack_require__(336); -const provider_1 = __webpack_require__(363); -class ProviderAsync extends provider_1.default { - constructor() { - super(...arguments); - this._reader = new stream_1.default(this._settings); - } - read(task) { - const root = this._getRootDirectory(task); - const options = this._getReaderOptions(task); - const entries = []; - return new Promise((resolve, reject) => { - const stream = this.api(root, task, options); - stream.once('error', reject); - stream.on('data', (entry) => entries.push(options.transform(entry))); - stream.once('end', () => resolve(entries)); - }); - } - api(root, task, options) { - if (task.dynamic) { - return this._reader.dynamic(root, options); - } - return this._reader.static(task.patterns, options); - } -} -exports.default = ProviderAsync; - - -/***/ }), -/* 336 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const stream_1 = __webpack_require__(137); -const fsStat = __webpack_require__(337); -const fsWalk = __webpack_require__(342); -const reader_1 = __webpack_require__(362); -class ReaderStream extends reader_1.default { - constructor() { - super(...arguments); - this._walkStream = fsWalk.walkStream; - this._stat = fsStat.stat; - } - dynamic(root, options) { - return this._walkStream(root, options); - } - static(patterns, options) { - const filepaths = patterns.map(this._getFullEntryPath, this); - const stream = new stream_1.PassThrough({ objectMode: true }); - stream._write = (index, _enc, done) => { - return this._getEntry(filepaths[index], patterns[index], options) - .then((entry) => { - if (entry !== null && options.entryFilter(entry)) { - stream.push(entry); - } - if (index === filepaths.length - 1) { - stream.end(); - } - done(); - }) - .catch(done); - }; - for (let i = 0; i < filepaths.length; i++) { - stream.write(i); - } - return stream; - } - _getEntry(filepath, pattern, options) { - return this._getStat(filepath) - .then((stats) => this._makeEntry(stats, pattern)) - .catch((error) => { - if (options.errorFilter(error)) { - return null; - } - throw error; - }); - } - _getStat(filepath) { - return new Promise((resolve, reject) => { - this._stat(filepath, this._fsStatSettings, (error, stats) => { - return error === null ? resolve(stats) : reject(error); - }); - }); - } -} -exports.default = ReaderStream; - - -/***/ }), -/* 337 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const async = __webpack_require__(338); -const sync = __webpack_require__(339); -const settings_1 = __webpack_require__(340); -exports.Settings = settings_1.default; -function stat(path, optionsOrSettingsOrCallback, callback) { - if (typeof optionsOrSettingsOrCallback === 'function') { - return async.read(path, getSettings(), optionsOrSettingsOrCallback); - } - async.read(path, getSettings(optionsOrSettingsOrCallback), callback); -} -exports.stat = stat; -function statSync(path, optionsOrSettings) { - const settings = getSettings(optionsOrSettings); - return sync.read(path, settings); -} -exports.statSync = statSync; -function getSettings(settingsOrOptions = {}) { - if (settingsOrOptions instanceof settings_1.default) { - return settingsOrOptions; - } - return new settings_1.default(settingsOrOptions); -} - - -/***/ }), -/* 338 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -function read(path, settings, callback) { - settings.fs.lstat(path, (lstatError, lstat) => { - if (lstatError !== null) { - return callFailureCallback(callback, lstatError); - } - if (!lstat.isSymbolicLink() || !settings.followSymbolicLink) { - return callSuccessCallback(callback, lstat); - } - settings.fs.stat(path, (statError, stat) => { - if (statError !== null) { - if (settings.throwErrorOnBrokenSymbolicLink) { - return callFailureCallback(callback, statError); - } - return callSuccessCallback(callback, lstat); - } - if (settings.markSymbolicLink) { - stat.isSymbolicLink = () => true; - } - callSuccessCallback(callback, stat); - }); - }); -} -exports.read = read; -function callFailureCallback(callback, error) { - callback(error); -} -function callSuccessCallback(callback, result) { - callback(null, result); -} - - -/***/ }), -/* 339 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -function read(path, settings) { - const lstat = settings.fs.lstatSync(path); - if (!lstat.isSymbolicLink() || !settings.followSymbolicLink) { - return lstat; - } - try { - const stat = settings.fs.statSync(path); - if (settings.markSymbolicLink) { - stat.isSymbolicLink = () => true; - } - return stat; - } - catch (error) { - if (!settings.throwErrorOnBrokenSymbolicLink) { - return lstat; - } - throw error; - } -} -exports.read = read; - - -/***/ }), -/* 340 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(341); -class Settings { - constructor(_options = {}) { - this._options = _options; - this.followSymbolicLink = this._getValue(this._options.followSymbolicLink, true); - this.fs = fs.createFileSystemAdapter(this._options.fs); - this.markSymbolicLink = this._getValue(this._options.markSymbolicLink, false); - this.throwErrorOnBrokenSymbolicLink = this._getValue(this._options.throwErrorOnBrokenSymbolicLink, true); - } - _getValue(option, value) { - return option === undefined ? value : option; - } -} -exports.default = Settings; - - -/***/ }), -/* 341 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(133); -exports.FILE_SYSTEM_ADAPTER = { - lstat: fs.lstat, - stat: fs.stat, - lstatSync: fs.lstatSync, - statSync: fs.statSync -}; -function createFileSystemAdapter(fsMethods) { - if (fsMethods === undefined) { - return exports.FILE_SYSTEM_ADAPTER; - } - return Object.assign(Object.assign({}, exports.FILE_SYSTEM_ADAPTER), fsMethods); -} -exports.createFileSystemAdapter = createFileSystemAdapter; - - -/***/ }), -/* 342 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const async_1 = __webpack_require__(343); -const stream_1 = __webpack_require__(358); -const sync_1 = __webpack_require__(359); -const settings_1 = __webpack_require__(361); -exports.Settings = settings_1.default; -function walk(directory, optionsOrSettingsOrCallback, callback) { - if (typeof optionsOrSettingsOrCallback === 'function') { - return new async_1.default(directory, getSettings()).read(optionsOrSettingsOrCallback); - } - new async_1.default(directory, getSettings(optionsOrSettingsOrCallback)).read(callback); -} -exports.walk = walk; -function walkSync(directory, optionsOrSettings) { - const settings = getSettings(optionsOrSettings); - const provider = new sync_1.default(directory, settings); - return provider.read(); -} -exports.walkSync = walkSync; -function walkStream(directory, optionsOrSettings) { - const settings = getSettings(optionsOrSettings); - const provider = new stream_1.default(directory, settings); - return provider.read(); -} -exports.walkStream = walkStream; -function getSettings(settingsOrOptions = {}) { - if (settingsOrOptions instanceof settings_1.default) { - return settingsOrOptions; - } - return new settings_1.default(settingsOrOptions); -} - - -/***/ }), -/* 343 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const async_1 = __webpack_require__(344); -class AsyncProvider { - constructor(_root, _settings) { - this._root = _root; - this._settings = _settings; - this._reader = new async_1.default(this._root, this._settings); - this._storage = new Set(); - } - read(callback) { - this._reader.onError((error) => { - callFailureCallback(callback, error); - }); - this._reader.onEntry((entry) => { - this._storage.add(entry); - }); - this._reader.onEnd(() => { - callSuccessCallback(callback, [...this._storage]); - }); - this._reader.read(); - } -} -exports.default = AsyncProvider; -function callFailureCallback(callback, error) { - callback(error); -} -function callSuccessCallback(callback, entries) { - callback(null, entries); -} - - -/***/ }), -/* 344 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const events_1 = __webpack_require__(155); -const fsScandir = __webpack_require__(345); -const fastq = __webpack_require__(354); -const common = __webpack_require__(356); -const reader_1 = __webpack_require__(357); -class AsyncReader extends reader_1.default { - constructor(_root, _settings) { - super(_root, _settings); - this._settings = _settings; - this._scandir = fsScandir.scandir; - this._emitter = new events_1.EventEmitter(); - this._queue = fastq(this._worker.bind(this), this._settings.concurrency); - this._isFatalError = false; - this._isDestroyed = false; - this._queue.drain = () => { - if (!this._isFatalError) { - this._emitter.emit('end'); - } - }; - } - read() { - this._isFatalError = false; - this._isDestroyed = false; - setImmediate(() => { - this._pushToQueue(this._root, this._settings.basePath); - }); - return this._emitter; - } - destroy() { - if (this._isDestroyed) { - throw new Error('The reader is already destroyed'); - } - this._isDestroyed = true; - this._queue.killAndDrain(); - } - onEntry(callback) { - this._emitter.on('entry', callback); - } - onError(callback) { - this._emitter.once('error', callback); - } - onEnd(callback) { - this._emitter.once('end', callback); - } - _pushToQueue(directory, base) { - const queueItem = { directory, base }; - this._queue.push(queueItem, (error) => { - if (error !== null) { - this._handleError(error); - } - }); - } - _worker(item, done) { - this._scandir(item.directory, this._settings.fsScandirSettings, (error, entries) => { - if (error !== null) { - return done(error, undefined); - } - for (const entry of entries) { - this._handleEntry(entry, item.base); - } - done(null, undefined); - }); - } - _handleError(error) { - if (!common.isFatalError(this._settings, error)) { - return; - } - this._isFatalError = true; - this._isDestroyed = true; - this._emitter.emit('error', error); - } - _handleEntry(entry, base) { - if (this._isDestroyed || this._isFatalError) { - return; - } - const fullpath = entry.path; - if (base !== undefined) { - entry.path = common.joinPathSegments(base, entry.name, this._settings.pathSegmentSeparator); - } - if (common.isAppliedFilter(this._settings.entryFilter, entry)) { - this._emitEntry(entry); - } - if (entry.dirent.isDirectory() && common.isAppliedFilter(this._settings.deepFilter, entry)) { - this._pushToQueue(fullpath, entry.path); - } - } - _emitEntry(entry) { - this._emitter.emit('entry', entry); - } -} -exports.default = AsyncReader; - - -/***/ }), -/* 345 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const async = __webpack_require__(346); -const sync = __webpack_require__(351); -const settings_1 = __webpack_require__(352); -exports.Settings = settings_1.default; -function scandir(path, optionsOrSettingsOrCallback, callback) { - if (typeof optionsOrSettingsOrCallback === 'function') { - return async.read(path, getSettings(), optionsOrSettingsOrCallback); - } - async.read(path, getSettings(optionsOrSettingsOrCallback), callback); -} -exports.scandir = scandir; -function scandirSync(path, optionsOrSettings) { - const settings = getSettings(optionsOrSettings); - return sync.read(path, settings); -} -exports.scandirSync = scandirSync; -function getSettings(settingsOrOptions = {}) { - if (settingsOrOptions instanceof settings_1.default) { - return settingsOrOptions; - } - return new settings_1.default(settingsOrOptions); -} - - -/***/ }), -/* 346 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fsStat = __webpack_require__(337); -const rpl = __webpack_require__(347); -const constants_1 = __webpack_require__(348); -const utils = __webpack_require__(349); -function read(directory, settings, callback) { - if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { - return readdirWithFileTypes(directory, settings, callback); - } - return readdir(directory, settings, callback); -} -exports.read = read; -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: `${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 !== null) { - return callFailureCallback(callback, rplError); - } - callSuccessCallback(callback, rplEntries); - }); - }); -} -exports.readdirWithFileTypes = readdirWithFileTypes; -function makeRplTaskEntry(entry, settings) { - return (done) => { - if (!entry.dirent.isSymbolicLink()) { - return done(null, entry); - } - settings.fs.stat(entry.path, (statError, stats) => { - if (statError !== null) { - if (settings.throwErrorOnBrokenSymbolicLink) { - return done(statError); - } - return done(null, entry); - } - entry.dirent = utils.fs.createDirentFromStats(entry.name, stats); - return done(null, entry); - }); - }; -} -function readdir(directory, settings, callback) { - settings.fs.readdir(directory, (readdirError, names) => { - if (readdirError !== null) { - return callFailureCallback(callback, readdirError); - } - 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 !== null) { - return callFailureCallback(callback, rplError); - } - const entries = []; - names.forEach((name, index) => { - const stats = results[index]; - const entry = { - name, - path: filepaths[index], - dirent: utils.fs.createDirentFromStats(name, stats) - }; - if (settings.stats) { - entry.stats = stats; - } - entries.push(entry); - }); - callSuccessCallback(callback, entries); - }); - }); -} -exports.readdir = readdir; -function callFailureCallback(callback, error) { - callback(error); -} -function callSuccessCallback(callback, result) { - callback(null, result); -} - - -/***/ }), -/* 347 */ -/***/ (function(module, exports) { - -module.exports = runParallel - -function runParallel (tasks, cb) { - var results, pending, keys - var isSync = true - - if (Array.isArray(tasks)) { - results = [] - pending = tasks.length - } else { - keys = Object.keys(tasks) - results = {} - pending = keys.length - } - - function done (err) { - function end () { - if (cb) cb(err, results) - cb = null - } - if (isSync) process.nextTick(end) - else end() - } - - function each (i, err, result) { - results[i] = result - if (--pending === 0 || err) { - done(err) - } - } - - if (!pending) { - // empty - done(null) - } else if (keys) { - // object - keys.forEach(function (key) { - tasks[key](function (err, result) { each(key, err, result) }) - }) - } else { - // array - tasks.forEach(function (task, i) { - task(function (err, result) { each(i, err, result) }) - }) - } - - isSync = false -} - - -/***/ }), -/* 348 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -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 = IS_MATCHED_BY_MAJOR || IS_MATCHED_BY_MAJOR_AND_MINOR; - - -/***/ }), -/* 349 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(350); -exports.fs = fs; - - -/***/ }), -/* 350 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -class DirentFromStats { - constructor(name, stats) { - this.name = name; - this.isBlockDevice = stats.isBlockDevice.bind(stats); - this.isCharacterDevice = stats.isCharacterDevice.bind(stats); - this.isDirectory = stats.isDirectory.bind(stats); - this.isFIFO = stats.isFIFO.bind(stats); - this.isFile = stats.isFile.bind(stats); - this.isSocket = stats.isSocket.bind(stats); - this.isSymbolicLink = stats.isSymbolicLink.bind(stats); - } -} -function createDirentFromStats(name, stats) { - return new DirentFromStats(name, stats); -} -exports.createDirentFromStats = createDirentFromStats; - - -/***/ }), -/* 351 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fsStat = __webpack_require__(337); -const constants_1 = __webpack_require__(348); -const utils = __webpack_require__(349); -function read(directory, settings) { - if (!settings.stats && constants_1.IS_SUPPORT_READDIR_WITH_FILE_TYPES) { - return readdirWithFileTypes(directory, settings); - } - return readdir(directory, settings); -} -exports.read = read; -function readdirWithFileTypes(directory, settings) { - const dirents = settings.fs.readdirSync(directory, { withFileTypes: true }); - return dirents.map((dirent) => { - const entry = { - dirent, - name: dirent.name, - path: `${directory}${settings.pathSegmentSeparator}${dirent.name}` - }; - if (entry.dirent.isSymbolicLink() && settings.followSymbolicLinks) { - try { - const stats = settings.fs.statSync(entry.path); - entry.dirent = utils.fs.createDirentFromStats(entry.name, stats); - } - catch (error) { - if (settings.throwErrorOnBrokenSymbolicLink) { - throw error; - } - } - } - return entry; - }); -} -exports.readdirWithFileTypes = readdirWithFileTypes; -function readdir(directory, settings) { - const names = settings.fs.readdirSync(directory); - return names.map((name) => { - const entryPath = `${directory}${settings.pathSegmentSeparator}${name}`; - const stats = fsStat.statSync(entryPath, settings.fsStatSettings); - const entry = { - name, - path: entryPath, - dirent: utils.fs.createDirentFromStats(name, stats) - }; - if (settings.stats) { - entry.stats = stats; - } - return entry; - }); -} -exports.readdir = readdir; - - -/***/ }), -/* 352 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const path = __webpack_require__(4); -const fsStat = __webpack_require__(337); -const fs = __webpack_require__(353); -class Settings { - constructor(_options = {}) { - this._options = _options; - this.followSymbolicLinks = this._getValue(this._options.followSymbolicLinks, false); - this.fs = fs.createFileSystemAdapter(this._options.fs); - this.pathSegmentSeparator = this._getValue(this._options.pathSegmentSeparator, path.sep); - this.stats = this._getValue(this._options.stats, false); - this.throwErrorOnBrokenSymbolicLink = this._getValue(this._options.throwErrorOnBrokenSymbolicLink, true); - this.fsStatSettings = new fsStat.Settings({ - followSymbolicLink: this.followSymbolicLinks, - fs: this.fs, - throwErrorOnBrokenSymbolicLink: this.throwErrorOnBrokenSymbolicLink - }); - } - _getValue(option, value) { - return option === undefined ? value : option; - } -} -exports.default = Settings; - - -/***/ }), -/* 353 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(133); -exports.FILE_SYSTEM_ADAPTER = { - lstat: fs.lstat, - stat: fs.stat, - lstatSync: fs.lstatSync, - statSync: fs.statSync, - readdir: fs.readdir, - readdirSync: fs.readdirSync -}; -function createFileSystemAdapter(fsMethods) { - if (fsMethods === undefined) { - return exports.FILE_SYSTEM_ADAPTER; - } - return Object.assign(Object.assign({}, exports.FILE_SYSTEM_ADAPTER), fsMethods); -} -exports.createFileSystemAdapter = createFileSystemAdapter; - - -/***/ }), -/* 354 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var reusify = __webpack_require__(355) - -function fastqueue (context, worker, concurrency) { - if (typeof context === 'function') { - concurrency = worker - worker = context - context = null - } - - var cache = reusify(Task) - var queueHead = null - var queueTail = null - var _running = 0 - - var self = { - push: push, - drain: noop, - saturated: noop, - pause: pause, - paused: false, - concurrency: concurrency, - running: running, - resume: resume, - idle: idle, - length: length, - unshift: unshift, - empty: noop, - kill: kill, - killAndDrain: killAndDrain - } - - return self - - function running () { - return _running - } - - function pause () { - self.paused = true - } - - function length () { - var current = queueHead - var counter = 0 - - while (current) { - current = current.next - counter++ - } - - return counter - } - - function resume () { - if (!self.paused) return - self.paused = false - for (var i = 0; i < self.concurrency; i++) { - _running++ - release() - } - } - - function idle () { - return _running === 0 && self.length() === 0 - } - - function push (value, done) { - var current = cache.get() - - current.context = context - current.release = release - current.value = value - current.callback = done || noop - - if (_running === self.concurrency || self.paused) { - if (queueTail) { - queueTail.next = current - queueTail = current - } else { - queueHead = current - queueTail = current - self.saturated() - } - } else { - _running++ - worker.call(context, current.value, current.worked) - } - } - - function unshift (value, done) { - var current = cache.get() - - current.context = context - current.release = release - current.value = value - current.callback = done || noop - - if (_running === self.concurrency || self.paused) { - if (queueHead) { - current.next = queueHead - queueHead = current - } else { - queueHead = current - queueTail = current - self.saturated() - } - } else { - _running++ - worker.call(context, current.value, current.worked) - } - } - - function release (holder) { - if (holder) { - cache.release(holder) - } - var next = queueHead - if (next) { - if (!self.paused) { - if (queueTail === queueHead) { - queueTail = null - } - queueHead = next.next - next.next = null - worker.call(context, next.value, next.worked) - if (queueTail === null) { - self.empty() - } - } else { - _running-- - } - } else if (--_running === 0) { - self.drain() - } - } - - function kill () { - queueHead = null - queueTail = null - self.drain = noop - } - - function killAndDrain () { - queueHead = null - queueTail = null - self.drain() - self.drain = noop - } -} - -function noop () {} - -function Task () { - this.value = null - this.callback = noop - this.next = null - this.release = noop - this.context = null - - var self = this - - this.worked = function worked (err, result) { - var callback = self.callback - self.value = null - self.callback = noop - callback.call(self.context, err, result) - self.release(self) - } -} - -module.exports = fastqueue - - -/***/ }), -/* 355 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -function reusify (Constructor) { - var head = new Constructor() - var tail = head - - function get () { - var current = head - - if (current.next) { - head = current.next - } else { - head = new Constructor() - tail = head - } - - current.next = null - - return current - } - - function release (obj) { - tail.next = obj - tail = obj - } - - return { - get: get, - release: release - } -} - -module.exports = reusify - - -/***/ }), -/* 356 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -function isFatalError(settings, error) { - if (settings.errorFilter === null) { - return true; - } - return !settings.errorFilter(error); -} -exports.isFatalError = isFatalError; -function isAppliedFilter(filter, value) { - return filter === null || filter(value); -} -exports.isAppliedFilter = isAppliedFilter; -function replacePathSegmentSeparator(filepath, separator) { - return filepath.split(/[\\/]/).join(separator); -} -exports.replacePathSegmentSeparator = replacePathSegmentSeparator; -function joinPathSegments(a, b, separator) { - if (a === '') { - return b; - } - return a + separator + b; -} -exports.joinPathSegments = joinPathSegments; - - -/***/ }), -/* 357 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const common = __webpack_require__(356); -class Reader { - constructor(_root, _settings) { - this._root = _root; - this._settings = _settings; - this._root = common.replacePathSegmentSeparator(_root, _settings.pathSegmentSeparator); - } -} -exports.default = Reader; - - -/***/ }), -/* 358 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const stream_1 = __webpack_require__(137); -const async_1 = __webpack_require__(344); -class StreamProvider { - constructor(_root, _settings) { - this._root = _root; - this._settings = _settings; - this._reader = new async_1.default(this._root, this._settings); - this._stream = new stream_1.Readable({ - objectMode: true, - read: () => { }, - destroy: this._reader.destroy.bind(this._reader) - }); - } - read() { - this._reader.onError((error) => { - this._stream.emit('error', error); - }); - this._reader.onEntry((entry) => { - this._stream.push(entry); - }); - this._reader.onEnd(() => { - this._stream.push(null); - }); - this._reader.read(); - return this._stream; - } -} -exports.default = StreamProvider; - - -/***/ }), -/* 359 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const sync_1 = __webpack_require__(360); -class SyncProvider { - constructor(_root, _settings) { - this._root = _root; - this._settings = _settings; - this._reader = new sync_1.default(this._root, this._settings); - } - read() { - return this._reader.read(); - } -} -exports.default = SyncProvider; - - -/***/ }), -/* 360 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fsScandir = __webpack_require__(345); -const common = __webpack_require__(356); -const reader_1 = __webpack_require__(357); -class SyncReader extends reader_1.default { - constructor() { - super(...arguments); - this._scandir = fsScandir.scandirSync; - this._storage = new Set(); - this._queue = new Set(); - } - read() { - this._pushToQueue(this._root, this._settings.basePath); - this._handleQueue(); - return [...this._storage]; - } - _pushToQueue(directory, base) { - this._queue.add({ directory, base }); - } - _handleQueue() { - for (const item of this._queue.values()) { - this._handleDirectory(item.directory, item.base); - } - } - _handleDirectory(directory, base) { - try { - const entries = this._scandir(directory, this._settings.fsScandirSettings); - for (const entry of entries) { - this._handleEntry(entry, base); - } - } - catch (error) { - this._handleError(error); - } - } - _handleError(error) { - if (!common.isFatalError(this._settings, error)) { - return; - } - throw error; - } - _handleEntry(entry, base) { - const fullpath = entry.path; - if (base !== undefined) { - entry.path = common.joinPathSegments(base, entry.name, this._settings.pathSegmentSeparator); - } - if (common.isAppliedFilter(this._settings.entryFilter, entry)) { - this._pushToStorage(entry); - } - if (entry.dirent.isDirectory() && common.isAppliedFilter(this._settings.deepFilter, entry)) { - this._pushToQueue(fullpath, entry.path); - } - } - _pushToStorage(entry) { - this._storage.add(entry); - } -} -exports.default = SyncReader; - - -/***/ }), -/* 361 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const path = __webpack_require__(4); -const fsScandir = __webpack_require__(345); -class Settings { - constructor(_options = {}) { - this._options = _options; - this.basePath = this._getValue(this._options.basePath, undefined); - this.concurrency = this._getValue(this._options.concurrency, Infinity); - this.deepFilter = this._getValue(this._options.deepFilter, null); - this.entryFilter = this._getValue(this._options.entryFilter, null); - this.errorFilter = this._getValue(this._options.errorFilter, null); - this.pathSegmentSeparator = this._getValue(this._options.pathSegmentSeparator, path.sep); - this.fsScandirSettings = new fsScandir.Settings({ - followSymbolicLinks: this._options.followSymbolicLinks, - fs: this._options.fs, - pathSegmentSeparator: this._options.pathSegmentSeparator, - stats: this._options.stats, - throwErrorOnBrokenSymbolicLink: this._options.throwErrorOnBrokenSymbolicLink - }); - } - _getValue(option, value) { - return option === undefined ? value : option; - } -} -exports.default = Settings; - - -/***/ }), -/* 362 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const path = __webpack_require__(4); -const fsStat = __webpack_require__(337); -const utils = __webpack_require__(307); -class Reader { - constructor(_settings) { - this._settings = _settings; - this._fsStatSettings = new fsStat.Settings({ - followSymbolicLink: this._settings.followSymbolicLinks, - fs: this._settings.fs, - throwErrorOnBrokenSymbolicLink: this._settings.followSymbolicLinks - }); - } - _getFullEntryPath(filepath) { - return path.resolve(this._settings.cwd, filepath); - } - _makeEntry(stats, pattern) { - const entry = { - name: pattern, - path: pattern, - dirent: utils.fs.createDirentFromStats(pattern, stats) - }; - if (this._settings.stats) { - entry.stats = stats; - } - return entry; - } - _isFatalError(error) { - return !utils.errno.isEnoentCodeError(error) && !this._settings.suppressErrors; - } -} -exports.default = Reader; - - -/***/ }), -/* 363 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const path = __webpack_require__(4); -const deep_1 = __webpack_require__(364); -const entry_1 = __webpack_require__(367); -const error_1 = __webpack_require__(368); -const entry_2 = __webpack_require__(369); -class Provider { - constructor(_settings) { - this._settings = _settings; - this.errorFilter = new error_1.default(this._settings); - this.entryFilter = new entry_1.default(this._settings, this._getMicromatchOptions()); - this.deepFilter = new deep_1.default(this._settings, this._getMicromatchOptions()); - this.entryTransformer = new entry_2.default(this._settings); - } - _getRootDirectory(task) { - return path.resolve(this._settings.cwd, task.base); - } - _getReaderOptions(task) { - const basePath = task.base === '.' ? '' : task.base; - return { - basePath, - pathSegmentSeparator: '/', - concurrency: this._settings.concurrency, - deepFilter: this.deepFilter.getFilter(basePath, task.positive, task.negative), - entryFilter: this.entryFilter.getFilter(task.positive, task.negative), - errorFilter: this.errorFilter.getFilter(), - followSymbolicLinks: this._settings.followSymbolicLinks, - fs: this._settings.fs, - stats: this._settings.stats, - throwErrorOnBrokenSymbolicLink: this._settings.throwErrorOnBrokenSymbolicLink, - transform: this.entryTransformer.getTransformer() - }; - } - _getMicromatchOptions() { - return { - dot: this._settings.dot, - matchBase: this._settings.baseNameMatch, - nobrace: !this._settings.braceExpansion, - nocase: !this._settings.caseSensitiveMatch, - noext: !this._settings.extglob, - noglobstar: !this._settings.globstar, - posix: true, - strictSlashes: false - }; - } -} -exports.default = Provider; - - -/***/ }), -/* 364 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(307); -const partial_1 = __webpack_require__(365); -class DeepFilter { - constructor(_settings, _micromatchOptions) { - this._settings = _settings; - this._micromatchOptions = _micromatchOptions; - } - getFilter(basePath, positive, negative) { - const matcher = this._getMatcher(positive); - const negativeRe = this._getNegativePatternsRe(negative); - return (entry) => this._filter(basePath, entry, matcher, negativeRe); - } - _getMatcher(patterns) { - return new partial_1.default(patterns, this._settings, this._micromatchOptions); - } - _getNegativePatternsRe(patterns) { - const affectDepthOfReadingPatterns = patterns.filter(utils.pattern.isAffectDepthOfReadingPattern); - return utils.pattern.convertPatternsToRe(affectDepthOfReadingPatterns, this._micromatchOptions); - } - _filter(basePath, entry, matcher, negativeRe) { - const depth = this._getEntryLevel(basePath, entry.path); - if (this._isSkippedByDeep(depth)) { - return false; - } - if (this._isSkippedSymbolicLink(entry)) { - return false; - } - const filepath = utils.path.removeLeadingDotSegment(entry.path); - if (this._isSkippedByPositivePatterns(filepath, matcher)) { - return false; - } - return this._isSkippedByNegativePatterns(filepath, negativeRe); - } - _isSkippedByDeep(entryDepth) { - return entryDepth >= this._settings.deep; - } - _isSkippedSymbolicLink(entry) { - return !this._settings.followSymbolicLinks && entry.dirent.isSymbolicLink(); - } - _getEntryLevel(basePath, entryPath) { - const basePathDepth = basePath.split('/').length; - const entryPathDepth = entryPath.split('/').length; - return entryPathDepth - (basePath === '' ? 0 : basePathDepth); - } - _isSkippedByPositivePatterns(entryPath, matcher) { - return !this._settings.baseNameMatch && !matcher.match(entryPath); - } - _isSkippedByNegativePatterns(entryPath, negativeRe) { - return !utils.pattern.matchAny(entryPath, negativeRe); - } -} -exports.default = DeepFilter; - - -/***/ }), -/* 365 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const matcher_1 = __webpack_require__(366); -class PartialMatcher extends matcher_1.default { - match(filepath) { - const parts = filepath.split('/'); - const levels = parts.length; - const patterns = this._storage.filter((info) => !info.complete || info.segments.length > levels); - for (const pattern of patterns) { - const section = pattern.sections[0]; - /** - * In this case, the pattern has a globstar and we must read all directories unconditionally, - * but only if the level has reached the end of the first group. - * - * fixtures/{a,b}/** - * ^ true/false ^ always true - */ - if (!pattern.complete && levels > section.length) { - return true; - } - const match = parts.every((part, index) => { - const segment = pattern.segments[index]; - if (segment.dynamic && segment.patternRe.test(part)) { - return true; - } - if (!segment.dynamic && segment.pattern === part) { - return true; - } - return false; - }); - if (match) { - return true; - } - } - return false; - } -} -exports.default = PartialMatcher; - - -/***/ }), -/* 366 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(307); -class Matcher { - constructor(_patterns, _settings, _micromatchOptions) { - this._patterns = _patterns; - this._settings = _settings; - this._micromatchOptions = _micromatchOptions; - this._storage = []; - this._fillStorage(); - } - _fillStorage() { - /** - * The original pattern may include `{,*,**,a/*}`, which will lead to problems with matching (unresolved level). - * So, before expand patterns with brace expansion into separated patterns. - */ - const patterns = utils.pattern.expandPatternsWithBraceExpansion(this._patterns); - for (const pattern of patterns) { - const segments = this._getPatternSegments(pattern); - const sections = this._splitSegmentsIntoSections(segments); - this._storage.push({ - complete: sections.length <= 1, - pattern, - segments, - sections - }); - } - } - _getPatternSegments(pattern) { - const parts = utils.pattern.getPatternParts(pattern, this._micromatchOptions); - return parts.map((part) => { - const dynamic = utils.pattern.isDynamicPattern(part, this._settings); - if (!dynamic) { - return { - dynamic: false, - pattern: part - }; - } - return { - dynamic: true, - pattern: part, - patternRe: utils.pattern.makeRe(part, this._micromatchOptions) - }; - }); - } - _splitSegmentsIntoSections(segments) { - return utils.array.splitWhen(segments, (segment) => segment.dynamic && utils.pattern.hasGlobStar(segment.pattern)); - } -} -exports.default = Matcher; - - -/***/ }), -/* 367 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(307); -class EntryFilter { - constructor(_settings, _micromatchOptions) { - this._settings = _settings; - this._micromatchOptions = _micromatchOptions; - this.index = new Map(); - } - getFilter(positive, negative) { - const positiveRe = utils.pattern.convertPatternsToRe(positive, this._micromatchOptions); - const negativeRe = utils.pattern.convertPatternsToRe(negative, this._micromatchOptions); - return (entry) => this._filter(entry, positiveRe, negativeRe); - } - _filter(entry, positiveRe, negativeRe) { - if (this._settings.unique) { - if (this._isDuplicateEntry(entry)) { - return false; - } - this._createIndexRecord(entry); - } - if (this._onlyFileFilter(entry) || this._onlyDirectoryFilter(entry)) { - return false; - } - if (this._isSkippedByAbsoluteNegativePatterns(entry, negativeRe)) { - return false; - } - const filepath = this._settings.baseNameMatch ? entry.name : entry.path; - return this._isMatchToPatterns(filepath, positiveRe) && !this._isMatchToPatterns(entry.path, negativeRe); - } - _isDuplicateEntry(entry) { - return this.index.has(entry.path); - } - _createIndexRecord(entry) { - this.index.set(entry.path, undefined); - } - _onlyFileFilter(entry) { - return this._settings.onlyFiles && !entry.dirent.isFile(); - } - _onlyDirectoryFilter(entry) { - return this._settings.onlyDirectories && !entry.dirent.isDirectory(); - } - _isSkippedByAbsoluteNegativePatterns(entry, negativeRe) { - if (!this._settings.absolute) { - return false; - } - const fullpath = utils.path.makeAbsolute(this._settings.cwd, entry.path); - return this._isMatchToPatterns(fullpath, negativeRe); - } - _isMatchToPatterns(entryPath, patternsRe) { - const filepath = utils.path.removeLeadingDotSegment(entryPath); - return utils.pattern.matchAny(filepath, patternsRe); - } -} -exports.default = EntryFilter; - - -/***/ }), -/* 368 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(307); -class ErrorFilter { - constructor(_settings) { - this._settings = _settings; - } - getFilter() { - return (error) => this._isNonFatalError(error); - } - _isNonFatalError(error) { - return utils.errno.isEnoentCodeError(error) || this._settings.suppressErrors; - } -} -exports.default = ErrorFilter; - - -/***/ }), -/* 369 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(307); -class EntryTransformer { - constructor(_settings) { - this._settings = _settings; - } - getTransformer() { - return (entry) => this._transform(entry); - } - _transform(entry) { - let filepath = entry.path; - if (this._settings.absolute) { - filepath = utils.path.makeAbsolute(this._settings.cwd, filepath); - filepath = utils.path.unixify(filepath); - } - if (this._settings.markDirectories && entry.dirent.isDirectory()) { - filepath += '/'; - } - if (!this._settings.objectMode) { - return filepath; - } - return Object.assign(Object.assign({}, entry), { path: filepath }); - } -} -exports.default = EntryTransformer; - - -/***/ }), -/* 370 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const stream_1 = __webpack_require__(137); -const stream_2 = __webpack_require__(336); -const provider_1 = __webpack_require__(363); -class ProviderStream extends provider_1.default { - constructor() { - super(...arguments); - this._reader = new stream_2.default(this._settings); - } - read(task) { - const root = this._getRootDirectory(task); - const options = this._getReaderOptions(task); - const source = this.api(root, task, options); - const destination = new stream_1.Readable({ objectMode: true, read: () => { } }); - source - .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) { - return this._reader.dynamic(root, options); - } - return this._reader.static(task.patterns, options); - } -} -exports.default = ProviderStream; - - -/***/ }), -/* 371 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const sync_1 = __webpack_require__(372); -const provider_1 = __webpack_require__(363); -class ProviderSync extends provider_1.default { - constructor() { - super(...arguments); - this._reader = new sync_1.default(this._settings); - } - read(task) { - const root = this._getRootDirectory(task); - const options = this._getReaderOptions(task); - const entries = this.api(root, task, options); - return entries.map(options.transform); - } - api(root, task, options) { - if (task.dynamic) { - return this._reader.dynamic(root, options); - } - return this._reader.static(task.patterns, options); - } -} -exports.default = ProviderSync; - - -/***/ }), -/* 372 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fsStat = __webpack_require__(337); -const fsWalk = __webpack_require__(342); -const reader_1 = __webpack_require__(362); -class ReaderSync extends reader_1.default { - constructor() { - super(...arguments); - this._walkSync = fsWalk.walkSync; - this._statSync = fsStat.statSync; - } - dynamic(root, options) { - return this._walkSync(root, options); - } - static(patterns, options) { - const entries = []; - for (const pattern of patterns) { - const filepath = this._getFullEntryPath(pattern); - const entry = this._getEntry(filepath, pattern, options); - if (entry === null || !options.entryFilter(entry)) { - continue; - } - entries.push(entry); - } - return entries; - } - _getEntry(filepath, pattern, options) { - try { - const stats = this._getStat(filepath); - return this._makeEntry(stats, pattern); - } - catch (error) { - if (options.errorFilter(error)) { - return null; - } - throw error; - } - } - _getStat(filepath) { - return this._statSync(filepath, this._fsStatSettings); - } -} -exports.default = ReaderSync; - - -/***/ }), -/* 373 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(133); -const os = __webpack_require__(120); -const CPU_COUNT = os.cpus().length; -exports.DEFAULT_FILE_SYSTEM_ADAPTER = { - lstat: fs.lstat, - lstatSync: fs.lstatSync, - stat: fs.stat, - statSync: fs.statSync, - readdir: fs.readdir, - readdirSync: fs.readdirSync -}; -class Settings { - constructor(_options = {}) { - this._options = _options; - this.absolute = this._getValue(this._options.absolute, false); - this.baseNameMatch = this._getValue(this._options.baseNameMatch, false); - this.braceExpansion = this._getValue(this._options.braceExpansion, true); - this.caseSensitiveMatch = this._getValue(this._options.caseSensitiveMatch, true); - this.concurrency = this._getValue(this._options.concurrency, CPU_COUNT); - this.cwd = this._getValue(this._options.cwd, process.cwd()); - this.deep = this._getValue(this._options.deep, Infinity); - this.dot = this._getValue(this._options.dot, false); - this.extglob = this._getValue(this._options.extglob, true); - this.followSymbolicLinks = this._getValue(this._options.followSymbolicLinks, true); - this.fs = this._getFileSystemMethods(this._options.fs); - this.globstar = this._getValue(this._options.globstar, true); - this.ignore = this._getValue(this._options.ignore, []); - this.markDirectories = this._getValue(this._options.markDirectories, false); - this.objectMode = this._getValue(this._options.objectMode, false); - this.onlyDirectories = this._getValue(this._options.onlyDirectories, false); - this.onlyFiles = this._getValue(this._options.onlyFiles, true); - this.stats = this._getValue(this._options.stats, false); - this.suppressErrors = this._getValue(this._options.suppressErrors, false); - this.throwErrorOnBrokenSymbolicLink = this._getValue(this._options.throwErrorOnBrokenSymbolicLink, false); - this.unique = this._getValue(this._options.unique, true); - if (this.onlyDirectories) { - this.onlyFiles = false; - } - if (this.stats) { - this.objectMode = true; - } - } - _getValue(option, value) { - return option === undefined ? value : option; - } - _getFileSystemMethods(methods = {}) { - return Object.assign(Object.assign({}, exports.DEFAULT_FILE_SYSTEM_ADAPTER), methods); - } -} -exports.default = Settings; - - -/***/ }), -/* 374 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const path = __webpack_require__(4); -const pathType = __webpack_require__(375); - -const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; - -const getPath = (filepath, cwd) => { - const pth = filepath[0] === '!' ? filepath.slice(1) : filepath; - return path.isAbsolute(pth) ? pth : path.join(cwd, pth); -}; - -const addExtensions = (file, extensions) => { - if (path.extname(file)) { - return `**/${file}`; - } - - return `**/${file}.${getExtensions(extensions)}`; -}; - -const getGlob = (directory, options) => { - if (options.files && !Array.isArray(options.files)) { - throw new TypeError(`Expected \`files\` to be of type \`Array\` but received type \`${typeof options.files}\``); - } - - if (options.extensions && !Array.isArray(options.extensions)) { - throw new TypeError(`Expected \`extensions\` to be of type \`Array\` but received type \`${typeof options.extensions}\``); - } - - if (options.files && options.extensions) { - return options.files.map(x => path.posix.join(directory, addExtensions(x, options.extensions))); - } - - if (options.files) { - return options.files.map(x => path.posix.join(directory, `**/${x}`)); - } - - if (options.extensions) { - return [path.posix.join(directory, `**/*.${getExtensions(options.extensions)}`)]; - } - - return [path.posix.join(directory, '**')]; -}; - -module.exports = async (input, options) => { - options = { - cwd: process.cwd(), - ...options - }; - - if (typeof options.cwd !== 'string') { - throw new TypeError(`Expected \`cwd\` to be of type \`string\` but received type \`${typeof options.cwd}\``); - } - - const globs = await Promise.all([].concat(input).map(async x => { - const isDirectory = await pathType.isDirectory(getPath(x, options.cwd)); - return isDirectory ? getGlob(x, options) : x; - })); - - return [].concat.apply([], globs); // eslint-disable-line prefer-spread -}; - -module.exports.sync = (input, options) => { - options = { - cwd: process.cwd(), - ...options - }; - - if (typeof options.cwd !== 'string') { - throw new TypeError(`Expected \`cwd\` to be of type \`string\` but received type \`${typeof options.cwd}\``); - } - - const globs = [].concat(input).map(x => pathType.isDirectorySync(getPath(x, options.cwd)) ? getGlob(x, options) : x); - - return [].concat.apply([], globs); // eslint-disable-line prefer-spread -}; - - -/***/ }), -/* 375 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const {promisify} = __webpack_require__(111); -const fs = __webpack_require__(133); - -async function isType(fsStatType, statsMethodName, filePath) { - if (typeof filePath !== 'string') { - throw new TypeError(`Expected a string, got ${typeof filePath}`); - } - - try { - const stats = await promisify(fs[fsStatType])(filePath); - return stats[statsMethodName](); - } catch (error) { - if (error.code === 'ENOENT') { - return false; - } - - throw error; - } -} - -function isTypeSync(fsStatType, statsMethodName, filePath) { - if (typeof filePath !== 'string') { - throw new TypeError(`Expected a string, got ${typeof filePath}`); - } - - try { - return fs[fsStatType](filePath)[statsMethodName](); - } catch (error) { - if (error.code === 'ENOENT') { - return false; - } - - throw error; - } -} - -exports.isFile = isType.bind(null, 'stat', 'isFile'); -exports.isDirectory = isType.bind(null, 'stat', 'isDirectory'); -exports.isSymlink = isType.bind(null, 'lstat', 'isSymbolicLink'); -exports.isFileSync = isTypeSync.bind(null, 'statSync', 'isFile'); -exports.isDirectorySync = isTypeSync.bind(null, 'statSync', 'isDirectory'); -exports.isSymlinkSync = isTypeSync.bind(null, 'lstatSync', 'isSymbolicLink'); - - -/***/ }), -/* 376 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const {promisify} = __webpack_require__(111); -const fs = __webpack_require__(133); -const path = __webpack_require__(4); -const fastGlob = __webpack_require__(305); -const gitIgnore = __webpack_require__(377); -const slash = __webpack_require__(378); - -const DEFAULT_IGNORE = [ - '**/node_modules/**', - '**/flow-typed/**', - '**/coverage/**', - '**/.git' -]; - -const readFileP = promisify(fs.readFile); - -const mapGitIgnorePatternTo = base => ignore => { - if (ignore.startsWith('!')) { - return '!' + path.posix.join(base, ignore.slice(1)); - } - - return path.posix.join(base, ignore); -}; - -const parseGitIgnore = (content, options) => { - const base = slash(path.relative(options.cwd, path.dirname(options.fileName))); - - return content - .split(/\r?\n/) - .filter(Boolean) - .filter(line => !line.startsWith('#')) - .map(mapGitIgnorePatternTo(base)); -}; - -const reduceIgnore = files => { - return files.reduce((ignores, file) => { - ignores.add(parseGitIgnore(file.content, { - cwd: file.cwd, - fileName: file.filePath - })); - return ignores; - }, gitIgnore()); -}; - -const ensureAbsolutePathForCwd = (cwd, p) => { - if (path.isAbsolute(p)) { - if (p.startsWith(cwd)) { - return p; - } - - throw new Error(`Path ${p} is not in cwd ${cwd}`); - } - - return path.join(cwd, p); -}; - -const getIsIgnoredPredecate = (ignores, cwd) => { - return p => ignores.ignores(slash(path.relative(cwd, ensureAbsolutePathForCwd(cwd, p)))); -}; - -const getFile = async (file, cwd) => { - const filePath = path.join(cwd, file); - const content = await readFileP(filePath, 'utf8'); - - return { - cwd, - filePath, - content - }; -}; - -const getFileSync = (file, cwd) => { - const filePath = path.join(cwd, file); - const content = fs.readFileSync(filePath, 'utf8'); - - return { - cwd, - filePath, - content - }; -}; - -const normalizeOptions = ({ - ignore = [], - cwd = slash(process.cwd()) -} = {}) => { - return {ignore, cwd}; -}; - -module.exports = async options => { - options = normalizeOptions(options); - - const paths = await fastGlob('**/.gitignore', { - ignore: DEFAULT_IGNORE.concat(options.ignore), - cwd: options.cwd - }); - - const files = await Promise.all(paths.map(file => getFile(file, options.cwd))); - const ignores = reduceIgnore(files); - - return getIsIgnoredPredecate(ignores, options.cwd); -}; - -module.exports.sync = options => { - options = normalizeOptions(options); - - const paths = fastGlob.sync('**/.gitignore', { - ignore: DEFAULT_IGNORE.concat(options.ignore), - cwd: options.cwd - }); - - const files = paths.map(file => getFileSync(file, options.cwd)); - const ignores = reduceIgnore(files); - - return getIsIgnoredPredecate(ignores, options.cwd); -}; - - -/***/ }), -/* 377 */ -/***/ (function(module, exports) { - -// A simple implementation of make-array -function makeArray (subject) { - return Array.isArray(subject) - ? subject - : [subject] -} - -const EMPTY = '' -const SPACE = ' ' -const ESCAPE = '\\' -const REGEX_TEST_BLANK_LINE = /^\s+$/ -const REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/ -const REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/ -const REGEX_SPLITALL_CRLF = /\r?\n/g -// /foo, -// ./foo, -// ../foo, -// . -// .. -const REGEX_TEST_INVALID_PATH = /^\.*\/|^\.+$/ - -const SLASH = '/' -const KEY_IGNORE = typeof Symbol !== 'undefined' - ? Symbol.for('node-ignore') - /* istanbul ignore next */ - : 'node-ignore' - -const define = (object, key, value) => - Object.defineProperty(object, key, {value}) - -const REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g - -// Sanitize the range of a regular expression -// The cases are complicated, see test cases for details -const sanitizeRange = range => range.replace( - REGEX_REGEXP_RANGE, - (match, from, to) => from.charCodeAt(0) <= to.charCodeAt(0) - ? match - // Invalid range (out of order) which is ok for gitignore rules but - // fatal for JavaScript regular expression, so eliminate it. - : EMPTY -) - -// See fixtures #59 -const cleanRangeBackSlash = slashes => { - const {length} = slashes - return slashes.slice(0, length - length % 2) -} - -// > If the pattern ends with a slash, -// > it is removed for the purpose of the following description, -// > but it would only find a match with a directory. -// > In other words, foo/ will match a directory foo and paths underneath it, -// > but will not match a regular file or a symbolic link foo -// > (this is consistent with the way how pathspec works in general in Git). -// '`foo/`' will not match regular file '`foo`' or symbolic link '`foo`' -// -> ignore-rules will not deal with it, because it costs extra `fs.stat` call -// you could use option `mark: true` with `glob` - -// '`foo/`' should not continue with the '`..`' -const REPLACERS = [ - - // > Trailing spaces are ignored unless they are quoted with backslash ("\") - [ - // (a\ ) -> (a ) - // (a ) -> (a) - // (a \ ) -> (a ) - /\\?\s+$/, - match => match.indexOf('\\') === 0 - ? SPACE - : EMPTY - ], - - // replace (\ ) with ' ' - [ - /\\\s/g, - () => SPACE - ], - - // Escape metacharacters - // which is written down by users but means special for regular expressions. - - // > There are 12 characters with special meanings: - // > - the backslash \, - // > - the caret ^, - // > - the dollar sign $, - // > - the period or dot ., - // > - the vertical bar or pipe symbol |, - // > - the question mark ?, - // > - the asterisk or star *, - // > - the plus sign +, - // > - the opening parenthesis (, - // > - the closing parenthesis ), - // > - and the opening square bracket [, - // > - the opening curly brace {, - // > These special characters are often called "metacharacters". - [ - /[\\$.|*+(){^]/g, - match => `\\${match}` - ], - - [ - // > a question mark (?) matches a single character - /(?!\\)\?/g, - () => '[^/]' - ], - - // leading slash - [ - - // > A leading slash matches the beginning of the pathname. - // > For example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c". - // A leading slash matches the beginning of the pathname - /^\//, - () => '^' - ], - - // replace special metacharacter slash after the leading slash - [ - /\//g, - () => '\\/' - ], - - [ - // > A leading "**" followed by a slash means match in all directories. - // > For example, "**/foo" matches file or directory "foo" anywhere, - // > the same as pattern "foo". - // > "**/foo/bar" matches file or directory "bar" anywhere that is directly - // > under directory "foo". - // Notice that the '*'s have been replaced as '\\*' - /^\^*\\\*\\\*\\\//, - - // '**/foo' <-> 'foo' - () => '^(?:.*\\/)?' - ], - - // starting - [ - // there will be no leading '/' - // (which has been replaced by section "leading slash") - // If starts with '**', adding a '^' to the regular expression also works - /^(?=[^^])/, - function startingReplacer () { - // If has a slash `/` at the beginning or middle - return !/\/(?!$)/.test(this) - // > Prior to 2.22.1 - // > If the pattern does not contain a slash /, - // > Git treats it as a shell glob pattern - // Actually, if there is only a trailing slash, - // git also treats it as a shell glob pattern - - // After 2.22.1 (compatible but clearer) - // > If there is a separator at the beginning or middle (or both) - // > of the pattern, then the pattern is relative to the directory - // > level of the particular .gitignore file itself. - // > Otherwise the pattern may also match at any level below - // > the .gitignore level. - ? '(?:^|\\/)' - - // > Otherwise, Git treats the pattern as a shell glob suitable for - // > consumption by fnmatch(3) - : '^' - } - ], - - // two globstars - [ - // Use lookahead assertions so that we could match more than one `'/**'` - /\\\/\\\*\\\*(?=\\\/|$)/g, - - // Zero, one or several directories - // should not use '*', or it will be replaced by the next replacer - - // Check if it is not the last `'/**'` - (_, index, str) => index + 6 < str.length - - // case: /**/ - // > A slash followed by two consecutive asterisks then a slash matches - // > zero or more directories. - // > For example, "a/**/b" matches "a/b", "a/x/b", "a/x/y/b" and so on. - // '/**/' - ? '(?:\\/[^\\/]+)*' - - // case: /** - // > A trailing `"/**"` matches everything inside. - - // #21: everything inside but it should not include the current folder - : '\\/.+' - ], - - // intermediate wildcards - [ - // Never replace escaped '*' - // ignore rule '\*' will match the path '*' - - // 'abc.*/' -> go - // 'abc.*' -> skip this rule - /(^|[^\\]+)\\\*(?=.+)/g, - - // '*.js' matches '.js' - // '*.js' doesn't match 'abc' - (_, p1) => `${p1}[^\\/]*` - ], - - [ - // unescape, revert step 3 except for back slash - // For example, if a user escape a '\\*', - // after step 3, the result will be '\\\\\\*' - /\\\\\\(?=[$.|*+(){^])/g, - () => ESCAPE - ], - - [ - // '\\\\' -> '\\' - /\\\\/g, - () => ESCAPE - ], - - [ - // > The range notation, e.g. [a-zA-Z], - // > can be used to match one of the characters in a range. - - // `\` is escaped by step 3 - /(\\)?\[([^\]/]*?)(\\*)($|\])/g, - (match, leadEscape, range, endEscape, close) => leadEscape === ESCAPE - // '\\[bar]' -> '\\\\[bar\\]' - ? `\\[${range}${cleanRangeBackSlash(endEscape)}${close}` - : close === ']' - ? endEscape.length % 2 === 0 - // A normal case, and it is a range notation - // '[bar]' - // '[bar\\\\]' - ? `[${sanitizeRange(range)}${endEscape}]` - // Invalid range notaton - // '[bar\\]' -> '[bar\\\\]' - : '[]' - : '[]' - ], - - // ending - [ - // 'js' will not match 'js.' - // 'ab' will not match 'abc' - /(?:[^*])$/, - - // WTF! - // https://git-scm.com/docs/gitignore - // changes in [2.22.1](https://git-scm.com/docs/gitignore/2.22.1) - // which re-fixes #24, #38 - - // > If there is a separator at the end of the pattern then the pattern - // > will only match directories, otherwise the pattern can match both - // > files and directories. - - // 'js*' will not match 'a.js' - // 'js/' will not match 'a.js' - // 'js' will match 'a.js' and 'a.js/' - match => /\/$/.test(match) - // foo/ will not match 'foo' - ? `${match}$` - // foo matches 'foo' and 'foo/' - : `${match}(?=$|\\/$)` - ], - - // trailing wildcard - [ - /(\^|\\\/)?\\\*$/, - (_, p1) => { - const prefix = p1 - // '\^': - // '/*' does not match EMPTY - // '/*' does not match everything - - // '\\\/': - // 'abc/*' does not match 'abc/' - ? `${p1}[^/]+` - - // 'a*' matches 'a' - // 'a*' matches 'aa' - : '[^/]*' - - return `${prefix}(?=$|\\/$)` - } - ], -] - -// A simple cache, because an ignore rule only has only one certain meaning -const regexCache = Object.create(null) - -// @param {pattern} -const makeRegex = (pattern, negative, ignorecase) => { - const r = regexCache[pattern] - if (r) { - return r - } - - // const replacers = negative - // ? NEGATIVE_REPLACERS - // : POSITIVE_REPLACERS - - const source = REPLACERS.reduce( - (prev, current) => prev.replace(current[0], current[1].bind(pattern)), - pattern - ) - - return regexCache[pattern] = ignorecase - ? new RegExp(source, 'i') - : new RegExp(source) -} - -const isString = subject => typeof subject === 'string' - -// > A blank line matches no files, so it can serve as a separator for readability. -const checkPattern = pattern => pattern - && isString(pattern) - && !REGEX_TEST_BLANK_LINE.test(pattern) - - // > A line starting with # serves as a comment. - && pattern.indexOf('#') !== 0 - -const splitPattern = pattern => pattern.split(REGEX_SPLITALL_CRLF) - -class IgnoreRule { - constructor ( - origin, - pattern, - negative, - regex - ) { - this.origin = origin - this.pattern = pattern - this.negative = negative - this.regex = regex - } -} - -const createRule = (pattern, ignorecase) => { - const origin = pattern - let negative = false - - // > An optional prefix "!" which negates the pattern; - if (pattern.indexOf('!') === 0) { - negative = true - pattern = pattern.substr(1) - } - - pattern = pattern - // > Put a backslash ("\") in front of the first "!" for patterns that - // > begin with a literal "!", for example, `"\!important!.txt"`. - .replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, '!') - // > Put a backslash ("\") in front of the first hash for patterns that - // > begin with a hash. - .replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, '#') - - const regex = makeRegex(pattern, negative, ignorecase) - - return new IgnoreRule( - origin, - pattern, - negative, - regex - ) -} - -const throwError = (message, Ctor) => { - throw new Ctor(message) -} - -const checkPath = (path, originalPath, doThrow) => { - if (!isString(path)) { - return doThrow( - `path must be a string, but got \`${originalPath}\``, - TypeError - ) - } - - // We don't know if we should ignore EMPTY, so throw - if (!path) { - return doThrow(`path must not be empty`, TypeError) - } - - // Check if it is a relative path - if (checkPath.isNotRelative(path)) { - const r = '`path.relative()`d' - return doThrow( - `path should be a ${r} string, but got "${originalPath}"`, - RangeError - ) - } - - return true -} - -const isNotRelative = path => REGEX_TEST_INVALID_PATH.test(path) - -checkPath.isNotRelative = isNotRelative -checkPath.convert = p => p - -class Ignore { - constructor ({ - ignorecase = true - } = {}) { - this._rules = [] - this._ignorecase = ignorecase - define(this, KEY_IGNORE, true) - this._initCache() - } - - _initCache () { - this._ignoreCache = Object.create(null) - this._testCache = Object.create(null) - } - - _addPattern (pattern) { - // #32 - if (pattern && pattern[KEY_IGNORE]) { - this._rules = this._rules.concat(pattern._rules) - this._added = true - return - } - - if (checkPattern(pattern)) { - const rule = createRule(pattern, this._ignorecase) - this._added = true - this._rules.push(rule) - } - } - - // @param {Array | string | Ignore} pattern - add (pattern) { - this._added = false - - makeArray( - isString(pattern) - ? splitPattern(pattern) - : pattern - ).forEach(this._addPattern, this) - - // Some rules have just added to the ignore, - // making the behavior changed. - if (this._added) { - this._initCache() - } - - return this - } - - // legacy - addPattern (pattern) { - return this.add(pattern) - } - - // | ignored : unignored - // negative | 0:0 | 0:1 | 1:0 | 1:1 - // -------- | ------- | ------- | ------- | -------- - // 0 | TEST | TEST | SKIP | X - // 1 | TESTIF | SKIP | TEST | X - - // - SKIP: always skip - // - TEST: always test - // - TESTIF: only test if checkUnignored - // - X: that never happen - - // @param {boolean} whether should check if the path is unignored, - // setting `checkUnignored` to `false` could reduce additional - // path matching. - - // @returns {TestResult} true if a file is ignored - _testOne (path, checkUnignored) { - let ignored = false - let unignored = false - - this._rules.forEach(rule => { - const {negative} = rule - if ( - unignored === negative && ignored !== unignored - || negative && !ignored && !unignored && !checkUnignored - ) { - return - } - - const matched = rule.regex.test(path) - - if (matched) { - ignored = !negative - unignored = negative - } - }) - - return { - ignored, - unignored - } - } - - // @returns {TestResult} - _test (originalPath, cache, checkUnignored, slices) { - const path = originalPath - // Supports nullable path - && checkPath.convert(originalPath) - - checkPath(path, originalPath, throwError) - - return this._t(path, cache, checkUnignored, slices) - } - - _t (path, cache, checkUnignored, slices) { - if (path in cache) { - return cache[path] - } - - if (!slices) { - // path/to/a.js - // ['path', 'to', 'a.js'] - slices = path.split(SLASH) - } - - slices.pop() - - // If the path has no parent directory, just test it - if (!slices.length) { - return cache[path] = this._testOne(path, checkUnignored) - } - - const parent = this._t( - slices.join(SLASH) + SLASH, - cache, - checkUnignored, - slices - ) - - // If the path contains a parent directory, check the parent first - return cache[path] = parent.ignored - // > It is not possible to re-include a file if a parent directory of - // > that file is excluded. - ? parent - : this._testOne(path, checkUnignored) - } - - ignores (path) { - return this._test(path, this._ignoreCache, false).ignored - } - - createFilter () { - return path => !this.ignores(path) - } - - filter (paths) { - return makeArray(paths).filter(this.createFilter()) - } - - // @returns {TestResult} - test (path) { - return this._test(path, this._testCache, true) - } -} - -const factory = options => new Ignore(options) - -const returnFalse = () => false - -const isPathValid = path => - checkPath(path && checkPath.convert(path), path, returnFalse) - -factory.isPathValid = isPathValid - -// Fixes typescript -factory.default = factory - -module.exports = factory - -// Windows -// -------------------------------------------------------------- -/* istanbul ignore if */ -if ( - // Detect `process` so that it can run in browsers. - typeof process !== 'undefined' - && ( - process.env && process.env.IGNORE_TEST_WIN32 - || process.platform === 'win32' - ) -) { - /* eslint no-control-regex: "off" */ - const makePosix = str => /^\\\\\?\\/.test(str) - || /["<>|\u0000-\u001F]+/u.test(str) - ? str - : str.replace(/\\/g, '/') - - checkPath.convert = makePosix - - // 'C:\\foo' <- 'C:\\foo' has been converted to 'C:/' - // 'd:\\foo' - const REGIX_IS_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i - checkPath.isNotRelative = path => - REGIX_IS_WINDOWS_PATH_ABSOLUTE.test(path) - || isNotRelative(path) -} - - -/***/ }), -/* 378 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -module.exports = path => { - const isExtendedLengthPath = /^\\\\\?\\/.test(path); - const hasNonAscii = /[^\u0000-\u0080]+/.test(path); // eslint-disable-line no-control-regex - - if (isExtendedLengthPath || hasNonAscii) { - return path; - } - - return path.replace(/\\/g, '/'); -}; - - -/***/ }), -/* 379 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const {Transform} = __webpack_require__(137); - -class ObjectTransform extends Transform { - constructor() { - super({ - objectMode: true - }); - } -} - -class FilterStream extends ObjectTransform { - constructor(filter) { - super(); - this._filter = filter; - } - - _transform(data, encoding, callback) { - if (this._filter(data)) { - this.push(data); - } - - callback(); - } -} - -class UniqueStream extends ObjectTransform { - constructor() { - super(); - this._pushed = new Set(); - } - - _transform(data, encoding, callback) { - if (!this._pushed.has(data)) { - this.push(data); - this._pushed.add(data); - } - - callback(); - } -} - -module.exports = { - FilterStream, - UniqueStream -}; - - -/***/ }), -/* 380 */ -/***/ (function(module, exports, __webpack_require__) { - -/*! - * is-glob - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ - -var isExtglob = __webpack_require__(315); -var chars = { '{': '}', '(': ')', '[': ']'}; -var strictRegex = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/; -var relaxedRegex = /\\(.)|(^!|[*?{}()[\]]|\(\?)/; - -module.exports = function isGlob(str, options) { - if (typeof str !== 'string' || str === '') { - return false; - } - - if (isExtglob(str)) { - return true; - } - - var regex = strictRegex; - var match; - - // optionally relax regex - if (options && options.strict === false) { - regex = relaxedRegex; - } - - 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; -}; - - -/***/ }), -/* 381 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const path = __webpack_require__(4); - -module.exports = path_ => { - let cwd = process.cwd(); - - path_ = path.resolve(path_); - - if (process.platform === 'win32') { - cwd = cwd.toLowerCase(); - path_ = path_.toLowerCase(); - } - - return path_ === cwd; -}; - - -/***/ }), -/* 382 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const path = __webpack_require__(4); - -module.exports = (childPath, parentPath) => { - childPath = path.resolve(childPath); - parentPath = path.resolve(parentPath); - - if (process.platform === 'win32') { - childPath = childPath.toLowerCase(); - parentPath = parentPath.toLowerCase(); - } - - if (childPath === parentPath) { - return false; - } - - childPath += path.sep; - parentPath += path.sep; - - return childPath.startsWith(parentPath); -}; - - -/***/ }), -/* 383 */ -/***/ (function(module, exports, __webpack_require__) { - -const assert = __webpack_require__(139) -const path = __webpack_require__(4) -const fs = __webpack_require__(133) -let glob = undefined -try { - glob = __webpack_require__(300) -} catch (_err) { - // treat glob as optional. -} - -const defaultGlobOpts = { - nosort: true, - silent: true -} - -// for EMFILE handling -let timeout = 0 - -const isWindows = (process.platform === "win32") - -const defaults = options => { - const methods = [ - 'unlink', - 'chmod', - 'stat', - 'lstat', - 'rmdir', - 'readdir' - ] - methods.forEach(m => { - options[m] = options[m] || fs[m] - m = m + 'Sync' - options[m] = options[m] || fs[m] - }) - - options.maxBusyTries = options.maxBusyTries || 3 - options.emfileWait = options.emfileWait || 1000 - if (options.glob === false) { - options.disableGlob = true - } - if (options.disableGlob !== true && glob === undefined) { - throw Error('glob dependency not found, set `options.disableGlob = true` if intentional') - } - options.disableGlob = options.disableGlob || false - options.glob = options.glob || defaultGlobOpts -} - -const rimraf = (p, options, cb) => { - if (typeof options === 'function') { - cb = options - options = {} - } - - assert(p, 'rimraf: missing path') - assert.equal(typeof p, 'string', 'rimraf: path should be a string') - assert.equal(typeof cb, 'function', 'rimraf: callback function required') - assert(options, 'rimraf: invalid options argument provided') - assert.equal(typeof options, 'object', 'rimraf: options should be object') - - defaults(options) - - let busyTries = 0 - let errState = null - let n = 0 - - const next = (er) => { - errState = errState || er - if (--n === 0) - cb(errState) - } - - const afterGlob = (er, results) => { - if (er) - return cb(er) - - n = results.length - if (n === 0) - return cb() - - results.forEach(p => { - const CB = (er) => { - if (er) { - if ((er.code === "EBUSY" || er.code === "ENOTEMPTY" || er.code === "EPERM") && - busyTries < options.maxBusyTries) { - busyTries ++ - // try again, with the same exact callback as this one. - return setTimeout(() => rimraf_(p, options, CB), busyTries * 100) - } - - // this one won't happen if graceful-fs is used. - if (er.code === "EMFILE" && timeout < options.emfileWait) { - return setTimeout(() => rimraf_(p, options, CB), timeout ++) - } - - // already gone - if (er.code === "ENOENT") er = null - } - - timeout = 0 - next(er) - } - rimraf_(p, options, CB) - }) - } - - if (options.disableGlob || !glob.hasMagic(p)) - return afterGlob(null, [p]) - - options.lstat(p, (er, stat) => { - if (!er) - return afterGlob(null, [p]) - - glob(p, options.glob, afterGlob) - }) - -} - -// Two possible strategies. -// 1. Assume it's a file. unlink it, then do the dir stuff on EPERM or EISDIR -// 2. Assume it's a directory. readdir, then do the file stuff on ENOTDIR -// -// Both result in an extra syscall when you guess wrong. However, there -// are likely far more normal files in the world than directories. This -// is based on the assumption that a the average number of files per -// directory is >= 1. -// -// If anyone ever complains about this, then I guess the strategy could -// be made configurable somehow. But until then, YAGNI. -const rimraf_ = (p, options, cb) => { - assert(p) - assert(options) - assert(typeof cb === 'function') - - // sunos lets the root user unlink directories, which is... weird. - // so we have to lstat here and make sure it's not a dir. - options.lstat(p, (er, st) => { - if (er && er.code === "ENOENT") - return cb(null) - - // Windows can EPERM on stat. Life is suffering. - if (er && er.code === "EPERM" && isWindows) - fixWinEPERM(p, options, er, cb) - - if (st && st.isDirectory()) - return rmdir(p, options, er, cb) - - options.unlink(p, er => { - if (er) { - if (er.code === "ENOENT") - return cb(null) - if (er.code === "EPERM") - return (isWindows) - ? fixWinEPERM(p, options, er, cb) - : rmdir(p, options, er, cb) - if (er.code === "EISDIR") - return rmdir(p, options, er, cb) - } - return cb(er) - }) - }) -} - -const fixWinEPERM = (p, options, er, cb) => { - assert(p) - assert(options) - assert(typeof cb === 'function') - if (er) - assert(er instanceof Error) - - options.chmod(p, 0o666, er2 => { - if (er2) - cb(er2.code === "ENOENT" ? null : er) - else - options.stat(p, (er3, stats) => { - if (er3) - cb(er3.code === "ENOENT" ? null : er) - else if (stats.isDirectory()) - rmdir(p, options, er, cb) - else - options.unlink(p, cb) - }) - }) -} - -const fixWinEPERMSync = (p, options, er) => { - assert(p) - assert(options) - if (er) - assert(er instanceof Error) - - try { - options.chmodSync(p, 0o666) - } catch (er2) { - if (er2.code === "ENOENT") - return - else - throw er - } - - let stats - try { - stats = options.statSync(p) - } catch (er3) { - if (er3.code === "ENOENT") - return - else - throw er - } - - if (stats.isDirectory()) - rmdirSync(p, options, er) - else - options.unlinkSync(p) -} - -const rmdir = (p, options, originalEr, cb) => { - assert(p) - assert(options) - if (originalEr) - assert(originalEr instanceof Error) - assert(typeof cb === 'function') - - // try to rmdir first, and only readdir on ENOTEMPTY or EEXIST (SunOS) - // if we guessed wrong, and it's not a directory, then - // raise the original error. - options.rmdir(p, er => { - if (er && (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM")) - rmkids(p, options, cb) - else if (er && er.code === "ENOTDIR") - cb(originalEr) - else - cb(er) - }) -} - -const rmkids = (p, options, cb) => { - assert(p) - assert(options) - assert(typeof cb === 'function') - - options.readdir(p, (er, files) => { - if (er) - return cb(er) - let n = files.length - if (n === 0) - return options.rmdir(p, cb) - let errState - files.forEach(f => { - rimraf(path.join(p, f), options, er => { - if (errState) - return - if (er) - return cb(errState = er) - if (--n === 0) - options.rmdir(p, cb) - }) - }) - }) -} - -// this looks simpler, and is strictly *faster*, but will -// tie up the JavaScript thread and fail on excessively -// deep directory trees. -const rimrafSync = (p, options) => { - options = options || {} - defaults(options) - - assert(p, 'rimraf: missing path') - assert.equal(typeof p, 'string', 'rimraf: path should be a string') - assert(options, 'rimraf: missing options') - assert.equal(typeof options, 'object', 'rimraf: options should be object') - - let results - - if (options.disableGlob || !glob.hasMagic(p)) { - results = [p] - } else { - try { - options.lstatSync(p) - results = [p] - } catch (er) { - results = glob.sync(p, options.glob) - } - } - - if (!results.length) - return - - for (let i = 0; i < results.length; i++) { - const p = results[i] - - let st - try { - st = options.lstatSync(p) - } catch (er) { - if (er.code === "ENOENT") - return - - // Windows can EPERM on stat. Life is suffering. - if (er.code === "EPERM" && isWindows) - fixWinEPERMSync(p, options, er) - } +/***/ }), +/* 361 */ +/***/ (function(module, exports, __webpack_require__) { - try { - // sunos lets the root user unlink directories, which is... weird. - if (st && st.isDirectory()) - rmdirSync(p, options, null) - else - options.unlinkSync(p) - } catch (er) { - if (er.code === "ENOENT") - return - if (er.code === "EPERM") - return isWindows ? fixWinEPERMSync(p, options, er) : rmdirSync(p, options, er) - if (er.code !== "EISDIR") - throw er +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const utils = __webpack_require__(302); +class Matcher { + constructor(_patterns, _settings, _micromatchOptions) { + this._patterns = _patterns; + this._settings = _settings; + this._micromatchOptions = _micromatchOptions; + this._storage = []; + this._fillStorage(); + } + _fillStorage() { + /** + * The original pattern may include `{,*,**,a/*}`, which will lead to problems with matching (unresolved level). + * So, before expand patterns with brace expansion into separated patterns. + */ + const patterns = utils.pattern.expandPatternsWithBraceExpansion(this._patterns); + for (const pattern of patterns) { + const segments = this._getPatternSegments(pattern); + const sections = this._splitSegmentsIntoSections(segments); + this._storage.push({ + complete: sections.length <= 1, + pattern, + segments, + sections + }); + } + } + _getPatternSegments(pattern) { + const parts = utils.pattern.getPatternParts(pattern, this._micromatchOptions); + return parts.map((part) => { + const dynamic = utils.pattern.isDynamicPattern(part, this._settings); + if (!dynamic) { + return { + dynamic: false, + pattern: part + }; + } + return { + dynamic: true, + pattern: part, + patternRe: utils.pattern.makeRe(part, this._micromatchOptions) + }; + }); + } + _splitSegmentsIntoSections(segments) { + return utils.array.splitWhen(segments, (segment) => segment.dynamic && utils.pattern.hasGlobStar(segment.pattern)); + } +} +exports.default = Matcher; - rmdirSync(p, options, er) - } - } -} -const rmdirSync = (p, options, originalEr) => { - assert(p) - assert(options) - if (originalEr) - assert(originalEr instanceof Error) +/***/ }), +/* 362 */ +/***/ (function(module, exports, __webpack_require__) { - try { - options.rmdirSync(p) - } catch (er) { - if (er.code === "ENOENT") - return - if (er.code === "ENOTDIR") - throw originalEr - if (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM") - rmkidsSync(p, options) - } -} +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const utils = __webpack_require__(302); +class EntryFilter { + constructor(_settings, _micromatchOptions) { + this._settings = _settings; + this._micromatchOptions = _micromatchOptions; + this.index = new Map(); + } + getFilter(positive, negative) { + const positiveRe = utils.pattern.convertPatternsToRe(positive, this._micromatchOptions); + const negativeRe = utils.pattern.convertPatternsToRe(negative, this._micromatchOptions); + return (entry) => this._filter(entry, positiveRe, negativeRe); + } + _filter(entry, positiveRe, negativeRe) { + if (this._settings.unique) { + if (this._isDuplicateEntry(entry)) { + return false; + } + this._createIndexRecord(entry); + } + if (this._onlyFileFilter(entry) || this._onlyDirectoryFilter(entry)) { + return false; + } + if (this._isSkippedByAbsoluteNegativePatterns(entry, negativeRe)) { + return false; + } + const filepath = this._settings.baseNameMatch ? entry.name : entry.path; + return this._isMatchToPatterns(filepath, positiveRe) && !this._isMatchToPatterns(entry.path, negativeRe); + } + _isDuplicateEntry(entry) { + return this.index.has(entry.path); + } + _createIndexRecord(entry) { + this.index.set(entry.path, undefined); + } + _onlyFileFilter(entry) { + return this._settings.onlyFiles && !entry.dirent.isFile(); + } + _onlyDirectoryFilter(entry) { + return this._settings.onlyDirectories && !entry.dirent.isDirectory(); + } + _isSkippedByAbsoluteNegativePatterns(entry, negativeRe) { + if (!this._settings.absolute) { + return false; + } + const fullpath = utils.path.makeAbsolute(this._settings.cwd, entry.path); + return this._isMatchToPatterns(fullpath, negativeRe); + } + _isMatchToPatterns(entryPath, patternsRe) { + const filepath = utils.path.removeLeadingDotSegment(entryPath); + return utils.pattern.matchAny(filepath, patternsRe); + } +} +exports.default = EntryFilter; -const rmkidsSync = (p, options) => { - assert(p) - assert(options) - options.readdirSync(p).forEach(f => rimrafSync(path.join(p, f), options)) - // We only end up here once we got ENOTEMPTY at least once, and - // at this point, we are guaranteed to have removed all the kids. - // So, we know that it won't be ENOENT or ENOTDIR or anything else. - // try really hard to delete stuff on windows, because it has a - // PROFOUNDLY annoying habit of not closing handles promptly when - // files are deleted, resulting in spurious ENOTEMPTY errors. - const retries = isWindows ? 100 : 1 - let i = 0 - do { - let threw = true - try { - const ret = options.rmdirSync(p, options) - threw = false - return ret - } finally { - if (++i < retries && threw) - continue - } - } while (true) -} +/***/ }), +/* 363 */ +/***/ (function(module, exports, __webpack_require__) { -module.exports = rimraf -rimraf.sync = rimrafSync +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const utils = __webpack_require__(302); +class ErrorFilter { + constructor(_settings) { + this._settings = _settings; + } + getFilter() { + return (error) => this._isNonFatalError(error); + } + _isNonFatalError(error) { + return utils.errno.isEnoentCodeError(error) || this._settings.suppressErrors; + } +} +exports.default = ErrorFilter; /***/ }), -/* 384 */ +/* 364 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const utils = __webpack_require__(302); +class EntryTransformer { + constructor(_settings) { + this._settings = _settings; + } + getTransformer() { + return (entry) => this._transform(entry); + } + _transform(entry) { + let filepath = entry.path; + if (this._settings.absolute) { + filepath = utils.path.makeAbsolute(this._settings.cwd, filepath); + filepath = utils.path.unixify(filepath); + } + if (this._settings.markDirectories && entry.dirent.isDirectory()) { + filepath += '/'; + } + if (!this._settings.objectMode) { + return filepath; + } + return Object.assign(Object.assign({}, entry), { path: filepath }); + } +} +exports.default = EntryTransformer; -const AggregateError = __webpack_require__(385); - -module.exports = async ( - iterable, - mapper, - { - concurrency = Infinity, - stopOnError = true - } = {} -) => { - return new Promise((resolve, reject) => { - if (typeof mapper !== 'function') { - throw new TypeError('Mapper function is required'); - } - if (!(typeof concurrency === 'number' && concurrency >= 1)) { - throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${concurrency}\` (${typeof concurrency})`); - } +/***/ }), +/* 365 */ +/***/ (function(module, exports, __webpack_require__) { - const ret = []; - const errors = []; - const iterator = iterable[Symbol.iterator](); - let isRejected = false; - let isIterableDone = false; - let resolvingCount = 0; - let currentIndex = 0; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const stream_1 = __webpack_require__(137); +const stream_2 = __webpack_require__(331); +const provider_1 = __webpack_require__(358); +class ProviderStream extends provider_1.default { + constructor() { + super(...arguments); + this._reader = new stream_2.default(this._settings); + } + read(task) { + const root = this._getRootDirectory(task); + const options = this._getReaderOptions(task); + const source = this.api(root, task, options); + const destination = new stream_1.Readable({ objectMode: true, read: () => { } }); + source + .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) { + return this._reader.dynamic(root, options); + } + return this._reader.static(task.patterns, options); + } +} +exports.default = ProviderStream; - const next = () => { - if (isRejected) { - return; - } - const nextItem = iterator.next(); - const i = currentIndex; - currentIndex++; +/***/ }), +/* 366 */ +/***/ (function(module, exports, __webpack_require__) { - if (nextItem.done) { - isIterableDone = true; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const sync_1 = __webpack_require__(367); +const provider_1 = __webpack_require__(358); +class ProviderSync extends provider_1.default { + constructor() { + super(...arguments); + this._reader = new sync_1.default(this._settings); + } + read(task) { + const root = this._getRootDirectory(task); + const options = this._getReaderOptions(task); + const entries = this.api(root, task, options); + return entries.map(options.transform); + } + api(root, task, options) { + if (task.dynamic) { + return this._reader.dynamic(root, options); + } + return this._reader.static(task.patterns, options); + } +} +exports.default = ProviderSync; - if (resolvingCount === 0) { - if (!stopOnError && errors.length !== 0) { - reject(new AggregateError(errors)); - } else { - resolve(ret); - } - } - return; - } +/***/ }), +/* 367 */ +/***/ (function(module, exports, __webpack_require__) { - resolvingCount++; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const fsStat = __webpack_require__(332); +const fsWalk = __webpack_require__(337); +const reader_1 = __webpack_require__(357); +class ReaderSync extends reader_1.default { + constructor() { + super(...arguments); + this._walkSync = fsWalk.walkSync; + this._statSync = fsStat.statSync; + } + dynamic(root, options) { + return this._walkSync(root, options); + } + static(patterns, options) { + const entries = []; + for (const pattern of patterns) { + const filepath = this._getFullEntryPath(pattern); + const entry = this._getEntry(filepath, pattern, options); + if (entry === null || !options.entryFilter(entry)) { + continue; + } + entries.push(entry); + } + return entries; + } + _getEntry(filepath, pattern, options) { + try { + const stats = this._getStat(filepath); + return this._makeEntry(stats, pattern); + } + catch (error) { + if (options.errorFilter(error)) { + return null; + } + throw error; + } + } + _getStat(filepath) { + return this._statSync(filepath, this._fsStatSettings); + } +} +exports.default = ReaderSync; - (async () => { - try { - const element = await nextItem.value; - ret[i] = await mapper(element, i); - resolvingCount--; - next(); - } catch (error) { - if (stopOnError) { - isRejected = true; - reject(error); - } else { - errors.push(error); - resolvingCount--; - next(); - } - } - })(); - }; - for (let i = 0; i < concurrency; i++) { - next(); +/***/ }), +/* 368 */ +/***/ (function(module, exports, __webpack_require__) { - if (isIterableDone) { - break; - } - } - }); -}; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const fs = __webpack_require__(133); +const os = __webpack_require__(120); +const CPU_COUNT = os.cpus().length; +exports.DEFAULT_FILE_SYSTEM_ADAPTER = { + lstat: fs.lstat, + lstatSync: fs.lstatSync, + stat: fs.stat, + statSync: fs.statSync, + readdir: fs.readdir, + readdirSync: fs.readdirSync +}; +class Settings { + constructor(_options = {}) { + this._options = _options; + this.absolute = this._getValue(this._options.absolute, false); + this.baseNameMatch = this._getValue(this._options.baseNameMatch, false); + this.braceExpansion = this._getValue(this._options.braceExpansion, true); + this.caseSensitiveMatch = this._getValue(this._options.caseSensitiveMatch, true); + this.concurrency = this._getValue(this._options.concurrency, CPU_COUNT); + this.cwd = this._getValue(this._options.cwd, process.cwd()); + this.deep = this._getValue(this._options.deep, Infinity); + this.dot = this._getValue(this._options.dot, false); + this.extglob = this._getValue(this._options.extglob, true); + this.followSymbolicLinks = this._getValue(this._options.followSymbolicLinks, true); + this.fs = this._getFileSystemMethods(this._options.fs); + this.globstar = this._getValue(this._options.globstar, true); + this.ignore = this._getValue(this._options.ignore, []); + this.markDirectories = this._getValue(this._options.markDirectories, false); + this.objectMode = this._getValue(this._options.objectMode, false); + this.onlyDirectories = this._getValue(this._options.onlyDirectories, false); + this.onlyFiles = this._getValue(this._options.onlyFiles, true); + this.stats = this._getValue(this._options.stats, false); + this.suppressErrors = this._getValue(this._options.suppressErrors, false); + this.throwErrorOnBrokenSymbolicLink = this._getValue(this._options.throwErrorOnBrokenSymbolicLink, false); + this.unique = this._getValue(this._options.unique, true); + if (this.onlyDirectories) { + this.onlyFiles = false; + } + if (this.stats) { + this.objectMode = true; + } + } + _getValue(option, value) { + return option === undefined ? value : option; + } + _getFileSystemMethods(methods = {}) { + return Object.assign(Object.assign({}, exports.DEFAULT_FILE_SYSTEM_ADAPTER), methods); + } +} +exports.default = Settings; /***/ }), -/* 385 */ +/* 369 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const indentString = __webpack_require__(386); -const cleanStack = __webpack_require__(387); - -const cleanInternalStack = stack => stack.replace(/\s+at .*aggregate-error\/index.js:\d+:\d+\)?/g, ''); - -class AggregateError extends Error { - constructor(errors) { - if (!Array.isArray(errors)) { - throw new TypeError(`Expected input to be an Array, got ${typeof errors}`); - } - - errors = [...errors].map(error => { - if (error instanceof Error) { - return error; - } +const path = __webpack_require__(4); +const pathType = __webpack_require__(370); - if (error !== null && typeof error === 'object') { - // Handle plain error objects with message property and/or possibly other metadata - return Object.assign(new Error(error.message), error); - } +const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; - return new Error(error); - }); +const getPath = (filepath, cwd) => { + const pth = filepath[0] === '!' ? filepath.slice(1) : filepath; + return path.isAbsolute(pth) ? pth : path.join(cwd, pth); +}; - let message = errors - .map(error => { - // The `stack` property is not standardized, so we can't assume it exists - return typeof error.stack === 'string' ? cleanInternalStack(cleanStack(error.stack)) : String(error); - }) - .join('\n'); - message = '\n' + indentString(message, 4); - super(message); +const addExtensions = (file, extensions) => { + if (path.extname(file)) { + return `**/${file}`; + } - this.name = 'AggregateError'; + return `**/${file}.${getExtensions(extensions)}`; +}; - Object.defineProperty(this, '_errors', {value: errors}); +const getGlob = (directory, options) => { + if (options.files && !Array.isArray(options.files)) { + throw new TypeError(`Expected \`files\` to be of type \`Array\` but received type \`${typeof options.files}\``); } - * [Symbol.iterator]() { - for (const error of this._errors) { - yield error; - } + if (options.extensions && !Array.isArray(options.extensions)) { + throw new TypeError(`Expected \`extensions\` to be of type \`Array\` but received type \`${typeof options.extensions}\``); } -} - -module.exports = AggregateError; + if (options.files && options.extensions) { + return options.files.map(x => path.posix.join(directory, addExtensions(x, options.extensions))); + } -/***/ }), -/* 386 */ -/***/ (function(module, exports, __webpack_require__) { + if (options.files) { + return options.files.map(x => path.posix.join(directory, `**/${x}`)); + } -"use strict"; + if (options.extensions) { + return [path.posix.join(directory, `**/*.${getExtensions(options.extensions)}`)]; + } + return [path.posix.join(directory, '**')]; +}; -module.exports = (string, count = 1, options) => { +module.exports = async (input, options) => { options = { - indent: ' ', - includeEmptyLines: false, + cwd: process.cwd(), ...options }; - if (typeof string !== 'string') { - throw new TypeError( - `Expected \`input\` to be a \`string\`, got \`${typeof string}\`` - ); - } - - if (typeof count !== 'number') { - throw new TypeError( - `Expected \`count\` to be a \`number\`, got \`${typeof count}\`` - ); - } - - if (typeof options.indent !== 'string') { - throw new TypeError( - `Expected \`options.indent\` to be a \`string\`, got \`${typeof options.indent}\`` - ); - } - - if (count === 0) { - return string; + if (typeof options.cwd !== 'string') { + throw new TypeError(`Expected \`cwd\` to be of type \`string\` but received type \`${typeof options.cwd}\``); } - const regex = options.includeEmptyLines ? /^/gm : /^(?!\s*$)/gm; + const globs = await Promise.all([].concat(input).map(async x => { + const isDirectory = await pathType.isDirectory(getPath(x, options.cwd)); + return isDirectory ? getGlob(x, options) : x; + })); - return string.replace(regex, options.indent.repeat(count)); + return [].concat.apply([], globs); // eslint-disable-line prefer-spread }; +module.exports.sync = (input, options) => { + options = { + cwd: process.cwd(), + ...options + }; -/***/ }), -/* 387 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const os = __webpack_require__(120); - -const extractPathRegex = /\s+at.*(?:\(|\s)(.*)\)?/; -const pathRegex = /^(?:(?:(?:node|(?:internal\/[\w/]*|.*node_modules\/(?:babel-polyfill|pirates)\/.*)?\w+)\.js:\d+:\d+)|native)/; -const homeDir = typeof os.homedir === 'undefined' ? '' : os.homedir(); - -module.exports = (stack, options) => { - options = Object.assign({pretty: false}, options); - - return stack.replace(/\\/g, '/') - .split('\n') - .filter(line => { - const pathMatches = line.match(extractPathRegex); - if (pathMatches === null || !pathMatches[1]) { - return true; - } - - const match = pathMatches[1]; - - // Electron - if ( - match.includes('.app/Contents/Resources/electron.asar') || - match.includes('.app/Contents/Resources/default_app.asar') - ) { - return false; - } + if (typeof options.cwd !== 'string') { + throw new TypeError(`Expected \`cwd\` to be of type \`string\` but received type \`${typeof options.cwd}\``); + } - return !pathRegex.test(match); - }) - .filter(line => line.trim() !== '') - .map(line => { - if (options.pretty) { - return line.replace(extractPathRegex, (m, p1) => m.replace(p1, p1.replace(homeDir, '~'))); - } + const globs = [].concat(input).map(x => pathType.isDirectorySync(getPath(x, options.cwd)) ? getGlob(x, options) : x); - return line; - }) - .join('\n'); + return [].concat.apply([], globs); // eslint-disable-line prefer-spread }; /***/ }), -/* 388 */ +/* 370 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const chalk = __webpack_require__(389); -const cliCursor = __webpack_require__(392); -const cliSpinners = __webpack_require__(396); -const logSymbols = __webpack_require__(398); - -class Ora { - constructor(options) { - if (typeof options === 'string') { - options = { - text: options - }; - } - - this.options = Object.assign({ - text: '', - color: 'cyan', - stream: process.stderr - }, options); - - const sp = this.options.spinner; - this.spinner = typeof sp === 'object' ? sp : (process.platform === 'win32' ? cliSpinners.line : (cliSpinners[sp] || cliSpinners.dots)); // eslint-disable-line no-nested-ternary - - if (this.spinner.frames === undefined) { - throw new Error('Spinner must define `frames`'); - } +const {promisify} = __webpack_require__(111); +const fs = __webpack_require__(133); - this.text = this.options.text; - this.color = this.options.color; - this.interval = this.options.interval || this.spinner.interval || 100; - this.stream = this.options.stream; - this.id = null; - this.frameIndex = 0; - this.enabled = typeof this.options.enabled === 'boolean' ? this.options.enabled : ((this.stream && this.stream.isTTY) && !process.env.CI); +async function isType(fsStatType, statsMethodName, filePath) { + if (typeof filePath !== 'string') { + throw new TypeError(`Expected a string, got ${typeof filePath}`); } - frame() { - const frames = this.spinner.frames; - let frame = frames[this.frameIndex]; - if (this.color) { - frame = chalk[this.color](frame); + try { + const stats = await promisify(fs[fsStatType])(filePath); + return stats[statsMethodName](); + } catch (error) { + if (error.code === 'ENOENT') { + return false; } - this.frameIndex = ++this.frameIndex % frames.length; - - return frame + ' ' + this.text; + throw error; } - clear() { - if (!this.enabled) { - return this; - } - - this.stream.clearLine(); - this.stream.cursorTo(0); +} - return this; +function isTypeSync(fsStatType, statsMethodName, filePath) { + if (typeof filePath !== 'string') { + throw new TypeError(`Expected a string, got ${typeof filePath}`); } - render() { - this.clear(); - this.stream.write(this.frame()); - return this; - } - start(text) { - if (text) { - this.text = text; + try { + return fs[fsStatType](filePath)[statsMethodName](); + } catch (error) { + if (error.code === 'ENOENT') { + return false; } - if (!this.enabled || this.id) { - return this; - } + throw error; + } +} - cliCursor.hide(this.stream); - this.render(); - this.id = setInterval(this.render.bind(this), this.interval); +exports.isFile = isType.bind(null, 'stat', 'isFile'); +exports.isDirectory = isType.bind(null, 'stat', 'isDirectory'); +exports.isSymlink = isType.bind(null, 'lstat', 'isSymbolicLink'); +exports.isFileSync = isTypeSync.bind(null, 'statSync', 'isFile'); +exports.isDirectorySync = isTypeSync.bind(null, 'statSync', 'isDirectory'); +exports.isSymlinkSync = isTypeSync.bind(null, 'lstatSync', 'isSymbolicLink'); - return this; - } - stop() { - if (!this.enabled) { - return this; - } - clearInterval(this.id); - this.id = null; - this.frameIndex = 0; - this.clear(); - cliCursor.show(this.stream); +/***/ }), +/* 371 */ +/***/ (function(module, exports, __webpack_require__) { - return this; - } - succeed(text) { - return this.stopAndPersist({symbol: logSymbols.success, text}); - } - fail(text) { - return this.stopAndPersist({symbol: logSymbols.error, text}); - } - warn(text) { - return this.stopAndPersist({symbol: logSymbols.warning, text}); - } - info(text) { - return this.stopAndPersist({symbol: logSymbols.info, text}); - } - stopAndPersist(options) { - if (!this.enabled) { - return this; - } +"use strict"; - // Legacy argument - // TODO: Deprecate sometime in the future - if (typeof options === 'string') { - options = { - symbol: options - }; - } +const {promisify} = __webpack_require__(111); +const fs = __webpack_require__(133); +const path = __webpack_require__(4); +const fastGlob = __webpack_require__(300); +const gitIgnore = __webpack_require__(372); +const slash = __webpack_require__(373); - options = options || {}; +const DEFAULT_IGNORE = [ + '**/node_modules/**', + '**/flow-typed/**', + '**/coverage/**', + '**/.git' +]; - this.stop(); - this.stream.write(`${options.symbol || ' '} ${options.text || this.text}\n`); +const readFileP = promisify(fs.readFile); - return this; +const mapGitIgnorePatternTo = base => ignore => { + if (ignore.startsWith('!')) { + return '!' + path.posix.join(base, ignore.slice(1)); } -} -module.exports = function (opts) { - return new Ora(opts); + return path.posix.join(base, ignore); }; -module.exports.promise = (action, options) => { - if (typeof action.then !== 'function') { - throw new TypeError('Parameter `action` must be a Promise'); - } +const parseGitIgnore = (content, options) => { + const base = slash(path.relative(options.cwd, path.dirname(options.fileName))); - const spinner = new Ora(options); - spinner.start(); + return content + .split(/\r?\n/) + .filter(Boolean) + .filter(line => !line.startsWith('#')) + .map(mapGitIgnorePatternTo(base)); +}; - action.then( - () => { - spinner.succeed(); - }, - () => { - spinner.fail(); +const reduceIgnore = files => { + return files.reduce((ignores, file) => { + ignores.add(parseGitIgnore(file.content, { + cwd: file.cwd, + fileName: file.filePath + })); + return ignores; + }, gitIgnore()); +}; + +const ensureAbsolutePathForCwd = (cwd, p) => { + if (path.isAbsolute(p)) { + if (p.startsWith(cwd)) { + return p; } - ); - return spinner; -}; + throw new Error(`Path ${p} is not in cwd ${cwd}`); + } + return path.join(cwd, p); +}; -/***/ }), -/* 389 */ -/***/ (function(module, exports, __webpack_require__) { +const getIsIgnoredPredecate = (ignores, cwd) => { + return p => ignores.ignores(slash(path.relative(cwd, ensureAbsolutePathForCwd(cwd, p)))); +}; -"use strict"; +const getFile = async (file, cwd) => { + const filePath = path.join(cwd, file); + const content = await readFileP(filePath, 'utf8'); -const escapeStringRegexp = __webpack_require__(178); -const ansiStyles = __webpack_require__(390); -const stdoutColor = __webpack_require__(184).stdout; + return { + cwd, + filePath, + content + }; +}; -const template = __webpack_require__(391); +const getFileSync = (file, cwd) => { + const filePath = path.join(cwd, file); + const content = fs.readFileSync(filePath, 'utf8'); -const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); + return { + cwd, + filePath, + content + }; +}; -// `supportsColor.level` → `ansiStyles.color[name]` mapping -const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m']; +const normalizeOptions = ({ + ignore = [], + cwd = slash(process.cwd()) +} = {}) => { + return {ignore, cwd}; +}; -// `color-convert` models to exclude from the Chalk API due to conflicts and such -const skipModels = new Set(['gray']); +module.exports = async options => { + options = normalizeOptions(options); -const styles = Object.create(null); + const paths = await fastGlob('**/.gitignore', { + ignore: DEFAULT_IGNORE.concat(options.ignore), + cwd: options.cwd + }); -function applyOptions(obj, options) { - options = options || {}; + const files = await Promise.all(paths.map(file => getFile(file, options.cwd))); + const ignores = reduceIgnore(files); - // Detect level if not set manually - const scLevel = stdoutColor ? stdoutColor.level : 0; - obj.level = options.level === undefined ? scLevel : options.level; - obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0; -} + return getIsIgnoredPredecate(ignores, options.cwd); +}; -function Chalk(options) { - // We check for this.template here since calling `chalk.constructor()` - // by itself will have a `this` of a previously constructed chalk object - if (!this || !(this instanceof Chalk) || this.template) { - const chalk = {}; - applyOptions(chalk, options); +module.exports.sync = options => { + options = normalizeOptions(options); - chalk.template = function () { - const args = [].slice.call(arguments); - return chalkTag.apply(null, [chalk.template].concat(args)); - }; + const paths = fastGlob.sync('**/.gitignore', { + ignore: DEFAULT_IGNORE.concat(options.ignore), + cwd: options.cwd + }); - Object.setPrototypeOf(chalk, Chalk.prototype); - Object.setPrototypeOf(chalk.template, chalk); + const files = paths.map(file => getFileSync(file, options.cwd)); + const ignores = reduceIgnore(files); - chalk.template.constructor = Chalk; + return getIsIgnoredPredecate(ignores, options.cwd); +}; - return chalk.template; - } - applyOptions(this, options); -} +/***/ }), +/* 372 */ +/***/ (function(module, exports) { -// Use bright blue on Windows as the normal blue color is illegible -if (isSimpleWindowsTerm) { - ansiStyles.blue.open = '\u001B[94m'; +// A simple implementation of make-array +function makeArray (subject) { + return Array.isArray(subject) + ? subject + : [subject] } -for (const key of Object.keys(ansiStyles)) { - ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); +const EMPTY = '' +const SPACE = ' ' +const ESCAPE = '\\' +const REGEX_TEST_BLANK_LINE = /^\s+$/ +const REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/ +const REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/ +const REGEX_SPLITALL_CRLF = /\r?\n/g +// /foo, +// ./foo, +// ../foo, +// . +// .. +const REGEX_TEST_INVALID_PATH = /^\.*\/|^\.+$/ - styles[key] = { - get() { - const codes = ansiStyles[key]; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key); - } - }; -} +const SLASH = '/' +const KEY_IGNORE = typeof Symbol !== 'undefined' + ? Symbol.for('node-ignore') + /* istanbul ignore next */ + : 'node-ignore' -styles.visible = { - get() { - return build.call(this, this._styles || [], true, 'visible'); - } -}; +const define = (object, key, value) => + Object.defineProperty(object, key, {value}) -ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g'); -for (const model of Object.keys(ansiStyles.color.ansi)) { - if (skipModels.has(model)) { - continue; - } +const REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g - styles[model] = { - get() { - const level = this.level; - return function () { - const open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments); - const codes = { - open, - close: ansiStyles.color.close, - closeRe: ansiStyles.color.closeRe - }; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); - }; - } - }; +// Sanitize the range of a regular expression +// The cases are complicated, see test cases for details +const sanitizeRange = range => range.replace( + REGEX_REGEXP_RANGE, + (match, from, to) => from.charCodeAt(0) <= to.charCodeAt(0) + ? match + // Invalid range (out of order) which is ok for gitignore rules but + // fatal for JavaScript regular expression, so eliminate it. + : EMPTY +) + +// See fixtures #59 +const cleanRangeBackSlash = slashes => { + const {length} = slashes + return slashes.slice(0, length - length % 2) } -ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g'); -for (const model of Object.keys(ansiStyles.bgColor.ansi)) { - if (skipModels.has(model)) { - continue; - } +// > If the pattern ends with a slash, +// > it is removed for the purpose of the following description, +// > but it would only find a match with a directory. +// > In other words, foo/ will match a directory foo and paths underneath it, +// > but will not match a regular file or a symbolic link foo +// > (this is consistent with the way how pathspec works in general in Git). +// '`foo/`' will not match regular file '`foo`' or symbolic link '`foo`' +// -> ignore-rules will not deal with it, because it costs extra `fs.stat` call +// you could use option `mark: true` with `glob` - const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1); - styles[bgModel] = { - get() { - const level = this.level; - return function () { - const open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments); - const codes = { - open, - close: ansiStyles.bgColor.close, - closeRe: ansiStyles.bgColor.closeRe - }; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); - }; - } - }; -} +// '`foo/`' should not continue with the '`..`' +const REPLACERS = [ -const proto = Object.defineProperties(() => {}, styles); + // > Trailing spaces are ignored unless they are quoted with backslash ("\") + [ + // (a\ ) -> (a ) + // (a ) -> (a) + // (a \ ) -> (a ) + /\\?\s+$/, + match => match.indexOf('\\') === 0 + ? SPACE + : EMPTY + ], -function build(_styles, _empty, key) { - const builder = function () { - return applyStyle.apply(builder, arguments); - }; + // replace (\ ) with ' ' + [ + /\\\s/g, + () => SPACE + ], - builder._styles = _styles; - builder._empty = _empty; + // Escape metacharacters + // which is written down by users but means special for regular expressions. - const self = this; + // > There are 12 characters with special meanings: + // > - the backslash \, + // > - the caret ^, + // > - the dollar sign $, + // > - the period or dot ., + // > - the vertical bar or pipe symbol |, + // > - the question mark ?, + // > - the asterisk or star *, + // > - the plus sign +, + // > - the opening parenthesis (, + // > - the closing parenthesis ), + // > - and the opening square bracket [, + // > - the opening curly brace {, + // > These special characters are often called "metacharacters". + [ + /[\\$.|*+(){^]/g, + match => `\\${match}` + ], - Object.defineProperty(builder, 'level', { - enumerable: true, - get() { - return self.level; - }, - set(level) { - self.level = level; - } - }); + [ + // > a question mark (?) matches a single character + /(?!\\)\?/g, + () => '[^/]' + ], - Object.defineProperty(builder, 'enabled', { - enumerable: true, - get() { - return self.enabled; - }, - set(enabled) { - self.enabled = enabled; - } - }); + // leading slash + [ - // See below for fix regarding invisible grey/dim combination on Windows - builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; + // > A leading slash matches the beginning of the pathname. + // > For example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c". + // A leading slash matches the beginning of the pathname + /^\//, + () => '^' + ], - // `__proto__` is used because we must return a function, but there is - // no way to create a function with a different prototype - builder.__proto__ = proto; // eslint-disable-line no-proto + // replace special metacharacter slash after the leading slash + [ + /\//g, + () => '\\/' + ], - return builder; -} + [ + // > A leading "**" followed by a slash means match in all directories. + // > For example, "**/foo" matches file or directory "foo" anywhere, + // > the same as pattern "foo". + // > "**/foo/bar" matches file or directory "bar" anywhere that is directly + // > under directory "foo". + // Notice that the '*'s have been replaced as '\\*' + /^\^*\\\*\\\*\\\//, -function applyStyle() { - // Support varags, but simply cast to string in case there's only one arg - const args = arguments; - const argsLen = args.length; - let str = String(arguments[0]); + // '**/foo' <-> 'foo' + () => '^(?:.*\\/)?' + ], - if (argsLen === 0) { - return ''; - } + // starting + [ + // there will be no leading '/' + // (which has been replaced by section "leading slash") + // If starts with '**', adding a '^' to the regular expression also works + /^(?=[^^])/, + function startingReplacer () { + // If has a slash `/` at the beginning or middle + return !/\/(?!$)/.test(this) + // > Prior to 2.22.1 + // > If the pattern does not contain a slash /, + // > Git treats it as a shell glob pattern + // Actually, if there is only a trailing slash, + // git also treats it as a shell glob pattern - if (argsLen > 1) { - // Don't slice `arguments`, it prevents V8 optimizations - for (let a = 1; a < argsLen; a++) { - str += ' ' + args[a]; - } - } + // After 2.22.1 (compatible but clearer) + // > If there is a separator at the beginning or middle (or both) + // > of the pattern, then the pattern is relative to the directory + // > level of the particular .gitignore file itself. + // > Otherwise the pattern may also match at any level below + // > the .gitignore level. + ? '(?:^|\\/)' - if (!this.enabled || this.level <= 0 || !str) { - return this._empty ? '' : str; - } + // > Otherwise, Git treats the pattern as a shell glob suitable for + // > consumption by fnmatch(3) + : '^' + } + ], - // Turns out that on Windows dimmed gray text becomes invisible in cmd.exe, - // see https://github.com/chalk/chalk/issues/58 - // If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop. - const originalDim = ansiStyles.dim.open; - if (isSimpleWindowsTerm && this.hasGrey) { - ansiStyles.dim.open = ''; - } + // two globstars + [ + // Use lookahead assertions so that we could match more than one `'/**'` + /\\\/\\\*\\\*(?=\\\/|$)/g, - for (const code of this._styles.slice().reverse()) { - // Replace any instances already present with a re-opening code - // otherwise only the part of the string until said closing code - // will be colored, and the rest will simply be 'plain'. - str = code.open + str.replace(code.closeRe, code.open) + code.close; + // Zero, one or several directories + // should not use '*', or it will be replaced by the next replacer - // Close the styling before a linebreak and reopen - // after next line to fix a bleed issue on macOS - // https://github.com/chalk/chalk/pull/92 - str = str.replace(/\r?\n/g, `${code.close}$&${code.open}`); - } + // Check if it is not the last `'/**'` + (_, index, str) => index + 6 < str.length - // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue - ansiStyles.dim.open = originalDim; + // case: /**/ + // > A slash followed by two consecutive asterisks then a slash matches + // > zero or more directories. + // > For example, "a/**/b" matches "a/b", "a/x/b", "a/x/y/b" and so on. + // '/**/' + ? '(?:\\/[^\\/]+)*' - return str; -} + // case: /** + // > A trailing `"/**"` matches everything inside. -function chalkTag(chalk, strings) { - if (!Array.isArray(strings)) { - // If chalk() was called by itself or with a string, - // return the string itself as a string. - return [].slice.call(arguments, 1).join(' '); - } + // #21: everything inside but it should not include the current folder + : '\\/.+' + ], - const args = [].slice.call(arguments, 2); - const parts = [strings.raw[0]]; + // intermediate wildcards + [ + // Never replace escaped '*' + // ignore rule '\*' will match the path '*' - for (let i = 1; i < strings.length; i++) { - parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&')); - parts.push(String(strings.raw[i])); - } + // 'abc.*/' -> go + // 'abc.*' -> skip this rule + /(^|[^\\]+)\\\*(?=.+)/g, - return template(chalk, parts.join('')); -} + // '*.js' matches '.js' + // '*.js' doesn't match 'abc' + (_, p1) => `${p1}[^\\/]*` + ], -Object.defineProperties(Chalk.prototype, styles); + [ + // unescape, revert step 3 except for back slash + // For example, if a user escape a '\\*', + // after step 3, the result will be '\\\\\\*' + /\\\\\\(?=[$.|*+(){^])/g, + () => ESCAPE + ], -module.exports = Chalk(); // eslint-disable-line new-cap -module.exports.supportsColor = stdoutColor; -module.exports.default = module.exports; // For TypeScript + [ + // '\\\\' -> '\\' + /\\\\/g, + () => ESCAPE + ], + [ + // > The range notation, e.g. [a-zA-Z], + // > can be used to match one of the characters in a range. -/***/ }), -/* 390 */ -/***/ (function(module, exports, __webpack_require__) { + // `\` is escaped by step 3 + /(\\)?\[([^\]/]*?)(\\*)($|\])/g, + (match, leadEscape, range, endEscape, close) => leadEscape === ESCAPE + // '\\[bar]' -> '\\\\[bar\\]' + ? `\\[${range}${cleanRangeBackSlash(endEscape)}${close}` + : close === ']' + ? endEscape.length % 2 === 0 + // A normal case, and it is a range notation + // '[bar]' + // '[bar\\\\]' + ? `[${sanitizeRange(range)}${endEscape}]` + // Invalid range notaton + // '[bar\\]' -> '[bar\\\\]' + : '[]' + : '[]' + ], -"use strict"; -/* WEBPACK VAR INJECTION */(function(module) { -const colorConvert = __webpack_require__(180); + // ending + [ + // 'js' will not match 'js.' + // 'ab' will not match 'abc' + /(?:[^*])$/, -const wrapAnsi16 = (fn, offset) => function () { - const code = fn.apply(colorConvert, arguments); - return `\u001B[${code + offset}m`; -}; + // WTF! + // https://git-scm.com/docs/gitignore + // changes in [2.22.1](https://git-scm.com/docs/gitignore/2.22.1) + // which re-fixes #24, #38 -const wrapAnsi256 = (fn, offset) => function () { - const code = fn.apply(colorConvert, arguments); - return `\u001B[${38 + offset};5;${code}m`; -}; + // > If there is a separator at the end of the pattern then the pattern + // > will only match directories, otherwise the pattern can match both + // > files and directories. -const wrapAnsi16m = (fn, offset) => function () { - const rgb = fn.apply(colorConvert, arguments); - return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}m`; -}; + // 'js*' will not match 'a.js' + // 'js/' will not match 'a.js' + // 'js' will match 'a.js' and 'a.js/' + match => /\/$/.test(match) + // foo/ will not match 'foo' + ? `${match}$` + // foo matches 'foo' and 'foo/' + : `${match}(?=$|\\/$)` + ], -function assembleStyles() { - const codes = new Map(); - const styles = { - modifier: { - reset: [0, 0], - // 21 isn't widely supported and 22 does the same thing - bold: [1, 22], - dim: [2, 22], - italic: [3, 23], - underline: [4, 24], - inverse: [7, 27], - hidden: [8, 28], - strikethrough: [9, 29] - }, - color: { - black: [30, 39], - red: [31, 39], - green: [32, 39], - yellow: [33, 39], - blue: [34, 39], - magenta: [35, 39], - cyan: [36, 39], - white: [37, 39], - gray: [90, 39], + // trailing wildcard + [ + /(\^|\\\/)?\\\*$/, + (_, p1) => { + const prefix = p1 + // '\^': + // '/*' does not match EMPTY + // '/*' does not match everything - // Bright color - redBright: [91, 39], - greenBright: [92, 39], - yellowBright: [93, 39], - blueBright: [94, 39], - magentaBright: [95, 39], - cyanBright: [96, 39], - whiteBright: [97, 39] - }, - bgColor: { - bgBlack: [40, 49], - bgRed: [41, 49], - bgGreen: [42, 49], - bgYellow: [43, 49], - bgBlue: [44, 49], - bgMagenta: [45, 49], - bgCyan: [46, 49], - bgWhite: [47, 49], + // '\\\/': + // 'abc/*' does not match 'abc/' + ? `${p1}[^/]+` - // Bright color - bgBlackBright: [100, 49], - bgRedBright: [101, 49], - bgGreenBright: [102, 49], - bgYellowBright: [103, 49], - bgBlueBright: [104, 49], - bgMagentaBright: [105, 49], - bgCyanBright: [106, 49], - bgWhiteBright: [107, 49] - } - }; + // 'a*' matches 'a' + // 'a*' matches 'aa' + : '[^/]*' - // Fix humans - styles.color.grey = styles.color.gray; + return `${prefix}(?=$|\\/$)` + } + ], +] - for (const groupName of Object.keys(styles)) { - const group = styles[groupName]; +// A simple cache, because an ignore rule only has only one certain meaning +const regexCache = Object.create(null) - for (const styleName of Object.keys(group)) { - const style = group[styleName]; +// @param {pattern} +const makeRegex = (pattern, negative, ignorecase) => { + const r = regexCache[pattern] + if (r) { + return r + } - styles[styleName] = { - open: `\u001B[${style[0]}m`, - close: `\u001B[${style[1]}m` - }; + // const replacers = negative + // ? NEGATIVE_REPLACERS + // : POSITIVE_REPLACERS - group[styleName] = styles[styleName]; + const source = REPLACERS.reduce( + (prev, current) => prev.replace(current[0], current[1].bind(pattern)), + pattern + ) - codes.set(style[0], style[1]); - } + return regexCache[pattern] = ignorecase + ? new RegExp(source, 'i') + : new RegExp(source) +} - Object.defineProperty(styles, groupName, { - value: group, - enumerable: false - }); +const isString = subject => typeof subject === 'string' - Object.defineProperty(styles, 'codes', { - value: codes, - enumerable: false - }); - } +// > A blank line matches no files, so it can serve as a separator for readability. +const checkPattern = pattern => pattern + && isString(pattern) + && !REGEX_TEST_BLANK_LINE.test(pattern) - const ansi2ansi = n => n; - const rgb2rgb = (r, g, b) => [r, g, b]; + // > A line starting with # serves as a comment. + && pattern.indexOf('#') !== 0 - styles.color.close = '\u001B[39m'; - styles.bgColor.close = '\u001B[49m'; +const splitPattern = pattern => pattern.split(REGEX_SPLITALL_CRLF) - styles.color.ansi = { - ansi: wrapAnsi16(ansi2ansi, 0) - }; - styles.color.ansi256 = { - ansi256: wrapAnsi256(ansi2ansi, 0) - }; - styles.color.ansi16m = { - rgb: wrapAnsi16m(rgb2rgb, 0) - }; +class IgnoreRule { + constructor ( + origin, + pattern, + negative, + regex + ) { + this.origin = origin + this.pattern = pattern + this.negative = negative + this.regex = regex + } +} - styles.bgColor.ansi = { - ansi: wrapAnsi16(ansi2ansi, 10) - }; - styles.bgColor.ansi256 = { - ansi256: wrapAnsi256(ansi2ansi, 10) - }; - styles.bgColor.ansi16m = { - rgb: wrapAnsi16m(rgb2rgb, 10) - }; +const createRule = (pattern, ignorecase) => { + const origin = pattern + let negative = false + + // > An optional prefix "!" which negates the pattern; + if (pattern.indexOf('!') === 0) { + negative = true + pattern = pattern.substr(1) + } - for (let key of Object.keys(colorConvert)) { - if (typeof colorConvert[key] !== 'object') { - continue; - } + pattern = pattern + // > Put a backslash ("\") in front of the first "!" for patterns that + // > begin with a literal "!", for example, `"\!important!.txt"`. + .replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, '!') + // > Put a backslash ("\") in front of the first hash for patterns that + // > begin with a hash. + .replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, '#') - const suite = colorConvert[key]; + const regex = makeRegex(pattern, negative, ignorecase) - if (key === 'ansi16') { - key = 'ansi'; - } + return new IgnoreRule( + origin, + pattern, + negative, + regex + ) +} - if ('ansi16' in suite) { - styles.color.ansi[key] = wrapAnsi16(suite.ansi16, 0); - styles.bgColor.ansi[key] = wrapAnsi16(suite.ansi16, 10); - } +const throwError = (message, Ctor) => { + throw new Ctor(message) +} - if ('ansi256' in suite) { - styles.color.ansi256[key] = wrapAnsi256(suite.ansi256, 0); - styles.bgColor.ansi256[key] = wrapAnsi256(suite.ansi256, 10); - } +const checkPath = (path, originalPath, doThrow) => { + if (!isString(path)) { + return doThrow( + `path must be a string, but got \`${originalPath}\``, + TypeError + ) + } - if ('rgb' in suite) { - styles.color.ansi16m[key] = wrapAnsi16m(suite.rgb, 0); - styles.bgColor.ansi16m[key] = wrapAnsi16m(suite.rgb, 10); - } - } + // We don't know if we should ignore EMPTY, so throw + if (!path) { + return doThrow(`path must not be empty`, TypeError) + } - return styles; + // Check if it is a relative path + if (checkPath.isNotRelative(path)) { + const r = '`path.relative()`d' + return doThrow( + `path should be a ${r} string, but got "${originalPath}"`, + RangeError + ) + } + + return true } -// Make the export immutable -Object.defineProperty(module, 'exports', { - enumerable: true, - get: assembleStyles -}); +const isNotRelative = path => REGEX_TEST_INVALID_PATH.test(path) -/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(114)(module))) +checkPath.isNotRelative = isNotRelative +checkPath.convert = p => p -/***/ }), -/* 391 */ -/***/ (function(module, exports, __webpack_require__) { +class Ignore { + constructor ({ + ignorecase = true + } = {}) { + this._rules = [] + this._ignorecase = ignorecase + define(this, KEY_IGNORE, true) + this._initCache() + } -"use strict"; + _initCache () { + this._ignoreCache = Object.create(null) + this._testCache = Object.create(null) + } -const TEMPLATE_REGEX = /(?:\\(u[a-f\d]{4}|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; -const STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; -const STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/; -const ESCAPE_REGEX = /\\(u[a-f\d]{4}|x[a-f\d]{2}|.)|([^\\])/gi; + _addPattern (pattern) { + // #32 + if (pattern && pattern[KEY_IGNORE]) { + this._rules = this._rules.concat(pattern._rules) + this._added = true + return + } -const ESCAPES = new Map([ - ['n', '\n'], - ['r', '\r'], - ['t', '\t'], - ['b', '\b'], - ['f', '\f'], - ['v', '\v'], - ['0', '\0'], - ['\\', '\\'], - ['e', '\u001B'], - ['a', '\u0007'] -]); + if (checkPattern(pattern)) { + const rule = createRule(pattern, this._ignorecase) + this._added = true + this._rules.push(rule) + } + } -function unescape(c) { - if ((c[0] === 'u' && c.length === 5) || (c[0] === 'x' && c.length === 3)) { - return String.fromCharCode(parseInt(c.slice(1), 16)); - } + // @param {Array | string | Ignore} pattern + add (pattern) { + this._added = false - return ESCAPES.get(c) || c; -} + makeArray( + isString(pattern) + ? splitPattern(pattern) + : pattern + ).forEach(this._addPattern, this) -function parseArguments(name, args) { - const results = []; - const chunks = args.trim().split(/\s*,\s*/g); - let matches; + // Some rules have just added to the ignore, + // making the behavior changed. + if (this._added) { + this._initCache() + } - for (const chunk of chunks) { - if (!isNaN(chunk)) { - results.push(Number(chunk)); - } else if ((matches = chunk.match(STRING_REGEX))) { - results.push(matches[2].replace(ESCAPE_REGEX, (m, escape, chr) => escape ? unescape(escape) : chr)); - } else { - throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`); - } - } + return this + } - return results; -} + // legacy + addPattern (pattern) { + return this.add(pattern) + } -function parseStyle(style) { - STYLE_REGEX.lastIndex = 0; + // | ignored : unignored + // negative | 0:0 | 0:1 | 1:0 | 1:1 + // -------- | ------- | ------- | ------- | -------- + // 0 | TEST | TEST | SKIP | X + // 1 | TESTIF | SKIP | TEST | X - const results = []; - let matches; + // - SKIP: always skip + // - TEST: always test + // - TESTIF: only test if checkUnignored + // - X: that never happen - while ((matches = STYLE_REGEX.exec(style)) !== null) { - const name = matches[1]; + // @param {boolean} whether should check if the path is unignored, + // setting `checkUnignored` to `false` could reduce additional + // path matching. - if (matches[2]) { - const args = parseArguments(name, matches[2]); - results.push([name].concat(args)); - } else { - results.push([name]); - } - } + // @returns {TestResult} true if a file is ignored + _testOne (path, checkUnignored) { + let ignored = false + let unignored = false - return results; -} + this._rules.forEach(rule => { + const {negative} = rule + if ( + unignored === negative && ignored !== unignored + || negative && !ignored && !unignored && !checkUnignored + ) { + return + } -function buildStyle(chalk, styles) { - const enabled = {}; + const matched = rule.regex.test(path) - for (const layer of styles) { - for (const style of layer.styles) { - enabled[style[0]] = layer.inverse ? null : style.slice(1); - } - } + if (matched) { + ignored = !negative + unignored = negative + } + }) - let current = chalk; - for (const styleName of Object.keys(enabled)) { - if (Array.isArray(enabled[styleName])) { - if (!(styleName in current)) { - throw new Error(`Unknown Chalk style: ${styleName}`); - } + return { + ignored, + unignored + } + } - if (enabled[styleName].length > 0) { - current = current[styleName].apply(current, enabled[styleName]); - } else { - current = current[styleName]; - } - } - } + // @returns {TestResult} + _test (originalPath, cache, checkUnignored, slices) { + const path = originalPath + // Supports nullable path + && checkPath.convert(originalPath) - return current; -} + checkPath(path, originalPath, throwError) -module.exports = (chalk, tmp) => { - const styles = []; - const chunks = []; - let chunk = []; + return this._t(path, cache, checkUnignored, slices) + } - // eslint-disable-next-line max-params - tmp.replace(TEMPLATE_REGEX, (m, escapeChar, inverse, style, close, chr) => { - if (escapeChar) { - chunk.push(unescape(escapeChar)); - } else if (style) { - const str = chunk.join(''); - chunk = []; - chunks.push(styles.length === 0 ? str : buildStyle(chalk, styles)(str)); - styles.push({inverse, styles: parseStyle(style)}); - } else if (close) { - if (styles.length === 0) { - throw new Error('Found extraneous } in Chalk template literal'); - } + _t (path, cache, checkUnignored, slices) { + if (path in cache) { + return cache[path] + } - chunks.push(buildStyle(chalk, styles)(chunk.join(''))); - chunk = []; - styles.pop(); - } else { - chunk.push(chr); - } - }); + if (!slices) { + // path/to/a.js + // ['path', 'to', 'a.js'] + slices = path.split(SLASH) + } - chunks.push(chunk.join('')); + slices.pop() - if (styles.length > 0) { - const errMsg = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? '' : 's'} (\`}\`)`; - throw new Error(errMsg); - } + // If the path has no parent directory, just test it + if (!slices.length) { + return cache[path] = this._testOne(path, checkUnignored) + } - return chunks.join(''); -}; + const parent = this._t( + slices.join(SLASH) + SLASH, + cache, + checkUnignored, + slices + ) + // If the path contains a parent directory, check the parent first + return cache[path] = parent.ignored + // > It is not possible to re-include a file if a parent directory of + // > that file is excluded. + ? parent + : this._testOne(path, checkUnignored) + } -/***/ }), -/* 392 */ -/***/ (function(module, exports, __webpack_require__) { + ignores (path) { + return this._test(path, this._ignoreCache, false).ignored + } -"use strict"; + createFilter () { + return path => !this.ignores(path) + } -const restoreCursor = __webpack_require__(393); + filter (paths) { + return makeArray(paths).filter(this.createFilter()) + } -let hidden = false; + // @returns {TestResult} + test (path) { + return this._test(path, this._testCache, true) + } +} -exports.show = stream => { - const s = stream || process.stderr; +const factory = options => new Ignore(options) - if (!s.isTTY) { - return; - } +const returnFalse = () => false - hidden = false; - s.write('\u001b[?25h'); -}; +const isPathValid = path => + checkPath(path && checkPath.convert(path), path, returnFalse) -exports.hide = stream => { - const s = stream || process.stderr; +factory.isPathValid = isPathValid - if (!s.isTTY) { - return; - } +// Fixes typescript +factory.default = factory - restoreCursor(); - hidden = true; - s.write('\u001b[?25l'); -}; +module.exports = factory -exports.toggle = (force, stream) => { - if (force !== undefined) { - hidden = force; - } +// Windows +// -------------------------------------------------------------- +/* istanbul ignore if */ +if ( + // Detect `process` so that it can run in browsers. + typeof process !== 'undefined' + && ( + process.env && process.env.IGNORE_TEST_WIN32 + || process.platform === 'win32' + ) +) { + /* eslint no-control-regex: "off" */ + const makePosix = str => /^\\\\\?\\/.test(str) + || /["<>|\u0000-\u001F]+/u.test(str) + ? str + : str.replace(/\\/g, '/') - if (hidden) { - exports.show(stream); - } else { - exports.hide(stream); - } -}; + checkPath.convert = makePosix + + // 'C:\\foo' <- 'C:\\foo' has been converted to 'C:/' + // 'd:\\foo' + const REGIX_IS_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i + checkPath.isNotRelative = path => + REGIX_IS_WINDOWS_PATH_ABSOLUTE.test(path) + || isNotRelative(path) +} /***/ }), -/* 393 */ +/* 373 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const onetime = __webpack_require__(394); -const signalExit = __webpack_require__(225); +module.exports = path => { + const isExtendedLengthPath = /^\\\\\?\\/.test(path); + const hasNonAscii = /[^\u0000-\u0080]+/.test(path); // eslint-disable-line no-control-regex -module.exports = onetime(() => { - signalExit(() => { - process.stderr.write('\u001b[?25h'); - }, {alwaysLast: true}); -}); + if (isExtendedLengthPath || hasNonAscii) { + return path; + } + + return path.replace(/\\/g, '/'); +}; /***/ }), -/* 394 */ +/* 374 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const mimicFn = __webpack_require__(395); +const {Transform} = __webpack_require__(137); -module.exports = (fn, opts) => { - // TODO: Remove this in v3 - if (opts === true) { - throw new TypeError('The second argument is now an options object'); +class ObjectTransform extends Transform { + constructor() { + super({ + objectMode: true + }); } +} - if (typeof fn !== 'function') { - throw new TypeError('Expected a function'); +class FilterStream extends ObjectTransform { + constructor(filter) { + super(); + this._filter = filter; } - opts = opts || {}; - - let ret; - let called = false; - const fnName = fn.displayName || fn.name || ''; - - const onetime = function () { - if (called) { - if (opts.throw === true) { - throw new Error(`Function \`${fnName}\` can only be called once`); - } - - return ret; + _transform(data, encoding, callback) { + if (this._filter(data)) { + this.push(data); } - called = true; - ret = fn.apply(this, arguments); - fn = null; - - return ret; - }; - - mimicFn(onetime, fn); - - return onetime; -}; - + callback(); + } +} -/***/ }), -/* 395 */ -/***/ (function(module, exports, __webpack_require__) { +class UniqueStream extends ObjectTransform { + constructor() { + super(); + this._pushed = new Set(); + } -"use strict"; + _transform(data, encoding, callback) { + if (!this._pushed.has(data)) { + this.push(data); + this._pushed.add(data); + } -module.exports = (to, from) => { - // TODO: use `Reflect.ownKeys()` when targeting Node.js 6 - for (const prop of Object.getOwnPropertyNames(from).concat(Object.getOwnPropertySymbols(from))) { - Object.defineProperty(to, prop, Object.getOwnPropertyDescriptor(from, prop)); + callback(); } +} - return to; +module.exports = { + FilterStream, + UniqueStream }; /***/ }), -/* 396 */ +/* 375 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; - -module.exports = __webpack_require__(397); - +/*! + * is-glob + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. + */ -/***/ }), -/* 397 */ -/***/ (function(module) { +var isExtglob = __webpack_require__(310); +var chars = { '{': '}', '(': ')', '[': ']'}; +var strictRegex = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/; +var relaxedRegex = /\\(.)|(^!|[*?{}()[\]]|\(\?)/; -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\":[\"🌲\",\"🎄\"]}}"); +module.exports = function isGlob(str, options) { + if (typeof str !== 'string' || str === '') { + return false; + } -/***/ }), -/* 398 */ -/***/ (function(module, exports, __webpack_require__) { + if (isExtglob(str)) { + return true; + } -"use strict"; + var regex = strictRegex; + var match; -const chalk = __webpack_require__(399); + // optionally relax regex + if (options && options.strict === false) { + regex = relaxedRegex; + } -const isSupported = process.platform !== 'win32' || process.env.CI || process.env.TERM === 'xterm-256color'; + while ((match = regex.exec(str))) { + if (match[2]) return true; + var idx = match.index + match[0].length; -const main = { - info: chalk.blue('ℹ'), - success: chalk.green('✔'), - warning: chalk.yellow('⚠'), - error: chalk.red('✖') -}; + // 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; + } + } -const fallbacks = { - info: chalk.blue('i'), - success: chalk.green('√'), - warning: chalk.yellow('‼'), - error: chalk.red('×') + str = str.slice(idx); + } + return false; }; -module.exports = isSupported ? main : fallbacks; - /***/ }), -/* 399 */ +/* 376 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const escapeStringRegexp = __webpack_require__(178); -const ansiStyles = __webpack_require__(400); -const stdoutColor = __webpack_require__(184).stdout; - -const template = __webpack_require__(401); - -const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); +const path = __webpack_require__(4); -// `supportsColor.level` → `ansiStyles.color[name]` mapping -const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m']; +module.exports = path_ => { + let cwd = process.cwd(); -// `color-convert` models to exclude from the Chalk API due to conflicts and such -const skipModels = new Set(['gray']); + path_ = path.resolve(path_); -const styles = Object.create(null); + if (process.platform === 'win32') { + cwd = cwd.toLowerCase(); + path_ = path_.toLowerCase(); + } -function applyOptions(obj, options) { - options = options || {}; + return path_ === cwd; +}; - // Detect level if not set manually - const scLevel = stdoutColor ? stdoutColor.level : 0; - obj.level = options.level === undefined ? scLevel : options.level; - obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0; -} -function Chalk(options) { - // We check for this.template here since calling `chalk.constructor()` - // by itself will have a `this` of a previously constructed chalk object - if (!this || !(this instanceof Chalk) || this.template) { - const chalk = {}; - applyOptions(chalk, options); +/***/ }), +/* 377 */ +/***/ (function(module, exports, __webpack_require__) { - chalk.template = function () { - const args = [].slice.call(arguments); - return chalkTag.apply(null, [chalk.template].concat(args)); - }; +"use strict"; - Object.setPrototypeOf(chalk, Chalk.prototype); - Object.setPrototypeOf(chalk.template, chalk); +const path = __webpack_require__(4); - chalk.template.constructor = Chalk; +module.exports = (childPath, parentPath) => { + childPath = path.resolve(childPath); + parentPath = path.resolve(parentPath); - return chalk.template; + if (process.platform === 'win32') { + childPath = childPath.toLowerCase(); + parentPath = parentPath.toLowerCase(); } - applyOptions(this, options); -} - -// Use bright blue on Windows as the normal blue color is illegible -if (isSimpleWindowsTerm) { - ansiStyles.blue.open = '\u001B[94m'; -} - -for (const key of Object.keys(ansiStyles)) { - ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); + if (childPath === parentPath) { + return false; + } - styles[key] = { - get() { - const codes = ansiStyles[key]; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key); - } - }; -} + childPath += path.sep; + parentPath += path.sep; -styles.visible = { - get() { - return build.call(this, this._styles || [], true, 'visible'); - } + return childPath.startsWith(parentPath); }; -ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g'); -for (const model of Object.keys(ansiStyles.color.ansi)) { - if (skipModels.has(model)) { - continue; - } - - styles[model] = { - get() { - const level = this.level; - return function () { - const open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments); - const codes = { - open, - close: ansiStyles.color.close, - closeRe: ansiStyles.color.closeRe - }; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); - }; - } - }; -} -ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g'); -for (const model of Object.keys(ansiStyles.bgColor.ansi)) { - if (skipModels.has(model)) { - continue; - } +/***/ }), +/* 378 */ +/***/ (function(module, exports, __webpack_require__) { - const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1); - styles[bgModel] = { - get() { - const level = this.level; - return function () { - const open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments); - const codes = { - open, - close: ansiStyles.bgColor.close, - closeRe: ansiStyles.bgColor.closeRe - }; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); - }; - } - }; +const assert = __webpack_require__(139) +const path = __webpack_require__(4) +const fs = __webpack_require__(133) +let glob = undefined +try { + glob = __webpack_require__(146) +} catch (_err) { + // treat glob as optional. } -const proto = Object.defineProperties(() => {}, styles); - -function build(_styles, _empty, key) { - const builder = function () { - return applyStyle.apply(builder, arguments); - }; - - builder._styles = _styles; - builder._empty = _empty; +const defaultGlobOpts = { + nosort: true, + silent: true +} - const self = this; +// for EMFILE handling +let timeout = 0 - Object.defineProperty(builder, 'level', { - enumerable: true, - get() { - return self.level; - }, - set(level) { - self.level = level; - } - }); +const isWindows = (process.platform === "win32") - Object.defineProperty(builder, 'enabled', { - enumerable: true, - get() { - return self.enabled; - }, - set(enabled) { - self.enabled = enabled; - } - }); +const defaults = options => { + const methods = [ + 'unlink', + 'chmod', + 'stat', + 'lstat', + 'rmdir', + 'readdir' + ] + methods.forEach(m => { + options[m] = options[m] || fs[m] + m = m + 'Sync' + options[m] = options[m] || fs[m] + }) - // See below for fix regarding invisible grey/dim combination on Windows - builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; + options.maxBusyTries = options.maxBusyTries || 3 + options.emfileWait = options.emfileWait || 1000 + if (options.glob === false) { + options.disableGlob = true + } + if (options.disableGlob !== true && glob === undefined) { + throw Error('glob dependency not found, set `options.disableGlob = true` if intentional') + } + options.disableGlob = options.disableGlob || false + options.glob = options.glob || defaultGlobOpts +} - // `__proto__` is used because we must return a function, but there is - // no way to create a function with a different prototype - builder.__proto__ = proto; // eslint-disable-line no-proto +const rimraf = (p, options, cb) => { + if (typeof options === 'function') { + cb = options + options = {} + } - return builder; -} + assert(p, 'rimraf: missing path') + assert.equal(typeof p, 'string', 'rimraf: path should be a string') + assert.equal(typeof cb, 'function', 'rimraf: callback function required') + assert(options, 'rimraf: invalid options argument provided') + assert.equal(typeof options, 'object', 'rimraf: options should be object') -function applyStyle() { - // Support varags, but simply cast to string in case there's only one arg - const args = arguments; - const argsLen = args.length; - let str = String(arguments[0]); + defaults(options) - if (argsLen === 0) { - return ''; - } + let busyTries = 0 + let errState = null + let n = 0 - if (argsLen > 1) { - // Don't slice `arguments`, it prevents V8 optimizations - for (let a = 1; a < argsLen; a++) { - str += ' ' + args[a]; - } - } + const next = (er) => { + errState = errState || er + if (--n === 0) + cb(errState) + } - if (!this.enabled || this.level <= 0 || !str) { - return this._empty ? '' : str; - } + const afterGlob = (er, results) => { + if (er) + return cb(er) - // Turns out that on Windows dimmed gray text becomes invisible in cmd.exe, - // see https://github.com/chalk/chalk/issues/58 - // If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop. - const originalDim = ansiStyles.dim.open; - if (isSimpleWindowsTerm && this.hasGrey) { - ansiStyles.dim.open = ''; - } + n = results.length + if (n === 0) + return cb() - for (const code of this._styles.slice().reverse()) { - // Replace any instances already present with a re-opening code - // otherwise only the part of the string until said closing code - // will be colored, and the rest will simply be 'plain'. - str = code.open + str.replace(code.closeRe, code.open) + code.close; + results.forEach(p => { + const CB = (er) => { + if (er) { + if ((er.code === "EBUSY" || er.code === "ENOTEMPTY" || er.code === "EPERM") && + busyTries < options.maxBusyTries) { + busyTries ++ + // try again, with the same exact callback as this one. + return setTimeout(() => rimraf_(p, options, CB), busyTries * 100) + } - // Close the styling before a linebreak and reopen - // after next line to fix a bleed issue on macOS - // https://github.com/chalk/chalk/pull/92 - str = str.replace(/\r?\n/g, `${code.close}$&${code.open}`); - } + // this one won't happen if graceful-fs is used. + if (er.code === "EMFILE" && timeout < options.emfileWait) { + return setTimeout(() => rimraf_(p, options, CB), timeout ++) + } - // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue - ansiStyles.dim.open = originalDim; + // already gone + if (er.code === "ENOENT") er = null + } - return str; -} + timeout = 0 + next(er) + } + rimraf_(p, options, CB) + }) + } -function chalkTag(chalk, strings) { - if (!Array.isArray(strings)) { - // If chalk() was called by itself or with a string, - // return the string itself as a string. - return [].slice.call(arguments, 1).join(' '); - } + if (options.disableGlob || !glob.hasMagic(p)) + return afterGlob(null, [p]) - const args = [].slice.call(arguments, 2); - const parts = [strings.raw[0]]; + options.lstat(p, (er, stat) => { + if (!er) + return afterGlob(null, [p]) - for (let i = 1; i < strings.length; i++) { - parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&')); - parts.push(String(strings.raw[i])); - } + glob(p, options.glob, afterGlob) + }) - return template(chalk, parts.join('')); } -Object.defineProperties(Chalk.prototype, styles); - -module.exports = Chalk(); // eslint-disable-line new-cap -module.exports.supportsColor = stdoutColor; -module.exports.default = module.exports; // For TypeScript +// Two possible strategies. +// 1. Assume it's a file. unlink it, then do the dir stuff on EPERM or EISDIR +// 2. Assume it's a directory. readdir, then do the file stuff on ENOTDIR +// +// Both result in an extra syscall when you guess wrong. However, there +// are likely far more normal files in the world than directories. This +// is based on the assumption that a the average number of files per +// directory is >= 1. +// +// If anyone ever complains about this, then I guess the strategy could +// be made configurable somehow. But until then, YAGNI. +const rimraf_ = (p, options, cb) => { + assert(p) + assert(options) + assert(typeof cb === 'function') + // sunos lets the root user unlink directories, which is... weird. + // so we have to lstat here and make sure it's not a dir. + options.lstat(p, (er, st) => { + if (er && er.code === "ENOENT") + return cb(null) -/***/ }), -/* 400 */ -/***/ (function(module, exports, __webpack_require__) { + // Windows can EPERM on stat. Life is suffering. + if (er && er.code === "EPERM" && isWindows) + fixWinEPERM(p, options, er, cb) -"use strict"; -/* WEBPACK VAR INJECTION */(function(module) { -const colorConvert = __webpack_require__(180); + if (st && st.isDirectory()) + return rmdir(p, options, er, cb) -const wrapAnsi16 = (fn, offset) => function () { - const code = fn.apply(colorConvert, arguments); - return `\u001B[${code + offset}m`; -}; + options.unlink(p, er => { + if (er) { + if (er.code === "ENOENT") + return cb(null) + if (er.code === "EPERM") + return (isWindows) + ? fixWinEPERM(p, options, er, cb) + : rmdir(p, options, er, cb) + if (er.code === "EISDIR") + return rmdir(p, options, er, cb) + } + return cb(er) + }) + }) +} -const wrapAnsi256 = (fn, offset) => function () { - const code = fn.apply(colorConvert, arguments); - return `\u001B[${38 + offset};5;${code}m`; -}; +const fixWinEPERM = (p, options, er, cb) => { + assert(p) + assert(options) + assert(typeof cb === 'function') -const wrapAnsi16m = (fn, offset) => function () { - const rgb = fn.apply(colorConvert, arguments); - return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}m`; -}; + options.chmod(p, 0o666, er2 => { + if (er2) + cb(er2.code === "ENOENT" ? null : er) + else + options.stat(p, (er3, stats) => { + if (er3) + cb(er3.code === "ENOENT" ? null : er) + else if (stats.isDirectory()) + rmdir(p, options, er, cb) + else + options.unlink(p, cb) + }) + }) +} -function assembleStyles() { - const codes = new Map(); - const styles = { - modifier: { - reset: [0, 0], - // 21 isn't widely supported and 22 does the same thing - bold: [1, 22], - dim: [2, 22], - italic: [3, 23], - underline: [4, 24], - inverse: [7, 27], - hidden: [8, 28], - strikethrough: [9, 29] - }, - color: { - black: [30, 39], - red: [31, 39], - green: [32, 39], - yellow: [33, 39], - blue: [34, 39], - magenta: [35, 39], - cyan: [36, 39], - white: [37, 39], - gray: [90, 39], +const fixWinEPERMSync = (p, options, er) => { + assert(p) + assert(options) - // Bright color - redBright: [91, 39], - greenBright: [92, 39], - yellowBright: [93, 39], - blueBright: [94, 39], - magentaBright: [95, 39], - cyanBright: [96, 39], - whiteBright: [97, 39] - }, - bgColor: { - bgBlack: [40, 49], - bgRed: [41, 49], - bgGreen: [42, 49], - bgYellow: [43, 49], - bgBlue: [44, 49], - bgMagenta: [45, 49], - bgCyan: [46, 49], - bgWhite: [47, 49], + try { + options.chmodSync(p, 0o666) + } catch (er2) { + if (er2.code === "ENOENT") + return + else + throw er + } - // Bright color - bgBlackBright: [100, 49], - bgRedBright: [101, 49], - bgGreenBright: [102, 49], - bgYellowBright: [103, 49], - bgBlueBright: [104, 49], - bgMagentaBright: [105, 49], - bgCyanBright: [106, 49], - bgWhiteBright: [107, 49] - } - }; + let stats + try { + stats = options.statSync(p) + } catch (er3) { + if (er3.code === "ENOENT") + return + else + throw er + } - // Fix humans - styles.color.grey = styles.color.gray; + if (stats.isDirectory()) + rmdirSync(p, options, er) + else + options.unlinkSync(p) +} - for (const groupName of Object.keys(styles)) { - const group = styles[groupName]; +const rmdir = (p, options, originalEr, cb) => { + assert(p) + assert(options) + assert(typeof cb === 'function') - for (const styleName of Object.keys(group)) { - const style = group[styleName]; + // try to rmdir first, and only readdir on ENOTEMPTY or EEXIST (SunOS) + // if we guessed wrong, and it's not a directory, then + // raise the original error. + options.rmdir(p, er => { + if (er && (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM")) + rmkids(p, options, cb) + else if (er && er.code === "ENOTDIR") + cb(originalEr) + else + cb(er) + }) +} - styles[styleName] = { - open: `\u001B[${style[0]}m`, - close: `\u001B[${style[1]}m` - }; +const rmkids = (p, options, cb) => { + assert(p) + assert(options) + assert(typeof cb === 'function') - group[styleName] = styles[styleName]; + options.readdir(p, (er, files) => { + if (er) + return cb(er) + let n = files.length + if (n === 0) + return options.rmdir(p, cb) + let errState + files.forEach(f => { + rimraf(path.join(p, f), options, er => { + if (errState) + return + if (er) + return cb(errState = er) + if (--n === 0) + options.rmdir(p, cb) + }) + }) + }) +} - codes.set(style[0], style[1]); - } +// this looks simpler, and is strictly *faster*, but will +// tie up the JavaScript thread and fail on excessively +// deep directory trees. +const rimrafSync = (p, options) => { + options = options || {} + defaults(options) - Object.defineProperty(styles, groupName, { - value: group, - enumerable: false - }); + assert(p, 'rimraf: missing path') + assert.equal(typeof p, 'string', 'rimraf: path should be a string') + assert(options, 'rimraf: missing options') + assert.equal(typeof options, 'object', 'rimraf: options should be object') - Object.defineProperty(styles, 'codes', { - value: codes, - enumerable: false - }); - } + let results - const ansi2ansi = n => n; - const rgb2rgb = (r, g, b) => [r, g, b]; + if (options.disableGlob || !glob.hasMagic(p)) { + results = [p] + } else { + try { + options.lstatSync(p) + results = [p] + } catch (er) { + results = glob.sync(p, options.glob) + } + } - styles.color.close = '\u001B[39m'; - styles.bgColor.close = '\u001B[49m'; + if (!results.length) + return - styles.color.ansi = { - ansi: wrapAnsi16(ansi2ansi, 0) - }; - styles.color.ansi256 = { - ansi256: wrapAnsi256(ansi2ansi, 0) - }; - styles.color.ansi16m = { - rgb: wrapAnsi16m(rgb2rgb, 0) - }; + for (let i = 0; i < results.length; i++) { + const p = results[i] - styles.bgColor.ansi = { - ansi: wrapAnsi16(ansi2ansi, 10) - }; - styles.bgColor.ansi256 = { - ansi256: wrapAnsi256(ansi2ansi, 10) - }; - styles.bgColor.ansi16m = { - rgb: wrapAnsi16m(rgb2rgb, 10) - }; + let st + try { + st = options.lstatSync(p) + } catch (er) { + if (er.code === "ENOENT") + return - for (let key of Object.keys(colorConvert)) { - if (typeof colorConvert[key] !== 'object') { - continue; - } + // Windows can EPERM on stat. Life is suffering. + if (er.code === "EPERM" && isWindows) + fixWinEPERMSync(p, options, er) + } - const suite = colorConvert[key]; + try { + // sunos lets the root user unlink directories, which is... weird. + if (st && st.isDirectory()) + rmdirSync(p, options, null) + else + options.unlinkSync(p) + } catch (er) { + if (er.code === "ENOENT") + return + if (er.code === "EPERM") + return isWindows ? fixWinEPERMSync(p, options, er) : rmdirSync(p, options, er) + if (er.code !== "EISDIR") + throw er - if (key === 'ansi16') { - key = 'ansi'; - } + rmdirSync(p, options, er) + } + } +} - if ('ansi16' in suite) { - styles.color.ansi[key] = wrapAnsi16(suite.ansi16, 0); - styles.bgColor.ansi[key] = wrapAnsi16(suite.ansi16, 10); - } +const rmdirSync = (p, options, originalEr) => { + assert(p) + assert(options) - if ('ansi256' in suite) { - styles.color.ansi256[key] = wrapAnsi256(suite.ansi256, 0); - styles.bgColor.ansi256[key] = wrapAnsi256(suite.ansi256, 10); - } + try { + options.rmdirSync(p) + } catch (er) { + if (er.code === "ENOENT") + return + if (er.code === "ENOTDIR") + throw originalEr + if (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM") + rmkidsSync(p, options) + } +} - if ('rgb' in suite) { - styles.color.ansi16m[key] = wrapAnsi16m(suite.rgb, 0); - styles.bgColor.ansi16m[key] = wrapAnsi16m(suite.rgb, 10); - } - } +const rmkidsSync = (p, options) => { + assert(p) + assert(options) + options.readdirSync(p).forEach(f => rimrafSync(path.join(p, f), options)) - return styles; + // We only end up here once we got ENOTEMPTY at least once, and + // at this point, we are guaranteed to have removed all the kids. + // So, we know that it won't be ENOENT or ENOTDIR or anything else. + // try really hard to delete stuff on windows, because it has a + // PROFOUNDLY annoying habit of not closing handles promptly when + // files are deleted, resulting in spurious ENOTEMPTY errors. + const retries = isWindows ? 100 : 1 + let i = 0 + do { + let threw = true + try { + const ret = options.rmdirSync(p, options) + threw = false + return ret + } finally { + if (++i < retries && threw) + continue + } + } while (true) } -// Make the export immutable -Object.defineProperty(module, 'exports', { - enumerable: true, - get: assembleStyles -}); +module.exports = rimraf +rimraf.sync = rimrafSync -/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(114)(module))) /***/ }), -/* 401 */ +/* 379 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const TEMPLATE_REGEX = /(?:\\(u[a-f\d]{4}|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; -const STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; -const STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/; -const ESCAPE_REGEX = /\\(u[a-f\d]{4}|x[a-f\d]{2}|.)|([^\\])/gi; - -const ESCAPES = new Map([ - ['n', '\n'], - ['r', '\r'], - ['t', '\t'], - ['b', '\b'], - ['f', '\f'], - ['v', '\v'], - ['0', '\0'], - ['\\', '\\'], - ['e', '\u001B'], - ['a', '\u0007'] -]); - -function unescape(c) { - if ((c[0] === 'u' && c.length === 5) || (c[0] === 'x' && c.length === 3)) { - return String.fromCharCode(parseInt(c.slice(1), 16)); - } - - return ESCAPES.get(c) || c; -} - -function parseArguments(name, args) { - const results = []; - const chunks = args.trim().split(/\s*,\s*/g); - let matches; +const AggregateError = __webpack_require__(380); - for (const chunk of chunks) { - if (!isNaN(chunk)) { - results.push(Number(chunk)); - } else if ((matches = chunk.match(STRING_REGEX))) { - results.push(matches[2].replace(ESCAPE_REGEX, (m, escape, chr) => escape ? unescape(escape) : chr)); - } else { - throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`); +module.exports = async ( + iterable, + mapper, + { + concurrency = Infinity, + stopOnError = true + } = {} +) => { + return new Promise((resolve, reject) => { + if (typeof mapper !== 'function') { + throw new TypeError('Mapper function is required'); } - } - - return results; -} -function parseStyle(style) { - STYLE_REGEX.lastIndex = 0; - - const results = []; - let matches; + if (!(typeof concurrency === 'number' && concurrency >= 1)) { + throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${concurrency}\` (${typeof concurrency})`); + } - while ((matches = STYLE_REGEX.exec(style)) !== null) { - const name = matches[1]; + const ret = []; + const errors = []; + const iterator = iterable[Symbol.iterator](); + let isRejected = false; + let isIterableDone = false; + let resolvingCount = 0; + let currentIndex = 0; - if (matches[2]) { - const args = parseArguments(name, matches[2]); - results.push([name].concat(args)); - } else { - results.push([name]); - } - } + const next = () => { + if (isRejected) { + return; + } - return results; -} + const nextItem = iterator.next(); + const i = currentIndex; + currentIndex++; -function buildStyle(chalk, styles) { - const enabled = {}; + if (nextItem.done) { + isIterableDone = true; - for (const layer of styles) { - for (const style of layer.styles) { - enabled[style[0]] = layer.inverse ? null : style.slice(1); - } - } + if (resolvingCount === 0) { + if (!stopOnError && errors.length !== 0) { + reject(new AggregateError(errors)); + } else { + resolve(ret); + } + } - let current = chalk; - for (const styleName of Object.keys(enabled)) { - if (Array.isArray(enabled[styleName])) { - if (!(styleName in current)) { - throw new Error(`Unknown Chalk style: ${styleName}`); + return; } - if (enabled[styleName].length > 0) { - current = current[styleName].apply(current, enabled[styleName]); - } else { - current = current[styleName]; - } - } - } + resolvingCount++; - return current; -} + (async () => { + try { + const element = await nextItem.value; + ret[i] = await mapper(element, i); + resolvingCount--; + next(); + } catch (error) { + if (stopOnError) { + isRejected = true; + reject(error); + } else { + errors.push(error); + resolvingCount--; + next(); + } + } + })(); + }; -module.exports = (chalk, tmp) => { - const styles = []; - const chunks = []; - let chunk = []; + for (let i = 0; i < concurrency; i++) { + next(); - // eslint-disable-next-line max-params - tmp.replace(TEMPLATE_REGEX, (m, escapeChar, inverse, style, close, chr) => { - if (escapeChar) { - chunk.push(unescape(escapeChar)); - } else if (style) { - const str = chunk.join(''); - chunk = []; - chunks.push(styles.length === 0 ? str : buildStyle(chalk, styles)(str)); - styles.push({inverse, styles: parseStyle(style)}); - } else if (close) { - if (styles.length === 0) { - throw new Error('Found extraneous } in Chalk template literal'); + if (isIterableDone) { + break; } - - chunks.push(buildStyle(chalk, styles)(chunk.join(''))); - chunk = []; - styles.pop(); - } else { - chunk.push(chr); } }); - - chunks.push(chunk.join('')); - - if (styles.length > 0) { - const errMsg = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? '' : 's'} (\`}\`)`; - throw new Error(errMsg); - } - - return chunks.join(''); }; /***/ }), -/* 402 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* 380 */ +/***/ (function(module, exports, __webpack_require__) { "use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RunCommand", function() { return RunCommand; }); -/* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); -/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(143); -/* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(144); -/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(145); -/* - * 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. - */ +const indentString = __webpack_require__(381); +const cleanStack = __webpack_require__(382); +const cleanInternalStack = stack => stack.replace(/\s+at .*aggregate-error\/index.js:\d+:\d+\)?/g, ''); +class AggregateError extends Error { + constructor(errors) { + if (!Array.isArray(errors)) { + throw new TypeError(`Expected input to be an Array, got ${typeof errors}`); + } -const RunCommand = { - description: 'Run script defined in package.json in each package that contains that script.', - name: 'run', + errors = [...errors].map(error => { + if (error instanceof Error) { + return error; + } - async run(projects, projectGraph, { - extraArgs - }) { - const batchedProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_3__["topologicallyBatchProjects"])(projects, projectGraph); + if (error !== null && typeof error === 'object') { + // Handle plain error objects with message property and/or possibly other metadata + return Object.assign(new Error(error.message), error); + } - if (extraArgs.length === 0) { - throw new _utils_errors__WEBPACK_IMPORTED_MODULE_0__["CliError"]('No script specified'); - } + return new Error(error); + }); - const scriptName = extraArgs[0]; - const scriptArgs = extraArgs.slice(1); - await Object(_utils_parallelize__WEBPACK_IMPORTED_MODULE_2__["parallelizeBatches"])(batchedProjects, async project => { - if (project.hasScript(scriptName)) { - _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].info(`[${project.name}] running "${scriptName}" script`); - await project.runScriptStreaming(scriptName, { - args: scriptArgs - }); - _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].success(`[${project.name}] complete`); - } - }); - } + let message = errors + .map(error => { + // The `stack` property is not standardized, so we can't assume it exists + return typeof error.stack === 'string' ? cleanInternalStack(cleanStack(error.stack)) : String(error); + }) + .join('\n'); + message = '\n' + indentString(message, 4); + super(message); + + this.name = 'AggregateError'; + + Object.defineProperty(this, '_errors', {value: errors}); + } + + * [Symbol.iterator]() { + for (const error of this._errors) { + yield error; + } + } +} + +module.exports = AggregateError; -}; /***/ }), -/* 403 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* 381 */ +/***/ (function(module, exports, __webpack_require__) { "use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WatchCommand", function() { return WatchCommand; }); -/* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); -/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(143); -/* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(144); -/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(145); -/* harmony import */ var _utils_watch__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(404); -/* - * 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. - */ +module.exports = (string, count = 1, options) => { + options = { + indent: ' ', + includeEmptyLines: false, + ...options + }; + + if (typeof string !== 'string') { + throw new TypeError( + `Expected \`input\` to be a \`string\`, got \`${typeof string}\`` + ); + } + + if (typeof count !== 'number') { + throw new TypeError( + `Expected \`count\` to be a \`number\`, got \`${typeof count}\`` + ); + } + if (typeof options.indent !== 'string') { + throw new TypeError( + `Expected \`options.indent\` to be a \`string\`, got \`${typeof options.indent}\`` + ); + } + if (count === 0) { + return string; + } + const regex = options.includeEmptyLines ? /^/gm : /^(?!\s*$)/gm; -/** - * Name of the script in the package/project package.json file to run during `kbn watch`. - */ -const watchScriptName = 'kbn:watch'; -/** - * Name of the Kibana project. - */ + return string.replace(regex, options.indent.repeat(count)); +}; -const kibanaProjectName = 'kibana'; -/** - * Command that traverses through list of available projects/packages that have `kbn:watch` script in their - * package.json files, groups them into topology aware batches and then processes theses batches one by one - * running `kbn:watch` scripts in parallel within the same batch. - * - * Command internally relies on the fact that most of the build systems that are triggered by `kbn:watch` - * will emit special "marker" once build/watch process is ready that we can use as completion condition for - * the `kbn:watch` script and eventually for the entire batch. Currently we support completion "markers" for - * `webpack` and `tsc` only, for the rest we rely on predefined timeouts. - */ -const WatchCommand = { - description: 'Runs `kbn:watch` script for every project.', - name: 'watch', +/***/ }), +/* 382 */ +/***/ (function(module, exports, __webpack_require__) { - async run(projects, projectGraph) { - const projectsToWatch = new Map(); +"use strict"; - for (const project of projects.values()) { - // We can't watch project that doesn't have `kbn:watch` script. - if (project.hasScript(watchScriptName)) { - projectsToWatch.set(project.name, project); - } - } +const os = __webpack_require__(120); - if (projectsToWatch.size === 0) { - throw new _utils_errors__WEBPACK_IMPORTED_MODULE_0__["CliError"](`There are no projects to watch found. Make sure that projects define 'kbn:watch' script in 'package.json'.`); - } +const extractPathRegex = /\s+at.*(?:\(|\s)(.*)\)?/; +const pathRegex = /^(?:(?:(?:node|(?:internal\/[\w/]*|.*node_modules\/(?:babel-polyfill|pirates)\/.*)?\w+)\.js:\d+:\d+)|native)/; +const homeDir = typeof os.homedir === 'undefined' ? '' : os.homedir(); - const projectNames = Array.from(projectsToWatch.keys()); - _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].info(`Running ${watchScriptName} scripts for [${projectNames.join(', ')}].`); // Kibana should always be run the last, so we don't rely on automatic - // topological batching and push it to the last one-entry batch manually. +module.exports = (stack, options) => { + options = Object.assign({pretty: false}, options); - const shouldWatchKibanaProject = projectsToWatch.delete(kibanaProjectName); - const batchedProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_3__["topologicallyBatchProjects"])(projectsToWatch, projectGraph); + return stack.replace(/\\/g, '/') + .split('\n') + .filter(line => { + const pathMatches = line.match(extractPathRegex); + if (pathMatches === null || !pathMatches[1]) { + return true; + } - if (shouldWatchKibanaProject) { - batchedProjects.push([projects.get(kibanaProjectName)]); - } + const match = pathMatches[1]; - await Object(_utils_parallelize__WEBPACK_IMPORTED_MODULE_2__["parallelizeBatches"])(batchedProjects, async pkg => { - const completionHint = await Object(_utils_watch__WEBPACK_IMPORTED_MODULE_4__["waitUntilWatchIsReady"])(pkg.runScriptStreaming(watchScriptName, { - debug: false - }).stdout); - _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].success(`[${pkg.name}] Initial build completed (${completionHint}).`); - }); - } + // Electron + if ( + match.includes('.app/Contents/Resources/electron.asar') || + match.includes('.app/Contents/Resources/default_app.asar') + ) { + return false; + } + return !pathRegex.test(match); + }) + .filter(line => line.trim() !== '') + .map(line => { + if (options.pretty) { + return line.replace(extractPathRegex, (m, p1) => m.replace(p1, p1.replace(homeDir, '~'))); + } + + return line; + }) + .join('\n'); }; + /***/ }), -/* 404 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* 383 */ +/***/ (function(module, exports, __webpack_require__) { "use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "waitUntilWatchIsReady", function() { return waitUntilWatchIsReady; }); -/* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(8); -/* harmony import */ var rxjs_operators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(405); -/* - * 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. - */ - - -/** - * Number of milliseconds we wait before we fall back to the default watch handler. - */ -const defaultHandlerDelay = 3000; -/** - * If default watch handler is used, then it's the number of milliseconds we wait for - * any build output before we consider watch task ready. - */ +const chalk = __webpack_require__(384); +const cliCursor = __webpack_require__(387); +const cliSpinners = __webpack_require__(391); +const logSymbols = __webpack_require__(393); -const defaultHandlerReadinessTimeout = 2000; -/** - * Describes configurable watch options. - */ +class Ora { + constructor(options) { + if (typeof options === 'string') { + options = { + text: options + }; + } -function getWatchHandlers(buildOutput$, { - handlerDelay = defaultHandlerDelay, - handlerReadinessTimeout = defaultHandlerReadinessTimeout -}) { - const typescriptHandler = buildOutput$.pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["first"])(data => data.includes('$ tsc')), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["map"])(() => buildOutput$.pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["first"])(data => data.includes('Compilation complete.')), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["mapTo"])('tsc')))); - const webpackHandler = buildOutput$.pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["first"])(data => data.includes('$ webpack')), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["map"])(() => buildOutput$.pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["first"])(data => data.includes('Chunk Names')), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["mapTo"])('webpack')))); - const defaultHandler = rxjs__WEBPACK_IMPORTED_MODULE_0__["of"](undefined).pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["delay"])(handlerReadinessTimeout), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["map"])(() => buildOutput$.pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["timeout"])(handlerDelay), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["catchError"])(() => rxjs__WEBPACK_IMPORTED_MODULE_0__["of"]('timeout'))))); - return [typescriptHandler, webpackHandler, defaultHandler]; -} + this.options = Object.assign({ + text: '', + color: 'cyan', + stream: process.stderr + }, options); -function waitUntilWatchIsReady(stream, opts = {}) { - const buildOutput$ = new rxjs__WEBPACK_IMPORTED_MODULE_0__["Subject"](); + const sp = this.options.spinner; + this.spinner = typeof sp === 'object' ? sp : (process.platform === 'win32' ? cliSpinners.line : (cliSpinners[sp] || cliSpinners.dots)); // eslint-disable-line no-nested-ternary - const onDataListener = data => buildOutput$.next(data.toString('utf-8')); + if (this.spinner.frames === undefined) { + throw new Error('Spinner must define `frames`'); + } - const onEndListener = () => buildOutput$.complete(); + this.text = this.options.text; + this.color = this.options.color; + this.interval = this.options.interval || this.spinner.interval || 100; + this.stream = this.options.stream; + this.id = null; + this.frameIndex = 0; + this.enabled = typeof this.options.enabled === 'boolean' ? this.options.enabled : ((this.stream && this.stream.isTTY) && !process.env.CI); + } + frame() { + const frames = this.spinner.frames; + let frame = frames[this.frameIndex]; - const onErrorListener = e => buildOutput$.error(e); + if (this.color) { + frame = chalk[this.color](frame); + } - stream.once('end', onEndListener); - stream.once('error', onErrorListener); - stream.on('data', onDataListener); - return rxjs__WEBPACK_IMPORTED_MODULE_0__["race"](getWatchHandlers(buildOutput$, opts)).pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["mergeMap"])(whenReady => whenReady), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["finalize"])(() => { - stream.removeListener('data', onDataListener); - stream.removeListener('end', onEndListener); - stream.removeListener('error', onErrorListener); - buildOutput$.complete(); - })).toPromise(); -} + this.frameIndex = ++this.frameIndex % frames.length; -/***/ }), -/* 405 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + return frame + ' ' + this.text; + } + clear() { + if (!this.enabled) { + return this; + } -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony import */ var _internal_operators_audit__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(406); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "audit", function() { return _internal_operators_audit__WEBPACK_IMPORTED_MODULE_0__["audit"]; }); + this.stream.clearLine(); + this.stream.cursorTo(0); -/* harmony import */ var _internal_operators_auditTime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(407); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "auditTime", function() { return _internal_operators_auditTime__WEBPACK_IMPORTED_MODULE_1__["auditTime"]; }); + return this; + } + render() { + this.clear(); + this.stream.write(this.frame()); -/* harmony import */ var _internal_operators_buffer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(408); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buffer", function() { return _internal_operators_buffer__WEBPACK_IMPORTED_MODULE_2__["buffer"]; }); + return this; + } + start(text) { + if (text) { + this.text = text; + } -/* harmony import */ var _internal_operators_bufferCount__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(409); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferCount", function() { return _internal_operators_bufferCount__WEBPACK_IMPORTED_MODULE_3__["bufferCount"]; }); + if (!this.enabled || this.id) { + return this; + } -/* harmony import */ var _internal_operators_bufferTime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(410); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferTime", function() { return _internal_operators_bufferTime__WEBPACK_IMPORTED_MODULE_4__["bufferTime"]; }); + cliCursor.hide(this.stream); + this.render(); + this.id = setInterval(this.render.bind(this), this.interval); -/* harmony import */ var _internal_operators_bufferToggle__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(411); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferToggle", function() { return _internal_operators_bufferToggle__WEBPACK_IMPORTED_MODULE_5__["bufferToggle"]; }); + return this; + } + stop() { + if (!this.enabled) { + return this; + } -/* harmony import */ var _internal_operators_bufferWhen__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(412); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferWhen", function() { return _internal_operators_bufferWhen__WEBPACK_IMPORTED_MODULE_6__["bufferWhen"]; }); + clearInterval(this.id); + this.id = null; + this.frameIndex = 0; + this.clear(); + cliCursor.show(this.stream); -/* harmony import */ var _internal_operators_catchError__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(413); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "catchError", function() { return _internal_operators_catchError__WEBPACK_IMPORTED_MODULE_7__["catchError"]; }); + return this; + } + succeed(text) { + return this.stopAndPersist({symbol: logSymbols.success, text}); + } + fail(text) { + return this.stopAndPersist({symbol: logSymbols.error, text}); + } + warn(text) { + return this.stopAndPersist({symbol: logSymbols.warning, text}); + } + info(text) { + return this.stopAndPersist({symbol: logSymbols.info, text}); + } + stopAndPersist(options) { + if (!this.enabled) { + return this; + } -/* harmony import */ var _internal_operators_combineAll__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(414); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "combineAll", function() { return _internal_operators_combineAll__WEBPACK_IMPORTED_MODULE_8__["combineAll"]; }); + // Legacy argument + // TODO: Deprecate sometime in the future + if (typeof options === 'string') { + options = { + symbol: options + }; + } -/* harmony import */ var _internal_operators_combineLatest__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(415); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "combineLatest", function() { return _internal_operators_combineLatest__WEBPACK_IMPORTED_MODULE_9__["combineLatest"]; }); + options = options || {}; -/* harmony import */ var _internal_operators_concat__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(416); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concat", function() { return _internal_operators_concat__WEBPACK_IMPORTED_MODULE_10__["concat"]; }); + this.stop(); + this.stream.write(`${options.symbol || ' '} ${options.text || this.text}\n`); -/* harmony import */ var _internal_operators_concatAll__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(80); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concatAll", function() { return _internal_operators_concatAll__WEBPACK_IMPORTED_MODULE_11__["concatAll"]; }); + return this; + } +} -/* harmony import */ var _internal_operators_concatMap__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(417); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concatMap", function() { return _internal_operators_concatMap__WEBPACK_IMPORTED_MODULE_12__["concatMap"]; }); +module.exports = function (opts) { + return new Ora(opts); +}; -/* harmony import */ var _internal_operators_concatMapTo__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(418); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concatMapTo", function() { return _internal_operators_concatMapTo__WEBPACK_IMPORTED_MODULE_13__["concatMapTo"]; }); +module.exports.promise = (action, options) => { + if (typeof action.then !== 'function') { + throw new TypeError('Parameter `action` must be a Promise'); + } -/* harmony import */ var _internal_operators_count__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(419); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "count", function() { return _internal_operators_count__WEBPACK_IMPORTED_MODULE_14__["count"]; }); + const spinner = new Ora(options); + spinner.start(); -/* harmony import */ var _internal_operators_debounce__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(420); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "debounce", function() { return _internal_operators_debounce__WEBPACK_IMPORTED_MODULE_15__["debounce"]; }); + action.then( + () => { + spinner.succeed(); + }, + () => { + spinner.fail(); + } + ); -/* harmony import */ var _internal_operators_debounceTime__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(421); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "debounceTime", function() { return _internal_operators_debounceTime__WEBPACK_IMPORTED_MODULE_16__["debounceTime"]; }); + return spinner; +}; -/* harmony import */ var _internal_operators_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(422); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "defaultIfEmpty", function() { return _internal_operators_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_17__["defaultIfEmpty"]; }); -/* harmony import */ var _internal_operators_delay__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(423); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "delay", function() { return _internal_operators_delay__WEBPACK_IMPORTED_MODULE_18__["delay"]; }); +/***/ }), +/* 384 */ +/***/ (function(module, exports, __webpack_require__) { -/* harmony import */ var _internal_operators_delayWhen__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(425); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "delayWhen", function() { return _internal_operators_delayWhen__WEBPACK_IMPORTED_MODULE_19__["delayWhen"]; }); +"use strict"; -/* harmony import */ var _internal_operators_dematerialize__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(426); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "dematerialize", function() { return _internal_operators_dematerialize__WEBPACK_IMPORTED_MODULE_20__["dematerialize"]; }); +const escapeStringRegexp = __webpack_require__(178); +const ansiStyles = __webpack_require__(385); +const stdoutColor = __webpack_require__(184).stdout; -/* harmony import */ var _internal_operators_distinct__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(427); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "distinct", function() { return _internal_operators_distinct__WEBPACK_IMPORTED_MODULE_21__["distinct"]; }); +const template = __webpack_require__(386); -/* harmony import */ var _internal_operators_distinctUntilChanged__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(428); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "distinctUntilChanged", function() { return _internal_operators_distinctUntilChanged__WEBPACK_IMPORTED_MODULE_22__["distinctUntilChanged"]; }); +const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); -/* harmony import */ var _internal_operators_distinctUntilKeyChanged__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(429); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "distinctUntilKeyChanged", function() { return _internal_operators_distinctUntilKeyChanged__WEBPACK_IMPORTED_MODULE_23__["distinctUntilKeyChanged"]; }); +// `supportsColor.level` → `ansiStyles.color[name]` mapping +const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m']; -/* harmony import */ var _internal_operators_elementAt__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(430); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "elementAt", function() { return _internal_operators_elementAt__WEBPACK_IMPORTED_MODULE_24__["elementAt"]; }); +// `color-convert` models to exclude from the Chalk API due to conflicts and such +const skipModels = new Set(['gray']); -/* harmony import */ var _internal_operators_endWith__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(433); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "endWith", function() { return _internal_operators_endWith__WEBPACK_IMPORTED_MODULE_25__["endWith"]; }); +const styles = Object.create(null); -/* harmony import */ var _internal_operators_every__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(434); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "every", function() { return _internal_operators_every__WEBPACK_IMPORTED_MODULE_26__["every"]; }); +function applyOptions(obj, options) { + options = options || {}; -/* harmony import */ var _internal_operators_exhaust__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(435); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "exhaust", function() { return _internal_operators_exhaust__WEBPACK_IMPORTED_MODULE_27__["exhaust"]; }); + // Detect level if not set manually + const scLevel = stdoutColor ? stdoutColor.level : 0; + obj.level = options.level === undefined ? scLevel : options.level; + obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0; +} -/* harmony import */ var _internal_operators_exhaustMap__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(436); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "exhaustMap", function() { return _internal_operators_exhaustMap__WEBPACK_IMPORTED_MODULE_28__["exhaustMap"]; }); +function Chalk(options) { + // We check for this.template here since calling `chalk.constructor()` + // by itself will have a `this` of a previously constructed chalk object + if (!this || !(this instanceof Chalk) || this.template) { + const chalk = {}; + applyOptions(chalk, options); -/* harmony import */ var _internal_operators_expand__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(437); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "expand", function() { return _internal_operators_expand__WEBPACK_IMPORTED_MODULE_29__["expand"]; }); + chalk.template = function () { + const args = [].slice.call(arguments); + return chalkTag.apply(null, [chalk.template].concat(args)); + }; -/* harmony import */ var _internal_operators_filter__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(104); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "filter", function() { return _internal_operators_filter__WEBPACK_IMPORTED_MODULE_30__["filter"]; }); + Object.setPrototypeOf(chalk, Chalk.prototype); + Object.setPrototypeOf(chalk.template, chalk); -/* harmony import */ var _internal_operators_finalize__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(438); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "finalize", function() { return _internal_operators_finalize__WEBPACK_IMPORTED_MODULE_31__["finalize"]; }); + chalk.template.constructor = Chalk; -/* harmony import */ var _internal_operators_find__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(439); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "find", function() { return _internal_operators_find__WEBPACK_IMPORTED_MODULE_32__["find"]; }); + return chalk.template; + } -/* harmony import */ var _internal_operators_findIndex__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(440); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "findIndex", function() { return _internal_operators_findIndex__WEBPACK_IMPORTED_MODULE_33__["findIndex"]; }); + applyOptions(this, options); +} -/* harmony import */ var _internal_operators_first__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(441); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "first", function() { return _internal_operators_first__WEBPACK_IMPORTED_MODULE_34__["first"]; }); +// Use bright blue on Windows as the normal blue color is illegible +if (isSimpleWindowsTerm) { + ansiStyles.blue.open = '\u001B[94m'; +} -/* harmony import */ var _internal_operators_groupBy__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(31); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "groupBy", function() { return _internal_operators_groupBy__WEBPACK_IMPORTED_MODULE_35__["groupBy"]; }); +for (const key of Object.keys(ansiStyles)) { + ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); -/* harmony import */ var _internal_operators_ignoreElements__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(442); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ignoreElements", function() { return _internal_operators_ignoreElements__WEBPACK_IMPORTED_MODULE_36__["ignoreElements"]; }); + styles[key] = { + get() { + const codes = ansiStyles[key]; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key); + } + }; +} -/* harmony import */ var _internal_operators_isEmpty__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(443); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "isEmpty", function() { return _internal_operators_isEmpty__WEBPACK_IMPORTED_MODULE_37__["isEmpty"]; }); +styles.visible = { + get() { + return build.call(this, this._styles || [], true, 'visible'); + } +}; -/* harmony import */ var _internal_operators_last__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(444); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "last", function() { return _internal_operators_last__WEBPACK_IMPORTED_MODULE_38__["last"]; }); +ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g'); +for (const model of Object.keys(ansiStyles.color.ansi)) { + if (skipModels.has(model)) { + continue; + } -/* harmony import */ var _internal_operators_map__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(66); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "map", function() { return _internal_operators_map__WEBPACK_IMPORTED_MODULE_39__["map"]; }); + styles[model] = { + get() { + const level = this.level; + return function () { + const open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments); + const codes = { + open, + close: ansiStyles.color.close, + closeRe: ansiStyles.color.closeRe + }; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); + }; + } + }; +} -/* harmony import */ var _internal_operators_mapTo__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(446); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mapTo", function() { return _internal_operators_mapTo__WEBPACK_IMPORTED_MODULE_40__["mapTo"]; }); +ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g'); +for (const model of Object.keys(ansiStyles.bgColor.ansi)) { + if (skipModels.has(model)) { + continue; + } -/* harmony import */ var _internal_operators_materialize__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(447); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "materialize", function() { return _internal_operators_materialize__WEBPACK_IMPORTED_MODULE_41__["materialize"]; }); + const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1); + styles[bgModel] = { + get() { + const level = this.level; + return function () { + const open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments); + const codes = { + open, + close: ansiStyles.bgColor.close, + closeRe: ansiStyles.bgColor.closeRe + }; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); + }; + } + }; +} -/* harmony import */ var _internal_operators_max__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(448); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "max", function() { return _internal_operators_max__WEBPACK_IMPORTED_MODULE_42__["max"]; }); +const proto = Object.defineProperties(() => {}, styles); -/* harmony import */ var _internal_operators_merge__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(451); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "merge", function() { return _internal_operators_merge__WEBPACK_IMPORTED_MODULE_43__["merge"]; }); +function build(_styles, _empty, key) { + const builder = function () { + return applyStyle.apply(builder, arguments); + }; -/* harmony import */ var _internal_operators_mergeAll__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(81); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mergeAll", function() { return _internal_operators_mergeAll__WEBPACK_IMPORTED_MODULE_44__["mergeAll"]; }); + builder._styles = _styles; + builder._empty = _empty; -/* harmony import */ var _internal_operators_mergeMap__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(82); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mergeMap", function() { return _internal_operators_mergeMap__WEBPACK_IMPORTED_MODULE_45__["mergeMap"]; }); + const self = this; -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "flatMap", function() { return _internal_operators_mergeMap__WEBPACK_IMPORTED_MODULE_45__["mergeMap"]; }); + Object.defineProperty(builder, 'level', { + enumerable: true, + get() { + return self.level; + }, + set(level) { + self.level = level; + } + }); -/* harmony import */ var _internal_operators_mergeMapTo__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(452); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mergeMapTo", function() { return _internal_operators_mergeMapTo__WEBPACK_IMPORTED_MODULE_46__["mergeMapTo"]; }); + Object.defineProperty(builder, 'enabled', { + enumerable: true, + get() { + return self.enabled; + }, + set(enabled) { + self.enabled = enabled; + } + }); -/* harmony import */ var _internal_operators_mergeScan__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(453); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mergeScan", function() { return _internal_operators_mergeScan__WEBPACK_IMPORTED_MODULE_47__["mergeScan"]; }); + // See below for fix regarding invisible grey/dim combination on Windows + builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; -/* harmony import */ var _internal_operators_min__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(454); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "min", function() { return _internal_operators_min__WEBPACK_IMPORTED_MODULE_48__["min"]; }); + // `__proto__` is used because we must return a function, but there is + // no way to create a function with a different prototype + builder.__proto__ = proto; // eslint-disable-line no-proto -/* harmony import */ var _internal_operators_multicast__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(455); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "multicast", function() { return _internal_operators_multicast__WEBPACK_IMPORTED_MODULE_49__["multicast"]; }); + return builder; +} -/* harmony import */ var _internal_operators_observeOn__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(41); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "observeOn", function() { return _internal_operators_observeOn__WEBPACK_IMPORTED_MODULE_50__["observeOn"]; }); +function applyStyle() { + // Support varags, but simply cast to string in case there's only one arg + const args = arguments; + const argsLen = args.length; + let str = String(arguments[0]); -/* harmony import */ var _internal_operators_onErrorResumeNext__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(456); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "onErrorResumeNext", function() { return _internal_operators_onErrorResumeNext__WEBPACK_IMPORTED_MODULE_51__["onErrorResumeNext"]; }); + if (argsLen === 0) { + return ''; + } -/* harmony import */ var _internal_operators_pairwise__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(457); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "pairwise", function() { return _internal_operators_pairwise__WEBPACK_IMPORTED_MODULE_52__["pairwise"]; }); + if (argsLen > 1) { + // Don't slice `arguments`, it prevents V8 optimizations + for (let a = 1; a < argsLen; a++) { + str += ' ' + args[a]; + } + } -/* harmony import */ var _internal_operators_partition__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(458); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "partition", function() { return _internal_operators_partition__WEBPACK_IMPORTED_MODULE_53__["partition"]; }); + if (!this.enabled || this.level <= 0 || !str) { + return this._empty ? '' : str; + } -/* harmony import */ var _internal_operators_pluck__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(459); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "pluck", function() { return _internal_operators_pluck__WEBPACK_IMPORTED_MODULE_54__["pluck"]; }); + // Turns out that on Windows dimmed gray text becomes invisible in cmd.exe, + // see https://github.com/chalk/chalk/issues/58 + // If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop. + const originalDim = ansiStyles.dim.open; + if (isSimpleWindowsTerm && this.hasGrey) { + ansiStyles.dim.open = ''; + } -/* harmony import */ var _internal_operators_publish__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(460); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publish", function() { return _internal_operators_publish__WEBPACK_IMPORTED_MODULE_55__["publish"]; }); + for (const code of this._styles.slice().reverse()) { + // Replace any instances already present with a re-opening code + // otherwise only the part of the string until said closing code + // will be colored, and the rest will simply be 'plain'. + str = code.open + str.replace(code.closeRe, code.open) + code.close; -/* harmony import */ var _internal_operators_publishBehavior__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(461); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publishBehavior", function() { return _internal_operators_publishBehavior__WEBPACK_IMPORTED_MODULE_56__["publishBehavior"]; }); + // Close the styling before a linebreak and reopen + // after next line to fix a bleed issue on macOS + // https://github.com/chalk/chalk/pull/92 + str = str.replace(/\r?\n/g, `${code.close}$&${code.open}`); + } -/* harmony import */ var _internal_operators_publishLast__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(462); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publishLast", function() { return _internal_operators_publishLast__WEBPACK_IMPORTED_MODULE_57__["publishLast"]; }); + // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue + ansiStyles.dim.open = originalDim; -/* harmony import */ var _internal_operators_publishReplay__WEBPACK_IMPORTED_MODULE_58__ = __webpack_require__(463); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publishReplay", function() { return _internal_operators_publishReplay__WEBPACK_IMPORTED_MODULE_58__["publishReplay"]; }); + return str; +} -/* harmony import */ var _internal_operators_race__WEBPACK_IMPORTED_MODULE_59__ = __webpack_require__(464); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "race", function() { return _internal_operators_race__WEBPACK_IMPORTED_MODULE_59__["race"]; }); +function chalkTag(chalk, strings) { + if (!Array.isArray(strings)) { + // If chalk() was called by itself or with a string, + // return the string itself as a string. + return [].slice.call(arguments, 1).join(' '); + } -/* harmony import */ var _internal_operators_reduce__WEBPACK_IMPORTED_MODULE_60__ = __webpack_require__(449); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "reduce", function() { return _internal_operators_reduce__WEBPACK_IMPORTED_MODULE_60__["reduce"]; }); + const args = [].slice.call(arguments, 2); + const parts = [strings.raw[0]]; -/* harmony import */ var _internal_operators_repeat__WEBPACK_IMPORTED_MODULE_61__ = __webpack_require__(465); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "repeat", function() { return _internal_operators_repeat__WEBPACK_IMPORTED_MODULE_61__["repeat"]; }); + for (let i = 1; i < strings.length; i++) { + parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&')); + parts.push(String(strings.raw[i])); + } -/* harmony import */ var _internal_operators_repeatWhen__WEBPACK_IMPORTED_MODULE_62__ = __webpack_require__(466); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "repeatWhen", function() { return _internal_operators_repeatWhen__WEBPACK_IMPORTED_MODULE_62__["repeatWhen"]; }); + return template(chalk, parts.join('')); +} -/* harmony import */ var _internal_operators_retry__WEBPACK_IMPORTED_MODULE_63__ = __webpack_require__(467); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "retry", function() { return _internal_operators_retry__WEBPACK_IMPORTED_MODULE_63__["retry"]; }); +Object.defineProperties(Chalk.prototype, styles); -/* harmony import */ var _internal_operators_retryWhen__WEBPACK_IMPORTED_MODULE_64__ = __webpack_require__(468); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "retryWhen", function() { return _internal_operators_retryWhen__WEBPACK_IMPORTED_MODULE_64__["retryWhen"]; }); +module.exports = Chalk(); // eslint-disable-line new-cap +module.exports.supportsColor = stdoutColor; +module.exports.default = module.exports; // For TypeScript -/* harmony import */ var _internal_operators_refCount__WEBPACK_IMPORTED_MODULE_65__ = __webpack_require__(30); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "refCount", function() { return _internal_operators_refCount__WEBPACK_IMPORTED_MODULE_65__["refCount"]; }); -/* harmony import */ var _internal_operators_sample__WEBPACK_IMPORTED_MODULE_66__ = __webpack_require__(469); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "sample", function() { return _internal_operators_sample__WEBPACK_IMPORTED_MODULE_66__["sample"]; }); +/***/ }), +/* 385 */ +/***/ (function(module, exports, __webpack_require__) { -/* harmony import */ var _internal_operators_sampleTime__WEBPACK_IMPORTED_MODULE_67__ = __webpack_require__(470); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "sampleTime", function() { return _internal_operators_sampleTime__WEBPACK_IMPORTED_MODULE_67__["sampleTime"]; }); +"use strict"; +/* WEBPACK VAR INJECTION */(function(module) { +const colorConvert = __webpack_require__(180); -/* harmony import */ var _internal_operators_scan__WEBPACK_IMPORTED_MODULE_68__ = __webpack_require__(450); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "scan", function() { return _internal_operators_scan__WEBPACK_IMPORTED_MODULE_68__["scan"]; }); +const wrapAnsi16 = (fn, offset) => function () { + const code = fn.apply(colorConvert, arguments); + return `\u001B[${code + offset}m`; +}; -/* harmony import */ var _internal_operators_sequenceEqual__WEBPACK_IMPORTED_MODULE_69__ = __webpack_require__(471); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "sequenceEqual", function() { return _internal_operators_sequenceEqual__WEBPACK_IMPORTED_MODULE_69__["sequenceEqual"]; }); +const wrapAnsi256 = (fn, offset) => function () { + const code = fn.apply(colorConvert, arguments); + return `\u001B[${38 + offset};5;${code}m`; +}; -/* harmony import */ var _internal_operators_share__WEBPACK_IMPORTED_MODULE_70__ = __webpack_require__(472); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "share", function() { return _internal_operators_share__WEBPACK_IMPORTED_MODULE_70__["share"]; }); +const wrapAnsi16m = (fn, offset) => function () { + const rgb = fn.apply(colorConvert, arguments); + return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}m`; +}; -/* harmony import */ var _internal_operators_shareReplay__WEBPACK_IMPORTED_MODULE_71__ = __webpack_require__(473); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "shareReplay", function() { return _internal_operators_shareReplay__WEBPACK_IMPORTED_MODULE_71__["shareReplay"]; }); +function assembleStyles() { + const codes = new Map(); + const styles = { + modifier: { + reset: [0, 0], + // 21 isn't widely supported and 22 does the same thing + bold: [1, 22], + dim: [2, 22], + italic: [3, 23], + underline: [4, 24], + inverse: [7, 27], + hidden: [8, 28], + strikethrough: [9, 29] + }, + color: { + black: [30, 39], + red: [31, 39], + green: [32, 39], + yellow: [33, 39], + blue: [34, 39], + magenta: [35, 39], + cyan: [36, 39], + white: [37, 39], + gray: [90, 39], -/* harmony import */ var _internal_operators_single__WEBPACK_IMPORTED_MODULE_72__ = __webpack_require__(474); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "single", function() { return _internal_operators_single__WEBPACK_IMPORTED_MODULE_72__["single"]; }); + // Bright color + redBright: [91, 39], + greenBright: [92, 39], + yellowBright: [93, 39], + blueBright: [94, 39], + magentaBright: [95, 39], + cyanBright: [96, 39], + whiteBright: [97, 39] + }, + bgColor: { + bgBlack: [40, 49], + bgRed: [41, 49], + bgGreen: [42, 49], + bgYellow: [43, 49], + bgBlue: [44, 49], + bgMagenta: [45, 49], + bgCyan: [46, 49], + bgWhite: [47, 49], -/* harmony import */ var _internal_operators_skip__WEBPACK_IMPORTED_MODULE_73__ = __webpack_require__(475); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skip", function() { return _internal_operators_skip__WEBPACK_IMPORTED_MODULE_73__["skip"]; }); + // Bright color + bgBlackBright: [100, 49], + bgRedBright: [101, 49], + bgGreenBright: [102, 49], + bgYellowBright: [103, 49], + bgBlueBright: [104, 49], + bgMagentaBright: [105, 49], + bgCyanBright: [106, 49], + bgWhiteBright: [107, 49] + } + }; -/* harmony import */ var _internal_operators_skipLast__WEBPACK_IMPORTED_MODULE_74__ = __webpack_require__(476); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skipLast", function() { return _internal_operators_skipLast__WEBPACK_IMPORTED_MODULE_74__["skipLast"]; }); + // Fix humans + styles.color.grey = styles.color.gray; -/* harmony import */ var _internal_operators_skipUntil__WEBPACK_IMPORTED_MODULE_75__ = __webpack_require__(477); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skipUntil", function() { return _internal_operators_skipUntil__WEBPACK_IMPORTED_MODULE_75__["skipUntil"]; }); + for (const groupName of Object.keys(styles)) { + const group = styles[groupName]; -/* harmony import */ var _internal_operators_skipWhile__WEBPACK_IMPORTED_MODULE_76__ = __webpack_require__(478); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skipWhile", function() { return _internal_operators_skipWhile__WEBPACK_IMPORTED_MODULE_76__["skipWhile"]; }); + for (const styleName of Object.keys(group)) { + const style = group[styleName]; -/* harmony import */ var _internal_operators_startWith__WEBPACK_IMPORTED_MODULE_77__ = __webpack_require__(479); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "startWith", function() { return _internal_operators_startWith__WEBPACK_IMPORTED_MODULE_77__["startWith"]; }); + styles[styleName] = { + open: `\u001B[${style[0]}m`, + close: `\u001B[${style[1]}m` + }; -/* harmony import */ var _internal_operators_subscribeOn__WEBPACK_IMPORTED_MODULE_78__ = __webpack_require__(480); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "subscribeOn", function() { return _internal_operators_subscribeOn__WEBPACK_IMPORTED_MODULE_78__["subscribeOn"]; }); + group[styleName] = styles[styleName]; -/* harmony import */ var _internal_operators_switchAll__WEBPACK_IMPORTED_MODULE_79__ = __webpack_require__(482); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "switchAll", function() { return _internal_operators_switchAll__WEBPACK_IMPORTED_MODULE_79__["switchAll"]; }); + codes.set(style[0], style[1]); + } -/* harmony import */ var _internal_operators_switchMap__WEBPACK_IMPORTED_MODULE_80__ = __webpack_require__(483); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "switchMap", function() { return _internal_operators_switchMap__WEBPACK_IMPORTED_MODULE_80__["switchMap"]; }); + Object.defineProperty(styles, groupName, { + value: group, + enumerable: false + }); -/* harmony import */ var _internal_operators_switchMapTo__WEBPACK_IMPORTED_MODULE_81__ = __webpack_require__(484); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "switchMapTo", function() { return _internal_operators_switchMapTo__WEBPACK_IMPORTED_MODULE_81__["switchMapTo"]; }); + Object.defineProperty(styles, 'codes', { + value: codes, + enumerable: false + }); + } -/* harmony import */ var _internal_operators_take__WEBPACK_IMPORTED_MODULE_82__ = __webpack_require__(432); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "take", function() { return _internal_operators_take__WEBPACK_IMPORTED_MODULE_82__["take"]; }); + const ansi2ansi = n => n; + const rgb2rgb = (r, g, b) => [r, g, b]; -/* harmony import */ var _internal_operators_takeLast__WEBPACK_IMPORTED_MODULE_83__ = __webpack_require__(445); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "takeLast", function() { return _internal_operators_takeLast__WEBPACK_IMPORTED_MODULE_83__["takeLast"]; }); + styles.color.close = '\u001B[39m'; + styles.bgColor.close = '\u001B[49m'; -/* harmony import */ var _internal_operators_takeUntil__WEBPACK_IMPORTED_MODULE_84__ = __webpack_require__(485); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "takeUntil", function() { return _internal_operators_takeUntil__WEBPACK_IMPORTED_MODULE_84__["takeUntil"]; }); + styles.color.ansi = { + ansi: wrapAnsi16(ansi2ansi, 0) + }; + styles.color.ansi256 = { + ansi256: wrapAnsi256(ansi2ansi, 0) + }; + styles.color.ansi16m = { + rgb: wrapAnsi16m(rgb2rgb, 0) + }; -/* harmony import */ var _internal_operators_takeWhile__WEBPACK_IMPORTED_MODULE_85__ = __webpack_require__(486); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "takeWhile", function() { return _internal_operators_takeWhile__WEBPACK_IMPORTED_MODULE_85__["takeWhile"]; }); + styles.bgColor.ansi = { + ansi: wrapAnsi16(ansi2ansi, 10) + }; + styles.bgColor.ansi256 = { + ansi256: wrapAnsi256(ansi2ansi, 10) + }; + styles.bgColor.ansi16m = { + rgb: wrapAnsi16m(rgb2rgb, 10) + }; -/* harmony import */ var _internal_operators_tap__WEBPACK_IMPORTED_MODULE_86__ = __webpack_require__(487); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "tap", function() { return _internal_operators_tap__WEBPACK_IMPORTED_MODULE_86__["tap"]; }); + for (let key of Object.keys(colorConvert)) { + if (typeof colorConvert[key] !== 'object') { + continue; + } -/* harmony import */ var _internal_operators_throttle__WEBPACK_IMPORTED_MODULE_87__ = __webpack_require__(488); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "throttle", function() { return _internal_operators_throttle__WEBPACK_IMPORTED_MODULE_87__["throttle"]; }); + const suite = colorConvert[key]; -/* harmony import */ var _internal_operators_throttleTime__WEBPACK_IMPORTED_MODULE_88__ = __webpack_require__(489); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "throttleTime", function() { return _internal_operators_throttleTime__WEBPACK_IMPORTED_MODULE_88__["throttleTime"]; }); + if (key === 'ansi16') { + key = 'ansi'; + } -/* harmony import */ var _internal_operators_throwIfEmpty__WEBPACK_IMPORTED_MODULE_89__ = __webpack_require__(431); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "throwIfEmpty", function() { return _internal_operators_throwIfEmpty__WEBPACK_IMPORTED_MODULE_89__["throwIfEmpty"]; }); + if ('ansi16' in suite) { + styles.color.ansi[key] = wrapAnsi16(suite.ansi16, 0); + styles.bgColor.ansi[key] = wrapAnsi16(suite.ansi16, 10); + } -/* harmony import */ var _internal_operators_timeInterval__WEBPACK_IMPORTED_MODULE_90__ = __webpack_require__(490); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timeInterval", function() { return _internal_operators_timeInterval__WEBPACK_IMPORTED_MODULE_90__["timeInterval"]; }); + if ('ansi256' in suite) { + styles.color.ansi256[key] = wrapAnsi256(suite.ansi256, 0); + styles.bgColor.ansi256[key] = wrapAnsi256(suite.ansi256, 10); + } -/* harmony import */ var _internal_operators_timeout__WEBPACK_IMPORTED_MODULE_91__ = __webpack_require__(491); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timeout", function() { return _internal_operators_timeout__WEBPACK_IMPORTED_MODULE_91__["timeout"]; }); + if ('rgb' in suite) { + styles.color.ansi16m[key] = wrapAnsi16m(suite.rgb, 0); + styles.bgColor.ansi16m[key] = wrapAnsi16m(suite.rgb, 10); + } + } -/* harmony import */ var _internal_operators_timeoutWith__WEBPACK_IMPORTED_MODULE_92__ = __webpack_require__(492); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timeoutWith", function() { return _internal_operators_timeoutWith__WEBPACK_IMPORTED_MODULE_92__["timeoutWith"]; }); + return styles; +} -/* harmony import */ var _internal_operators_timestamp__WEBPACK_IMPORTED_MODULE_93__ = __webpack_require__(493); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timestamp", function() { return _internal_operators_timestamp__WEBPACK_IMPORTED_MODULE_93__["timestamp"]; }); +// Make the export immutable +Object.defineProperty(module, 'exports', { + enumerable: true, + get: assembleStyles +}); -/* harmony import */ var _internal_operators_toArray__WEBPACK_IMPORTED_MODULE_94__ = __webpack_require__(494); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "toArray", function() { return _internal_operators_toArray__WEBPACK_IMPORTED_MODULE_94__["toArray"]; }); +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(114)(module))) -/* harmony import */ var _internal_operators_window__WEBPACK_IMPORTED_MODULE_95__ = __webpack_require__(495); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "window", function() { return _internal_operators_window__WEBPACK_IMPORTED_MODULE_95__["window"]; }); +/***/ }), +/* 386 */ +/***/ (function(module, exports, __webpack_require__) { -/* harmony import */ var _internal_operators_windowCount__WEBPACK_IMPORTED_MODULE_96__ = __webpack_require__(496); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowCount", function() { return _internal_operators_windowCount__WEBPACK_IMPORTED_MODULE_96__["windowCount"]; }); +"use strict"; -/* harmony import */ var _internal_operators_windowTime__WEBPACK_IMPORTED_MODULE_97__ = __webpack_require__(497); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowTime", function() { return _internal_operators_windowTime__WEBPACK_IMPORTED_MODULE_97__["windowTime"]; }); +const TEMPLATE_REGEX = /(?:\\(u[a-f\d]{4}|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; +const STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; +const STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/; +const ESCAPE_REGEX = /\\(u[a-f\d]{4}|x[a-f\d]{2}|.)|([^\\])/gi; -/* harmony import */ var _internal_operators_windowToggle__WEBPACK_IMPORTED_MODULE_98__ = __webpack_require__(498); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowToggle", function() { return _internal_operators_windowToggle__WEBPACK_IMPORTED_MODULE_98__["windowToggle"]; }); +const ESCAPES = new Map([ + ['n', '\n'], + ['r', '\r'], + ['t', '\t'], + ['b', '\b'], + ['f', '\f'], + ['v', '\v'], + ['0', '\0'], + ['\\', '\\'], + ['e', '\u001B'], + ['a', '\u0007'] +]); -/* harmony import */ var _internal_operators_windowWhen__WEBPACK_IMPORTED_MODULE_99__ = __webpack_require__(499); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowWhen", function() { return _internal_operators_windowWhen__WEBPACK_IMPORTED_MODULE_99__["windowWhen"]; }); +function unescape(c) { + if ((c[0] === 'u' && c.length === 5) || (c[0] === 'x' && c.length === 3)) { + return String.fromCharCode(parseInt(c.slice(1), 16)); + } -/* harmony import */ var _internal_operators_withLatestFrom__WEBPACK_IMPORTED_MODULE_100__ = __webpack_require__(500); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "withLatestFrom", function() { return _internal_operators_withLatestFrom__WEBPACK_IMPORTED_MODULE_100__["withLatestFrom"]; }); + return ESCAPES.get(c) || c; +} -/* harmony import */ var _internal_operators_zip__WEBPACK_IMPORTED_MODULE_101__ = __webpack_require__(501); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "zip", function() { return _internal_operators_zip__WEBPACK_IMPORTED_MODULE_101__["zip"]; }); +function parseArguments(name, args) { + const results = []; + const chunks = args.trim().split(/\s*,\s*/g); + let matches; -/* harmony import */ var _internal_operators_zipAll__WEBPACK_IMPORTED_MODULE_102__ = __webpack_require__(502); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "zipAll", function() { return _internal_operators_zipAll__WEBPACK_IMPORTED_MODULE_102__["zipAll"]; }); + for (const chunk of chunks) { + if (!isNaN(chunk)) { + results.push(Number(chunk)); + } else if ((matches = chunk.match(STRING_REGEX))) { + results.push(matches[2].replace(ESCAPE_REGEX, (m, escape, chr) => escape ? unescape(escape) : chr)); + } else { + throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`); + } + } -/** PURE_IMPORTS_START PURE_IMPORTS_END */ + return results; +} +function parseStyle(style) { + STYLE_REGEX.lastIndex = 0; + const results = []; + let matches; + while ((matches = STYLE_REGEX.exec(style)) !== null) { + const name = matches[1]; + if (matches[2]) { + const args = parseArguments(name, matches[2]); + results.push([name].concat(args)); + } else { + results.push([name]); + } + } + return results; +} +function buildStyle(chalk, styles) { + const enabled = {}; + for (const layer of styles) { + for (const style of layer.styles) { + enabled[style[0]] = layer.inverse ? null : style.slice(1); + } + } + let current = chalk; + for (const styleName of Object.keys(enabled)) { + if (Array.isArray(enabled[styleName])) { + if (!(styleName in current)) { + throw new Error(`Unknown Chalk style: ${styleName}`); + } + if (enabled[styleName].length > 0) { + current = current[styleName].apply(current, enabled[styleName]); + } else { + current = current[styleName]; + } + } + } + return current; +} +module.exports = (chalk, tmp) => { + const styles = []; + const chunks = []; + let chunk = []; + // eslint-disable-next-line max-params + tmp.replace(TEMPLATE_REGEX, (m, escapeChar, inverse, style, close, chr) => { + if (escapeChar) { + chunk.push(unescape(escapeChar)); + } else if (style) { + const str = chunk.join(''); + chunk = []; + chunks.push(styles.length === 0 ? str : buildStyle(chalk, styles)(str)); + styles.push({inverse, styles: parseStyle(style)}); + } else if (close) { + if (styles.length === 0) { + throw new Error('Found extraneous } in Chalk template literal'); + } + chunks.push(buildStyle(chalk, styles)(chunk.join(''))); + chunk = []; + styles.pop(); + } else { + chunk.push(chr); + } + }); + chunks.push(chunk.join('')); + if (styles.length > 0) { + const errMsg = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? '' : 's'} (\`}\`)`; + throw new Error(errMsg); + } + return chunks.join(''); +}; +/***/ }), +/* 387 */ +/***/ (function(module, exports, __webpack_require__) { +"use strict"; +const restoreCursor = __webpack_require__(388); +let hidden = false; +exports.show = stream => { + const s = stream || process.stderr; + if (!s.isTTY) { + return; + } + hidden = false; + s.write('\u001b[?25h'); +}; +exports.hide = stream => { + const s = stream || process.stderr; + if (!s.isTTY) { + return; + } + restoreCursor(); + hidden = true; + s.write('\u001b[?25l'); +}; +exports.toggle = (force, stream) => { + if (force !== undefined) { + hidden = force; + } + if (hidden) { + exports.show(stream); + } else { + exports.hide(stream); + } +}; +/***/ }), +/* 388 */ +/***/ (function(module, exports, __webpack_require__) { +"use strict"; +const onetime = __webpack_require__(389); +const signalExit = __webpack_require__(225); +module.exports = onetime(() => { + signalExit(() => { + process.stderr.write('\u001b[?25h'); + }, {alwaysLast: true}); +}); +/***/ }), +/* 389 */ +/***/ (function(module, exports, __webpack_require__) { +"use strict"; +const mimicFn = __webpack_require__(390); +module.exports = (fn, opts) => { + // TODO: Remove this in v3 + if (opts === true) { + throw new TypeError('The second argument is now an options object'); + } + if (typeof fn !== 'function') { + throw new TypeError('Expected a function'); + } + opts = opts || {}; + let ret; + let called = false; + const fnName = fn.displayName || fn.name || ''; + const onetime = function () { + if (called) { + if (opts.throw === true) { + throw new Error(`Function \`${fnName}\` can only be called once`); + } + return ret; + } + called = true; + ret = fn.apply(this, arguments); + fn = null; + return ret; + }; + mimicFn(onetime, fn); + return onetime; +}; +/***/ }), +/* 390 */ +/***/ (function(module, exports, __webpack_require__) { +"use strict"; +module.exports = (to, from) => { + // TODO: use `Reflect.ownKeys()` when targeting Node.js 6 + for (const prop of Object.getOwnPropertyNames(from).concat(Object.getOwnPropertySymbols(from))) { + Object.defineProperty(to, prop, Object.getOwnPropertyDescriptor(from, prop)); + } + return to; +}; +/***/ }), +/* 391 */ +/***/ (function(module, exports, __webpack_require__) { +"use strict"; +module.exports = __webpack_require__(392); +/***/ }), +/* 392 */ +/***/ (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\":[\"🌲\",\"🎄\"]}}"); +/***/ }), +/* 393 */ +/***/ (function(module, exports, __webpack_require__) { +"use strict"; +const chalk = __webpack_require__(394); +const isSupported = process.platform !== 'win32' || process.env.CI || process.env.TERM === 'xterm-256color'; +const main = { + info: chalk.blue('ℹ'), + success: chalk.green('✔'), + warning: chalk.yellow('⚠'), + error: chalk.red('✖') +}; +const fallbacks = { + info: chalk.blue('i'), + success: chalk.green('√'), + warning: chalk.yellow('‼'), + error: chalk.red('×') +}; +module.exports = isSupported ? main : fallbacks; +/***/ }), +/* 394 */ +/***/ (function(module, exports, __webpack_require__) { +"use strict"; +const escapeStringRegexp = __webpack_require__(178); +const ansiStyles = __webpack_require__(395); +const stdoutColor = __webpack_require__(184).stdout; +const template = __webpack_require__(396); +const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); +// `supportsColor.level` → `ansiStyles.color[name]` mapping +const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m']; +// `color-convert` models to exclude from the Chalk API due to conflicts and such +const skipModels = new Set(['gray']); +const styles = Object.create(null); +function applyOptions(obj, options) { + options = options || {}; + // Detect level if not set manually + const scLevel = stdoutColor ? stdoutColor.level : 0; + obj.level = options.level === undefined ? scLevel : options.level; + obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0; +} +function Chalk(options) { + // We check for this.template here since calling `chalk.constructor()` + // by itself will have a `this` of a previously constructed chalk object + if (!this || !(this instanceof Chalk) || this.template) { + const chalk = {}; + applyOptions(chalk, options); + chalk.template = function () { + const args = [].slice.call(arguments); + return chalkTag.apply(null, [chalk.template].concat(args)); + }; + Object.setPrototypeOf(chalk, Chalk.prototype); + Object.setPrototypeOf(chalk.template, chalk); + chalk.template.constructor = Chalk; + return chalk.template; + } + applyOptions(this, options); +} +// Use bright blue on Windows as the normal blue color is illegible +if (isSimpleWindowsTerm) { + ansiStyles.blue.open = '\u001B[94m'; +} +for (const key of Object.keys(ansiStyles)) { + ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); + styles[key] = { + get() { + const codes = ansiStyles[key]; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key); + } + }; +} +styles.visible = { + get() { + return build.call(this, this._styles || [], true, 'visible'); + } +}; +ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g'); +for (const model of Object.keys(ansiStyles.color.ansi)) { + if (skipModels.has(model)) { + continue; + } + styles[model] = { + get() { + const level = this.level; + return function () { + const open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments); + const codes = { + open, + close: ansiStyles.color.close, + closeRe: ansiStyles.color.closeRe + }; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); + }; + } + }; +} +ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g'); +for (const model of Object.keys(ansiStyles.bgColor.ansi)) { + if (skipModels.has(model)) { + continue; + } + const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1); + styles[bgModel] = { + get() { + const level = this.level; + return function () { + const open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments); + const codes = { + open, + close: ansiStyles.bgColor.close, + closeRe: ansiStyles.bgColor.closeRe + }; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model); + }; + } + }; +} +const proto = Object.defineProperties(() => {}, styles); +function build(_styles, _empty, key) { + const builder = function () { + return applyStyle.apply(builder, arguments); + }; + builder._styles = _styles; + builder._empty = _empty; + const self = this; + Object.defineProperty(builder, 'level', { + enumerable: true, + get() { + return self.level; + }, + set(level) { + self.level = level; + } + }); + Object.defineProperty(builder, 'enabled', { + enumerable: true, + get() { + return self.enabled; + }, + set(enabled) { + self.enabled = enabled; + } + }); + // See below for fix regarding invisible grey/dim combination on Windows + builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; + // `__proto__` is used because we must return a function, but there is + // no way to create a function with a different prototype + builder.__proto__ = proto; // eslint-disable-line no-proto + return builder; +} +function applyStyle() { + // Support varags, but simply cast to string in case there's only one arg + const args = arguments; + const argsLen = args.length; + let str = String(arguments[0]); + if (argsLen === 0) { + return ''; + } -//# sourceMappingURL=index.js.map + if (argsLen > 1) { + // Don't slice `arguments`, it prevents V8 optimizations + for (let a = 1; a < argsLen; a++) { + str += ' ' + args[a]; + } + } + if (!this.enabled || this.level <= 0 || !str) { + return this._empty ? '' : str; + } -/***/ }), -/* 406 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + // Turns out that on Windows dimmed gray text becomes invisible in cmd.exe, + // see https://github.com/chalk/chalk/issues/58 + // If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop. + const originalDim = ansiStyles.dim.open; + if (isSimpleWindowsTerm && this.hasGrey) { + ansiStyles.dim.open = ''; + } -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "audit", function() { return audit; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(70); -/** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ + for (const code of this._styles.slice().reverse()) { + // Replace any instances already present with a re-opening code + // otherwise only the part of the string until said closing code + // will be colored, and the rest will simply be 'plain'. + str = code.open + str.replace(code.closeRe, code.open) + code.close; + // Close the styling before a linebreak and reopen + // after next line to fix a bleed issue on macOS + // https://github.com/chalk/chalk/pull/92 + str = str.replace(/\r?\n/g, `${code.close}$&${code.open}`); + } + // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue + ansiStyles.dim.open = originalDim; -function audit(durationSelector) { - return function auditOperatorFunction(source) { - return source.lift(new AuditOperator(durationSelector)); - }; + return str; } -var AuditOperator = /*@__PURE__*/ (function () { - function AuditOperator(durationSelector) { - this.durationSelector = durationSelector; - } - AuditOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new AuditSubscriber(subscriber, this.durationSelector)); - }; - return AuditOperator; -}()); -var AuditSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](AuditSubscriber, _super); - function AuditSubscriber(destination, durationSelector) { - var _this = _super.call(this, destination) || this; - _this.durationSelector = durationSelector; - _this.hasValue = false; - return _this; - } - AuditSubscriber.prototype._next = function (value) { - this.value = value; - this.hasValue = true; - if (!this.throttled) { - var duration = void 0; - try { - var durationSelector = this.durationSelector; - duration = durationSelector(value); - } - catch (err) { - return this.destination.error(err); - } - var innerSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(this, duration); - if (!innerSubscription || innerSubscription.closed) { - this.clearThrottle(); - } - else { - this.add(this.throttled = innerSubscription); - } - } - }; - AuditSubscriber.prototype.clearThrottle = function () { - var _a = this, value = _a.value, hasValue = _a.hasValue, throttled = _a.throttled; - if (throttled) { - this.remove(throttled); - this.throttled = null; - throttled.unsubscribe(); - } - if (hasValue) { - this.value = null; - this.hasValue = false; - this.destination.next(value); - } - }; - AuditSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex) { - this.clearThrottle(); - }; - AuditSubscriber.prototype.notifyComplete = function () { - this.clearThrottle(); - }; - return AuditSubscriber; -}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); -//# sourceMappingURL=audit.js.map - - -/***/ }), -/* 407 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "auditTime", function() { return auditTime; }); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(55); -/* harmony import */ var _audit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(406); -/* harmony import */ var _observable_timer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(107); -/** PURE_IMPORTS_START _scheduler_async,_audit,_observable_timer PURE_IMPORTS_END */ +function chalkTag(chalk, strings) { + if (!Array.isArray(strings)) { + // If chalk() was called by itself or with a string, + // return the string itself as a string. + return [].slice.call(arguments, 1).join(' '); + } + const args = [].slice.call(arguments, 2); + const parts = [strings.raw[0]]; + for (let i = 1; i < strings.length; i++) { + parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&')); + parts.push(String(strings.raw[i])); + } -function auditTime(duration, scheduler) { - if (scheduler === void 0) { - scheduler = _scheduler_async__WEBPACK_IMPORTED_MODULE_0__["async"]; - } - return Object(_audit__WEBPACK_IMPORTED_MODULE_1__["audit"])(function () { return Object(_observable_timer__WEBPACK_IMPORTED_MODULE_2__["timer"])(duration, scheduler); }); + return template(chalk, parts.join('')); } -//# sourceMappingURL=auditTime.js.map - - -/***/ }), -/* 408 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buffer", function() { return buffer; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(70); -/** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ - +Object.defineProperties(Chalk.prototype, styles); -function buffer(closingNotifier) { - return function bufferOperatorFunction(source) { - return source.lift(new BufferOperator(closingNotifier)); - }; -} -var BufferOperator = /*@__PURE__*/ (function () { - function BufferOperator(closingNotifier) { - this.closingNotifier = closingNotifier; - } - BufferOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new BufferSubscriber(subscriber, this.closingNotifier)); - }; - return BufferOperator; -}()); -var BufferSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](BufferSubscriber, _super); - function BufferSubscriber(destination, closingNotifier) { - var _this = _super.call(this, destination) || this; - _this.buffer = []; - _this.add(Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(_this, closingNotifier)); - return _this; - } - BufferSubscriber.prototype._next = function (value) { - this.buffer.push(value); - }; - BufferSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { - var buffer = this.buffer; - this.buffer = []; - this.destination.next(buffer); - }; - return BufferSubscriber; -}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); -//# sourceMappingURL=buffer.js.map +module.exports = Chalk(); // eslint-disable-line new-cap +module.exports.supportsColor = stdoutColor; +module.exports.default = module.exports; // For TypeScript /***/ }), -/* 409 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* 395 */ +/***/ (function(module, exports, __webpack_require__) { "use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "bufferCount", function() { return bufferCount; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ - - -function bufferCount(bufferSize, startBufferEvery) { - if (startBufferEvery === void 0) { - startBufferEvery = null; - } - return function bufferCountOperatorFunction(source) { - return source.lift(new BufferCountOperator(bufferSize, startBufferEvery)); - }; -} -var BufferCountOperator = /*@__PURE__*/ (function () { - function BufferCountOperator(bufferSize, startBufferEvery) { - this.bufferSize = bufferSize; - this.startBufferEvery = startBufferEvery; - if (!startBufferEvery || bufferSize === startBufferEvery) { - this.subscriberClass = BufferCountSubscriber; - } - else { - this.subscriberClass = BufferSkipCountSubscriber; - } - } - BufferCountOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new this.subscriberClass(subscriber, this.bufferSize, this.startBufferEvery)); - }; - return BufferCountOperator; -}()); -var BufferCountSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](BufferCountSubscriber, _super); - function BufferCountSubscriber(destination, bufferSize) { - var _this = _super.call(this, destination) || this; - _this.bufferSize = bufferSize; - _this.buffer = []; - return _this; - } - BufferCountSubscriber.prototype._next = function (value) { - var buffer = this.buffer; - buffer.push(value); - if (buffer.length == this.bufferSize) { - this.destination.next(buffer); - this.buffer = []; - } - }; - BufferCountSubscriber.prototype._complete = function () { - var buffer = this.buffer; - if (buffer.length > 0) { - this.destination.next(buffer); - } - _super.prototype._complete.call(this); - }; - return BufferCountSubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -var BufferSkipCountSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](BufferSkipCountSubscriber, _super); - function BufferSkipCountSubscriber(destination, bufferSize, startBufferEvery) { - var _this = _super.call(this, destination) || this; - _this.bufferSize = bufferSize; - _this.startBufferEvery = startBufferEvery; - _this.buffers = []; - _this.count = 0; - return _this; - } - BufferSkipCountSubscriber.prototype._next = function (value) { - var _a = this, bufferSize = _a.bufferSize, startBufferEvery = _a.startBufferEvery, buffers = _a.buffers, count = _a.count; - this.count++; - if (count % startBufferEvery === 0) { - buffers.push([]); - } - for (var i = buffers.length; i--;) { - var buffer = buffers[i]; - buffer.push(value); - if (buffer.length === bufferSize) { - buffers.splice(i, 1); - this.destination.next(buffer); - } - } - }; - BufferSkipCountSubscriber.prototype._complete = function () { - var _a = this, buffers = _a.buffers, destination = _a.destination; - while (buffers.length > 0) { - var buffer = buffers.shift(); - if (buffer.length > 0) { - destination.next(buffer); - } - } - _super.prototype._complete.call(this); - }; - return BufferSkipCountSubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=bufferCount.js.map - +/* WEBPACK VAR INJECTION */(function(module) { +const colorConvert = __webpack_require__(180); -/***/ }), -/* 410 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +const wrapAnsi16 = (fn, offset) => function () { + const code = fn.apply(colorConvert, arguments); + return `\u001B[${code + offset}m`; +}; -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "bufferTime", function() { return bufferTime; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(55); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(11); -/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(45); -/** PURE_IMPORTS_START tslib,_scheduler_async,_Subscriber,_util_isScheduler PURE_IMPORTS_END */ +const wrapAnsi256 = (fn, offset) => function () { + const code = fn.apply(colorConvert, arguments); + return `\u001B[${38 + offset};5;${code}m`; +}; +const wrapAnsi16m = (fn, offset) => function () { + const rgb = fn.apply(colorConvert, arguments); + return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}m`; +}; +function assembleStyles() { + const codes = new Map(); + const styles = { + modifier: { + reset: [0, 0], + // 21 isn't widely supported and 22 does the same thing + bold: [1, 22], + dim: [2, 22], + italic: [3, 23], + underline: [4, 24], + inverse: [7, 27], + hidden: [8, 28], + strikethrough: [9, 29] + }, + color: { + black: [30, 39], + red: [31, 39], + green: [32, 39], + yellow: [33, 39], + blue: [34, 39], + magenta: [35, 39], + cyan: [36, 39], + white: [37, 39], + gray: [90, 39], + // Bright color + redBright: [91, 39], + greenBright: [92, 39], + yellowBright: [93, 39], + blueBright: [94, 39], + magentaBright: [95, 39], + cyanBright: [96, 39], + whiteBright: [97, 39] + }, + bgColor: { + bgBlack: [40, 49], + bgRed: [41, 49], + bgGreen: [42, 49], + bgYellow: [43, 49], + bgBlue: [44, 49], + bgMagenta: [45, 49], + bgCyan: [46, 49], + bgWhite: [47, 49], -function bufferTime(bufferTimeSpan) { - var length = arguments.length; - var scheduler = _scheduler_async__WEBPACK_IMPORTED_MODULE_1__["async"]; - if (Object(_util_isScheduler__WEBPACK_IMPORTED_MODULE_3__["isScheduler"])(arguments[arguments.length - 1])) { - scheduler = arguments[arguments.length - 1]; - length--; - } - var bufferCreationInterval = null; - if (length >= 2) { - bufferCreationInterval = arguments[1]; - } - var maxBufferSize = Number.POSITIVE_INFINITY; - if (length >= 3) { - maxBufferSize = arguments[2]; - } - return function bufferTimeOperatorFunction(source) { - return source.lift(new BufferTimeOperator(bufferTimeSpan, bufferCreationInterval, maxBufferSize, scheduler)); - }; -} -var BufferTimeOperator = /*@__PURE__*/ (function () { - function BufferTimeOperator(bufferTimeSpan, bufferCreationInterval, maxBufferSize, scheduler) { - this.bufferTimeSpan = bufferTimeSpan; - this.bufferCreationInterval = bufferCreationInterval; - this.maxBufferSize = maxBufferSize; - this.scheduler = scheduler; - } - BufferTimeOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new BufferTimeSubscriber(subscriber, this.bufferTimeSpan, this.bufferCreationInterval, this.maxBufferSize, this.scheduler)); - }; - return BufferTimeOperator; -}()); -var Context = /*@__PURE__*/ (function () { - function Context() { - this.buffer = []; - } - return Context; -}()); -var BufferTimeSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](BufferTimeSubscriber, _super); - function BufferTimeSubscriber(destination, bufferTimeSpan, bufferCreationInterval, maxBufferSize, scheduler) { - var _this = _super.call(this, destination) || this; - _this.bufferTimeSpan = bufferTimeSpan; - _this.bufferCreationInterval = bufferCreationInterval; - _this.maxBufferSize = maxBufferSize; - _this.scheduler = scheduler; - _this.contexts = []; - var context = _this.openContext(); - _this.timespanOnly = bufferCreationInterval == null || bufferCreationInterval < 0; - if (_this.timespanOnly) { - var timeSpanOnlyState = { subscriber: _this, context: context, bufferTimeSpan: bufferTimeSpan }; - _this.add(context.closeAction = scheduler.schedule(dispatchBufferTimeSpanOnly, bufferTimeSpan, timeSpanOnlyState)); - } - else { - var closeState = { subscriber: _this, context: context }; - var creationState = { bufferTimeSpan: bufferTimeSpan, bufferCreationInterval: bufferCreationInterval, subscriber: _this, scheduler: scheduler }; - _this.add(context.closeAction = scheduler.schedule(dispatchBufferClose, bufferTimeSpan, closeState)); - _this.add(scheduler.schedule(dispatchBufferCreation, bufferCreationInterval, creationState)); - } - return _this; - } - BufferTimeSubscriber.prototype._next = function (value) { - var contexts = this.contexts; - var len = contexts.length; - var filledBufferContext; - for (var i = 0; i < len; i++) { - var context_1 = contexts[i]; - var buffer = context_1.buffer; - buffer.push(value); - if (buffer.length == this.maxBufferSize) { - filledBufferContext = context_1; - } - } - if (filledBufferContext) { - this.onBufferFull(filledBufferContext); - } - }; - BufferTimeSubscriber.prototype._error = function (err) { - this.contexts.length = 0; - _super.prototype._error.call(this, err); - }; - BufferTimeSubscriber.prototype._complete = function () { - var _a = this, contexts = _a.contexts, destination = _a.destination; - while (contexts.length > 0) { - var context_2 = contexts.shift(); - destination.next(context_2.buffer); - } - _super.prototype._complete.call(this); - }; - BufferTimeSubscriber.prototype._unsubscribe = function () { - this.contexts = null; - }; - BufferTimeSubscriber.prototype.onBufferFull = function (context) { - this.closeContext(context); - var closeAction = context.closeAction; - closeAction.unsubscribe(); - this.remove(closeAction); - if (!this.closed && this.timespanOnly) { - context = this.openContext(); - var bufferTimeSpan = this.bufferTimeSpan; - var timeSpanOnlyState = { subscriber: this, context: context, bufferTimeSpan: bufferTimeSpan }; - this.add(context.closeAction = this.scheduler.schedule(dispatchBufferTimeSpanOnly, bufferTimeSpan, timeSpanOnlyState)); - } - }; - BufferTimeSubscriber.prototype.openContext = function () { - var context = new Context(); - this.contexts.push(context); - return context; - }; - BufferTimeSubscriber.prototype.closeContext = function (context) { - this.destination.next(context.buffer); - var contexts = this.contexts; - var spliceIndex = contexts ? contexts.indexOf(context) : -1; - if (spliceIndex >= 0) { - contexts.splice(contexts.indexOf(context), 1); - } - }; - return BufferTimeSubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_2__["Subscriber"])); -function dispatchBufferTimeSpanOnly(state) { - var subscriber = state.subscriber; - var prevContext = state.context; - if (prevContext) { - subscriber.closeContext(prevContext); - } - if (!subscriber.closed) { - state.context = subscriber.openContext(); - state.context.closeAction = this.schedule(state, state.bufferTimeSpan); - } -} -function dispatchBufferCreation(state) { - var bufferCreationInterval = state.bufferCreationInterval, bufferTimeSpan = state.bufferTimeSpan, subscriber = state.subscriber, scheduler = state.scheduler; - var context = subscriber.openContext(); - var action = this; - if (!subscriber.closed) { - subscriber.add(context.closeAction = scheduler.schedule(dispatchBufferClose, bufferTimeSpan, { subscriber: subscriber, context: context })); - action.schedule(state, bufferCreationInterval); - } -} -function dispatchBufferClose(arg) { - var subscriber = arg.subscriber, context = arg.context; - subscriber.closeContext(context); + // Bright color + bgBlackBright: [100, 49], + bgRedBright: [101, 49], + bgGreenBright: [102, 49], + bgYellowBright: [103, 49], + bgBlueBright: [104, 49], + bgMagentaBright: [105, 49], + bgCyanBright: [106, 49], + bgWhiteBright: [107, 49] + } + }; + + // Fix humans + styles.color.grey = styles.color.gray; + + for (const groupName of Object.keys(styles)) { + const group = styles[groupName]; + + for (const styleName of Object.keys(group)) { + const style = group[styleName]; + + styles[styleName] = { + open: `\u001B[${style[0]}m`, + close: `\u001B[${style[1]}m` + }; + + group[styleName] = styles[styleName]; + + codes.set(style[0], style[1]); + } + + Object.defineProperty(styles, groupName, { + value: group, + enumerable: false + }); + + Object.defineProperty(styles, 'codes', { + value: codes, + enumerable: false + }); + } + + const ansi2ansi = n => n; + const rgb2rgb = (r, g, b) => [r, g, b]; + + styles.color.close = '\u001B[39m'; + styles.bgColor.close = '\u001B[49m'; + + styles.color.ansi = { + ansi: wrapAnsi16(ansi2ansi, 0) + }; + styles.color.ansi256 = { + ansi256: wrapAnsi256(ansi2ansi, 0) + }; + styles.color.ansi16m = { + rgb: wrapAnsi16m(rgb2rgb, 0) + }; + + styles.bgColor.ansi = { + ansi: wrapAnsi16(ansi2ansi, 10) + }; + styles.bgColor.ansi256 = { + ansi256: wrapAnsi256(ansi2ansi, 10) + }; + styles.bgColor.ansi16m = { + rgb: wrapAnsi16m(rgb2rgb, 10) + }; + + for (let key of Object.keys(colorConvert)) { + if (typeof colorConvert[key] !== 'object') { + continue; + } + + const suite = colorConvert[key]; + + if (key === 'ansi16') { + key = 'ansi'; + } + + if ('ansi16' in suite) { + styles.color.ansi[key] = wrapAnsi16(suite.ansi16, 0); + styles.bgColor.ansi[key] = wrapAnsi16(suite.ansi16, 10); + } + + if ('ansi256' in suite) { + styles.color.ansi256[key] = wrapAnsi256(suite.ansi256, 0); + styles.bgColor.ansi256[key] = wrapAnsi256(suite.ansi256, 10); + } + + if ('rgb' in suite) { + styles.color.ansi16m[key] = wrapAnsi16m(suite.rgb, 0); + styles.bgColor.ansi16m[key] = wrapAnsi16m(suite.rgb, 10); + } + } + + return styles; } -//# sourceMappingURL=bufferTime.js.map +// Make the export immutable +Object.defineProperty(module, 'exports', { + enumerable: true, + get: assembleStyles +}); + +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(114)(module))) /***/ }), -/* 411 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* 396 */ +/***/ (function(module, exports, __webpack_require__) { "use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "bufferToggle", function() { return bufferToggle; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(17); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(70); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(69); -/** PURE_IMPORTS_START tslib,_Subscription,_util_subscribeToResult,_OuterSubscriber PURE_IMPORTS_END */ +const TEMPLATE_REGEX = /(?:\\(u[a-f\d]{4}|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; +const STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; +const STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/; +const ESCAPE_REGEX = /\\(u[a-f\d]{4}|x[a-f\d]{2}|.)|([^\\])/gi; +const ESCAPES = new Map([ + ['n', '\n'], + ['r', '\r'], + ['t', '\t'], + ['b', '\b'], + ['f', '\f'], + ['v', '\v'], + ['0', '\0'], + ['\\', '\\'], + ['e', '\u001B'], + ['a', '\u0007'] +]); +function unescape(c) { + if ((c[0] === 'u' && c.length === 5) || (c[0] === 'x' && c.length === 3)) { + return String.fromCharCode(parseInt(c.slice(1), 16)); + } -function bufferToggle(openings, closingSelector) { - return function bufferToggleOperatorFunction(source) { - return source.lift(new BufferToggleOperator(openings, closingSelector)); - }; + return ESCAPES.get(c) || c; } -var BufferToggleOperator = /*@__PURE__*/ (function () { - function BufferToggleOperator(openings, closingSelector) { - this.openings = openings; - this.closingSelector = closingSelector; - } - BufferToggleOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new BufferToggleSubscriber(subscriber, this.openings, this.closingSelector)); - }; - return BufferToggleOperator; -}()); -var BufferToggleSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](BufferToggleSubscriber, _super); - function BufferToggleSubscriber(destination, openings, closingSelector) { - var _this = _super.call(this, destination) || this; - _this.openings = openings; - _this.closingSelector = closingSelector; - _this.contexts = []; - _this.add(Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(_this, openings)); - return _this; - } - BufferToggleSubscriber.prototype._next = function (value) { - var contexts = this.contexts; - var len = contexts.length; - for (var i = 0; i < len; i++) { - contexts[i].buffer.push(value); - } - }; - BufferToggleSubscriber.prototype._error = function (err) { - var contexts = this.contexts; - while (contexts.length > 0) { - var context_1 = contexts.shift(); - context_1.subscription.unsubscribe(); - context_1.buffer = null; - context_1.subscription = null; - } - this.contexts = null; - _super.prototype._error.call(this, err); - }; - BufferToggleSubscriber.prototype._complete = function () { - var contexts = this.contexts; - while (contexts.length > 0) { - var context_2 = contexts.shift(); - this.destination.next(context_2.buffer); - context_2.subscription.unsubscribe(); - context_2.buffer = null; - context_2.subscription = null; - } - this.contexts = null; - _super.prototype._complete.call(this); - }; - BufferToggleSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { - outerValue ? this.closeBuffer(outerValue) : this.openBuffer(innerValue); - }; - BufferToggleSubscriber.prototype.notifyComplete = function (innerSub) { - this.closeBuffer(innerSub.context); - }; - BufferToggleSubscriber.prototype.openBuffer = function (value) { - try { - var closingSelector = this.closingSelector; - var closingNotifier = closingSelector.call(this, value); - if (closingNotifier) { - this.trySubscribe(closingNotifier); - } - } - catch (err) { - this._error(err); - } - }; - BufferToggleSubscriber.prototype.closeBuffer = function (context) { - var contexts = this.contexts; - if (contexts && context) { - var buffer = context.buffer, subscription = context.subscription; - this.destination.next(buffer); - contexts.splice(contexts.indexOf(context), 1); - this.remove(subscription); - subscription.unsubscribe(); - } - }; - BufferToggleSubscriber.prototype.trySubscribe = function (closingNotifier) { - var contexts = this.contexts; - var buffer = []; - var subscription = new _Subscription__WEBPACK_IMPORTED_MODULE_1__["Subscription"](); - var context = { buffer: buffer, subscription: subscription }; - contexts.push(context); - var innerSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(this, closingNotifier, context); - if (!innerSubscription || innerSubscription.closed) { - this.closeBuffer(context); - } - else { - innerSubscription.context = context; - this.add(innerSubscription); - subscription.add(innerSubscription); - } - }; - return BufferToggleSubscriber; -}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__["OuterSubscriber"])); -//# sourceMappingURL=bufferToggle.js.map +function parseArguments(name, args) { + const results = []; + const chunks = args.trim().split(/\s*,\s*/g); + let matches; -/***/ }), -/* 412 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + for (const chunk of chunks) { + if (!isNaN(chunk)) { + results.push(Number(chunk)); + } else if ((matches = chunk.match(STRING_REGEX))) { + results.push(matches[2].replace(ESCAPE_REGEX, (m, escape, chr) => escape ? unescape(escape) : chr)); + } else { + throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`); + } + } -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "bufferWhen", function() { return bufferWhen; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(17); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(69); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(70); -/** PURE_IMPORTS_START tslib,_Subscription,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ + return results; +} +function parseStyle(style) { + STYLE_REGEX.lastIndex = 0; + const results = []; + let matches; + while ((matches = STYLE_REGEX.exec(style)) !== null) { + const name = matches[1]; -function bufferWhen(closingSelector) { - return function (source) { - return source.lift(new BufferWhenOperator(closingSelector)); - }; + if (matches[2]) { + const args = parseArguments(name, matches[2]); + results.push([name].concat(args)); + } else { + results.push([name]); + } + } + + return results; } -var BufferWhenOperator = /*@__PURE__*/ (function () { - function BufferWhenOperator(closingSelector) { - this.closingSelector = closingSelector; - } - BufferWhenOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new BufferWhenSubscriber(subscriber, this.closingSelector)); - }; - return BufferWhenOperator; -}()); -var BufferWhenSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](BufferWhenSubscriber, _super); - function BufferWhenSubscriber(destination, closingSelector) { - var _this = _super.call(this, destination) || this; - _this.closingSelector = closingSelector; - _this.subscribing = false; - _this.openBuffer(); - return _this; - } - BufferWhenSubscriber.prototype._next = function (value) { - this.buffer.push(value); - }; - BufferWhenSubscriber.prototype._complete = function () { - var buffer = this.buffer; - if (buffer) { - this.destination.next(buffer); - } - _super.prototype._complete.call(this); - }; - BufferWhenSubscriber.prototype._unsubscribe = function () { - this.buffer = null; - this.subscribing = false; - }; - BufferWhenSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { - this.openBuffer(); - }; - BufferWhenSubscriber.prototype.notifyComplete = function () { - if (this.subscribing) { - this.complete(); - } - else { - this.openBuffer(); - } - }; - BufferWhenSubscriber.prototype.openBuffer = function () { - var closingSubscription = this.closingSubscription; - if (closingSubscription) { - this.remove(closingSubscription); - closingSubscription.unsubscribe(); - } - var buffer = this.buffer; - if (this.buffer) { - this.destination.next(buffer); - } - this.buffer = []; - var closingNotifier; - try { - var closingSelector = this.closingSelector; - closingNotifier = closingSelector(); - } - catch (err) { - return this.error(err); - } - closingSubscription = new _Subscription__WEBPACK_IMPORTED_MODULE_1__["Subscription"](); - this.closingSubscription = closingSubscription; - this.add(closingSubscription); - this.subscribing = true; - closingSubscription.add(Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__["subscribeToResult"])(this, closingNotifier)); - this.subscribing = false; - }; - return BufferWhenSubscriber; -}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__["OuterSubscriber"])); -//# sourceMappingURL=bufferWhen.js.map + +function buildStyle(chalk, styles) { + const enabled = {}; + + for (const layer of styles) { + for (const style of layer.styles) { + enabled[style[0]] = layer.inverse ? null : style.slice(1); + } + } + + let current = chalk; + for (const styleName of Object.keys(enabled)) { + if (Array.isArray(enabled[styleName])) { + if (!(styleName in current)) { + throw new Error(`Unknown Chalk style: ${styleName}`); + } + + if (enabled[styleName].length > 0) { + current = current[styleName].apply(current, enabled[styleName]); + } else { + current = current[styleName]; + } + } + } + + return current; +} + +module.exports = (chalk, tmp) => { + const styles = []; + const chunks = []; + let chunk = []; + + // eslint-disable-next-line max-params + tmp.replace(TEMPLATE_REGEX, (m, escapeChar, inverse, style, close, chr) => { + if (escapeChar) { + chunk.push(unescape(escapeChar)); + } else if (style) { + const str = chunk.join(''); + chunk = []; + chunks.push(styles.length === 0 ? str : buildStyle(chalk, styles)(str)); + styles.push({inverse, styles: parseStyle(style)}); + } else if (close) { + if (styles.length === 0) { + throw new Error('Found extraneous } in Chalk template literal'); + } + + chunks.push(buildStyle(chalk, styles)(chunk.join(''))); + chunk = []; + styles.pop(); + } else { + chunk.push(chr); + } + }); + + chunks.push(chunk.join('')); + + if (styles.length > 0) { + const errMsg = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? '' : 's'} (\`}\`)`; + throw new Error(errMsg); + } + + return chunks.join(''); +}; /***/ }), -/* 413 */ +/* 397 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "catchError", function() { return catchError; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); -/* harmony import */ var _InnerSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(70); -/** PURE_IMPORTS_START tslib,_OuterSubscriber,_InnerSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RunCommand", function() { return RunCommand; }); +/* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(143); +/* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(144); +/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(145); +/* + * 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 catchError(selector) { - return function catchErrorOperatorFunction(source) { - var operator = new CatchOperator(selector); - var caught = source.lift(operator); - return (operator.caught = caught); - }; -} -var CatchOperator = /*@__PURE__*/ (function () { - function CatchOperator(selector) { - this.selector = selector; - } - CatchOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new CatchSubscriber(subscriber, this.selector, this.caught)); - }; - return CatchOperator; -}()); -var CatchSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](CatchSubscriber, _super); - function CatchSubscriber(destination, selector, caught) { - var _this = _super.call(this, destination) || this; - _this.selector = selector; - _this.caught = caught; - return _this; +const RunCommand = { + description: 'Run script defined in package.json in each package that contains that script.', + name: 'run', + + async run(projects, projectGraph, { + extraArgs + }) { + const batchedProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_3__["topologicallyBatchProjects"])(projects, projectGraph); + + if (extraArgs.length === 0) { + throw new _utils_errors__WEBPACK_IMPORTED_MODULE_0__["CliError"]('No script specified'); } - CatchSubscriber.prototype.error = function (err) { - if (!this.isStopped) { - var result = void 0; - try { - result = this.selector(err, this.caught); - } - catch (err2) { - _super.prototype.error.call(this, err2); - return; - } - this._unsubscribeAndRecycle(); - var innerSubscriber = new _InnerSubscriber__WEBPACK_IMPORTED_MODULE_2__["InnerSubscriber"](this, undefined, undefined); - this.add(innerSubscriber); - var innerSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__["subscribeToResult"])(this, result, undefined, undefined, innerSubscriber); - if (innerSubscription !== innerSubscriber) { - this.add(innerSubscription); - } - } - }; - return CatchSubscriber; -}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); -//# sourceMappingURL=catchError.js.map + const scriptName = extraArgs[0]; + const scriptArgs = extraArgs.slice(1); + await Object(_utils_parallelize__WEBPACK_IMPORTED_MODULE_2__["parallelizeBatches"])(batchedProjects, async project => { + if (project.hasScript(scriptName)) { + _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].info(`[${project.name}] running "${scriptName}" script`); + await project.runScriptStreaming(scriptName, { + args: scriptArgs + }); + _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].success(`[${project.name}] complete`); + } + }); + } + +}; /***/ }), -/* 414 */ +/* 398 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "combineAll", function() { return combineAll; }); -/* harmony import */ var _observable_combineLatest__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(68); -/** PURE_IMPORTS_START _observable_combineLatest PURE_IMPORTS_END */ +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "WatchCommand", function() { return WatchCommand; }); +/* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(143); +/* harmony import */ var _utils_parallelize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(144); +/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(145); +/* harmony import */ var _utils_watch__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(399); +/* + * 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 combineAll(project) { - return function (source) { return source.lift(new _observable_combineLatest__WEBPACK_IMPORTED_MODULE_0__["CombineLatestOperator"](project)); }; -} -//# sourceMappingURL=combineAll.js.map -/***/ }), -/* 415 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "combineLatest", function() { return combineLatest; }); -/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(18); -/* harmony import */ var _observable_combineLatest__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(68); -/* harmony import */ var _observable_from__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(83); -/** PURE_IMPORTS_START _util_isArray,_observable_combineLatest,_observable_from PURE_IMPORTS_END */ +/** + * Name of the script in the package/project package.json file to run during `kbn watch`. + */ +const watchScriptName = 'kbn:watch'; +/** + * Name of the Kibana project. + */ -var none = {}; -function combineLatest() { - var observables = []; - for (var _i = 0; _i < arguments.length; _i++) { - observables[_i] = arguments[_i]; +const kibanaProjectName = 'kibana'; +/** + * Command that traverses through list of available projects/packages that have `kbn:watch` script in their + * package.json files, groups them into topology aware batches and then processes theses batches one by one + * running `kbn:watch` scripts in parallel within the same batch. + * + * Command internally relies on the fact that most of the build systems that are triggered by `kbn:watch` + * will emit special "marker" once build/watch process is ready that we can use as completion condition for + * the `kbn:watch` script and eventually for the entire batch. Currently we support completion "markers" for + * `webpack` and `tsc` only, for the rest we rely on predefined timeouts. + */ + +const WatchCommand = { + description: 'Runs `kbn:watch` script for every project.', + name: 'watch', + + async run(projects, projectGraph) { + const projectsToWatch = new Map(); + + for (const project of projects.values()) { + // We can't watch project that doesn't have `kbn:watch` script. + if (project.hasScript(watchScriptName)) { + projectsToWatch.set(project.name, project); + } } - var project = null; - if (typeof observables[observables.length - 1] === 'function') { - project = observables.pop(); + + if (projectsToWatch.size === 0) { + throw new _utils_errors__WEBPACK_IMPORTED_MODULE_0__["CliError"](`There are no projects to watch found. Make sure that projects define 'kbn:watch' script in 'package.json'.`); } - if (observables.length === 1 && Object(_util_isArray__WEBPACK_IMPORTED_MODULE_0__["isArray"])(observables[0])) { - observables = observables[0].slice(); + + const projectNames = Array.from(projectsToWatch.keys()); + _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].info(`Running ${watchScriptName} scripts for [${projectNames.join(', ')}].`); // Kibana should always be run the last, so we don't rely on automatic + // topological batching and push it to the last one-entry batch manually. + + const shouldWatchKibanaProject = projectsToWatch.delete(kibanaProjectName); + const batchedProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_3__["topologicallyBatchProjects"])(projectsToWatch, projectGraph); + + if (shouldWatchKibanaProject) { + batchedProjects.push([projects.get(kibanaProjectName)]); } - return function (source) { return source.lift.call(Object(_observable_from__WEBPACK_IMPORTED_MODULE_2__["from"])([source].concat(observables)), new _observable_combineLatest__WEBPACK_IMPORTED_MODULE_1__["CombineLatestOperator"](project)); }; -} -//# sourceMappingURL=combineLatest.js.map + await Object(_utils_parallelize__WEBPACK_IMPORTED_MODULE_2__["parallelizeBatches"])(batchedProjects, async pkg => { + const completionHint = await Object(_utils_watch__WEBPACK_IMPORTED_MODULE_4__["waitUntilWatchIsReady"])(pkg.runScriptStreaming(watchScriptName, { + debug: false + }).stdout); + _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].success(`[${pkg.name}] Initial build completed (${completionHint}).`); + }); + } + +}; /***/ }), -/* 416 */ +/* 399 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "concat", function() { return concat; }); -/* harmony import */ var _observable_concat__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(79); -/** PURE_IMPORTS_START _observable_concat PURE_IMPORTS_END */ +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "waitUntilWatchIsReady", function() { return waitUntilWatchIsReady; }); +/* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(8); +/* harmony import */ var rxjs_operators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(400); +/* + * 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 concat() { - var observables = []; - for (var _i = 0; _i < arguments.length; _i++) { - observables[_i] = arguments[_i]; - } - return function (source) { return source.lift.call(_observable_concat__WEBPACK_IMPORTED_MODULE_0__["concat"].apply(void 0, [source].concat(observables))); }; -} -//# sourceMappingURL=concat.js.map +/** + * Number of milliseconds we wait before we fall back to the default watch handler. + */ -/***/ }), -/* 417 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +const defaultHandlerDelay = 3000; +/** + * If default watch handler is used, then it's the number of milliseconds we wait for + * any build output before we consider watch task ready. + */ -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "concatMap", function() { return concatMap; }); -/* harmony import */ var _mergeMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(82); -/** PURE_IMPORTS_START _mergeMap PURE_IMPORTS_END */ +const defaultHandlerReadinessTimeout = 2000; +/** + * Describes configurable watch options. + */ -function concatMap(project, resultSelector) { - return Object(_mergeMap__WEBPACK_IMPORTED_MODULE_0__["mergeMap"])(project, resultSelector, 1); +function getWatchHandlers(buildOutput$, { + handlerDelay = defaultHandlerDelay, + handlerReadinessTimeout = defaultHandlerReadinessTimeout +}) { + const typescriptHandler = buildOutput$.pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["first"])(data => data.includes('$ tsc')), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["map"])(() => buildOutput$.pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["first"])(data => data.includes('Compilation complete.')), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["mapTo"])('tsc')))); + const webpackHandler = buildOutput$.pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["first"])(data => data.includes('$ webpack')), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["map"])(() => buildOutput$.pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["first"])(data => data.includes('Chunk Names')), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["mapTo"])('webpack')))); + const defaultHandler = rxjs__WEBPACK_IMPORTED_MODULE_0__["of"](undefined).pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["delay"])(handlerReadinessTimeout), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["map"])(() => buildOutput$.pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["timeout"])(handlerDelay), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["catchError"])(() => rxjs__WEBPACK_IMPORTED_MODULE_0__["of"]('timeout'))))); + return [typescriptHandler, webpackHandler, defaultHandler]; } -//# sourceMappingURL=concatMap.js.map +function waitUntilWatchIsReady(stream, opts = {}) { + const buildOutput$ = new rxjs__WEBPACK_IMPORTED_MODULE_0__["Subject"](); -/***/ }), -/* 418 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + const onDataListener = data => buildOutput$.next(data.toString('utf-8')); -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "concatMapTo", function() { return concatMapTo; }); -/* harmony import */ var _concatMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(417); -/** PURE_IMPORTS_START _concatMap PURE_IMPORTS_END */ + const onEndListener = () => buildOutput$.complete(); -function concatMapTo(innerObservable, resultSelector) { - return Object(_concatMap__WEBPACK_IMPORTED_MODULE_0__["concatMap"])(function () { return innerObservable; }, resultSelector); -} -//# sourceMappingURL=concatMapTo.js.map + const onErrorListener = e => buildOutput$.error(e); + stream.once('end', onEndListener); + stream.once('error', onErrorListener); + stream.on('data', onDataListener); + return rxjs__WEBPACK_IMPORTED_MODULE_0__["race"](getWatchHandlers(buildOutput$, opts)).pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["mergeMap"])(whenReady => whenReady), Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__["finalize"])(() => { + stream.removeListener('data', onDataListener); + stream.removeListener('end', onEndListener); + stream.removeListener('error', onErrorListener); + buildOutput$.complete(); + })).toPromise(); +} /***/ }), -/* 419 */ +/* 400 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "count", function() { return count; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ +/* harmony import */ var _internal_operators_audit__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(401); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "audit", function() { return _internal_operators_audit__WEBPACK_IMPORTED_MODULE_0__["audit"]; }); +/* harmony import */ var _internal_operators_auditTime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(402); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "auditTime", function() { return _internal_operators_auditTime__WEBPACK_IMPORTED_MODULE_1__["auditTime"]; }); -function count(predicate) { - return function (source) { return source.lift(new CountOperator(predicate, source)); }; -} -var CountOperator = /*@__PURE__*/ (function () { - function CountOperator(predicate, source) { - this.predicate = predicate; - this.source = source; - } - CountOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new CountSubscriber(subscriber, this.predicate, this.source)); - }; - return CountOperator; -}()); -var CountSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](CountSubscriber, _super); - function CountSubscriber(destination, predicate, source) { - var _this = _super.call(this, destination) || this; - _this.predicate = predicate; - _this.source = source; - _this.count = 0; - _this.index = 0; - return _this; - } - CountSubscriber.prototype._next = function (value) { - if (this.predicate) { - this._tryPredicate(value); - } - else { - this.count++; - } - }; - CountSubscriber.prototype._tryPredicate = function (value) { - var result; - try { - result = this.predicate(value, this.index++, this.source); - } - catch (err) { - this.destination.error(err); - return; - } - if (result) { - this.count++; - } - }; - CountSubscriber.prototype._complete = function () { - this.destination.next(this.count); - this.destination.complete(); - }; - return CountSubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=count.js.map +/* harmony import */ var _internal_operators_buffer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(403); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buffer", function() { return _internal_operators_buffer__WEBPACK_IMPORTED_MODULE_2__["buffer"]; }); +/* harmony import */ var _internal_operators_bufferCount__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(404); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferCount", function() { return _internal_operators_bufferCount__WEBPACK_IMPORTED_MODULE_3__["bufferCount"]; }); -/***/ }), -/* 420 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* harmony import */ var _internal_operators_bufferTime__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(405); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferTime", function() { return _internal_operators_bufferTime__WEBPACK_IMPORTED_MODULE_4__["bufferTime"]; }); -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "debounce", function() { return debounce; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(70); -/** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ +/* harmony import */ var _internal_operators_bufferToggle__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(406); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferToggle", function() { return _internal_operators_bufferToggle__WEBPACK_IMPORTED_MODULE_5__["bufferToggle"]; }); +/* harmony import */ var _internal_operators_bufferWhen__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(407); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "bufferWhen", function() { return _internal_operators_bufferWhen__WEBPACK_IMPORTED_MODULE_6__["bufferWhen"]; }); +/* harmony import */ var _internal_operators_catchError__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(408); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "catchError", function() { return _internal_operators_catchError__WEBPACK_IMPORTED_MODULE_7__["catchError"]; }); -function debounce(durationSelector) { - return function (source) { return source.lift(new DebounceOperator(durationSelector)); }; -} -var DebounceOperator = /*@__PURE__*/ (function () { - function DebounceOperator(durationSelector) { - this.durationSelector = durationSelector; - } - DebounceOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new DebounceSubscriber(subscriber, this.durationSelector)); - }; - return DebounceOperator; -}()); -var DebounceSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](DebounceSubscriber, _super); - function DebounceSubscriber(destination, durationSelector) { - var _this = _super.call(this, destination) || this; - _this.durationSelector = durationSelector; - _this.hasValue = false; - _this.durationSubscription = null; - return _this; - } - DebounceSubscriber.prototype._next = function (value) { - try { - var result = this.durationSelector.call(this, value); - if (result) { - this._tryNext(value, result); - } - } - catch (err) { - this.destination.error(err); - } - }; - DebounceSubscriber.prototype._complete = function () { - this.emitValue(); - this.destination.complete(); - }; - DebounceSubscriber.prototype._tryNext = function (value, duration) { - var subscription = this.durationSubscription; - this.value = value; - this.hasValue = true; - if (subscription) { - subscription.unsubscribe(); - this.remove(subscription); - } - subscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(this, duration); - if (subscription && !subscription.closed) { - this.add(this.durationSubscription = subscription); - } - }; - DebounceSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { - this.emitValue(); - }; - DebounceSubscriber.prototype.notifyComplete = function () { - this.emitValue(); - }; - DebounceSubscriber.prototype.emitValue = function () { - if (this.hasValue) { - var value = this.value; - var subscription = this.durationSubscription; - if (subscription) { - this.durationSubscription = null; - subscription.unsubscribe(); - this.remove(subscription); - } - this.value = null; - this.hasValue = false; - _super.prototype._next.call(this, value); - } - }; - return DebounceSubscriber; -}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); -//# sourceMappingURL=debounce.js.map +/* harmony import */ var _internal_operators_combineAll__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(409); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "combineAll", function() { return _internal_operators_combineAll__WEBPACK_IMPORTED_MODULE_8__["combineAll"]; }); +/* harmony import */ var _internal_operators_combineLatest__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(410); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "combineLatest", function() { return _internal_operators_combineLatest__WEBPACK_IMPORTED_MODULE_9__["combineLatest"]; }); -/***/ }), -/* 421 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* harmony import */ var _internal_operators_concat__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(411); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concat", function() { return _internal_operators_concat__WEBPACK_IMPORTED_MODULE_10__["concat"]; }); -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "debounceTime", function() { return debounceTime; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(55); -/** PURE_IMPORTS_START tslib,_Subscriber,_scheduler_async PURE_IMPORTS_END */ +/* harmony import */ var _internal_operators_concatAll__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(80); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concatAll", function() { return _internal_operators_concatAll__WEBPACK_IMPORTED_MODULE_11__["concatAll"]; }); +/* harmony import */ var _internal_operators_concatMap__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(412); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concatMap", function() { return _internal_operators_concatMap__WEBPACK_IMPORTED_MODULE_12__["concatMap"]; }); +/* harmony import */ var _internal_operators_concatMapTo__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(413); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "concatMapTo", function() { return _internal_operators_concatMapTo__WEBPACK_IMPORTED_MODULE_13__["concatMapTo"]; }); -function debounceTime(dueTime, scheduler) { - if (scheduler === void 0) { - scheduler = _scheduler_async__WEBPACK_IMPORTED_MODULE_2__["async"]; - } - return function (source) { return source.lift(new DebounceTimeOperator(dueTime, scheduler)); }; -} -var DebounceTimeOperator = /*@__PURE__*/ (function () { - function DebounceTimeOperator(dueTime, scheduler) { - this.dueTime = dueTime; - this.scheduler = scheduler; - } - DebounceTimeOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new DebounceTimeSubscriber(subscriber, this.dueTime, this.scheduler)); - }; - return DebounceTimeOperator; -}()); -var DebounceTimeSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](DebounceTimeSubscriber, _super); - function DebounceTimeSubscriber(destination, dueTime, scheduler) { - var _this = _super.call(this, destination) || this; - _this.dueTime = dueTime; - _this.scheduler = scheduler; - _this.debouncedSubscription = null; - _this.lastValue = null; - _this.hasValue = false; - return _this; - } - DebounceTimeSubscriber.prototype._next = function (value) { - this.clearDebounce(); - this.lastValue = value; - this.hasValue = true; - this.add(this.debouncedSubscription = this.scheduler.schedule(dispatchNext, this.dueTime, this)); - }; - DebounceTimeSubscriber.prototype._complete = function () { - this.debouncedNext(); - this.destination.complete(); - }; - DebounceTimeSubscriber.prototype.debouncedNext = function () { - this.clearDebounce(); - if (this.hasValue) { - var lastValue = this.lastValue; - this.lastValue = null; - this.hasValue = false; - this.destination.next(lastValue); - } - }; - DebounceTimeSubscriber.prototype.clearDebounce = function () { - var debouncedSubscription = this.debouncedSubscription; - if (debouncedSubscription !== null) { - this.remove(debouncedSubscription); - debouncedSubscription.unsubscribe(); - this.debouncedSubscription = null; - } - }; - return DebounceTimeSubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -function dispatchNext(subscriber) { - subscriber.debouncedNext(); -} -//# sourceMappingURL=debounceTime.js.map +/* harmony import */ var _internal_operators_count__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(414); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "count", function() { return _internal_operators_count__WEBPACK_IMPORTED_MODULE_14__["count"]; }); +/* harmony import */ var _internal_operators_debounce__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(415); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "debounce", function() { return _internal_operators_debounce__WEBPACK_IMPORTED_MODULE_15__["debounce"]; }); -/***/ }), -/* 422 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* harmony import */ var _internal_operators_debounceTime__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(416); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "debounceTime", function() { return _internal_operators_debounceTime__WEBPACK_IMPORTED_MODULE_16__["debounceTime"]; }); -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "defaultIfEmpty", function() { return defaultIfEmpty; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ +/* harmony import */ var _internal_operators_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(417); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "defaultIfEmpty", function() { return _internal_operators_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_17__["defaultIfEmpty"]; }); +/* harmony import */ var _internal_operators_delay__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(418); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "delay", function() { return _internal_operators_delay__WEBPACK_IMPORTED_MODULE_18__["delay"]; }); -function defaultIfEmpty(defaultValue) { - if (defaultValue === void 0) { - defaultValue = null; - } - return function (source) { return source.lift(new DefaultIfEmptyOperator(defaultValue)); }; -} -var DefaultIfEmptyOperator = /*@__PURE__*/ (function () { - function DefaultIfEmptyOperator(defaultValue) { - this.defaultValue = defaultValue; - } - DefaultIfEmptyOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new DefaultIfEmptySubscriber(subscriber, this.defaultValue)); - }; - return DefaultIfEmptyOperator; -}()); -var DefaultIfEmptySubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](DefaultIfEmptySubscriber, _super); - function DefaultIfEmptySubscriber(destination, defaultValue) { - var _this = _super.call(this, destination) || this; - _this.defaultValue = defaultValue; - _this.isEmpty = true; - return _this; - } - DefaultIfEmptySubscriber.prototype._next = function (value) { - this.isEmpty = false; - this.destination.next(value); - }; - DefaultIfEmptySubscriber.prototype._complete = function () { - if (this.isEmpty) { - this.destination.next(this.defaultValue); - } - this.destination.complete(); - }; - return DefaultIfEmptySubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=defaultIfEmpty.js.map +/* harmony import */ var _internal_operators_delayWhen__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(420); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "delayWhen", function() { return _internal_operators_delayWhen__WEBPACK_IMPORTED_MODULE_19__["delayWhen"]; }); +/* harmony import */ var _internal_operators_dematerialize__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(421); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "dematerialize", function() { return _internal_operators_dematerialize__WEBPACK_IMPORTED_MODULE_20__["dematerialize"]; }); -/***/ }), -/* 423 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* harmony import */ var _internal_operators_distinct__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(422); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "distinct", function() { return _internal_operators_distinct__WEBPACK_IMPORTED_MODULE_21__["distinct"]; }); + +/* harmony import */ var _internal_operators_distinctUntilChanged__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(423); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "distinctUntilChanged", function() { return _internal_operators_distinctUntilChanged__WEBPACK_IMPORTED_MODULE_22__["distinctUntilChanged"]; }); + +/* harmony import */ var _internal_operators_distinctUntilKeyChanged__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(424); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "distinctUntilKeyChanged", function() { return _internal_operators_distinctUntilKeyChanged__WEBPACK_IMPORTED_MODULE_23__["distinctUntilKeyChanged"]; }); + +/* harmony import */ var _internal_operators_elementAt__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(425); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "elementAt", function() { return _internal_operators_elementAt__WEBPACK_IMPORTED_MODULE_24__["elementAt"]; }); + +/* harmony import */ var _internal_operators_endWith__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(428); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "endWith", function() { return _internal_operators_endWith__WEBPACK_IMPORTED_MODULE_25__["endWith"]; }); + +/* harmony import */ var _internal_operators_every__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(429); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "every", function() { return _internal_operators_every__WEBPACK_IMPORTED_MODULE_26__["every"]; }); + +/* harmony import */ var _internal_operators_exhaust__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(430); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "exhaust", function() { return _internal_operators_exhaust__WEBPACK_IMPORTED_MODULE_27__["exhaust"]; }); + +/* harmony import */ var _internal_operators_exhaustMap__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(431); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "exhaustMap", function() { return _internal_operators_exhaustMap__WEBPACK_IMPORTED_MODULE_28__["exhaustMap"]; }); + +/* harmony import */ var _internal_operators_expand__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(432); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "expand", function() { return _internal_operators_expand__WEBPACK_IMPORTED_MODULE_29__["expand"]; }); + +/* harmony import */ var _internal_operators_filter__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(104); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "filter", function() { return _internal_operators_filter__WEBPACK_IMPORTED_MODULE_30__["filter"]; }); + +/* harmony import */ var _internal_operators_finalize__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(433); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "finalize", function() { return _internal_operators_finalize__WEBPACK_IMPORTED_MODULE_31__["finalize"]; }); + +/* harmony import */ var _internal_operators_find__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(434); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "find", function() { return _internal_operators_find__WEBPACK_IMPORTED_MODULE_32__["find"]; }); + +/* harmony import */ var _internal_operators_findIndex__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(435); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "findIndex", function() { return _internal_operators_findIndex__WEBPACK_IMPORTED_MODULE_33__["findIndex"]; }); + +/* harmony import */ var _internal_operators_first__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(436); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "first", function() { return _internal_operators_first__WEBPACK_IMPORTED_MODULE_34__["first"]; }); + +/* harmony import */ var _internal_operators_groupBy__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(31); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "groupBy", function() { return _internal_operators_groupBy__WEBPACK_IMPORTED_MODULE_35__["groupBy"]; }); -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "delay", function() { return delay; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(55); -/* harmony import */ var _util_isDate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(424); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(11); -/* harmony import */ var _Notification__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(42); -/** PURE_IMPORTS_START tslib,_scheduler_async,_util_isDate,_Subscriber,_Notification PURE_IMPORTS_END */ +/* harmony import */ var _internal_operators_ignoreElements__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(437); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ignoreElements", function() { return _internal_operators_ignoreElements__WEBPACK_IMPORTED_MODULE_36__["ignoreElements"]; }); +/* harmony import */ var _internal_operators_isEmpty__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(438); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "isEmpty", function() { return _internal_operators_isEmpty__WEBPACK_IMPORTED_MODULE_37__["isEmpty"]; }); +/* harmony import */ var _internal_operators_last__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(439); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "last", function() { return _internal_operators_last__WEBPACK_IMPORTED_MODULE_38__["last"]; }); +/* harmony import */ var _internal_operators_map__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(66); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "map", function() { return _internal_operators_map__WEBPACK_IMPORTED_MODULE_39__["map"]; }); +/* harmony import */ var _internal_operators_mapTo__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(441); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mapTo", function() { return _internal_operators_mapTo__WEBPACK_IMPORTED_MODULE_40__["mapTo"]; }); -function delay(delay, scheduler) { - if (scheduler === void 0) { - scheduler = _scheduler_async__WEBPACK_IMPORTED_MODULE_1__["async"]; - } - var absoluteDelay = Object(_util_isDate__WEBPACK_IMPORTED_MODULE_2__["isDate"])(delay); - var delayFor = absoluteDelay ? (+delay - scheduler.now()) : Math.abs(delay); - return function (source) { return source.lift(new DelayOperator(delayFor, scheduler)); }; -} -var DelayOperator = /*@__PURE__*/ (function () { - function DelayOperator(delay, scheduler) { - this.delay = delay; - this.scheduler = scheduler; - } - DelayOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new DelaySubscriber(subscriber, this.delay, this.scheduler)); - }; - return DelayOperator; -}()); -var DelaySubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](DelaySubscriber, _super); - function DelaySubscriber(destination, delay, scheduler) { - var _this = _super.call(this, destination) || this; - _this.delay = delay; - _this.scheduler = scheduler; - _this.queue = []; - _this.active = false; - _this.errored = false; - return _this; - } - DelaySubscriber.dispatch = function (state) { - var source = state.source; - var queue = source.queue; - var scheduler = state.scheduler; - var destination = state.destination; - while (queue.length > 0 && (queue[0].time - scheduler.now()) <= 0) { - queue.shift().notification.observe(destination); - } - if (queue.length > 0) { - var delay_1 = Math.max(0, queue[0].time - scheduler.now()); - this.schedule(state, delay_1); - } - else { - this.unsubscribe(); - source.active = false; - } - }; - DelaySubscriber.prototype._schedule = function (scheduler) { - this.active = true; - var destination = this.destination; - destination.add(scheduler.schedule(DelaySubscriber.dispatch, this.delay, { - source: this, destination: this.destination, scheduler: scheduler - })); - }; - DelaySubscriber.prototype.scheduleNotification = function (notification) { - if (this.errored === true) { - return; - } - var scheduler = this.scheduler; - var message = new DelayMessage(scheduler.now() + this.delay, notification); - this.queue.push(message); - if (this.active === false) { - this._schedule(scheduler); - } - }; - DelaySubscriber.prototype._next = function (value) { - this.scheduleNotification(_Notification__WEBPACK_IMPORTED_MODULE_4__["Notification"].createNext(value)); - }; - DelaySubscriber.prototype._error = function (err) { - this.errored = true; - this.queue = []; - this.destination.error(err); - this.unsubscribe(); - }; - DelaySubscriber.prototype._complete = function () { - this.scheduleNotification(_Notification__WEBPACK_IMPORTED_MODULE_4__["Notification"].createComplete()); - this.unsubscribe(); - }; - return DelaySubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_3__["Subscriber"])); -var DelayMessage = /*@__PURE__*/ (function () { - function DelayMessage(time, notification) { - this.time = time; - this.notification = notification; - } - return DelayMessage; -}()); -//# sourceMappingURL=delay.js.map +/* harmony import */ var _internal_operators_materialize__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(442); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "materialize", function() { return _internal_operators_materialize__WEBPACK_IMPORTED_MODULE_41__["materialize"]; }); +/* harmony import */ var _internal_operators_max__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(443); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "max", function() { return _internal_operators_max__WEBPACK_IMPORTED_MODULE_42__["max"]; }); -/***/ }), -/* 424 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* harmony import */ var _internal_operators_merge__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(446); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "merge", function() { return _internal_operators_merge__WEBPACK_IMPORTED_MODULE_43__["merge"]; }); -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isDate", function() { return isDate; }); -/** PURE_IMPORTS_START PURE_IMPORTS_END */ -function isDate(value) { - return value instanceof Date && !isNaN(+value); -} -//# sourceMappingURL=isDate.js.map +/* harmony import */ var _internal_operators_mergeAll__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(81); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mergeAll", function() { return _internal_operators_mergeAll__WEBPACK_IMPORTED_MODULE_44__["mergeAll"]; }); +/* harmony import */ var _internal_operators_mergeMap__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(82); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mergeMap", function() { return _internal_operators_mergeMap__WEBPACK_IMPORTED_MODULE_45__["mergeMap"]; }); -/***/ }), -/* 425 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "flatMap", function() { return _internal_operators_mergeMap__WEBPACK_IMPORTED_MODULE_45__["mergeMap"]; }); -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "delayWhen", function() { return delayWhen; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(9); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(69); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(70); -/** PURE_IMPORTS_START tslib,_Subscriber,_Observable,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ +/* harmony import */ var _internal_operators_mergeMapTo__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(447); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mergeMapTo", function() { return _internal_operators_mergeMapTo__WEBPACK_IMPORTED_MODULE_46__["mergeMapTo"]; }); +/* harmony import */ var _internal_operators_mergeScan__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(448); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "mergeScan", function() { return _internal_operators_mergeScan__WEBPACK_IMPORTED_MODULE_47__["mergeScan"]; }); +/* harmony import */ var _internal_operators_min__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(449); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "min", function() { return _internal_operators_min__WEBPACK_IMPORTED_MODULE_48__["min"]; }); +/* harmony import */ var _internal_operators_multicast__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(450); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "multicast", function() { return _internal_operators_multicast__WEBPACK_IMPORTED_MODULE_49__["multicast"]; }); +/* harmony import */ var _internal_operators_observeOn__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(41); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "observeOn", function() { return _internal_operators_observeOn__WEBPACK_IMPORTED_MODULE_50__["observeOn"]; }); -function delayWhen(delayDurationSelector, subscriptionDelay) { - if (subscriptionDelay) { - return function (source) { - return new SubscriptionDelayObservable(source, subscriptionDelay) - .lift(new DelayWhenOperator(delayDurationSelector)); - }; - } - return function (source) { return source.lift(new DelayWhenOperator(delayDurationSelector)); }; -} -var DelayWhenOperator = /*@__PURE__*/ (function () { - function DelayWhenOperator(delayDurationSelector) { - this.delayDurationSelector = delayDurationSelector; - } - DelayWhenOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new DelayWhenSubscriber(subscriber, this.delayDurationSelector)); - }; - return DelayWhenOperator; -}()); -var DelayWhenSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](DelayWhenSubscriber, _super); - function DelayWhenSubscriber(destination, delayDurationSelector) { - var _this = _super.call(this, destination) || this; - _this.delayDurationSelector = delayDurationSelector; - _this.completed = false; - _this.delayNotifierSubscriptions = []; - _this.index = 0; - return _this; - } - DelayWhenSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { - this.destination.next(outerValue); - this.removeSubscription(innerSub); - this.tryComplete(); - }; - DelayWhenSubscriber.prototype.notifyError = function (error, innerSub) { - this._error(error); - }; - DelayWhenSubscriber.prototype.notifyComplete = function (innerSub) { - var value = this.removeSubscription(innerSub); - if (value) { - this.destination.next(value); - } - this.tryComplete(); - }; - DelayWhenSubscriber.prototype._next = function (value) { - var index = this.index++; - try { - var delayNotifier = this.delayDurationSelector(value, index); - if (delayNotifier) { - this.tryDelay(delayNotifier, value); - } - } - catch (err) { - this.destination.error(err); - } - }; - DelayWhenSubscriber.prototype._complete = function () { - this.completed = true; - this.tryComplete(); - this.unsubscribe(); - }; - DelayWhenSubscriber.prototype.removeSubscription = function (subscription) { - subscription.unsubscribe(); - var subscriptionIdx = this.delayNotifierSubscriptions.indexOf(subscription); - if (subscriptionIdx !== -1) { - this.delayNotifierSubscriptions.splice(subscriptionIdx, 1); - } - return subscription.outerValue; - }; - DelayWhenSubscriber.prototype.tryDelay = function (delayNotifier, value) { - var notifierSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__["subscribeToResult"])(this, delayNotifier, value); - if (notifierSubscription && !notifierSubscription.closed) { - var destination = this.destination; - destination.add(notifierSubscription); - this.delayNotifierSubscriptions.push(notifierSubscription); - } - }; - DelayWhenSubscriber.prototype.tryComplete = function () { - if (this.completed && this.delayNotifierSubscriptions.length === 0) { - this.destination.complete(); - } - }; - return DelayWhenSubscriber; -}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__["OuterSubscriber"])); -var SubscriptionDelayObservable = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SubscriptionDelayObservable, _super); - function SubscriptionDelayObservable(source, subscriptionDelay) { - var _this = _super.call(this) || this; - _this.source = source; - _this.subscriptionDelay = subscriptionDelay; - return _this; - } - SubscriptionDelayObservable.prototype._subscribe = function (subscriber) { - this.subscriptionDelay.subscribe(new SubscriptionDelaySubscriber(subscriber, this.source)); - }; - return SubscriptionDelayObservable; -}(_Observable__WEBPACK_IMPORTED_MODULE_2__["Observable"])); -var SubscriptionDelaySubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SubscriptionDelaySubscriber, _super); - function SubscriptionDelaySubscriber(parent, source) { - var _this = _super.call(this) || this; - _this.parent = parent; - _this.source = source; - _this.sourceSubscribed = false; - return _this; - } - SubscriptionDelaySubscriber.prototype._next = function (unused) { - this.subscribeToSource(); - }; - SubscriptionDelaySubscriber.prototype._error = function (err) { - this.unsubscribe(); - this.parent.error(err); - }; - SubscriptionDelaySubscriber.prototype._complete = function () { - this.unsubscribe(); - this.subscribeToSource(); - }; - SubscriptionDelaySubscriber.prototype.subscribeToSource = function () { - if (!this.sourceSubscribed) { - this.sourceSubscribed = true; - this.unsubscribe(); - this.source.subscribe(this.parent); - } - }; - return SubscriptionDelaySubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=delayWhen.js.map +/* harmony import */ var _internal_operators_onErrorResumeNext__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(451); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "onErrorResumeNext", function() { return _internal_operators_onErrorResumeNext__WEBPACK_IMPORTED_MODULE_51__["onErrorResumeNext"]; }); +/* harmony import */ var _internal_operators_pairwise__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(452); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "pairwise", function() { return _internal_operators_pairwise__WEBPACK_IMPORTED_MODULE_52__["pairwise"]; }); -/***/ }), -/* 426 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* harmony import */ var _internal_operators_partition__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(453); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "partition", function() { return _internal_operators_partition__WEBPACK_IMPORTED_MODULE_53__["partition"]; }); -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "dematerialize", function() { return dematerialize; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ +/* harmony import */ var _internal_operators_pluck__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(454); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "pluck", function() { return _internal_operators_pluck__WEBPACK_IMPORTED_MODULE_54__["pluck"]; }); +/* harmony import */ var _internal_operators_publish__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(455); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publish", function() { return _internal_operators_publish__WEBPACK_IMPORTED_MODULE_55__["publish"]; }); -function dematerialize() { - return function dematerializeOperatorFunction(source) { - return source.lift(new DeMaterializeOperator()); - }; -} -var DeMaterializeOperator = /*@__PURE__*/ (function () { - function DeMaterializeOperator() { - } - DeMaterializeOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new DeMaterializeSubscriber(subscriber)); - }; - return DeMaterializeOperator; -}()); -var DeMaterializeSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](DeMaterializeSubscriber, _super); - function DeMaterializeSubscriber(destination) { - return _super.call(this, destination) || this; - } - DeMaterializeSubscriber.prototype._next = function (value) { - value.observe(this.destination); - }; - return DeMaterializeSubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=dematerialize.js.map +/* harmony import */ var _internal_operators_publishBehavior__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(456); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publishBehavior", function() { return _internal_operators_publishBehavior__WEBPACK_IMPORTED_MODULE_56__["publishBehavior"]; }); +/* harmony import */ var _internal_operators_publishLast__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(457); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publishLast", function() { return _internal_operators_publishLast__WEBPACK_IMPORTED_MODULE_57__["publishLast"]; }); -/***/ }), -/* 427 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* harmony import */ var _internal_operators_publishReplay__WEBPACK_IMPORTED_MODULE_58__ = __webpack_require__(458); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "publishReplay", function() { return _internal_operators_publishReplay__WEBPACK_IMPORTED_MODULE_58__["publishReplay"]; }); -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "distinct", function() { return distinct; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DistinctSubscriber", function() { return DistinctSubscriber; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(70); -/** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ +/* harmony import */ var _internal_operators_race__WEBPACK_IMPORTED_MODULE_59__ = __webpack_require__(459); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "race", function() { return _internal_operators_race__WEBPACK_IMPORTED_MODULE_59__["race"]; }); +/* harmony import */ var _internal_operators_reduce__WEBPACK_IMPORTED_MODULE_60__ = __webpack_require__(444); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "reduce", function() { return _internal_operators_reduce__WEBPACK_IMPORTED_MODULE_60__["reduce"]; }); +/* harmony import */ var _internal_operators_repeat__WEBPACK_IMPORTED_MODULE_61__ = __webpack_require__(460); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "repeat", function() { return _internal_operators_repeat__WEBPACK_IMPORTED_MODULE_61__["repeat"]; }); -function distinct(keySelector, flushes) { - return function (source) { return source.lift(new DistinctOperator(keySelector, flushes)); }; -} -var DistinctOperator = /*@__PURE__*/ (function () { - function DistinctOperator(keySelector, flushes) { - this.keySelector = keySelector; - this.flushes = flushes; - } - DistinctOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new DistinctSubscriber(subscriber, this.keySelector, this.flushes)); - }; - return DistinctOperator; -}()); -var DistinctSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](DistinctSubscriber, _super); - function DistinctSubscriber(destination, keySelector, flushes) { - var _this = _super.call(this, destination) || this; - _this.keySelector = keySelector; - _this.values = new Set(); - if (flushes) { - _this.add(Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(_this, flushes)); - } - return _this; - } - DistinctSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { - this.values.clear(); - }; - DistinctSubscriber.prototype.notifyError = function (error, innerSub) { - this._error(error); - }; - DistinctSubscriber.prototype._next = function (value) { - if (this.keySelector) { - this._useKeySelector(value); - } - else { - this._finalizeNext(value, value); - } - }; - DistinctSubscriber.prototype._useKeySelector = function (value) { - var key; - var destination = this.destination; - try { - key = this.keySelector(value); - } - catch (err) { - destination.error(err); - return; - } - this._finalizeNext(key, value); - }; - DistinctSubscriber.prototype._finalizeNext = function (key, value) { - var values = this.values; - if (!values.has(key)) { - values.add(key); - this.destination.next(value); - } - }; - return DistinctSubscriber; -}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); +/* harmony import */ var _internal_operators_repeatWhen__WEBPACK_IMPORTED_MODULE_62__ = __webpack_require__(461); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "repeatWhen", function() { return _internal_operators_repeatWhen__WEBPACK_IMPORTED_MODULE_62__["repeatWhen"]; }); -//# sourceMappingURL=distinct.js.map +/* harmony import */ var _internal_operators_retry__WEBPACK_IMPORTED_MODULE_63__ = __webpack_require__(462); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "retry", function() { return _internal_operators_retry__WEBPACK_IMPORTED_MODULE_63__["retry"]; }); +/* harmony import */ var _internal_operators_retryWhen__WEBPACK_IMPORTED_MODULE_64__ = __webpack_require__(463); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "retryWhen", function() { return _internal_operators_retryWhen__WEBPACK_IMPORTED_MODULE_64__["retryWhen"]; }); -/***/ }), -/* 428 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* harmony import */ var _internal_operators_refCount__WEBPACK_IMPORTED_MODULE_65__ = __webpack_require__(30); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "refCount", function() { return _internal_operators_refCount__WEBPACK_IMPORTED_MODULE_65__["refCount"]; }); -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "distinctUntilChanged", function() { return distinctUntilChanged; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ +/* harmony import */ var _internal_operators_sample__WEBPACK_IMPORTED_MODULE_66__ = __webpack_require__(464); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "sample", function() { return _internal_operators_sample__WEBPACK_IMPORTED_MODULE_66__["sample"]; }); +/* harmony import */ var _internal_operators_sampleTime__WEBPACK_IMPORTED_MODULE_67__ = __webpack_require__(465); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "sampleTime", function() { return _internal_operators_sampleTime__WEBPACK_IMPORTED_MODULE_67__["sampleTime"]; }); -function distinctUntilChanged(compare, keySelector) { - return function (source) { return source.lift(new DistinctUntilChangedOperator(compare, keySelector)); }; -} -var DistinctUntilChangedOperator = /*@__PURE__*/ (function () { - function DistinctUntilChangedOperator(compare, keySelector) { - this.compare = compare; - this.keySelector = keySelector; - } - DistinctUntilChangedOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new DistinctUntilChangedSubscriber(subscriber, this.compare, this.keySelector)); - }; - return DistinctUntilChangedOperator; -}()); -var DistinctUntilChangedSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](DistinctUntilChangedSubscriber, _super); - function DistinctUntilChangedSubscriber(destination, compare, keySelector) { - var _this = _super.call(this, destination) || this; - _this.keySelector = keySelector; - _this.hasKey = false; - if (typeof compare === 'function') { - _this.compare = compare; - } - return _this; - } - DistinctUntilChangedSubscriber.prototype.compare = function (x, y) { - return x === y; - }; - DistinctUntilChangedSubscriber.prototype._next = function (value) { - var key; - try { - var keySelector = this.keySelector; - key = keySelector ? keySelector(value) : value; - } - catch (err) { - return this.destination.error(err); - } - var result = false; - if (this.hasKey) { - try { - var compare = this.compare; - result = compare(this.key, key); - } - catch (err) { - return this.destination.error(err); - } - } - else { - this.hasKey = true; - } - if (!result) { - this.key = key; - this.destination.next(value); - } - }; - return DistinctUntilChangedSubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=distinctUntilChanged.js.map +/* harmony import */ var _internal_operators_scan__WEBPACK_IMPORTED_MODULE_68__ = __webpack_require__(445); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "scan", function() { return _internal_operators_scan__WEBPACK_IMPORTED_MODULE_68__["scan"]; }); +/* harmony import */ var _internal_operators_sequenceEqual__WEBPACK_IMPORTED_MODULE_69__ = __webpack_require__(466); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "sequenceEqual", function() { return _internal_operators_sequenceEqual__WEBPACK_IMPORTED_MODULE_69__["sequenceEqual"]; }); -/***/ }), -/* 429 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* harmony import */ var _internal_operators_share__WEBPACK_IMPORTED_MODULE_70__ = __webpack_require__(467); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "share", function() { return _internal_operators_share__WEBPACK_IMPORTED_MODULE_70__["share"]; }); -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "distinctUntilKeyChanged", function() { return distinctUntilKeyChanged; }); -/* harmony import */ var _distinctUntilChanged__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(428); -/** PURE_IMPORTS_START _distinctUntilChanged PURE_IMPORTS_END */ +/* harmony import */ var _internal_operators_shareReplay__WEBPACK_IMPORTED_MODULE_71__ = __webpack_require__(468); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "shareReplay", function() { return _internal_operators_shareReplay__WEBPACK_IMPORTED_MODULE_71__["shareReplay"]; }); -function distinctUntilKeyChanged(key, compare) { - return Object(_distinctUntilChanged__WEBPACK_IMPORTED_MODULE_0__["distinctUntilChanged"])(function (x, y) { return compare ? compare(x[key], y[key]) : x[key] === y[key]; }); -} -//# sourceMappingURL=distinctUntilKeyChanged.js.map +/* harmony import */ var _internal_operators_single__WEBPACK_IMPORTED_MODULE_72__ = __webpack_require__(469); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "single", function() { return _internal_operators_single__WEBPACK_IMPORTED_MODULE_72__["single"]; }); +/* harmony import */ var _internal_operators_skip__WEBPACK_IMPORTED_MODULE_73__ = __webpack_require__(470); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skip", function() { return _internal_operators_skip__WEBPACK_IMPORTED_MODULE_73__["skip"]; }); -/***/ }), -/* 430 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* harmony import */ var _internal_operators_skipLast__WEBPACK_IMPORTED_MODULE_74__ = __webpack_require__(471); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skipLast", function() { return _internal_operators_skipLast__WEBPACK_IMPORTED_MODULE_74__["skipLast"]; }); -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "elementAt", function() { return elementAt; }); -/* harmony import */ var _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(62); -/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(104); -/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(431); -/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(422); -/* harmony import */ var _take__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(432); -/** PURE_IMPORTS_START _util_ArgumentOutOfRangeError,_filter,_throwIfEmpty,_defaultIfEmpty,_take PURE_IMPORTS_END */ +/* harmony import */ var _internal_operators_skipUntil__WEBPACK_IMPORTED_MODULE_75__ = __webpack_require__(472); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skipUntil", function() { return _internal_operators_skipUntil__WEBPACK_IMPORTED_MODULE_75__["skipUntil"]; }); +/* harmony import */ var _internal_operators_skipWhile__WEBPACK_IMPORTED_MODULE_76__ = __webpack_require__(473); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "skipWhile", function() { return _internal_operators_skipWhile__WEBPACK_IMPORTED_MODULE_76__["skipWhile"]; }); +/* harmony import */ var _internal_operators_startWith__WEBPACK_IMPORTED_MODULE_77__ = __webpack_require__(474); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "startWith", function() { return _internal_operators_startWith__WEBPACK_IMPORTED_MODULE_77__["startWith"]; }); +/* harmony import */ var _internal_operators_subscribeOn__WEBPACK_IMPORTED_MODULE_78__ = __webpack_require__(475); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "subscribeOn", function() { return _internal_operators_subscribeOn__WEBPACK_IMPORTED_MODULE_78__["subscribeOn"]; }); +/* harmony import */ var _internal_operators_switchAll__WEBPACK_IMPORTED_MODULE_79__ = __webpack_require__(477); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "switchAll", function() { return _internal_operators_switchAll__WEBPACK_IMPORTED_MODULE_79__["switchAll"]; }); -function elementAt(index, defaultValue) { - if (index < 0) { - throw new _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_0__["ArgumentOutOfRangeError"](); - } - var hasDefaultValue = arguments.length >= 2; - return function (source) { - return source.pipe(Object(_filter__WEBPACK_IMPORTED_MODULE_1__["filter"])(function (v, i) { return i === index; }), Object(_take__WEBPACK_IMPORTED_MODULE_4__["take"])(1), hasDefaultValue - ? Object(_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__["defaultIfEmpty"])(defaultValue) - : Object(_throwIfEmpty__WEBPACK_IMPORTED_MODULE_2__["throwIfEmpty"])(function () { return new _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_0__["ArgumentOutOfRangeError"](); })); - }; -} -//# sourceMappingURL=elementAt.js.map +/* harmony import */ var _internal_operators_switchMap__WEBPACK_IMPORTED_MODULE_80__ = __webpack_require__(478); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "switchMap", function() { return _internal_operators_switchMap__WEBPACK_IMPORTED_MODULE_80__["switchMap"]; }); +/* harmony import */ var _internal_operators_switchMapTo__WEBPACK_IMPORTED_MODULE_81__ = __webpack_require__(479); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "switchMapTo", function() { return _internal_operators_switchMapTo__WEBPACK_IMPORTED_MODULE_81__["switchMapTo"]; }); -/***/ }), -/* 431 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* harmony import */ var _internal_operators_take__WEBPACK_IMPORTED_MODULE_82__ = __webpack_require__(427); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "take", function() { return _internal_operators_take__WEBPACK_IMPORTED_MODULE_82__["take"]; }); -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "throwIfEmpty", function() { return throwIfEmpty; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(63); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(11); -/** PURE_IMPORTS_START tslib,_util_EmptyError,_Subscriber PURE_IMPORTS_END */ +/* harmony import */ var _internal_operators_takeLast__WEBPACK_IMPORTED_MODULE_83__ = __webpack_require__(440); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "takeLast", function() { return _internal_operators_takeLast__WEBPACK_IMPORTED_MODULE_83__["takeLast"]; }); +/* harmony import */ var _internal_operators_takeUntil__WEBPACK_IMPORTED_MODULE_84__ = __webpack_require__(480); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "takeUntil", function() { return _internal_operators_takeUntil__WEBPACK_IMPORTED_MODULE_84__["takeUntil"]; }); +/* harmony import */ var _internal_operators_takeWhile__WEBPACK_IMPORTED_MODULE_85__ = __webpack_require__(481); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "takeWhile", function() { return _internal_operators_takeWhile__WEBPACK_IMPORTED_MODULE_85__["takeWhile"]; }); -function throwIfEmpty(errorFactory) { - if (errorFactory === void 0) { - errorFactory = defaultErrorFactory; - } - return function (source) { - return source.lift(new ThrowIfEmptyOperator(errorFactory)); - }; -} -var ThrowIfEmptyOperator = /*@__PURE__*/ (function () { - function ThrowIfEmptyOperator(errorFactory) { - this.errorFactory = errorFactory; - } - ThrowIfEmptyOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new ThrowIfEmptySubscriber(subscriber, this.errorFactory)); - }; - return ThrowIfEmptyOperator; -}()); -var ThrowIfEmptySubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](ThrowIfEmptySubscriber, _super); - function ThrowIfEmptySubscriber(destination, errorFactory) { - var _this = _super.call(this, destination) || this; - _this.errorFactory = errorFactory; - _this.hasValue = false; - return _this; - } - ThrowIfEmptySubscriber.prototype._next = function (value) { - this.hasValue = true; - this.destination.next(value); - }; - ThrowIfEmptySubscriber.prototype._complete = function () { - if (!this.hasValue) { - var err = void 0; - try { - err = this.errorFactory(); - } - catch (e) { - err = e; - } - this.destination.error(err); - } - else { - return this.destination.complete(); - } - }; - return ThrowIfEmptySubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_2__["Subscriber"])); -function defaultErrorFactory() { - return new _util_EmptyError__WEBPACK_IMPORTED_MODULE_1__["EmptyError"](); -} -//# sourceMappingURL=throwIfEmpty.js.map +/* harmony import */ var _internal_operators_tap__WEBPACK_IMPORTED_MODULE_86__ = __webpack_require__(482); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "tap", function() { return _internal_operators_tap__WEBPACK_IMPORTED_MODULE_86__["tap"]; }); +/* harmony import */ var _internal_operators_throttle__WEBPACK_IMPORTED_MODULE_87__ = __webpack_require__(483); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "throttle", function() { return _internal_operators_throttle__WEBPACK_IMPORTED_MODULE_87__["throttle"]; }); -/***/ }), -/* 432 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* harmony import */ var _internal_operators_throttleTime__WEBPACK_IMPORTED_MODULE_88__ = __webpack_require__(484); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "throttleTime", function() { return _internal_operators_throttleTime__WEBPACK_IMPORTED_MODULE_88__["throttleTime"]; }); -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "take", function() { return take; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/* harmony import */ var _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(62); -/* harmony import */ var _observable_empty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(43); -/** PURE_IMPORTS_START tslib,_Subscriber,_util_ArgumentOutOfRangeError,_observable_empty PURE_IMPORTS_END */ +/* harmony import */ var _internal_operators_throwIfEmpty__WEBPACK_IMPORTED_MODULE_89__ = __webpack_require__(426); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "throwIfEmpty", function() { return _internal_operators_throwIfEmpty__WEBPACK_IMPORTED_MODULE_89__["throwIfEmpty"]; }); +/* harmony import */ var _internal_operators_timeInterval__WEBPACK_IMPORTED_MODULE_90__ = __webpack_require__(485); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timeInterval", function() { return _internal_operators_timeInterval__WEBPACK_IMPORTED_MODULE_90__["timeInterval"]; }); +/* harmony import */ var _internal_operators_timeout__WEBPACK_IMPORTED_MODULE_91__ = __webpack_require__(486); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timeout", function() { return _internal_operators_timeout__WEBPACK_IMPORTED_MODULE_91__["timeout"]; }); +/* harmony import */ var _internal_operators_timeoutWith__WEBPACK_IMPORTED_MODULE_92__ = __webpack_require__(487); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timeoutWith", function() { return _internal_operators_timeoutWith__WEBPACK_IMPORTED_MODULE_92__["timeoutWith"]; }); -function take(count) { - return function (source) { - if (count === 0) { - return Object(_observable_empty__WEBPACK_IMPORTED_MODULE_3__["empty"])(); - } - else { - return source.lift(new TakeOperator(count)); - } - }; -} -var TakeOperator = /*@__PURE__*/ (function () { - function TakeOperator(total) { - this.total = total; - if (this.total < 0) { - throw new _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_2__["ArgumentOutOfRangeError"]; - } - } - TakeOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new TakeSubscriber(subscriber, this.total)); - }; - return TakeOperator; -}()); -var TakeSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](TakeSubscriber, _super); - function TakeSubscriber(destination, total) { - var _this = _super.call(this, destination) || this; - _this.total = total; - _this.count = 0; - return _this; - } - TakeSubscriber.prototype._next = function (value) { - var total = this.total; - var count = ++this.count; - if (count <= total) { - this.destination.next(value); - if (count === total) { - this.destination.complete(); - this.unsubscribe(); - } - } - }; - return TakeSubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=take.js.map +/* harmony import */ var _internal_operators_timestamp__WEBPACK_IMPORTED_MODULE_93__ = __webpack_require__(488); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "timestamp", function() { return _internal_operators_timestamp__WEBPACK_IMPORTED_MODULE_93__["timestamp"]; }); +/* harmony import */ var _internal_operators_toArray__WEBPACK_IMPORTED_MODULE_94__ = __webpack_require__(489); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "toArray", function() { return _internal_operators_toArray__WEBPACK_IMPORTED_MODULE_94__["toArray"]; }); -/***/ }), -/* 433 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* harmony import */ var _internal_operators_window__WEBPACK_IMPORTED_MODULE_95__ = __webpack_require__(490); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "window", function() { return _internal_operators_window__WEBPACK_IMPORTED_MODULE_95__["window"]; }); -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "endWith", function() { return endWith; }); -/* harmony import */ var _observable_concat__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(79); -/* harmony import */ var _observable_of__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(44); -/** PURE_IMPORTS_START _observable_concat,_observable_of PURE_IMPORTS_END */ +/* harmony import */ var _internal_operators_windowCount__WEBPACK_IMPORTED_MODULE_96__ = __webpack_require__(491); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowCount", function() { return _internal_operators_windowCount__WEBPACK_IMPORTED_MODULE_96__["windowCount"]; }); +/* harmony import */ var _internal_operators_windowTime__WEBPACK_IMPORTED_MODULE_97__ = __webpack_require__(492); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowTime", function() { return _internal_operators_windowTime__WEBPACK_IMPORTED_MODULE_97__["windowTime"]; }); -function endWith() { - var array = []; - for (var _i = 0; _i < arguments.length; _i++) { - array[_i] = arguments[_i]; - } - return function (source) { return Object(_observable_concat__WEBPACK_IMPORTED_MODULE_0__["concat"])(source, _observable_of__WEBPACK_IMPORTED_MODULE_1__["of"].apply(void 0, array)); }; -} -//# sourceMappingURL=endWith.js.map +/* harmony import */ var _internal_operators_windowToggle__WEBPACK_IMPORTED_MODULE_98__ = __webpack_require__(493); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowToggle", function() { return _internal_operators_windowToggle__WEBPACK_IMPORTED_MODULE_98__["windowToggle"]; }); +/* harmony import */ var _internal_operators_windowWhen__WEBPACK_IMPORTED_MODULE_99__ = __webpack_require__(494); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "windowWhen", function() { return _internal_operators_windowWhen__WEBPACK_IMPORTED_MODULE_99__["windowWhen"]; }); -/***/ }), -/* 434 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* harmony import */ var _internal_operators_withLatestFrom__WEBPACK_IMPORTED_MODULE_100__ = __webpack_require__(495); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "withLatestFrom", function() { return _internal_operators_withLatestFrom__WEBPACK_IMPORTED_MODULE_100__["withLatestFrom"]; }); -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "every", function() { return every; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ +/* harmony import */ var _internal_operators_zip__WEBPACK_IMPORTED_MODULE_101__ = __webpack_require__(496); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "zip", function() { return _internal_operators_zip__WEBPACK_IMPORTED_MODULE_101__["zip"]; }); +/* harmony import */ var _internal_operators_zipAll__WEBPACK_IMPORTED_MODULE_102__ = __webpack_require__(497); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "zipAll", function() { return _internal_operators_zipAll__WEBPACK_IMPORTED_MODULE_102__["zipAll"]; }); -function every(predicate, thisArg) { - return function (source) { return source.lift(new EveryOperator(predicate, thisArg, source)); }; -} -var EveryOperator = /*@__PURE__*/ (function () { - function EveryOperator(predicate, thisArg, source) { - this.predicate = predicate; - this.thisArg = thisArg; - this.source = source; - } - EveryOperator.prototype.call = function (observer, source) { - return source.subscribe(new EverySubscriber(observer, this.predicate, this.thisArg, this.source)); - }; - return EveryOperator; -}()); -var EverySubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](EverySubscriber, _super); - function EverySubscriber(destination, predicate, thisArg, source) { - var _this = _super.call(this, destination) || this; - _this.predicate = predicate; - _this.thisArg = thisArg; - _this.source = source; - _this.index = 0; - _this.thisArg = thisArg || _this; - return _this; - } - EverySubscriber.prototype.notifyComplete = function (everyValueMatch) { - this.destination.next(everyValueMatch); - this.destination.complete(); - }; - EverySubscriber.prototype._next = function (value) { - var result = false; - try { - result = this.predicate.call(this.thisArg, value, this.index++, this.source); - } - catch (err) { - this.destination.error(err); - return; - } - if (!result) { - this.notifyComplete(false); - } - }; - EverySubscriber.prototype._complete = function () { - this.notifyComplete(true); - }; - return EverySubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=every.js.map +/** PURE_IMPORTS_START PURE_IMPORTS_END */ -/***/ }), -/* 435 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "exhaust", function() { return exhaust; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(70); -/** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ -function exhaust() { - return function (source) { return source.lift(new SwitchFirstOperator()); }; -} -var SwitchFirstOperator = /*@__PURE__*/ (function () { - function SwitchFirstOperator() { - } - SwitchFirstOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new SwitchFirstSubscriber(subscriber)); - }; - return SwitchFirstOperator; -}()); -var SwitchFirstSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SwitchFirstSubscriber, _super); - function SwitchFirstSubscriber(destination) { - var _this = _super.call(this, destination) || this; - _this.hasCompleted = false; - _this.hasSubscription = false; - return _this; - } - SwitchFirstSubscriber.prototype._next = function (value) { - if (!this.hasSubscription) { - this.hasSubscription = true; - this.add(Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(this, value)); - } - }; - SwitchFirstSubscriber.prototype._complete = function () { - this.hasCompleted = true; - if (!this.hasSubscription) { - this.destination.complete(); - } - }; - SwitchFirstSubscriber.prototype.notifyComplete = function (innerSub) { - this.remove(innerSub); - this.hasSubscription = false; - if (this.hasCompleted) { - this.destination.complete(); - } - }; - return SwitchFirstSubscriber; -}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); -//# sourceMappingURL=exhaust.js.map -/***/ }), -/* 436 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "exhaustMap", function() { return exhaustMap; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); -/* harmony import */ var _InnerSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(70); -/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(66); -/* harmony import */ var _observable_from__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(83); -/** PURE_IMPORTS_START tslib,_OuterSubscriber,_InnerSubscriber,_util_subscribeToResult,_map,_observable_from PURE_IMPORTS_END */ -function exhaustMap(project, resultSelector) { - if (resultSelector) { - return function (source) { return source.pipe(exhaustMap(function (a, i) { return Object(_observable_from__WEBPACK_IMPORTED_MODULE_5__["from"])(project(a, i)).pipe(Object(_map__WEBPACK_IMPORTED_MODULE_4__["map"])(function (b, ii) { return resultSelector(a, b, i, ii); })); })); }; - } - return function (source) { - return source.lift(new ExhaustMapOperator(project)); - }; -} -var ExhaustMapOperator = /*@__PURE__*/ (function () { - function ExhaustMapOperator(project) { - this.project = project; - } - ExhaustMapOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new ExhaustMapSubscriber(subscriber, this.project)); - }; - return ExhaustMapOperator; -}()); -var ExhaustMapSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](ExhaustMapSubscriber, _super); - function ExhaustMapSubscriber(destination, project) { - var _this = _super.call(this, destination) || this; - _this.project = project; - _this.hasSubscription = false; - _this.hasCompleted = false; - _this.index = 0; - return _this; - } - ExhaustMapSubscriber.prototype._next = function (value) { - if (!this.hasSubscription) { - this.tryNext(value); - } - }; - ExhaustMapSubscriber.prototype.tryNext = function (value) { - var result; - var index = this.index++; - try { - result = this.project(value, index); - } - catch (err) { - this.destination.error(err); - return; - } - this.hasSubscription = true; - this._innerSub(result, value, index); - }; - ExhaustMapSubscriber.prototype._innerSub = function (result, value, index) { - var innerSubscriber = new _InnerSubscriber__WEBPACK_IMPORTED_MODULE_2__["InnerSubscriber"](this, value, index); - var destination = this.destination; - destination.add(innerSubscriber); - var innerSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__["subscribeToResult"])(this, result, undefined, undefined, innerSubscriber); - if (innerSubscription !== innerSubscriber) { - destination.add(innerSubscription); - } - }; - ExhaustMapSubscriber.prototype._complete = function () { - this.hasCompleted = true; - if (!this.hasSubscription) { - this.destination.complete(); - } - this.unsubscribe(); - }; - ExhaustMapSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { - this.destination.next(innerValue); - }; - ExhaustMapSubscriber.prototype.notifyError = function (err) { - this.destination.error(err); - }; - ExhaustMapSubscriber.prototype.notifyComplete = function (innerSub) { - var destination = this.destination; - destination.remove(innerSub); - this.hasSubscription = false; - if (this.hasCompleted) { - this.destination.complete(); - } - }; - return ExhaustMapSubscriber; -}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); -//# sourceMappingURL=exhaustMap.js.map -/***/ }), -/* 437 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "expand", function() { return expand; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ExpandOperator", function() { return ExpandOperator; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ExpandSubscriber", function() { return ExpandSubscriber; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(70); -/** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ -function expand(project, concurrent, scheduler) { - if (concurrent === void 0) { - concurrent = Number.POSITIVE_INFINITY; - } - if (scheduler === void 0) { - scheduler = undefined; - } - concurrent = (concurrent || 0) < 1 ? Number.POSITIVE_INFINITY : concurrent; - return function (source) { return source.lift(new ExpandOperator(project, concurrent, scheduler)); }; -} -var ExpandOperator = /*@__PURE__*/ (function () { - function ExpandOperator(project, concurrent, scheduler) { - this.project = project; - this.concurrent = concurrent; - this.scheduler = scheduler; - } - ExpandOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new ExpandSubscriber(subscriber, this.project, this.concurrent, this.scheduler)); - }; - return ExpandOperator; -}()); -var ExpandSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](ExpandSubscriber, _super); - function ExpandSubscriber(destination, project, concurrent, scheduler) { - var _this = _super.call(this, destination) || this; - _this.project = project; - _this.concurrent = concurrent; - _this.scheduler = scheduler; - _this.index = 0; - _this.active = 0; - _this.hasCompleted = false; - if (concurrent < Number.POSITIVE_INFINITY) { - _this.buffer = []; - } - return _this; - } - ExpandSubscriber.dispatch = function (arg) { - var subscriber = arg.subscriber, result = arg.result, value = arg.value, index = arg.index; - subscriber.subscribeToProjection(result, value, index); - }; - ExpandSubscriber.prototype._next = function (value) { - var destination = this.destination; - if (destination.closed) { - this._complete(); - return; - } - var index = this.index++; - if (this.active < this.concurrent) { - destination.next(value); - try { - var project = this.project; - var result = project(value, index); - if (!this.scheduler) { - this.subscribeToProjection(result, value, index); - } - else { - var state = { subscriber: this, result: result, value: value, index: index }; - var destination_1 = this.destination; - destination_1.add(this.scheduler.schedule(ExpandSubscriber.dispatch, 0, state)); - } - } - catch (e) { - destination.error(e); - } - } - else { - this.buffer.push(value); - } - }; - ExpandSubscriber.prototype.subscribeToProjection = function (result, value, index) { - this.active++; - var destination = this.destination; - destination.add(Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(this, result, value, index)); - }; - ExpandSubscriber.prototype._complete = function () { - this.hasCompleted = true; - if (this.hasCompleted && this.active === 0) { - this.destination.complete(); - } - this.unsubscribe(); - }; - ExpandSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { - this._next(innerValue); - }; - ExpandSubscriber.prototype.notifyComplete = function (innerSub) { - var buffer = this.buffer; - var destination = this.destination; - destination.remove(innerSub); - this.active--; - if (buffer && buffer.length > 0) { - this._next(buffer.shift()); - } - if (this.hasCompleted && this.active === 0) { - this.destination.complete(); - } - }; - return ExpandSubscriber; -}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); -//# sourceMappingURL=expand.js.map -/***/ }), -/* 438 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "finalize", function() { return finalize; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(17); -/** PURE_IMPORTS_START tslib,_Subscriber,_Subscription PURE_IMPORTS_END */ -function finalize(callback) { - return function (source) { return source.lift(new FinallyOperator(callback)); }; -} -var FinallyOperator = /*@__PURE__*/ (function () { - function FinallyOperator(callback) { - this.callback = callback; - } - FinallyOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new FinallySubscriber(subscriber, this.callback)); - }; - return FinallyOperator; -}()); -var FinallySubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](FinallySubscriber, _super); - function FinallySubscriber(destination, callback) { - var _this = _super.call(this, destination) || this; - _this.add(new _Subscription__WEBPACK_IMPORTED_MODULE_2__["Subscription"](callback)); - return _this; - } - return FinallySubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=finalize.js.map -/***/ }), -/* 439 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "find", function() { return find; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FindValueOperator", function() { return FindValueOperator; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FindValueSubscriber", function() { return FindValueSubscriber; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ -function find(predicate, thisArg) { - if (typeof predicate !== 'function') { - throw new TypeError('predicate is not a function'); - } - return function (source) { return source.lift(new FindValueOperator(predicate, source, false, thisArg)); }; -} -var FindValueOperator = /*@__PURE__*/ (function () { - function FindValueOperator(predicate, source, yieldIndex, thisArg) { - this.predicate = predicate; - this.source = source; - this.yieldIndex = yieldIndex; - this.thisArg = thisArg; - } - FindValueOperator.prototype.call = function (observer, source) { - return source.subscribe(new FindValueSubscriber(observer, this.predicate, this.source, this.yieldIndex, this.thisArg)); - }; - return FindValueOperator; -}()); -var FindValueSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](FindValueSubscriber, _super); - function FindValueSubscriber(destination, predicate, source, yieldIndex, thisArg) { - var _this = _super.call(this, destination) || this; - _this.predicate = predicate; - _this.source = source; - _this.yieldIndex = yieldIndex; - _this.thisArg = thisArg; - _this.index = 0; - return _this; - } - FindValueSubscriber.prototype.notifyComplete = function (value) { - var destination = this.destination; - destination.next(value); - destination.complete(); - this.unsubscribe(); - }; - FindValueSubscriber.prototype._next = function (value) { - var _a = this, predicate = _a.predicate, thisArg = _a.thisArg; - var index = this.index++; - try { - var result = predicate.call(thisArg || this, value, index, this.source); - if (result) { - this.notifyComplete(this.yieldIndex ? index : value); - } - } - catch (err) { - this.destination.error(err); - } - }; - FindValueSubscriber.prototype._complete = function () { - this.notifyComplete(this.yieldIndex ? -1 : undefined); - }; - return FindValueSubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=find.js.map -/***/ }), -/* 440 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "findIndex", function() { return findIndex; }); -/* harmony import */ var _operators_find__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(439); -/** PURE_IMPORTS_START _operators_find PURE_IMPORTS_END */ -function findIndex(predicate, thisArg) { - return function (source) { return source.lift(new _operators_find__WEBPACK_IMPORTED_MODULE_0__["FindValueOperator"](predicate, source, true, thisArg)); }; -} -//# sourceMappingURL=findIndex.js.map -/***/ }), -/* 441 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "first", function() { return first; }); -/* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(63); -/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(104); -/* harmony import */ var _take__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(432); -/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(422); -/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(431); -/* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(25); -/** PURE_IMPORTS_START _util_EmptyError,_filter,_take,_defaultIfEmpty,_throwIfEmpty,_util_identity PURE_IMPORTS_END */ -function first(predicate, defaultValue) { - var hasDefaultValue = arguments.length >= 2; - return function (source) { return source.pipe(predicate ? Object(_filter__WEBPACK_IMPORTED_MODULE_1__["filter"])(function (v, i) { return predicate(v, i, source); }) : _util_identity__WEBPACK_IMPORTED_MODULE_5__["identity"], Object(_take__WEBPACK_IMPORTED_MODULE_2__["take"])(1), hasDefaultValue ? Object(_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__["defaultIfEmpty"])(defaultValue) : Object(_throwIfEmpty__WEBPACK_IMPORTED_MODULE_4__["throwIfEmpty"])(function () { return new _util_EmptyError__WEBPACK_IMPORTED_MODULE_0__["EmptyError"](); })); }; -} -//# sourceMappingURL=first.js.map -/***/ }), -/* 442 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ignoreElements", function() { return ignoreElements; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ -function ignoreElements() { - return function ignoreElementsOperatorFunction(source) { - return source.lift(new IgnoreElementsOperator()); - }; -} -var IgnoreElementsOperator = /*@__PURE__*/ (function () { - function IgnoreElementsOperator() { - } - IgnoreElementsOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new IgnoreElementsSubscriber(subscriber)); - }; - return IgnoreElementsOperator; -}()); -var IgnoreElementsSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](IgnoreElementsSubscriber, _super); - function IgnoreElementsSubscriber() { - return _super !== null && _super.apply(this, arguments) || this; - } - IgnoreElementsSubscriber.prototype._next = function (unused) { - }; - return IgnoreElementsSubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=ignoreElements.js.map -/***/ }), -/* 443 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isEmpty", function() { return isEmpty; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ -function isEmpty() { - return function (source) { return source.lift(new IsEmptyOperator()); }; -} -var IsEmptyOperator = /*@__PURE__*/ (function () { - function IsEmptyOperator() { - } - IsEmptyOperator.prototype.call = function (observer, source) { - return source.subscribe(new IsEmptySubscriber(observer)); - }; - return IsEmptyOperator; -}()); -var IsEmptySubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](IsEmptySubscriber, _super); - function IsEmptySubscriber(destination) { - return _super.call(this, destination) || this; - } - IsEmptySubscriber.prototype.notifyComplete = function (isEmpty) { - var destination = this.destination; - destination.next(isEmpty); - destination.complete(); - }; - IsEmptySubscriber.prototype._next = function (value) { - this.notifyComplete(false); - }; - IsEmptySubscriber.prototype._complete = function () { - this.notifyComplete(true); - }; - return IsEmptySubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=isEmpty.js.map -/***/ }), -/* 444 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "last", function() { return last; }); -/* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(63); -/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(104); -/* harmony import */ var _takeLast__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(445); -/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(431); -/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(422); -/* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(25); -/** PURE_IMPORTS_START _util_EmptyError,_filter,_takeLast,_throwIfEmpty,_defaultIfEmpty,_util_identity PURE_IMPORTS_END */ -function last(predicate, defaultValue) { - var hasDefaultValue = arguments.length >= 2; - return function (source) { return source.pipe(predicate ? Object(_filter__WEBPACK_IMPORTED_MODULE_1__["filter"])(function (v, i) { return predicate(v, i, source); }) : _util_identity__WEBPACK_IMPORTED_MODULE_5__["identity"], Object(_takeLast__WEBPACK_IMPORTED_MODULE_2__["takeLast"])(1), hasDefaultValue ? Object(_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_4__["defaultIfEmpty"])(defaultValue) : Object(_throwIfEmpty__WEBPACK_IMPORTED_MODULE_3__["throwIfEmpty"])(function () { return new _util_EmptyError__WEBPACK_IMPORTED_MODULE_0__["EmptyError"](); })); }; -} -//# sourceMappingURL=last.js.map -/***/ }), -/* 445 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "takeLast", function() { return takeLast; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/* harmony import */ var _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(62); -/* harmony import */ var _observable_empty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(43); -/** PURE_IMPORTS_START tslib,_Subscriber,_util_ArgumentOutOfRangeError,_observable_empty PURE_IMPORTS_END */ -function takeLast(count) { - return function takeLastOperatorFunction(source) { - if (count === 0) { - return Object(_observable_empty__WEBPACK_IMPORTED_MODULE_3__["empty"])(); - } - else { - return source.lift(new TakeLastOperator(count)); - } - }; -} -var TakeLastOperator = /*@__PURE__*/ (function () { - function TakeLastOperator(total) { - this.total = total; - if (this.total < 0) { - throw new _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_2__["ArgumentOutOfRangeError"]; - } - } - TakeLastOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new TakeLastSubscriber(subscriber, this.total)); - }; - return TakeLastOperator; -}()); -var TakeLastSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](TakeLastSubscriber, _super); - function TakeLastSubscriber(destination, total) { - var _this = _super.call(this, destination) || this; - _this.total = total; - _this.ring = new Array(); - _this.count = 0; - return _this; - } - TakeLastSubscriber.prototype._next = function (value) { - var ring = this.ring; - var total = this.total; - var count = this.count++; - if (ring.length < total) { - ring.push(value); - } - else { - var index = count % total; - ring[index] = value; - } - }; - TakeLastSubscriber.prototype._complete = function () { - var destination = this.destination; - var count = this.count; - if (count > 0) { - var total = this.count >= this.total ? this.total : this.count; - var ring = this.ring; - for (var i = 0; i < total; i++) { - var idx = (count++) % total; - destination.next(ring[idx]); - } - } - destination.complete(); - }; - return TakeLastSubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=takeLast.js.map -/***/ }), -/* 446 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mapTo", function() { return mapTo; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ -function mapTo(value) { - return function (source) { return source.lift(new MapToOperator(value)); }; -} -var MapToOperator = /*@__PURE__*/ (function () { - function MapToOperator(value) { - this.value = value; - } - MapToOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new MapToSubscriber(subscriber, this.value)); - }; - return MapToOperator; -}()); -var MapToSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](MapToSubscriber, _super); - function MapToSubscriber(destination, value) { - var _this = _super.call(this, destination) || this; - _this.value = value; - return _this; - } - MapToSubscriber.prototype._next = function (x) { - this.destination.next(this.value); - }; - return MapToSubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=mapTo.js.map -/***/ }), -/* 447 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "materialize", function() { return materialize; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/* harmony import */ var _Notification__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(42); -/** PURE_IMPORTS_START tslib,_Subscriber,_Notification PURE_IMPORTS_END */ -function materialize() { - return function materializeOperatorFunction(source) { - return source.lift(new MaterializeOperator()); - }; -} -var MaterializeOperator = /*@__PURE__*/ (function () { - function MaterializeOperator() { - } - MaterializeOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new MaterializeSubscriber(subscriber)); - }; - return MaterializeOperator; -}()); -var MaterializeSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](MaterializeSubscriber, _super); - function MaterializeSubscriber(destination) { - return _super.call(this, destination) || this; - } - MaterializeSubscriber.prototype._next = function (value) { - this.destination.next(_Notification__WEBPACK_IMPORTED_MODULE_2__["Notification"].createNext(value)); - }; - MaterializeSubscriber.prototype._error = function (err) { - var destination = this.destination; - destination.next(_Notification__WEBPACK_IMPORTED_MODULE_2__["Notification"].createError(err)); - destination.complete(); - }; - MaterializeSubscriber.prototype._complete = function () { - var destination = this.destination; - destination.next(_Notification__WEBPACK_IMPORTED_MODULE_2__["Notification"].createComplete()); - destination.complete(); - }; - return MaterializeSubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=materialize.js.map -/***/ }), -/* 448 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "max", function() { return max; }); -/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(449); -/** PURE_IMPORTS_START _reduce PURE_IMPORTS_END */ -function max(comparer) { - var max = (typeof comparer === 'function') - ? function (x, y) { return comparer(x, y) > 0 ? x : y; } - : function (x, y) { return x > y ? x : y; }; - return Object(_reduce__WEBPACK_IMPORTED_MODULE_0__["reduce"])(max); -} -//# sourceMappingURL=max.js.map -/***/ }), -/* 449 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "reduce", function() { return reduce; }); -/* harmony import */ var _scan__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(450); -/* harmony import */ var _takeLast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(445); -/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(422); -/* harmony import */ var _util_pipe__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(24); -/** PURE_IMPORTS_START _scan,_takeLast,_defaultIfEmpty,_util_pipe PURE_IMPORTS_END */ -function reduce(accumulator, seed) { - if (arguments.length >= 2) { - return function reduceOperatorFunctionWithSeed(source) { - return Object(_util_pipe__WEBPACK_IMPORTED_MODULE_3__["pipe"])(Object(_scan__WEBPACK_IMPORTED_MODULE_0__["scan"])(accumulator, seed), Object(_takeLast__WEBPACK_IMPORTED_MODULE_1__["takeLast"])(1), Object(_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_2__["defaultIfEmpty"])(seed))(source); - }; - } - return function reduceOperatorFunction(source) { - return Object(_util_pipe__WEBPACK_IMPORTED_MODULE_3__["pipe"])(Object(_scan__WEBPACK_IMPORTED_MODULE_0__["scan"])(function (acc, value, index) { return accumulator(acc, value, index + 1); }), Object(_takeLast__WEBPACK_IMPORTED_MODULE_1__["takeLast"])(1))(source); - }; -} -//# sourceMappingURL=reduce.js.map + + + + + + + +//# sourceMappingURL=index.js.map /***/ }), -/* 450 */ +/* 401 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "scan", function() { return scan; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "audit", function() { return audit; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(70); +/** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ -function scan(accumulator, seed) { - var hasSeed = false; - if (arguments.length >= 2) { - hasSeed = true; - } - return function scanOperatorFunction(source) { - return source.lift(new ScanOperator(accumulator, seed, hasSeed)); + +function audit(durationSelector) { + return function auditOperatorFunction(source) { + return source.lift(new AuditOperator(durationSelector)); }; } -var ScanOperator = /*@__PURE__*/ (function () { - function ScanOperator(accumulator, seed, hasSeed) { - if (hasSeed === void 0) { - hasSeed = false; - } - this.accumulator = accumulator; - this.seed = seed; - this.hasSeed = hasSeed; +var AuditOperator = /*@__PURE__*/ (function () { + function AuditOperator(durationSelector) { + this.durationSelector = durationSelector; } - ScanOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new ScanSubscriber(subscriber, this.accumulator, this.seed, this.hasSeed)); + AuditOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new AuditSubscriber(subscriber, this.durationSelector)); }; - return ScanOperator; + return AuditOperator; }()); -var ScanSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](ScanSubscriber, _super); - function ScanSubscriber(destination, accumulator, _seed, hasSeed) { +var AuditSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](AuditSubscriber, _super); + function AuditSubscriber(destination, durationSelector) { var _this = _super.call(this, destination) || this; - _this.accumulator = accumulator; - _this._seed = _seed; - _this.hasSeed = hasSeed; - _this.index = 0; + _this.durationSelector = durationSelector; + _this.hasValue = false; return _this; } - Object.defineProperty(ScanSubscriber.prototype, "seed", { - get: function () { - return this._seed; - }, - set: function (value) { - this.hasSeed = true; - this._seed = value; - }, - enumerable: true, - configurable: true - }); - ScanSubscriber.prototype._next = function (value) { - if (!this.hasSeed) { - this.seed = value; - this.destination.next(value); - } - else { - return this._tryNext(value); + AuditSubscriber.prototype._next = function (value) { + this.value = value; + this.hasValue = true; + if (!this.throttled) { + var duration = void 0; + try { + var durationSelector = this.durationSelector; + duration = durationSelector(value); + } + catch (err) { + return this.destination.error(err); + } + var innerSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(this, duration); + if (!innerSubscription || innerSubscription.closed) { + this.clearThrottle(); + } + else { + this.add(this.throttled = innerSubscription); + } } }; - ScanSubscriber.prototype._tryNext = function (value) { - var index = this.index++; - var result; - try { - result = this.accumulator(this.seed, value, index); + AuditSubscriber.prototype.clearThrottle = function () { + var _a = this, value = _a.value, hasValue = _a.hasValue, throttled = _a.throttled; + if (throttled) { + this.remove(throttled); + this.throttled = null; + throttled.unsubscribe(); } - catch (err) { - this.destination.error(err); + if (hasValue) { + this.value = null; + this.hasValue = false; + this.destination.next(value); } - this.seed = result; - this.destination.next(result); }; - return ScanSubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=scan.js.map + AuditSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex) { + this.clearThrottle(); + }; + AuditSubscriber.prototype.notifyComplete = function () { + this.clearThrottle(); + }; + return AuditSubscriber; +}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); +//# sourceMappingURL=audit.js.map /***/ }), -/* 451 */ +/* 402 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "merge", function() { return merge; }); -/* harmony import */ var _observable_merge__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(98); -/** PURE_IMPORTS_START _observable_merge PURE_IMPORTS_END */ +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "auditTime", function() { return auditTime; }); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(55); +/* harmony import */ var _audit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(401); +/* harmony import */ var _observable_timer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(107); +/** PURE_IMPORTS_START _scheduler_async,_audit,_observable_timer PURE_IMPORTS_END */ -function merge() { - var observables = []; - for (var _i = 0; _i < arguments.length; _i++) { - observables[_i] = arguments[_i]; + + +function auditTime(duration, scheduler) { + if (scheduler === void 0) { + scheduler = _scheduler_async__WEBPACK_IMPORTED_MODULE_0__["async"]; } - return function (source) { return source.lift.call(_observable_merge__WEBPACK_IMPORTED_MODULE_0__["merge"].apply(void 0, [source].concat(observables))); }; + return Object(_audit__WEBPACK_IMPORTED_MODULE_1__["audit"])(function () { return Object(_observable_timer__WEBPACK_IMPORTED_MODULE_2__["timer"])(duration, scheduler); }); } -//# sourceMappingURL=merge.js.map +//# sourceMappingURL=auditTime.js.map /***/ }), -/* 452 */ +/* 403 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mergeMapTo", function() { return mergeMapTo; }); -/* harmony import */ var _mergeMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(82); -/** PURE_IMPORTS_START _mergeMap PURE_IMPORTS_END */ +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buffer", function() { return buffer; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(70); +/** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ -function mergeMapTo(innerObservable, resultSelector, concurrent) { - if (concurrent === void 0) { - concurrent = Number.POSITIVE_INFINITY; - } - if (typeof resultSelector === 'function') { - return Object(_mergeMap__WEBPACK_IMPORTED_MODULE_0__["mergeMap"])(function () { return innerObservable; }, resultSelector, concurrent); + + +function buffer(closingNotifier) { + return function bufferOperatorFunction(source) { + return source.lift(new BufferOperator(closingNotifier)); + }; +} +var BufferOperator = /*@__PURE__*/ (function () { + function BufferOperator(closingNotifier) { + this.closingNotifier = closingNotifier; } - if (typeof resultSelector === 'number') { - concurrent = resultSelector; + BufferOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new BufferSubscriber(subscriber, this.closingNotifier)); + }; + return BufferOperator; +}()); +var BufferSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](BufferSubscriber, _super); + function BufferSubscriber(destination, closingNotifier) { + var _this = _super.call(this, destination) || this; + _this.buffer = []; + _this.add(Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(_this, closingNotifier)); + return _this; } - return Object(_mergeMap__WEBPACK_IMPORTED_MODULE_0__["mergeMap"])(function () { return innerObservable; }, concurrent); -} -//# sourceMappingURL=mergeMapTo.js.map + BufferSubscriber.prototype._next = function (value) { + this.buffer.push(value); + }; + BufferSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + var buffer = this.buffer; + this.buffer = []; + this.destination.next(buffer); + }; + return BufferSubscriber; +}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); +//# sourceMappingURL=buffer.js.map /***/ }), -/* 453 */ +/* 404 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mergeScan", function() { return mergeScan; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MergeScanOperator", function() { return MergeScanOperator; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MergeScanSubscriber", function() { return MergeScanSubscriber; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "bufferCount", function() { return bufferCount; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(70); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(69); -/* harmony import */ var _InnerSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(71); -/** PURE_IMPORTS_START tslib,_util_subscribeToResult,_OuterSubscriber,_InnerSubscriber PURE_IMPORTS_END */ - - +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ -function mergeScan(accumulator, seed, concurrent) { - if (concurrent === void 0) { - concurrent = Number.POSITIVE_INFINITY; +function bufferCount(bufferSize, startBufferEvery) { + if (startBufferEvery === void 0) { + startBufferEvery = null; } - return function (source) { return source.lift(new MergeScanOperator(accumulator, seed, concurrent)); }; + return function bufferCountOperatorFunction(source) { + return source.lift(new BufferCountOperator(bufferSize, startBufferEvery)); + }; } -var MergeScanOperator = /*@__PURE__*/ (function () { - function MergeScanOperator(accumulator, seed, concurrent) { - this.accumulator = accumulator; - this.seed = seed; - this.concurrent = concurrent; +var BufferCountOperator = /*@__PURE__*/ (function () { + function BufferCountOperator(bufferSize, startBufferEvery) { + this.bufferSize = bufferSize; + this.startBufferEvery = startBufferEvery; + if (!startBufferEvery || bufferSize === startBufferEvery) { + this.subscriberClass = BufferCountSubscriber; + } + else { + this.subscriberClass = BufferSkipCountSubscriber; + } } - MergeScanOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new MergeScanSubscriber(subscriber, this.accumulator, this.seed, this.concurrent)); + BufferCountOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new this.subscriberClass(subscriber, this.bufferSize, this.startBufferEvery)); }; - return MergeScanOperator; + return BufferCountOperator; }()); - -var MergeScanSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](MergeScanSubscriber, _super); - function MergeScanSubscriber(destination, accumulator, acc, concurrent) { +var BufferCountSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](BufferCountSubscriber, _super); + function BufferCountSubscriber(destination, bufferSize) { var _this = _super.call(this, destination) || this; - _this.accumulator = accumulator; - _this.acc = acc; - _this.concurrent = concurrent; - _this.hasValue = false; - _this.hasCompleted = false; + _this.bufferSize = bufferSize; _this.buffer = []; - _this.active = 0; - _this.index = 0; return _this; } - MergeScanSubscriber.prototype._next = function (value) { - if (this.active < this.concurrent) { - var index = this.index++; - var destination = this.destination; - var ish = void 0; - try { - var accumulator = this.accumulator; - ish = accumulator(this.acc, value, index); - } - catch (e) { - return destination.error(e); - } - this.active++; - this._innerSub(ish, value, index); - } - else { - this.buffer.push(value); + BufferCountSubscriber.prototype._next = function (value) { + var buffer = this.buffer; + buffer.push(value); + if (buffer.length == this.bufferSize) { + this.destination.next(buffer); + this.buffer = []; } }; - MergeScanSubscriber.prototype._innerSub = function (ish, value, index) { - var innerSubscriber = new _InnerSubscriber__WEBPACK_IMPORTED_MODULE_3__["InnerSubscriber"](this, value, index); - var destination = this.destination; - destination.add(innerSubscriber); - var innerSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_1__["subscribeToResult"])(this, ish, undefined, undefined, innerSubscriber); - if (innerSubscription !== innerSubscriber) { - destination.add(innerSubscription); + BufferCountSubscriber.prototype._complete = function () { + var buffer = this.buffer; + if (buffer.length > 0) { + this.destination.next(buffer); } + _super.prototype._complete.call(this); }; - MergeScanSubscriber.prototype._complete = function () { - this.hasCompleted = true; - if (this.active === 0 && this.buffer.length === 0) { - if (this.hasValue === false) { - this.destination.next(this.acc); + return BufferCountSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +var BufferSkipCountSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](BufferSkipCountSubscriber, _super); + function BufferSkipCountSubscriber(destination, bufferSize, startBufferEvery) { + var _this = _super.call(this, destination) || this; + _this.bufferSize = bufferSize; + _this.startBufferEvery = startBufferEvery; + _this.buffers = []; + _this.count = 0; + return _this; + } + BufferSkipCountSubscriber.prototype._next = function (value) { + var _a = this, bufferSize = _a.bufferSize, startBufferEvery = _a.startBufferEvery, buffers = _a.buffers, count = _a.count; + this.count++; + if (count % startBufferEvery === 0) { + buffers.push([]); + } + for (var i = buffers.length; i--;) { + var buffer = buffers[i]; + buffer.push(value); + if (buffer.length === bufferSize) { + buffers.splice(i, 1); + this.destination.next(buffer); } - this.destination.complete(); } - this.unsubscribe(); }; - MergeScanSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { - var destination = this.destination; - this.acc = innerValue; - this.hasValue = true; - destination.next(innerValue); - }; - MergeScanSubscriber.prototype.notifyComplete = function (innerSub) { - var buffer = this.buffer; - var destination = this.destination; - destination.remove(innerSub); - this.active--; - if (buffer.length > 0) { - this._next(buffer.shift()); - } - else if (this.active === 0 && this.hasCompleted) { - if (this.hasValue === false) { - this.destination.next(this.acc); + BufferSkipCountSubscriber.prototype._complete = function () { + var _a = this, buffers = _a.buffers, destination = _a.destination; + while (buffers.length > 0) { + var buffer = buffers.shift(); + if (buffer.length > 0) { + destination.next(buffer); } - this.destination.complete(); } + _super.prototype._complete.call(this); }; - return MergeScanSubscriber; -}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__["OuterSubscriber"])); - -//# sourceMappingURL=mergeScan.js.map + return BufferSkipCountSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +//# sourceMappingURL=bufferCount.js.map /***/ }), -/* 454 */ +/* 405 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "min", function() { return min; }); -/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(449); -/** PURE_IMPORTS_START _reduce PURE_IMPORTS_END */ - -function min(comparer) { - var min = (typeof comparer === 'function') - ? function (x, y) { return comparer(x, y) < 0 ? x : y; } - : function (x, y) { return x < y ? x : y; }; - return Object(_reduce__WEBPACK_IMPORTED_MODULE_0__["reduce"])(min); -} -//# sourceMappingURL=min.js.map +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "bufferTime", function() { return bufferTime; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(55); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(11); +/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(45); +/** PURE_IMPORTS_START tslib,_scheduler_async,_Subscriber,_util_isScheduler PURE_IMPORTS_END */ -/***/ }), -/* 455 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "multicast", function() { return multicast; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MulticastOperator", function() { return MulticastOperator; }); -/* harmony import */ var _observable_ConnectableObservable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(26); -/** PURE_IMPORTS_START _observable_ConnectableObservable PURE_IMPORTS_END */ -function multicast(subjectOrSubjectFactory, selector) { - return function multicastOperatorFunction(source) { - var subjectFactory; - if (typeof subjectOrSubjectFactory === 'function') { - subjectFactory = subjectOrSubjectFactory; +function bufferTime(bufferTimeSpan) { + var length = arguments.length; + var scheduler = _scheduler_async__WEBPACK_IMPORTED_MODULE_1__["async"]; + if (Object(_util_isScheduler__WEBPACK_IMPORTED_MODULE_3__["isScheduler"])(arguments[arguments.length - 1])) { + scheduler = arguments[arguments.length - 1]; + length--; + } + var bufferCreationInterval = null; + if (length >= 2) { + bufferCreationInterval = arguments[1]; + } + var maxBufferSize = Number.POSITIVE_INFINITY; + if (length >= 3) { + maxBufferSize = arguments[2]; + } + return function bufferTimeOperatorFunction(source) { + return source.lift(new BufferTimeOperator(bufferTimeSpan, bufferCreationInterval, maxBufferSize, scheduler)); + }; +} +var BufferTimeOperator = /*@__PURE__*/ (function () { + function BufferTimeOperator(bufferTimeSpan, bufferCreationInterval, maxBufferSize, scheduler) { + this.bufferTimeSpan = bufferTimeSpan; + this.bufferCreationInterval = bufferCreationInterval; + this.maxBufferSize = maxBufferSize; + this.scheduler = scheduler; + } + BufferTimeOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new BufferTimeSubscriber(subscriber, this.bufferTimeSpan, this.bufferCreationInterval, this.maxBufferSize, this.scheduler)); + }; + return BufferTimeOperator; +}()); +var Context = /*@__PURE__*/ (function () { + function Context() { + this.buffer = []; + } + return Context; +}()); +var BufferTimeSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](BufferTimeSubscriber, _super); + function BufferTimeSubscriber(destination, bufferTimeSpan, bufferCreationInterval, maxBufferSize, scheduler) { + var _this = _super.call(this, destination) || this; + _this.bufferTimeSpan = bufferTimeSpan; + _this.bufferCreationInterval = bufferCreationInterval; + _this.maxBufferSize = maxBufferSize; + _this.scheduler = scheduler; + _this.contexts = []; + var context = _this.openContext(); + _this.timespanOnly = bufferCreationInterval == null || bufferCreationInterval < 0; + if (_this.timespanOnly) { + var timeSpanOnlyState = { subscriber: _this, context: context, bufferTimeSpan: bufferTimeSpan }; + _this.add(context.closeAction = scheduler.schedule(dispatchBufferTimeSpanOnly, bufferTimeSpan, timeSpanOnlyState)); } else { - subjectFactory = function subjectFactory() { - return subjectOrSubjectFactory; - }; + var closeState = { subscriber: _this, context: context }; + var creationState = { bufferTimeSpan: bufferTimeSpan, bufferCreationInterval: bufferCreationInterval, subscriber: _this, scheduler: scheduler }; + _this.add(context.closeAction = scheduler.schedule(dispatchBufferClose, bufferTimeSpan, closeState)); + _this.add(scheduler.schedule(dispatchBufferCreation, bufferCreationInterval, creationState)); } - if (typeof selector === 'function') { - return source.lift(new MulticastOperator(subjectFactory, selector)); + return _this; + } + BufferTimeSubscriber.prototype._next = function (value) { + var contexts = this.contexts; + var len = contexts.length; + var filledBufferContext; + for (var i = 0; i < len; i++) { + var context_1 = contexts[i]; + var buffer = context_1.buffer; + buffer.push(value); + if (buffer.length == this.maxBufferSize) { + filledBufferContext = context_1; + } } - var connectable = Object.create(source, _observable_ConnectableObservable__WEBPACK_IMPORTED_MODULE_0__["connectableObservableDescriptor"]); - connectable.source = source; - connectable.subjectFactory = subjectFactory; - return connectable; + if (filledBufferContext) { + this.onBufferFull(filledBufferContext); + } + }; + BufferTimeSubscriber.prototype._error = function (err) { + this.contexts.length = 0; + _super.prototype._error.call(this, err); + }; + BufferTimeSubscriber.prototype._complete = function () { + var _a = this, contexts = _a.contexts, destination = _a.destination; + while (contexts.length > 0) { + var context_2 = contexts.shift(); + destination.next(context_2.buffer); + } + _super.prototype._complete.call(this); + }; + BufferTimeSubscriber.prototype._unsubscribe = function () { + this.contexts = null; + }; + BufferTimeSubscriber.prototype.onBufferFull = function (context) { + this.closeContext(context); + var closeAction = context.closeAction; + closeAction.unsubscribe(); + this.remove(closeAction); + if (!this.closed && this.timespanOnly) { + context = this.openContext(); + var bufferTimeSpan = this.bufferTimeSpan; + var timeSpanOnlyState = { subscriber: this, context: context, bufferTimeSpan: bufferTimeSpan }; + this.add(context.closeAction = this.scheduler.schedule(dispatchBufferTimeSpanOnly, bufferTimeSpan, timeSpanOnlyState)); + } + }; + BufferTimeSubscriber.prototype.openContext = function () { + var context = new Context(); + this.contexts.push(context); + return context; }; + BufferTimeSubscriber.prototype.closeContext = function (context) { + this.destination.next(context.buffer); + var contexts = this.contexts; + var spliceIndex = contexts ? contexts.indexOf(context) : -1; + if (spliceIndex >= 0) { + contexts.splice(contexts.indexOf(context), 1); + } + }; + return BufferTimeSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_2__["Subscriber"])); +function dispatchBufferTimeSpanOnly(state) { + var subscriber = state.subscriber; + var prevContext = state.context; + if (prevContext) { + subscriber.closeContext(prevContext); + } + if (!subscriber.closed) { + state.context = subscriber.openContext(); + state.context.closeAction = this.schedule(state, state.bufferTimeSpan); + } } -var MulticastOperator = /*@__PURE__*/ (function () { - function MulticastOperator(subjectFactory, selector) { - this.subjectFactory = subjectFactory; - this.selector = selector; +function dispatchBufferCreation(state) { + var bufferCreationInterval = state.bufferCreationInterval, bufferTimeSpan = state.bufferTimeSpan, subscriber = state.subscriber, scheduler = state.scheduler; + var context = subscriber.openContext(); + var action = this; + if (!subscriber.closed) { + subscriber.add(context.closeAction = scheduler.schedule(dispatchBufferClose, bufferTimeSpan, { subscriber: subscriber, context: context })); + action.schedule(state, bufferCreationInterval); } - MulticastOperator.prototype.call = function (subscriber, source) { - var selector = this.selector; - var subject = this.subjectFactory(); - var subscription = selector(subject).subscribe(subscriber); - subscription.add(source.subscribe(subject)); - return subscription; - }; - return MulticastOperator; -}()); - -//# sourceMappingURL=multicast.js.map +} +function dispatchBufferClose(arg) { + var subscriber = arg.subscriber, context = arg.context; + subscriber.closeContext(context); +} +//# sourceMappingURL=bufferTime.js.map /***/ }), -/* 456 */ +/* 406 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "onErrorResumeNext", function() { return onErrorResumeNext; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "onErrorResumeNextStatic", function() { return onErrorResumeNextStatic; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "bufferToggle", function() { return bufferToggle; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _observable_from__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(83); -/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(18); +/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(17); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(70); /* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(69); -/* harmony import */ var _InnerSubscriber__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(71); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(70); -/** PURE_IMPORTS_START tslib,_observable_from,_util_isArray,_OuterSubscriber,_InnerSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ - - +/** PURE_IMPORTS_START tslib,_Subscription,_util_subscribeToResult,_OuterSubscriber PURE_IMPORTS_END */ -function onErrorResumeNext() { - var nextSources = []; - for (var _i = 0; _i < arguments.length; _i++) { - nextSources[_i] = arguments[_i]; - } - if (nextSources.length === 1 && Object(_util_isArray__WEBPACK_IMPORTED_MODULE_2__["isArray"])(nextSources[0])) { - nextSources = nextSources[0]; - } - return function (source) { return source.lift(new OnErrorResumeNextOperator(nextSources)); }; -} -function onErrorResumeNextStatic() { - var nextSources = []; - for (var _i = 0; _i < arguments.length; _i++) { - nextSources[_i] = arguments[_i]; - } - var source = null; - if (nextSources.length === 1 && Object(_util_isArray__WEBPACK_IMPORTED_MODULE_2__["isArray"])(nextSources[0])) { - nextSources = nextSources[0]; - } - source = nextSources.shift(); - return Object(_observable_from__WEBPACK_IMPORTED_MODULE_1__["from"])(source, null).lift(new OnErrorResumeNextOperator(nextSources)); +function bufferToggle(openings, closingSelector) { + return function bufferToggleOperatorFunction(source) { + return source.lift(new BufferToggleOperator(openings, closingSelector)); + }; } -var OnErrorResumeNextOperator = /*@__PURE__*/ (function () { - function OnErrorResumeNextOperator(nextSources) { - this.nextSources = nextSources; +var BufferToggleOperator = /*@__PURE__*/ (function () { + function BufferToggleOperator(openings, closingSelector) { + this.openings = openings; + this.closingSelector = closingSelector; } - OnErrorResumeNextOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new OnErrorResumeNextSubscriber(subscriber, this.nextSources)); + BufferToggleOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new BufferToggleSubscriber(subscriber, this.openings, this.closingSelector)); }; - return OnErrorResumeNextOperator; + return BufferToggleOperator; }()); -var OnErrorResumeNextSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](OnErrorResumeNextSubscriber, _super); - function OnErrorResumeNextSubscriber(destination, nextSources) { +var BufferToggleSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](BufferToggleSubscriber, _super); + function BufferToggleSubscriber(destination, openings, closingSelector) { var _this = _super.call(this, destination) || this; - _this.destination = destination; - _this.nextSources = nextSources; + _this.openings = openings; + _this.closingSelector = closingSelector; + _this.contexts = []; + _this.add(Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(_this, openings)); return _this; } - OnErrorResumeNextSubscriber.prototype.notifyError = function (error, innerSub) { - this.subscribeToNextSource(); + BufferToggleSubscriber.prototype._next = function (value) { + var contexts = this.contexts; + var len = contexts.length; + for (var i = 0; i < len; i++) { + contexts[i].buffer.push(value); + } }; - OnErrorResumeNextSubscriber.prototype.notifyComplete = function (innerSub) { - this.subscribeToNextSource(); + BufferToggleSubscriber.prototype._error = function (err) { + var contexts = this.contexts; + while (contexts.length > 0) { + var context_1 = contexts.shift(); + context_1.subscription.unsubscribe(); + context_1.buffer = null; + context_1.subscription = null; + } + this.contexts = null; + _super.prototype._error.call(this, err); }; - OnErrorResumeNextSubscriber.prototype._error = function (err) { - this.subscribeToNextSource(); - this.unsubscribe(); + BufferToggleSubscriber.prototype._complete = function () { + var contexts = this.contexts; + while (contexts.length > 0) { + var context_2 = contexts.shift(); + this.destination.next(context_2.buffer); + context_2.subscription.unsubscribe(); + context_2.buffer = null; + context_2.subscription = null; + } + this.contexts = null; + _super.prototype._complete.call(this); }; - OnErrorResumeNextSubscriber.prototype._complete = function () { - this.subscribeToNextSource(); - this.unsubscribe(); + BufferToggleSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + outerValue ? this.closeBuffer(outerValue) : this.openBuffer(innerValue); }; - OnErrorResumeNextSubscriber.prototype.subscribeToNextSource = function () { - var next = this.nextSources.shift(); - if (!!next) { - var innerSubscriber = new _InnerSubscriber__WEBPACK_IMPORTED_MODULE_4__["InnerSubscriber"](this, undefined, undefined); - var destination = this.destination; - destination.add(innerSubscriber); - var innerSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_5__["subscribeToResult"])(this, next, undefined, undefined, innerSubscriber); - if (innerSubscription !== innerSubscriber) { - destination.add(innerSubscription); + BufferToggleSubscriber.prototype.notifyComplete = function (innerSub) { + this.closeBuffer(innerSub.context); + }; + BufferToggleSubscriber.prototype.openBuffer = function (value) { + try { + var closingSelector = this.closingSelector; + var closingNotifier = closingSelector.call(this, value); + if (closingNotifier) { + this.trySubscribe(closingNotifier); } } + catch (err) { + this._error(err); + } + }; + BufferToggleSubscriber.prototype.closeBuffer = function (context) { + var contexts = this.contexts; + if (contexts && context) { + var buffer = context.buffer, subscription = context.subscription; + this.destination.next(buffer); + contexts.splice(contexts.indexOf(context), 1); + this.remove(subscription); + subscription.unsubscribe(); + } + }; + BufferToggleSubscriber.prototype.trySubscribe = function (closingNotifier) { + var contexts = this.contexts; + var buffer = []; + var subscription = new _Subscription__WEBPACK_IMPORTED_MODULE_1__["Subscription"](); + var context = { buffer: buffer, subscription: subscription }; + contexts.push(context); + var innerSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(this, closingNotifier, context); + if (!innerSubscription || innerSubscription.closed) { + this.closeBuffer(context); + } else { - this.destination.complete(); + innerSubscription.context = context; + this.add(innerSubscription); + subscription.add(innerSubscription); } }; - return OnErrorResumeNextSubscriber; + return BufferToggleSubscriber; }(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__["OuterSubscriber"])); -//# sourceMappingURL=onErrorResumeNext.js.map +//# sourceMappingURL=bufferToggle.js.map /***/ }), -/* 457 */ +/* 407 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "pairwise", function() { return pairwise; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "bufferWhen", function() { return bufferWhen; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ +/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(17); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(69); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(70); +/** PURE_IMPORTS_START tslib,_Subscription,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ -function pairwise() { - return function (source) { return source.lift(new PairwiseOperator()); }; + + +function bufferWhen(closingSelector) { + return function (source) { + return source.lift(new BufferWhenOperator(closingSelector)); + }; } -var PairwiseOperator = /*@__PURE__*/ (function () { - function PairwiseOperator() { +var BufferWhenOperator = /*@__PURE__*/ (function () { + function BufferWhenOperator(closingSelector) { + this.closingSelector = closingSelector; } - PairwiseOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new PairwiseSubscriber(subscriber)); + BufferWhenOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new BufferWhenSubscriber(subscriber, this.closingSelector)); }; - return PairwiseOperator; + return BufferWhenOperator; }()); -var PairwiseSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](PairwiseSubscriber, _super); - function PairwiseSubscriber(destination) { +var BufferWhenSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](BufferWhenSubscriber, _super); + function BufferWhenSubscriber(destination, closingSelector) { var _this = _super.call(this, destination) || this; - _this.hasPrev = false; + _this.closingSelector = closingSelector; + _this.subscribing = false; + _this.openBuffer(); return _this; } - PairwiseSubscriber.prototype._next = function (value) { - var pair; - if (this.hasPrev) { - pair = [this.prev, value]; + BufferWhenSubscriber.prototype._next = function (value) { + this.buffer.push(value); + }; + BufferWhenSubscriber.prototype._complete = function () { + var buffer = this.buffer; + if (buffer) { + this.destination.next(buffer); + } + _super.prototype._complete.call(this); + }; + BufferWhenSubscriber.prototype._unsubscribe = function () { + this.buffer = null; + this.subscribing = false; + }; + BufferWhenSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + this.openBuffer(); + }; + BufferWhenSubscriber.prototype.notifyComplete = function () { + if (this.subscribing) { + this.complete(); } else { - this.hasPrev = true; + this.openBuffer(); } - this.prev = value; - if (pair) { - this.destination.next(pair); + }; + BufferWhenSubscriber.prototype.openBuffer = function () { + var closingSubscription = this.closingSubscription; + if (closingSubscription) { + this.remove(closingSubscription); + closingSubscription.unsubscribe(); + } + var buffer = this.buffer; + if (this.buffer) { + this.destination.next(buffer); + } + this.buffer = []; + var closingNotifier; + try { + var closingSelector = this.closingSelector; + closingNotifier = closingSelector(); + } + catch (err) { + return this.error(err); } + closingSubscription = new _Subscription__WEBPACK_IMPORTED_MODULE_1__["Subscription"](); + this.closingSubscription = closingSubscription; + this.add(closingSubscription); + this.subscribing = true; + closingSubscription.add(Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__["subscribeToResult"])(this, closingNotifier)); + this.subscribing = false; }; - return PairwiseSubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=pairwise.js.map + return BufferWhenSubscriber; +}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__["OuterSubscriber"])); +//# sourceMappingURL=bufferWhen.js.map /***/ }), -/* 458 */ +/* 408 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "partition", function() { return partition; }); -/* harmony import */ var _util_not__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(103); -/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(104); -/** PURE_IMPORTS_START _util_not,_filter PURE_IMPORTS_END */ - - -function partition(predicate, thisArg) { - return function (source) { - return [ - Object(_filter__WEBPACK_IMPORTED_MODULE_1__["filter"])(predicate, thisArg)(source), - Object(_filter__WEBPACK_IMPORTED_MODULE_1__["filter"])(Object(_util_not__WEBPACK_IMPORTED_MODULE_0__["not"])(predicate, thisArg))(source) - ]; - }; -} -//# sourceMappingURL=partition.js.map +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "catchError", function() { return catchError; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); +/* harmony import */ var _InnerSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(70); +/** PURE_IMPORTS_START tslib,_OuterSubscriber,_InnerSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ -/***/ }), -/* 459 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "pluck", function() { return pluck; }); -/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(66); -/** PURE_IMPORTS_START _map PURE_IMPORTS_END */ -function pluck() { - var properties = []; - for (var _i = 0; _i < arguments.length; _i++) { - properties[_i] = arguments[_i]; +function catchError(selector) { + return function catchErrorOperatorFunction(source) { + var operator = new CatchOperator(selector); + var caught = source.lift(operator); + return (operator.caught = caught); + }; +} +var CatchOperator = /*@__PURE__*/ (function () { + function CatchOperator(selector) { + this.selector = selector; } - var length = properties.length; - if (length === 0) { - throw new Error('list of properties cannot be empty.'); + CatchOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new CatchSubscriber(subscriber, this.selector, this.caught)); + }; + return CatchOperator; +}()); +var CatchSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](CatchSubscriber, _super); + function CatchSubscriber(destination, selector, caught) { + var _this = _super.call(this, destination) || this; + _this.selector = selector; + _this.caught = caught; + return _this; } - return function (source) { return Object(_map__WEBPACK_IMPORTED_MODULE_0__["map"])(plucker(properties, length))(source); }; -} -function plucker(props, length) { - var mapper = function (x) { - var currentProp = x; - for (var i = 0; i < length; i++) { - var p = currentProp[props[i]]; - if (typeof p !== 'undefined') { - currentProp = p; + CatchSubscriber.prototype.error = function (err) { + if (!this.isStopped) { + var result = void 0; + try { + result = this.selector(err, this.caught); } - else { - return undefined; + catch (err2) { + _super.prototype.error.call(this, err2); + return; + } + this._unsubscribeAndRecycle(); + var innerSubscriber = new _InnerSubscriber__WEBPACK_IMPORTED_MODULE_2__["InnerSubscriber"](this, undefined, undefined); + this.add(innerSubscriber); + var innerSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__["subscribeToResult"])(this, result, undefined, undefined, innerSubscriber); + if (innerSubscription !== innerSubscriber) { + this.add(innerSubscription); } } - return currentProp; }; - return mapper; -} -//# sourceMappingURL=pluck.js.map - - -/***/ }), -/* 460 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publish", function() { return publish; }); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(27); -/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(455); -/** PURE_IMPORTS_START _Subject,_multicast PURE_IMPORTS_END */ - - -function publish(selector) { - return selector ? - Object(_multicast__WEBPACK_IMPORTED_MODULE_1__["multicast"])(function () { return new _Subject__WEBPACK_IMPORTED_MODULE_0__["Subject"](); }, selector) : - Object(_multicast__WEBPACK_IMPORTED_MODULE_1__["multicast"])(new _Subject__WEBPACK_IMPORTED_MODULE_0__["Subject"]()); -} -//# sourceMappingURL=publish.js.map - - -/***/ }), -/* 461 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publishBehavior", function() { return publishBehavior; }); -/* harmony import */ var _BehaviorSubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(32); -/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(455); -/** PURE_IMPORTS_START _BehaviorSubject,_multicast PURE_IMPORTS_END */ - - -function publishBehavior(value) { - return function (source) { return Object(_multicast__WEBPACK_IMPORTED_MODULE_1__["multicast"])(new _BehaviorSubject__WEBPACK_IMPORTED_MODULE_0__["BehaviorSubject"](value))(source); }; -} -//# sourceMappingURL=publishBehavior.js.map - - -/***/ }), -/* 462 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publishLast", function() { return publishLast; }); -/* harmony import */ var _AsyncSubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(50); -/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(455); -/** PURE_IMPORTS_START _AsyncSubject,_multicast PURE_IMPORTS_END */ - - -function publishLast() { - return function (source) { return Object(_multicast__WEBPACK_IMPORTED_MODULE_1__["multicast"])(new _AsyncSubject__WEBPACK_IMPORTED_MODULE_0__["AsyncSubject"]())(source); }; -} -//# sourceMappingURL=publishLast.js.map + return CatchSubscriber; +}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); +//# sourceMappingURL=catchError.js.map /***/ }), -/* 463 */ +/* 409 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publishReplay", function() { return publishReplay; }); -/* harmony import */ var _ReplaySubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(33); -/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(455); -/** PURE_IMPORTS_START _ReplaySubject,_multicast PURE_IMPORTS_END */ - +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "combineAll", function() { return combineAll; }); +/* harmony import */ var _observable_combineLatest__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(68); +/** PURE_IMPORTS_START _observable_combineLatest PURE_IMPORTS_END */ -function publishReplay(bufferSize, windowTime, selectorOrScheduler, scheduler) { - if (selectorOrScheduler && typeof selectorOrScheduler !== 'function') { - scheduler = selectorOrScheduler; - } - var selector = typeof selectorOrScheduler === 'function' ? selectorOrScheduler : undefined; - var subject = new _ReplaySubject__WEBPACK_IMPORTED_MODULE_0__["ReplaySubject"](bufferSize, windowTime, scheduler); - return function (source) { return Object(_multicast__WEBPACK_IMPORTED_MODULE_1__["multicast"])(function () { return subject; }, selector)(source); }; +function combineAll(project) { + return function (source) { return source.lift(new _observable_combineLatest__WEBPACK_IMPORTED_MODULE_0__["CombineLatestOperator"](project)); }; } -//# sourceMappingURL=publishReplay.js.map +//# sourceMappingURL=combineAll.js.map /***/ }), -/* 464 */ +/* 410 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "race", function() { return race; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "combineLatest", function() { return combineLatest; }); /* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(18); -/* harmony import */ var _observable_race__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(105); -/** PURE_IMPORTS_START _util_isArray,_observable_race PURE_IMPORTS_END */ +/* harmony import */ var _observable_combineLatest__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(68); +/* harmony import */ var _observable_from__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(83); +/** PURE_IMPORTS_START _util_isArray,_observable_combineLatest,_observable_from PURE_IMPORTS_END */ -function race() { + +var none = {}; +function combineLatest() { var observables = []; for (var _i = 0; _i < arguments.length; _i++) { observables[_i] = arguments[_i]; } - return function raceOperatorFunction(source) { - if (observables.length === 1 && Object(_util_isArray__WEBPACK_IMPORTED_MODULE_0__["isArray"])(observables[0])) { - observables = observables[0]; - } - return source.lift.call(_observable_race__WEBPACK_IMPORTED_MODULE_1__["race"].apply(void 0, [source].concat(observables))); - }; -} -//# sourceMappingURL=race.js.map - - -/***/ }), -/* 465 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "repeat", function() { return repeat; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/* harmony import */ var _observable_empty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(43); -/** PURE_IMPORTS_START tslib,_Subscriber,_observable_empty PURE_IMPORTS_END */ - - - -function repeat(count) { - if (count === void 0) { - count = -1; - } - return function (source) { - if (count === 0) { - return Object(_observable_empty__WEBPACK_IMPORTED_MODULE_2__["empty"])(); - } - else if (count < 0) { - return source.lift(new RepeatOperator(-1, source)); - } - else { - return source.lift(new RepeatOperator(count - 1, source)); - } - }; -} -var RepeatOperator = /*@__PURE__*/ (function () { - function RepeatOperator(count, source) { - this.count = count; - this.source = source; + var project = null; + if (typeof observables[observables.length - 1] === 'function') { + project = observables.pop(); } - RepeatOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new RepeatSubscriber(subscriber, this.count, this.source)); - }; - return RepeatOperator; -}()); -var RepeatSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](RepeatSubscriber, _super); - function RepeatSubscriber(destination, count, source) { - var _this = _super.call(this, destination) || this; - _this.count = count; - _this.source = source; - return _this; + if (observables.length === 1 && Object(_util_isArray__WEBPACK_IMPORTED_MODULE_0__["isArray"])(observables[0])) { + observables = observables[0].slice(); } - RepeatSubscriber.prototype.complete = function () { - if (!this.isStopped) { - var _a = this, source = _a.source, count = _a.count; - if (count === 0) { - return _super.prototype.complete.call(this); - } - else if (count > -1) { - this.count = count - 1; - } - source.subscribe(this._unsubscribeAndRecycle()); - } - }; - return RepeatSubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=repeat.js.map + return function (source) { return source.lift.call(Object(_observable_from__WEBPACK_IMPORTED_MODULE_2__["from"])([source].concat(observables)), new _observable_combineLatest__WEBPACK_IMPORTED_MODULE_1__["CombineLatestOperator"](project)); }; +} +//# sourceMappingURL=combineLatest.js.map /***/ }), -/* 466 */ +/* 411 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "repeatWhen", function() { return repeatWhen; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(27); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(69); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(70); -/** PURE_IMPORTS_START tslib,_Subject,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ - - - +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "concat", function() { return concat; }); +/* harmony import */ var _observable_concat__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(79); +/** PURE_IMPORTS_START _observable_concat PURE_IMPORTS_END */ -function repeatWhen(notifier) { - return function (source) { return source.lift(new RepeatWhenOperator(notifier)); }; -} -var RepeatWhenOperator = /*@__PURE__*/ (function () { - function RepeatWhenOperator(notifier) { - this.notifier = notifier; - } - RepeatWhenOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new RepeatWhenSubscriber(subscriber, this.notifier, source)); - }; - return RepeatWhenOperator; -}()); -var RepeatWhenSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](RepeatWhenSubscriber, _super); - function RepeatWhenSubscriber(destination, notifier, source) { - var _this = _super.call(this, destination) || this; - _this.notifier = notifier; - _this.source = source; - _this.sourceIsBeingSubscribedTo = true; - return _this; +function concat() { + var observables = []; + for (var _i = 0; _i < arguments.length; _i++) { + observables[_i] = arguments[_i]; } - RepeatWhenSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { - this.sourceIsBeingSubscribedTo = true; - this.source.subscribe(this); - }; - RepeatWhenSubscriber.prototype.notifyComplete = function (innerSub) { - if (this.sourceIsBeingSubscribedTo === false) { - return _super.prototype.complete.call(this); - } - }; - RepeatWhenSubscriber.prototype.complete = function () { - this.sourceIsBeingSubscribedTo = false; - if (!this.isStopped) { - if (!this.retries) { - this.subscribeToRetries(); - } - if (!this.retriesSubscription || this.retriesSubscription.closed) { - return _super.prototype.complete.call(this); - } - this._unsubscribeAndRecycle(); - this.notifications.next(); - } - }; - RepeatWhenSubscriber.prototype._unsubscribe = function () { - var _a = this, notifications = _a.notifications, retriesSubscription = _a.retriesSubscription; - if (notifications) { - notifications.unsubscribe(); - this.notifications = null; - } - if (retriesSubscription) { - retriesSubscription.unsubscribe(); - this.retriesSubscription = null; - } - this.retries = null; - }; - RepeatWhenSubscriber.prototype._unsubscribeAndRecycle = function () { - var _unsubscribe = this._unsubscribe; - this._unsubscribe = null; - _super.prototype._unsubscribeAndRecycle.call(this); - this._unsubscribe = _unsubscribe; - return this; - }; - RepeatWhenSubscriber.prototype.subscribeToRetries = function () { - this.notifications = new _Subject__WEBPACK_IMPORTED_MODULE_1__["Subject"](); - var retries; - try { - var notifier = this.notifier; - retries = notifier(this.notifications); - } - catch (e) { - return _super.prototype.complete.call(this); - } - this.retries = retries; - this.retriesSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__["subscribeToResult"])(this, retries); - }; - return RepeatWhenSubscriber; -}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__["OuterSubscriber"])); -//# sourceMappingURL=repeatWhen.js.map + return function (source) { return source.lift.call(_observable_concat__WEBPACK_IMPORTED_MODULE_0__["concat"].apply(void 0, [source].concat(observables))); }; +} +//# sourceMappingURL=concat.js.map /***/ }), -/* 467 */ +/* 412 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "retry", function() { return retry; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ - - -function retry(count) { - if (count === void 0) { - count = -1; - } - return function (source) { return source.lift(new RetryOperator(count, source)); }; -} -var RetryOperator = /*@__PURE__*/ (function () { - function RetryOperator(count, source) { - this.count = count; - this.source = source; - } - RetryOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new RetrySubscriber(subscriber, this.count, this.source)); - }; - return RetryOperator; -}()); -var RetrySubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](RetrySubscriber, _super); - function RetrySubscriber(destination, count, source) { - var _this = _super.call(this, destination) || this; - _this.count = count; - _this.source = source; - return _this; - } - RetrySubscriber.prototype.error = function (err) { - if (!this.isStopped) { - var _a = this, source = _a.source, count = _a.count; - if (count === 0) { - return _super.prototype.error.call(this, err); - } - else if (count > -1) { - this.count = count - 1; - } - source.subscribe(this._unsubscribeAndRecycle()); - } - }; - return RetrySubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=retry.js.map +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "concatMap", function() { return concatMap; }); +/* harmony import */ var _mergeMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(82); +/** PURE_IMPORTS_START _mergeMap PURE_IMPORTS_END */ + +function concatMap(project, resultSelector) { + return Object(_mergeMap__WEBPACK_IMPORTED_MODULE_0__["mergeMap"])(project, resultSelector, 1); +} +//# sourceMappingURL=concatMap.js.map /***/ }), -/* 468 */ +/* 413 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "retryWhen", function() { return retryWhen; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(27); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(69); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(70); -/** PURE_IMPORTS_START tslib,_Subject,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "concatMapTo", function() { return concatMapTo; }); +/* harmony import */ var _concatMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(412); +/** PURE_IMPORTS_START _concatMap PURE_IMPORTS_END */ +function concatMapTo(innerObservable, resultSelector) { + return Object(_concatMap__WEBPACK_IMPORTED_MODULE_0__["concatMap"])(function () { return innerObservable; }, resultSelector); +} +//# sourceMappingURL=concatMapTo.js.map +/***/ }), +/* 414 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -function retryWhen(notifier) { - return function (source) { return source.lift(new RetryWhenOperator(notifier, source)); }; +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "count", function() { return count; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ + + +function count(predicate) { + return function (source) { return source.lift(new CountOperator(predicate, source)); }; } -var RetryWhenOperator = /*@__PURE__*/ (function () { - function RetryWhenOperator(notifier, source) { - this.notifier = notifier; +var CountOperator = /*@__PURE__*/ (function () { + function CountOperator(predicate, source) { + this.predicate = predicate; this.source = source; } - RetryWhenOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new RetryWhenSubscriber(subscriber, this.notifier, this.source)); + CountOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new CountSubscriber(subscriber, this.predicate, this.source)); }; - return RetryWhenOperator; + return CountOperator; }()); -var RetryWhenSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](RetryWhenSubscriber, _super); - function RetryWhenSubscriber(destination, notifier, source) { +var CountSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](CountSubscriber, _super); + function CountSubscriber(destination, predicate, source) { var _this = _super.call(this, destination) || this; - _this.notifier = notifier; + _this.predicate = predicate; _this.source = source; + _this.count = 0; + _this.index = 0; return _this; } - RetryWhenSubscriber.prototype.error = function (err) { - if (!this.isStopped) { - var errors = this.errors; - var retries = this.retries; - var retriesSubscription = this.retriesSubscription; - if (!retries) { - errors = new _Subject__WEBPACK_IMPORTED_MODULE_1__["Subject"](); - try { - var notifier = this.notifier; - retries = notifier(errors); - } - catch (e) { - return _super.prototype.error.call(this, e); - } - retriesSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__["subscribeToResult"])(this, retries); - } - else { - this.errors = null; - this.retriesSubscription = null; - } - this._unsubscribeAndRecycle(); - this.errors = errors; - this.retries = retries; - this.retriesSubscription = retriesSubscription; - errors.next(err); + CountSubscriber.prototype._next = function (value) { + if (this.predicate) { + this._tryPredicate(value); + } + else { + this.count++; } }; - RetryWhenSubscriber.prototype._unsubscribe = function () { - var _a = this, errors = _a.errors, retriesSubscription = _a.retriesSubscription; - if (errors) { - errors.unsubscribe(); - this.errors = null; + CountSubscriber.prototype._tryPredicate = function (value) { + var result; + try { + result = this.predicate(value, this.index++, this.source); } - if (retriesSubscription) { - retriesSubscription.unsubscribe(); - this.retriesSubscription = null; + catch (err) { + this.destination.error(err); + return; + } + if (result) { + this.count++; } - this.retries = null; }; - RetryWhenSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { - var _unsubscribe = this._unsubscribe; - this._unsubscribe = null; - this._unsubscribeAndRecycle(); - this._unsubscribe = _unsubscribe; - this.source.subscribe(this); + CountSubscriber.prototype._complete = function () { + this.destination.next(this.count); + this.destination.complete(); }; - return RetryWhenSubscriber; -}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__["OuterSubscriber"])); -//# sourceMappingURL=retryWhen.js.map + return CountSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +//# sourceMappingURL=count.js.map /***/ }), -/* 469 */ +/* 415 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sample", function() { return sample; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "debounce", function() { return debounce; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); /* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); /* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(70); @@ -56758,56 +52575,87 @@ __webpack_require__.r(__webpack_exports__); -function sample(notifier) { - return function (source) { return source.lift(new SampleOperator(notifier)); }; +function debounce(durationSelector) { + return function (source) { return source.lift(new DebounceOperator(durationSelector)); }; } -var SampleOperator = /*@__PURE__*/ (function () { - function SampleOperator(notifier) { - this.notifier = notifier; +var DebounceOperator = /*@__PURE__*/ (function () { + function DebounceOperator(durationSelector) { + this.durationSelector = durationSelector; } - SampleOperator.prototype.call = function (subscriber, source) { - var sampleSubscriber = new SampleSubscriber(subscriber); - var subscription = source.subscribe(sampleSubscriber); - subscription.add(Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(sampleSubscriber, this.notifier)); - return subscription; + DebounceOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new DebounceSubscriber(subscriber, this.durationSelector)); }; - return SampleOperator; + return DebounceOperator; }()); -var SampleSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SampleSubscriber, _super); - function SampleSubscriber() { - var _this = _super !== null && _super.apply(this, arguments) || this; +var DebounceSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](DebounceSubscriber, _super); + function DebounceSubscriber(destination, durationSelector) { + var _this = _super.call(this, destination) || this; + _this.durationSelector = durationSelector; _this.hasValue = false; + _this.durationSubscription = null; return _this; } - SampleSubscriber.prototype._next = function (value) { + DebounceSubscriber.prototype._next = function (value) { + try { + var result = this.durationSelector.call(this, value); + if (result) { + this._tryNext(value, result); + } + } + catch (err) { + this.destination.error(err); + } + }; + DebounceSubscriber.prototype._complete = function () { + this.emitValue(); + this.destination.complete(); + }; + DebounceSubscriber.prototype._tryNext = function (value, duration) { + var subscription = this.durationSubscription; this.value = value; this.hasValue = true; + if (subscription) { + subscription.unsubscribe(); + this.remove(subscription); + } + subscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(this, duration); + if (subscription && !subscription.closed) { + this.add(this.durationSubscription = subscription); + } }; - SampleSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + DebounceSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { this.emitValue(); }; - SampleSubscriber.prototype.notifyComplete = function () { + DebounceSubscriber.prototype.notifyComplete = function () { this.emitValue(); }; - SampleSubscriber.prototype.emitValue = function () { + DebounceSubscriber.prototype.emitValue = function () { if (this.hasValue) { + var value = this.value; + var subscription = this.durationSubscription; + if (subscription) { + this.durationSubscription = null; + subscription.unsubscribe(); + this.remove(subscription); + } + this.value = null; this.hasValue = false; - this.destination.next(this.value); + _super.prototype._next.call(this, value); } }; - return SampleSubscriber; + return DebounceSubscriber; }(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); -//# sourceMappingURL=sample.js.map +//# sourceMappingURL=debounce.js.map /***/ }), -/* 470 */ +/* 416 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sampleTime", function() { return sampleTime; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "debounceTime", function() { return debounceTime; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); /* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); /* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(55); @@ -56815,823 +52663,839 @@ __webpack_require__.r(__webpack_exports__); -function sampleTime(period, scheduler) { +function debounceTime(dueTime, scheduler) { if (scheduler === void 0) { scheduler = _scheduler_async__WEBPACK_IMPORTED_MODULE_2__["async"]; } - return function (source) { return source.lift(new SampleTimeOperator(period, scheduler)); }; + return function (source) { return source.lift(new DebounceTimeOperator(dueTime, scheduler)); }; } -var SampleTimeOperator = /*@__PURE__*/ (function () { - function SampleTimeOperator(period, scheduler) { - this.period = period; +var DebounceTimeOperator = /*@__PURE__*/ (function () { + function DebounceTimeOperator(dueTime, scheduler) { + this.dueTime = dueTime; this.scheduler = scheduler; } - SampleTimeOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new SampleTimeSubscriber(subscriber, this.period, this.scheduler)); + DebounceTimeOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new DebounceTimeSubscriber(subscriber, this.dueTime, this.scheduler)); }; - return SampleTimeOperator; + return DebounceTimeOperator; }()); -var SampleTimeSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SampleTimeSubscriber, _super); - function SampleTimeSubscriber(destination, period, scheduler) { +var DebounceTimeSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](DebounceTimeSubscriber, _super); + function DebounceTimeSubscriber(destination, dueTime, scheduler) { var _this = _super.call(this, destination) || this; - _this.period = period; + _this.dueTime = dueTime; _this.scheduler = scheduler; + _this.debouncedSubscription = null; + _this.lastValue = null; _this.hasValue = false; - _this.add(scheduler.schedule(dispatchNotification, period, { subscriber: _this, period: period })); return _this; } - SampleTimeSubscriber.prototype._next = function (value) { + DebounceTimeSubscriber.prototype._next = function (value) { + this.clearDebounce(); this.lastValue = value; this.hasValue = true; + this.add(this.debouncedSubscription = this.scheduler.schedule(dispatchNext, this.dueTime, this)); }; - SampleTimeSubscriber.prototype.notifyNext = function () { + DebounceTimeSubscriber.prototype._complete = function () { + this.debouncedNext(); + this.destination.complete(); + }; + DebounceTimeSubscriber.prototype.debouncedNext = function () { + this.clearDebounce(); if (this.hasValue) { + var lastValue = this.lastValue; + this.lastValue = null; this.hasValue = false; - this.destination.next(this.lastValue); + this.destination.next(lastValue); } }; - return SampleTimeSubscriber; + DebounceTimeSubscriber.prototype.clearDebounce = function () { + var debouncedSubscription = this.debouncedSubscription; + if (debouncedSubscription !== null) { + this.remove(debouncedSubscription); + debouncedSubscription.unsubscribe(); + this.debouncedSubscription = null; + } + }; + return DebounceTimeSubscriber; }(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -function dispatchNotification(state) { - var subscriber = state.subscriber, period = state.period; - subscriber.notifyNext(); - this.schedule(state, period); +function dispatchNext(subscriber) { + subscriber.debouncedNext(); } -//# sourceMappingURL=sampleTime.js.map +//# sourceMappingURL=debounceTime.js.map /***/ }), -/* 471 */ +/* 417 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sequenceEqual", function() { return sequenceEqual; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SequenceEqualOperator", function() { return SequenceEqualOperator; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SequenceEqualSubscriber", function() { return SequenceEqualSubscriber; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "defaultIfEmpty", function() { return defaultIfEmpty; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); /* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ -function sequenceEqual(compareTo, comparator) { - return function (source) { return source.lift(new SequenceEqualOperator(compareTo, comparator)); }; +function defaultIfEmpty(defaultValue) { + if (defaultValue === void 0) { + defaultValue = null; + } + return function (source) { return source.lift(new DefaultIfEmptyOperator(defaultValue)); }; } -var SequenceEqualOperator = /*@__PURE__*/ (function () { - function SequenceEqualOperator(compareTo, comparator) { - this.compareTo = compareTo; - this.comparator = comparator; +var DefaultIfEmptyOperator = /*@__PURE__*/ (function () { + function DefaultIfEmptyOperator(defaultValue) { + this.defaultValue = defaultValue; } - SequenceEqualOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new SequenceEqualSubscriber(subscriber, this.compareTo, this.comparator)); + DefaultIfEmptyOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new DefaultIfEmptySubscriber(subscriber, this.defaultValue)); }; - return SequenceEqualOperator; + return DefaultIfEmptyOperator; }()); - -var SequenceEqualSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SequenceEqualSubscriber, _super); - function SequenceEqualSubscriber(destination, compareTo, comparator) { +var DefaultIfEmptySubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](DefaultIfEmptySubscriber, _super); + function DefaultIfEmptySubscriber(destination, defaultValue) { var _this = _super.call(this, destination) || this; - _this.compareTo = compareTo; - _this.comparator = comparator; - _this._a = []; - _this._b = []; - _this._oneComplete = false; - _this.destination.add(compareTo.subscribe(new SequenceEqualCompareToSubscriber(destination, _this))); + _this.defaultValue = defaultValue; + _this.isEmpty = true; return _this; } - SequenceEqualSubscriber.prototype._next = function (value) { - if (this._oneComplete && this._b.length === 0) { - this.emit(false); - } - else { - this._a.push(value); - this.checkValues(); - } - }; - SequenceEqualSubscriber.prototype._complete = function () { - if (this._oneComplete) { - this.emit(this._a.length === 0 && this._b.length === 0); - } - else { - this._oneComplete = true; - } - this.unsubscribe(); - }; - SequenceEqualSubscriber.prototype.checkValues = function () { - var _c = this, _a = _c._a, _b = _c._b, comparator = _c.comparator; - while (_a.length > 0 && _b.length > 0) { - var a = _a.shift(); - var b = _b.shift(); - var areEqual = false; - try { - areEqual = comparator ? comparator(a, b) : a === b; - } - catch (e) { - this.destination.error(e); - } - if (!areEqual) { - this.emit(false); - } - } - }; - SequenceEqualSubscriber.prototype.emit = function (value) { - var destination = this.destination; - destination.next(value); - destination.complete(); - }; - SequenceEqualSubscriber.prototype.nextB = function (value) { - if (this._oneComplete && this._a.length === 0) { - this.emit(false); - } - else { - this._b.push(value); - this.checkValues(); - } + DefaultIfEmptySubscriber.prototype._next = function (value) { + this.isEmpty = false; + this.destination.next(value); }; - SequenceEqualSubscriber.prototype.completeB = function () { - if (this._oneComplete) { - this.emit(this._a.length === 0 && this._b.length === 0); - } - else { - this._oneComplete = true; + DefaultIfEmptySubscriber.prototype._complete = function () { + if (this.isEmpty) { + this.destination.next(this.defaultValue); } + this.destination.complete(); }; - return SequenceEqualSubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); - -var SequenceEqualCompareToSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SequenceEqualCompareToSubscriber, _super); - function SequenceEqualCompareToSubscriber(destination, parent) { - var _this = _super.call(this, destination) || this; - _this.parent = parent; - return _this; - } - SequenceEqualCompareToSubscriber.prototype._next = function (value) { - this.parent.nextB(value); - }; - SequenceEqualCompareToSubscriber.prototype._error = function (err) { - this.parent.error(err); - this.unsubscribe(); - }; - SequenceEqualCompareToSubscriber.prototype._complete = function () { - this.parent.completeB(); - this.unsubscribe(); - }; - return SequenceEqualCompareToSubscriber; + return DefaultIfEmptySubscriber; }(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=sequenceEqual.js.map +//# sourceMappingURL=defaultIfEmpty.js.map /***/ }), -/* 472 */ +/* 418 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "share", function() { return share; }); -/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(455); -/* harmony import */ var _refCount__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(30); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(27); -/** PURE_IMPORTS_START _multicast,_refCount,_Subject PURE_IMPORTS_END */ - - +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "delay", function() { return delay; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(55); +/* harmony import */ var _util_isDate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(419); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(11); +/* harmony import */ var _Notification__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(42); +/** PURE_IMPORTS_START tslib,_scheduler_async,_util_isDate,_Subscriber,_Notification PURE_IMPORTS_END */ -function shareSubjectFactory() { - return new _Subject__WEBPACK_IMPORTED_MODULE_2__["Subject"](); -} -function share() { - return function (source) { return Object(_refCount__WEBPACK_IMPORTED_MODULE_1__["refCount"])()(Object(_multicast__WEBPACK_IMPORTED_MODULE_0__["multicast"])(shareSubjectFactory)(source)); }; -} -//# sourceMappingURL=share.js.map -/***/ }), -/* 473 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "shareReplay", function() { return shareReplay; }); -/* harmony import */ var _ReplaySubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(33); -/** PURE_IMPORTS_START _ReplaySubject PURE_IMPORTS_END */ -function shareReplay(configOrBufferSize, windowTime, scheduler) { - var config; - if (configOrBufferSize && typeof configOrBufferSize === 'object') { - config = configOrBufferSize; - } - else { - config = { - bufferSize: configOrBufferSize, - windowTime: windowTime, - refCount: false, - scheduler: scheduler - }; +function delay(delay, scheduler) { + if (scheduler === void 0) { + scheduler = _scheduler_async__WEBPACK_IMPORTED_MODULE_1__["async"]; } - return function (source) { return source.lift(shareReplayOperator(config)); }; + var absoluteDelay = Object(_util_isDate__WEBPACK_IMPORTED_MODULE_2__["isDate"])(delay); + var delayFor = absoluteDelay ? (+delay - scheduler.now()) : Math.abs(delay); + return function (source) { return source.lift(new DelayOperator(delayFor, scheduler)); }; } -function shareReplayOperator(_a) { - var _b = _a.bufferSize, bufferSize = _b === void 0 ? Number.POSITIVE_INFINITY : _b, _c = _a.windowTime, windowTime = _c === void 0 ? Number.POSITIVE_INFINITY : _c, useRefCount = _a.refCount, scheduler = _a.scheduler; - var subject; - var refCount = 0; - var subscription; - var hasError = false; - var isComplete = false; - return function shareReplayOperation(source) { - refCount++; - if (!subject || hasError) { - hasError = false; - subject = new _ReplaySubject__WEBPACK_IMPORTED_MODULE_0__["ReplaySubject"](bufferSize, windowTime, scheduler); - subscription = source.subscribe({ - next: function (value) { subject.next(value); }, - error: function (err) { - hasError = true; - subject.error(err); - }, - complete: function () { - isComplete = true; - subscription = undefined; - subject.complete(); - }, - }); +var DelayOperator = /*@__PURE__*/ (function () { + function DelayOperator(delay, scheduler) { + this.delay = delay; + this.scheduler = scheduler; + } + DelayOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new DelaySubscriber(subscriber, this.delay, this.scheduler)); + }; + return DelayOperator; +}()); +var DelaySubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](DelaySubscriber, _super); + function DelaySubscriber(destination, delay, scheduler) { + var _this = _super.call(this, destination) || this; + _this.delay = delay; + _this.scheduler = scheduler; + _this.queue = []; + _this.active = false; + _this.errored = false; + return _this; + } + DelaySubscriber.dispatch = function (state) { + var source = state.source; + var queue = source.queue; + var scheduler = state.scheduler; + var destination = state.destination; + while (queue.length > 0 && (queue[0].time - scheduler.now()) <= 0) { + queue.shift().notification.observe(destination); + } + if (queue.length > 0) { + var delay_1 = Math.max(0, queue[0].time - scheduler.now()); + this.schedule(state, delay_1); + } + else { + this.unsubscribe(); + source.active = false; + } + }; + DelaySubscriber.prototype._schedule = function (scheduler) { + this.active = true; + var destination = this.destination; + destination.add(scheduler.schedule(DelaySubscriber.dispatch, this.delay, { + source: this, destination: this.destination, scheduler: scheduler + })); + }; + DelaySubscriber.prototype.scheduleNotification = function (notification) { + if (this.errored === true) { + return; } - var innerSub = subject.subscribe(this); - this.add(function () { - refCount--; - innerSub.unsubscribe(); - if (subscription && !isComplete && useRefCount && refCount === 0) { - subscription.unsubscribe(); - subscription = undefined; - subject = undefined; - } - }); + var scheduler = this.scheduler; + var message = new DelayMessage(scheduler.now() + this.delay, notification); + this.queue.push(message); + if (this.active === false) { + this._schedule(scheduler); + } + }; + DelaySubscriber.prototype._next = function (value) { + this.scheduleNotification(_Notification__WEBPACK_IMPORTED_MODULE_4__["Notification"].createNext(value)); + }; + DelaySubscriber.prototype._error = function (err) { + this.errored = true; + this.queue = []; + this.destination.error(err); + this.unsubscribe(); + }; + DelaySubscriber.prototype._complete = function () { + this.scheduleNotification(_Notification__WEBPACK_IMPORTED_MODULE_4__["Notification"].createComplete()); + this.unsubscribe(); }; + return DelaySubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_3__["Subscriber"])); +var DelayMessage = /*@__PURE__*/ (function () { + function DelayMessage(time, notification) { + this.time = time; + this.notification = notification; + } + return DelayMessage; +}()); +//# sourceMappingURL=delay.js.map + + +/***/ }), +/* 419 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isDate", function() { return isDate; }); +/** PURE_IMPORTS_START PURE_IMPORTS_END */ +function isDate(value) { + return value instanceof Date && !isNaN(+value); } -//# sourceMappingURL=shareReplay.js.map +//# sourceMappingURL=isDate.js.map /***/ }), -/* 474 */ +/* 420 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "single", function() { return single; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "delayWhen", function() { return delayWhen; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); /* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(63); -/** PURE_IMPORTS_START tslib,_Subscriber,_util_EmptyError PURE_IMPORTS_END */ +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(9); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(69); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(70); +/** PURE_IMPORTS_START tslib,_Subscriber,_Observable,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ -function single(predicate) { - return function (source) { return source.lift(new SingleOperator(predicate, source)); }; + + +function delayWhen(delayDurationSelector, subscriptionDelay) { + if (subscriptionDelay) { + return function (source) { + return new SubscriptionDelayObservable(source, subscriptionDelay) + .lift(new DelayWhenOperator(delayDurationSelector)); + }; + } + return function (source) { return source.lift(new DelayWhenOperator(delayDurationSelector)); }; } -var SingleOperator = /*@__PURE__*/ (function () { - function SingleOperator(predicate, source) { - this.predicate = predicate; - this.source = source; +var DelayWhenOperator = /*@__PURE__*/ (function () { + function DelayWhenOperator(delayDurationSelector) { + this.delayDurationSelector = delayDurationSelector; } - SingleOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new SingleSubscriber(subscriber, this.predicate, this.source)); + DelayWhenOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new DelayWhenSubscriber(subscriber, this.delayDurationSelector)); }; - return SingleOperator; + return DelayWhenOperator; }()); -var SingleSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SingleSubscriber, _super); - function SingleSubscriber(destination, predicate, source) { +var DelayWhenSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](DelayWhenSubscriber, _super); + function DelayWhenSubscriber(destination, delayDurationSelector) { var _this = _super.call(this, destination) || this; - _this.predicate = predicate; - _this.source = source; - _this.seenValue = false; + _this.delayDurationSelector = delayDurationSelector; + _this.completed = false; + _this.delayNotifierSubscriptions = []; _this.index = 0; return _this; } - SingleSubscriber.prototype.applySingleValue = function (value) { - if (this.seenValue) { - this.destination.error('Sequence contains more than one element'); - } - else { - this.seenValue = true; - this.singleValue = value; - } + DelayWhenSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + this.destination.next(outerValue); + this.removeSubscription(innerSub); + this.tryComplete(); }; - SingleSubscriber.prototype._next = function (value) { - var index = this.index++; - if (this.predicate) { - this.tryNext(value, index); - } - else { - this.applySingleValue(value); + DelayWhenSubscriber.prototype.notifyError = function (error, innerSub) { + this._error(error); + }; + DelayWhenSubscriber.prototype.notifyComplete = function (innerSub) { + var value = this.removeSubscription(innerSub); + if (value) { + this.destination.next(value); } + this.tryComplete(); }; - SingleSubscriber.prototype.tryNext = function (value, index) { + DelayWhenSubscriber.prototype._next = function (value) { + var index = this.index++; try { - if (this.predicate(value, index, this.source)) { - this.applySingleValue(value); + var delayNotifier = this.delayDurationSelector(value, index); + if (delayNotifier) { + this.tryDelay(delayNotifier, value); } } catch (err) { this.destination.error(err); } }; - SingleSubscriber.prototype._complete = function () { - var destination = this.destination; - if (this.index > 0) { - destination.next(this.seenValue ? this.singleValue : undefined); - destination.complete(); + DelayWhenSubscriber.prototype._complete = function () { + this.completed = true; + this.tryComplete(); + this.unsubscribe(); + }; + DelayWhenSubscriber.prototype.removeSubscription = function (subscription) { + subscription.unsubscribe(); + var subscriptionIdx = this.delayNotifierSubscriptions.indexOf(subscription); + if (subscriptionIdx !== -1) { + this.delayNotifierSubscriptions.splice(subscriptionIdx, 1); } - else { - destination.error(new _util_EmptyError__WEBPACK_IMPORTED_MODULE_2__["EmptyError"]); + return subscription.outerValue; + }; + DelayWhenSubscriber.prototype.tryDelay = function (delayNotifier, value) { + var notifierSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__["subscribeToResult"])(this, delayNotifier, value); + if (notifierSubscription && !notifierSubscription.closed) { + var destination = this.destination; + destination.add(notifierSubscription); + this.delayNotifierSubscriptions.push(notifierSubscription); } }; - return SingleSubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=single.js.map - - -/***/ }), -/* 475 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "skip", function() { return skip; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ - - -function skip(count) { - return function (source) { return source.lift(new SkipOperator(count)); }; -} -var SkipOperator = /*@__PURE__*/ (function () { - function SkipOperator(total) { - this.total = total; + DelayWhenSubscriber.prototype.tryComplete = function () { + if (this.completed && this.delayNotifierSubscriptions.length === 0) { + this.destination.complete(); + } + }; + return DelayWhenSubscriber; +}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__["OuterSubscriber"])); +var SubscriptionDelayObservable = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SubscriptionDelayObservable, _super); + function SubscriptionDelayObservable(source, subscriptionDelay) { + var _this = _super.call(this) || this; + _this.source = source; + _this.subscriptionDelay = subscriptionDelay; + return _this; } - SkipOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new SkipSubscriber(subscriber, this.total)); + SubscriptionDelayObservable.prototype._subscribe = function (subscriber) { + this.subscriptionDelay.subscribe(new SubscriptionDelaySubscriber(subscriber, this.source)); }; - return SkipOperator; -}()); -var SkipSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SkipSubscriber, _super); - function SkipSubscriber(destination, total) { - var _this = _super.call(this, destination) || this; - _this.total = total; - _this.count = 0; + return SubscriptionDelayObservable; +}(_Observable__WEBPACK_IMPORTED_MODULE_2__["Observable"])); +var SubscriptionDelaySubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SubscriptionDelaySubscriber, _super); + function SubscriptionDelaySubscriber(parent, source) { + var _this = _super.call(this) || this; + _this.parent = parent; + _this.source = source; + _this.sourceSubscribed = false; return _this; } - SkipSubscriber.prototype._next = function (x) { - if (++this.count > this.total) { - this.destination.next(x); + SubscriptionDelaySubscriber.prototype._next = function (unused) { + this.subscribeToSource(); + }; + SubscriptionDelaySubscriber.prototype._error = function (err) { + this.unsubscribe(); + this.parent.error(err); + }; + SubscriptionDelaySubscriber.prototype._complete = function () { + this.unsubscribe(); + this.subscribeToSource(); + }; + SubscriptionDelaySubscriber.prototype.subscribeToSource = function () { + if (!this.sourceSubscribed) { + this.sourceSubscribed = true; + this.unsubscribe(); + this.source.subscribe(this.parent); } }; - return SkipSubscriber; + return SubscriptionDelaySubscriber; }(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=skip.js.map +//# sourceMappingURL=delayWhen.js.map /***/ }), -/* 476 */ +/* 421 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "skipLast", function() { return skipLast; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "dematerialize", function() { return dematerialize; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); /* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/* harmony import */ var _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(62); -/** PURE_IMPORTS_START tslib,_Subscriber,_util_ArgumentOutOfRangeError PURE_IMPORTS_END */ - +/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ -function skipLast(count) { - return function (source) { return source.lift(new SkipLastOperator(count)); }; +function dematerialize() { + return function dematerializeOperatorFunction(source) { + return source.lift(new DeMaterializeOperator()); + }; } -var SkipLastOperator = /*@__PURE__*/ (function () { - function SkipLastOperator(_skipCount) { - this._skipCount = _skipCount; - if (this._skipCount < 0) { - throw new _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_2__["ArgumentOutOfRangeError"]; - } +var DeMaterializeOperator = /*@__PURE__*/ (function () { + function DeMaterializeOperator() { } - SkipLastOperator.prototype.call = function (subscriber, source) { - if (this._skipCount === 0) { - return source.subscribe(new _Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"](subscriber)); - } - else { - return source.subscribe(new SkipLastSubscriber(subscriber, this._skipCount)); - } + DeMaterializeOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new DeMaterializeSubscriber(subscriber)); }; - return SkipLastOperator; + return DeMaterializeOperator; }()); -var SkipLastSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SkipLastSubscriber, _super); - function SkipLastSubscriber(destination, _skipCount) { - var _this = _super.call(this, destination) || this; - _this._skipCount = _skipCount; - _this._count = 0; - _this._ring = new Array(_skipCount); - return _this; +var DeMaterializeSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](DeMaterializeSubscriber, _super); + function DeMaterializeSubscriber(destination) { + return _super.call(this, destination) || this; } - SkipLastSubscriber.prototype._next = function (value) { - var skipCount = this._skipCount; - var count = this._count++; - if (count < skipCount) { - this._ring[count] = value; - } - else { - var currentIndex = count % skipCount; - var ring = this._ring; - var oldValue = ring[currentIndex]; - ring[currentIndex] = value; - this.destination.next(oldValue); - } + DeMaterializeSubscriber.prototype._next = function (value) { + value.observe(this.destination); }; - return SkipLastSubscriber; + return DeMaterializeSubscriber; }(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=skipLast.js.map +//# sourceMappingURL=dematerialize.js.map /***/ }), -/* 477 */ +/* 422 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "skipUntil", function() { return skipUntil; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "distinct", function() { return distinct; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DistinctSubscriber", function() { return DistinctSubscriber; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); /* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); -/* harmony import */ var _InnerSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(70); -/** PURE_IMPORTS_START tslib,_OuterSubscriber,_InnerSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ - +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(70); +/** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ -function skipUntil(notifier) { - return function (source) { return source.lift(new SkipUntilOperator(notifier)); }; +function distinct(keySelector, flushes) { + return function (source) { return source.lift(new DistinctOperator(keySelector, flushes)); }; } -var SkipUntilOperator = /*@__PURE__*/ (function () { - function SkipUntilOperator(notifier) { - this.notifier = notifier; +var DistinctOperator = /*@__PURE__*/ (function () { + function DistinctOperator(keySelector, flushes) { + this.keySelector = keySelector; + this.flushes = flushes; } - SkipUntilOperator.prototype.call = function (destination, source) { - return source.subscribe(new SkipUntilSubscriber(destination, this.notifier)); + DistinctOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new DistinctSubscriber(subscriber, this.keySelector, this.flushes)); }; - return SkipUntilOperator; + return DistinctOperator; }()); -var SkipUntilSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SkipUntilSubscriber, _super); - function SkipUntilSubscriber(destination, notifier) { +var DistinctSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](DistinctSubscriber, _super); + function DistinctSubscriber(destination, keySelector, flushes) { var _this = _super.call(this, destination) || this; - _this.hasValue = false; - var innerSubscriber = new _InnerSubscriber__WEBPACK_IMPORTED_MODULE_2__["InnerSubscriber"](_this, undefined, undefined); - _this.add(innerSubscriber); - _this.innerSubscription = innerSubscriber; - var innerSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__["subscribeToResult"])(_this, notifier, undefined, undefined, innerSubscriber); - if (innerSubscription !== innerSubscriber) { - _this.add(innerSubscription); - _this.innerSubscription = innerSubscription; + _this.keySelector = keySelector; + _this.values = new Set(); + if (flushes) { + _this.add(Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(_this, flushes)); } return _this; } - SkipUntilSubscriber.prototype._next = function (value) { - if (this.hasValue) { - _super.prototype._next.call(this, value); + DistinctSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + this.values.clear(); + }; + DistinctSubscriber.prototype.notifyError = function (error, innerSub) { + this._error(error); + }; + DistinctSubscriber.prototype._next = function (value) { + if (this.keySelector) { + this._useKeySelector(value); + } + else { + this._finalizeNext(value, value); } }; - SkipUntilSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { - this.hasValue = true; - if (this.innerSubscription) { - this.innerSubscription.unsubscribe(); + DistinctSubscriber.prototype._useKeySelector = function (value) { + var key; + var destination = this.destination; + try { + key = this.keySelector(value); + } + catch (err) { + destination.error(err); + return; } + this._finalizeNext(key, value); }; - SkipUntilSubscriber.prototype.notifyComplete = function () { + DistinctSubscriber.prototype._finalizeNext = function (key, value) { + var values = this.values; + if (!values.has(key)) { + values.add(key); + this.destination.next(value); + } }; - return SkipUntilSubscriber; + return DistinctSubscriber; }(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); -//# sourceMappingURL=skipUntil.js.map + +//# sourceMappingURL=distinct.js.map /***/ }), -/* 478 */ +/* 423 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "skipWhile", function() { return skipWhile; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "distinctUntilChanged", function() { return distinctUntilChanged; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); /* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); /** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ -function skipWhile(predicate) { - return function (source) { return source.lift(new SkipWhileOperator(predicate)); }; +function distinctUntilChanged(compare, keySelector) { + return function (source) { return source.lift(new DistinctUntilChangedOperator(compare, keySelector)); }; } -var SkipWhileOperator = /*@__PURE__*/ (function () { - function SkipWhileOperator(predicate) { - this.predicate = predicate; +var DistinctUntilChangedOperator = /*@__PURE__*/ (function () { + function DistinctUntilChangedOperator(compare, keySelector) { + this.compare = compare; + this.keySelector = keySelector; } - SkipWhileOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new SkipWhileSubscriber(subscriber, this.predicate)); + DistinctUntilChangedOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new DistinctUntilChangedSubscriber(subscriber, this.compare, this.keySelector)); }; - return SkipWhileOperator; + return DistinctUntilChangedOperator; }()); -var SkipWhileSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SkipWhileSubscriber, _super); - function SkipWhileSubscriber(destination, predicate) { +var DistinctUntilChangedSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](DistinctUntilChangedSubscriber, _super); + function DistinctUntilChangedSubscriber(destination, compare, keySelector) { var _this = _super.call(this, destination) || this; - _this.predicate = predicate; - _this.skipping = true; - _this.index = 0; + _this.keySelector = keySelector; + _this.hasKey = false; + if (typeof compare === 'function') { + _this.compare = compare; + } return _this; } - SkipWhileSubscriber.prototype._next = function (value) { - var destination = this.destination; - if (this.skipping) { - this.tryCallPredicate(value); - } - if (!this.skipping) { - destination.next(value); - } + DistinctUntilChangedSubscriber.prototype.compare = function (x, y) { + return x === y; }; - SkipWhileSubscriber.prototype.tryCallPredicate = function (value) { + DistinctUntilChangedSubscriber.prototype._next = function (value) { + var key; try { - var result = this.predicate(value, this.index++); - this.skipping = Boolean(result); + var keySelector = this.keySelector; + key = keySelector ? keySelector(value) : value; } catch (err) { - this.destination.error(err); + return this.destination.error(err); + } + var result = false; + if (this.hasKey) { + try { + var compare = this.compare; + result = compare(this.key, key); + } + catch (err) { + return this.destination.error(err); + } + } + else { + this.hasKey = true; + } + if (!result) { + this.key = key; + this.destination.next(value); } }; - return SkipWhileSubscriber; + return DistinctUntilChangedSubscriber; }(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=skipWhile.js.map +//# sourceMappingURL=distinctUntilChanged.js.map /***/ }), -/* 479 */ +/* 424 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "startWith", function() { return startWith; }); -/* harmony import */ var _observable_concat__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(79); -/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(45); -/** PURE_IMPORTS_START _observable_concat,_util_isScheduler PURE_IMPORTS_END */ +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "distinctUntilKeyChanged", function() { return distinctUntilKeyChanged; }); +/* harmony import */ var _distinctUntilChanged__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(423); +/** PURE_IMPORTS_START _distinctUntilChanged PURE_IMPORTS_END */ + +function distinctUntilKeyChanged(key, compare) { + return Object(_distinctUntilChanged__WEBPACK_IMPORTED_MODULE_0__["distinctUntilChanged"])(function (x, y) { return compare ? compare(x[key], y[key]) : x[key] === y[key]; }); +} +//# sourceMappingURL=distinctUntilKeyChanged.js.map -function startWith() { - var array = []; - for (var _i = 0; _i < arguments.length; _i++) { - array[_i] = arguments[_i]; - } - var scheduler = array[array.length - 1]; - if (Object(_util_isScheduler__WEBPACK_IMPORTED_MODULE_1__["isScheduler"])(scheduler)) { - array.pop(); - return function (source) { return Object(_observable_concat__WEBPACK_IMPORTED_MODULE_0__["concat"])(array, source, scheduler); }; - } - else { - return function (source) { return Object(_observable_concat__WEBPACK_IMPORTED_MODULE_0__["concat"])(array, source); }; +/***/ }), +/* 425 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "elementAt", function() { return elementAt; }); +/* harmony import */ var _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(62); +/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(104); +/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(426); +/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(417); +/* harmony import */ var _take__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(427); +/** PURE_IMPORTS_START _util_ArgumentOutOfRangeError,_filter,_throwIfEmpty,_defaultIfEmpty,_take PURE_IMPORTS_END */ + + + + + +function elementAt(index, defaultValue) { + if (index < 0) { + throw new _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_0__["ArgumentOutOfRangeError"](); } + var hasDefaultValue = arguments.length >= 2; + return function (source) { + return source.pipe(Object(_filter__WEBPACK_IMPORTED_MODULE_1__["filter"])(function (v, i) { return i === index; }), Object(_take__WEBPACK_IMPORTED_MODULE_4__["take"])(1), hasDefaultValue + ? Object(_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__["defaultIfEmpty"])(defaultValue) + : Object(_throwIfEmpty__WEBPACK_IMPORTED_MODULE_2__["throwIfEmpty"])(function () { return new _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_0__["ArgumentOutOfRangeError"](); })); + }; } -//# sourceMappingURL=startWith.js.map +//# sourceMappingURL=elementAt.js.map /***/ }), -/* 480 */ +/* 426 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "subscribeOn", function() { return subscribeOn; }); -/* harmony import */ var _observable_SubscribeOnObservable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(481); -/** PURE_IMPORTS_START _observable_SubscribeOnObservable PURE_IMPORTS_END */ +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "throwIfEmpty", function() { return throwIfEmpty; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(63); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(11); +/** PURE_IMPORTS_START tslib,_util_EmptyError,_Subscriber PURE_IMPORTS_END */ -function subscribeOn(scheduler, delay) { - if (delay === void 0) { - delay = 0; + + +function throwIfEmpty(errorFactory) { + if (errorFactory === void 0) { + errorFactory = defaultErrorFactory; } - return function subscribeOnOperatorFunction(source) { - return source.lift(new SubscribeOnOperator(scheduler, delay)); + return function (source) { + return source.lift(new ThrowIfEmptyOperator(errorFactory)); }; } -var SubscribeOnOperator = /*@__PURE__*/ (function () { - function SubscribeOnOperator(scheduler, delay) { - this.scheduler = scheduler; - this.delay = delay; +var ThrowIfEmptyOperator = /*@__PURE__*/ (function () { + function ThrowIfEmptyOperator(errorFactory) { + this.errorFactory = errorFactory; } - SubscribeOnOperator.prototype.call = function (subscriber, source) { - return new _observable_SubscribeOnObservable__WEBPACK_IMPORTED_MODULE_0__["SubscribeOnObservable"](source, this.delay, this.scheduler).subscribe(subscriber); + ThrowIfEmptyOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new ThrowIfEmptySubscriber(subscriber, this.errorFactory)); }; - return SubscribeOnOperator; + return ThrowIfEmptyOperator; }()); -//# sourceMappingURL=subscribeOn.js.map +var ThrowIfEmptySubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](ThrowIfEmptySubscriber, _super); + function ThrowIfEmptySubscriber(destination, errorFactory) { + var _this = _super.call(this, destination) || this; + _this.errorFactory = errorFactory; + _this.hasValue = false; + return _this; + } + ThrowIfEmptySubscriber.prototype._next = function (value) { + this.hasValue = true; + this.destination.next(value); + }; + ThrowIfEmptySubscriber.prototype._complete = function () { + if (!this.hasValue) { + var err = void 0; + try { + err = this.errorFactory(); + } + catch (e) { + err = e; + } + this.destination.error(err); + } + else { + return this.destination.complete(); + } + }; + return ThrowIfEmptySubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_2__["Subscriber"])); +function defaultErrorFactory() { + return new _util_EmptyError__WEBPACK_IMPORTED_MODULE_1__["EmptyError"](); +} +//# sourceMappingURL=throwIfEmpty.js.map /***/ }), -/* 481 */ +/* 427 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SubscribeOnObservable", function() { return SubscribeOnObservable; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "take", function() { return take; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9); -/* harmony import */ var _scheduler_asap__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(51); -/* harmony import */ var _util_isNumeric__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(97); -/** PURE_IMPORTS_START tslib,_Observable,_scheduler_asap,_util_isNumeric PURE_IMPORTS_END */ +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/* harmony import */ var _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(62); +/* harmony import */ var _observable_empty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(43); +/** PURE_IMPORTS_START tslib,_Subscriber,_util_ArgumentOutOfRangeError,_observable_empty PURE_IMPORTS_END */ -var SubscribeOnObservable = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SubscribeOnObservable, _super); - function SubscribeOnObservable(source, delayTime, scheduler) { - if (delayTime === void 0) { - delayTime = 0; - } - if (scheduler === void 0) { - scheduler = _scheduler_asap__WEBPACK_IMPORTED_MODULE_2__["asap"]; +function take(count) { + return function (source) { + if (count === 0) { + return Object(_observable_empty__WEBPACK_IMPORTED_MODULE_3__["empty"])(); } - var _this = _super.call(this) || this; - _this.source = source; - _this.delayTime = delayTime; - _this.scheduler = scheduler; - if (!Object(_util_isNumeric__WEBPACK_IMPORTED_MODULE_3__["isNumeric"])(delayTime) || delayTime < 0) { - _this.delayTime = 0; + else { + return source.lift(new TakeOperator(count)); } - if (!scheduler || typeof scheduler.schedule !== 'function') { - _this.scheduler = _scheduler_asap__WEBPACK_IMPORTED_MODULE_2__["asap"]; + }; +} +var TakeOperator = /*@__PURE__*/ (function () { + function TakeOperator(total) { + this.total = total; + if (this.total < 0) { + throw new _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_2__["ArgumentOutOfRangeError"]; } + } + TakeOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new TakeSubscriber(subscriber, this.total)); + }; + return TakeOperator; +}()); +var TakeSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](TakeSubscriber, _super); + function TakeSubscriber(destination, total) { + var _this = _super.call(this, destination) || this; + _this.total = total; + _this.count = 0; return _this; } - SubscribeOnObservable.create = function (source, delay, scheduler) { - if (delay === void 0) { - delay = 0; - } - if (scheduler === void 0) { - scheduler = _scheduler_asap__WEBPACK_IMPORTED_MODULE_2__["asap"]; + TakeSubscriber.prototype._next = function (value) { + var total = this.total; + var count = ++this.count; + if (count <= total) { + this.destination.next(value); + if (count === total) { + this.destination.complete(); + this.unsubscribe(); + } } - return new SubscribeOnObservable(source, delay, scheduler); - }; - SubscribeOnObservable.dispatch = function (arg) { - var source = arg.source, subscriber = arg.subscriber; - return this.add(source.subscribe(subscriber)); - }; - SubscribeOnObservable.prototype._subscribe = function (subscriber) { - var delay = this.delayTime; - var source = this.source; - var scheduler = this.scheduler; - return scheduler.schedule(SubscribeOnObservable.dispatch, delay, { - source: source, subscriber: subscriber - }); }; - return SubscribeOnObservable; -}(_Observable__WEBPACK_IMPORTED_MODULE_1__["Observable"])); - -//# sourceMappingURL=SubscribeOnObservable.js.map + return TakeSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +//# sourceMappingURL=take.js.map /***/ }), -/* 482 */ +/* 428 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "switchAll", function() { return switchAll; }); -/* harmony import */ var _switchMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(483); -/* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(25); -/** PURE_IMPORTS_START _switchMap,_util_identity PURE_IMPORTS_END */ +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "endWith", function() { return endWith; }); +/* harmony import */ var _observable_concat__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(79); +/* harmony import */ var _observable_of__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(44); +/** PURE_IMPORTS_START _observable_concat,_observable_of PURE_IMPORTS_END */ -function switchAll() { - return Object(_switchMap__WEBPACK_IMPORTED_MODULE_0__["switchMap"])(_util_identity__WEBPACK_IMPORTED_MODULE_1__["identity"]); +function endWith() { + var array = []; + for (var _i = 0; _i < arguments.length; _i++) { + array[_i] = arguments[_i]; + } + return function (source) { return Object(_observable_concat__WEBPACK_IMPORTED_MODULE_0__["concat"])(source, _observable_of__WEBPACK_IMPORTED_MODULE_1__["of"].apply(void 0, array)); }; } -//# sourceMappingURL=switchAll.js.map +//# sourceMappingURL=endWith.js.map /***/ }), -/* 483 */ +/* 429 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "switchMap", function() { return switchMap; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "every", function() { return every; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); -/* harmony import */ var _InnerSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(70); -/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(66); -/* harmony import */ var _observable_from__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(83); -/** PURE_IMPORTS_START tslib,_OuterSubscriber,_InnerSubscriber,_util_subscribeToResult,_map,_observable_from PURE_IMPORTS_END */ - - - - +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ -function switchMap(project, resultSelector) { - if (typeof resultSelector === 'function') { - return function (source) { return source.pipe(switchMap(function (a, i) { return Object(_observable_from__WEBPACK_IMPORTED_MODULE_5__["from"])(project(a, i)).pipe(Object(_map__WEBPACK_IMPORTED_MODULE_4__["map"])(function (b, ii) { return resultSelector(a, b, i, ii); })); })); }; - } - return function (source) { return source.lift(new SwitchMapOperator(project)); }; +function every(predicate, thisArg) { + return function (source) { return source.lift(new EveryOperator(predicate, thisArg, source)); }; } -var SwitchMapOperator = /*@__PURE__*/ (function () { - function SwitchMapOperator(project) { - this.project = project; +var EveryOperator = /*@__PURE__*/ (function () { + function EveryOperator(predicate, thisArg, source) { + this.predicate = predicate; + this.thisArg = thisArg; + this.source = source; } - SwitchMapOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new SwitchMapSubscriber(subscriber, this.project)); + EveryOperator.prototype.call = function (observer, source) { + return source.subscribe(new EverySubscriber(observer, this.predicate, this.thisArg, this.source)); }; - return SwitchMapOperator; + return EveryOperator; }()); -var SwitchMapSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SwitchMapSubscriber, _super); - function SwitchMapSubscriber(destination, project) { +var EverySubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](EverySubscriber, _super); + function EverySubscriber(destination, predicate, thisArg, source) { var _this = _super.call(this, destination) || this; - _this.project = project; + _this.predicate = predicate; + _this.thisArg = thisArg; + _this.source = source; _this.index = 0; + _this.thisArg = thisArg || _this; return _this; } - SwitchMapSubscriber.prototype._next = function (value) { - var result; - var index = this.index++; + EverySubscriber.prototype.notifyComplete = function (everyValueMatch) { + this.destination.next(everyValueMatch); + this.destination.complete(); + }; + EverySubscriber.prototype._next = function (value) { + var result = false; try { - result = this.project(value, index); + result = this.predicate.call(this.thisArg, value, this.index++, this.source); } - catch (error) { - this.destination.error(error); + catch (err) { + this.destination.error(err); return; } - this._innerSub(result, value, index); - }; - SwitchMapSubscriber.prototype._innerSub = function (result, value, index) { - var innerSubscription = this.innerSubscription; - if (innerSubscription) { - innerSubscription.unsubscribe(); - } - var innerSubscriber = new _InnerSubscriber__WEBPACK_IMPORTED_MODULE_2__["InnerSubscriber"](this, value, index); - var destination = this.destination; - destination.add(innerSubscriber); - this.innerSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__["subscribeToResult"])(this, result, undefined, undefined, innerSubscriber); - if (this.innerSubscription !== innerSubscriber) { - destination.add(this.innerSubscription); - } - }; - SwitchMapSubscriber.prototype._complete = function () { - var innerSubscription = this.innerSubscription; - if (!innerSubscription || innerSubscription.closed) { - _super.prototype._complete.call(this); - } - this.unsubscribe(); - }; - SwitchMapSubscriber.prototype._unsubscribe = function () { - this.innerSubscription = null; - }; - SwitchMapSubscriber.prototype.notifyComplete = function (innerSub) { - var destination = this.destination; - destination.remove(innerSub); - this.innerSubscription = null; - if (this.isStopped) { - _super.prototype._complete.call(this); + if (!result) { + this.notifyComplete(false); } }; - SwitchMapSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { - this.destination.next(innerValue); + EverySubscriber.prototype._complete = function () { + this.notifyComplete(true); }; - return SwitchMapSubscriber; -}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); -//# sourceMappingURL=switchMap.js.map - - -/***/ }), -/* 484 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "switchMapTo", function() { return switchMapTo; }); -/* harmony import */ var _switchMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(483); -/** PURE_IMPORTS_START _switchMap PURE_IMPORTS_END */ - -function switchMapTo(innerObservable, resultSelector) { - return resultSelector ? Object(_switchMap__WEBPACK_IMPORTED_MODULE_0__["switchMap"])(function () { return innerObservable; }, resultSelector) : Object(_switchMap__WEBPACK_IMPORTED_MODULE_0__["switchMap"])(function () { return innerObservable; }); -} -//# sourceMappingURL=switchMapTo.js.map + return EverySubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +//# sourceMappingURL=every.js.map /***/ }), -/* 485 */ +/* 430 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "takeUntil", function() { return takeUntil; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "exhaust", function() { return exhaust; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); /* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); /* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(70); @@ -57639,206 +53503,158 @@ __webpack_require__.r(__webpack_exports__); -function takeUntil(notifier) { - return function (source) { return source.lift(new TakeUntilOperator(notifier)); }; +function exhaust() { + return function (source) { return source.lift(new SwitchFirstOperator()); }; } -var TakeUntilOperator = /*@__PURE__*/ (function () { - function TakeUntilOperator(notifier) { - this.notifier = notifier; +var SwitchFirstOperator = /*@__PURE__*/ (function () { + function SwitchFirstOperator() { } - TakeUntilOperator.prototype.call = function (subscriber, source) { - var takeUntilSubscriber = new TakeUntilSubscriber(subscriber); - var notifierSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(takeUntilSubscriber, this.notifier); - if (notifierSubscription && !takeUntilSubscriber.seenValue) { - takeUntilSubscriber.add(notifierSubscription); - return source.subscribe(takeUntilSubscriber); - } - return takeUntilSubscriber; + SwitchFirstOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new SwitchFirstSubscriber(subscriber)); }; - return TakeUntilOperator; + return SwitchFirstOperator; }()); -var TakeUntilSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](TakeUntilSubscriber, _super); - function TakeUntilSubscriber(destination) { +var SwitchFirstSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SwitchFirstSubscriber, _super); + function SwitchFirstSubscriber(destination) { var _this = _super.call(this, destination) || this; - _this.seenValue = false; + _this.hasCompleted = false; + _this.hasSubscription = false; return _this; } - TakeUntilSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { - this.seenValue = true; - this.complete(); + SwitchFirstSubscriber.prototype._next = function (value) { + if (!this.hasSubscription) { + this.hasSubscription = true; + this.add(Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(this, value)); + } }; - TakeUntilSubscriber.prototype.notifyComplete = function () { + SwitchFirstSubscriber.prototype._complete = function () { + this.hasCompleted = true; + if (!this.hasSubscription) { + this.destination.complete(); + } }; - return TakeUntilSubscriber; + SwitchFirstSubscriber.prototype.notifyComplete = function (innerSub) { + this.remove(innerSub); + this.hasSubscription = false; + if (this.hasCompleted) { + this.destination.complete(); + } + }; + return SwitchFirstSubscriber; }(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); -//# sourceMappingURL=takeUntil.js.map +//# sourceMappingURL=exhaust.js.map /***/ }), -/* 486 */ +/* 431 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "takeWhile", function() { return takeWhile; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "exhaustMap", function() { return exhaustMap; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); +/* harmony import */ var _InnerSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(70); +/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(66); +/* harmony import */ var _observable_from__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(83); +/** PURE_IMPORTS_START tslib,_OuterSubscriber,_InnerSubscriber,_util_subscribeToResult,_map,_observable_from PURE_IMPORTS_END */ -function takeWhile(predicate, inclusive) { - if (inclusive === void 0) { - inclusive = false; + + + + +function exhaustMap(project, resultSelector) { + if (resultSelector) { + return function (source) { return source.pipe(exhaustMap(function (a, i) { return Object(_observable_from__WEBPACK_IMPORTED_MODULE_5__["from"])(project(a, i)).pipe(Object(_map__WEBPACK_IMPORTED_MODULE_4__["map"])(function (b, ii) { return resultSelector(a, b, i, ii); })); })); }; } return function (source) { - return source.lift(new TakeWhileOperator(predicate, inclusive)); + return source.lift(new ExhaustMapOperator(project)); }; } -var TakeWhileOperator = /*@__PURE__*/ (function () { - function TakeWhileOperator(predicate, inclusive) { - this.predicate = predicate; - this.inclusive = inclusive; +var ExhaustMapOperator = /*@__PURE__*/ (function () { + function ExhaustMapOperator(project) { + this.project = project; } - TakeWhileOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new TakeWhileSubscriber(subscriber, this.predicate, this.inclusive)); + ExhaustMapOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new ExhaustMapSubscriber(subscriber, this.project)); }; - return TakeWhileOperator; + return ExhaustMapOperator; }()); -var TakeWhileSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](TakeWhileSubscriber, _super); - function TakeWhileSubscriber(destination, predicate, inclusive) { +var ExhaustMapSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](ExhaustMapSubscriber, _super); + function ExhaustMapSubscriber(destination, project) { var _this = _super.call(this, destination) || this; - _this.predicate = predicate; - _this.inclusive = inclusive; + _this.project = project; + _this.hasSubscription = false; + _this.hasCompleted = false; _this.index = 0; return _this; } - TakeWhileSubscriber.prototype._next = function (value) { - var destination = this.destination; - var result; - try { - result = this.predicate(value, this.index++); - } - catch (err) { - destination.error(err); - return; - } - this.nextOrComplete(value, result); - }; - TakeWhileSubscriber.prototype.nextOrComplete = function (value, predicateResult) { - var destination = this.destination; - if (Boolean(predicateResult)) { - destination.next(value); - } - else { - if (this.inclusive) { - destination.next(value); - } - destination.complete(); + ExhaustMapSubscriber.prototype._next = function (value) { + if (!this.hasSubscription) { + this.tryNext(value); } }; - return TakeWhileSubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=takeWhile.js.map - - -/***/ }), -/* 487 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "tap", function() { return tap; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/* harmony import */ var _util_noop__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(60); -/* harmony import */ var _util_isFunction__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(13); -/** PURE_IMPORTS_START tslib,_Subscriber,_util_noop,_util_isFunction PURE_IMPORTS_END */ - - - - -function tap(nextOrObserver, error, complete) { - return function tapOperatorFunction(source) { - return source.lift(new DoOperator(nextOrObserver, error, complete)); - }; -} -var DoOperator = /*@__PURE__*/ (function () { - function DoOperator(nextOrObserver, error, complete) { - this.nextOrObserver = nextOrObserver; - this.error = error; - this.complete = complete; - } - DoOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new TapSubscriber(subscriber, this.nextOrObserver, this.error, this.complete)); - }; - return DoOperator; -}()); -var TapSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](TapSubscriber, _super); - function TapSubscriber(destination, observerOrNext, error, complete) { - var _this = _super.call(this, destination) || this; - _this._tapNext = _util_noop__WEBPACK_IMPORTED_MODULE_2__["noop"]; - _this._tapError = _util_noop__WEBPACK_IMPORTED_MODULE_2__["noop"]; - _this._tapComplete = _util_noop__WEBPACK_IMPORTED_MODULE_2__["noop"]; - _this._tapError = error || _util_noop__WEBPACK_IMPORTED_MODULE_2__["noop"]; - _this._tapComplete = complete || _util_noop__WEBPACK_IMPORTED_MODULE_2__["noop"]; - if (Object(_util_isFunction__WEBPACK_IMPORTED_MODULE_3__["isFunction"])(observerOrNext)) { - _this._context = _this; - _this._tapNext = observerOrNext; - } - else if (observerOrNext) { - _this._context = observerOrNext; - _this._tapNext = observerOrNext.next || _util_noop__WEBPACK_IMPORTED_MODULE_2__["noop"]; - _this._tapError = observerOrNext.error || _util_noop__WEBPACK_IMPORTED_MODULE_2__["noop"]; - _this._tapComplete = observerOrNext.complete || _util_noop__WEBPACK_IMPORTED_MODULE_2__["noop"]; - } - return _this; - } - TapSubscriber.prototype._next = function (value) { + ExhaustMapSubscriber.prototype.tryNext = function (value) { + var result; + var index = this.index++; try { - this._tapNext.call(this._context, value); + result = this.project(value, index); } catch (err) { this.destination.error(err); return; } - this.destination.next(value); + this.hasSubscription = true; + this._innerSub(result, value, index); }; - TapSubscriber.prototype._error = function (err) { - try { - this._tapError.call(this._context, err); + ExhaustMapSubscriber.prototype._innerSub = function (result, value, index) { + var innerSubscriber = new _InnerSubscriber__WEBPACK_IMPORTED_MODULE_2__["InnerSubscriber"](this, value, index); + var destination = this.destination; + destination.add(innerSubscriber); + var innerSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__["subscribeToResult"])(this, result, undefined, undefined, innerSubscriber); + if (innerSubscription !== innerSubscriber) { + destination.add(innerSubscription); } - catch (err) { - this.destination.error(err); - return; + }; + ExhaustMapSubscriber.prototype._complete = function () { + this.hasCompleted = true; + if (!this.hasSubscription) { + this.destination.complete(); } + this.unsubscribe(); + }; + ExhaustMapSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + this.destination.next(innerValue); + }; + ExhaustMapSubscriber.prototype.notifyError = function (err) { this.destination.error(err); }; - TapSubscriber.prototype._complete = function () { - try { - this._tapComplete.call(this._context); - } - catch (err) { - this.destination.error(err); - return; + ExhaustMapSubscriber.prototype.notifyComplete = function (innerSub) { + var destination = this.destination; + destination.remove(innerSub); + this.hasSubscription = false; + if (this.hasCompleted) { + this.destination.complete(); } - return this.destination.complete(); }; - return TapSubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=tap.js.map + return ExhaustMapSubscriber; +}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); +//# sourceMappingURL=exhaustMap.js.map /***/ }), -/* 488 */ +/* 432 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "defaultThrottleConfig", function() { return defaultThrottleConfig; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "throttle", function() { return throttle; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "expand", function() { return expand; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ExpandOperator", function() { return ExpandOperator; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ExpandSubscriber", function() { return ExpandSubscriber; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); /* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); /* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(70); @@ -57846,3882 +53662,4875 @@ __webpack_require__.r(__webpack_exports__); -var defaultThrottleConfig = { - leading: true, - trailing: false -}; -function throttle(durationSelector, config) { - if (config === void 0) { - config = defaultThrottleConfig; +function expand(project, concurrent, scheduler) { + if (concurrent === void 0) { + concurrent = Number.POSITIVE_INFINITY; } - return function (source) { return source.lift(new ThrottleOperator(durationSelector, config.leading, config.trailing)); }; + if (scheduler === void 0) { + scheduler = undefined; + } + concurrent = (concurrent || 0) < 1 ? Number.POSITIVE_INFINITY : concurrent; + return function (source) { return source.lift(new ExpandOperator(project, concurrent, scheduler)); }; } -var ThrottleOperator = /*@__PURE__*/ (function () { - function ThrottleOperator(durationSelector, leading, trailing) { - this.durationSelector = durationSelector; - this.leading = leading; - this.trailing = trailing; +var ExpandOperator = /*@__PURE__*/ (function () { + function ExpandOperator(project, concurrent, scheduler) { + this.project = project; + this.concurrent = concurrent; + this.scheduler = scheduler; } - ThrottleOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new ThrottleSubscriber(subscriber, this.durationSelector, this.leading, this.trailing)); + ExpandOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new ExpandSubscriber(subscriber, this.project, this.concurrent, this.scheduler)); }; - return ThrottleOperator; + return ExpandOperator; }()); -var ThrottleSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](ThrottleSubscriber, _super); - function ThrottleSubscriber(destination, durationSelector, _leading, _trailing) { + +var ExpandSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](ExpandSubscriber, _super); + function ExpandSubscriber(destination, project, concurrent, scheduler) { var _this = _super.call(this, destination) || this; - _this.destination = destination; - _this.durationSelector = durationSelector; - _this._leading = _leading; - _this._trailing = _trailing; - _this._hasValue = false; + _this.project = project; + _this.concurrent = concurrent; + _this.scheduler = scheduler; + _this.index = 0; + _this.active = 0; + _this.hasCompleted = false; + if (concurrent < Number.POSITIVE_INFINITY) { + _this.buffer = []; + } return _this; } - ThrottleSubscriber.prototype._next = function (value) { - this._hasValue = true; - this._sendValue = value; - if (!this._throttled) { - if (this._leading) { - this.send(); + ExpandSubscriber.dispatch = function (arg) { + var subscriber = arg.subscriber, result = arg.result, value = arg.value, index = arg.index; + subscriber.subscribeToProjection(result, value, index); + }; + ExpandSubscriber.prototype._next = function (value) { + var destination = this.destination; + if (destination.closed) { + this._complete(); + return; + } + var index = this.index++; + if (this.active < this.concurrent) { + destination.next(value); + try { + var project = this.project; + var result = project(value, index); + if (!this.scheduler) { + this.subscribeToProjection(result, value, index); + } + else { + var state = { subscriber: this, result: result, value: value, index: index }; + var destination_1 = this.destination; + destination_1.add(this.scheduler.schedule(ExpandSubscriber.dispatch, 0, state)); + } } - else { - this.throttle(value); + catch (e) { + destination.error(e); } } - }; - ThrottleSubscriber.prototype.send = function () { - var _a = this, _hasValue = _a._hasValue, _sendValue = _a._sendValue; - if (_hasValue) { - this.destination.next(_sendValue); - this.throttle(_sendValue); + else { + this.buffer.push(value); } - this._hasValue = false; - this._sendValue = null; }; - ThrottleSubscriber.prototype.throttle = function (value) { - var duration = this.tryDurationSelector(value); - if (!!duration) { - this.add(this._throttled = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(this, duration)); - } + ExpandSubscriber.prototype.subscribeToProjection = function (result, value, index) { + this.active++; + var destination = this.destination; + destination.add(Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(this, result, value, index)); }; - ThrottleSubscriber.prototype.tryDurationSelector = function (value) { - try { - return this.durationSelector(value); - } - catch (err) { - this.destination.error(err); - return null; + ExpandSubscriber.prototype._complete = function () { + this.hasCompleted = true; + if (this.hasCompleted && this.active === 0) { + this.destination.complete(); } + this.unsubscribe(); }; - ThrottleSubscriber.prototype.throttlingDone = function () { - var _a = this, _throttled = _a._throttled, _trailing = _a._trailing; - if (_throttled) { - _throttled.unsubscribe(); + ExpandSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + this._next(innerValue); + }; + ExpandSubscriber.prototype.notifyComplete = function (innerSub) { + var buffer = this.buffer; + var destination = this.destination; + destination.remove(innerSub); + this.active--; + if (buffer && buffer.length > 0) { + this._next(buffer.shift()); } - this._throttled = null; - if (_trailing) { - this.send(); + if (this.hasCompleted && this.active === 0) { + this.destination.complete(); } }; - ThrottleSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { - this.throttlingDone(); - }; - ThrottleSubscriber.prototype.notifyComplete = function () { - this.throttlingDone(); - }; - return ThrottleSubscriber; + return ExpandSubscriber; }(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); -//# sourceMappingURL=throttle.js.map + +//# sourceMappingURL=expand.js.map /***/ }), -/* 489 */ +/* 433 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "throttleTime", function() { return throttleTime; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "finalize", function() { return finalize; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); /* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(55); -/* harmony import */ var _throttle__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(488); -/** PURE_IMPORTS_START tslib,_Subscriber,_scheduler_async,_throttle PURE_IMPORTS_END */ - +/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(17); +/** PURE_IMPORTS_START tslib,_Subscriber,_Subscription PURE_IMPORTS_END */ -function throttleTime(duration, scheduler, config) { - if (scheduler === void 0) { - scheduler = _scheduler_async__WEBPACK_IMPORTED_MODULE_2__["async"]; +function finalize(callback) { + return function (source) { return source.lift(new FinallyOperator(callback)); }; +} +var FinallyOperator = /*@__PURE__*/ (function () { + function FinallyOperator(callback) { + this.callback = callback; } - if (config === void 0) { - config = _throttle__WEBPACK_IMPORTED_MODULE_3__["defaultThrottleConfig"]; + FinallyOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new FinallySubscriber(subscriber, this.callback)); + }; + return FinallyOperator; +}()); +var FinallySubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](FinallySubscriber, _super); + function FinallySubscriber(destination, callback) { + var _this = _super.call(this, destination) || this; + _this.add(new _Subscription__WEBPACK_IMPORTED_MODULE_2__["Subscription"](callback)); + return _this; } - return function (source) { return source.lift(new ThrottleTimeOperator(duration, scheduler, config.leading, config.trailing)); }; + return FinallySubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +//# sourceMappingURL=finalize.js.map + + +/***/ }), +/* 434 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "find", function() { return find; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FindValueOperator", function() { return FindValueOperator; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FindValueSubscriber", function() { return FindValueSubscriber; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ + + +function find(predicate, thisArg) { + if (typeof predicate !== 'function') { + throw new TypeError('predicate is not a function'); + } + return function (source) { return source.lift(new FindValueOperator(predicate, source, false, thisArg)); }; } -var ThrottleTimeOperator = /*@__PURE__*/ (function () { - function ThrottleTimeOperator(duration, scheduler, leading, trailing) { - this.duration = duration; - this.scheduler = scheduler; - this.leading = leading; - this.trailing = trailing; +var FindValueOperator = /*@__PURE__*/ (function () { + function FindValueOperator(predicate, source, yieldIndex, thisArg) { + this.predicate = predicate; + this.source = source; + this.yieldIndex = yieldIndex; + this.thisArg = thisArg; } - ThrottleTimeOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new ThrottleTimeSubscriber(subscriber, this.duration, this.scheduler, this.leading, this.trailing)); + FindValueOperator.prototype.call = function (observer, source) { + return source.subscribe(new FindValueSubscriber(observer, this.predicate, this.source, this.yieldIndex, this.thisArg)); }; - return ThrottleTimeOperator; + return FindValueOperator; }()); -var ThrottleTimeSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](ThrottleTimeSubscriber, _super); - function ThrottleTimeSubscriber(destination, duration, scheduler, leading, trailing) { + +var FindValueSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](FindValueSubscriber, _super); + function FindValueSubscriber(destination, predicate, source, yieldIndex, thisArg) { var _this = _super.call(this, destination) || this; - _this.duration = duration; - _this.scheduler = scheduler; - _this.leading = leading; - _this.trailing = trailing; - _this._hasTrailingValue = false; - _this._trailingValue = null; + _this.predicate = predicate; + _this.source = source; + _this.yieldIndex = yieldIndex; + _this.thisArg = thisArg; + _this.index = 0; return _this; } - ThrottleTimeSubscriber.prototype._next = function (value) { - if (this.throttled) { - if (this.trailing) { - this._trailingValue = value; - this._hasTrailingValue = true; - } - } - else { - this.add(this.throttled = this.scheduler.schedule(dispatchNext, this.duration, { subscriber: this })); - if (this.leading) { - this.destination.next(value); - } - else if (this.trailing) { - this._trailingValue = value; - this._hasTrailingValue = true; - } - } + FindValueSubscriber.prototype.notifyComplete = function (value) { + var destination = this.destination; + destination.next(value); + destination.complete(); + this.unsubscribe(); }; - ThrottleTimeSubscriber.prototype._complete = function () { - if (this._hasTrailingValue) { - this.destination.next(this._trailingValue); - this.destination.complete(); + FindValueSubscriber.prototype._next = function (value) { + var _a = this, predicate = _a.predicate, thisArg = _a.thisArg; + var index = this.index++; + try { + var result = predicate.call(thisArg || this, value, index, this.source); + if (result) { + this.notifyComplete(this.yieldIndex ? index : value); + } } - else { - this.destination.complete(); + catch (err) { + this.destination.error(err); } }; - ThrottleTimeSubscriber.prototype.clearThrottle = function () { - var throttled = this.throttled; - if (throttled) { - if (this.trailing && this._hasTrailingValue) { - this.destination.next(this._trailingValue); - this._trailingValue = null; - this._hasTrailingValue = false; - } - throttled.unsubscribe(); - this.remove(throttled); - this.throttled = null; - } + FindValueSubscriber.prototype._complete = function () { + this.notifyComplete(this.yieldIndex ? -1 : undefined); }; - return ThrottleTimeSubscriber; + return FindValueSubscriber; }(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -function dispatchNext(arg) { - var subscriber = arg.subscriber; - subscriber.clearThrottle(); -} -//# sourceMappingURL=throttleTime.js.map + +//# sourceMappingURL=find.js.map /***/ }), -/* 490 */ +/* 435 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timeInterval", function() { return timeInterval; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TimeInterval", function() { return TimeInterval; }); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(55); -/* harmony import */ var _scan__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(450); -/* harmony import */ var _observable_defer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(90); -/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(66); -/** PURE_IMPORTS_START _scheduler_async,_scan,_observable_defer,_map PURE_IMPORTS_END */ - - - +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "findIndex", function() { return findIndex; }); +/* harmony import */ var _operators_find__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(434); +/** PURE_IMPORTS_START _operators_find PURE_IMPORTS_END */ -function timeInterval(scheduler) { - if (scheduler === void 0) { - scheduler = _scheduler_async__WEBPACK_IMPORTED_MODULE_0__["async"]; - } - return function (source) { - return Object(_observable_defer__WEBPACK_IMPORTED_MODULE_2__["defer"])(function () { - return source.pipe(Object(_scan__WEBPACK_IMPORTED_MODULE_1__["scan"])(function (_a, value) { - var current = _a.current; - return ({ value: value, current: scheduler.now(), last: current }); - }, { current: scheduler.now(), value: undefined, last: undefined }), Object(_map__WEBPACK_IMPORTED_MODULE_3__["map"])(function (_a) { - var current = _a.current, last = _a.last, value = _a.value; - return new TimeInterval(value, current - last); - })); - }); - }; +function findIndex(predicate, thisArg) { + return function (source) { return source.lift(new _operators_find__WEBPACK_IMPORTED_MODULE_0__["FindValueOperator"](predicate, source, true, thisArg)); }; } -var TimeInterval = /*@__PURE__*/ (function () { - function TimeInterval(value, interval) { - this.value = value; - this.interval = interval; - } - return TimeInterval; -}()); - -//# sourceMappingURL=timeInterval.js.map +//# sourceMappingURL=findIndex.js.map /***/ }), -/* 491 */ +/* 436 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timeout", function() { return timeout; }); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(55); -/* harmony import */ var _util_TimeoutError__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(64); -/* harmony import */ var _timeoutWith__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(492); -/* harmony import */ var _observable_throwError__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(49); -/** PURE_IMPORTS_START _scheduler_async,_util_TimeoutError,_timeoutWith,_observable_throwError PURE_IMPORTS_END */ +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "first", function() { return first; }); +/* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(63); +/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(104); +/* harmony import */ var _take__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(427); +/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(417); +/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(426); +/* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(25); +/** PURE_IMPORTS_START _util_EmptyError,_filter,_take,_defaultIfEmpty,_throwIfEmpty,_util_identity PURE_IMPORTS_END */ -function timeout(due, scheduler) { - if (scheduler === void 0) { - scheduler = _scheduler_async__WEBPACK_IMPORTED_MODULE_0__["async"]; - } - return Object(_timeoutWith__WEBPACK_IMPORTED_MODULE_2__["timeoutWith"])(due, Object(_observable_throwError__WEBPACK_IMPORTED_MODULE_3__["throwError"])(new _util_TimeoutError__WEBPACK_IMPORTED_MODULE_1__["TimeoutError"]()), scheduler); + + +function first(predicate, defaultValue) { + var hasDefaultValue = arguments.length >= 2; + return function (source) { return source.pipe(predicate ? Object(_filter__WEBPACK_IMPORTED_MODULE_1__["filter"])(function (v, i) { return predicate(v, i, source); }) : _util_identity__WEBPACK_IMPORTED_MODULE_5__["identity"], Object(_take__WEBPACK_IMPORTED_MODULE_2__["take"])(1), hasDefaultValue ? Object(_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_3__["defaultIfEmpty"])(defaultValue) : Object(_throwIfEmpty__WEBPACK_IMPORTED_MODULE_4__["throwIfEmpty"])(function () { return new _util_EmptyError__WEBPACK_IMPORTED_MODULE_0__["EmptyError"](); })); }; } -//# sourceMappingURL=timeout.js.map +//# sourceMappingURL=first.js.map /***/ }), -/* 492 */ +/* 437 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timeoutWith", function() { return timeoutWith; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ignoreElements", function() { return ignoreElements; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(55); -/* harmony import */ var _util_isDate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(424); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(69); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(70); -/** PURE_IMPORTS_START tslib,_scheduler_async,_util_isDate,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ - - - +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ -function timeoutWith(due, withObservable, scheduler) { - if (scheduler === void 0) { - scheduler = _scheduler_async__WEBPACK_IMPORTED_MODULE_1__["async"]; - } - return function (source) { - var absoluteTimeout = Object(_util_isDate__WEBPACK_IMPORTED_MODULE_2__["isDate"])(due); - var waitFor = absoluteTimeout ? (+due - scheduler.now()) : Math.abs(due); - return source.lift(new TimeoutWithOperator(waitFor, absoluteTimeout, withObservable, scheduler)); +function ignoreElements() { + return function ignoreElementsOperatorFunction(source) { + return source.lift(new IgnoreElementsOperator()); }; } -var TimeoutWithOperator = /*@__PURE__*/ (function () { - function TimeoutWithOperator(waitFor, absoluteTimeout, withObservable, scheduler) { - this.waitFor = waitFor; - this.absoluteTimeout = absoluteTimeout; - this.withObservable = withObservable; - this.scheduler = scheduler; +var IgnoreElementsOperator = /*@__PURE__*/ (function () { + function IgnoreElementsOperator() { } - TimeoutWithOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new TimeoutWithSubscriber(subscriber, this.absoluteTimeout, this.waitFor, this.withObservable, this.scheduler)); + IgnoreElementsOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new IgnoreElementsSubscriber(subscriber)); }; - return TimeoutWithOperator; + return IgnoreElementsOperator; }()); -var TimeoutWithSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](TimeoutWithSubscriber, _super); - function TimeoutWithSubscriber(destination, absoluteTimeout, waitFor, withObservable, scheduler) { - var _this = _super.call(this, destination) || this; - _this.absoluteTimeout = absoluteTimeout; - _this.waitFor = waitFor; - _this.withObservable = withObservable; - _this.scheduler = scheduler; - _this.action = null; - _this.scheduleTimeout(); - return _this; +var IgnoreElementsSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](IgnoreElementsSubscriber, _super); + function IgnoreElementsSubscriber() { + return _super !== null && _super.apply(this, arguments) || this; } - TimeoutWithSubscriber.dispatchTimeout = function (subscriber) { - var withObservable = subscriber.withObservable; - subscriber._unsubscribeAndRecycle(); - subscriber.add(Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__["subscribeToResult"])(subscriber, withObservable)); + IgnoreElementsSubscriber.prototype._next = function (unused) { }; - TimeoutWithSubscriber.prototype.scheduleTimeout = function () { - var action = this.action; - if (action) { - this.action = action.schedule(this, this.waitFor); - } - else { - this.add(this.action = this.scheduler.schedule(TimeoutWithSubscriber.dispatchTimeout, this.waitFor, this)); - } + return IgnoreElementsSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +//# sourceMappingURL=ignoreElements.js.map + + +/***/ }), +/* 438 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isEmpty", function() { return isEmpty; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ + + +function isEmpty() { + return function (source) { return source.lift(new IsEmptyOperator()); }; +} +var IsEmptyOperator = /*@__PURE__*/ (function () { + function IsEmptyOperator() { + } + IsEmptyOperator.prototype.call = function (observer, source) { + return source.subscribe(new IsEmptySubscriber(observer)); }; - TimeoutWithSubscriber.prototype._next = function (value) { - if (!this.absoluteTimeout) { - this.scheduleTimeout(); - } - _super.prototype._next.call(this, value); + return IsEmptyOperator; +}()); +var IsEmptySubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](IsEmptySubscriber, _super); + function IsEmptySubscriber(destination) { + return _super.call(this, destination) || this; + } + IsEmptySubscriber.prototype.notifyComplete = function (isEmpty) { + var destination = this.destination; + destination.next(isEmpty); + destination.complete(); }; - TimeoutWithSubscriber.prototype._unsubscribe = function () { - this.action = null; - this.scheduler = null; - this.withObservable = null; + IsEmptySubscriber.prototype._next = function (value) { + this.notifyComplete(false); }; - return TimeoutWithSubscriber; -}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__["OuterSubscriber"])); -//# sourceMappingURL=timeoutWith.js.map + IsEmptySubscriber.prototype._complete = function () { + this.notifyComplete(true); + }; + return IsEmptySubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +//# sourceMappingURL=isEmpty.js.map /***/ }), -/* 493 */ +/* 439 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timestamp", function() { return timestamp; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Timestamp", function() { return Timestamp; }); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(55); -/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(66); -/** PURE_IMPORTS_START _scheduler_async,_map PURE_IMPORTS_END */ - +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "last", function() { return last; }); +/* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(63); +/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(104); +/* harmony import */ var _takeLast__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(440); +/* harmony import */ var _throwIfEmpty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(426); +/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(417); +/* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(25); +/** PURE_IMPORTS_START _util_EmptyError,_filter,_takeLast,_throwIfEmpty,_defaultIfEmpty,_util_identity PURE_IMPORTS_END */ -function timestamp(scheduler) { - if (scheduler === void 0) { - scheduler = _scheduler_async__WEBPACK_IMPORTED_MODULE_0__["async"]; - } - return Object(_map__WEBPACK_IMPORTED_MODULE_1__["map"])(function (value) { return new Timestamp(value, scheduler.now()); }); -} -var Timestamp = /*@__PURE__*/ (function () { - function Timestamp(value, timestamp) { - this.value = value; - this.timestamp = timestamp; - } - return Timestamp; -}()); -//# sourceMappingURL=timestamp.js.map -/***/ }), -/* 494 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "toArray", function() { return toArray; }); -/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(449); -/** PURE_IMPORTS_START _reduce PURE_IMPORTS_END */ -function toArrayReducer(arr, item, index) { - if (index === 0) { - return [item]; - } - arr.push(item); - return arr; -} -function toArray() { - return Object(_reduce__WEBPACK_IMPORTED_MODULE_0__["reduce"])(toArrayReducer, []); +function last(predicate, defaultValue) { + var hasDefaultValue = arguments.length >= 2; + return function (source) { return source.pipe(predicate ? Object(_filter__WEBPACK_IMPORTED_MODULE_1__["filter"])(function (v, i) { return predicate(v, i, source); }) : _util_identity__WEBPACK_IMPORTED_MODULE_5__["identity"], Object(_takeLast__WEBPACK_IMPORTED_MODULE_2__["takeLast"])(1), hasDefaultValue ? Object(_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_4__["defaultIfEmpty"])(defaultValue) : Object(_throwIfEmpty__WEBPACK_IMPORTED_MODULE_3__["throwIfEmpty"])(function () { return new _util_EmptyError__WEBPACK_IMPORTED_MODULE_0__["EmptyError"](); })); }; } -//# sourceMappingURL=toArray.js.map +//# sourceMappingURL=last.js.map /***/ }), -/* 495 */ +/* 440 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "window", function() { return window; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "takeLast", function() { return takeLast; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(27); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(69); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(70); -/** PURE_IMPORTS_START tslib,_Subject,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/* harmony import */ var _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(62); +/* harmony import */ var _observable_empty__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(43); +/** PURE_IMPORTS_START tslib,_Subscriber,_util_ArgumentOutOfRangeError,_observable_empty PURE_IMPORTS_END */ -function window(windowBoundaries) { - return function windowOperatorFunction(source) { - return source.lift(new WindowOperator(windowBoundaries)); +function takeLast(count) { + return function takeLastOperatorFunction(source) { + if (count === 0) { + return Object(_observable_empty__WEBPACK_IMPORTED_MODULE_3__["empty"])(); + } + else { + return source.lift(new TakeLastOperator(count)); + } }; } -var WindowOperator = /*@__PURE__*/ (function () { - function WindowOperator(windowBoundaries) { - this.windowBoundaries = windowBoundaries; - } - WindowOperator.prototype.call = function (subscriber, source) { - var windowSubscriber = new WindowSubscriber(subscriber); - var sourceSubscription = source.subscribe(windowSubscriber); - if (!sourceSubscription.closed) { - windowSubscriber.add(Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__["subscribeToResult"])(windowSubscriber, this.windowBoundaries)); +var TakeLastOperator = /*@__PURE__*/ (function () { + function TakeLastOperator(total) { + this.total = total; + if (this.total < 0) { + throw new _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_2__["ArgumentOutOfRangeError"]; } - return sourceSubscription; + } + TakeLastOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new TakeLastSubscriber(subscriber, this.total)); }; - return WindowOperator; + return TakeLastOperator; }()); -var WindowSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](WindowSubscriber, _super); - function WindowSubscriber(destination) { +var TakeLastSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](TakeLastSubscriber, _super); + function TakeLastSubscriber(destination, total) { var _this = _super.call(this, destination) || this; - _this.window = new _Subject__WEBPACK_IMPORTED_MODULE_1__["Subject"](); - destination.next(_this.window); + _this.total = total; + _this.ring = new Array(); + _this.count = 0; return _this; } - WindowSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { - this.openWindow(); - }; - WindowSubscriber.prototype.notifyError = function (error, innerSub) { - this._error(error); - }; - WindowSubscriber.prototype.notifyComplete = function (innerSub) { - this._complete(); - }; - WindowSubscriber.prototype._next = function (value) { - this.window.next(value); - }; - WindowSubscriber.prototype._error = function (err) { - this.window.error(err); - this.destination.error(err); - }; - WindowSubscriber.prototype._complete = function () { - this.window.complete(); - this.destination.complete(); - }; - WindowSubscriber.prototype._unsubscribe = function () { - this.window = null; - }; - WindowSubscriber.prototype.openWindow = function () { - var prevWindow = this.window; - if (prevWindow) { - prevWindow.complete(); + TakeLastSubscriber.prototype._next = function (value) { + var ring = this.ring; + var total = this.total; + var count = this.count++; + if (ring.length < total) { + ring.push(value); } + else { + var index = count % total; + ring[index] = value; + } + }; + TakeLastSubscriber.prototype._complete = function () { var destination = this.destination; - var newWindow = this.window = new _Subject__WEBPACK_IMPORTED_MODULE_1__["Subject"](); - destination.next(newWindow); + var count = this.count; + if (count > 0) { + var total = this.count >= this.total ? this.total : this.count; + var ring = this.ring; + for (var i = 0; i < total; i++) { + var idx = (count++) % total; + destination.next(ring[idx]); + } + } + destination.complete(); }; - return WindowSubscriber; -}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__["OuterSubscriber"])); -//# sourceMappingURL=window.js.map + return TakeLastSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +//# sourceMappingURL=takeLast.js.map /***/ }), -/* 496 */ +/* 441 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "windowCount", function() { return windowCount; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mapTo", function() { return mapTo; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); /* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(27); -/** PURE_IMPORTS_START tslib,_Subscriber,_Subject PURE_IMPORTS_END */ - +/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ -function windowCount(windowSize, startWindowEvery) { - if (startWindowEvery === void 0) { - startWindowEvery = 0; - } - return function windowCountOperatorFunction(source) { - return source.lift(new WindowCountOperator(windowSize, startWindowEvery)); - }; +function mapTo(value) { + return function (source) { return source.lift(new MapToOperator(value)); }; } -var WindowCountOperator = /*@__PURE__*/ (function () { - function WindowCountOperator(windowSize, startWindowEvery) { - this.windowSize = windowSize; - this.startWindowEvery = startWindowEvery; +var MapToOperator = /*@__PURE__*/ (function () { + function MapToOperator(value) { + this.value = value; } - WindowCountOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new WindowCountSubscriber(subscriber, this.windowSize, this.startWindowEvery)); + MapToOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new MapToSubscriber(subscriber, this.value)); }; - return WindowCountOperator; + return MapToOperator; }()); -var WindowCountSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](WindowCountSubscriber, _super); - function WindowCountSubscriber(destination, windowSize, startWindowEvery) { +var MapToSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](MapToSubscriber, _super); + function MapToSubscriber(destination, value) { var _this = _super.call(this, destination) || this; - _this.destination = destination; - _this.windowSize = windowSize; - _this.startWindowEvery = startWindowEvery; - _this.windows = [new _Subject__WEBPACK_IMPORTED_MODULE_2__["Subject"]()]; - _this.count = 0; - destination.next(_this.windows[0]); + _this.value = value; return _this; } - WindowCountSubscriber.prototype._next = function (value) { - var startWindowEvery = (this.startWindowEvery > 0) ? this.startWindowEvery : this.windowSize; - var destination = this.destination; - var windowSize = this.windowSize; - var windows = this.windows; - var len = windows.length; - for (var i = 0; i < len && !this.closed; i++) { - windows[i].next(value); - } - var c = this.count - windowSize + 1; - if (c >= 0 && c % startWindowEvery === 0 && !this.closed) { - windows.shift().complete(); - } - if (++this.count % startWindowEvery === 0 && !this.closed) { - var window_1 = new _Subject__WEBPACK_IMPORTED_MODULE_2__["Subject"](); - windows.push(window_1); - destination.next(window_1); - } + MapToSubscriber.prototype._next = function (x) { + this.destination.next(this.value); }; - WindowCountSubscriber.prototype._error = function (err) { - var windows = this.windows; - if (windows) { - while (windows.length > 0 && !this.closed) { - windows.shift().error(err); - } - } - this.destination.error(err); + return MapToSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +//# sourceMappingURL=mapTo.js.map + + +/***/ }), +/* 442 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "materialize", function() { return materialize; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/* harmony import */ var _Notification__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(42); +/** PURE_IMPORTS_START tslib,_Subscriber,_Notification PURE_IMPORTS_END */ + + + +function materialize() { + return function materializeOperatorFunction(source) { + return source.lift(new MaterializeOperator()); }; - WindowCountSubscriber.prototype._complete = function () { - var windows = this.windows; - if (windows) { - while (windows.length > 0 && !this.closed) { - windows.shift().complete(); - } - } - this.destination.complete(); +} +var MaterializeOperator = /*@__PURE__*/ (function () { + function MaterializeOperator() { + } + MaterializeOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new MaterializeSubscriber(subscriber)); }; - WindowCountSubscriber.prototype._unsubscribe = function () { - this.count = 0; - this.windows = null; + return MaterializeOperator; +}()); +var MaterializeSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](MaterializeSubscriber, _super); + function MaterializeSubscriber(destination) { + return _super.call(this, destination) || this; + } + MaterializeSubscriber.prototype._next = function (value) { + this.destination.next(_Notification__WEBPACK_IMPORTED_MODULE_2__["Notification"].createNext(value)); }; - return WindowCountSubscriber; + MaterializeSubscriber.prototype._error = function (err) { + var destination = this.destination; + destination.next(_Notification__WEBPACK_IMPORTED_MODULE_2__["Notification"].createError(err)); + destination.complete(); + }; + MaterializeSubscriber.prototype._complete = function () { + var destination = this.destination; + destination.next(_Notification__WEBPACK_IMPORTED_MODULE_2__["Notification"].createComplete()); + destination.complete(); + }; + return MaterializeSubscriber; }(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); -//# sourceMappingURL=windowCount.js.map +//# sourceMappingURL=materialize.js.map /***/ }), -/* 497 */ +/* 443 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "windowTime", function() { return windowTime; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(27); -/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(55); -/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(11); -/* harmony import */ var _util_isNumeric__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(97); -/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(45); -/** PURE_IMPORTS_START tslib,_Subject,_scheduler_async,_Subscriber,_util_isNumeric,_util_isScheduler PURE_IMPORTS_END */ +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "max", function() { return max; }); +/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(444); +/** PURE_IMPORTS_START _reduce PURE_IMPORTS_END */ + +function max(comparer) { + var max = (typeof comparer === 'function') + ? function (x, y) { return comparer(x, y) > 0 ? x : y; } + : function (x, y) { return x > y ? x : y; }; + return Object(_reduce__WEBPACK_IMPORTED_MODULE_0__["reduce"])(max); +} +//# sourceMappingURL=max.js.map +/***/ }), +/* 444 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "reduce", function() { return reduce; }); +/* harmony import */ var _scan__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(445); +/* harmony import */ var _takeLast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(440); +/* harmony import */ var _defaultIfEmpty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(417); +/* harmony import */ var _util_pipe__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(24); +/** PURE_IMPORTS_START _scan,_takeLast,_defaultIfEmpty,_util_pipe PURE_IMPORTS_END */ -function windowTime(windowTimeSpan) { - var scheduler = _scheduler_async__WEBPACK_IMPORTED_MODULE_2__["async"]; - var windowCreationInterval = null; - var maxWindowSize = Number.POSITIVE_INFINITY; - if (Object(_util_isScheduler__WEBPACK_IMPORTED_MODULE_5__["isScheduler"])(arguments[3])) { - scheduler = arguments[3]; - } - if (Object(_util_isScheduler__WEBPACK_IMPORTED_MODULE_5__["isScheduler"])(arguments[2])) { - scheduler = arguments[2]; - } - else if (Object(_util_isNumeric__WEBPACK_IMPORTED_MODULE_4__["isNumeric"])(arguments[2])) { - maxWindowSize = arguments[2]; - } - if (Object(_util_isScheduler__WEBPACK_IMPORTED_MODULE_5__["isScheduler"])(arguments[1])) { - scheduler = arguments[1]; + +function reduce(accumulator, seed) { + if (arguments.length >= 2) { + return function reduceOperatorFunctionWithSeed(source) { + return Object(_util_pipe__WEBPACK_IMPORTED_MODULE_3__["pipe"])(Object(_scan__WEBPACK_IMPORTED_MODULE_0__["scan"])(accumulator, seed), Object(_takeLast__WEBPACK_IMPORTED_MODULE_1__["takeLast"])(1), Object(_defaultIfEmpty__WEBPACK_IMPORTED_MODULE_2__["defaultIfEmpty"])(seed))(source); + }; } - else if (Object(_util_isNumeric__WEBPACK_IMPORTED_MODULE_4__["isNumeric"])(arguments[1])) { - windowCreationInterval = arguments[1]; + return function reduceOperatorFunction(source) { + return Object(_util_pipe__WEBPACK_IMPORTED_MODULE_3__["pipe"])(Object(_scan__WEBPACK_IMPORTED_MODULE_0__["scan"])(function (acc, value, index) { return accumulator(acc, value, index + 1); }), Object(_takeLast__WEBPACK_IMPORTED_MODULE_1__["takeLast"])(1))(source); + }; +} +//# sourceMappingURL=reduce.js.map + + +/***/ }), +/* 445 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "scan", function() { return scan; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ + + +function scan(accumulator, seed) { + var hasSeed = false; + if (arguments.length >= 2) { + hasSeed = true; } - return function windowTimeOperatorFunction(source) { - return source.lift(new WindowTimeOperator(windowTimeSpan, windowCreationInterval, maxWindowSize, scheduler)); + return function scanOperatorFunction(source) { + return source.lift(new ScanOperator(accumulator, seed, hasSeed)); }; } -var WindowTimeOperator = /*@__PURE__*/ (function () { - function WindowTimeOperator(windowTimeSpan, windowCreationInterval, maxWindowSize, scheduler) { - this.windowTimeSpan = windowTimeSpan; - this.windowCreationInterval = windowCreationInterval; - this.maxWindowSize = maxWindowSize; - this.scheduler = scheduler; +var ScanOperator = /*@__PURE__*/ (function () { + function ScanOperator(accumulator, seed, hasSeed) { + if (hasSeed === void 0) { + hasSeed = false; + } + this.accumulator = accumulator; + this.seed = seed; + this.hasSeed = hasSeed; } - WindowTimeOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new WindowTimeSubscriber(subscriber, this.windowTimeSpan, this.windowCreationInterval, this.maxWindowSize, this.scheduler)); + ScanOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new ScanSubscriber(subscriber, this.accumulator, this.seed, this.hasSeed)); }; - return WindowTimeOperator; + return ScanOperator; }()); -var CountedSubject = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](CountedSubject, _super); - function CountedSubject() { - var _this = _super !== null && _super.apply(this, arguments) || this; - _this._numberOfNextedValues = 0; +var ScanSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](ScanSubscriber, _super); + function ScanSubscriber(destination, accumulator, _seed, hasSeed) { + var _this = _super.call(this, destination) || this; + _this.accumulator = accumulator; + _this._seed = _seed; + _this.hasSeed = hasSeed; + _this.index = 0; return _this; } - CountedSubject.prototype.next = function (value) { - this._numberOfNextedValues++; - _super.prototype.next.call(this, value); - }; - Object.defineProperty(CountedSubject.prototype, "numberOfNextedValues", { + Object.defineProperty(ScanSubscriber.prototype, "seed", { get: function () { - return this._numberOfNextedValues; + return this._seed; + }, + set: function (value) { + this.hasSeed = true; + this._seed = value; }, enumerable: true, configurable: true }); - return CountedSubject; -}(_Subject__WEBPACK_IMPORTED_MODULE_1__["Subject"])); -var WindowTimeSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](WindowTimeSubscriber, _super); - function WindowTimeSubscriber(destination, windowTimeSpan, windowCreationInterval, maxWindowSize, scheduler) { - var _this = _super.call(this, destination) || this; - _this.destination = destination; - _this.windowTimeSpan = windowTimeSpan; - _this.windowCreationInterval = windowCreationInterval; - _this.maxWindowSize = maxWindowSize; - _this.scheduler = scheduler; - _this.windows = []; - var window = _this.openWindow(); - if (windowCreationInterval !== null && windowCreationInterval >= 0) { - var closeState = { subscriber: _this, window: window, context: null }; - var creationState = { windowTimeSpan: windowTimeSpan, windowCreationInterval: windowCreationInterval, subscriber: _this, scheduler: scheduler }; - _this.add(scheduler.schedule(dispatchWindowClose, windowTimeSpan, closeState)); - _this.add(scheduler.schedule(dispatchWindowCreation, windowCreationInterval, creationState)); + ScanSubscriber.prototype._next = function (value) { + if (!this.hasSeed) { + this.seed = value; + this.destination.next(value); } else { - var timeSpanOnlyState = { subscriber: _this, window: window, windowTimeSpan: windowTimeSpan }; - _this.add(scheduler.schedule(dispatchWindowTimeSpanOnly, windowTimeSpan, timeSpanOnlyState)); - } - return _this; - } - WindowTimeSubscriber.prototype._next = function (value) { - var windows = this.windows; - var len = windows.length; - for (var i = 0; i < len; i++) { - var window_1 = windows[i]; - if (!window_1.closed) { - window_1.next(value); - if (window_1.numberOfNextedValues >= this.maxWindowSize) { - this.closeWindow(window_1); - } - } - } - }; - WindowTimeSubscriber.prototype._error = function (err) { - var windows = this.windows; - while (windows.length > 0) { - windows.shift().error(err); + return this._tryNext(value); } - this.destination.error(err); }; - WindowTimeSubscriber.prototype._complete = function () { - var windows = this.windows; - while (windows.length > 0) { - var window_2 = windows.shift(); - if (!window_2.closed) { - window_2.complete(); - } + ScanSubscriber.prototype._tryNext = function (value) { + var index = this.index++; + var result; + try { + result = this.accumulator(this.seed, value, index); } - this.destination.complete(); - }; - WindowTimeSubscriber.prototype.openWindow = function () { - var window = new CountedSubject(); - this.windows.push(window); - var destination = this.destination; - destination.next(window); - return window; - }; - WindowTimeSubscriber.prototype.closeWindow = function (window) { - window.complete(); - var windows = this.windows; - windows.splice(windows.indexOf(window), 1); - }; - return WindowTimeSubscriber; -}(_Subscriber__WEBPACK_IMPORTED_MODULE_3__["Subscriber"])); -function dispatchWindowTimeSpanOnly(state) { - var subscriber = state.subscriber, windowTimeSpan = state.windowTimeSpan, window = state.window; - if (window) { - subscriber.closeWindow(window); + catch (err) { + this.destination.error(err); + } + this.seed = result; + this.destination.next(result); + }; + return ScanSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +//# sourceMappingURL=scan.js.map + + +/***/ }), +/* 446 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "merge", function() { return merge; }); +/* harmony import */ var _observable_merge__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(98); +/** PURE_IMPORTS_START _observable_merge PURE_IMPORTS_END */ + +function merge() { + var observables = []; + for (var _i = 0; _i < arguments.length; _i++) { + observables[_i] = arguments[_i]; } - state.window = subscriber.openWindow(); - this.schedule(state, windowTimeSpan); -} -function dispatchWindowCreation(state) { - var windowTimeSpan = state.windowTimeSpan, subscriber = state.subscriber, scheduler = state.scheduler, windowCreationInterval = state.windowCreationInterval; - var window = subscriber.openWindow(); - var action = this; - var context = { action: action, subscription: null }; - var timeSpanState = { subscriber: subscriber, window: window, context: context }; - context.subscription = scheduler.schedule(dispatchWindowClose, windowTimeSpan, timeSpanState); - action.add(context.subscription); - action.schedule(state, windowCreationInterval); + return function (source) { return source.lift.call(_observable_merge__WEBPACK_IMPORTED_MODULE_0__["merge"].apply(void 0, [source].concat(observables))); }; } -function dispatchWindowClose(state) { - var subscriber = state.subscriber, window = state.window, context = state.context; - if (context && context.action && context.subscription) { - context.action.remove(context.subscription); +//# sourceMappingURL=merge.js.map + + +/***/ }), +/* 447 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mergeMapTo", function() { return mergeMapTo; }); +/* harmony import */ var _mergeMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(82); +/** PURE_IMPORTS_START _mergeMap PURE_IMPORTS_END */ + +function mergeMapTo(innerObservable, resultSelector, concurrent) { + if (concurrent === void 0) { + concurrent = Number.POSITIVE_INFINITY; } - subscriber.closeWindow(window); + if (typeof resultSelector === 'function') { + return Object(_mergeMap__WEBPACK_IMPORTED_MODULE_0__["mergeMap"])(function () { return innerObservable; }, resultSelector, concurrent); + } + if (typeof resultSelector === 'number') { + concurrent = resultSelector; + } + return Object(_mergeMap__WEBPACK_IMPORTED_MODULE_0__["mergeMap"])(function () { return innerObservable; }, concurrent); } -//# sourceMappingURL=windowTime.js.map +//# sourceMappingURL=mergeMapTo.js.map /***/ }), -/* 498 */ +/* 448 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "windowToggle", function() { return windowToggle; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mergeScan", function() { return mergeScan; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MergeScanOperator", function() { return MergeScanOperator; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MergeScanSubscriber", function() { return MergeScanSubscriber; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(27); -/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(17); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(69); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(70); -/** PURE_IMPORTS_START tslib,_Subject,_Subscription,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ - +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(70); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(69); +/* harmony import */ var _InnerSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(71); +/** PURE_IMPORTS_START tslib,_util_subscribeToResult,_OuterSubscriber,_InnerSubscriber PURE_IMPORTS_END */ -function windowToggle(openings, closingSelector) { - return function (source) { return source.lift(new WindowToggleOperator(openings, closingSelector)); }; +function mergeScan(accumulator, seed, concurrent) { + if (concurrent === void 0) { + concurrent = Number.POSITIVE_INFINITY; + } + return function (source) { return source.lift(new MergeScanOperator(accumulator, seed, concurrent)); }; } -var WindowToggleOperator = /*@__PURE__*/ (function () { - function WindowToggleOperator(openings, closingSelector) { - this.openings = openings; - this.closingSelector = closingSelector; +var MergeScanOperator = /*@__PURE__*/ (function () { + function MergeScanOperator(accumulator, seed, concurrent) { + this.accumulator = accumulator; + this.seed = seed; + this.concurrent = concurrent; } - WindowToggleOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new WindowToggleSubscriber(subscriber, this.openings, this.closingSelector)); + MergeScanOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new MergeScanSubscriber(subscriber, this.accumulator, this.seed, this.concurrent)); }; - return WindowToggleOperator; + return MergeScanOperator; }()); -var WindowToggleSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](WindowToggleSubscriber, _super); - function WindowToggleSubscriber(destination, openings, closingSelector) { + +var MergeScanSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](MergeScanSubscriber, _super); + function MergeScanSubscriber(destination, accumulator, acc, concurrent) { var _this = _super.call(this, destination) || this; - _this.openings = openings; - _this.closingSelector = closingSelector; - _this.contexts = []; - _this.add(_this.openSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__["subscribeToResult"])(_this, openings, openings)); + _this.accumulator = accumulator; + _this.acc = acc; + _this.concurrent = concurrent; + _this.hasValue = false; + _this.hasCompleted = false; + _this.buffer = []; + _this.active = 0; + _this.index = 0; return _this; } - WindowToggleSubscriber.prototype._next = function (value) { - var contexts = this.contexts; - if (contexts) { - var len = contexts.length; - for (var i = 0; i < len; i++) { - contexts[i].window.next(value); + MergeScanSubscriber.prototype._next = function (value) { + if (this.active < this.concurrent) { + var index = this.index++; + var destination = this.destination; + var ish = void 0; + try { + var accumulator = this.accumulator; + ish = accumulator(this.acc, value, index); } - } - }; - WindowToggleSubscriber.prototype._error = function (err) { - var contexts = this.contexts; - this.contexts = null; - if (contexts) { - var len = contexts.length; - var index = -1; - while (++index < len) { - var context_1 = contexts[index]; - context_1.window.error(err); - context_1.subscription.unsubscribe(); + catch (e) { + return destination.error(e); } + this.active++; + this._innerSub(ish, value, index); } - _super.prototype._error.call(this, err); - }; - WindowToggleSubscriber.prototype._complete = function () { - var contexts = this.contexts; - this.contexts = null; - if (contexts) { - var len = contexts.length; - var index = -1; - while (++index < len) { - var context_2 = contexts[index]; - context_2.window.complete(); - context_2.subscription.unsubscribe(); - } + else { + this.buffer.push(value); } - _super.prototype._complete.call(this); }; - WindowToggleSubscriber.prototype._unsubscribe = function () { - var contexts = this.contexts; - this.contexts = null; - if (contexts) { - var len = contexts.length; - var index = -1; - while (++index < len) { - var context_3 = contexts[index]; - context_3.window.unsubscribe(); - context_3.subscription.unsubscribe(); - } + MergeScanSubscriber.prototype._innerSub = function (ish, value, index) { + var innerSubscriber = new _InnerSubscriber__WEBPACK_IMPORTED_MODULE_3__["InnerSubscriber"](this, value, index); + var destination = this.destination; + destination.add(innerSubscriber); + var innerSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_1__["subscribeToResult"])(this, ish, undefined, undefined, innerSubscriber); + if (innerSubscription !== innerSubscriber) { + destination.add(innerSubscription); } }; - WindowToggleSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { - if (outerValue === this.openings) { - var closingNotifier = void 0; - try { - var closingSelector = this.closingSelector; - closingNotifier = closingSelector(innerValue); - } - catch (e) { - return this.error(e); - } - var window_1 = new _Subject__WEBPACK_IMPORTED_MODULE_1__["Subject"](); - var subscription = new _Subscription__WEBPACK_IMPORTED_MODULE_2__["Subscription"](); - var context_4 = { window: window_1, subscription: subscription }; - this.contexts.push(context_4); - var innerSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__["subscribeToResult"])(this, closingNotifier, context_4); - if (innerSubscription.closed) { - this.closeWindow(this.contexts.length - 1); - } - else { - innerSubscription.context = context_4; - subscription.add(innerSubscription); + MergeScanSubscriber.prototype._complete = function () { + this.hasCompleted = true; + if (this.active === 0 && this.buffer.length === 0) { + if (this.hasValue === false) { + this.destination.next(this.acc); } - this.destination.next(window_1); - } - else { - this.closeWindow(this.contexts.indexOf(outerValue)); + this.destination.complete(); } + this.unsubscribe(); }; - WindowToggleSubscriber.prototype.notifyError = function (err) { - this.error(err); + MergeScanSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + var destination = this.destination; + this.acc = innerValue; + this.hasValue = true; + destination.next(innerValue); }; - WindowToggleSubscriber.prototype.notifyComplete = function (inner) { - if (inner !== this.openSubscription) { - this.closeWindow(this.contexts.indexOf(inner.context)); + MergeScanSubscriber.prototype.notifyComplete = function (innerSub) { + var buffer = this.buffer; + var destination = this.destination; + destination.remove(innerSub); + this.active--; + if (buffer.length > 0) { + this._next(buffer.shift()); } - }; - WindowToggleSubscriber.prototype.closeWindow = function (index) { - if (index === -1) { - return; + else if (this.active === 0 && this.hasCompleted) { + if (this.hasValue === false) { + this.destination.next(this.acc); + } + this.destination.complete(); } - var contexts = this.contexts; - var context = contexts[index]; - var window = context.window, subscription = context.subscription; - contexts.splice(index, 1); - window.complete(); - subscription.unsubscribe(); }; - return WindowToggleSubscriber; -}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__["OuterSubscriber"])); -//# sourceMappingURL=windowToggle.js.map + return MergeScanSubscriber; +}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__["OuterSubscriber"])); + +//# sourceMappingURL=mergeScan.js.map /***/ }), -/* 499 */ +/* 449 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "windowWhen", function() { return windowWhen; }); -/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(27); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(69); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(70); -/** PURE_IMPORTS_START tslib,_Subject,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "min", function() { return min; }); +/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(444); +/** PURE_IMPORTS_START _reduce PURE_IMPORTS_END */ + +function min(comparer) { + var min = (typeof comparer === 'function') + ? function (x, y) { return comparer(x, y) < 0 ? x : y; } + : function (x, y) { return x < y ? x : y; }; + return Object(_reduce__WEBPACK_IMPORTED_MODULE_0__["reduce"])(min); +} +//# sourceMappingURL=min.js.map +/***/ }), +/* 450 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "multicast", function() { return multicast; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MulticastOperator", function() { return MulticastOperator; }); +/* harmony import */ var _observable_ConnectableObservable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(26); +/** PURE_IMPORTS_START _observable_ConnectableObservable PURE_IMPORTS_END */ -function windowWhen(closingSelector) { - return function windowWhenOperatorFunction(source) { - return source.lift(new WindowOperator(closingSelector)); +function multicast(subjectOrSubjectFactory, selector) { + return function multicastOperatorFunction(source) { + var subjectFactory; + if (typeof subjectOrSubjectFactory === 'function') { + subjectFactory = subjectOrSubjectFactory; + } + else { + subjectFactory = function subjectFactory() { + return subjectOrSubjectFactory; + }; + } + if (typeof selector === 'function') { + return source.lift(new MulticastOperator(subjectFactory, selector)); + } + var connectable = Object.create(source, _observable_ConnectableObservable__WEBPACK_IMPORTED_MODULE_0__["connectableObservableDescriptor"]); + connectable.source = source; + connectable.subjectFactory = subjectFactory; + return connectable; }; } -var WindowOperator = /*@__PURE__*/ (function () { - function WindowOperator(closingSelector) { - this.closingSelector = closingSelector; +var MulticastOperator = /*@__PURE__*/ (function () { + function MulticastOperator(subjectFactory, selector) { + this.subjectFactory = subjectFactory; + this.selector = selector; } - WindowOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new WindowSubscriber(subscriber, this.closingSelector)); + MulticastOperator.prototype.call = function (subscriber, source) { + var selector = this.selector; + var subject = this.subjectFactory(); + var subscription = selector(subject).subscribe(subscriber); + subscription.add(source.subscribe(subject)); + return subscription; }; - return WindowOperator; + return MulticastOperator; }()); -var WindowSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](WindowSubscriber, _super); - function WindowSubscriber(destination, closingSelector) { - var _this = _super.call(this, destination) || this; - _this.destination = destination; - _this.closingSelector = closingSelector; - _this.openWindow(); - return _this; - } - WindowSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { - this.openWindow(innerSub); - }; - WindowSubscriber.prototype.notifyError = function (error, innerSub) { - this._error(error); - }; - WindowSubscriber.prototype.notifyComplete = function (innerSub) { - this.openWindow(innerSub); - }; - WindowSubscriber.prototype._next = function (value) { - this.window.next(value); - }; - WindowSubscriber.prototype._error = function (err) { - this.window.error(err); - this.destination.error(err); - this.unsubscribeClosingNotification(); - }; - WindowSubscriber.prototype._complete = function () { - this.window.complete(); - this.destination.complete(); - this.unsubscribeClosingNotification(); - }; - WindowSubscriber.prototype.unsubscribeClosingNotification = function () { - if (this.closingNotification) { - this.closingNotification.unsubscribe(); - } - }; - WindowSubscriber.prototype.openWindow = function (innerSub) { - if (innerSub === void 0) { - innerSub = null; - } - if (innerSub) { - this.remove(innerSub); - innerSub.unsubscribe(); - } - var prevWindow = this.window; - if (prevWindow) { - prevWindow.complete(); - } - var window = this.window = new _Subject__WEBPACK_IMPORTED_MODULE_1__["Subject"](); - this.destination.next(window); - var closingNotifier; - try { - var closingSelector = this.closingSelector; - closingNotifier = closingSelector(); - } - catch (e) { - this.destination.error(e); - this.window.error(e); - return; - } - this.add(this.closingNotification = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__["subscribeToResult"])(this, closingNotifier)); - }; - return WindowSubscriber; -}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__["OuterSubscriber"])); -//# sourceMappingURL=windowWhen.js.map + +//# sourceMappingURL=multicast.js.map /***/ }), -/* 500 */ +/* 451 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "withLatestFrom", function() { return withLatestFrom; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "onErrorResumeNext", function() { return onErrorResumeNext; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "onErrorResumeNextStatic", function() { return onErrorResumeNextStatic; }); /* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); -/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); -/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(70); -/** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ +/* harmony import */ var _observable_from__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(83); +/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(18); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(69); +/* harmony import */ var _InnerSubscriber__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(71); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(70); +/** PURE_IMPORTS_START tslib,_observable_from,_util_isArray,_OuterSubscriber,_InnerSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ -function withLatestFrom() { - var args = []; + + + +function onErrorResumeNext() { + var nextSources = []; for (var _i = 0; _i < arguments.length; _i++) { - args[_i] = arguments[_i]; + nextSources[_i] = arguments[_i]; } - return function (source) { - var project; - if (typeof args[args.length - 1] === 'function') { - project = args.pop(); - } - var observables = args; - return source.lift(new WithLatestFromOperator(observables, project)); - }; + if (nextSources.length === 1 && Object(_util_isArray__WEBPACK_IMPORTED_MODULE_2__["isArray"])(nextSources[0])) { + nextSources = nextSources[0]; + } + return function (source) { return source.lift(new OnErrorResumeNextOperator(nextSources)); }; } -var WithLatestFromOperator = /*@__PURE__*/ (function () { - function WithLatestFromOperator(observables, project) { - this.observables = observables; - this.project = project; +function onErrorResumeNextStatic() { + var nextSources = []; + for (var _i = 0; _i < arguments.length; _i++) { + nextSources[_i] = arguments[_i]; } - WithLatestFromOperator.prototype.call = function (subscriber, source) { - return source.subscribe(new WithLatestFromSubscriber(subscriber, this.observables, this.project)); + var source = null; + if (nextSources.length === 1 && Object(_util_isArray__WEBPACK_IMPORTED_MODULE_2__["isArray"])(nextSources[0])) { + nextSources = nextSources[0]; + } + source = nextSources.shift(); + return Object(_observable_from__WEBPACK_IMPORTED_MODULE_1__["from"])(source, null).lift(new OnErrorResumeNextOperator(nextSources)); +} +var OnErrorResumeNextOperator = /*@__PURE__*/ (function () { + function OnErrorResumeNextOperator(nextSources) { + this.nextSources = nextSources; + } + OnErrorResumeNextOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new OnErrorResumeNextSubscriber(subscriber, this.nextSources)); }; - return WithLatestFromOperator; + return OnErrorResumeNextOperator; }()); -var WithLatestFromSubscriber = /*@__PURE__*/ (function (_super) { - tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](WithLatestFromSubscriber, _super); - function WithLatestFromSubscriber(destination, observables, project) { +var OnErrorResumeNextSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](OnErrorResumeNextSubscriber, _super); + function OnErrorResumeNextSubscriber(destination, nextSources) { var _this = _super.call(this, destination) || this; - _this.observables = observables; - _this.project = project; - _this.toRespond = []; - var len = observables.length; - _this.values = new Array(len); - for (var i = 0; i < len; i++) { - _this.toRespond.push(i); - } - for (var i = 0; i < len; i++) { - var observable = observables[i]; - _this.add(Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(_this, observable, observable, i)); - } + _this.destination = destination; + _this.nextSources = nextSources; return _this; } - WithLatestFromSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { - this.values[outerIndex] = innerValue; - var toRespond = this.toRespond; - if (toRespond.length > 0) { - var found = toRespond.indexOf(outerIndex); - if (found !== -1) { - toRespond.splice(found, 1); - } - } + OnErrorResumeNextSubscriber.prototype.notifyError = function (error, innerSub) { + this.subscribeToNextSource(); }; - WithLatestFromSubscriber.prototype.notifyComplete = function () { + OnErrorResumeNextSubscriber.prototype.notifyComplete = function (innerSub) { + this.subscribeToNextSource(); }; - WithLatestFromSubscriber.prototype._next = function (value) { - if (this.toRespond.length === 0) { - var args = [value].concat(this.values); - if (this.project) { - this._tryProject(args); - } - else { - this.destination.next(args); - } - } + OnErrorResumeNextSubscriber.prototype._error = function (err) { + this.subscribeToNextSource(); + this.unsubscribe(); }; - WithLatestFromSubscriber.prototype._tryProject = function (args) { - var result; - try { - result = this.project.apply(this, args); + OnErrorResumeNextSubscriber.prototype._complete = function () { + this.subscribeToNextSource(); + this.unsubscribe(); + }; + OnErrorResumeNextSubscriber.prototype.subscribeToNextSource = function () { + var next = this.nextSources.shift(); + if (!!next) { + var innerSubscriber = new _InnerSubscriber__WEBPACK_IMPORTED_MODULE_4__["InnerSubscriber"](this, undefined, undefined); + var destination = this.destination; + destination.add(innerSubscriber); + var innerSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_5__["subscribeToResult"])(this, next, undefined, undefined, innerSubscriber); + if (innerSubscription !== innerSubscriber) { + destination.add(innerSubscription); + } } - catch (err) { - this.destination.error(err); - return; + else { + this.destination.complete(); } - this.destination.next(result); }; - return WithLatestFromSubscriber; -}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); -//# sourceMappingURL=withLatestFrom.js.map + return OnErrorResumeNextSubscriber; +}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__["OuterSubscriber"])); +//# sourceMappingURL=onErrorResumeNext.js.map /***/ }), -/* 501 */ +/* 452 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "zip", function() { return zip; }); -/* harmony import */ var _observable_zip__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(109); -/** PURE_IMPORTS_START _observable_zip PURE_IMPORTS_END */ +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "pairwise", function() { return pairwise; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ -function zip() { - var observables = []; - for (var _i = 0; _i < arguments.length; _i++) { - observables[_i] = arguments[_i]; + +function pairwise() { + return function (source) { return source.lift(new PairwiseOperator()); }; +} +var PairwiseOperator = /*@__PURE__*/ (function () { + function PairwiseOperator() { } - return function zipOperatorFunction(source) { - return source.lift.call(_observable_zip__WEBPACK_IMPORTED_MODULE_0__["zip"].apply(void 0, [source].concat(observables))); + PairwiseOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new PairwiseSubscriber(subscriber)); }; -} -//# sourceMappingURL=zip.js.map + return PairwiseOperator; +}()); +var PairwiseSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](PairwiseSubscriber, _super); + function PairwiseSubscriber(destination) { + var _this = _super.call(this, destination) || this; + _this.hasPrev = false; + return _this; + } + PairwiseSubscriber.prototype._next = function (value) { + var pair; + if (this.hasPrev) { + pair = [this.prev, value]; + } + else { + this.hasPrev = true; + } + this.prev = value; + if (pair) { + this.destination.next(pair); + } + }; + return PairwiseSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +//# sourceMappingURL=pairwise.js.map /***/ }), -/* 502 */ +/* 453 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "zipAll", function() { return zipAll; }); -/* harmony import */ var _observable_zip__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(109); -/** PURE_IMPORTS_START _observable_zip PURE_IMPORTS_END */ +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "partition", function() { return partition; }); +/* harmony import */ var _util_not__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(103); +/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(104); +/** PURE_IMPORTS_START _util_not,_filter PURE_IMPORTS_END */ -function zipAll(project) { - return function (source) { return source.lift(new _observable_zip__WEBPACK_IMPORTED_MODULE_0__["ZipOperator"](project)); }; + +function partition(predicate, thisArg) { + return function (source) { + return [ + Object(_filter__WEBPACK_IMPORTED_MODULE_1__["filter"])(predicate, thisArg)(source), + Object(_filter__WEBPACK_IMPORTED_MODULE_1__["filter"])(Object(_util_not__WEBPACK_IMPORTED_MODULE_0__["not"])(predicate, thisArg))(source) + ]; + }; } -//# sourceMappingURL=zipAll.js.map +//# sourceMappingURL=partition.js.map /***/ }), -/* 503 */ +/* 454 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "runCommand", function() { return runCommand; }); -/* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); -/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(143); -/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(145); -/* harmony import */ var _utils_projects_tree__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(504); -/* harmony import */ var _utils_kibana__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(505); -function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } - -function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } - -function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } - -/* - * 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 runCommand(command, config) { - try { - _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].debug(`Running [${command.name}] command from [${config.rootPath}]`); - const kbn = await _utils_kibana__WEBPACK_IMPORTED_MODULE_4__["Kibana"].loadFrom(config.rootPath); - const projects = kbn.getFilteredProjects({ - skipKibanaPlugins: Boolean(config.options['skip-kibana-plugins']), - ossOnly: Boolean(config.options.oss), - exclude: toArray(config.options.exclude), - include: toArray(config.options.include) - }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "pluck", function() { return pluck; }); +/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(66); +/** PURE_IMPORTS_START _map PURE_IMPORTS_END */ - if (projects.size === 0) { - _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].error(`There are no projects found. Double check project name(s) in '-i/--include' and '-e/--exclude' filters.`); - return process.exit(1); +function pluck() { + var properties = []; + for (var _i = 0; _i < arguments.length; _i++) { + properties[_i] = arguments[_i]; } - - const projectGraph = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_2__["buildProjectGraph"])(projects); - _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].debug(`Found ${projects.size.toString()} projects`); - _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].debug(Object(_utils_projects_tree__WEBPACK_IMPORTED_MODULE_3__["renderProjectsTree"])(config.rootPath, projects)); - await command.run(projects, projectGraph, _objectSpread(_objectSpread({}, config), {}, { - kbn - })); - } catch (error) { - _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].error(`[${command.name}] failed:`); - - if (error instanceof _utils_errors__WEBPACK_IMPORTED_MODULE_0__["CliError"]) { - _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].error(error.message); - const metaOutput = Object.entries(error.meta).map(([key, value]) => `${key}: ${value}`).join('\n'); - - if (metaOutput) { - _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].info('Additional debugging info:\n'); - _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].indent(2); - _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].info(metaOutput); - _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].indent(-2); - } - } else { - _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].error(error); + var length = properties.length; + if (length === 0) { + throw new Error('list of properties cannot be empty.'); } - - process.exit(1); - } + return function (source) { return Object(_map__WEBPACK_IMPORTED_MODULE_0__["map"])(plucker(properties, length))(source); }; } - -function toArray(value) { - if (value == null) { - return []; - } - - return Array.isArray(value) ? value : [value]; +function plucker(props, length) { + var mapper = function (x) { + var currentProp = x; + for (var i = 0; i < length; i++) { + var p = currentProp[props[i]]; + if (typeof p !== 'undefined') { + currentProp = p; + } + else { + return undefined; + } + } + return currentProp; + }; + return mapper; } +//# sourceMappingURL=pluck.js.map + /***/ }), -/* 504 */ +/* 455 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "renderProjectsTree", function() { return renderProjectsTree; }); -/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(235); -/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__); -/* - * 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. - */ - - -const projectKey = Symbol('__project'); -function renderProjectsTree(rootPath, projects) { - const projectsTree = buildProjectsTree(rootPath, projects); - return treeToString(createTreeStructure(projectsTree)); -} - -function treeToString(tree) { - return [tree.name].concat(childrenToStrings(tree.children, '')).join('\n'); -} +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publish", function() { return publish; }); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(27); +/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(450); +/** PURE_IMPORTS_START _Subject,_multicast PURE_IMPORTS_END */ -function childrenToStrings(tree, treePrefix) { - if (tree === undefined) { - return []; - } - let strings = []; - tree.forEach((node, index) => { - const isLastNode = tree.length - 1 === index; - const nodePrefix = isLastNode ? '└── ' : '├── '; - const childPrefix = isLastNode ? ' ' : '│ '; - const childrenPrefix = treePrefix + childPrefix; - strings.push(`${treePrefix}${nodePrefix}${node.name}`); - strings = strings.concat(childrenToStrings(node.children, childrenPrefix)); - }); - return strings; +function publish(selector) { + return selector ? + Object(_multicast__WEBPACK_IMPORTED_MODULE_1__["multicast"])(function () { return new _Subject__WEBPACK_IMPORTED_MODULE_0__["Subject"](); }, selector) : + Object(_multicast__WEBPACK_IMPORTED_MODULE_1__["multicast"])(new _Subject__WEBPACK_IMPORTED_MODULE_0__["Subject"]()); } +//# sourceMappingURL=publish.js.map -function createTreeStructure(tree) { - let name; - const children = []; - - for (const [dir, project] of tree.entries()) { - // This is a leaf node (aka a project) - if (typeof project === 'string') { - name = chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(project); - continue; - } // If there's only one project and the key indicates it's a leaf node, we - // know that we're at a package folder that contains a package.json, so we - // "inline it" so we don't get unnecessary levels, i.e. we'll just see - // `foo` instead of `foo -> foo`. +/***/ }), +/* 456 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - if (project.size === 1 && project.has(projectKey)) { - const projectName = project.get(projectKey); - children.push({ - children: [], - name: dirOrProjectName(dir, projectName) - }); - continue; - } +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publishBehavior", function() { return publishBehavior; }); +/* harmony import */ var _BehaviorSubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(32); +/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(450); +/** PURE_IMPORTS_START _BehaviorSubject,_multicast PURE_IMPORTS_END */ - const subtree = createTreeStructure(project); // If the name is specified, we know there's a package at the "root" of the - // subtree itself. - if (subtree.name !== undefined) { - const projectName = subtree.name; - children.push({ - children: subtree.children, - name: dirOrProjectName(dir, projectName) - }); - continue; - } // Special-case whenever we have one child, so we don't get unnecessary - // folders in the output. E.g. instead of `foo -> bar -> baz` we get - // `foo/bar/baz` instead. +function publishBehavior(value) { + return function (source) { return Object(_multicast__WEBPACK_IMPORTED_MODULE_1__["multicast"])(new _BehaviorSubject__WEBPACK_IMPORTED_MODULE_0__["BehaviorSubject"](value))(source); }; +} +//# sourceMappingURL=publishBehavior.js.map - if (subtree.children && subtree.children.length === 1) { - const child = subtree.children[0]; - const newName = chalk__WEBPACK_IMPORTED_MODULE_0___default.a.dim(path__WEBPACK_IMPORTED_MODULE_1___default.a.join(dir.toString(), child.name)); - children.push({ - children: child.children, - name: newName - }); - continue; - } +/***/ }), +/* 457 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - children.push({ - children: subtree.children, - name: chalk__WEBPACK_IMPORTED_MODULE_0___default.a.dim(dir.toString()) - }); - } +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publishLast", function() { return publishLast; }); +/* harmony import */ var _AsyncSubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(50); +/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(450); +/** PURE_IMPORTS_START _AsyncSubject,_multicast PURE_IMPORTS_END */ - return { - name, - children - }; -} -function dirOrProjectName(dir, projectName) { - return dir === projectName ? chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(dir) : chalk__WEBPACK_IMPORTED_MODULE_0___default.a`{dim ${dir.toString()} ({reset.green ${projectName}})}`; +function publishLast() { + return function (source) { return Object(_multicast__WEBPACK_IMPORTED_MODULE_1__["multicast"])(new _AsyncSubject__WEBPACK_IMPORTED_MODULE_0__["AsyncSubject"]())(source); }; } +//# sourceMappingURL=publishLast.js.map -function buildProjectsTree(rootPath, projects) { - const tree = new Map(); - for (const project of projects.values()) { - if (rootPath === project.path) { - tree.set(projectKey, project.name); - } else { - const relativeProjectPath = path__WEBPACK_IMPORTED_MODULE_1___default.a.relative(rootPath, project.path); - addProjectToTree(tree, relativeProjectPath.split(path__WEBPACK_IMPORTED_MODULE_1___default.a.sep), project); - } - } +/***/ }), +/* 458 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - return tree; -} +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "publishReplay", function() { return publishReplay; }); +/* harmony import */ var _ReplaySubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(33); +/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(450); +/** PURE_IMPORTS_START _ReplaySubject,_multicast PURE_IMPORTS_END */ -function addProjectToTree(tree, pathParts, project) { - if (pathParts.length === 0) { - tree.set(projectKey, project.name); - } else { - const [currentDir, ...rest] = pathParts; - if (!tree.has(currentDir)) { - tree.set(currentDir, new Map()); +function publishReplay(bufferSize, windowTime, selectorOrScheduler, scheduler) { + if (selectorOrScheduler && typeof selectorOrScheduler !== 'function') { + scheduler = selectorOrScheduler; } - - const subtree = tree.get(currentDir); - addProjectToTree(subtree, rest, project); - } + var selector = typeof selectorOrScheduler === 'function' ? selectorOrScheduler : undefined; + var subject = new _ReplaySubject__WEBPACK_IMPORTED_MODULE_0__["ReplaySubject"](bufferSize, windowTime, scheduler); + return function (source) { return Object(_multicast__WEBPACK_IMPORTED_MODULE_1__["multicast"])(function () { return subject; }, selector)(source); }; } +//# sourceMappingURL=publishReplay.js.map + /***/ }), -/* 505 */ +/* 459 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __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__(4); -/* 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__(506); -/* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(multimatch__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var is_path_inside__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(510); -/* harmony import */ var is_path_inside__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(is_path_inside__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var _projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(145); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(288); -function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } - -function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } - -function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } - -/* - * 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. - */ - - +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "race", function() { return race; }); +/* harmony import */ var _util_isArray__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(18); +/* harmony import */ var _observable_race__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(105); +/** PURE_IMPORTS_START _util_isArray,_observable_race PURE_IMPORTS_END */ +function race() { + var observables = []; + for (var _i = 0; _i < arguments.length; _i++) { + observables[_i] = arguments[_i]; + } + return function raceOperatorFunction(source) { + if (observables.length === 1 && Object(_util_isArray__WEBPACK_IMPORTED_MODULE_0__["isArray"])(observables[0])) { + observables = observables[0]; + } + return source.lift.call(_observable_race__WEBPACK_IMPORTED_MODULE_1__["race"].apply(void 0, [source].concat(observables))); + }; +} +//# sourceMappingURL=race.js.map -/** - * Helper class for dealing with a set of projects as children of - * the Kibana project. The kbn/pm is currently implemented to be - * more generic, where everything is an operation of generic projects, - * but that leads to exceptions where we need the kibana project and - * do things like `project.get('kibana')!`. - * - * Using this helper we can restructre the generic list of projects - * as a Kibana object which encapulates all the projects in the - * workspace and knows about the root Kibana project. - */ -class Kibana { - static async loadFrom(rootPath) { - return new Kibana(await Object(_projects__WEBPACK_IMPORTED_MODULE_3__["getProjects"])(rootPath, Object(_config__WEBPACK_IMPORTED_MODULE_4__["getProjectPaths"])({ - rootPath - }))); - } +/***/ }), +/* 460 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - constructor(allWorkspaceProjects) { - this.allWorkspaceProjects = allWorkspaceProjects; +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "repeat", function() { return repeat; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/* harmony import */ var _observable_empty__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(43); +/** PURE_IMPORTS_START tslib,_Subscriber,_observable_empty PURE_IMPORTS_END */ - _defineProperty(this, "kibanaProject", void 0); - const kibanaProject = allWorkspaceProjects.get('kibana'); - if (!kibanaProject) { - throw new TypeError('Unable to create Kibana object without all projects, including the Kibana project.'); +function repeat(count) { + if (count === void 0) { + count = -1; } - - this.kibanaProject = kibanaProject; - } - /** make an absolute path by resolving subPath relative to the kibana repo */ - - - getAbsolute(...subPath) { - return path__WEBPACK_IMPORTED_MODULE_0___default.a.resolve(this.kibanaProject.path, ...subPath); - } - /** convert an absolute path to a relative path, relative to the kibana repo */ - - - getRelative(absolute) { - return path__WEBPACK_IMPORTED_MODULE_0___default.a.relative(this.kibanaProject.path, absolute); - } - /** get a copy of the map of all projects in the kibana workspace */ + return function (source) { + if (count === 0) { + return Object(_observable_empty__WEBPACK_IMPORTED_MODULE_2__["empty"])(); + } + else if (count < 0) { + return source.lift(new RepeatOperator(-1, source)); + } + else { + return source.lift(new RepeatOperator(count - 1, source)); + } + }; +} +var RepeatOperator = /*@__PURE__*/ (function () { + function RepeatOperator(count, source) { + this.count = count; + this.source = source; + } + RepeatOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new RepeatSubscriber(subscriber, this.count, this.source)); + }; + return RepeatOperator; +}()); +var RepeatSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](RepeatSubscriber, _super); + function RepeatSubscriber(destination, count, source) { + var _this = _super.call(this, destination) || this; + _this.count = count; + _this.source = source; + return _this; + } + RepeatSubscriber.prototype.complete = function () { + if (!this.isStopped) { + var _a = this, source = _a.source, count = _a.count; + if (count === 0) { + return _super.prototype.complete.call(this); + } + else if (count > -1) { + this.count = count - 1; + } + source.subscribe(this._unsubscribeAndRecycle()); + } + }; + return RepeatSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +//# sourceMappingURL=repeat.js.map - getAllProjects() { - return new Map(this.allWorkspaceProjects); - } - /** determine if a project with the given name exists */ +/***/ }), +/* 461 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "repeatWhen", function() { return repeatWhen; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(27); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(69); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(70); +/** PURE_IMPORTS_START tslib,_Subject,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ - hasProject(name) { - return this.allWorkspaceProjects.has(name); - } - /** get a specific project, throws if the name is not known (use hasProject() first) */ - getProject(name) { - const project = this.allWorkspaceProjects.get(name); - if (!project) { - throw new Error(`No package with name "${name}" in the workspace`); +function repeatWhen(notifier) { + return function (source) { return source.lift(new RepeatWhenOperator(notifier)); }; +} +var RepeatWhenOperator = /*@__PURE__*/ (function () { + function RepeatWhenOperator(notifier) { + this.notifier = notifier; + } + RepeatWhenOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new RepeatWhenSubscriber(subscriber, this.notifier, source)); + }; + return RepeatWhenOperator; +}()); +var RepeatWhenSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](RepeatWhenSubscriber, _super); + function RepeatWhenSubscriber(destination, notifier, source) { + var _this = _super.call(this, destination) || this; + _this.notifier = notifier; + _this.source = source; + _this.sourceIsBeingSubscribedTo = true; + return _this; } + RepeatWhenSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + this.sourceIsBeingSubscribedTo = true; + this.source.subscribe(this); + }; + RepeatWhenSubscriber.prototype.notifyComplete = function (innerSub) { + if (this.sourceIsBeingSubscribedTo === false) { + return _super.prototype.complete.call(this); + } + }; + RepeatWhenSubscriber.prototype.complete = function () { + this.sourceIsBeingSubscribedTo = false; + if (!this.isStopped) { + if (!this.retries) { + this.subscribeToRetries(); + } + if (!this.retriesSubscription || this.retriesSubscription.closed) { + return _super.prototype.complete.call(this); + } + this._unsubscribeAndRecycle(); + this.notifications.next(); + } + }; + RepeatWhenSubscriber.prototype._unsubscribe = function () { + var _a = this, notifications = _a.notifications, retriesSubscription = _a.retriesSubscription; + if (notifications) { + notifications.unsubscribe(); + this.notifications = null; + } + if (retriesSubscription) { + retriesSubscription.unsubscribe(); + this.retriesSubscription = null; + } + this.retries = null; + }; + RepeatWhenSubscriber.prototype._unsubscribeAndRecycle = function () { + var _unsubscribe = this._unsubscribe; + this._unsubscribe = null; + _super.prototype._unsubscribeAndRecycle.call(this); + this._unsubscribe = _unsubscribe; + return this; + }; + RepeatWhenSubscriber.prototype.subscribeToRetries = function () { + this.notifications = new _Subject__WEBPACK_IMPORTED_MODULE_1__["Subject"](); + var retries; + try { + var notifier = this.notifier; + retries = notifier(this.notifications); + } + catch (e) { + return _super.prototype.complete.call(this); + } + this.retries = retries; + this.retriesSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__["subscribeToResult"])(this, retries); + }; + return RepeatWhenSubscriber; +}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__["OuterSubscriber"])); +//# sourceMappingURL=repeatWhen.js.map - return project; - } - /** get a project and all of the projects it depends on in a ProjectMap */ +/***/ }), +/* 462 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - getProjectAndDeps(name) { - const project = this.getProject(name); - return Object(_projects__WEBPACK_IMPORTED_MODULE_3__["includeTransitiveProjects"])([project], this.allWorkspaceProjects); - } - /** filter the projects to just those matching certain paths/include/exclude tags */ +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "retry", function() { return retry; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ - getFilteredProjects(options) { - const allProjects = this.getAllProjects(); - const filteredProjects = new Map(); - const pkgJsonPaths = Array.from(allProjects.values()).map(p => p.packageJsonLocation); - const filteredPkgJsonGlobs = Object(_config__WEBPACK_IMPORTED_MODULE_4__["getProjectPaths"])(_objectSpread(_objectSpread({}, options), {}, { - rootPath: this.kibanaProject.path - })).map(g => path__WEBPACK_IMPORTED_MODULE_0___default.a.resolve(g, 'package.json')); - const matchingPkgJsonPaths = multimatch__WEBPACK_IMPORTED_MODULE_1___default()(pkgJsonPaths, filteredPkgJsonGlobs); +function retry(count) { + if (count === void 0) { + count = -1; + } + return function (source) { return source.lift(new RetryOperator(count, source)); }; +} +var RetryOperator = /*@__PURE__*/ (function () { + function RetryOperator(count, source) { + this.count = count; + this.source = source; + } + RetryOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new RetrySubscriber(subscriber, this.count, this.source)); + }; + return RetryOperator; +}()); +var RetrySubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](RetrySubscriber, _super); + function RetrySubscriber(destination, count, source) { + var _this = _super.call(this, destination) || this; + _this.count = count; + _this.source = source; + return _this; + } + RetrySubscriber.prototype.error = function (err) { + if (!this.isStopped) { + var _a = this, source = _a.source, count = _a.count; + if (count === 0) { + return _super.prototype.error.call(this, err); + } + else if (count > -1) { + this.count = count - 1; + } + source.subscribe(this._unsubscribeAndRecycle()); + } + }; + return RetrySubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +//# sourceMappingURL=retry.js.map - for (const project of allProjects.values()) { - const pathMatches = matchingPkgJsonPaths.includes(project.packageJsonLocation); - const notExcluded = !options.exclude.includes(project.name); - const isIncluded = !options.include.length || options.include.includes(project.name); - if (pathMatches && notExcluded && isIncluded) { - filteredProjects.set(project.name, project); - } - } +/***/ }), +/* 463 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - return filteredProjects; - } +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "retryWhen", function() { return retryWhen; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(27); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(69); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(70); +/** PURE_IMPORTS_START tslib,_Subject,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ - isPartOfRepo(project) { - return project.path === this.kibanaProject.path || is_path_inside__WEBPACK_IMPORTED_MODULE_2___default()(project.path, this.kibanaProject.path); - } - isOutsideRepo(project) { - return !this.isPartOfRepo(project); - } + +function retryWhen(notifier) { + return function (source) { return source.lift(new RetryWhenOperator(notifier, source)); }; } +var RetryWhenOperator = /*@__PURE__*/ (function () { + function RetryWhenOperator(notifier, source) { + this.notifier = notifier; + this.source = source; + } + RetryWhenOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new RetryWhenSubscriber(subscriber, this.notifier, this.source)); + }; + return RetryWhenOperator; +}()); +var RetryWhenSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](RetryWhenSubscriber, _super); + function RetryWhenSubscriber(destination, notifier, source) { + var _this = _super.call(this, destination) || this; + _this.notifier = notifier; + _this.source = source; + return _this; + } + RetryWhenSubscriber.prototype.error = function (err) { + if (!this.isStopped) { + var errors = this.errors; + var retries = this.retries; + var retriesSubscription = this.retriesSubscription; + if (!retries) { + errors = new _Subject__WEBPACK_IMPORTED_MODULE_1__["Subject"](); + try { + var notifier = this.notifier; + retries = notifier(errors); + } + catch (e) { + return _super.prototype.error.call(this, e); + } + retriesSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__["subscribeToResult"])(this, retries); + } + else { + this.errors = null; + this.retriesSubscription = null; + } + this._unsubscribeAndRecycle(); + this.errors = errors; + this.retries = retries; + this.retriesSubscription = retriesSubscription; + errors.next(err); + } + }; + RetryWhenSubscriber.prototype._unsubscribe = function () { + var _a = this, errors = _a.errors, retriesSubscription = _a.retriesSubscription; + if (errors) { + errors.unsubscribe(); + this.errors = null; + } + if (retriesSubscription) { + retriesSubscription.unsubscribe(); + this.retriesSubscription = null; + } + this.retries = null; + }; + RetryWhenSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + var _unsubscribe = this._unsubscribe; + this._unsubscribe = null; + this._unsubscribeAndRecycle(); + this._unsubscribe = _unsubscribe; + this.source.subscribe(this); + }; + return RetryWhenSubscriber; +}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__["OuterSubscriber"])); +//# sourceMappingURL=retryWhen.js.map + /***/ }), -/* 506 */ -/***/ (function(module, exports, __webpack_require__) { +/* 464 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sample", function() { return sample; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(70); +/** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ -const minimatch = __webpack_require__(149); -const arrayUnion = __webpack_require__(507); -const arrayDiffer = __webpack_require__(508); -const arrify = __webpack_require__(509); - -module.exports = (list, patterns, options = {}) => { - list = arrify(list); - patterns = arrify(patterns); - - if (list.length === 0 || patterns.length === 0) { - return []; - } - - return patterns.reduce((result, pattern) => { - let process = arrayUnion; - if (pattern[0] === '!') { - pattern = pattern.slice(1); - process = arrayDiffer; - } - return process(result, minimatch.match(list, pattern, options)); - }, []); -}; +function sample(notifier) { + return function (source) { return source.lift(new SampleOperator(notifier)); }; +} +var SampleOperator = /*@__PURE__*/ (function () { + function SampleOperator(notifier) { + this.notifier = notifier; + } + SampleOperator.prototype.call = function (subscriber, source) { + var sampleSubscriber = new SampleSubscriber(subscriber); + var subscription = source.subscribe(sampleSubscriber); + subscription.add(Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(sampleSubscriber, this.notifier)); + return subscription; + }; + return SampleOperator; +}()); +var SampleSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SampleSubscriber, _super); + function SampleSubscriber() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.hasValue = false; + return _this; + } + SampleSubscriber.prototype._next = function (value) { + this.value = value; + this.hasValue = true; + }; + SampleSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + this.emitValue(); + }; + SampleSubscriber.prototype.notifyComplete = function () { + this.emitValue(); + }; + SampleSubscriber.prototype.emitValue = function () { + if (this.hasValue) { + this.hasValue = false; + this.destination.next(this.value); + } + }; + return SampleSubscriber; +}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); +//# sourceMappingURL=sample.js.map /***/ }), -/* 507 */ -/***/ (function(module, exports, __webpack_require__) { +/* 465 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sampleTime", function() { return sampleTime; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(55); +/** PURE_IMPORTS_START tslib,_Subscriber,_scheduler_async PURE_IMPORTS_END */ -module.exports = (...arguments_) => { - return [...new Set([].concat(...arguments_))]; -}; + +function sampleTime(period, scheduler) { + if (scheduler === void 0) { + scheduler = _scheduler_async__WEBPACK_IMPORTED_MODULE_2__["async"]; + } + return function (source) { return source.lift(new SampleTimeOperator(period, scheduler)); }; +} +var SampleTimeOperator = /*@__PURE__*/ (function () { + function SampleTimeOperator(period, scheduler) { + this.period = period; + this.scheduler = scheduler; + } + SampleTimeOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new SampleTimeSubscriber(subscriber, this.period, this.scheduler)); + }; + return SampleTimeOperator; +}()); +var SampleTimeSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SampleTimeSubscriber, _super); + function SampleTimeSubscriber(destination, period, scheduler) { + var _this = _super.call(this, destination) || this; + _this.period = period; + _this.scheduler = scheduler; + _this.hasValue = false; + _this.add(scheduler.schedule(dispatchNotification, period, { subscriber: _this, period: period })); + return _this; + } + SampleTimeSubscriber.prototype._next = function (value) { + this.lastValue = value; + this.hasValue = true; + }; + SampleTimeSubscriber.prototype.notifyNext = function () { + if (this.hasValue) { + this.hasValue = false; + this.destination.next(this.lastValue); + } + }; + return SampleTimeSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +function dispatchNotification(state) { + var subscriber = state.subscriber, period = state.period; + subscriber.notifyNext(); + this.schedule(state, period); +} +//# sourceMappingURL=sampleTime.js.map /***/ }), -/* 508 */ -/***/ (function(module, exports, __webpack_require__) { +/* 466 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sequenceEqual", function() { return sequenceEqual; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SequenceEqualOperator", function() { return SequenceEqualOperator; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SequenceEqualSubscriber", function() { return SequenceEqualSubscriber; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ -const arrayDiffer = (array, ...values) => { - const rest = new Set([].concat(...values)); - return array.filter(element => !rest.has(element)); -}; +function sequenceEqual(compareTo, comparator) { + return function (source) { return source.lift(new SequenceEqualOperator(compareTo, comparator)); }; +} +var SequenceEqualOperator = /*@__PURE__*/ (function () { + function SequenceEqualOperator(compareTo, comparator) { + this.compareTo = compareTo; + this.comparator = comparator; + } + SequenceEqualOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new SequenceEqualSubscriber(subscriber, this.compareTo, this.comparator)); + }; + return SequenceEqualOperator; +}()); -module.exports = arrayDiffer; +var SequenceEqualSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SequenceEqualSubscriber, _super); + function SequenceEqualSubscriber(destination, compareTo, comparator) { + var _this = _super.call(this, destination) || this; + _this.compareTo = compareTo; + _this.comparator = comparator; + _this._a = []; + _this._b = []; + _this._oneComplete = false; + _this.destination.add(compareTo.subscribe(new SequenceEqualCompareToSubscriber(destination, _this))); + return _this; + } + SequenceEqualSubscriber.prototype._next = function (value) { + if (this._oneComplete && this._b.length === 0) { + this.emit(false); + } + else { + this._a.push(value); + this.checkValues(); + } + }; + SequenceEqualSubscriber.prototype._complete = function () { + if (this._oneComplete) { + this.emit(this._a.length === 0 && this._b.length === 0); + } + else { + this._oneComplete = true; + } + this.unsubscribe(); + }; + SequenceEqualSubscriber.prototype.checkValues = function () { + var _c = this, _a = _c._a, _b = _c._b, comparator = _c.comparator; + while (_a.length > 0 && _b.length > 0) { + var a = _a.shift(); + var b = _b.shift(); + var areEqual = false; + try { + areEqual = comparator ? comparator(a, b) : a === b; + } + catch (e) { + this.destination.error(e); + } + if (!areEqual) { + this.emit(false); + } + } + }; + SequenceEqualSubscriber.prototype.emit = function (value) { + var destination = this.destination; + destination.next(value); + destination.complete(); + }; + SequenceEqualSubscriber.prototype.nextB = function (value) { + if (this._oneComplete && this._a.length === 0) { + this.emit(false); + } + else { + this._b.push(value); + this.checkValues(); + } + }; + SequenceEqualSubscriber.prototype.completeB = function () { + if (this._oneComplete) { + this.emit(this._a.length === 0 && this._b.length === 0); + } + else { + this._oneComplete = true; + } + }; + return SequenceEqualSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); + +var SequenceEqualCompareToSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SequenceEqualCompareToSubscriber, _super); + function SequenceEqualCompareToSubscriber(destination, parent) { + var _this = _super.call(this, destination) || this; + _this.parent = parent; + return _this; + } + SequenceEqualCompareToSubscriber.prototype._next = function (value) { + this.parent.nextB(value); + }; + SequenceEqualCompareToSubscriber.prototype._error = function (err) { + this.parent.error(err); + this.unsubscribe(); + }; + SequenceEqualCompareToSubscriber.prototype._complete = function () { + this.parent.completeB(); + this.unsubscribe(); + }; + return SequenceEqualCompareToSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +//# sourceMappingURL=sequenceEqual.js.map /***/ }), -/* 509 */ -/***/ (function(module, exports, __webpack_require__) { +/* 467 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "share", function() { return share; }); +/* harmony import */ var _multicast__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(450); +/* harmony import */ var _refCount__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(30); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(27); +/** PURE_IMPORTS_START _multicast,_refCount,_Subject PURE_IMPORTS_END */ -const arrify = value => { - if (value === null || value === undefined) { - return []; - } - if (Array.isArray(value)) { - return value; - } +function shareSubjectFactory() { + return new _Subject__WEBPACK_IMPORTED_MODULE_2__["Subject"](); +} +function share() { + return function (source) { return Object(_refCount__WEBPACK_IMPORTED_MODULE_1__["refCount"])()(Object(_multicast__WEBPACK_IMPORTED_MODULE_0__["multicast"])(shareSubjectFactory)(source)); }; +} +//# sourceMappingURL=share.js.map - if (typeof value === 'string') { - return [value]; - } - if (typeof value[Symbol.iterator] === 'function') { - return [...value]; - } +/***/ }), +/* 468 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - return [value]; -}; +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "shareReplay", function() { return shareReplay; }); +/* harmony import */ var _ReplaySubject__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(33); +/** PURE_IMPORTS_START _ReplaySubject PURE_IMPORTS_END */ -module.exports = arrify; +function shareReplay(configOrBufferSize, windowTime, scheduler) { + var config; + if (configOrBufferSize && typeof configOrBufferSize === 'object') { + config = configOrBufferSize; + } + else { + config = { + bufferSize: configOrBufferSize, + windowTime: windowTime, + refCount: false, + scheduler: scheduler + }; + } + return function (source) { return source.lift(shareReplayOperator(config)); }; +} +function shareReplayOperator(_a) { + var _b = _a.bufferSize, bufferSize = _b === void 0 ? Number.POSITIVE_INFINITY : _b, _c = _a.windowTime, windowTime = _c === void 0 ? Number.POSITIVE_INFINITY : _c, useRefCount = _a.refCount, scheduler = _a.scheduler; + var subject; + var refCount = 0; + var subscription; + var hasError = false; + var isComplete = false; + return function shareReplayOperation(source) { + refCount++; + if (!subject || hasError) { + hasError = false; + subject = new _ReplaySubject__WEBPACK_IMPORTED_MODULE_0__["ReplaySubject"](bufferSize, windowTime, scheduler); + subscription = source.subscribe({ + next: function (value) { subject.next(value); }, + error: function (err) { + hasError = true; + subject.error(err); + }, + complete: function () { + isComplete = true; + subscription = undefined; + subject.complete(); + }, + }); + } + var innerSub = subject.subscribe(this); + this.add(function () { + refCount--; + innerSub.unsubscribe(); + if (subscription && !isComplete && useRefCount && refCount === 0) { + subscription.unsubscribe(); + subscription = undefined; + subject = undefined; + } + }); + }; +} +//# sourceMappingURL=shareReplay.js.map /***/ }), -/* 510 */ -/***/ (function(module, exports, __webpack_require__) { +/* 469 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "single", function() { return single; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/* harmony import */ var _util_EmptyError__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(63); +/** PURE_IMPORTS_START tslib,_Subscriber,_util_EmptyError PURE_IMPORTS_END */ -const path = __webpack_require__(4); - -module.exports = (childPath, parentPath) => { - childPath = path.resolve(childPath); - parentPath = path.resolve(parentPath); - - if (process.platform === 'win32') { - childPath = childPath.toLowerCase(); - parentPath = parentPath.toLowerCase(); - } - - if (childPath === parentPath) { - return false; - } - childPath += path.sep; - parentPath += path.sep; - return childPath.startsWith(parentPath); -}; +function single(predicate) { + return function (source) { return source.lift(new SingleOperator(predicate, source)); }; +} +var SingleOperator = /*@__PURE__*/ (function () { + function SingleOperator(predicate, source) { + this.predicate = predicate; + this.source = source; + } + SingleOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new SingleSubscriber(subscriber, this.predicate, this.source)); + }; + return SingleOperator; +}()); +var SingleSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SingleSubscriber, _super); + function SingleSubscriber(destination, predicate, source) { + var _this = _super.call(this, destination) || this; + _this.predicate = predicate; + _this.source = source; + _this.seenValue = false; + _this.index = 0; + return _this; + } + SingleSubscriber.prototype.applySingleValue = function (value) { + if (this.seenValue) { + this.destination.error('Sequence contains more than one element'); + } + else { + this.seenValue = true; + this.singleValue = value; + } + }; + SingleSubscriber.prototype._next = function (value) { + var index = this.index++; + if (this.predicate) { + this.tryNext(value, index); + } + else { + this.applySingleValue(value); + } + }; + SingleSubscriber.prototype.tryNext = function (value, index) { + try { + if (this.predicate(value, index, this.source)) { + this.applySingleValue(value); + } + } + catch (err) { + this.destination.error(err); + } + }; + SingleSubscriber.prototype._complete = function () { + var destination = this.destination; + if (this.index > 0) { + destination.next(this.seenValue ? this.singleValue : undefined); + destination.complete(); + } + else { + destination.error(new _util_EmptyError__WEBPACK_IMPORTED_MODULE_2__["EmptyError"]); + } + }; + return SingleSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +//# sourceMappingURL=single.js.map /***/ }), -/* 511 */ +/* 470 */ /***/ (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__(512); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _build_production_projects__WEBPACK_IMPORTED_MODULE_0__["buildProductionProjects"]; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "skip", function() { return skip; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ -/* - * 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 skip(count) { + return function (source) { return source.lift(new SkipOperator(count)); }; +} +var SkipOperator = /*@__PURE__*/ (function () { + function SkipOperator(total) { + this.total = total; + } + SkipOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new SkipSubscriber(subscriber, this.total)); + }; + return SkipOperator; +}()); +var SkipSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SkipSubscriber, _super); + function SkipSubscriber(destination, total) { + var _this = _super.call(this, destination) || this; + _this.total = total; + _this.count = 0; + return _this; + } + SkipSubscriber.prototype._next = function (x) { + if (++this.count > this.total) { + this.destination.next(x); + } + }; + return SkipSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +//# sourceMappingURL=skip.js.map /***/ }), -/* 512 */ +/* 471 */ /***/ (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__(513); -/* 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__(296); -/* 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__(4); -/* 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__(288); -/* harmony import */ var _utils_fs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(130); -/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(143); -/* harmony import */ var _utils_package_json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(164); -/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(145); -/* - * 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. - */ +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "skipLast", function() { return skipLast; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/* harmony import */ var _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(62); +/** PURE_IMPORTS_START tslib,_Subscriber,_util_ArgumentOutOfRangeError PURE_IMPORTS_END */ +function skipLast(count) { + return function (source) { return source.lift(new SkipLastOperator(count)); }; +} +var SkipLastOperator = /*@__PURE__*/ (function () { + function SkipLastOperator(_skipCount) { + this._skipCount = _skipCount; + if (this._skipCount < 0) { + throw new _util_ArgumentOutOfRangeError__WEBPACK_IMPORTED_MODULE_2__["ArgumentOutOfRangeError"]; + } + } + SkipLastOperator.prototype.call = function (subscriber, source) { + if (this._skipCount === 0) { + return source.subscribe(new _Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"](subscriber)); + } + else { + return source.subscribe(new SkipLastSubscriber(subscriber, this._skipCount)); + } + }; + return SkipLastOperator; +}()); +var SkipLastSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SkipLastSubscriber, _super); + function SkipLastSubscriber(destination, _skipCount) { + var _this = _super.call(this, destination) || this; + _this._skipCount = _skipCount; + _this._count = 0; + _this._ring = new Array(_skipCount); + return _this; + } + SkipLastSubscriber.prototype._next = function (value) { + var skipCount = this._skipCount; + var count = this._count++; + if (count < skipCount) { + this._ring[count] = value; + } + else { + var currentIndex = count % skipCount; + var ring = this._ring; + var oldValue = ring[currentIndex]; + ring[currentIndex] = value; + this.destination.next(oldValue); + } + }; + return SkipLastSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +//# sourceMappingURL=skipLast.js.map + +/***/ }), +/* 472 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "skipUntil", function() { return skipUntil; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); +/* harmony import */ var _InnerSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(70); +/** PURE_IMPORTS_START tslib,_OuterSubscriber,_InnerSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ -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"].info(`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); - } - } +function skipUntil(notifier) { + return function (source) { return source.lift(new SkipUntilOperator(notifier)); }; } -/** - * 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')]; +var SkipUntilOperator = /*@__PURE__*/ (function () { + function SkipUntilOperator(notifier) { + this.notifier = notifier; + } + SkipUntilOperator.prototype.call = function (destination, source) { + return source.subscribe(new SkipUntilSubscriber(destination, this.notifier)); + }; + return SkipUntilOperator; +}()); +var SkipUntilSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SkipUntilSubscriber, _super); + function SkipUntilSubscriber(destination, notifier) { + var _this = _super.call(this, destination) || this; + _this.hasValue = false; + var innerSubscriber = new _InnerSubscriber__WEBPACK_IMPORTED_MODULE_2__["InnerSubscriber"](_this, undefined, undefined); + _this.add(innerSubscriber); + _this.innerSubscription = innerSubscriber; + var innerSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__["subscribeToResult"])(_this, notifier, undefined, undefined, innerSubscriber); + if (innerSubscription !== innerSubscriber) { + _this.add(innerSubscription); + _this.innerSubscription = innerSubscription; + } + return _this; + } + SkipUntilSubscriber.prototype._next = function (value) { + if (this.hasValue) { + _super.prototype._next.call(this, value); + } + }; + SkipUntilSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + this.hasValue = true; + if (this.innerSubscription) { + this.innerSubscription.unsubscribe(); + } + }; + SkipUntilSubscriber.prototype.notifyComplete = function () { + }; + return SkipUntilSubscriber; +}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); +//# sourceMappingURL=skipUntil.js.map - 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 +/***/ }), +/* 473 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - productionProjects.delete('kibana'); +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "skipWhile", function() { return skipWhile; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ - if (onlyOSS) { - productionProjects.forEach(project => { - if (project.getBuildConfig().oss === false) { - productionProjects.delete(project.json.name); - } - }); - } - return productionProjects; +function skipWhile(predicate) { + return function (source) { return source.lift(new SkipWhileOperator(predicate)); }; } +var SkipWhileOperator = /*@__PURE__*/ (function () { + function SkipWhileOperator(predicate) { + this.predicate = predicate; + } + SkipWhileOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new SkipWhileSubscriber(subscriber, this.predicate)); + }; + return SkipWhileOperator; +}()); +var SkipWhileSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SkipWhileSubscriber, _super); + function SkipWhileSubscriber(destination, predicate) { + var _this = _super.call(this, destination) || this; + _this.predicate = predicate; + _this.skipping = true; + _this.index = 0; + return _this; + } + SkipWhileSubscriber.prototype._next = function (value) { + var destination = this.destination; + if (this.skipping) { + this.tryCallPredicate(value); + } + if (!this.skipping) { + destination.next(value); + } + }; + SkipWhileSubscriber.prototype.tryCallPredicate = function (value) { + try { + var result = this.predicate(value, this.index++); + this.skipping = Boolean(result); + } + catch (err) { + this.destination.error(err); + } + }; + return SkipWhileSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +//# sourceMappingURL=skipWhile.js.map -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 - }); - } -} +/***/ }), +/* 474 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -async function buildProject(project) { - if (project.hasScript('build')) { - await project.runScript('build'); - } +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "startWith", function() { return startWith; }); +/* harmony import */ var _observable_concat__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(79); +/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(45); +/** PURE_IMPORTS_START _observable_concat,_util_isScheduler PURE_IMPORTS_END */ + + +function startWith() { + var array = []; + for (var _i = 0; _i < arguments.length; _i++) { + array[_i] = arguments[_i]; + } + var scheduler = array[array.length - 1]; + if (Object(_util_isScheduler__WEBPACK_IMPORTED_MODULE_1__["isScheduler"])(scheduler)) { + array.pop(); + return function (source) { return Object(_observable_concat__WEBPACK_IMPORTED_MODULE_0__["concat"])(array, source, scheduler); }; + } + else { + return function (source) { return Object(_observable_concat__WEBPACK_IMPORTED_MODULE_0__["concat"])(array, source); }; + } } -/** - * 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. - */ +//# sourceMappingURL=startWith.js.map -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`. +/***/ }), +/* 475 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - 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); +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "subscribeOn", function() { return subscribeOn; }); +/* harmony import */ var _observable_SubscribeOnObservable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(476); +/** PURE_IMPORTS_START _observable_SubscribeOnObservable PURE_IMPORTS_END */ + +function subscribeOn(scheduler, delay) { + if (delay === void 0) { + delay = 0; + } + return function subscribeOnOperatorFunction(source) { + return source.lift(new SubscribeOnOperator(scheduler, delay)); + }; } +var SubscribeOnOperator = /*@__PURE__*/ (function () { + function SubscribeOnOperator(scheduler, delay) { + this.scheduler = scheduler; + this.delay = delay; + } + SubscribeOnOperator.prototype.call = function (subscriber, source) { + return new _observable_SubscribeOnObservable__WEBPACK_IMPORTED_MODULE_0__["SubscribeOnObservable"](source, this.delay, this.scheduler).subscribe(subscriber); + }; + return SubscribeOnOperator; +}()); +//# sourceMappingURL=subscribeOn.js.map + /***/ }), -/* 513 */ -/***/ (function(module, exports, __webpack_require__) { +/* 476 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SubscribeOnObservable", function() { return SubscribeOnObservable; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Observable__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9); +/* harmony import */ var _scheduler_asap__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(51); +/* harmony import */ var _util_isNumeric__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(97); +/** PURE_IMPORTS_START tslib,_Observable,_scheduler_asap,_util_isNumeric PURE_IMPORTS_END */ -const EventEmitter = __webpack_require__(155); -const path = __webpack_require__(4); -const os = __webpack_require__(120); -const pAll = __webpack_require__(514); -const arrify = __webpack_require__(516); -const globby = __webpack_require__(517); -const isGlob = __webpack_require__(732); -const cpFile = __webpack_require__(733); -const junk = __webpack_require__(745); -const CpyError = __webpack_require__(746); -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); +var SubscribeOnObservable = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SubscribeOnObservable, _super); + function SubscribeOnObservable(source, delayTime, scheduler) { + if (delayTime === void 0) { + delayTime = 0; + } + if (scheduler === void 0) { + scheduler = _scheduler_asap__WEBPACK_IMPORTED_MODULE_2__["asap"]; + } + var _this = _super.call(this) || this; + _this.source = source; + _this.delayTime = delayTime; + _this.scheduler = scheduler; + if (!Object(_util_isNumeric__WEBPACK_IMPORTED_MODULE_3__["isNumeric"])(delayTime) || delayTime < 0) { + _this.delayTime = 0; + } + if (!scheduler || typeof scheduler.schedule !== 'function') { + _this.scheduler = _scheduler_asap__WEBPACK_IMPORTED_MODULE_2__["asap"]; + } + return _this; + } + SubscribeOnObservable.create = function (source, delay, scheduler) { + if (delay === void 0) { + delay = 0; + } + if (scheduler === void 0) { + scheduler = _scheduler_asap__WEBPACK_IMPORTED_MODULE_2__["asap"]; + } + return new SubscribeOnObservable(source, delay, scheduler); + }; + SubscribeOnObservable.dispatch = function (arg) { + var source = arg.source, subscriber = arg.subscriber; + return this.add(source.subscribe(subscriber)); + }; + SubscribeOnObservable.prototype._subscribe = function (subscriber) { + var delay = this.delayTime; + var source = this.source; + var scheduler = this.scheduler; + return scheduler.schedule(SubscribeOnObservable.dispatch, delay, { + source: source, subscriber: subscriber + }); + }; + return SubscribeOnObservable; +}(_Observable__WEBPACK_IMPORTED_MODULE_1__["Observable"])); - if (typeof options.rename === 'string') { - basename = options.rename; - } else if (typeof options.rename === 'function') { - basename = options.rename(basename); - } +//# sourceMappingURL=SubscribeOnObservable.js.map - if (options.cwd) { - destination = path.resolve(options.cwd, destination); - } - if (options.parents) { - return path.join(destination, dirname, basename); - } +/***/ }), +/* 477 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - return path.join(destination, basename); -}; +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "switchAll", function() { return switchAll; }); +/* harmony import */ var _switchMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(478); +/* harmony import */ var _util_identity__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(25); +/** PURE_IMPORTS_START _switchMap,_util_identity PURE_IMPORTS_END */ -module.exports = (source, destination, { - concurrency = (os.cpus().length || 1) * 2, - ...options -} = {}) => { - const progressEmitter = new EventEmitter(); - options = { - ...defaultOptions, - ...options - }; +function switchAll() { + return Object(_switchMap__WEBPACK_IMPORTED_MODULE_0__["switchMap"])(_util_identity__WEBPACK_IMPORTED_MODULE_1__["identity"]); +} +//# sourceMappingURL=switchAll.js.map - const promise = (async () => { - source = arrify(source); - if (source.length === 0 || !destination) { - throw new CpyError('`source` and `destination` required'); - } +/***/ }), +/* 478 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - const copyStatus = new Map(); - let completedFiles = 0; - let completedSize = 0; +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "switchMap", function() { return switchMap; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); +/* harmony import */ var _InnerSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(71); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(70); +/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(66); +/* harmony import */ var _observable_from__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(83); +/** PURE_IMPORTS_START tslib,_OuterSubscriber,_InnerSubscriber,_util_subscribeToResult,_map,_observable_from PURE_IMPORTS_END */ - 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; +function switchMap(project, resultSelector) { + if (typeof resultSelector === 'function') { + return function (source) { return source.pipe(switchMap(function (a, i) { return Object(_observable_from__WEBPACK_IMPORTED_MODULE_5__["from"])(project(a, i)).pipe(Object(_map__WEBPACK_IMPORTED_MODULE_4__["map"])(function (b, ii) { return resultSelector(a, b, i, ii); })); })); }; + } + return function (source) { return source.lift(new SwitchMapOperator(project)); }; +} +var SwitchMapOperator = /*@__PURE__*/ (function () { + function SwitchMapOperator(project) { + this.project = project; + } + SwitchMapOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new SwitchMapSubscriber(subscriber, this.project)); + }; + return SwitchMapOperator; +}()); +var SwitchMapSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](SwitchMapSubscriber, _super); + function SwitchMapSubscriber(destination, project) { + var _this = _super.call(this, destination) || this; + _this.project = project; + _this.index = 0; + return _this; + } + SwitchMapSubscriber.prototype._next = function (value) { + var result; + var index = this.index++; + try { + result = this.project(value, index); + } + catch (error) { + this.destination.error(error); + return; + } + this._innerSub(result, value, index); + }; + SwitchMapSubscriber.prototype._innerSub = function (result, value, index) { + var innerSubscription = this.innerSubscription; + if (innerSubscription) { + innerSubscription.unsubscribe(); + } + var innerSubscriber = new _InnerSubscriber__WEBPACK_IMPORTED_MODULE_2__["InnerSubscriber"](this, value, index); + var destination = this.destination; + destination.add(innerSubscriber); + this.innerSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__["subscribeToResult"])(this, result, undefined, undefined, innerSubscriber); + if (this.innerSubscription !== innerSubscriber) { + destination.add(this.innerSubscription); + } + }; + SwitchMapSubscriber.prototype._complete = function () { + var innerSubscription = this.innerSubscription; + if (!innerSubscription || innerSubscription.closed) { + _super.prototype._complete.call(this); + } + this.unsubscribe(); + }; + SwitchMapSubscriber.prototype._unsubscribe = function () { + this.innerSubscription = null; + }; + SwitchMapSubscriber.prototype.notifyComplete = function (innerSub) { + var destination = this.destination; + destination.remove(innerSub); + this.innerSubscription = null; + if (this.isStopped) { + _super.prototype._complete.call(this); + } + }; + SwitchMapSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + this.destination.next(innerValue); + }; + return SwitchMapSubscriber; +}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); +//# sourceMappingURL=switchMap.js.map - if (event.percent === 1 && fileStatus.percent !== 1) { - completedFiles++; - } - copyStatus.set(event.src, { - written: event.written, - percent: event.percent - }); +/***/ }), +/* 479 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - progressEmitter.emit('progress', { - totalFiles: files.length, - percent: completedFiles / files.length, - completedFiles, - completedSize - }); - } - }; +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "switchMapTo", function() { return switchMapTo; }); +/* harmony import */ var _switchMap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(478); +/** PURE_IMPORTS_START _switchMap PURE_IMPORTS_END */ - return pAll(files.map(sourcePath => { - return async () => { - const from = preprocessSourcePath(sourcePath, options); - const to = preprocessDestinationPath(sourcePath, destination, options); +function switchMapTo(innerObservable, resultSelector) { + return resultSelector ? Object(_switchMap__WEBPACK_IMPORTED_MODULE_0__["switchMap"])(function () { return innerObservable; }, resultSelector) : Object(_switchMap__WEBPACK_IMPORTED_MODULE_0__["switchMap"])(function () { return innerObservable; }); +} +//# sourceMappingURL=switchMapTo.js.map - 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}); - })(); +/***/ }), +/* 480 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - promise.on = (...arguments_) => { - progressEmitter.on(...arguments_); - return promise; - }; +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "takeUntil", function() { return takeUntil; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(70); +/** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ - return promise; -}; + + +function takeUntil(notifier) { + return function (source) { return source.lift(new TakeUntilOperator(notifier)); }; +} +var TakeUntilOperator = /*@__PURE__*/ (function () { + function TakeUntilOperator(notifier) { + this.notifier = notifier; + } + TakeUntilOperator.prototype.call = function (subscriber, source) { + var takeUntilSubscriber = new TakeUntilSubscriber(subscriber); + var notifierSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(takeUntilSubscriber, this.notifier); + if (notifierSubscription && !takeUntilSubscriber.seenValue) { + takeUntilSubscriber.add(notifierSubscription); + return source.subscribe(takeUntilSubscriber); + } + return takeUntilSubscriber; + }; + return TakeUntilOperator; +}()); +var TakeUntilSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](TakeUntilSubscriber, _super); + function TakeUntilSubscriber(destination) { + var _this = _super.call(this, destination) || this; + _this.seenValue = false; + return _this; + } + TakeUntilSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + this.seenValue = true; + this.complete(); + }; + TakeUntilSubscriber.prototype.notifyComplete = function () { + }; + return TakeUntilSubscriber; +}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); +//# sourceMappingURL=takeUntil.js.map /***/ }), -/* 514 */ -/***/ (function(module, exports, __webpack_require__) { +/* 481 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "takeWhile", function() { return takeWhile; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/** PURE_IMPORTS_START tslib,_Subscriber PURE_IMPORTS_END */ -const pMap = __webpack_require__(515); -module.exports = (iterable, options) => pMap(iterable, element => element(), options); -// TODO: Remove this for the next major release -module.exports.default = module.exports; +function takeWhile(predicate, inclusive) { + if (inclusive === void 0) { + inclusive = false; + } + return function (source) { + return source.lift(new TakeWhileOperator(predicate, inclusive)); + }; +} +var TakeWhileOperator = /*@__PURE__*/ (function () { + function TakeWhileOperator(predicate, inclusive) { + this.predicate = predicate; + this.inclusive = inclusive; + } + TakeWhileOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new TakeWhileSubscriber(subscriber, this.predicate, this.inclusive)); + }; + return TakeWhileOperator; +}()); +var TakeWhileSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](TakeWhileSubscriber, _super); + function TakeWhileSubscriber(destination, predicate, inclusive) { + var _this = _super.call(this, destination) || this; + _this.predicate = predicate; + _this.inclusive = inclusive; + _this.index = 0; + return _this; + } + TakeWhileSubscriber.prototype._next = function (value) { + var destination = this.destination; + var result; + try { + result = this.predicate(value, this.index++); + } + catch (err) { + destination.error(err); + return; + } + this.nextOrComplete(value, result); + }; + TakeWhileSubscriber.prototype.nextOrComplete = function (value, predicateResult) { + var destination = this.destination; + if (Boolean(predicateResult)) { + destination.next(value); + } + else { + if (this.inclusive) { + destination.next(value); + } + destination.complete(); + } + }; + return TakeWhileSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +//# sourceMappingURL=takeWhile.js.map /***/ }), -/* 515 */ -/***/ (function(module, exports, __webpack_require__) { +/* 482 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "tap", function() { return tap; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/* harmony import */ var _util_noop__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(60); +/* harmony import */ var _util_isFunction__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(13); +/** PURE_IMPORTS_START tslib,_Subscriber,_util_noop,_util_isFunction PURE_IMPORTS_END */ -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; +function tap(nextOrObserver, error, complete) { + return function tapOperatorFunction(source) { + return source.lift(new DoOperator(nextOrObserver, error, complete)); + }; +} +var DoOperator = /*@__PURE__*/ (function () { + function DoOperator(nextOrObserver, error, complete) { + this.nextOrObserver = nextOrObserver; + this.error = error; + this.complete = complete; + } + DoOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new TapSubscriber(subscriber, this.nextOrObserver, this.error, this.complete)); + }; + return DoOperator; +}()); +var TapSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](TapSubscriber, _super); + function TapSubscriber(destination, observerOrNext, error, complete) { + var _this = _super.call(this, destination) || this; + _this._tapNext = _util_noop__WEBPACK_IMPORTED_MODULE_2__["noop"]; + _this._tapError = _util_noop__WEBPACK_IMPORTED_MODULE_2__["noop"]; + _this._tapComplete = _util_noop__WEBPACK_IMPORTED_MODULE_2__["noop"]; + _this._tapError = error || _util_noop__WEBPACK_IMPORTED_MODULE_2__["noop"]; + _this._tapComplete = complete || _util_noop__WEBPACK_IMPORTED_MODULE_2__["noop"]; + if (Object(_util_isFunction__WEBPACK_IMPORTED_MODULE_3__["isFunction"])(observerOrNext)) { + _this._context = _this; + _this._tapNext = observerOrNext; + } + else if (observerOrNext) { + _this._context = observerOrNext; + _this._tapNext = observerOrNext.next || _util_noop__WEBPACK_IMPORTED_MODULE_2__["noop"]; + _this._tapError = observerOrNext.error || _util_noop__WEBPACK_IMPORTED_MODULE_2__["noop"]; + _this._tapComplete = observerOrNext.complete || _util_noop__WEBPACK_IMPORTED_MODULE_2__["noop"]; + } + return _this; + } + TapSubscriber.prototype._next = function (value) { + try { + this._tapNext.call(this._context, value); + } + catch (err) { + this.destination.error(err); + return; + } + this.destination.next(value); + }; + TapSubscriber.prototype._error = function (err) { + try { + this._tapError.call(this._context, err); + } + catch (err) { + this.destination.error(err); + return; + } + this.destination.error(err); + }; + TapSubscriber.prototype._complete = function () { + try { + this._tapComplete.call(this._context); + } + catch (err) { + this.destination.error(err); + return; + } + return this.destination.complete(); + }; + return TapSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +//# sourceMappingURL=tap.js.map + - if (!(typeof concurrency === 'number' && concurrency >= 1)) { - throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${concurrency}\` (${typeof concurrency})`); - } +/***/ }), +/* 483 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - const ret = []; - const iterator = iterable[Symbol.iterator](); - let isRejected = false; - let isIterableDone = false; - let resolvingCount = 0; - let currentIndex = 0; +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "defaultThrottleConfig", function() { return defaultThrottleConfig; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "throttle", function() { return throttle; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(70); +/** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ - const next = () => { - if (isRejected) { - return; - } - const nextItem = iterator.next(); - const i = currentIndex; - currentIndex++; - if (nextItem.done) { - isIterableDone = true; +var defaultThrottleConfig = { + leading: true, + trailing: false +}; +function throttle(durationSelector, config) { + if (config === void 0) { + config = defaultThrottleConfig; + } + return function (source) { return source.lift(new ThrottleOperator(durationSelector, config.leading, config.trailing)); }; +} +var ThrottleOperator = /*@__PURE__*/ (function () { + function ThrottleOperator(durationSelector, leading, trailing) { + this.durationSelector = durationSelector; + this.leading = leading; + this.trailing = trailing; + } + ThrottleOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new ThrottleSubscriber(subscriber, this.durationSelector, this.leading, this.trailing)); + }; + return ThrottleOperator; +}()); +var ThrottleSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](ThrottleSubscriber, _super); + function ThrottleSubscriber(destination, durationSelector, _leading, _trailing) { + var _this = _super.call(this, destination) || this; + _this.destination = destination; + _this.durationSelector = durationSelector; + _this._leading = _leading; + _this._trailing = _trailing; + _this._hasValue = false; + return _this; + } + ThrottleSubscriber.prototype._next = function (value) { + this._hasValue = true; + this._sendValue = value; + if (!this._throttled) { + if (this._leading) { + this.send(); + } + else { + this.throttle(value); + } + } + }; + ThrottleSubscriber.prototype.send = function () { + var _a = this, _hasValue = _a._hasValue, _sendValue = _a._sendValue; + if (_hasValue) { + this.destination.next(_sendValue); + this.throttle(_sendValue); + } + this._hasValue = false; + this._sendValue = null; + }; + ThrottleSubscriber.prototype.throttle = function (value) { + var duration = this.tryDurationSelector(value); + if (!!duration) { + this.add(this._throttled = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(this, duration)); + } + }; + ThrottleSubscriber.prototype.tryDurationSelector = function (value) { + try { + return this.durationSelector(value); + } + catch (err) { + this.destination.error(err); + return null; + } + }; + ThrottleSubscriber.prototype.throttlingDone = function () { + var _a = this, _throttled = _a._throttled, _trailing = _a._trailing; + if (_throttled) { + _throttled.unsubscribe(); + } + this._throttled = null; + if (_trailing) { + this.send(); + } + }; + ThrottleSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + this.throttlingDone(); + }; + ThrottleSubscriber.prototype.notifyComplete = function () { + this.throttlingDone(); + }; + return ThrottleSubscriber; +}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); +//# sourceMappingURL=throttle.js.map - if (resolvingCount === 0) { - resolve(ret); - } - return; - } +/***/ }), +/* 484 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - resolvingCount++; +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "throttleTime", function() { return throttleTime; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(55); +/* harmony import */ var _throttle__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(483); +/** PURE_IMPORTS_START tslib,_Subscriber,_scheduler_async,_throttle PURE_IMPORTS_END */ - 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; +function throttleTime(duration, scheduler, config) { + if (scheduler === void 0) { + scheduler = _scheduler_async__WEBPACK_IMPORTED_MODULE_2__["async"]; + } + if (config === void 0) { + config = _throttle__WEBPACK_IMPORTED_MODULE_3__["defaultThrottleConfig"]; + } + return function (source) { return source.lift(new ThrottleTimeOperator(duration, scheduler, config.leading, config.trailing)); }; +} +var ThrottleTimeOperator = /*@__PURE__*/ (function () { + function ThrottleTimeOperator(duration, scheduler, leading, trailing) { + this.duration = duration; + this.scheduler = scheduler; + this.leading = leading; + this.trailing = trailing; + } + ThrottleTimeOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new ThrottleTimeSubscriber(subscriber, this.duration, this.scheduler, this.leading, this.trailing)); + }; + return ThrottleTimeOperator; +}()); +var ThrottleTimeSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](ThrottleTimeSubscriber, _super); + function ThrottleTimeSubscriber(destination, duration, scheduler, leading, trailing) { + var _this = _super.call(this, destination) || this; + _this.duration = duration; + _this.scheduler = scheduler; + _this.leading = leading; + _this.trailing = trailing; + _this._hasTrailingValue = false; + _this._trailingValue = null; + return _this; + } + ThrottleTimeSubscriber.prototype._next = function (value) { + if (this.throttled) { + if (this.trailing) { + this._trailingValue = value; + this._hasTrailingValue = true; + } + } + else { + this.add(this.throttled = this.scheduler.schedule(dispatchNext, this.duration, { subscriber: this })); + if (this.leading) { + this.destination.next(value); + } + else if (this.trailing) { + this._trailingValue = value; + this._hasTrailingValue = true; + } + } + }; + ThrottleTimeSubscriber.prototype._complete = function () { + if (this._hasTrailingValue) { + this.destination.next(this._trailingValue); + this.destination.complete(); + } + else { + this.destination.complete(); + } + }; + ThrottleTimeSubscriber.prototype.clearThrottle = function () { + var throttled = this.throttled; + if (throttled) { + if (this.trailing && this._hasTrailingValue) { + this.destination.next(this._trailingValue); + this._trailingValue = null; + this._hasTrailingValue = false; + } + throttled.unsubscribe(); + this.remove(throttled); + this.throttled = null; + } + }; + return ThrottleTimeSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +function dispatchNext(arg) { + var subscriber = arg.subscriber; + subscriber.clearThrottle(); +} +//# sourceMappingURL=throttleTime.js.map /***/ }), -/* 516 */ -/***/ (function(module, exports, __webpack_require__) { +/* 485 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timeInterval", function() { return timeInterval; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TimeInterval", function() { return TimeInterval; }); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(55); +/* harmony import */ var _scan__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(445); +/* harmony import */ var _observable_defer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(90); +/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(66); +/** PURE_IMPORTS_START _scheduler_async,_scan,_observable_defer,_map PURE_IMPORTS_END */ -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]; -}; +function timeInterval(scheduler) { + if (scheduler === void 0) { + scheduler = _scheduler_async__WEBPACK_IMPORTED_MODULE_0__["async"]; + } + return function (source) { + return Object(_observable_defer__WEBPACK_IMPORTED_MODULE_2__["defer"])(function () { + return source.pipe(Object(_scan__WEBPACK_IMPORTED_MODULE_1__["scan"])(function (_a, value) { + var current = _a.current; + return ({ value: value, current: scheduler.now(), last: current }); + }, { current: scheduler.now(), value: undefined, last: undefined }), Object(_map__WEBPACK_IMPORTED_MODULE_3__["map"])(function (_a) { + var current = _a.current, last = _a.last, value = _a.value; + return new TimeInterval(value, current - last); + })); + }); + }; +} +var TimeInterval = /*@__PURE__*/ (function () { + function TimeInterval(value, interval) { + this.value = value; + this.interval = interval; + } + return TimeInterval; +}()); -module.exports = arrify; +//# sourceMappingURL=timeInterval.js.map /***/ }), -/* 517 */ -/***/ (function(module, exports, __webpack_require__) { +/* 486 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timeout", function() { return timeout; }); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(55); +/* harmony import */ var _util_TimeoutError__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(64); +/* harmony import */ var _timeoutWith__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(487); +/* harmony import */ var _observable_throwError__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(49); +/** PURE_IMPORTS_START _scheduler_async,_util_TimeoutError,_timeoutWith,_observable_throwError PURE_IMPORTS_END */ -const fs = __webpack_require__(133); -const arrayUnion = __webpack_require__(518); -const glob = __webpack_require__(520); -const fastGlob = __webpack_require__(525); -const dirGlob = __webpack_require__(725); -const gitignore = __webpack_require__(728); - -const DEFAULT_FILTER = () => false; - -const isNegative = pattern => pattern[0] === '!'; - -const assertPatternsInput = patterns => { - if (!patterns.every(x => typeof x === 'string')) { - throw new TypeError('Patterns must be a string or an array of strings'); - } -}; -const checkCwdOption = options => { - if (options && options.cwd && !fs.statSync(options.cwd).isDirectory()) { - throw new Error('The `cwd` option must be a path to a directory'); - } -}; -const generateGlobTasks = (patterns, taskOptions) => { - patterns = arrayUnion([].concat(patterns)); - assertPatternsInput(patterns); - checkCwdOption(taskOptions); - const globTasks = []; +function timeout(due, scheduler) { + if (scheduler === void 0) { + scheduler = _scheduler_async__WEBPACK_IMPORTED_MODULE_0__["async"]; + } + return Object(_timeoutWith__WEBPACK_IMPORTED_MODULE_2__["timeoutWith"])(due, Object(_observable_throwError__WEBPACK_IMPORTED_MODULE_3__["throwError"])(new _util_TimeoutError__WEBPACK_IMPORTED_MODULE_1__["TimeoutError"]()), scheduler); +} +//# sourceMappingURL=timeout.js.map - taskOptions = Object.assign({ - ignore: [], - expandDirectories: true - }, taskOptions); - patterns.forEach((pattern, i) => { - if (isNegative(pattern)) { - return; - } +/***/ }), +/* 487 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - const ignore = patterns - .slice(i) - .filter(isNegative) - .map(pattern => pattern.slice(1)); +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timeoutWith", function() { return timeoutWith; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(55); +/* harmony import */ var _util_isDate__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(419); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(69); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(70); +/** PURE_IMPORTS_START tslib,_scheduler_async,_util_isDate,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ - const options = Object.assign({}, taskOptions, { - ignore: taskOptions.ignore.concat(ignore) - }); - globTasks.push({pattern, options}); - }); - return globTasks; -}; -const globDirs = (task, fn) => { - let options = {}; - if (task.options.cwd) { - options.cwd = task.options.cwd; - } - if (Array.isArray(task.options.expandDirectories)) { - options = Object.assign(options, {files: task.options.expandDirectories}); - } else if (typeof task.options.expandDirectories === 'object') { - options = Object.assign(options, task.options.expandDirectories); - } +function timeoutWith(due, withObservable, scheduler) { + if (scheduler === void 0) { + scheduler = _scheduler_async__WEBPACK_IMPORTED_MODULE_1__["async"]; + } + return function (source) { + var absoluteTimeout = Object(_util_isDate__WEBPACK_IMPORTED_MODULE_2__["isDate"])(due); + var waitFor = absoluteTimeout ? (+due - scheduler.now()) : Math.abs(due); + return source.lift(new TimeoutWithOperator(waitFor, absoluteTimeout, withObservable, scheduler)); + }; +} +var TimeoutWithOperator = /*@__PURE__*/ (function () { + function TimeoutWithOperator(waitFor, absoluteTimeout, withObservable, scheduler) { + this.waitFor = waitFor; + this.absoluteTimeout = absoluteTimeout; + this.withObservable = withObservable; + this.scheduler = scheduler; + } + TimeoutWithOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new TimeoutWithSubscriber(subscriber, this.absoluteTimeout, this.waitFor, this.withObservable, this.scheduler)); + }; + return TimeoutWithOperator; +}()); +var TimeoutWithSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](TimeoutWithSubscriber, _super); + function TimeoutWithSubscriber(destination, absoluteTimeout, waitFor, withObservable, scheduler) { + var _this = _super.call(this, destination) || this; + _this.absoluteTimeout = absoluteTimeout; + _this.waitFor = waitFor; + _this.withObservable = withObservable; + _this.scheduler = scheduler; + _this.action = null; + _this.scheduleTimeout(); + return _this; + } + TimeoutWithSubscriber.dispatchTimeout = function (subscriber) { + var withObservable = subscriber.withObservable; + subscriber._unsubscribeAndRecycle(); + subscriber.add(Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__["subscribeToResult"])(subscriber, withObservable)); + }; + TimeoutWithSubscriber.prototype.scheduleTimeout = function () { + var action = this.action; + if (action) { + this.action = action.schedule(this, this.waitFor); + } + else { + this.add(this.action = this.scheduler.schedule(TimeoutWithSubscriber.dispatchTimeout, this.waitFor, this)); + } + }; + TimeoutWithSubscriber.prototype._next = function (value) { + if (!this.absoluteTimeout) { + this.scheduleTimeout(); + } + _super.prototype._next.call(this, value); + }; + TimeoutWithSubscriber.prototype._unsubscribe = function () { + this.action = null; + this.scheduler = null; + this.withObservable = null; + }; + return TimeoutWithSubscriber; +}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__["OuterSubscriber"])); +//# sourceMappingURL=timeoutWith.js.map - return fn(task.pattern, options); -}; -const getPattern = (task, fn) => task.options.expandDirectories ? globDirs(task, fn) : [task.pattern]; +/***/ }), +/* 488 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -const globToTask = task => glob => { - const {options} = task; - if (options.ignore && Array.isArray(options.ignore) && options.expandDirectories) { - options.ignore = dirGlob.sync(options.ignore); - } +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "timestamp", function() { return timestamp; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Timestamp", function() { return Timestamp; }); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(55); +/* harmony import */ var _map__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(66); +/** PURE_IMPORTS_START _scheduler_async,_map PURE_IMPORTS_END */ - return { - pattern: glob, - options - }; -}; -const globby = (patterns, options) => { - let globTasks; +function timestamp(scheduler) { + if (scheduler === void 0) { + scheduler = _scheduler_async__WEBPACK_IMPORTED_MODULE_0__["async"]; + } + return Object(_map__WEBPACK_IMPORTED_MODULE_1__["map"])(function (value) { return new Timestamp(value, scheduler.now()); }); +} +var Timestamp = /*@__PURE__*/ (function () { + function Timestamp(value, timestamp) { + this.value = value; + this.timestamp = timestamp; + } + return Timestamp; +}()); - try { - globTasks = generateGlobTasks(patterns, options); - } catch (error) { - return Promise.reject(error); - } +//# sourceMappingURL=timestamp.js.map - const getTasks = Promise.all(globTasks.map(task => Promise.resolve(getPattern(task, dirGlob)) - .then(globs => Promise.all(globs.map(globToTask(task)))) - )) - .then(tasks => arrayUnion(...tasks)); - const getFilter = () => { - return Promise.resolve( - options && options.gitignore ? - gitignore({cwd: options.cwd, ignore: options.ignore}) : - DEFAULT_FILTER - ); - }; +/***/ }), +/* 489 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - return getFilter() - .then(filter => { - return getTasks - .then(tasks => Promise.all(tasks.map(task => fastGlob(task.pattern, task.options)))) - .then(paths => arrayUnion(...paths)) - .then(paths => paths.filter(p => !filter(p))); - }); -}; +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "toArray", function() { return toArray; }); +/* harmony import */ var _reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(444); +/** PURE_IMPORTS_START _reduce PURE_IMPORTS_END */ -module.exports = globby; -// TODO: Remove this for the next major release -module.exports.default = globby; +function toArrayReducer(arr, item, index) { + if (index === 0) { + return [item]; + } + arr.push(item); + return arr; +} +function toArray() { + return Object(_reduce__WEBPACK_IMPORTED_MODULE_0__["reduce"])(toArrayReducer, []); +} +//# sourceMappingURL=toArray.js.map -module.exports.sync = (patterns, options) => { - const globTasks = generateGlobTasks(patterns, options); - const getFilter = () => { - return options && options.gitignore ? - gitignore.sync({cwd: options.cwd, ignore: options.ignore}) : - DEFAULT_FILTER; - }; +/***/ }), +/* 490 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - const tasks = globTasks.reduce((tasks, task) => { - const newTask = getPattern(task, dirGlob.sync).map(globToTask(task)); - return tasks.concat(newTask); - }, []); +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "window", function() { return window; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(27); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(69); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(70); +/** PURE_IMPORTS_START tslib,_Subject,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ - const filter = getFilter(); - return tasks.reduce( - (matches, task) => arrayUnion(matches, fastGlob.sync(task.pattern, task.options)), - [] - ).filter(p => !filter(p)); -}; -module.exports.generateGlobTasks = generateGlobTasks; -module.exports.hasMagic = (patterns, options) => [] - .concat(patterns) - .some(pattern => glob.hasMagic(pattern, options)); -module.exports.gitignore = gitignore; +function window(windowBoundaries) { + return function windowOperatorFunction(source) { + return source.lift(new WindowOperator(windowBoundaries)); + }; +} +var WindowOperator = /*@__PURE__*/ (function () { + function WindowOperator(windowBoundaries) { + this.windowBoundaries = windowBoundaries; + } + WindowOperator.prototype.call = function (subscriber, source) { + var windowSubscriber = new WindowSubscriber(subscriber); + var sourceSubscription = source.subscribe(windowSubscriber); + if (!sourceSubscription.closed) { + windowSubscriber.add(Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__["subscribeToResult"])(windowSubscriber, this.windowBoundaries)); + } + return sourceSubscription; + }; + return WindowOperator; +}()); +var WindowSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](WindowSubscriber, _super); + function WindowSubscriber(destination) { + var _this = _super.call(this, destination) || this; + _this.window = new _Subject__WEBPACK_IMPORTED_MODULE_1__["Subject"](); + destination.next(_this.window); + return _this; + } + WindowSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + this.openWindow(); + }; + WindowSubscriber.prototype.notifyError = function (error, innerSub) { + this._error(error); + }; + WindowSubscriber.prototype.notifyComplete = function (innerSub) { + this._complete(); + }; + WindowSubscriber.prototype._next = function (value) { + this.window.next(value); + }; + WindowSubscriber.prototype._error = function (err) { + this.window.error(err); + this.destination.error(err); + }; + WindowSubscriber.prototype._complete = function () { + this.window.complete(); + this.destination.complete(); + }; + WindowSubscriber.prototype._unsubscribe = function () { + this.window = null; + }; + WindowSubscriber.prototype.openWindow = function () { + var prevWindow = this.window; + if (prevWindow) { + prevWindow.complete(); + } + var destination = this.destination; + var newWindow = this.window = new _Subject__WEBPACK_IMPORTED_MODULE_1__["Subject"](); + destination.next(newWindow); + }; + return WindowSubscriber; +}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__["OuterSubscriber"])); +//# sourceMappingURL=window.js.map /***/ }), -/* 518 */ -/***/ (function(module, exports, __webpack_require__) { +/* 491 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "windowCount", function() { return windowCount; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(27); +/** PURE_IMPORTS_START tslib,_Subscriber,_Subject PURE_IMPORTS_END */ -var arrayUniq = __webpack_require__(519); -module.exports = function () { - return arrayUniq([].concat.apply([], arguments)); -}; + +function windowCount(windowSize, startWindowEvery) { + if (startWindowEvery === void 0) { + startWindowEvery = 0; + } + return function windowCountOperatorFunction(source) { + return source.lift(new WindowCountOperator(windowSize, startWindowEvery)); + }; +} +var WindowCountOperator = /*@__PURE__*/ (function () { + function WindowCountOperator(windowSize, startWindowEvery) { + this.windowSize = windowSize; + this.startWindowEvery = startWindowEvery; + } + WindowCountOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new WindowCountSubscriber(subscriber, this.windowSize, this.startWindowEvery)); + }; + return WindowCountOperator; +}()); +var WindowCountSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](WindowCountSubscriber, _super); + function WindowCountSubscriber(destination, windowSize, startWindowEvery) { + var _this = _super.call(this, destination) || this; + _this.destination = destination; + _this.windowSize = windowSize; + _this.startWindowEvery = startWindowEvery; + _this.windows = [new _Subject__WEBPACK_IMPORTED_MODULE_2__["Subject"]()]; + _this.count = 0; + destination.next(_this.windows[0]); + return _this; + } + WindowCountSubscriber.prototype._next = function (value) { + var startWindowEvery = (this.startWindowEvery > 0) ? this.startWindowEvery : this.windowSize; + var destination = this.destination; + var windowSize = this.windowSize; + var windows = this.windows; + var len = windows.length; + for (var i = 0; i < len && !this.closed; i++) { + windows[i].next(value); + } + var c = this.count - windowSize + 1; + if (c >= 0 && c % startWindowEvery === 0 && !this.closed) { + windows.shift().complete(); + } + if (++this.count % startWindowEvery === 0 && !this.closed) { + var window_1 = new _Subject__WEBPACK_IMPORTED_MODULE_2__["Subject"](); + windows.push(window_1); + destination.next(window_1); + } + }; + WindowCountSubscriber.prototype._error = function (err) { + var windows = this.windows; + if (windows) { + while (windows.length > 0 && !this.closed) { + windows.shift().error(err); + } + } + this.destination.error(err); + }; + WindowCountSubscriber.prototype._complete = function () { + var windows = this.windows; + if (windows) { + while (windows.length > 0 && !this.closed) { + windows.shift().complete(); + } + } + this.destination.complete(); + }; + WindowCountSubscriber.prototype._unsubscribe = function () { + this.count = 0; + this.windows = null; + }; + return WindowCountSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_1__["Subscriber"])); +//# sourceMappingURL=windowCount.js.map /***/ }), -/* 519 */ -/***/ (function(module, exports, __webpack_require__) { +/* 492 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "windowTime", function() { return windowTime; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(27); +/* harmony import */ var _scheduler_async__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(55); +/* harmony import */ var _Subscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(11); +/* harmony import */ var _util_isNumeric__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(97); +/* harmony import */ var _util_isScheduler__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(45); +/** PURE_IMPORTS_START tslib,_Subject,_scheduler_async,_Subscriber,_util_isNumeric,_util_isScheduler PURE_IMPORTS_END */ -// there's 3 implementations written in increasing order of efficiency - -// 1 - no Set type is defined -function uniqNoSet(arr) { - var ret = []; - for (var i = 0; i < arr.length; i++) { - if (ret.indexOf(arr[i]) === -1) { - ret.push(arr[i]); - } - } - return ret; -} -// 2 - a simple Set type is defined -function uniqSet(arr) { - var seen = new Set(); - return arr.filter(function (el) { - if (!seen.has(el)) { - seen.add(el); - return true; - } - return false; - }); +function windowTime(windowTimeSpan) { + var scheduler = _scheduler_async__WEBPACK_IMPORTED_MODULE_2__["async"]; + var windowCreationInterval = null; + var maxWindowSize = Number.POSITIVE_INFINITY; + if (Object(_util_isScheduler__WEBPACK_IMPORTED_MODULE_5__["isScheduler"])(arguments[3])) { + scheduler = arguments[3]; + } + if (Object(_util_isScheduler__WEBPACK_IMPORTED_MODULE_5__["isScheduler"])(arguments[2])) { + scheduler = arguments[2]; + } + else if (Object(_util_isNumeric__WEBPACK_IMPORTED_MODULE_4__["isNumeric"])(arguments[2])) { + maxWindowSize = arguments[2]; + } + if (Object(_util_isScheduler__WEBPACK_IMPORTED_MODULE_5__["isScheduler"])(arguments[1])) { + scheduler = arguments[1]; + } + else if (Object(_util_isNumeric__WEBPACK_IMPORTED_MODULE_4__["isNumeric"])(arguments[1])) { + windowCreationInterval = arguments[1]; + } + return function windowTimeOperatorFunction(source) { + return source.lift(new WindowTimeOperator(windowTimeSpan, windowCreationInterval, maxWindowSize, scheduler)); + }; +} +var WindowTimeOperator = /*@__PURE__*/ (function () { + function WindowTimeOperator(windowTimeSpan, windowCreationInterval, maxWindowSize, scheduler) { + this.windowTimeSpan = windowTimeSpan; + this.windowCreationInterval = windowCreationInterval; + this.maxWindowSize = maxWindowSize; + this.scheduler = scheduler; + } + WindowTimeOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new WindowTimeSubscriber(subscriber, this.windowTimeSpan, this.windowCreationInterval, this.maxWindowSize, this.scheduler)); + }; + return WindowTimeOperator; +}()); +var CountedSubject = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](CountedSubject, _super); + function CountedSubject() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this._numberOfNextedValues = 0; + return _this; + } + CountedSubject.prototype.next = function (value) { + this._numberOfNextedValues++; + _super.prototype.next.call(this, value); + }; + Object.defineProperty(CountedSubject.prototype, "numberOfNextedValues", { + get: function () { + return this._numberOfNextedValues; + }, + enumerable: true, + configurable: true + }); + return CountedSubject; +}(_Subject__WEBPACK_IMPORTED_MODULE_1__["Subject"])); +var WindowTimeSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](WindowTimeSubscriber, _super); + function WindowTimeSubscriber(destination, windowTimeSpan, windowCreationInterval, maxWindowSize, scheduler) { + var _this = _super.call(this, destination) || this; + _this.destination = destination; + _this.windowTimeSpan = windowTimeSpan; + _this.windowCreationInterval = windowCreationInterval; + _this.maxWindowSize = maxWindowSize; + _this.scheduler = scheduler; + _this.windows = []; + var window = _this.openWindow(); + if (windowCreationInterval !== null && windowCreationInterval >= 0) { + var closeState = { subscriber: _this, window: window, context: null }; + var creationState = { windowTimeSpan: windowTimeSpan, windowCreationInterval: windowCreationInterval, subscriber: _this, scheduler: scheduler }; + _this.add(scheduler.schedule(dispatchWindowClose, windowTimeSpan, closeState)); + _this.add(scheduler.schedule(dispatchWindowCreation, windowCreationInterval, creationState)); + } + else { + var timeSpanOnlyState = { subscriber: _this, window: window, windowTimeSpan: windowTimeSpan }; + _this.add(scheduler.schedule(dispatchWindowTimeSpanOnly, windowTimeSpan, timeSpanOnlyState)); + } + return _this; + } + WindowTimeSubscriber.prototype._next = function (value) { + var windows = this.windows; + var len = windows.length; + for (var i = 0; i < len; i++) { + var window_1 = windows[i]; + if (!window_1.closed) { + window_1.next(value); + if (window_1.numberOfNextedValues >= this.maxWindowSize) { + this.closeWindow(window_1); + } + } + } + }; + WindowTimeSubscriber.prototype._error = function (err) { + var windows = this.windows; + while (windows.length > 0) { + windows.shift().error(err); + } + this.destination.error(err); + }; + WindowTimeSubscriber.prototype._complete = function () { + var windows = this.windows; + while (windows.length > 0) { + var window_2 = windows.shift(); + if (!window_2.closed) { + window_2.complete(); + } + } + this.destination.complete(); + }; + WindowTimeSubscriber.prototype.openWindow = function () { + var window = new CountedSubject(); + this.windows.push(window); + var destination = this.destination; + destination.next(window); + return window; + }; + WindowTimeSubscriber.prototype.closeWindow = function (window) { + window.complete(); + var windows = this.windows; + windows.splice(windows.indexOf(window), 1); + }; + return WindowTimeSubscriber; +}(_Subscriber__WEBPACK_IMPORTED_MODULE_3__["Subscriber"])); +function dispatchWindowTimeSpanOnly(state) { + var subscriber = state.subscriber, windowTimeSpan = state.windowTimeSpan, window = state.window; + if (window) { + subscriber.closeWindow(window); + } + state.window = subscriber.openWindow(); + this.schedule(state, windowTimeSpan); +} +function dispatchWindowCreation(state) { + var windowTimeSpan = state.windowTimeSpan, subscriber = state.subscriber, scheduler = state.scheduler, windowCreationInterval = state.windowCreationInterval; + var window = subscriber.openWindow(); + var action = this; + var context = { action: action, subscription: null }; + var timeSpanState = { subscriber: subscriber, window: window, context: context }; + context.subscription = scheduler.schedule(dispatchWindowClose, windowTimeSpan, timeSpanState); + action.add(context.subscription); + action.schedule(state, windowCreationInterval); +} +function dispatchWindowClose(state) { + var subscriber = state.subscriber, window = state.window, context = state.context; + if (context && context.action && context.subscription) { + context.action.remove(context.subscription); + } + subscriber.closeWindow(window); } +//# sourceMappingURL=windowTime.js.map -// 3 - a standard Set type is defined and it has a forEach method -function uniqSetWithForEach(arr) { - var ret = []; - (new Set(arr)).forEach(function (el) { - ret.push(el); - }); +/***/ }), +/* 493 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - return ret; -} +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "windowToggle", function() { return windowToggle; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(27); +/* harmony import */ var _Subscription__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(17); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(69); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(70); +/** PURE_IMPORTS_START tslib,_Subject,_Subscription,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ -// V8 currently has a broken implementation -// https://github.com/joyent/node/issues/8449 -function doesForEachActuallyWork() { - var ret = false; - (new Set([true])).forEach(function (el) { - ret = el; - }); - return ret === true; -} -if ('Set' in global) { - if (typeof Set.prototype.forEach === 'function' && doesForEachActuallyWork()) { - module.exports = uniqSetWithForEach; - } else { - module.exports = uniqSet; - } -} else { - module.exports = uniqNoSet; + +function windowToggle(openings, closingSelector) { + return function (source) { return source.lift(new WindowToggleOperator(openings, closingSelector)); }; } +var WindowToggleOperator = /*@__PURE__*/ (function () { + function WindowToggleOperator(openings, closingSelector) { + this.openings = openings; + this.closingSelector = closingSelector; + } + WindowToggleOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new WindowToggleSubscriber(subscriber, this.openings, this.closingSelector)); + }; + return WindowToggleOperator; +}()); +var WindowToggleSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](WindowToggleSubscriber, _super); + function WindowToggleSubscriber(destination, openings, closingSelector) { + var _this = _super.call(this, destination) || this; + _this.openings = openings; + _this.closingSelector = closingSelector; + _this.contexts = []; + _this.add(_this.openSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__["subscribeToResult"])(_this, openings, openings)); + return _this; + } + WindowToggleSubscriber.prototype._next = function (value) { + var contexts = this.contexts; + if (contexts) { + var len = contexts.length; + for (var i = 0; i < len; i++) { + contexts[i].window.next(value); + } + } + }; + WindowToggleSubscriber.prototype._error = function (err) { + var contexts = this.contexts; + this.contexts = null; + if (contexts) { + var len = contexts.length; + var index = -1; + while (++index < len) { + var context_1 = contexts[index]; + context_1.window.error(err); + context_1.subscription.unsubscribe(); + } + } + _super.prototype._error.call(this, err); + }; + WindowToggleSubscriber.prototype._complete = function () { + var contexts = this.contexts; + this.contexts = null; + if (contexts) { + var len = contexts.length; + var index = -1; + while (++index < len) { + var context_2 = contexts[index]; + context_2.window.complete(); + context_2.subscription.unsubscribe(); + } + } + _super.prototype._complete.call(this); + }; + WindowToggleSubscriber.prototype._unsubscribe = function () { + var contexts = this.contexts; + this.contexts = null; + if (contexts) { + var len = contexts.length; + var index = -1; + while (++index < len) { + var context_3 = contexts[index]; + context_3.window.unsubscribe(); + context_3.subscription.unsubscribe(); + } + } + }; + WindowToggleSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + if (outerValue === this.openings) { + var closingNotifier = void 0; + try { + var closingSelector = this.closingSelector; + closingNotifier = closingSelector(innerValue); + } + catch (e) { + return this.error(e); + } + var window_1 = new _Subject__WEBPACK_IMPORTED_MODULE_1__["Subject"](); + var subscription = new _Subscription__WEBPACK_IMPORTED_MODULE_2__["Subscription"](); + var context_4 = { window: window_1, subscription: subscription }; + this.contexts.push(context_4); + var innerSubscription = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_4__["subscribeToResult"])(this, closingNotifier, context_4); + if (innerSubscription.closed) { + this.closeWindow(this.contexts.length - 1); + } + else { + innerSubscription.context = context_4; + subscription.add(innerSubscription); + } + this.destination.next(window_1); + } + else { + this.closeWindow(this.contexts.indexOf(outerValue)); + } + }; + WindowToggleSubscriber.prototype.notifyError = function (err) { + this.error(err); + }; + WindowToggleSubscriber.prototype.notifyComplete = function (inner) { + if (inner !== this.openSubscription) { + this.closeWindow(this.contexts.indexOf(inner.context)); + } + }; + WindowToggleSubscriber.prototype.closeWindow = function (index) { + if (index === -1) { + return; + } + var contexts = this.contexts; + var context = contexts[index]; + var window = context.window, subscription = context.subscription; + contexts.splice(index, 1); + window.complete(); + subscription.unsubscribe(); + }; + return WindowToggleSubscriber; +}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_3__["OuterSubscriber"])); +//# sourceMappingURL=windowToggle.js.map /***/ }), -/* 520 */ -/***/ (function(module, exports, __webpack_require__) { - -// Approach: -// -// 1. Get the minimatch set -// 2. For each pattern in the set, PROCESS(pattern, false) -// 3. Store matches per-set, then uniq them -// -// PROCESS(pattern, inGlobStar) -// Get the first [n] items from pattern that are all strings -// Join these together. This is PREFIX. -// If there is no more remaining, then stat(PREFIX) and -// add to matches if it succeeds. END. -// -// If inGlobStar and PREFIX is symlink and points to dir -// set ENTRIES = [] -// else readdir(PREFIX) as ENTRIES -// If fail, END -// -// with ENTRIES -// If pattern[n] is GLOBSTAR -// // handle the case where the globstar match is empty -// // by pruning it out, and testing the resulting pattern -// PROCESS(pattern[0..n] + pattern[n+1 .. $], false) -// // handle other cases. -// for ENTRY in ENTRIES (not dotfiles) -// // attach globstar + tail onto the entry -// // Mark that this entry is a globstar match -// PROCESS(pattern[0..n] + ENTRY + pattern[n .. $], true) -// -// else // not globstar -// for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot) -// Test ENTRY against pattern[n] -// If fails, continue -// If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $]) -// -// Caveat: -// Cache all stats and readdirs results to minimize syscall. Since all -// we ever care about is existence and directory-ness, we can just keep -// `true` for files, and [children,...] for directories, or `false` for -// things that don't exist. - -module.exports = glob - -var fs = __webpack_require__(133) -var rp = __webpack_require__(147) -var minimatch = __webpack_require__(149) -var Minimatch = minimatch.Minimatch -var inherits = __webpack_require__(521) -var EE = __webpack_require__(155).EventEmitter -var path = __webpack_require__(4) -var assert = __webpack_require__(139) -var isAbsolute = __webpack_require__(156) -var globSync = __webpack_require__(523) -var common = __webpack_require__(524) -var alphasort = common.alphasort -var alphasorti = common.alphasorti -var setopts = common.setopts -var ownProp = common.ownProp -var inflight = __webpack_require__(159) -var util = __webpack_require__(111) -var childrenIgnored = common.childrenIgnored -var isIgnored = common.isIgnored - -var once = __webpack_require__(161) - -function glob (pattern, options, cb) { - if (typeof options === 'function') cb = options, options = {} - if (!options) options = {} - - if (options.sync) { - if (cb) - throw new TypeError('callback provided to sync glob') - return globSync(pattern, options) - } +/* 494 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - return new Glob(pattern, options, cb) -} +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "windowWhen", function() { return windowWhen; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _Subject__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(27); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(69); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(70); +/** PURE_IMPORTS_START tslib,_Subject,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ -glob.sync = globSync -var GlobSync = glob.GlobSync = globSync.GlobSync -// old api surface -glob.glob = glob -function extend (origin, add) { - if (add === null || typeof add !== 'object') { - return origin - } - var keys = Object.keys(add) - var i = keys.length - while (i--) { - origin[keys[i]] = add[keys[i]] - } - return origin +function windowWhen(closingSelector) { + return function windowWhenOperatorFunction(source) { + return source.lift(new WindowOperator(closingSelector)); + }; } +var WindowOperator = /*@__PURE__*/ (function () { + function WindowOperator(closingSelector) { + this.closingSelector = closingSelector; + } + WindowOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new WindowSubscriber(subscriber, this.closingSelector)); + }; + return WindowOperator; +}()); +var WindowSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](WindowSubscriber, _super); + function WindowSubscriber(destination, closingSelector) { + var _this = _super.call(this, destination) || this; + _this.destination = destination; + _this.closingSelector = closingSelector; + _this.openWindow(); + return _this; + } + WindowSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + this.openWindow(innerSub); + }; + WindowSubscriber.prototype.notifyError = function (error, innerSub) { + this._error(error); + }; + WindowSubscriber.prototype.notifyComplete = function (innerSub) { + this.openWindow(innerSub); + }; + WindowSubscriber.prototype._next = function (value) { + this.window.next(value); + }; + WindowSubscriber.prototype._error = function (err) { + this.window.error(err); + this.destination.error(err); + this.unsubscribeClosingNotification(); + }; + WindowSubscriber.prototype._complete = function () { + this.window.complete(); + this.destination.complete(); + this.unsubscribeClosingNotification(); + }; + WindowSubscriber.prototype.unsubscribeClosingNotification = function () { + if (this.closingNotification) { + this.closingNotification.unsubscribe(); + } + }; + WindowSubscriber.prototype.openWindow = function (innerSub) { + if (innerSub === void 0) { + innerSub = null; + } + if (innerSub) { + this.remove(innerSub); + innerSub.unsubscribe(); + } + var prevWindow = this.window; + if (prevWindow) { + prevWindow.complete(); + } + var window = this.window = new _Subject__WEBPACK_IMPORTED_MODULE_1__["Subject"](); + this.destination.next(window); + var closingNotifier; + try { + var closingSelector = this.closingSelector; + closingNotifier = closingSelector(); + } + catch (e) { + this.destination.error(e); + this.window.error(e); + return; + } + this.add(this.closingNotification = Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_3__["subscribeToResult"])(this, closingNotifier)); + }; + return WindowSubscriber; +}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_2__["OuterSubscriber"])); +//# sourceMappingURL=windowWhen.js.map -glob.hasMagic = function (pattern, options_) { - var options = extend({}, options_) - options.noprocess = true - var g = new Glob(pattern, options) - var set = g.minimatch.set +/***/ }), +/* 495 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - if (!pattern) - return false +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "withLatestFrom", function() { return withLatestFrom; }); +/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12); +/* harmony import */ var _OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(69); +/* harmony import */ var _util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(70); +/** PURE_IMPORTS_START tslib,_OuterSubscriber,_util_subscribeToResult PURE_IMPORTS_END */ - if (set.length > 1) - return true - for (var j = 0; j < set[0].length; j++) { - if (typeof set[0][j] !== 'string') - return true - } - return false +function withLatestFrom() { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + return function (source) { + var project; + if (typeof args[args.length - 1] === 'function') { + project = args.pop(); + } + var observables = args; + return source.lift(new WithLatestFromOperator(observables, project)); + }; } +var WithLatestFromOperator = /*@__PURE__*/ (function () { + function WithLatestFromOperator(observables, project) { + this.observables = observables; + this.project = project; + } + WithLatestFromOperator.prototype.call = function (subscriber, source) { + return source.subscribe(new WithLatestFromSubscriber(subscriber, this.observables, this.project)); + }; + return WithLatestFromOperator; +}()); +var WithLatestFromSubscriber = /*@__PURE__*/ (function (_super) { + tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](WithLatestFromSubscriber, _super); + function WithLatestFromSubscriber(destination, observables, project) { + var _this = _super.call(this, destination) || this; + _this.observables = observables; + _this.project = project; + _this.toRespond = []; + var len = observables.length; + _this.values = new Array(len); + for (var i = 0; i < len; i++) { + _this.toRespond.push(i); + } + for (var i = 0; i < len; i++) { + var observable = observables[i]; + _this.add(Object(_util_subscribeToResult__WEBPACK_IMPORTED_MODULE_2__["subscribeToResult"])(_this, observable, observable, i)); + } + return _this; + } + WithLatestFromSubscriber.prototype.notifyNext = function (outerValue, innerValue, outerIndex, innerIndex, innerSub) { + this.values[outerIndex] = innerValue; + var toRespond = this.toRespond; + if (toRespond.length > 0) { + var found = toRespond.indexOf(outerIndex); + if (found !== -1) { + toRespond.splice(found, 1); + } + } + }; + WithLatestFromSubscriber.prototype.notifyComplete = function () { + }; + WithLatestFromSubscriber.prototype._next = function (value) { + if (this.toRespond.length === 0) { + var args = [value].concat(this.values); + if (this.project) { + this._tryProject(args); + } + else { + this.destination.next(args); + } + } + }; + WithLatestFromSubscriber.prototype._tryProject = function (args) { + var result; + try { + result = this.project.apply(this, args); + } + catch (err) { + this.destination.error(err); + return; + } + this.destination.next(result); + }; + return WithLatestFromSubscriber; +}(_OuterSubscriber__WEBPACK_IMPORTED_MODULE_1__["OuterSubscriber"])); +//# sourceMappingURL=withLatestFrom.js.map -glob.Glob = Glob -inherits(Glob, EE) -function Glob (pattern, options, cb) { - if (typeof options === 'function') { - cb = options - options = null - } - - if (options && options.sync) { - if (cb) - throw new TypeError('callback provided to sync glob') - return new GlobSync(pattern, options) - } - - if (!(this instanceof Glob)) - return new Glob(pattern, options, cb) - - setopts(this, pattern, options) - this._didRealPath = false - - // process each pattern in the minimatch set - var n = this.minimatch.set.length - - // The matches are stored as {: true,...} so that - // duplicates are automagically pruned. - // Later, we do an Object.keys() on these. - // Keep them as a list so we can fill in when nonull is set. - this.matches = new Array(n) - - if (typeof cb === 'function') { - cb = once(cb) - this.on('error', cb) - this.on('end', function (matches) { - cb(null, matches) - }) - } - - var self = this - this._processing = 0 - - this._emitQueue = [] - this._processQueue = [] - this.paused = false - - if (this.noprocess) - return this - if (n === 0) - return done() +/***/ }), +/* 496 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - var sync = true - for (var i = 0; i < n; i ++) { - this._process(this.minimatch.set[i], i, false, done) - } - sync = false +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "zip", function() { return zip; }); +/* harmony import */ var _observable_zip__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(109); +/** PURE_IMPORTS_START _observable_zip PURE_IMPORTS_END */ - function done () { - --self._processing - if (self._processing <= 0) { - if (sync) { - process.nextTick(function () { - self._finish() - }) - } else { - self._finish() - } +function zip() { + var observables = []; + for (var _i = 0; _i < arguments.length; _i++) { + observables[_i] = arguments[_i]; } - } + return function zipOperatorFunction(source) { + return source.lift.call(_observable_zip__WEBPACK_IMPORTED_MODULE_0__["zip"].apply(void 0, [source].concat(observables))); + }; } +//# sourceMappingURL=zip.js.map -Glob.prototype._finish = function () { - assert(this instanceof Glob) - if (this.aborted) - return - - if (this.realpath && !this._didRealpath) - return this._realpath() - - common.finish(this) - this.emit('end', this.found) -} -Glob.prototype._realpath = function () { - if (this._didRealpath) - return +/***/ }), +/* 497 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - this._didRealpath = true +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "zipAll", function() { return zipAll; }); +/* harmony import */ var _observable_zip__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(109); +/** PURE_IMPORTS_START _observable_zip PURE_IMPORTS_END */ - var n = this.matches.length - if (n === 0) - return this._finish() +function zipAll(project) { + return function (source) { return source.lift(new _observable_zip__WEBPACK_IMPORTED_MODULE_0__["ZipOperator"](project)); }; +} +//# sourceMappingURL=zipAll.js.map - var self = this - for (var i = 0; i < this.matches.length; i++) - this._realpathSet(i, next) - function next () { - if (--n === 0) - self._finish() - } -} +/***/ }), +/* 498 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -Glob.prototype._realpathSet = function (index, cb) { - var matchset = this.matches[index] - if (!matchset) - return cb() +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "runCommand", function() { return runCommand; }); +/* harmony import */ var _utils_errors__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(162); +/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(143); +/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(145); +/* harmony import */ var _utils_projects_tree__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(499); +/* harmony import */ var _utils_kibana__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(500); +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; } - var found = Object.keys(matchset) - var self = this - var n = found.length +function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } - if (n === 0) - return cb() +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } - var set = this.matches[index] = Object.create(null) - found.forEach(function (p, i) { - // If there's a problem with the stat, then it means that - // one or more of the links in the realpath couldn't be - // resolved. just return the abs value in that case. - p = self._makeAbs(p) - rp.realpath(p, self.realpathCache, function (er, real) { - if (!er) - set[real] = true - else if (er.syscall === 'stat') - set[p] = true - else - self.emit('error', er) // srsly wtf right here +/* + * 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. + */ - if (--n === 0) { - self.matches[index] = set - cb() - } - }) - }) -} -Glob.prototype._mark = function (p) { - return common.mark(this, p) -} -Glob.prototype._makeAbs = function (f) { - return common.makeAbs(this, f) -} -Glob.prototype.abort = function () { - this.aborted = true - this.emit('abort') -} -Glob.prototype.pause = function () { - if (!this.paused) { - this.paused = true - this.emit('pause') - } -} +async function runCommand(command, config) { + try { + _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].debug(`Running [${command.name}] command from [${config.rootPath}]`); + const kbn = await _utils_kibana__WEBPACK_IMPORTED_MODULE_4__["Kibana"].loadFrom(config.rootPath); + const projects = kbn.getFilteredProjects({ + skipKibanaPlugins: Boolean(config.options['skip-kibana-plugins']), + ossOnly: Boolean(config.options.oss), + exclude: toArray(config.options.exclude), + include: toArray(config.options.include) + }); -Glob.prototype.resume = function () { - if (this.paused) { - this.emit('resume') - this.paused = false - if (this._emitQueue.length) { - var eq = this._emitQueue.slice(0) - this._emitQueue.length = 0 - for (var i = 0; i < eq.length; i ++) { - var e = eq[i] - this._emitMatch(e[0], e[1]) - } + if (projects.size === 0) { + _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].error(`There are no projects found. Double check project name(s) in '-i/--include' and '-e/--exclude' filters.`); + return process.exit(1); } - if (this._processQueue.length) { - var pq = this._processQueue.slice(0) - this._processQueue.length = 0 - for (var i = 0; i < pq.length; i ++) { - var p = pq[i] - this._processing-- - this._process(p[0], p[1], p[2], p[3]) + + const projectGraph = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_2__["buildProjectGraph"])(projects); + _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].debug(`Found ${projects.size.toString()} projects`); + _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].debug(Object(_utils_projects_tree__WEBPACK_IMPORTED_MODULE_3__["renderProjectsTree"])(config.rootPath, projects)); + await command.run(projects, projectGraph, _objectSpread(_objectSpread({}, config), {}, { + kbn + })); + } catch (error) { + _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].error(`[${command.name}] failed:`); + + if (error instanceof _utils_errors__WEBPACK_IMPORTED_MODULE_0__["CliError"]) { + _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].error(error.message); + const metaOutput = Object.entries(error.meta).map(([key, value]) => `${key}: ${value}`).join('\n'); + + if (metaOutput) { + _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].info('Additional debugging info:\n'); + _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].indent(2); + _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].info(metaOutput); + _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].indent(-2); } + } else { + _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].error(error); } + + process.exit(1); } } -Glob.prototype._process = function (pattern, index, inGlobStar, cb) { - assert(this instanceof Glob) - assert(typeof cb === 'function') +function toArray(value) { + if (value == null) { + return []; + } - if (this.aborted) - return + return Array.isArray(value) ? value : [value]; +} - this._processing++ - if (this.paused) { - this._processQueue.push([pattern, index, inGlobStar, cb]) - return - } +/***/ }), +/* 499 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - //console.error('PROCESS %d', this._processing, pattern) +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "renderProjectsTree", function() { return renderProjectsTree; }); +/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(235); +/* harmony import */ var chalk__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(chalk__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4); +/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__); +/* + * 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. + */ - // Get the first [n] parts of pattern that are all strings. - var n = 0 - while (typeof pattern[n] === 'string') { - n ++ - } - // now n is the index of the first one that is *not* a string. - // see if there's anything else - var prefix - switch (n) { - // if not, then this is rather simple - case pattern.length: - this._processSimple(pattern.join('/'), index, cb) - return +const projectKey = Symbol('__project'); +function renderProjectsTree(rootPath, projects) { + const projectsTree = buildProjectsTree(rootPath, projects); + return treeToString(createTreeStructure(projectsTree)); +} - case 0: - // pattern *starts* with some non-trivial item. - // going to readdir(cwd), but not include the prefix in matches. - prefix = null - break +function treeToString(tree) { + return [tree.name].concat(childrenToStrings(tree.children, '')).join('\n'); +} - default: - // pattern has some string bits in the front. - // whatever it starts with, whether that's 'absolute' like /foo/bar, - // or 'relative' like '../baz' - prefix = pattern.slice(0, n).join('/') - break +function childrenToStrings(tree, treePrefix) { + if (tree === undefined) { + return []; } - var remain = pattern.slice(n) - - // get the list of entries. - var read - if (prefix === null) - read = '.' - else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) { - if (!prefix || !isAbsolute(prefix)) - prefix = '/' + prefix - read = prefix - } else - read = prefix + let strings = []; + tree.forEach((node, index) => { + const isLastNode = tree.length - 1 === index; + const nodePrefix = isLastNode ? '└── ' : '├── '; + const childPrefix = isLastNode ? ' ' : '│ '; + const childrenPrefix = treePrefix + childPrefix; + strings.push(`${treePrefix}${nodePrefix}${node.name}`); + strings = strings.concat(childrenToStrings(node.children, childrenPrefix)); + }); + return strings; +} - var abs = this._makeAbs(read) +function createTreeStructure(tree) { + let name; + const children = []; - //if ignored, skip _processing - if (childrenIgnored(this, read)) - return cb() + for (const [dir, project] of tree.entries()) { + // This is a leaf node (aka a project) + if (typeof project === 'string') { + name = chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(project); + continue; + } // If there's only one project and the key indicates it's a leaf node, we + // know that we're at a package folder that contains a package.json, so we + // "inline it" so we don't get unnecessary levels, i.e. we'll just see + // `foo` instead of `foo -> foo`. - var isGlobStar = remain[0] === minimatch.GLOBSTAR - if (isGlobStar) - this._processGlobStar(prefix, read, abs, remain, index, inGlobStar, cb) - else - this._processReaddir(prefix, read, abs, remain, index, inGlobStar, cb) -} -Glob.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar, cb) { - var self = this - this._readdir(abs, inGlobStar, function (er, entries) { - return self._processReaddir2(prefix, read, abs, remain, index, inGlobStar, entries, cb) - }) -} + if (project.size === 1 && project.has(projectKey)) { + const projectName = project.get(projectKey); + children.push({ + children: [], + name: dirOrProjectName(dir, projectName) + }); + continue; + } -Glob.prototype._processReaddir2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { + const subtree = createTreeStructure(project); // If the name is specified, we know there's a package at the "root" of the + // subtree itself. - // if the abs isn't a dir, then nothing can match! - if (!entries) - return cb() + if (subtree.name !== undefined) { + const projectName = subtree.name; + children.push({ + children: subtree.children, + name: dirOrProjectName(dir, projectName) + }); + continue; + } // Special-case whenever we have one child, so we don't get unnecessary + // folders in the output. E.g. instead of `foo -> bar -> baz` we get + // `foo/bar/baz` instead. - // It will only match dot entries if it starts with a dot, or if - // dot is set. Stuff like @(.foo|.bar) isn't allowed. - var pn = remain[0] - var negate = !!this.minimatch.negate - var rawGlob = pn._glob - var dotOk = this.dot || rawGlob.charAt(0) === '.' - var matchedEntries = [] - for (var i = 0; i < entries.length; i++) { - var e = entries[i] - if (e.charAt(0) !== '.' || dotOk) { - var m - if (negate && !prefix) { - m = !e.match(pn) - } else { - m = e.match(pn) - } - if (m) - matchedEntries.push(e) + if (subtree.children && subtree.children.length === 1) { + const child = subtree.children[0]; + const newName = chalk__WEBPACK_IMPORTED_MODULE_0___default.a.dim(path__WEBPACK_IMPORTED_MODULE_1___default.a.join(dir.toString(), child.name)); + children.push({ + children: child.children, + name: newName + }); + continue; } - } - - //console.error('prd2', prefix, entries, remain[0]._glob, matchedEntries) - var len = matchedEntries.length - // If there are no matched entries, then nothing matches. - if (len === 0) - return cb() + children.push({ + children: subtree.children, + name: chalk__WEBPACK_IMPORTED_MODULE_0___default.a.dim(dir.toString()) + }); + } - // if this is the last remaining pattern bit, then no need for - // an additional stat *unless* the user has specified mark or - // stat explicitly. We know they exist, since readdir returned - // them. + return { + name, + children + }; +} - if (remain.length === 1 && !this.mark && !this.stat) { - if (!this.matches[index]) - this.matches[index] = Object.create(null) +function dirOrProjectName(dir, projectName) { + return dir === projectName ? chalk__WEBPACK_IMPORTED_MODULE_0___default.a.green(dir) : chalk__WEBPACK_IMPORTED_MODULE_0___default.a`{dim ${dir.toString()} ({reset.green ${projectName}})}`; +} - for (var i = 0; i < len; i ++) { - var e = matchedEntries[i] - if (prefix) { - if (prefix !== '/') - e = prefix + '/' + e - else - e = prefix + e - } +function buildProjectsTree(rootPath, projects) { + const tree = new Map(); - if (e.charAt(0) === '/' && !this.nomount) { - e = path.join(this.root, e) - } - this._emitMatch(index, e) + for (const project of projects.values()) { + if (rootPath === project.path) { + tree.set(projectKey, project.name); + } else { + const relativeProjectPath = path__WEBPACK_IMPORTED_MODULE_1___default.a.relative(rootPath, project.path); + addProjectToTree(tree, relativeProjectPath.split(path__WEBPACK_IMPORTED_MODULE_1___default.a.sep), project); } - // This was the last one, and no stats were needed - return cb() } - // now test all matched entries as stand-ins for that part - // of the pattern. - remain.shift() - for (var i = 0; i < len; i ++) { - var e = matchedEntries[i] - var newPattern - if (prefix) { - if (prefix !== '/') - e = prefix + '/' + e - else - e = prefix + e - } - this._process([e].concat(remain), index, inGlobStar, cb) - } - cb() + return tree; } -Glob.prototype._emitMatch = function (index, e) { - if (this.aborted) - return +function addProjectToTree(tree, pathParts, project) { + if (pathParts.length === 0) { + tree.set(projectKey, project.name); + } else { + const [currentDir, ...rest] = pathParts; - if (isIgnored(this, e)) - return + if (!tree.has(currentDir)) { + tree.set(currentDir, new Map()); + } - if (this.paused) { - this._emitQueue.push([index, e]) - return + const subtree = tree.get(currentDir); + addProjectToTree(subtree, rest, project); } +} - var abs = isAbsolute(e) ? e : this._makeAbs(e) +/***/ }), +/* 500 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - if (this.mark) - e = this._mark(e) +"use strict"; +__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__(4); +/* 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__(501); +/* harmony import */ var multimatch__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(multimatch__WEBPACK_IMPORTED_MODULE_1__); +/* harmony import */ var is_path_inside__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(377); +/* harmony import */ var is_path_inside__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(is_path_inside__WEBPACK_IMPORTED_MODULE_2__); +/* harmony import */ var _projects__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(145); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(288); +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; } - if (this.absolute) - e = abs +function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } - if (this.matches[index][e]) - return +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } - if (this.nodir) { - var c = this.cache[abs] - if (c === 'DIR' || Array.isArray(c)) - return - } +/* + * 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. + */ - this.matches[index][e] = true - var st = this.statCache[abs] - if (st) - this.emit('stat', e, st) - this.emit('match', e) -} -Glob.prototype._readdirInGlobStar = function (abs, cb) { - if (this.aborted) - return - // follow all symlinked directories forever - // just proceed as if this is a non-globstar situation - if (this.follow) - return this._readdir(abs, false, cb) +/** + * Helper class for dealing with a set of projects as children of + * the Kibana project. The kbn/pm is currently implemented to be + * more generic, where everything is an operation of generic projects, + * but that leads to exceptions where we need the kibana project and + * do things like `project.get('kibana')!`. + * + * Using this helper we can restructre the generic list of projects + * as a Kibana object which encapulates all the projects in the + * workspace and knows about the root Kibana project. + */ - var lstatkey = 'lstat\0' + abs - var self = this - var lstatcb = inflight(lstatkey, lstatcb_) +class Kibana { + static async loadFrom(rootPath) { + return new Kibana(await Object(_projects__WEBPACK_IMPORTED_MODULE_3__["getProjects"])(rootPath, Object(_config__WEBPACK_IMPORTED_MODULE_4__["getProjectPaths"])({ + rootPath + }))); + } - if (lstatcb) - fs.lstat(abs, lstatcb) + constructor(allWorkspaceProjects) { + this.allWorkspaceProjects = allWorkspaceProjects; - function lstatcb_ (er, lstat) { - if (er && er.code === 'ENOENT') - return cb() + _defineProperty(this, "kibanaProject", void 0); - var isSym = lstat && lstat.isSymbolicLink() - self.symlinks[abs] = isSym + const kibanaProject = allWorkspaceProjects.get('kibana'); - // If it's not a symlink or a dir, then it's definitely a regular file. - // don't bother doing a readdir in that case. - if (!isSym && lstat && !lstat.isDirectory()) { - self.cache[abs] = 'FILE' - cb() - } else - self._readdir(abs, false, cb) + if (!kibanaProject) { + throw new TypeError('Unable to create Kibana object without all projects, including the Kibana project.'); + } + + this.kibanaProject = kibanaProject; } -} + /** make an absolute path by resolving subPath relative to the kibana repo */ -Glob.prototype._readdir = function (abs, inGlobStar, cb) { - if (this.aborted) - return - cb = inflight('readdir\0'+abs+'\0'+inGlobStar, cb) - if (!cb) - return + getAbsolute(...subPath) { + return path__WEBPACK_IMPORTED_MODULE_0___default.a.resolve(this.kibanaProject.path, ...subPath); + } + /** convert an absolute path to a relative path, relative to the kibana repo */ - //console.error('RD %j %j', +inGlobStar, abs) - if (inGlobStar && !ownProp(this.symlinks, abs)) - return this._readdirInGlobStar(abs, cb) - if (ownProp(this.cache, abs)) { - var c = this.cache[abs] - if (!c || c === 'FILE') - return cb() + getRelative(absolute) { + return path__WEBPACK_IMPORTED_MODULE_0___default.a.relative(this.kibanaProject.path, absolute); + } + /** get a copy of the map of all projects in the kibana workspace */ - if (Array.isArray(c)) - return cb(null, c) + + getAllProjects() { + return new Map(this.allWorkspaceProjects); } + /** determine if a project with the given name exists */ - var self = this - fs.readdir(abs, readdirCb(this, abs, cb)) -} -function readdirCb (self, abs, cb) { - return function (er, entries) { - if (er) - self._readdirError(abs, er, cb) - else - self._readdirEntries(abs, entries, cb) + hasProject(name) { + return this.allWorkspaceProjects.has(name); } -} + /** get a specific project, throws if the name is not known (use hasProject() first) */ -Glob.prototype._readdirEntries = function (abs, entries, cb) { - if (this.aborted) - return - // if we haven't asked to stat everything, then just - // assume that everything in there exists, so we can avoid - // having to stat it a second time. - if (!this.mark && !this.stat) { - for (var i = 0; i < entries.length; i ++) { - var e = entries[i] - if (abs === '/') - e = abs + e - else - e = abs + '/' + e - this.cache[e] = true + getProject(name) { + const project = this.allWorkspaceProjects.get(name); + + if (!project) { + throw new Error(`No package with name "${name}" in the workspace`); } + + return project; } + /** get a project and all of the projects it depends on in a ProjectMap */ - this.cache[abs] = entries - return cb(null, entries) -} -Glob.prototype._readdirError = function (f, er, cb) { - if (this.aborted) - return + getProjectAndDeps(name) { + const project = this.getProject(name); + return Object(_projects__WEBPACK_IMPORTED_MODULE_3__["includeTransitiveProjects"])([project], this.allWorkspaceProjects); + } + /** filter the projects to just those matching certain paths/include/exclude tags */ - // handle errors, and cache the information - switch (er.code) { - case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205 - case 'ENOTDIR': // totally normal. means it *does* exist. - var abs = this._makeAbs(f) - this.cache[abs] = 'FILE' - if (abs === this.cwdAbs) { - var error = new Error(er.code + ' invalid cwd ' + this.cwd) - error.path = this.cwd - error.code = er.code - this.emit('error', error) - this.abort() - } - break - case 'ENOENT': // not terribly unusual - case 'ELOOP': - case 'ENAMETOOLONG': - case 'UNKNOWN': - this.cache[this._makeAbs(f)] = false - break + getFilteredProjects(options) { + const allProjects = this.getAllProjects(); + const filteredProjects = new Map(); + const pkgJsonPaths = Array.from(allProjects.values()).map(p => p.packageJsonLocation); + const filteredPkgJsonGlobs = Object(_config__WEBPACK_IMPORTED_MODULE_4__["getProjectPaths"])(_objectSpread(_objectSpread({}, options), {}, { + rootPath: this.kibanaProject.path + })).map(g => path__WEBPACK_IMPORTED_MODULE_0___default.a.resolve(g, 'package.json')); + const matchingPkgJsonPaths = multimatch__WEBPACK_IMPORTED_MODULE_1___default()(pkgJsonPaths, filteredPkgJsonGlobs); - default: // some unusual error. Treat as failure. - this.cache[this._makeAbs(f)] = false - if (this.strict) { - this.emit('error', er) - // If the error is handled, then we abort - // if not, we threw out of here - this.abort() + for (const project of allProjects.values()) { + const pathMatches = matchingPkgJsonPaths.includes(project.packageJsonLocation); + const notExcluded = !options.exclude.includes(project.name); + const isIncluded = !options.include.length || options.include.includes(project.name); + + if (pathMatches && notExcluded && isIncluded) { + filteredProjects.set(project.name, project); } - if (!this.silent) - console.error('glob error', er) - break + } + + return filteredProjects; } - return cb() -} + isPartOfRepo(project) { + return project.path === this.kibanaProject.path || is_path_inside__WEBPACK_IMPORTED_MODULE_2___default()(project.path, this.kibanaProject.path); + } -Glob.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar, cb) { - var self = this - this._readdir(abs, inGlobStar, function (er, entries) { - self._processGlobStar2(prefix, read, abs, remain, index, inGlobStar, entries, cb) - }) -} + isOutsideRepo(project) { + return !this.isPartOfRepo(project); + } +} -Glob.prototype._processGlobStar2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { - //console.error('pgs2', prefix, remain[0], entries) +/***/ }), +/* 501 */ +/***/ (function(module, exports, __webpack_require__) { - // no entries means not a dir, so it can never have matches - // foo.txt/** doesn't match foo.txt - if (!entries) - return cb() +"use strict"; - // test without the globstar, and with every child both below - // and replacing the globstar. - var remainWithoutGlobStar = remain.slice(1) - var gspref = prefix ? [ prefix ] : [] - var noGlobStar = gspref.concat(remainWithoutGlobStar) +const minimatch = __webpack_require__(149); +const arrayUnion = __webpack_require__(502); +const arrayDiffer = __webpack_require__(503); +const arrify = __webpack_require__(504); - // the noGlobStar pattern exits the inGlobStar state - this._process(noGlobStar, index, false, cb) +module.exports = (list, patterns, options = {}) => { + list = arrify(list); + patterns = arrify(patterns); - var isSym = this.symlinks[abs] - var len = entries.length + if (list.length === 0 || patterns.length === 0) { + return []; + } - // If it's a symlink, and we're in a globstar, then stop - if (isSym && inGlobStar) - return cb() + return patterns.reduce((result, pattern) => { + let process = arrayUnion; - for (var i = 0; i < len; i++) { - var e = entries[i] - if (e.charAt(0) === '.' && !this.dot) - continue + if (pattern[0] === '!') { + pattern = pattern.slice(1); + process = arrayDiffer; + } - // these two cases enter the inGlobStar state - var instead = gspref.concat(entries[i], remainWithoutGlobStar) - this._process(instead, index, true, cb) + return process(result, minimatch.match(list, pattern, options)); + }, []); +}; - var below = gspref.concat(entries[i], remain) - this._process(below, index, true, cb) - } - cb() -} +/***/ }), +/* 502 */ +/***/ (function(module, exports, __webpack_require__) { -Glob.prototype._processSimple = function (prefix, index, cb) { - // XXX review this. Shouldn't it be doing the mounting etc - // before doing stat? kinda weird? - var self = this - this._stat(prefix, function (er, exists) { - self._processSimple2(prefix, index, er, exists, cb) - }) -} -Glob.prototype._processSimple2 = function (prefix, index, er, exists, cb) { +"use strict"; - //console.error('ps2', prefix, exists) - if (!this.matches[index]) - this.matches[index] = Object.create(null) +module.exports = (...arguments_) => { + return [...new Set([].concat(...arguments_))]; +}; - // If it doesn't exist, then just mark the lack of results - if (!exists) - return cb() - if (prefix && isAbsolute(prefix) && !this.nomount) { - var trail = /[\/\\]$/.test(prefix) - if (prefix.charAt(0) === '/') { - prefix = path.join(this.root, prefix) - } else { - prefix = path.resolve(this.root, prefix) - if (trail) - prefix += '/' - } - } +/***/ }), +/* 503 */ +/***/ (function(module, exports, __webpack_require__) { - if (process.platform === 'win32') - prefix = prefix.replace(/\\/g, '/') +"use strict"; - // Mark this as a match - this._emitMatch(index, prefix) - cb() -} -// Returns either 'DIR', 'FILE', or false -Glob.prototype._stat = function (f, cb) { - var abs = this._makeAbs(f) - var needDir = f.slice(-1) === '/' +const arrayDiffer = (array, ...values) => { + const rest = new Set([].concat(...values)); + return array.filter(element => !rest.has(element)); +}; - if (f.length > this.maxLength) - return cb() +module.exports = arrayDiffer; - if (!this.stat && ownProp(this.cache, abs)) { - var c = this.cache[abs] - if (Array.isArray(c)) - c = 'DIR' +/***/ }), +/* 504 */ +/***/ (function(module, exports, __webpack_require__) { - // It exists, but maybe not how we need it - if (!needDir || c === 'DIR') - return cb(null, c) +"use strict"; - if (needDir && c === 'FILE') - return cb() - // otherwise we have to stat, because maybe c=true - // if we know it exists, but not what it is. - } +const arrify = value => { + if (value === null || value === undefined) { + return []; + } - var exists - var stat = this.statCache[abs] - if (stat !== undefined) { - if (stat === false) - return cb(null, stat) - else { - var type = stat.isDirectory() ? 'DIR' : 'FILE' - if (needDir && type === 'FILE') - return cb() - else - return cb(null, type, stat) - } - } + if (Array.isArray(value)) { + return value; + } - var self = this - var statcb = inflight('stat\0' + abs, lstatcb_) - if (statcb) - fs.lstat(abs, statcb) + if (typeof value === 'string') { + return [value]; + } - function lstatcb_ (er, lstat) { - if (lstat && lstat.isSymbolicLink()) { - // If it's a symlink, then treat it as the target, unless - // the target does not exist, then treat it as a file. - return fs.stat(abs, function (er, stat) { - if (er) - self._stat2(f, abs, null, lstat, cb) - else - self._stat2(f, abs, er, stat, cb) - }) - } else { - self._stat2(f, abs, er, lstat, cb) - } - } -} + if (typeof value[Symbol.iterator] === 'function') { + return [...value]; + } -Glob.prototype._stat2 = function (f, abs, er, stat, cb) { - if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) { - this.statCache[abs] = false - return cb() - } + return [value]; +}; - var needDir = f.slice(-1) === '/' - this.statCache[abs] = stat +module.exports = arrify; - if (abs.slice(-1) === '/' && stat && !stat.isDirectory()) - return cb(null, false, stat) - var c = true - if (stat) - c = stat.isDirectory() ? 'DIR' : 'FILE' - this.cache[abs] = this.cache[abs] || c +/***/ }), +/* 505 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - if (needDir && c === 'FILE') - return cb() +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _build_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(506); +/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _build_production_projects__WEBPACK_IMPORTED_MODULE_0__["buildProductionProjects"]; }); - return cb(null, c, stat) -} +/* + * 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. + */ /***/ }), -/* 521 */ -/***/ (function(module, exports, __webpack_require__) { +/* 506 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -try { - var util = __webpack_require__(111); - /* istanbul ignore next */ - if (typeof util.inherits !== 'function') throw ''; - module.exports = util.inherits; -} catch (e) { - /* istanbul ignore next */ - module.exports = __webpack_require__(522); -} +"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__(507); +/* 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__(296); +/* 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__(4); +/* 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__(288); +/* harmony import */ var _utils_fs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(130); +/* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(143); +/* harmony import */ var _utils_package_json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(164); +/* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(145); +/* + * 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. + */ -/***/ }), -/* 522 */ -/***/ (function(module, exports) { -if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - if (superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }) - } - }; -} else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - if (superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor - } - } -} -/***/ }), -/* 523 */ -/***/ (function(module, exports, __webpack_require__) { -module.exports = globSync -globSync.GlobSync = GlobSync -var fs = __webpack_require__(133) -var rp = __webpack_require__(147) -var minimatch = __webpack_require__(149) -var Minimatch = minimatch.Minimatch -var Glob = __webpack_require__(520).Glob -var util = __webpack_require__(111) -var path = __webpack_require__(4) -var assert = __webpack_require__(139) -var isAbsolute = __webpack_require__(156) -var common = __webpack_require__(524) -var alphasort = common.alphasort -var alphasorti = common.alphasorti -var setopts = common.setopts -var ownProp = common.ownProp -var childrenIgnored = common.childrenIgnored -var isIgnored = common.isIgnored -function globSync (pattern, options) { - if (typeof options === 'function' || arguments.length === 3) - throw new TypeError('callback provided to sync glob\n'+ - 'See: https://github.com/isaacs/node-glob/issues/167') +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"].info(`Preparing production build for [${projectNames.join(', ')}]`); - return new GlobSync(pattern, options).found + 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. + */ -function GlobSync (pattern, options) { - if (!pattern) - throw new Error('must provide pattern') +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 (typeof options === 'function' || arguments.length === 3) - throw new TypeError('callback provided to sync glob\n'+ - 'See: https://github.com/isaacs/node-glob/issues/167') + if (projects.has('x-pack')) { + projectsSubset.push(projects.get('x-pack')); + } - if (!(this instanceof GlobSync)) - return new GlobSync(pattern, options) + const productionProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["includeTransitiveProjects"])(projectsSubset, projects, { + onlyProductionDependencies: true + }); // We remove Kibana, as we're already building Kibana - setopts(this, pattern, options) + productionProjects.delete('kibana'); - if (this.noprocess) - return this + if (onlyOSS) { + productionProjects.forEach(project => { + if (project.getBuildConfig().oss === false) { + productionProjects.delete(project.json.name); + } + }); + } - var n = this.minimatch.set.length - this.matches = new Array(n) - for (var i = 0; i < n; i ++) { - this._process(this.minimatch.set[i], i, false) + 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 + }); } - this._finish() } -GlobSync.prototype._finish = function () { - assert(this instanceof GlobSync) - if (this.realpath) { - var self = this - this.matches.forEach(function (matchset, index) { - var set = self.matches[index] = Object.create(null) - for (var p in matchset) { - try { - p = self._makeAbs(p) - var real = rp.realpathSync(p, self.realpathCache) - set[real] = true - } catch (er) { - if (er.syscall === 'stat') - set[self._makeAbs(p)] = true - else - throw er - } - } - }) +async function buildProject(project) { + if (project.hasScript('build')) { + await project.runScript('build'); } - common.finish(this) } +/** + * 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. + */ -GlobSync.prototype._process = function (pattern, index, inGlobStar) { - assert(this instanceof GlobSync) +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`. - // Get the first [n] parts of pattern that are all strings. - var n = 0 - while (typeof pattern[n] === 'string') { - n ++ - } - // now n is the index of the first one that is *not* a string. + 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); +} - // See if there's anything else - var prefix - switch (n) { - // if not, then this is rather simple - case pattern.length: - this._processSimple(pattern.join('/'), index) - return +/***/ }), +/* 507 */ +/***/ (function(module, exports, __webpack_require__) { - case 0: - // pattern *starts* with some non-trivial item. - // going to readdir(cwd), but not include the prefix in matches. - prefix = null - break +"use strict"; - default: - // pattern has some string bits in the front. - // whatever it starts with, whether that's 'absolute' like /foo/bar, - // or 'relative' like '../baz' - prefix = pattern.slice(0, n).join('/') - break - } +const EventEmitter = __webpack_require__(155); +const path = __webpack_require__(4); +const os = __webpack_require__(120); +const pAll = __webpack_require__(508); +const arrify = __webpack_require__(510); +const globby = __webpack_require__(511); +const isGlob = __webpack_require__(721); +const cpFile = __webpack_require__(722); +const junk = __webpack_require__(734); +const CpyError = __webpack_require__(735); - var remain = pattern.slice(n) +const defaultOptions = { + ignoreJunk: true +}; - // get the list of entries. - var read - if (prefix === null) - read = '.' - else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) { - if (!prefix || !isAbsolute(prefix)) - prefix = '/' + prefix - read = prefix - } else - read = prefix +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); + } - var abs = this._makeAbs(read) + if (options.parents) { + return path.join(destination, dirname, basename); + } - //if ignored, skip processing - if (childrenIgnored(this, read)) - return + return path.join(destination, basename); +}; - var isGlobStar = remain[0] === minimatch.GLOBSTAR - if (isGlobStar) - this._processGlobStar(prefix, read, abs, remain, index, inGlobStar) - else - this._processReaddir(prefix, read, abs, remain, index, inGlobStar) -} +module.exports = (source, destination, { + concurrency = (os.cpus().length || 1) * 2, + ...options +} = {}) => { + const progressEmitter = new EventEmitter(); + options = { + ...defaultOptions, + ...options + }; -GlobSync.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar) { - var entries = this._readdir(abs, inGlobStar) + const promise = (async () => { + source = arrify(source); - // if the abs isn't a dir, then nothing can match! - if (!entries) - return + if (source.length === 0 || !destination) { + throw new CpyError('`source` and `destination` required'); + } - // It will only match dot entries if it starts with a dot, or if - // dot is set. Stuff like @(.foo|.bar) isn't allowed. - var pn = remain[0] - var negate = !!this.minimatch.negate - var rawGlob = pn._glob - var dotOk = this.dot || rawGlob.charAt(0) === '.' + const copyStatus = new Map(); + let completedFiles = 0; + let completedSize = 0; - var matchedEntries = [] - for (var i = 0; i < entries.length; i++) { - var e = entries[i] - if (e.charAt(0) !== '.' || dotOk) { - var m - if (negate && !prefix) { - m = !e.match(pn) - } else { - m = e.match(pn) - } - if (m) - matchedEntries.push(e) - } - } + let files; + try { + files = await globby(source, options); - var len = matchedEntries.length - // If there are no matched entries, then nothing matches. - if (len === 0) - return + if (options.ignoreJunk) { + files = files.filter(file => junk.not(path.basename(file))); + } + } catch (error) { + throw new CpyError(`Cannot glob \`${source}\`: ${error.message}`, error); + } - // if this is the last remaining pattern bit, then no need for - // an additional stat *unless* the user has specified mark or - // stat explicitly. We know they exist, since readdir returned - // them. + const sourcePaths = source.filter(value => !isGlob(value)); - if (remain.length === 1 && !this.mark && !this.stat) { - if (!this.matches[index]) - this.matches[index] = Object.create(null) + if (files.length === 0 || (sourcePaths.length > 0 && !sourcePaths.every(value => files.includes(value)))) { + throw new CpyError(`Cannot copy \`${source}\`: the file doesn't exist`); + } - for (var i = 0; i < len; i ++) { - var e = matchedEntries[i] - if (prefix) { - if (prefix.slice(-1) !== '/') - e = prefix + '/' + e - else - e = prefix + e - } + const fileProgressHandler = event => { + const fileStatus = copyStatus.get(event.src) || {written: 0, percent: 0}; - if (e.charAt(0) === '/' && !this.nomount) { - e = path.join(this.root, e) - } - this._emitMatch(index, e) - } - // This was the last one, and no stats were needed - return - } + if (fileStatus.written !== event.written || fileStatus.percent !== event.percent) { + completedSize -= fileStatus.written; + completedSize += event.written; - // now test all matched entries as stand-ins for that part - // of the pattern. - remain.shift() - for (var i = 0; i < len; i ++) { - var e = matchedEntries[i] - var newPattern - if (prefix) - newPattern = [prefix, e] - else - newPattern = [e] - this._process(newPattern.concat(remain), index, inGlobStar) - } -} + if (event.percent === 1 && fileStatus.percent !== 1) { + completedFiles++; + } + copyStatus.set(event.src, { + written: event.written, + percent: event.percent + }); -GlobSync.prototype._emitMatch = function (index, e) { - if (isIgnored(this, e)) - return + progressEmitter.emit('progress', { + totalFiles: files.length, + percent: completedFiles / files.length, + completedFiles, + completedSize + }); + } + }; - var abs = this._makeAbs(e) + return pAll(files.map(sourcePath => { + return async () => { + const from = preprocessSourcePath(sourcePath, options); + const to = preprocessDestinationPath(sourcePath, destination, options); - if (this.mark) - e = this._mark(e) + try { + await cpFile(from, to, options).on('progress', fileProgressHandler); + } catch (error) { + throw new CpyError(`Cannot copy from \`${from}\` to \`${to}\`: ${error.message}`, error); + } - if (this.absolute) { - e = abs - } + return to; + }; + }), {concurrency}); + })(); - if (this.matches[index][e]) - return + promise.on = (...arguments_) => { + progressEmitter.on(...arguments_); + return promise; + }; - if (this.nodir) { - var c = this.cache[abs] - if (c === 'DIR' || Array.isArray(c)) - return - } + return promise; +}; - this.matches[index][e] = true - if (this.stat) - this._stat(e) -} +/***/ }), +/* 508 */ +/***/ (function(module, exports, __webpack_require__) { +"use strict"; -GlobSync.prototype._readdirInGlobStar = function (abs) { - // follow all symlinked directories forever - // just proceed as if this is a non-globstar situation - if (this.follow) - return this._readdir(abs, false) +const pMap = __webpack_require__(509); - var entries - var lstat - var stat - try { - lstat = fs.lstatSync(abs) - } catch (er) { - if (er.code === 'ENOENT') { - // lstat failed, doesn't exist - return null - } - } +module.exports = (iterable, options) => pMap(iterable, element => element(), options); +// TODO: Remove this for the next major release +module.exports.default = module.exports; - var isSym = lstat && lstat.isSymbolicLink() - this.symlinks[abs] = isSym - // If it's not a symlink or a dir, then it's definitely a regular file. - // don't bother doing a readdir in that case. - if (!isSym && lstat && !lstat.isDirectory()) - this.cache[abs] = 'FILE' - else - entries = this._readdir(abs, false) +/***/ }), +/* 509 */ +/***/ (function(module, exports, __webpack_require__) { - return entries -} +"use strict"; -GlobSync.prototype._readdir = function (abs, inGlobStar) { - var entries - if (inGlobStar && !ownProp(this.symlinks, abs)) - return this._readdirInGlobStar(abs) +const pMap = (iterable, mapper, options) => new Promise((resolve, reject) => { + options = Object.assign({ + concurrency: Infinity + }, options); - if (ownProp(this.cache, abs)) { - var c = this.cache[abs] - if (!c || c === 'FILE') - return null + if (typeof mapper !== 'function') { + throw new TypeError('Mapper function is required'); + } - if (Array.isArray(c)) - return c - } + const {concurrency} = options; - try { - return this._readdirEntries(abs, fs.readdirSync(abs)) - } catch (er) { - this._readdirError(abs, er) - return null - } -} + if (!(typeof concurrency === 'number' && concurrency >= 1)) { + throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${concurrency}\` (${typeof concurrency})`); + } -GlobSync.prototype._readdirEntries = function (abs, entries) { - // if we haven't asked to stat everything, then just - // assume that everything in there exists, so we can avoid - // having to stat it a second time. - if (!this.mark && !this.stat) { - for (var i = 0; i < entries.length; i ++) { - var e = entries[i] - if (abs === '/') - e = abs + e - else - e = abs + '/' + e - this.cache[e] = true - } - } + const ret = []; + const iterator = iterable[Symbol.iterator](); + let isRejected = false; + let isIterableDone = false; + let resolvingCount = 0; + let currentIndex = 0; - this.cache[abs] = entries + const next = () => { + if (isRejected) { + return; + } - // mark and cache dir-ness - return entries -} + const nextItem = iterator.next(); + const i = currentIndex; + currentIndex++; -GlobSync.prototype._readdirError = function (f, er) { - // handle errors, and cache the information - switch (er.code) { - case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205 - case 'ENOTDIR': // totally normal. means it *does* exist. - var abs = this._makeAbs(f) - this.cache[abs] = 'FILE' - if (abs === this.cwdAbs) { - var error = new Error(er.code + ' invalid cwd ' + this.cwd) - error.path = this.cwd - error.code = er.code - throw error - } - break + if (nextItem.done) { + isIterableDone = true; - case 'ENOENT': // not terribly unusual - case 'ELOOP': - case 'ENAMETOOLONG': - case 'UNKNOWN': - this.cache[this._makeAbs(f)] = false - break + if (resolvingCount === 0) { + resolve(ret); + } - default: // some unusual error. Treat as failure. - this.cache[this._makeAbs(f)] = false - if (this.strict) - throw er - if (!this.silent) - console.error('glob error', er) - break - } -} + return; + } -GlobSync.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar) { + resolvingCount++; - var entries = this._readdir(abs, inGlobStar) + Promise.resolve(nextItem.value) + .then(element => mapper(element, i)) + .then( + value => { + ret[i] = value; + resolvingCount--; + next(); + }, + error => { + isRejected = true; + reject(error); + } + ); + }; - // no entries means not a dir, so it can never have matches - // foo.txt/** doesn't match foo.txt - if (!entries) - return + for (let i = 0; i < concurrency; i++) { + next(); - // test without the globstar, and with every child both below - // and replacing the globstar. - var remainWithoutGlobStar = remain.slice(1) - var gspref = prefix ? [ prefix ] : [] - var noGlobStar = gspref.concat(remainWithoutGlobStar) + if (isIterableDone) { + break; + } + } +}); - // the noGlobStar pattern exits the inGlobStar state - this._process(noGlobStar, index, false) +module.exports = pMap; +// TODO: Remove this for the next major release +module.exports.default = pMap; - var len = entries.length - var isSym = this.symlinks[abs] - // If it's a symlink, and we're in a globstar, then stop - if (isSym && inGlobStar) - return +/***/ }), +/* 510 */ +/***/ (function(module, exports, __webpack_require__) { - for (var i = 0; i < len; i++) { - var e = entries[i] - if (e.charAt(0) === '.' && !this.dot) - continue +"use strict"; - // these two cases enter the inGlobStar state - var instead = gspref.concat(entries[i], remainWithoutGlobStar) - this._process(instead, index, true) - var below = gspref.concat(entries[i], remain) - this._process(below, index, true) - } -} +const arrify = value => { + if (value === null || value === undefined) { + return []; + } -GlobSync.prototype._processSimple = function (prefix, index) { - // XXX review this. Shouldn't it be doing the mounting etc - // before doing stat? kinda weird? - var exists = this._stat(prefix) + if (Array.isArray(value)) { + return value; + } - if (!this.matches[index]) - this.matches[index] = Object.create(null) + if (typeof value === 'string') { + return [value]; + } - // If it doesn't exist, then just mark the lack of results - if (!exists) - return + if (typeof value[Symbol.iterator] === 'function') { + return [...value]; + } - if (prefix && isAbsolute(prefix) && !this.nomount) { - var trail = /[\/\\]$/.test(prefix) - if (prefix.charAt(0) === '/') { - prefix = path.join(this.root, prefix) - } else { - prefix = path.resolve(this.root, prefix) - if (trail) - prefix += '/' - } - } + return [value]; +}; - if (process.platform === 'win32') - prefix = prefix.replace(/\\/g, '/') +module.exports = arrify; - // Mark this as a match - this._emitMatch(index, prefix) -} -// Returns either 'DIR', 'FILE', or false -GlobSync.prototype._stat = function (f) { - var abs = this._makeAbs(f) - var needDir = f.slice(-1) === '/' +/***/ }), +/* 511 */ +/***/ (function(module, exports, __webpack_require__) { - if (f.length > this.maxLength) - return false +"use strict"; - if (!this.stat && ownProp(this.cache, abs)) { - var c = this.cache[abs] +const fs = __webpack_require__(133); +const arrayUnion = __webpack_require__(512); +const glob = __webpack_require__(146); +const fastGlob = __webpack_require__(514); +const dirGlob = __webpack_require__(714); +const gitignore = __webpack_require__(717); - if (Array.isArray(c)) - c = 'DIR' +const DEFAULT_FILTER = () => false; - // It exists, but maybe not how we need it - if (!needDir || c === 'DIR') - return c +const isNegative = pattern => pattern[0] === '!'; - if (needDir && c === 'FILE') - return false +const assertPatternsInput = patterns => { + if (!patterns.every(x => typeof x === 'string')) { + throw new TypeError('Patterns must be a string or an array of strings'); + } +}; - // otherwise we have to stat, because maybe c=true - // if we know it exists, but not what it is. - } +const checkCwdOption = options => { + if (options && options.cwd && !fs.statSync(options.cwd).isDirectory()) { + throw new Error('The `cwd` option must be a path to a directory'); + } +}; - 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 - } - } +const generateGlobTasks = (patterns, taskOptions) => { + patterns = arrayUnion([].concat(patterns)); + assertPatternsInput(patterns); + checkCwdOption(taskOptions); - if (lstat && lstat.isSymbolicLink()) { - try { - stat = fs.statSync(abs) - } catch (er) { - stat = lstat - } - } else { - stat = lstat - } - } + const globTasks = []; - this.statCache[abs] = stat + taskOptions = Object.assign({ + ignore: [], + expandDirectories: true + }, taskOptions); - var c = true - if (stat) - c = stat.isDirectory() ? 'DIR' : 'FILE' + patterns.forEach((pattern, i) => { + if (isNegative(pattern)) { + return; + } - this.cache[abs] = this.cache[abs] || c + const ignore = patterns + .slice(i) + .filter(isNegative) + .map(pattern => pattern.slice(1)); - if (needDir && c === 'FILE') - return false + const options = Object.assign({}, taskOptions, { + ignore: taskOptions.ignore.concat(ignore) + }); - return c -} + globTasks.push({pattern, options}); + }); -GlobSync.prototype._mark = function (p) { - return common.mark(this, p) -} + return globTasks; +}; -GlobSync.prototype._makeAbs = function (f) { - return common.makeAbs(this, f) -} +const globDirs = (task, fn) => { + let options = {}; + if (task.options.cwd) { + options.cwd = task.options.cwd; + } + + if (Array.isArray(task.options.expandDirectories)) { + options = Object.assign(options, {files: task.options.expandDirectories}); + } else if (typeof task.options.expandDirectories === 'object') { + options = Object.assign(options, task.options.expandDirectories); + } + + return fn(task.pattern, options); +}; +const getPattern = (task, fn) => task.options.expandDirectories ? globDirs(task, fn) : [task.pattern]; -/***/ }), -/* 524 */ -/***/ (function(module, exports, __webpack_require__) { +const globToTask = task => glob => { + const {options} = task; + if (options.ignore && Array.isArray(options.ignore) && options.expandDirectories) { + options.ignore = dirGlob.sync(options.ignore); + } -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 + return { + pattern: glob, + options + }; +}; -function ownProp (obj, field) { - return Object.prototype.hasOwnProperty.call(obj, field) -} +const globby = (patterns, options) => { + let globTasks; -var path = __webpack_require__(4) -var minimatch = __webpack_require__(149) -var isAbsolute = __webpack_require__(156) -var Minimatch = minimatch.Minimatch + try { + globTasks = generateGlobTasks(patterns, options); + } catch (error) { + return Promise.reject(error); + } -function alphasorti (a, b) { - return a.toLowerCase().localeCompare(b.toLowerCase()) -} + const getTasks = Promise.all(globTasks.map(task => Promise.resolve(getPattern(task, dirGlob)) + .then(globs => Promise.all(globs.map(globToTask(task)))) + )) + .then(tasks => arrayUnion(...tasks)); -function alphasort (a, b) { - return a.localeCompare(b) -} + const getFilter = () => { + return Promise.resolve( + options && options.gitignore ? + gitignore({cwd: options.cwd, ignore: options.ignore}) : + DEFAULT_FILTER + ); + }; -function setupIgnores (self, options) { - self.ignore = options.ignore || [] + return getFilter() + .then(filter => { + return getTasks + .then(tasks => Promise.all(tasks.map(task => fastGlob(task.pattern, task.options)))) + .then(paths => arrayUnion(...paths)) + .then(paths => paths.filter(p => !filter(p))); + }); +}; - if (!Array.isArray(self.ignore)) - self.ignore = [self.ignore] +module.exports = globby; +// TODO: Remove this for the next major release +module.exports.default = globby; - if (self.ignore.length) { - self.ignore = self.ignore.map(ignoreMap) - } -} +module.exports.sync = (patterns, options) => { + const globTasks = generateGlobTasks(patterns, options); -// 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 }) - } + const getFilter = () => { + return options && options.gitignore ? + gitignore.sync({cwd: options.cwd, ignore: options.ignore}) : + DEFAULT_FILTER; + }; - return { - matcher: new Minimatch(pattern, { dot: true }), - gmatcher: gmatcher - } -} + const tasks = globTasks.reduce((tasks, task) => { + const newTask = getPattern(task, dirGlob.sync).map(globToTask(task)); + return tasks.concat(newTask); + }, []); -function setopts (self, pattern, options) { - if (!options) - options = {} + const filter = getFilter(); + return tasks.reduce( + (matches, task) => arrayUnion(matches, fastGlob.sync(task.pattern, task.options)), + [] + ).filter(p => !filter(p)); +}; - // 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 - } +module.exports.generateGlobTasks = generateGlobTasks; - 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 +module.exports.hasMagic = (patterns, options) => [] + .concat(patterns) + .some(pattern => glob.hasMagic(pattern, options)); - 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) +module.exports.gitignore = gitignore; - 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 - } +/***/ }), +/* 512 */ +/***/ (function(module, exports, __webpack_require__) { - self.root = options.root || path.resolve(self.cwd, "/") - self.root = path.resolve(self.root) - if (process.platform === "win32") - self.root = self.root.replace(/\\/g, "/") +"use strict"; - // 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 +var arrayUniq = __webpack_require__(513); - // disable comments and negation in Minimatch. - // Note that they are not supported in Glob itself anyway. - options.nonegate = true - options.nocomment = true +module.exports = function () { + return arrayUniq([].concat.apply([], arguments)); +}; - self.minimatch = new Minimatch(pattern, options) - self.options = self.minimatch.options -} -function finish (self) { - var nou = self.nounique - var all = nou ? [] : Object.create(null) +/***/ }), +/* 513 */ +/***/ (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"; - if (!nou) - all = Object.keys(all) - if (!self.nosort) - all = all.sort(self.nocase ? alphasorti : alphasort) +// there's 3 implementations written in increasing order of efficiency - // 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 - }) - } - } +// 1 - no Set type is defined +function uniqNoSet(arr) { + var ret = []; - if (self.ignore.length) - all = all.filter(function(m) { - return !isIgnored(self, m) - }) + for (var i = 0; i < arr.length; i++) { + if (ret.indexOf(arr[i]) === -1) { + ret.push(arr[i]); + } + } - self.found = all + return ret; } -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] - } - } +// 2 - a simple Set type is defined +function uniqSet(arr) { + var seen = new Set(); + return arr.filter(function (el) { + if (!seen.has(el)) { + seen.add(el); + return true; + } - return m + return false; + }); } -// 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) - } +// 3 - a standard Set type is defined and it has a forEach method +function uniqSetWithForEach(arr) { + var ret = []; - if (process.platform === 'win32') - abs = abs.replace(/\\/g, '/') + (new Set(arr)).forEach(function (el) { + ret.push(el); + }); - return abs + return ret; } +// V8 currently has a broken implementation +// https://github.com/joyent/node/issues/8449 +function doesForEachActuallyWork() { + var ret = false; -// 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 + (new Set([true])).forEach(function (el) { + ret = el; + }); - return self.ignore.some(function(item) { - return item.matcher.match(path) || !!(item.gmatcher && item.gmatcher.match(path)) - }) + return ret === true; } -function childrenIgnored (self, path) { - if (!self.ignore.length) - return false - - return self.ignore.some(function(item) { - return !!(item.gmatcher && item.gmatcher.match(path)) - }) +if ('Set' in global) { + if (typeof Set.prototype.forEach === 'function' && doesForEachActuallyWork()) { + module.exports = uniqSetWithForEach; + } else { + module.exports = uniqSet; + } +} else { + module.exports = uniqNoSet; } /***/ }), -/* 525 */ +/* 514 */ /***/ (function(module, exports, __webpack_require__) { -const pkg = __webpack_require__(526); +const pkg = __webpack_require__(515); module.exports = pkg.async; module.exports.default = pkg.async; @@ -61734,19 +58543,19 @@ module.exports.generateTasks = pkg.generateTasks; /***/ }), -/* 526 */ +/* 515 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var optionsManager = __webpack_require__(527); -var taskManager = __webpack_require__(528); -var reader_async_1 = __webpack_require__(696); -var reader_stream_1 = __webpack_require__(720); -var reader_sync_1 = __webpack_require__(721); -var arrayUtils = __webpack_require__(723); -var streamUtils = __webpack_require__(724); +var optionsManager = __webpack_require__(516); +var taskManager = __webpack_require__(517); +var reader_async_1 = __webpack_require__(685); +var reader_stream_1 = __webpack_require__(709); +var reader_sync_1 = __webpack_require__(710); +var arrayUtils = __webpack_require__(712); +var streamUtils = __webpack_require__(713); /** * Synchronous API. */ @@ -61812,7 +58621,7 @@ function isString(source) { /***/ }), -/* 527 */ +/* 516 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -61850,13 +58659,13 @@ exports.prepare = prepare; /***/ }), -/* 528 */ +/* 517 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var patternUtils = __webpack_require__(529); +var patternUtils = __webpack_require__(518); /** * Generate tasks based on parent directory of each pattern. */ @@ -61947,16 +58756,16 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask; /***/ }), -/* 529 */ +/* 518 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(4); -var globParent = __webpack_require__(530); -var isGlob = __webpack_require__(533); -var micromatch = __webpack_require__(534); +var globParent = __webpack_require__(519); +var isGlob = __webpack_require__(522); +var micromatch = __webpack_require__(523); var GLOBSTAR = '**'; /** * Return true for static pattern. @@ -62102,15 +58911,15 @@ exports.matchAny = matchAny; /***/ }), -/* 530 */ +/* 519 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var path = __webpack_require__(4); -var isglob = __webpack_require__(531); -var pathDirname = __webpack_require__(532); +var isglob = __webpack_require__(520); +var pathDirname = __webpack_require__(521); var isWin32 = __webpack_require__(120).platform() === 'win32'; module.exports = function globParent(str) { @@ -62133,7 +58942,7 @@ module.exports = function globParent(str) { /***/ }), -/* 531 */ +/* 520 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -62143,7 +58952,7 @@ module.exports = function globParent(str) { * Licensed under the MIT License. */ -var isExtglob = __webpack_require__(315); +var isExtglob = __webpack_require__(310); module.exports = function isGlob(str) { if (typeof str !== 'string' || str === '') { @@ -62164,7 +58973,7 @@ module.exports = function isGlob(str) { /***/ }), -/* 532 */ +/* 521 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -62314,7 +59123,7 @@ module.exports.win32 = win32; /***/ }), -/* 533 */ +/* 522 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -62324,7 +59133,7 @@ module.exports.win32 = win32; * Released under the MIT License. */ -var isExtglob = __webpack_require__(315); +var isExtglob = __webpack_require__(310); var chars = { '{': '}', '(': ')', '[': ']'}; module.exports = function isGlob(str, options) { @@ -62366,7 +59175,7 @@ module.exports = function isGlob(str, options) { /***/ }), -/* 534 */ +/* 523 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -62377,18 +59186,18 @@ module.exports = function isGlob(str, options) { */ var util = __webpack_require__(111); -var braces = __webpack_require__(535); -var toRegex = __webpack_require__(648); -var extend = __webpack_require__(656); +var braces = __webpack_require__(524); +var toRegex = __webpack_require__(637); +var extend = __webpack_require__(645); /** * Local dependencies */ -var compilers = __webpack_require__(659); -var parsers = __webpack_require__(692); -var cache = __webpack_require__(693); -var utils = __webpack_require__(694); +var compilers = __webpack_require__(648); +var parsers = __webpack_require__(681); +var cache = __webpack_require__(682); +var utils = __webpack_require__(683); var MAX_LENGTH = 1024 * 64; /** @@ -63250,7 +60059,7 @@ module.exports = micromatch; /***/ }), -/* 535 */ +/* 524 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63260,18 +60069,18 @@ module.exports = micromatch; * Module dependencies */ -var toRegex = __webpack_require__(536); -var unique = __webpack_require__(550); -var extend = __webpack_require__(545); +var toRegex = __webpack_require__(525); +var unique = __webpack_require__(539); +var extend = __webpack_require__(534); /** * Local dependencies */ -var compilers = __webpack_require__(551); -var parsers = __webpack_require__(568); -var Braces = __webpack_require__(578); -var utils = __webpack_require__(552); +var compilers = __webpack_require__(540); +var parsers = __webpack_require__(557); +var Braces = __webpack_require__(567); +var utils = __webpack_require__(541); var MAX_LENGTH = 1024 * 64; var cache = {}; @@ -63575,15 +60384,15 @@ module.exports = braces; /***/ }), -/* 536 */ +/* 525 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(537); -var extend = __webpack_require__(545); -var not = __webpack_require__(547); +var define = __webpack_require__(526); +var extend = __webpack_require__(534); +var not = __webpack_require__(536); var MAX_LENGTH = 1024 * 64; /** @@ -63730,7 +60539,7 @@ module.exports.makeRe = makeRe; /***/ }), -/* 537 */ +/* 526 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63743,7 +60552,7 @@ module.exports.makeRe = makeRe; -var isDescriptor = __webpack_require__(538); +var isDescriptor = __webpack_require__(527); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -63768,7 +60577,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 538 */ +/* 527 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63781,9 +60590,9 @@ module.exports = function defineProperty(obj, prop, val) { -var typeOf = __webpack_require__(539); -var isAccessor = __webpack_require__(540); -var isData = __webpack_require__(543); +var typeOf = __webpack_require__(528); +var isAccessor = __webpack_require__(529); +var isData = __webpack_require__(532); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -63797,7 +60606,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 539 */ +/* 528 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -63950,7 +60759,7 @@ function isBuffer(val) { /***/ }), -/* 540 */ +/* 529 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63963,7 +60772,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(541); +var typeOf = __webpack_require__(530); // accessor descriptor properties var accessor = { @@ -64026,10 +60835,10 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 541 */ +/* 530 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(542); +var isBuffer = __webpack_require__(531); var toString = Object.prototype.toString; /** @@ -64148,7 +60957,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 542 */ +/* 531 */ /***/ (function(module, exports) { /*! @@ -64175,7 +60984,7 @@ function isSlowBuffer (obj) { /***/ }), -/* 543 */ +/* 532 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64188,7 +60997,7 @@ function isSlowBuffer (obj) { -var typeOf = __webpack_require__(544); +var typeOf = __webpack_require__(533); // data descriptor properties var data = { @@ -64237,10 +61046,10 @@ module.exports = isDataDescriptor; /***/ }), -/* 544 */ +/* 533 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(542); +var isBuffer = __webpack_require__(531); var toString = Object.prototype.toString; /** @@ -64359,13 +61168,13 @@ module.exports = function kindOf(val) { /***/ }), -/* 545 */ +/* 534 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(546); +var isObject = __webpack_require__(535); module.exports = function extend(o/*, objects*/) { if (!isObject(o)) { o = {}; } @@ -64399,7 +61208,7 @@ function hasOwn(obj, key) { /***/ }), -/* 546 */ +/* 535 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64419,13 +61228,13 @@ module.exports = function isExtendable(val) { /***/ }), -/* 547 */ +/* 536 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(548); +var extend = __webpack_require__(537); /** * The main export is a function that takes a `pattern` string and an `options` object. @@ -64492,13 +61301,13 @@ module.exports = toRegex; /***/ }), -/* 548 */ +/* 537 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(549); +var isObject = __webpack_require__(538); module.exports = function extend(o/*, objects*/) { if (!isObject(o)) { o = {}; } @@ -64532,7 +61341,7 @@ function hasOwn(obj, key) { /***/ }), -/* 549 */ +/* 538 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64552,7 +61361,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 550 */ +/* 539 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64602,13 +61411,13 @@ module.exports.immutable = function uniqueImmutable(arr) { /***/ }), -/* 551 */ +/* 540 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(552); +var utils = __webpack_require__(541); module.exports = function(braces, options) { braces.compiler @@ -64891,25 +61700,25 @@ function hasQueue(node) { /***/ }), -/* 552 */ +/* 541 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var splitString = __webpack_require__(553); +var splitString = __webpack_require__(542); var utils = module.exports; /** * Module dependencies */ -utils.extend = __webpack_require__(545); -utils.flatten = __webpack_require__(559); -utils.isObject = __webpack_require__(557); -utils.fillRange = __webpack_require__(560); -utils.repeat = __webpack_require__(567); -utils.unique = __webpack_require__(550); +utils.extend = __webpack_require__(534); +utils.flatten = __webpack_require__(548); +utils.isObject = __webpack_require__(546); +utils.fillRange = __webpack_require__(549); +utils.repeat = __webpack_require__(556); +utils.unique = __webpack_require__(539); utils.define = function(obj, key, val) { Object.defineProperty(obj, key, { @@ -65241,7 +62050,7 @@ utils.escapeRegex = function(str) { /***/ }), -/* 553 */ +/* 542 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65254,7 +62063,7 @@ utils.escapeRegex = function(str) { -var extend = __webpack_require__(554); +var extend = __webpack_require__(543); module.exports = function(str, options, fn) { if (typeof str !== 'string') { @@ -65419,14 +62228,14 @@ function keepEscaping(opts, str, idx) { /***/ }), -/* 554 */ +/* 543 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(555); -var assignSymbols = __webpack_require__(558); +var isExtendable = __webpack_require__(544); +var assignSymbols = __webpack_require__(547); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -65486,7 +62295,7 @@ function isEnum(obj, key) { /***/ }), -/* 555 */ +/* 544 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65499,7 +62308,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(556); +var isPlainObject = __webpack_require__(545); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -65507,7 +62316,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 556 */ +/* 545 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65520,7 +62329,7 @@ module.exports = function isExtendable(val) { -var isObject = __webpack_require__(557); +var isObject = __webpack_require__(546); function isObjectObject(o) { return isObject(o) === true @@ -65551,7 +62360,7 @@ module.exports = function isPlainObject(o) { /***/ }), -/* 557 */ +/* 546 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65570,7 +62379,7 @@ module.exports = function isObject(val) { /***/ }), -/* 558 */ +/* 547 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65617,7 +62426,7 @@ module.exports = function(receiver, objects) { /***/ }), -/* 559 */ +/* 548 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65646,7 +62455,7 @@ function flat(arr, res) { /***/ }), -/* 560 */ +/* 549 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65660,10 +62469,10 @@ function flat(arr, res) { var util = __webpack_require__(111); -var isNumber = __webpack_require__(561); -var extend = __webpack_require__(563); -var repeat = __webpack_require__(565); -var toRegex = __webpack_require__(566); +var isNumber = __webpack_require__(550); +var extend = __webpack_require__(552); +var repeat = __webpack_require__(554); +var toRegex = __webpack_require__(555); /** * Return a range of numbers or letters. @@ -65861,7 +62670,7 @@ module.exports = fillRange; /***/ }), -/* 561 */ +/* 550 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65874,7 +62683,7 @@ module.exports = fillRange; -var typeOf = __webpack_require__(562); +var typeOf = __webpack_require__(551); module.exports = function isNumber(num) { var type = typeOf(num); @@ -65890,10 +62699,10 @@ module.exports = function isNumber(num) { /***/ }), -/* 562 */ +/* 551 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(542); +var isBuffer = __webpack_require__(531); var toString = Object.prototype.toString; /** @@ -66012,13 +62821,13 @@ module.exports = function kindOf(val) { /***/ }), -/* 563 */ +/* 552 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(564); +var isObject = __webpack_require__(553); module.exports = function extend(o/*, objects*/) { if (!isObject(o)) { o = {}; } @@ -66052,7 +62861,7 @@ function hasOwn(obj, key) { /***/ }), -/* 564 */ +/* 553 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -66072,7 +62881,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 565 */ +/* 554 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -66149,7 +62958,7 @@ function repeat(str, num) { /***/ }), -/* 566 */ +/* 555 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -66162,8 +62971,8 @@ function repeat(str, num) { -var repeat = __webpack_require__(565); -var isNumber = __webpack_require__(561); +var repeat = __webpack_require__(554); +var isNumber = __webpack_require__(550); var cache = {}; function toRegexRange(min, max, options) { @@ -66450,7 +63259,7 @@ module.exports = toRegexRange; /***/ }), -/* 567 */ +/* 556 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -66475,14 +63284,14 @@ module.exports = function repeat(ele, num) { /***/ }), -/* 568 */ +/* 557 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Node = __webpack_require__(569); -var utils = __webpack_require__(552); +var Node = __webpack_require__(558); +var utils = __webpack_require__(541); /** * Braces parsers @@ -66842,15 +63651,15 @@ function concatNodes(pos, node, parent, options) { /***/ }), -/* 569 */ +/* 558 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(557); -var define = __webpack_require__(570); -var utils = __webpack_require__(577); +var isObject = __webpack_require__(546); +var define = __webpack_require__(559); +var utils = __webpack_require__(566); var ownNames; /** @@ -67341,7 +64150,7 @@ exports = module.exports = Node; /***/ }), -/* 570 */ +/* 559 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67354,7 +64163,7 @@ exports = module.exports = Node; -var isDescriptor = __webpack_require__(571); +var isDescriptor = __webpack_require__(560); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -67379,7 +64188,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 571 */ +/* 560 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67392,9 +64201,9 @@ module.exports = function defineProperty(obj, prop, val) { -var typeOf = __webpack_require__(572); -var isAccessor = __webpack_require__(573); -var isData = __webpack_require__(575); +var typeOf = __webpack_require__(561); +var isAccessor = __webpack_require__(562); +var isData = __webpack_require__(564); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -67408,7 +64217,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 572 */ +/* 561 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -67543,7 +64352,7 @@ function isBuffer(val) { /***/ }), -/* 573 */ +/* 562 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67556,7 +64365,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(574); +var typeOf = __webpack_require__(563); // accessor descriptor properties var accessor = { @@ -67619,7 +64428,7 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 574 */ +/* 563 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -67754,7 +64563,7 @@ function isBuffer(val) { /***/ }), -/* 575 */ +/* 564 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67767,7 +64576,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(576); +var typeOf = __webpack_require__(565); module.exports = function isDataDescriptor(obj, prop) { // data descriptor properties @@ -67810,7 +64619,7 @@ module.exports = function isDataDescriptor(obj, prop) { /***/ }), -/* 576 */ +/* 565 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -67945,13 +64754,13 @@ function isBuffer(val) { /***/ }), -/* 577 */ +/* 566 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(562); +var typeOf = __webpack_require__(551); var utils = module.exports; /** @@ -68971,17 +65780,17 @@ function assert(val, message) { /***/ }), -/* 578 */ +/* 567 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(545); -var Snapdragon = __webpack_require__(579); -var compilers = __webpack_require__(551); -var parsers = __webpack_require__(568); -var utils = __webpack_require__(552); +var extend = __webpack_require__(534); +var Snapdragon = __webpack_require__(568); +var compilers = __webpack_require__(540); +var parsers = __webpack_require__(557); +var utils = __webpack_require__(541); /** * Customize Snapdragon parser and renderer @@ -69082,17 +65891,17 @@ module.exports = Braces; /***/ }), -/* 579 */ +/* 568 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Base = __webpack_require__(580); -var define = __webpack_require__(606); -var Compiler = __webpack_require__(616); -var Parser = __webpack_require__(645); -var utils = __webpack_require__(625); +var Base = __webpack_require__(569); +var define = __webpack_require__(595); +var Compiler = __webpack_require__(605); +var Parser = __webpack_require__(634); +var utils = __webpack_require__(614); var regexCache = {}; var cache = {}; @@ -69263,20 +66072,20 @@ module.exports.Parser = Parser; /***/ }), -/* 580 */ +/* 569 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(111); -var define = __webpack_require__(581); -var CacheBase = __webpack_require__(582); -var Emitter = __webpack_require__(583); -var isObject = __webpack_require__(557); -var merge = __webpack_require__(600); -var pascal = __webpack_require__(603); -var cu = __webpack_require__(604); +var define = __webpack_require__(570); +var CacheBase = __webpack_require__(571); +var Emitter = __webpack_require__(572); +var isObject = __webpack_require__(546); +var merge = __webpack_require__(589); +var pascal = __webpack_require__(592); +var cu = __webpack_require__(593); /** * Optionally define a custom `cache` namespace to use. @@ -69705,7 +66514,7 @@ module.exports.namespace = namespace; /***/ }), -/* 581 */ +/* 570 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69718,7 +66527,7 @@ module.exports.namespace = namespace; -var isDescriptor = __webpack_require__(571); +var isDescriptor = __webpack_require__(560); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -69743,21 +66552,21 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 582 */ +/* 571 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(557); -var Emitter = __webpack_require__(583); -var visit = __webpack_require__(584); -var toPath = __webpack_require__(587); -var union = __webpack_require__(588); -var del = __webpack_require__(592); -var get = __webpack_require__(590); -var has = __webpack_require__(597); -var set = __webpack_require__(591); +var isObject = __webpack_require__(546); +var Emitter = __webpack_require__(572); +var visit = __webpack_require__(573); +var toPath = __webpack_require__(576); +var union = __webpack_require__(577); +var del = __webpack_require__(581); +var get = __webpack_require__(579); +var has = __webpack_require__(586); +var set = __webpack_require__(580); /** * Create a `Cache` constructor that when instantiated will @@ -70011,7 +66820,7 @@ module.exports.namespace = namespace; /***/ }), -/* 583 */ +/* 572 */ /***/ (function(module, exports, __webpack_require__) { @@ -70180,7 +66989,7 @@ Emitter.prototype.hasListeners = function(event){ /***/ }), -/* 584 */ +/* 573 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70193,8 +67002,8 @@ Emitter.prototype.hasListeners = function(event){ -var visit = __webpack_require__(585); -var mapVisit = __webpack_require__(586); +var visit = __webpack_require__(574); +var mapVisit = __webpack_require__(575); module.exports = function(collection, method, val) { var result; @@ -70217,7 +67026,7 @@ module.exports = function(collection, method, val) { /***/ }), -/* 585 */ +/* 574 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70230,7 +67039,7 @@ module.exports = function(collection, method, val) { -var isObject = __webpack_require__(557); +var isObject = __webpack_require__(546); module.exports = function visit(thisArg, method, target, val) { if (!isObject(thisArg) && typeof thisArg !== 'function') { @@ -70257,14 +67066,14 @@ module.exports = function visit(thisArg, method, target, val) { /***/ }), -/* 586 */ +/* 575 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(111); -var visit = __webpack_require__(585); +var visit = __webpack_require__(574); /** * Map `visit` over an array of objects. @@ -70301,7 +67110,7 @@ function isObject(val) { /***/ }), -/* 587 */ +/* 576 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70314,7 +67123,7 @@ function isObject(val) { -var typeOf = __webpack_require__(562); +var typeOf = __webpack_require__(551); module.exports = function toPath(args) { if (typeOf(args) !== 'arguments') { @@ -70341,16 +67150,16 @@ function filter(arr) { /***/ }), -/* 588 */ +/* 577 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(549); -var union = __webpack_require__(589); -var get = __webpack_require__(590); -var set = __webpack_require__(591); +var isObject = __webpack_require__(538); +var union = __webpack_require__(578); +var get = __webpack_require__(579); +var set = __webpack_require__(580); module.exports = function unionValue(obj, prop, value) { if (!isObject(obj)) { @@ -70378,7 +67187,7 @@ function arrayify(val) { /***/ }), -/* 589 */ +/* 578 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70414,7 +67223,7 @@ module.exports = function union(init) { /***/ }), -/* 590 */ +/* 579 */ /***/ (function(module, exports) { /*! @@ -70470,7 +67279,7 @@ function toString(val) { /***/ }), -/* 591 */ +/* 580 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70483,10 +67292,10 @@ function toString(val) { -var split = __webpack_require__(553); -var extend = __webpack_require__(548); -var isPlainObject = __webpack_require__(556); -var isObject = __webpack_require__(549); +var split = __webpack_require__(542); +var extend = __webpack_require__(537); +var isPlainObject = __webpack_require__(545); +var isObject = __webpack_require__(538); module.exports = function(obj, prop, val) { if (!isObject(obj)) { @@ -70532,7 +67341,7 @@ function isValidKey(key) { /***/ }), -/* 592 */ +/* 581 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70545,8 +67354,8 @@ function isValidKey(key) { -var isObject = __webpack_require__(557); -var has = __webpack_require__(593); +var isObject = __webpack_require__(546); +var has = __webpack_require__(582); module.exports = function unset(obj, prop) { if (!isObject(obj)) { @@ -70571,7 +67380,7 @@ module.exports = function unset(obj, prop) { /***/ }), -/* 593 */ +/* 582 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70584,9 +67393,9 @@ module.exports = function unset(obj, prop) { -var isObject = __webpack_require__(594); -var hasValues = __webpack_require__(596); -var get = __webpack_require__(590); +var isObject = __webpack_require__(583); +var hasValues = __webpack_require__(585); +var get = __webpack_require__(579); module.exports = function(obj, prop, noZero) { if (isObject(obj)) { @@ -70597,7 +67406,7 @@ module.exports = function(obj, prop, noZero) { /***/ }), -/* 594 */ +/* 583 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70610,7 +67419,7 @@ module.exports = function(obj, prop, noZero) { -var isArray = __webpack_require__(595); +var isArray = __webpack_require__(584); module.exports = function isObject(val) { return val != null && typeof val === 'object' && isArray(val) === false; @@ -70618,7 +67427,7 @@ module.exports = function isObject(val) { /***/ }), -/* 595 */ +/* 584 */ /***/ (function(module, exports) { var toString = {}.toString; @@ -70629,7 +67438,7 @@ module.exports = Array.isArray || function (arr) { /***/ }), -/* 596 */ +/* 585 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70672,7 +67481,7 @@ module.exports = function hasValue(o, noZero) { /***/ }), -/* 597 */ +/* 586 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70685,9 +67494,9 @@ module.exports = function hasValue(o, noZero) { -var isObject = __webpack_require__(557); -var hasValues = __webpack_require__(598); -var get = __webpack_require__(590); +var isObject = __webpack_require__(546); +var hasValues = __webpack_require__(587); +var get = __webpack_require__(579); module.exports = function(val, prop) { return hasValues(isObject(val) && prop ? get(val, prop) : val); @@ -70695,7 +67504,7 @@ module.exports = function(val, prop) { /***/ }), -/* 598 */ +/* 587 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70708,8 +67517,8 @@ module.exports = function(val, prop) { -var typeOf = __webpack_require__(599); -var isNumber = __webpack_require__(561); +var typeOf = __webpack_require__(588); +var isNumber = __webpack_require__(550); module.exports = function hasValue(val) { // is-number checks for NaN and other edge cases @@ -70762,10 +67571,10 @@ module.exports = function hasValue(val) { /***/ }), -/* 599 */ +/* 588 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(542); +var isBuffer = __webpack_require__(531); var toString = Object.prototype.toString; /** @@ -70887,14 +67696,14 @@ module.exports = function kindOf(val) { /***/ }), -/* 600 */ +/* 589 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(601); -var forIn = __webpack_require__(602); +var isExtendable = __webpack_require__(590); +var forIn = __webpack_require__(591); function mixinDeep(target, objects) { var len = arguments.length, i = 0; @@ -70958,7 +67767,7 @@ module.exports = mixinDeep; /***/ }), -/* 601 */ +/* 590 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70971,7 +67780,7 @@ module.exports = mixinDeep; -var isPlainObject = __webpack_require__(556); +var isPlainObject = __webpack_require__(545); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -70979,7 +67788,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 602 */ +/* 591 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71002,7 +67811,7 @@ module.exports = function forIn(obj, fn, thisArg) { /***/ }), -/* 603 */ +/* 592 */ /***/ (function(module, exports) { /*! @@ -71029,14 +67838,14 @@ module.exports = pascalcase; /***/ }), -/* 604 */ +/* 593 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(111); -var utils = __webpack_require__(605); +var utils = __webpack_require__(594); /** * Expose class utils @@ -71401,7 +68210,7 @@ cu.bubble = function(Parent, events) { /***/ }), -/* 605 */ +/* 594 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71415,10 +68224,10 @@ var utils = {}; * Lazily required module dependencies */ -utils.union = __webpack_require__(589); -utils.define = __webpack_require__(606); -utils.isObj = __webpack_require__(557); -utils.staticExtend = __webpack_require__(613); +utils.union = __webpack_require__(578); +utils.define = __webpack_require__(595); +utils.isObj = __webpack_require__(546); +utils.staticExtend = __webpack_require__(602); /** @@ -71429,7 +68238,7 @@ module.exports = utils; /***/ }), -/* 606 */ +/* 595 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71442,7 +68251,7 @@ module.exports = utils; -var isDescriptor = __webpack_require__(607); +var isDescriptor = __webpack_require__(596); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -71467,7 +68276,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 607 */ +/* 596 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71480,9 +68289,9 @@ module.exports = function defineProperty(obj, prop, val) { -var typeOf = __webpack_require__(608); -var isAccessor = __webpack_require__(609); -var isData = __webpack_require__(611); +var typeOf = __webpack_require__(597); +var isAccessor = __webpack_require__(598); +var isData = __webpack_require__(600); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -71496,7 +68305,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 608 */ +/* 597 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -71649,7 +68458,7 @@ function isBuffer(val) { /***/ }), -/* 609 */ +/* 598 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71662,7 +68471,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(610); +var typeOf = __webpack_require__(599); // accessor descriptor properties var accessor = { @@ -71725,10 +68534,10 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 610 */ +/* 599 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(542); +var isBuffer = __webpack_require__(531); var toString = Object.prototype.toString; /** @@ -71847,7 +68656,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 611 */ +/* 600 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71860,7 +68669,7 @@ module.exports = function kindOf(val) { -var typeOf = __webpack_require__(612); +var typeOf = __webpack_require__(601); // data descriptor properties var data = { @@ -71909,10 +68718,10 @@ module.exports = isDataDescriptor; /***/ }), -/* 612 */ +/* 601 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(542); +var isBuffer = __webpack_require__(531); var toString = Object.prototype.toString; /** @@ -72031,7 +68840,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 613 */ +/* 602 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72044,8 +68853,8 @@ module.exports = function kindOf(val) { -var copy = __webpack_require__(614); -var define = __webpack_require__(606); +var copy = __webpack_require__(603); +var define = __webpack_require__(595); var util = __webpack_require__(111); /** @@ -72128,15 +68937,15 @@ module.exports = extend; /***/ }), -/* 614 */ +/* 603 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(562); -var copyDescriptor = __webpack_require__(615); -var define = __webpack_require__(606); +var typeOf = __webpack_require__(551); +var copyDescriptor = __webpack_require__(604); +var define = __webpack_require__(595); /** * Copy static properties, prototype properties, and descriptors from one object to another. @@ -72309,7 +69118,7 @@ module.exports.has = has; /***/ }), -/* 615 */ +/* 604 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72397,16 +69206,16 @@ function isObject(val) { /***/ }), -/* 616 */ +/* 605 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(617); -var define = __webpack_require__(606); -var debug = __webpack_require__(619)('snapdragon:compiler'); -var utils = __webpack_require__(625); +var use = __webpack_require__(606); +var define = __webpack_require__(595); +var debug = __webpack_require__(608)('snapdragon:compiler'); +var utils = __webpack_require__(614); /** * Create a new `Compiler` with the given `options`. @@ -72560,7 +69369,7 @@ Compiler.prototype = { // source map support if (opts.sourcemap) { - var sourcemaps = __webpack_require__(644); + var sourcemaps = __webpack_require__(633); sourcemaps(this); this.mapVisit(this.ast.nodes); this.applySourceMaps(); @@ -72581,7 +69390,7 @@ module.exports = Compiler; /***/ }), -/* 617 */ +/* 606 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72594,7 +69403,7 @@ module.exports = Compiler; -var utils = __webpack_require__(618); +var utils = __webpack_require__(607); module.exports = function base(app, opts) { if (!utils.isObject(app) && typeof app !== 'function') { @@ -72709,7 +69518,7 @@ module.exports = function base(app, opts) { /***/ }), -/* 618 */ +/* 607 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72723,8 +69532,8 @@ var utils = {}; * Lazily required module dependencies */ -utils.define = __webpack_require__(606); -utils.isObject = __webpack_require__(557); +utils.define = __webpack_require__(595); +utils.isObject = __webpack_require__(546); utils.isString = function(val) { @@ -72739,7 +69548,7 @@ module.exports = utils; /***/ }), -/* 619 */ +/* 608 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -72748,14 +69557,14 @@ module.exports = utils; */ if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(620); + module.exports = __webpack_require__(609); } else { - module.exports = __webpack_require__(623); + module.exports = __webpack_require__(612); } /***/ }), -/* 620 */ +/* 609 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -72764,7 +69573,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') { * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(621); +exports = module.exports = __webpack_require__(610); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -72946,7 +69755,7 @@ function localstorage() { /***/ }), -/* 621 */ +/* 610 */ /***/ (function(module, exports, __webpack_require__) { @@ -72962,7 +69771,7 @@ exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; -exports.humanize = __webpack_require__(622); +exports.humanize = __webpack_require__(611); /** * The currently active debug mode names, and names to skip. @@ -73154,7 +69963,7 @@ function coerce(val) { /***/ }), -/* 622 */ +/* 611 */ /***/ (function(module, exports) { /** @@ -73312,7 +70121,7 @@ function plural(ms, n, name) { /***/ }), -/* 623 */ +/* 612 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -73328,7 +70137,7 @@ var util = __webpack_require__(111); * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(621); +exports = module.exports = __webpack_require__(610); exports.init = init; exports.log = log; exports.formatArgs = formatArgs; @@ -73507,7 +70316,7 @@ function createWritableStdioStream (fd) { case 'PIPE': case 'TCP': - var net = __webpack_require__(624); + var net = __webpack_require__(613); stream = new net.Socket({ fd: fd, readable: false, @@ -73566,13 +70375,13 @@ exports.enable(load()); /***/ }), -/* 624 */ +/* 613 */ /***/ (function(module, exports) { module.exports = require("net"); /***/ }), -/* 625 */ +/* 614 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -73582,9 +70391,9 @@ module.exports = require("net"); * Module dependencies */ -exports.extend = __webpack_require__(548); -exports.SourceMap = __webpack_require__(626); -exports.sourceMapResolve = __webpack_require__(637); +exports.extend = __webpack_require__(537); +exports.SourceMap = __webpack_require__(615); +exports.sourceMapResolve = __webpack_require__(626); /** * Convert backslash in the given string to forward slashes @@ -73627,7 +70436,7 @@ exports.last = function(arr, n) { /***/ }), -/* 626 */ +/* 615 */ /***/ (function(module, exports, __webpack_require__) { /* @@ -73635,13 +70444,13 @@ exports.last = function(arr, n) { * Licensed under the New BSD license. See LICENSE.txt or: * http://opensource.org/licenses/BSD-3-Clause */ -exports.SourceMapGenerator = __webpack_require__(627).SourceMapGenerator; -exports.SourceMapConsumer = __webpack_require__(633).SourceMapConsumer; -exports.SourceNode = __webpack_require__(636).SourceNode; +exports.SourceMapGenerator = __webpack_require__(616).SourceMapGenerator; +exports.SourceMapConsumer = __webpack_require__(622).SourceMapConsumer; +exports.SourceNode = __webpack_require__(625).SourceNode; /***/ }), -/* 627 */ +/* 616 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -73651,10 +70460,10 @@ exports.SourceNode = __webpack_require__(636).SourceNode; * http://opensource.org/licenses/BSD-3-Clause */ -var base64VLQ = __webpack_require__(628); -var util = __webpack_require__(630); -var ArraySet = __webpack_require__(631).ArraySet; -var MappingList = __webpack_require__(632).MappingList; +var base64VLQ = __webpack_require__(617); +var util = __webpack_require__(619); +var ArraySet = __webpack_require__(620).ArraySet; +var MappingList = __webpack_require__(621).MappingList; /** * An instance of the SourceMapGenerator represents a source map which is @@ -74063,7 +70872,7 @@ exports.SourceMapGenerator = SourceMapGenerator; /***/ }), -/* 628 */ +/* 617 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -74103,7 +70912,7 @@ exports.SourceMapGenerator = SourceMapGenerator; * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -var base64 = __webpack_require__(629); +var base64 = __webpack_require__(618); // 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, @@ -74209,7 +71018,7 @@ exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { /***/ }), -/* 629 */ +/* 618 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -74282,7 +71091,7 @@ exports.decode = function (charCode) { /***/ }), -/* 630 */ +/* 619 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -74705,7 +71514,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate /***/ }), -/* 631 */ +/* 620 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -74715,7 +71524,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(630); +var util = __webpack_require__(619); var has = Object.prototype.hasOwnProperty; var hasNativeMap = typeof Map !== "undefined"; @@ -74832,7 +71641,7 @@ exports.ArraySet = ArraySet; /***/ }), -/* 632 */ +/* 621 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -74842,7 +71651,7 @@ exports.ArraySet = ArraySet; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(630); +var util = __webpack_require__(619); /** * Determine whether mappingB is after mappingA with respect to generated @@ -74917,7 +71726,7 @@ exports.MappingList = MappingList; /***/ }), -/* 633 */ +/* 622 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -74927,11 +71736,11 @@ exports.MappingList = MappingList; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(630); -var binarySearch = __webpack_require__(634); -var ArraySet = __webpack_require__(631).ArraySet; -var base64VLQ = __webpack_require__(628); -var quickSort = __webpack_require__(635).quickSort; +var util = __webpack_require__(619); +var binarySearch = __webpack_require__(623); +var ArraySet = __webpack_require__(620).ArraySet; +var base64VLQ = __webpack_require__(617); +var quickSort = __webpack_require__(624).quickSort; function SourceMapConsumer(aSourceMap) { var sourceMap = aSourceMap; @@ -76005,7 +72814,7 @@ exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer; /***/ }), -/* 634 */ +/* 623 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -76122,7 +72931,7 @@ exports.search = function search(aNeedle, aHaystack, aCompare, aBias) { /***/ }), -/* 635 */ +/* 624 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -76242,7 +73051,7 @@ exports.quickSort = function (ary, comparator) { /***/ }), -/* 636 */ +/* 625 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -76252,8 +73061,8 @@ exports.quickSort = function (ary, comparator) { * http://opensource.org/licenses/BSD-3-Clause */ -var SourceMapGenerator = __webpack_require__(627).SourceMapGenerator; -var util = __webpack_require__(630); +var SourceMapGenerator = __webpack_require__(616).SourceMapGenerator; +var util = __webpack_require__(619); // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other // operating systems these days (capturing the result). @@ -76661,17 +73470,17 @@ exports.SourceNode = SourceNode; /***/ }), -/* 637 */ +/* 626 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014, 2015, 2016, 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var sourceMappingURL = __webpack_require__(638) -var resolveUrl = __webpack_require__(639) -var decodeUriComponent = __webpack_require__(640) -var urix = __webpack_require__(642) -var atob = __webpack_require__(643) +var sourceMappingURL = __webpack_require__(627) +var resolveUrl = __webpack_require__(628) +var decodeUriComponent = __webpack_require__(629) +var urix = __webpack_require__(631) +var atob = __webpack_require__(632) @@ -76969,7 +73778,7 @@ module.exports = { /***/ }), -/* 638 */ +/* 627 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// Copyright 2014 Simon Lydell @@ -77032,7 +73841,7 @@ void (function(root, factory) { /***/ }), -/* 639 */ +/* 628 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -77050,13 +73859,13 @@ module.exports = resolveUrl /***/ }), -/* 640 */ +/* 629 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var decodeUriComponent = __webpack_require__(641) +var decodeUriComponent = __webpack_require__(630) function customDecodeUriComponent(string) { // `decodeUriComponent` turns `+` into ` `, but that's not wanted. @@ -77067,7 +73876,7 @@ module.exports = customDecodeUriComponent /***/ }), -/* 641 */ +/* 630 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77168,7 +73977,7 @@ module.exports = function (encodedURI) { /***/ }), -/* 642 */ +/* 631 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -77191,7 +74000,7 @@ module.exports = urix /***/ }), -/* 643 */ +/* 632 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77205,7 +74014,7 @@ module.exports = atob.atob = atob; /***/ }), -/* 644 */ +/* 633 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77213,8 +74022,8 @@ module.exports = atob.atob = atob; var fs = __webpack_require__(133); var path = __webpack_require__(4); -var define = __webpack_require__(606); -var utils = __webpack_require__(625); +var define = __webpack_require__(595); +var utils = __webpack_require__(614); /** * Expose `mixin()`. @@ -77357,19 +74166,19 @@ exports.comment = function(node) { /***/ }), -/* 645 */ +/* 634 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(617); +var use = __webpack_require__(606); var util = __webpack_require__(111); -var Cache = __webpack_require__(646); -var define = __webpack_require__(606); -var debug = __webpack_require__(619)('snapdragon:parser'); -var Position = __webpack_require__(647); -var utils = __webpack_require__(625); +var Cache = __webpack_require__(635); +var define = __webpack_require__(595); +var debug = __webpack_require__(608)('snapdragon:parser'); +var Position = __webpack_require__(636); +var utils = __webpack_require__(614); /** * Create a new `Parser` with the given `input` and `options`. @@ -77897,7 +74706,7 @@ module.exports = Parser; /***/ }), -/* 646 */ +/* 635 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78004,13 +74813,13 @@ MapCache.prototype.del = function mapDelete(key) { /***/ }), -/* 647 */ +/* 636 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(606); +var define = __webpack_require__(595); /** * Store position for a node @@ -78025,16 +74834,16 @@ module.exports = function Position(start, parser) { /***/ }), -/* 648 */ +/* 637 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var safe = __webpack_require__(649); -var define = __webpack_require__(655); -var extend = __webpack_require__(656); -var not = __webpack_require__(658); +var safe = __webpack_require__(638); +var define = __webpack_require__(644); +var extend = __webpack_require__(645); +var not = __webpack_require__(647); var MAX_LENGTH = 1024 * 64; /** @@ -78187,10 +74996,10 @@ module.exports.makeRe = makeRe; /***/ }), -/* 649 */ +/* 638 */ /***/ (function(module, exports, __webpack_require__) { -var parse = __webpack_require__(650); +var parse = __webpack_require__(639); var types = parse.types; module.exports = function (re, opts) { @@ -78236,13 +75045,13 @@ function isRegExp (x) { /***/ }), -/* 650 */ +/* 639 */ /***/ (function(module, exports, __webpack_require__) { -var util = __webpack_require__(651); -var types = __webpack_require__(652); -var sets = __webpack_require__(653); -var positions = __webpack_require__(654); +var util = __webpack_require__(640); +var types = __webpack_require__(641); +var sets = __webpack_require__(642); +var positions = __webpack_require__(643); module.exports = function(regexpStr) { @@ -78524,11 +75333,11 @@ module.exports.types = types; /***/ }), -/* 651 */ +/* 640 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(652); -var sets = __webpack_require__(653); +var types = __webpack_require__(641); +var sets = __webpack_require__(642); // All of these are private and only used by randexp. @@ -78641,7 +75450,7 @@ exports.error = function(regexp, msg) { /***/ }), -/* 652 */ +/* 641 */ /***/ (function(module, exports) { module.exports = { @@ -78657,10 +75466,10 @@ module.exports = { /***/ }), -/* 653 */ +/* 642 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(652); +var types = __webpack_require__(641); var INTS = function() { return [{ type: types.RANGE , from: 48, to: 57 }]; @@ -78745,10 +75554,10 @@ exports.anyChar = function() { /***/ }), -/* 654 */ +/* 643 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(652); +var types = __webpack_require__(641); exports.wordBoundary = function() { return { type: types.POSITION, value: 'b' }; @@ -78768,7 +75577,7 @@ exports.end = function() { /***/ }), -/* 655 */ +/* 644 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78781,8 +75590,8 @@ exports.end = function() { -var isobject = __webpack_require__(557); -var isDescriptor = __webpack_require__(571); +var isobject = __webpack_require__(546); +var isDescriptor = __webpack_require__(560); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -78813,14 +75622,14 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 656 */ +/* 645 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(657); -var assignSymbols = __webpack_require__(558); +var isExtendable = __webpack_require__(646); +var assignSymbols = __webpack_require__(547); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -78880,7 +75689,7 @@ function isEnum(obj, key) { /***/ }), -/* 657 */ +/* 646 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78893,7 +75702,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(556); +var isPlainObject = __webpack_require__(545); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -78901,14 +75710,14 @@ module.exports = function isExtendable(val) { /***/ }), -/* 658 */ +/* 647 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(656); -var safe = __webpack_require__(649); +var extend = __webpack_require__(645); +var safe = __webpack_require__(638); /** * The main export is a function that takes a `pattern` string and an `options` object. @@ -78980,14 +75789,14 @@ module.exports = toRegex; /***/ }), -/* 659 */ +/* 648 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var nanomatch = __webpack_require__(660); -var extglob = __webpack_require__(676); +var nanomatch = __webpack_require__(649); +var extglob = __webpack_require__(665); module.exports = function(snapdragon) { var compilers = snapdragon.compiler.compilers; @@ -79064,7 +75873,7 @@ function escapeExtglobs(compiler) { /***/ }), -/* 660 */ +/* 649 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79075,17 +75884,17 @@ function escapeExtglobs(compiler) { */ var util = __webpack_require__(111); -var toRegex = __webpack_require__(661); -var extend = __webpack_require__(662); +var toRegex = __webpack_require__(650); +var extend = __webpack_require__(651); /** * Local dependencies */ -var compilers = __webpack_require__(664); -var parsers = __webpack_require__(665); -var cache = __webpack_require__(668); -var utils = __webpack_require__(670); +var compilers = __webpack_require__(653); +var parsers = __webpack_require__(654); +var cache = __webpack_require__(657); +var utils = __webpack_require__(659); var MAX_LENGTH = 1024 * 64; /** @@ -79909,15 +76718,15 @@ module.exports = nanomatch; /***/ }), -/* 661 */ +/* 650 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(606); -var extend = __webpack_require__(548); -var not = __webpack_require__(547); +var define = __webpack_require__(595); +var extend = __webpack_require__(537); +var not = __webpack_require__(536); var MAX_LENGTH = 1024 * 64; /** @@ -80064,14 +76873,14 @@ module.exports.makeRe = makeRe; /***/ }), -/* 662 */ +/* 651 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(663); -var assignSymbols = __webpack_require__(558); +var isExtendable = __webpack_require__(652); +var assignSymbols = __webpack_require__(547); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -80131,7 +76940,7 @@ function isEnum(obj, key) { /***/ }), -/* 663 */ +/* 652 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80144,7 +76953,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(556); +var isPlainObject = __webpack_require__(545); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -80152,7 +76961,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 664 */ +/* 653 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80498,15 +77307,15 @@ module.exports = function(nanomatch, options) { /***/ }), -/* 665 */ +/* 654 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regexNot = __webpack_require__(547); -var toRegex = __webpack_require__(661); -var isOdd = __webpack_require__(666); +var regexNot = __webpack_require__(536); +var toRegex = __webpack_require__(650); +var isOdd = __webpack_require__(655); /** * Characters to use in negation regex (we want to "not" match @@ -80892,7 +77701,7 @@ module.exports.not = NOT_REGEX; /***/ }), -/* 666 */ +/* 655 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80905,7 +77714,7 @@ module.exports.not = NOT_REGEX; -var isNumber = __webpack_require__(667); +var isNumber = __webpack_require__(656); module.exports = function isOdd(i) { if (!isNumber(i)) { @@ -80919,7 +77728,7 @@ module.exports = function isOdd(i) { /***/ }), -/* 667 */ +/* 656 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80947,14 +77756,14 @@ module.exports = function isNumber(num) { /***/ }), -/* 668 */ +/* 657 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(669))(); +module.exports = new (__webpack_require__(658))(); /***/ }), -/* 669 */ +/* 658 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80967,7 +77776,7 @@ module.exports = new (__webpack_require__(669))(); -var MapCache = __webpack_require__(646); +var MapCache = __webpack_require__(635); /** * Create a new `FragmentCache` with an optional object to use for `caches`. @@ -81089,7 +77898,7 @@ exports = module.exports = FragmentCache; /***/ }), -/* 670 */ +/* 659 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81102,14 +77911,14 @@ var path = __webpack_require__(4); * Module dependencies */ -var isWindows = __webpack_require__(671)(); -var Snapdragon = __webpack_require__(579); -utils.define = __webpack_require__(672); -utils.diff = __webpack_require__(673); -utils.extend = __webpack_require__(662); -utils.pick = __webpack_require__(674); -utils.typeOf = __webpack_require__(675); -utils.unique = __webpack_require__(550); +var isWindows = __webpack_require__(660)(); +var Snapdragon = __webpack_require__(568); +utils.define = __webpack_require__(661); +utils.diff = __webpack_require__(662); +utils.extend = __webpack_require__(651); +utils.pick = __webpack_require__(663); +utils.typeOf = __webpack_require__(664); +utils.unique = __webpack_require__(539); /** * Returns true if the given value is effectively an empty string @@ -81475,7 +78284,7 @@ utils.unixify = function(options) { /***/ }), -/* 671 */ +/* 660 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! @@ -81503,7 +78312,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ /***/ }), -/* 672 */ +/* 661 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81516,8 +78325,8 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ -var isobject = __webpack_require__(557); -var isDescriptor = __webpack_require__(571); +var isobject = __webpack_require__(546); +var isDescriptor = __webpack_require__(560); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -81548,7 +78357,7 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 673 */ +/* 662 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81602,7 +78411,7 @@ function diffArray(one, two) { /***/ }), -/* 674 */ +/* 663 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81615,7 +78424,7 @@ function diffArray(one, two) { -var isObject = __webpack_require__(557); +var isObject = __webpack_require__(546); module.exports = function pick(obj, keys) { if (!isObject(obj) && typeof obj !== 'function') { @@ -81644,7 +78453,7 @@ module.exports = function pick(obj, keys) { /***/ }), -/* 675 */ +/* 664 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -81779,7 +78588,7 @@ function isBuffer(val) { /***/ }), -/* 676 */ +/* 665 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81789,18 +78598,18 @@ function isBuffer(val) { * Module dependencies */ -var extend = __webpack_require__(548); -var unique = __webpack_require__(550); -var toRegex = __webpack_require__(661); +var extend = __webpack_require__(537); +var unique = __webpack_require__(539); +var toRegex = __webpack_require__(650); /** * Local dependencies */ -var compilers = __webpack_require__(677); -var parsers = __webpack_require__(688); -var Extglob = __webpack_require__(691); -var utils = __webpack_require__(690); +var compilers = __webpack_require__(666); +var parsers = __webpack_require__(677); +var Extglob = __webpack_require__(680); +var utils = __webpack_require__(679); var MAX_LENGTH = 1024 * 64; /** @@ -82117,13 +78926,13 @@ module.exports = extglob; /***/ }), -/* 677 */ +/* 666 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(678); +var brackets = __webpack_require__(667); /** * Extglob compilers @@ -82293,7 +79102,7 @@ module.exports = function(extglob) { /***/ }), -/* 678 */ +/* 667 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82303,17 +79112,17 @@ module.exports = function(extglob) { * Local dependencies */ -var compilers = __webpack_require__(679); -var parsers = __webpack_require__(681); +var compilers = __webpack_require__(668); +var parsers = __webpack_require__(670); /** * Module dependencies */ -var debug = __webpack_require__(683)('expand-brackets'); -var extend = __webpack_require__(548); -var Snapdragon = __webpack_require__(579); -var toRegex = __webpack_require__(661); +var debug = __webpack_require__(672)('expand-brackets'); +var extend = __webpack_require__(537); +var Snapdragon = __webpack_require__(568); +var toRegex = __webpack_require__(650); /** * Parses the given POSIX character class `pattern` and returns a @@ -82511,13 +79320,13 @@ module.exports = brackets; /***/ }), -/* 679 */ +/* 668 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var posix = __webpack_require__(680); +var posix = __webpack_require__(669); module.exports = function(brackets) { brackets.compiler @@ -82605,7 +79414,7 @@ module.exports = function(brackets) { /***/ }), -/* 680 */ +/* 669 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82634,14 +79443,14 @@ module.exports = { /***/ }), -/* 681 */ +/* 670 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(682); -var define = __webpack_require__(606); +var utils = __webpack_require__(671); +var define = __webpack_require__(595); /** * Text regex @@ -82860,14 +79669,14 @@ module.exports.TEXT_REGEX = TEXT_REGEX; /***/ }), -/* 682 */ +/* 671 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var toRegex = __webpack_require__(661); -var regexNot = __webpack_require__(547); +var toRegex = __webpack_require__(650); +var regexNot = __webpack_require__(536); var cached; /** @@ -82901,7 +79710,7 @@ exports.createRegex = function(pattern, include) { /***/ }), -/* 683 */ +/* 672 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -82910,14 +79719,14 @@ exports.createRegex = function(pattern, include) { */ if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(684); + module.exports = __webpack_require__(673); } else { - module.exports = __webpack_require__(687); + module.exports = __webpack_require__(676); } /***/ }), -/* 684 */ +/* 673 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -82926,7 +79735,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') { * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(685); +exports = module.exports = __webpack_require__(674); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -83108,7 +79917,7 @@ function localstorage() { /***/ }), -/* 685 */ +/* 674 */ /***/ (function(module, exports, __webpack_require__) { @@ -83124,7 +79933,7 @@ exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; -exports.humanize = __webpack_require__(686); +exports.humanize = __webpack_require__(675); /** * The currently active debug mode names, and names to skip. @@ -83316,7 +80125,7 @@ function coerce(val) { /***/ }), -/* 686 */ +/* 675 */ /***/ (function(module, exports) { /** @@ -83474,7 +80283,7 @@ function plural(ms, n, name) { /***/ }), -/* 687 */ +/* 676 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -83490,7 +80299,7 @@ var util = __webpack_require__(111); * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(685); +exports = module.exports = __webpack_require__(674); exports.init = init; exports.log = log; exports.formatArgs = formatArgs; @@ -83669,7 +80478,7 @@ function createWritableStdioStream (fd) { case 'PIPE': case 'TCP': - var net = __webpack_require__(624); + var net = __webpack_require__(613); stream = new net.Socket({ fd: fd, readable: false, @@ -83728,15 +80537,15 @@ exports.enable(load()); /***/ }), -/* 688 */ +/* 677 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(678); -var define = __webpack_require__(689); -var utils = __webpack_require__(690); +var brackets = __webpack_require__(667); +var define = __webpack_require__(678); +var utils = __webpack_require__(679); /** * Characters to use in text regex (we want to "not" match @@ -83891,7 +80700,7 @@ module.exports = parsers; /***/ }), -/* 689 */ +/* 678 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83904,7 +80713,7 @@ module.exports = parsers; -var isDescriptor = __webpack_require__(571); +var isDescriptor = __webpack_require__(560); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -83929,14 +80738,14 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 690 */ +/* 679 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regex = __webpack_require__(547); -var Cache = __webpack_require__(669); +var regex = __webpack_require__(536); +var Cache = __webpack_require__(658); /** * Utils @@ -84005,7 +80814,7 @@ utils.createRegex = function(str) { /***/ }), -/* 691 */ +/* 680 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84015,16 +80824,16 @@ utils.createRegex = function(str) { * Module dependencies */ -var Snapdragon = __webpack_require__(579); -var define = __webpack_require__(689); -var extend = __webpack_require__(548); +var Snapdragon = __webpack_require__(568); +var define = __webpack_require__(678); +var extend = __webpack_require__(537); /** * Local dependencies */ -var compilers = __webpack_require__(677); -var parsers = __webpack_require__(688); +var compilers = __webpack_require__(666); +var parsers = __webpack_require__(677); /** * Customize Snapdragon parser and renderer @@ -84090,16 +80899,16 @@ module.exports = Extglob; /***/ }), -/* 692 */ +/* 681 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extglob = __webpack_require__(676); -var nanomatch = __webpack_require__(660); -var regexNot = __webpack_require__(547); -var toRegex = __webpack_require__(648); +var extglob = __webpack_require__(665); +var nanomatch = __webpack_require__(649); +var regexNot = __webpack_require__(536); +var toRegex = __webpack_require__(637); var not; /** @@ -84180,14 +80989,14 @@ function textRegex(pattern) { /***/ }), -/* 693 */ +/* 682 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(669))(); +module.exports = new (__webpack_require__(658))(); /***/ }), -/* 694 */ +/* 683 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84200,13 +81009,13 @@ var path = __webpack_require__(4); * Module dependencies */ -var Snapdragon = __webpack_require__(579); -utils.define = __webpack_require__(655); -utils.diff = __webpack_require__(673); -utils.extend = __webpack_require__(656); -utils.pick = __webpack_require__(674); -utils.typeOf = __webpack_require__(695); -utils.unique = __webpack_require__(550); +var Snapdragon = __webpack_require__(568); +utils.define = __webpack_require__(644); +utils.diff = __webpack_require__(662); +utils.extend = __webpack_require__(645); +utils.pick = __webpack_require__(663); +utils.typeOf = __webpack_require__(684); +utils.unique = __webpack_require__(539); /** * Returns true if the platform is windows, or `path.sep` is `\\`. @@ -84503,7 +81312,7 @@ utils.unixify = function(options) { /***/ }), -/* 695 */ +/* 684 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -84638,7 +81447,7 @@ function isBuffer(val) { /***/ }), -/* 696 */ +/* 685 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84657,9 +81466,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(697); -var reader_1 = __webpack_require__(710); -var fs_stream_1 = __webpack_require__(714); +var readdir = __webpack_require__(686); +var reader_1 = __webpack_require__(699); +var fs_stream_1 = __webpack_require__(703); var ReaderAsync = /** @class */ (function (_super) { __extends(ReaderAsync, _super); function ReaderAsync() { @@ -84720,15 +81529,15 @@ exports.default = ReaderAsync; /***/ }), -/* 697 */ +/* 686 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const readdirSync = __webpack_require__(698); -const readdirAsync = __webpack_require__(706); -const readdirStream = __webpack_require__(709); +const readdirSync = __webpack_require__(687); +const readdirAsync = __webpack_require__(695); +const readdirStream = __webpack_require__(698); module.exports = exports = readdirAsyncPath; exports.readdir = exports.readdirAsync = exports.async = readdirAsyncPath; @@ -84812,7 +81621,7 @@ function readdirStreamStat (dir, options) { /***/ }), -/* 698 */ +/* 687 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84820,11 +81629,11 @@ function readdirStreamStat (dir, options) { module.exports = readdirSync; -const DirectoryReader = __webpack_require__(699); +const DirectoryReader = __webpack_require__(688); let syncFacade = { - fs: __webpack_require__(704), - forEach: __webpack_require__(705), + fs: __webpack_require__(693), + forEach: __webpack_require__(694), sync: true }; @@ -84853,7 +81662,7 @@ function readdirSync (dir, options, internalOptions) { /***/ }), -/* 699 */ +/* 688 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84862,9 +81671,9 @@ function readdirSync (dir, options, internalOptions) { const Readable = __webpack_require__(137).Readable; const EventEmitter = __webpack_require__(155).EventEmitter; const path = __webpack_require__(4); -const normalizeOptions = __webpack_require__(700); -const stat = __webpack_require__(702); -const call = __webpack_require__(703); +const normalizeOptions = __webpack_require__(689); +const stat = __webpack_require__(691); +const call = __webpack_require__(692); /** * Asynchronously reads the contents of a directory and streams the results @@ -85240,14 +82049,14 @@ module.exports = DirectoryReader; /***/ }), -/* 700 */ +/* 689 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const globToRegExp = __webpack_require__(701); +const globToRegExp = __webpack_require__(690); module.exports = normalizeOptions; @@ -85424,7 +82233,7 @@ function normalizeOptions (options, internalOptions) { /***/ }), -/* 701 */ +/* 690 */ /***/ (function(module, exports) { module.exports = function (glob, opts) { @@ -85561,13 +82370,13 @@ module.exports = function (glob, opts) { /***/ }), -/* 702 */ +/* 691 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const call = __webpack_require__(703); +const call = __webpack_require__(692); module.exports = stat; @@ -85642,7 +82451,7 @@ function symlinkStat (fs, path, lstats, callback) { /***/ }), -/* 703 */ +/* 692 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85703,14 +82512,14 @@ function callOnce (fn) { /***/ }), -/* 704 */ +/* 693 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(133); -const call = __webpack_require__(703); +const call = __webpack_require__(692); /** * A facade around {@link fs.readdirSync} that allows it to be called @@ -85774,7 +82583,7 @@ exports.lstat = function (path, callback) { /***/ }), -/* 705 */ +/* 694 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85803,7 +82612,7 @@ function syncForEach (array, iterator, done) { /***/ }), -/* 706 */ +/* 695 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85811,12 +82620,12 @@ function syncForEach (array, iterator, done) { module.exports = readdirAsync; -const maybe = __webpack_require__(707); -const DirectoryReader = __webpack_require__(699); +const maybe = __webpack_require__(696); +const DirectoryReader = __webpack_require__(688); let asyncFacade = { fs: __webpack_require__(133), - forEach: __webpack_require__(708), + forEach: __webpack_require__(697), async: true }; @@ -85858,7 +82667,7 @@ function readdirAsync (dir, options, callback, internalOptions) { /***/ }), -/* 707 */ +/* 696 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85885,7 +82694,7 @@ module.exports = function maybe (cb, promise) { /***/ }), -/* 708 */ +/* 697 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85921,7 +82730,7 @@ function asyncForEach (array, iterator, done) { /***/ }), -/* 709 */ +/* 698 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85929,11 +82738,11 @@ function asyncForEach (array, iterator, done) { module.exports = readdirStream; -const DirectoryReader = __webpack_require__(699); +const DirectoryReader = __webpack_require__(688); let streamFacade = { fs: __webpack_require__(133), - forEach: __webpack_require__(708), + forEach: __webpack_require__(697), async: true }; @@ -85953,16 +82762,16 @@ function readdirStream (dir, options, internalOptions) { /***/ }), -/* 710 */ +/* 699 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(4); -var deep_1 = __webpack_require__(711); -var entry_1 = __webpack_require__(713); -var pathUtil = __webpack_require__(712); +var deep_1 = __webpack_require__(700); +var entry_1 = __webpack_require__(702); +var pathUtil = __webpack_require__(701); var Reader = /** @class */ (function () { function Reader(options) { this.options = options; @@ -86028,14 +82837,14 @@ exports.default = Reader; /***/ }), -/* 711 */ +/* 700 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(712); -var patternUtils = __webpack_require__(529); +var pathUtils = __webpack_require__(701); +var patternUtils = __webpack_require__(518); var DeepFilter = /** @class */ (function () { function DeepFilter(options, micromatchOptions) { this.options = options; @@ -86118,7 +82927,7 @@ exports.default = DeepFilter; /***/ }), -/* 712 */ +/* 701 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86149,14 +82958,14 @@ exports.makeAbsolute = makeAbsolute; /***/ }), -/* 713 */ +/* 702 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(712); -var patternUtils = __webpack_require__(529); +var pathUtils = __webpack_require__(701); +var patternUtils = __webpack_require__(518); var EntryFilter = /** @class */ (function () { function EntryFilter(options, micromatchOptions) { this.options = options; @@ -86241,7 +83050,7 @@ exports.default = EntryFilter; /***/ }), -/* 714 */ +/* 703 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86261,8 +83070,8 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(137); -var fsStat = __webpack_require__(715); -var fs_1 = __webpack_require__(719); +var fsStat = __webpack_require__(704); +var fs_1 = __webpack_require__(708); var FileSystemStream = /** @class */ (function (_super) { __extends(FileSystemStream, _super); function FileSystemStream() { @@ -86312,14 +83121,14 @@ exports.default = FileSystemStream; /***/ }), -/* 715 */ +/* 704 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const optionsManager = __webpack_require__(716); -const statProvider = __webpack_require__(718); +const optionsManager = __webpack_require__(705); +const statProvider = __webpack_require__(707); /** * Asynchronous API. */ @@ -86350,13 +83159,13 @@ exports.statSync = statSync; /***/ }), -/* 716 */ +/* 705 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsAdapter = __webpack_require__(717); +const fsAdapter = __webpack_require__(706); function prepare(opts) { const options = Object.assign({ fs: fsAdapter.getFileSystemAdapter(opts ? opts.fs : undefined), @@ -86369,7 +83178,7 @@ exports.prepare = prepare; /***/ }), -/* 717 */ +/* 706 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86392,7 +83201,7 @@ exports.getFileSystemAdapter = getFileSystemAdapter; /***/ }), -/* 718 */ +/* 707 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86444,7 +83253,7 @@ exports.isFollowedSymlink = isFollowedSymlink; /***/ }), -/* 719 */ +/* 708 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86475,7 +83284,7 @@ exports.default = FileSystem; /***/ }), -/* 720 */ +/* 709 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86495,9 +83304,9 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(137); -var readdir = __webpack_require__(697); -var reader_1 = __webpack_require__(710); -var fs_stream_1 = __webpack_require__(714); +var readdir = __webpack_require__(686); +var reader_1 = __webpack_require__(699); +var fs_stream_1 = __webpack_require__(703); var TransformStream = /** @class */ (function (_super) { __extends(TransformStream, _super); function TransformStream(reader) { @@ -86565,7 +83374,7 @@ exports.default = ReaderStream; /***/ }), -/* 721 */ +/* 710 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86584,9 +83393,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(697); -var reader_1 = __webpack_require__(710); -var fs_sync_1 = __webpack_require__(722); +var readdir = __webpack_require__(686); +var reader_1 = __webpack_require__(699); +var fs_sync_1 = __webpack_require__(711); var ReaderSync = /** @class */ (function (_super) { __extends(ReaderSync, _super); function ReaderSync() { @@ -86646,7 +83455,7 @@ exports.default = ReaderSync; /***/ }), -/* 722 */ +/* 711 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86665,8 +83474,8 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var fsStat = __webpack_require__(715); -var fs_1 = __webpack_require__(719); +var fsStat = __webpack_require__(704); +var fs_1 = __webpack_require__(708); var FileSystemSync = /** @class */ (function (_super) { __extends(FileSystemSync, _super); function FileSystemSync() { @@ -86712,7 +83521,7 @@ exports.default = FileSystemSync; /***/ }), -/* 723 */ +/* 712 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86728,7 +83537,7 @@ exports.flatten = flatten; /***/ }), -/* 724 */ +/* 713 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86749,13 +83558,13 @@ exports.merge = merge; /***/ }), -/* 725 */ +/* 714 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const pathType = __webpack_require__(726); +const pathType = __webpack_require__(715); const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; @@ -86821,13 +83630,13 @@ module.exports.sync = (input, opts) => { /***/ }), -/* 726 */ +/* 715 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(133); -const pify = __webpack_require__(727); +const pify = __webpack_require__(716); function type(fn, fn2, fp) { if (typeof fp !== 'string') { @@ -86870,7 +83679,7 @@ exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink'); /***/ }), -/* 727 */ +/* 716 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86961,17 +83770,17 @@ module.exports = (obj, opts) => { /***/ }), -/* 728 */ +/* 717 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(133); const path = __webpack_require__(4); -const fastGlob = __webpack_require__(525); -const gitIgnore = __webpack_require__(729); -const pify = __webpack_require__(730); -const slash = __webpack_require__(731); +const fastGlob = __webpack_require__(514); +const gitIgnore = __webpack_require__(718); +const pify = __webpack_require__(719); +const slash = __webpack_require__(720); const DEFAULT_IGNORE = [ '**/node_modules/**', @@ -87069,7 +83878,7 @@ module.exports.sync = options => { /***/ }), -/* 729 */ +/* 718 */ /***/ (function(module, exports) { // A simple implementation of make-array @@ -87538,7 +84347,7 @@ module.exports = options => new IgnoreBase(options) /***/ }), -/* 730 */ +/* 719 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -87613,7 +84422,7 @@ module.exports = (input, options) => { /***/ }), -/* 731 */ +/* 720 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -87631,7 +84440,7 @@ module.exports = input => { /***/ }), -/* 732 */ +/* 721 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -87641,7 +84450,7 @@ module.exports = input => { * Released under the MIT License. */ -var isExtglob = __webpack_require__(315); +var isExtglob = __webpack_require__(310); var chars = { '{': '}', '(': ')', '[': ']'}; var strictRegex = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/; var relaxedRegex = /\\(.)|(^!|[*?{}()[\]]|\(\?)/; @@ -87685,17 +84494,17 @@ module.exports = function isGlob(str, options) { /***/ }), -/* 733 */ +/* 722 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); const {constants: fsConstants} = __webpack_require__(133); -const pEvent = __webpack_require__(734); -const CpFileError = __webpack_require__(737); -const fs = __webpack_require__(741); -const ProgressEmitter = __webpack_require__(744); +const pEvent = __webpack_require__(723); +const CpFileError = __webpack_require__(726); +const fs = __webpack_require__(730); +const ProgressEmitter = __webpack_require__(733); const cpFileAsync = async (source, destination, options, progressEmitter) => { let readError; @@ -87809,12 +84618,12 @@ module.exports.sync = (source, destination, options) => { /***/ }), -/* 734 */ +/* 723 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pTimeout = __webpack_require__(735); +const pTimeout = __webpack_require__(724); const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator'; @@ -88105,12 +84914,12 @@ module.exports.iterator = (emitter, event, options) => { /***/ }), -/* 735 */ +/* 724 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pFinally = __webpack_require__(736); +const pFinally = __webpack_require__(725); class TimeoutError extends Error { constructor(message) { @@ -88156,7 +84965,7 @@ module.exports.TimeoutError = TimeoutError; /***/ }), -/* 736 */ +/* 725 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88178,12 +84987,12 @@ module.exports = (promise, onFinally) => { /***/ }), -/* 737 */ +/* 726 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(738); +const NestedError = __webpack_require__(727); class CpFileError extends NestedError { constructor(message, nested) { @@ -88197,10 +85006,10 @@ module.exports = CpFileError; /***/ }), -/* 738 */ +/* 727 */ /***/ (function(module, exports, __webpack_require__) { -var inherits = __webpack_require__(739); +var inherits = __webpack_require__(728); var NestedError = function (message, nested) { this.nested = nested; @@ -88251,7 +85060,7 @@ module.exports = NestedError; /***/ }), -/* 739 */ +/* 728 */ /***/ (function(module, exports, __webpack_require__) { try { @@ -88259,12 +85068,12 @@ try { if (typeof util.inherits !== 'function') throw ''; module.exports = util.inherits; } catch (e) { - module.exports = __webpack_require__(740); + module.exports = __webpack_require__(729); } /***/ }), -/* 740 */ +/* 729 */ /***/ (function(module, exports) { if (typeof Object.create === 'function') { @@ -88293,16 +85102,16 @@ if (typeof Object.create === 'function') { /***/ }), -/* 741 */ +/* 730 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const {promisify} = __webpack_require__(111); const fs = __webpack_require__(132); -const makeDir = __webpack_require__(742); -const pEvent = __webpack_require__(734); -const CpFileError = __webpack_require__(737); +const makeDir = __webpack_require__(731); +const pEvent = __webpack_require__(723); +const CpFileError = __webpack_require__(726); const stat = promisify(fs.stat); const lstat = promisify(fs.lstat); @@ -88399,7 +85208,7 @@ exports.copyFileSync = (source, destination, flags) => { /***/ }), -/* 742 */ +/* 731 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88407,7 +85216,7 @@ exports.copyFileSync = (source, destination, flags) => { const fs = __webpack_require__(133); const path = __webpack_require__(4); const {promisify} = __webpack_require__(111); -const semver = __webpack_require__(743); +const semver = __webpack_require__(732); const useNativeRecursiveOption = semver.satisfies(process.version, '>=10.12.0'); @@ -88562,7 +85371,7 @@ module.exports.sync = (input, options) => { /***/ }), -/* 743 */ +/* 732 */ /***/ (function(module, exports) { exports = module.exports = SemVer @@ -90164,7 +86973,7 @@ function coerce (version, options) { /***/ }), -/* 744 */ +/* 733 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90205,7 +87014,7 @@ module.exports = ProgressEmitter; /***/ }), -/* 745 */ +/* 734 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90251,12 +87060,12 @@ exports.default = module.exports; /***/ }), -/* 746 */ +/* 735 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(747); +const NestedError = __webpack_require__(736); class CpyError extends NestedError { constructor(message, nested) { @@ -90270,7 +87079,7 @@ module.exports = CpyError; /***/ }), -/* 747 */ +/* 736 */ /***/ (function(module, exports, __webpack_require__) { var inherits = __webpack_require__(111).inherits; diff --git a/packages/kbn-storybook/index.js b/packages/kbn-storybook/index.js index c7dae20902f1a..77d457f2bb3c0 100644 --- a/packages/kbn-storybook/index.js +++ b/packages/kbn-storybook/index.js @@ -24,7 +24,7 @@ const { first } = require('rxjs/operators'); const storybook = require('@storybook/react/standalone'); const { run } = require('@kbn/dev-utils'); const { generateStorybookEntry } = require('./lib/storybook_entry'); -const { REPO_ROOT, ASSET_DIR, CURRENT_CONFIG } = require('./lib/constants'); +const { ASSET_DIR, CURRENT_CONFIG } = require('./lib/constants'); const { buildDll } = require('./lib/dll'); exports.runStorybookCli = (config) => { @@ -45,14 +45,6 @@ exports.runStorybookCli = (config) => { procRunner, }); - // Build sass and continue when initial build complete - await procRunner.run('watch sass', { - cmd: process.execPath, - args: ['scripts/build_sass', '--watch'], - cwd: REPO_ROOT, - wait: /scss bundles created/, - }); - const subj = new Rx.ReplaySubject(1); generateStorybookEntry({ log, storyGlobs }).subscribe(subj); diff --git a/packages/kbn-storybook/lib/storybook_entry.js b/packages/kbn-storybook/lib/storybook_entry.js index 9eb1b0a458c6a..8b8aa4126ad88 100644 --- a/packages/kbn-storybook/lib/storybook_entry.js +++ b/packages/kbn-storybook/lib/storybook_entry.js @@ -35,7 +35,7 @@ const { REPO_ROOT, STORY_ENTRY_PATH } = require('./constants'); const STORE_ENTRY_DIR = dirname(STORY_ENTRY_PATH); exports.generateStorybookEntry = ({ log, storyGlobs }) => { - const globs = ['built_assets/css/**/*.light.css', ...storyGlobs]; + const globs = [...storyGlobs]; log.info('Storybook globs:\n', globs); const norm = (p) => normalize(relative(STORE_ENTRY_DIR, p)); diff --git a/packages/kbn-storybook/lib/webpack.dll.config.js b/packages/kbn-storybook/lib/webpack.dll.config.js index 661312b9a0581..18dbe3bd049d3 100644 --- a/packages/kbn-storybook/lib/webpack.dll.config.js +++ b/packages/kbn-storybook/lib/webpack.dll.config.js @@ -72,7 +72,6 @@ module.exports = { 'rxjs', 'sinon', 'tinycolor2', - './src/legacy/ui/public/styles/bootstrap/bootstrap_light.less', ], plugins: [ // Produce the DLL and its manifest @@ -118,22 +117,6 @@ module.exports = { }, ], }, - { - test: /\.less$/, - use: [ - { loader: 'style-loader' }, - { loader: 'css-loader', options: { importLoaders: 2 } }, - { - loader: 'postcss-loader', - options: { - config: { - path: require.resolve('@kbn/optimizer/postcss.config.js'), - }, - }, - }, - { loader: 'less-loader' }, - ], - }, { test: /\.(woff|woff2|ttf|eot|svg|ico)(\?|$)/, loader: 'file-loader', diff --git a/packages/kbn-storybook/package.json b/packages/kbn-storybook/package.json index 53ad84da93988..9f12cd1f46c68 100644 --- a/packages/kbn-storybook/package.json +++ b/packages/kbn-storybook/package.json @@ -14,6 +14,7 @@ "@storybook/addon-storyshots": "^5.3.19", "@storybook/react": "^5.3.19", "@storybook/theming": "^5.3.19", + "babel-loader": "^8.0.6", "copy-webpack-plugin": "^6.0.2", "fast-glob": "2.2.7", "glob-watcher": "5.0.3", diff --git a/packages/kbn-storybook/storybook_config/webpack.config.js b/packages/kbn-storybook/storybook_config/webpack.config.js index 7b43d106417b2..d505c4f9a0448 100644 --- a/packages/kbn-storybook/storybook_config/webpack.config.js +++ b/packages/kbn-storybook/storybook_config/webpack.config.js @@ -17,7 +17,7 @@ * under the License. */ -const { parse, resolve } = require('path'); +const { resolve } = require('path'); const webpack = require('webpack'); const webpackMerge = require('webpack-merge'); const { stringifyRequest } = require('loader-utils'); @@ -73,34 +73,13 @@ module.exports = async ({ config: storybookConfig }) => { }, }, }, - { - loader: 'resolve-url-loader', - options: { - // If you don't have arguments (_, __) to the join function, the - // resolve-url-loader fails with a loader misconfiguration error. - // - // eslint-disable-next-line no-unused-vars - join: (_, __) => (uri, base) => { - if (!base || !parse(base).dir.includes('legacy')) { - return null; - } - - // URIs on mixins in src/legacy/public/styles need to be resolved. - if (uri.startsWith('ui/assets')) { - return resolve(REPO_ROOT, 'src/core/server/core_app/', uri.replace('ui/', '')); - } - - return null; - }, - }, - }, { loader: 'sass-loader', options: { prependData(loaderContext) { return `@import ${stringifyRequest( loaderContext, - resolve(REPO_ROOT, 'src/legacy/ui/public/styles/_globals_v7light.scss') + resolve(REPO_ROOT, 'src/core/public/core_app/styles/_globals_v7light.scss') )};\n`; }, sassOptions: { @@ -137,6 +116,9 @@ module.exports = async ({ config: storybookConfig }) => { resolve: { // Tell Webpack about the ts/x extensions extensions: ['.ts', '.tsx', '.scss'], + alias: { + core_app_image_assets: resolve(REPO_ROOT, 'src/core/public/core_app/images'), + }, }, }; diff --git a/packages/kbn-test/src/functional_tests/lib/paths.js b/packages/kbn-test/src/functional_tests/lib/paths.js index 97ba44f4d711e..9ede5a105b08a 100644 --- a/packages/kbn-test/src/functional_tests/lib/paths.js +++ b/packages/kbn-test/src/functional_tests/lib/paths.js @@ -32,4 +32,3 @@ export const KIBANA_FTR_SCRIPT = resolve(KIBANA_ROOT, 'scripts/functional_test_r export const PROJECT_ROOT = resolve(__dirname, '../../../../../../'); export const FUNCTIONAL_CONFIG_PATH = resolve(KIBANA_ROOT, 'test/functional/config'); export const API_CONFIG_PATH = resolve(KIBANA_ROOT, 'test/api_integration/config'); -export const OPTIMIZE_BUNDLE_DIR = resolve(KIBANA_ROOT, 'data/optimize/bundles'); diff --git a/packages/kbn-test/src/index.ts b/packages/kbn-test/src/index.ts index f7321ca713087..50ef521a2d811 100644 --- a/packages/kbn-test/src/index.ts +++ b/packages/kbn-test/src/index.ts @@ -31,7 +31,7 @@ export { runTestsCli, processRunTestsCliOptions, startServersCli, processStartSe export { runTests, startServers } from './functional_tests/tasks'; // @ts-ignore not typed yet -export { OPTIMIZE_BUNDLE_DIR, KIBANA_ROOT } from './functional_tests/lib/paths'; +export { KIBANA_ROOT } from './functional_tests/lib/paths'; // @ts-ignore not typed yet export { esTestConfig, createLegacyEsTestCluster } from './legacy_es'; diff --git a/scripts/build_sass.js b/scripts/build_sass.js deleted file mode 100644 index 4c1c1766761c5..0000000000000 --- a/scripts/build_sass.js +++ /dev/null @@ -1,21 +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. - */ - -require('../src/setup_node_env'); -require('../src/dev/sass/run_build_sass_cli'); diff --git a/src/cli/cluster/cluster_manager.test.ts b/src/cli/cluster/cluster_manager.test.ts index 2ddccae2fada6..a8e139533d397 100644 --- a/src/cli/cluster/cluster_manager.test.ts +++ b/src/cli/cluster/cluster_manager.test.ts @@ -21,20 +21,6 @@ import * as Rx from 'rxjs'; import { mockCluster } from './cluster_manager.test.mocks'; -jest.mock('./run_kbn_optimizer', () => { - // eslint-disable-next-line @typescript-eslint/no-var-requires,no-shadow - const Rx = require('rxjs'); - - return { - runKbnOptimizer: () => - new Rx.BehaviorSubject({ - type: 'compiler success', - durSec: 0, - bundles: [], - }), - }; -}); - jest.mock('readline', () => ({ createInterface: jest.fn(() => ({ on: jest.fn(), @@ -43,18 +29,26 @@ jest.mock('readline', () => ({ })), })); -const mockConfig: any = { - get: (key: string) => { - expect(key).toBe('optimize.enabled'); - return false; - }, -}; +const mockConfig: any = {}; import { sample } from 'lodash'; -import { ClusterManager } from './cluster_manager'; +import { ClusterManager, SomeCliArgs } from './cluster_manager'; import { Worker } from './worker'; +const CLI_ARGS: SomeCliArgs = { + disableOptimizer: true, + open: false, + oss: false, + quiet: false, + repl: false, + runExamples: false, + silent: false, + watch: false, + cache: false, + dist: false, +}; + describe('CLI cluster manager', () => { beforeEach(() => { mockCluster.fork.mockImplementation(() => { @@ -75,17 +69,18 @@ describe('CLI cluster manager', () => { }); test('has two workers', () => { - const manager = new ClusterManager({}, mockConfig); + const manager = new ClusterManager(CLI_ARGS, mockConfig); - expect(manager.workers).toHaveLength(2); - for (const worker of manager.workers) expect(worker).toBeInstanceOf(Worker); + expect(manager.workers).toHaveLength(1); + for (const worker of manager.workers) { + expect(worker).toBeInstanceOf(Worker); + } - expect(manager.optimizer).toBeInstanceOf(Worker); expect(manager.server).toBeInstanceOf(Worker); }); test('delivers broadcast messages to other workers', () => { - const manager = new ClusterManager({}, mockConfig); + const manager = new ClusterManager(CLI_ARGS, mockConfig); for (const worker of manager.workers) { Worker.prototype.start.call(worker); // bypass the debounced start method @@ -110,7 +105,7 @@ describe('CLI cluster manager', () => { test('correctly configures `BasePathProxy`.', async () => { const basePathProxyMock = { start: jest.fn() }; - new ClusterManager({}, mockConfig, basePathProxyMock as any); + new ClusterManager(CLI_ARGS, mockConfig, basePathProxyMock as any); expect(basePathProxyMock.start).toHaveBeenCalledWith({ shouldRedirectFromOldBasePath: expect.any(Function), @@ -125,7 +120,7 @@ describe('CLI cluster manager', () => { beforeEach(async () => { const basePathProxyMock = { start: jest.fn() }; - clusterManager = new ClusterManager({}, mockConfig, basePathProxyMock as any); + clusterManager = new ClusterManager(CLI_ARGS, mockConfig, basePathProxyMock as any); [[{ delayUntil, shouldRedirectFromOldBasePath }]] = basePathProxyMock.start.mock.calls; }); @@ -147,7 +142,6 @@ describe('CLI cluster manager', () => { describe('delayUntil()', () => { test('returns an observable which emits when the server and kbnOptimizer are ready and completes', async () => { clusterManager.serverReady$.next(false); - clusterManager.optimizerReady$.next(false); clusterManager.kbnOptimizerReady$.next(false); const events: Array = []; diff --git a/src/cli/cluster/cluster_manager.ts b/src/cli/cluster/cluster_manager.ts index 5ada95bfeef94..eb7db8dac7cb6 100644 --- a/src/cli/cluster/cluster_manager.ts +++ b/src/cli/cluster/cluster_manager.ts @@ -27,6 +27,7 @@ import * as Rx from 'rxjs'; import { startWith, mapTo, filter, map, take, tap } from 'rxjs/operators'; import { runKbnOptimizer } from './run_kbn_optimizer'; +import { CliArgs } from '../../core/server/config'; import { LegacyConfig } from '../../core/server/legacy'; import { BasePathProxyServer } from '../../core/server/http'; @@ -35,6 +36,20 @@ import { Worker } from './worker'; process.env.kbnWorkerType = 'managr'; +export type SomeCliArgs = Pick< + CliArgs, + | 'quiet' + | 'silent' + | 'repl' + | 'disableOptimizer' + | 'open' + | 'watch' + | 'oss' + | 'runExamples' + | 'cache' + | 'dist' +>; + const firstAllTrue = (...sources: Array>) => Rx.combineLatest(...sources).pipe( filter((values) => values.every((v) => v === true)), @@ -43,7 +58,6 @@ const firstAllTrue = (...sources: Array>) => ); export class ClusterManager { - public optimizer: Worker; public server: Worker; public workers: Worker[]; @@ -56,45 +70,33 @@ export class ClusterManager { // exposed for testing public readonly serverReady$ = new Rx.ReplaySubject(1); // exposed for testing - public readonly optimizerReady$ = new Rx.ReplaySubject(1); - // exposed for testing public readonly kbnOptimizerReady$ = new Rx.ReplaySubject(1); - constructor( - opts: Record, - config: LegacyConfig, - basePathProxy?: BasePathProxyServer - ) { + constructor(opts: SomeCliArgs, config: LegacyConfig, basePathProxy?: BasePathProxyServer) { this.log = new Log(opts.quiet, opts.silent); this.inReplMode = !!opts.repl; this.basePathProxy = basePathProxy; - if (config.get('optimize.enabled') !== false) { - // run @kbn/optimizer and write it's state to kbnOptimizerReady$ + // run @kbn/optimizer and write it's state to kbnOptimizerReady$ + if (opts.disableOptimizer) { + this.kbnOptimizerReady$.next(true); + } else { runKbnOptimizer(opts, config) .pipe( map(({ state }) => state.phase === 'success' || state.phase === 'issue'), tap({ error: (error) => { - this.log.bad('New platform optimizer error', error.stack); + this.log.bad('@kbn/optimizer error', error.stack); process.exit(1); }, }) ) .subscribe(this.kbnOptimizerReady$); - } else { - this.kbnOptimizerReady$.next(true); } const serverArgv = []; - const optimizerArgv = ['--plugins.initialize=false', '--server.autoListen=false']; if (this.basePathProxy) { - optimizerArgv.push( - `--server.basePath=${this.basePathProxy.basePath}`, - '--server.rewriteBasePath=true' - ); - serverArgv.push( `--server.port=${this.basePathProxy.targetPort}`, `--server.basePath=${this.basePathProxy.basePath}`, @@ -103,13 +105,6 @@ export class ClusterManager { } this.workers = [ - (this.optimizer = new Worker({ - type: 'optmzr', - title: 'optimizer', - log: this.log, - argv: optimizerArgv, - watch: false, - })), (this.server = new Worker({ type: 'server', log: this.log, @@ -126,18 +121,6 @@ export class ClusterManager { .pipe(startWith(this.server.listening || this.server.crashed)) .subscribe(this.serverReady$); - // write optimizer status to the optimizerReady$ subject - Rx.merge( - Rx.fromEvent(this.optimizer, 'optimizeStatus'), - Rx.defer(() => { - if (this.optimizer.fork) { - this.optimizer.fork.send({ optimizeReady: '?' }); - } - }) - ) - .pipe(map((msg: any) => msg && !!msg.success)) - .subscribe(this.optimizerReady$); - // broker messages between workers this.workers.forEach((worker) => { worker.on('broadcast', (msg) => { @@ -224,7 +207,7 @@ export class ClusterManager { } setupOpen(openUrl: string) { - firstAllTrue(this.serverReady$, this.kbnOptimizerReady$, this.optimizerReady$) + firstAllTrue(this.serverReady$, this.kbnOptimizerReady$) .toPromise() .then(() => { opn(openUrl); diff --git a/src/cli/cluster/run_kbn_optimizer.ts b/src/cli/cluster/run_kbn_optimizer.ts index f36ce70f65a45..c231437da3943 100644 --- a/src/cli/cluster/run_kbn_optimizer.ts +++ b/src/cli/cluster/run_kbn_optimizer.ts @@ -28,9 +28,12 @@ import { } from '@kbn/dev-utils'; import { runOptimizer, OptimizerConfig, logOptimizerState } from '@kbn/optimizer'; +import { CliArgs } from '../../core/server/config'; import { LegacyConfig } from '../../core/server/legacy'; -export function runKbnOptimizer(opts: Record, config: LegacyConfig) { +type SomeCliArgs = Pick; + +export function runKbnOptimizer(opts: SomeCliArgs, config: LegacyConfig) { const optimizerConfig = OptimizerConfig.create({ repoRoot: REPO_ROOT, watch: !!opts.watch, diff --git a/src/cli/serve/serve.js b/src/cli/serve/serve.js index 972bcdba6b403..3bc710e44f7bc 100644 --- a/src/cli/serve/serve.js +++ b/src/cli/serve/serve.js @@ -77,7 +77,6 @@ function applyConfigOverrides(rawConfig, opts, extraCliOptions) { if (opts.dev) { set('env', 'development'); - set('optimize.watch', true); if (!has('elasticsearch.username')) { set('elasticsearch.username', 'kibana_system'); @@ -194,7 +193,7 @@ export default function (program) { [] ) .option('--plugins ', 'an alias for --plugin-dir', pluginDirCollector) - .option('--optimize', 'Run the legacy plugin optimizer and then stop the server'); + .option('--optimize', 'Deprecated, running the optimizer is no longer required'); if (CAN_REPL) { command.option('--repl', 'Run the server with a REPL prompt and access to the server object'); @@ -220,6 +219,7 @@ export default function (program) { "Don't put a proxy in front of the dev server, which adds a random basePath" ) .option('--no-watch', 'Prevents automatic restarts of the server in --dev mode') + .option('--no-optimizer', 'Disable the kbn/optimizer completely') .option('--no-cache', 'Disable the kbn/optimizer cache') .option('--no-dev-config', 'Prevents loading the kibana.dev.yml file in --dev mode'); } @@ -255,6 +255,7 @@ export default function (program) { // elastic.co links. basePath: opts.runExamples ? false : !!opts.basePath, optimize: !!opts.optimize, + disableOptimizer: !opts.optimizer, oss: !!opts.oss, cache: !!opts.cache, dist: !!opts.dist, diff --git a/src/core/MIGRATION.md b/src/core/MIGRATION.md index 72945597758e2..ea0e8d66d58f2 100644 --- a/src/core/MIGRATION.md +++ b/src/core/MIGRATION.md @@ -1322,7 +1322,6 @@ This table shows where these uiExports have moved to in the New Platform. In mos | `savedObjectTypes` | | Part of SavedObjects, see [#33587](https://github.com/elastic/kibana/issues/33587) | | `search` | | | | `shareContextMenuExtensions` | | | -| `styleSheetPaths` | | | | `taskDefinitions` | | Should be an API on the taskManager plugin. | | `uiCapabilities` | [`core.application.register`](/docs/development/core/public/kibana-plugin-core-public.applicationsetup.register.md) | | | `uiSettingDefaults` | [`core.uiSettings.register`](/docs/development/core/server/kibana-plugin-core-server.uisettingsservicesetup.md) | | diff --git a/src/core/server/core_app/assets/images/bg_bottom_branded.svg b/src/core/public/core_app/images/bg_bottom_branded.svg similarity index 100% rename from src/core/server/core_app/assets/images/bg_bottom_branded.svg rename to src/core/public/core_app/images/bg_bottom_branded.svg diff --git a/src/core/server/core_app/assets/images/bg_bottom_branded_dark.svg b/src/core/public/core_app/images/bg_bottom_branded_dark.svg similarity index 100% rename from src/core/server/core_app/assets/images/bg_bottom_branded_dark.svg rename to src/core/public/core_app/images/bg_bottom_branded_dark.svg diff --git a/src/core/server/core_app/assets/images/bg_top_branded.svg b/src/core/public/core_app/images/bg_top_branded.svg similarity index 100% rename from src/core/server/core_app/assets/images/bg_top_branded.svg rename to src/core/public/core_app/images/bg_top_branded.svg diff --git a/src/core/server/core_app/assets/images/bg_top_branded_dark.svg b/src/core/public/core_app/images/bg_top_branded_dark.svg similarity index 100% rename from src/core/server/core_app/assets/images/bg_top_branded_dark.svg rename to src/core/public/core_app/images/bg_top_branded_dark.svg diff --git a/src/legacy/ui/public/styles/_globals_v7dark.scss b/src/core/public/core_app/styles/_globals_v7dark.scss similarity index 81% rename from src/legacy/ui/public/styles/_globals_v7dark.scss rename to src/core/public/core_app/styles/_globals_v7dark.scss index d5a8535f32718..8ac841aab8469 100644 --- a/src/legacy/ui/public/styles/_globals_v7dark.scss +++ b/src/core/public/core_app/styles/_globals_v7dark.scss @@ -1,7 +1,6 @@ // v7dark global scope // -// prepended to all .scss imports (from JS, when v7dark theme selected) and -// legacy uiExports.styleSheetPaths when any dark theme is selected +// prepended to all .scss imports (from JS, when v7dark theme selected) @import '@elastic/eui/src/themes/eui/eui_colors_dark'; diff --git a/src/legacy/ui/public/styles/_globals_v7light.scss b/src/core/public/core_app/styles/_globals_v7light.scss similarity index 80% rename from src/legacy/ui/public/styles/_globals_v7light.scss rename to src/core/public/core_app/styles/_globals_v7light.scss index 522b346b64900..701bbdfe03662 100644 --- a/src/legacy/ui/public/styles/_globals_v7light.scss +++ b/src/core/public/core_app/styles/_globals_v7light.scss @@ -1,7 +1,6 @@ // v7light global scope // -// prepended to all .scss imports (from JS, when v7light theme selected) and -// legacy uiExports.styleSheetPaths when any dark theme is selected +// prepended to all .scss imports (from JS, when v7light theme selected) @import '@elastic/eui/src/themes/eui/eui_colors_light'; diff --git a/src/legacy/ui/public/styles/_globals_v8dark.scss b/src/core/public/core_app/styles/_globals_v8dark.scss similarity index 100% rename from src/legacy/ui/public/styles/_globals_v8dark.scss rename to src/core/public/core_app/styles/_globals_v8dark.scss diff --git a/src/legacy/ui/public/styles/_globals_v8light.scss b/src/core/public/core_app/styles/_globals_v8light.scss similarity index 100% rename from src/legacy/ui/public/styles/_globals_v8light.scss rename to src/core/public/core_app/styles/_globals_v8light.scss diff --git a/src/legacy/ui/public/styles/_mixins.scss b/src/core/public/core_app/styles/_mixins.scss similarity index 88% rename from src/legacy/ui/public/styles/_mixins.scss rename to src/core/public/core_app/styles/_mixins.scss index e335ef88a01b5..4e5ed5d42f126 100644 --- a/src/legacy/ui/public/styles/_mixins.scss +++ b/src/core/public/core_app/styles/_mixins.scss @@ -89,7 +89,7 @@ z-index: 1; width: 310px; height: 477px; - content: url(lightOrDarkTheme('ui/assets/images/bg_top_branded.svg', 'ui/assets/images/bg_top_branded_dark.svg')); + content: url(lightOrDarkTheme('~core_app_image_assets/bg_top_branded.svg', '~core_app_image_assets/bg_top_branded_dark.svg')); } &::after { @@ -99,7 +99,7 @@ z-index: 1; width: 313px; height: 461px; - content: url(lightOrDarkTheme('ui/assets/images/bg_bottom_branded.svg', 'ui/assets/images/bg_bottom_branded_dark.svg')); + content: url(lightOrDarkTheme('~core_app_image_assets/bg_bottom_branded.svg', '~core_app_image_assets/bg_bottom_branded_dark.svg')); } @keyframes kibanaFullScreenGraphics_FadeIn { diff --git a/src/core/server/bootstrap.ts b/src/core/server/bootstrap.ts index 5dbe5a0b4f955..c0cbe3a39ff54 100644 --- a/src/core/server/bootstrap.ts +++ b/src/core/server/bootstrap.ts @@ -55,6 +55,11 @@ export async function bootstrap({ onRootShutdown('Kibana REPL mode can only be run in development mode.'); } + if (cliArgs.optimize) { + // --optimize is deprecated and does nothing now, avoid starting up and just shutdown + return; + } + const env = Env.createDefault({ configs, cliArgs, @@ -106,12 +111,6 @@ export async function bootstrap({ } catch (err) { await shutdown(err); } - - if (cliArgs.optimize) { - const cliLogger = root.logger.get('cli'); - cliLogger.info('Optimization done.'); - await shutdown(); - } } function onRootShutdown(reason?: any) { diff --git a/src/core/server/config/__mocks__/env.ts b/src/core/server/config/__mocks__/env.ts index 80cfab81fb557..f37ac14e60235 100644 --- a/src/core/server/config/__mocks__/env.ts +++ b/src/core/server/config/__mocks__/env.ts @@ -36,7 +36,9 @@ export function getEnvOptions(options: DeepPartial = {}): EnvOptions watch: false, repl: false, basePath: false, - optimize: false, + disableOptimizer: true, + cache: true, + dist: false, oss: false, runExamples: false, ...(options.cliArgs || {}), diff --git a/src/core/server/config/__snapshots__/env.test.ts.snap b/src/core/server/config/__snapshots__/env.test.ts.snap index 204b8a70aa877..005fa6e680f8b 100644 --- a/src/core/server/config/__snapshots__/env.test.ts.snap +++ b/src/core/server/config/__snapshots__/env.test.ts.snap @@ -5,10 +5,12 @@ Env { "binDir": "/test/kibanaRoot/bin", "cliArgs": Object { "basePath": false, + "cache": true, "dev": true, + "disableOptimizer": true, + "dist": false, "envName": "development", "open": false, - "optimize": false, "oss": false, "quiet": false, "repl": false, @@ -49,10 +51,12 @@ Env { "binDir": "/test/kibanaRoot/bin", "cliArgs": Object { "basePath": false, + "cache": true, "dev": false, + "disableOptimizer": true, + "dist": false, "envName": "production", "open": false, - "optimize": false, "oss": false, "quiet": false, "repl": false, @@ -93,9 +97,11 @@ Env { "binDir": "/test/kibanaRoot/bin", "cliArgs": Object { "basePath": false, + "cache": true, "dev": true, + "disableOptimizer": true, + "dist": false, "open": false, - "optimize": false, "oss": false, "quiet": false, "repl": false, @@ -136,9 +142,11 @@ Env { "binDir": "/test/kibanaRoot/bin", "cliArgs": Object { "basePath": false, + "cache": true, "dev": false, + "disableOptimizer": true, + "dist": false, "open": false, - "optimize": false, "oss": false, "quiet": false, "repl": false, @@ -179,9 +187,11 @@ Env { "binDir": "/test/kibanaRoot/bin", "cliArgs": Object { "basePath": false, + "cache": true, "dev": false, + "disableOptimizer": true, + "dist": false, "open": false, - "optimize": false, "oss": false, "quiet": false, "repl": false, @@ -222,9 +232,11 @@ Env { "binDir": "/some/home/dir/bin", "cliArgs": Object { "basePath": false, + "cache": true, "dev": false, + "disableOptimizer": true, + "dist": false, "open": false, - "optimize": false, "oss": false, "quiet": false, "repl": false, diff --git a/src/core/server/config/deprecation/core_deprecations.ts b/src/core/server/config/deprecation/core_deprecations.ts index 6cc0e5ef138d5..e4e881ab24372 100644 --- a/src/core/server/config/deprecation/core_deprecations.ts +++ b/src/core/server/config/deprecation/core_deprecations.ts @@ -113,18 +113,29 @@ const mapManifestServiceUrlDeprecation: ConfigDeprecation = (settings, fromPath, return settings; }; -export const coreDeprecationProvider: ConfigDeprecationProvider = ({ - unusedFromRoot, - renameFromRoot, -}) => [ +export const coreDeprecationProvider: ConfigDeprecationProvider = ({ unusedFromRoot }) => [ unusedFromRoot('savedObjects.indexCheckTimeout'), unusedFromRoot('server.xsrf.token'), unusedFromRoot('maps.manifestServiceUrl'), - renameFromRoot('optimize.lazy', 'optimize.watch'), - renameFromRoot('optimize.lazyPort', 'optimize.watchPort'), - renameFromRoot('optimize.lazyHost', 'optimize.watchHost'), - renameFromRoot('optimize.lazyPrebuild', 'optimize.watchPrebuild'), - renameFromRoot('optimize.lazyProxyTimeout', 'optimize.watchProxyTimeout'), + unusedFromRoot('optimize.lazy'), + unusedFromRoot('optimize.lazyPort'), + unusedFromRoot('optimize.lazyHost'), + unusedFromRoot('optimize.lazyPrebuild'), + unusedFromRoot('optimize.lazyProxyTimeout'), + unusedFromRoot('optimize.enabled'), + unusedFromRoot('optimize.bundleFilter'), + unusedFromRoot('optimize.bundleDir'), + unusedFromRoot('optimize.viewCaching'), + unusedFromRoot('optimize.watch'), + unusedFromRoot('optimize.watchPort'), + unusedFromRoot('optimize.watchHost'), + unusedFromRoot('optimize.watchPrebuild'), + unusedFromRoot('optimize.watchProxyTimeout'), + unusedFromRoot('optimize.useBundleCache'), + unusedFromRoot('optimize.sourceMaps'), + unusedFromRoot('optimize.workers'), + unusedFromRoot('optimize.profile'), + unusedFromRoot('optimize.validateSyntaxOfNodeModules'), configPathDeprecation, dataPathDeprecation, rewriteBasePathDeprecation, diff --git a/src/core/server/config/env.ts b/src/core/server/config/env.ts index d8068c5b383fa..d8b056996315b 100644 --- a/src/core/server/config/env.ts +++ b/src/core/server/config/env.ts @@ -40,10 +40,14 @@ export interface CliArgs { watch: boolean; repl: boolean; basePath: boolean; - optimize: boolean; open: boolean; oss: boolean; + /** @deprecated use disableOptimizer to know if the @kbn/optimizer is disabled in development */ + optimize?: boolean; runExamples: boolean; + disableOptimizer: boolean; + cache: boolean; + dist: boolean; } export class Env { diff --git a/src/core/server/config/integration_tests/config_deprecation.test.ts b/src/core/server/config/integration_tests/config_deprecation.test.ts index 56385f3b171c9..65f5bbdac5248 100644 --- a/src/core/server/config/integration_tests/config_deprecation.test.ts +++ b/src/core/server/config/integration_tests/config_deprecation.test.ts @@ -24,6 +24,10 @@ import * as kbnTestServer from '../../../../test_utils/kbn_server'; describe('configuration deprecations', () => { let root: ReturnType; + beforeEach(() => { + jest.clearAllMocks(); + }); + afterEach(async () => { if (root) { await root.shutdown(); @@ -36,13 +40,7 @@ describe('configuration deprecations', () => { await root.setup(); const logs = loggingSystemMock.collect(mockLoggingSystem); - const warnings = logs.warn.flatMap((i) => i); - expect(warnings).not.toContain( - '"optimize.lazy" is deprecated and has been replaced by "optimize.watch"' - ); - expect(warnings).not.toContain( - '"optimize.lazyPort" is deprecated and has been replaced by "optimize.watchPort"' - ); + expect(logs.warn.flat()).toMatchInlineSnapshot(`Array []`); }); it('should log deprecation warnings for core deprecations', async () => { @@ -56,12 +54,11 @@ describe('configuration deprecations', () => { await root.setup(); const logs = loggingSystemMock.collect(mockLoggingSystem); - const warnings = logs.warn.flatMap((i) => i); - expect(warnings).toContain( - '"optimize.lazy" is deprecated and has been replaced by "optimize.watch"' - ); - expect(warnings).toContain( - '"optimize.lazyPort" is deprecated and has been replaced by "optimize.watchPort"' - ); + expect(logs.warn.flat()).toMatchInlineSnapshot(` + Array [ + "optimize.lazy is deprecated and is no longer used", + "optimize.lazyPort is deprecated and is no longer used", + ] + `); }); }); diff --git a/src/core/server/core_app/assets/fonts/readme.md b/src/core/server/core_app/assets/fonts/readme.md index 8bb92cc6aa0d9..4042fd98a7a0e 100644 --- a/src/core/server/core_app/assets/fonts/readme.md +++ b/src/core/server/core_app/assets/fonts/readme.md @@ -6,8 +6,3 @@ Kibana packages two fonts: * [Roboto Mono](https://fonts.google.com/specimen/Roboto+Mono) was pulled from the Google Fonts website on January 22, 2019. Licenses for both can be found in the folders below this root. - - -## How fonts are loaded - -Reference the `src/legacy/ui/ui_render/views/chrome.pug` which makes the font-face CSS declarations against the files contained here. References to those those faces are called directly in [EUI](https://github.com/elastic/eui) primarily through the [typography variables](https://github.com/elastic/eui/blob/master/src/global_styling/variables/_typography.scss). \ No newline at end of file diff --git a/src/core/server/core_app/assets/images/kibana.svg b/src/core/server/core_app/assets/images/kibana.svg deleted file mode 100644 index 6ac1fed080261..0000000000000 --- a/src/core/server/core_app/assets/images/kibana.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/src/core/server/core_app/assets/legacy_dark_theme.css b/src/core/server/core_app/assets/legacy_dark_theme.css new file mode 100644 index 0000000000000..f5891b361bc43 --- /dev/null +++ b/src/core/server/core_app/assets/legacy_dark_theme.css @@ -0,0 +1,4419 @@ +/*! + * Bootstrap v3.3.6 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +/* @notice + * This product bundles bootstrap@3.3.6 which is available under a + * "MIT" license. + * + * The MIT License (MIT) + * + * Copyright (c) 2011-2015 Twitter, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +.container { + margin-right: auto; + margin-left: auto; + padding-left: 15px; + padding-right: 15px; +} +@media (min-width: 768px) { + .container { + width: 750px; + } +} +@media (min-width: 992px) { + .container { + width: 970px; + } +} +@media (min-width: 1200px) { + .container { + width: 1170px; + } +} +.container-fluid { + margin-right: auto; + margin-left: auto; + padding-left: 15px; + padding-right: 15px; +} +.row { + margin-left: -15px; + margin-right: -15px; +} +.col-xs-1, +.col-sm-1, +.col-md-1, +.col-lg-1, +.col-xs-2, +.col-sm-2, +.col-md-2, +.col-lg-2, +.col-xs-3, +.col-sm-3, +.col-md-3, +.col-lg-3, +.col-xs-4, +.col-sm-4, +.col-md-4, +.col-lg-4, +.col-xs-5, +.col-sm-5, +.col-md-5, +.col-lg-5, +.col-xs-6, +.col-sm-6, +.col-md-6, +.col-lg-6, +.col-xs-7, +.col-sm-7, +.col-md-7, +.col-lg-7, +.col-xs-8, +.col-sm-8, +.col-md-8, +.col-lg-8, +.col-xs-9, +.col-sm-9, +.col-md-9, +.col-lg-9, +.col-xs-10, +.col-sm-10, +.col-md-10, +.col-lg-10, +.col-xs-11, +.col-sm-11, +.col-md-11, +.col-lg-11, +.col-xs-12, +.col-sm-12, +.col-md-12, +.col-lg-12 { + position: relative; + min-height: 1px; + padding-left: 15px; + padding-right: 15px; +} +.col-xs-1, +.col-xs-2, +.col-xs-3, +.col-xs-4, +.col-xs-5, +.col-xs-6, +.col-xs-7, +.col-xs-8, +.col-xs-9, +.col-xs-10, +.col-xs-11, +.col-xs-12 { + float: left; +} +.col-xs-12 { + width: 100%; +} +.col-xs-11 { + width: 91.66666667%; +} +.col-xs-10 { + width: 83.33333333%; +} +.col-xs-9 { + width: 75%; +} +.col-xs-8 { + width: 66.66666667%; +} +.col-xs-7 { + width: 58.33333333%; +} +.col-xs-6 { + width: 50%; +} +.col-xs-5 { + width: 41.66666667%; +} +.col-xs-4 { + width: 33.33333333%; +} +.col-xs-3 { + width: 25%; +} +.col-xs-2 { + width: 16.66666667%; +} +.col-xs-1 { + width: 8.33333333%; +} +.col-xs-pull-12 { + right: 100%; +} +.col-xs-pull-11 { + right: 91.66666667%; +} +.col-xs-pull-10 { + right: 83.33333333%; +} +.col-xs-pull-9 { + right: 75%; +} +.col-xs-pull-8 { + right: 66.66666667%; +} +.col-xs-pull-7 { + right: 58.33333333%; +} +.col-xs-pull-6 { + right: 50%; +} +.col-xs-pull-5 { + right: 41.66666667%; +} +.col-xs-pull-4 { + right: 33.33333333%; +} +.col-xs-pull-3 { + right: 25%; +} +.col-xs-pull-2 { + right: 16.66666667%; +} +.col-xs-pull-1 { + right: 8.33333333%; +} +.col-xs-pull-0 { + right: auto; +} +.col-xs-push-12 { + left: 100%; +} +.col-xs-push-11 { + left: 91.66666667%; +} +.col-xs-push-10 { + left: 83.33333333%; +} +.col-xs-push-9 { + left: 75%; +} +.col-xs-push-8 { + left: 66.66666667%; +} +.col-xs-push-7 { + left: 58.33333333%; +} +.col-xs-push-6 { + left: 50%; +} +.col-xs-push-5 { + left: 41.66666667%; +} +.col-xs-push-4 { + left: 33.33333333%; +} +.col-xs-push-3 { + left: 25%; +} +.col-xs-push-2 { + left: 16.66666667%; +} +.col-xs-push-1 { + left: 8.33333333%; +} +.col-xs-push-0 { + left: auto; +} +.col-xs-offset-12 { + margin-left: 100%; +} +.col-xs-offset-11 { + margin-left: 91.66666667%; +} +.col-xs-offset-10 { + margin-left: 83.33333333%; +} +.col-xs-offset-9 { + margin-left: 75%; +} +.col-xs-offset-8 { + margin-left: 66.66666667%; +} +.col-xs-offset-7 { + margin-left: 58.33333333%; +} +.col-xs-offset-6 { + margin-left: 50%; +} +.col-xs-offset-5 { + margin-left: 41.66666667%; +} +.col-xs-offset-4 { + margin-left: 33.33333333%; +} +.col-xs-offset-3 { + margin-left: 25%; +} +.col-xs-offset-2 { + margin-left: 16.66666667%; +} +.col-xs-offset-1 { + margin-left: 8.33333333%; +} +.col-xs-offset-0 { + margin-left: 0%; +} +@media (min-width: 768px) { + .col-sm-1, + .col-sm-2, + .col-sm-3, + .col-sm-4, + .col-sm-5, + .col-sm-6, + .col-sm-7, + .col-sm-8, + .col-sm-9, + .col-sm-10, + .col-sm-11, + .col-sm-12 { + float: left; + } + .col-sm-12 { + width: 100%; + } + .col-sm-11 { + width: 91.66666667%; + } + .col-sm-10 { + width: 83.33333333%; + } + .col-sm-9 { + width: 75%; + } + .col-sm-8 { + width: 66.66666667%; + } + .col-sm-7 { + width: 58.33333333%; + } + .col-sm-6 { + width: 50%; + } + .col-sm-5 { + width: 41.66666667%; + } + .col-sm-4 { + width: 33.33333333%; + } + .col-sm-3 { + width: 25%; + } + .col-sm-2 { + width: 16.66666667%; + } + .col-sm-1 { + width: 8.33333333%; + } + .col-sm-pull-12 { + right: 100%; + } + .col-sm-pull-11 { + right: 91.66666667%; + } + .col-sm-pull-10 { + right: 83.33333333%; + } + .col-sm-pull-9 { + right: 75%; + } + .col-sm-pull-8 { + right: 66.66666667%; + } + .col-sm-pull-7 { + right: 58.33333333%; + } + .col-sm-pull-6 { + right: 50%; + } + .col-sm-pull-5 { + right: 41.66666667%; + } + .col-sm-pull-4 { + right: 33.33333333%; + } + .col-sm-pull-3 { + right: 25%; + } + .col-sm-pull-2 { + right: 16.66666667%; + } + .col-sm-pull-1 { + right: 8.33333333%; + } + .col-sm-pull-0 { + right: auto; + } + .col-sm-push-12 { + left: 100%; + } + .col-sm-push-11 { + left: 91.66666667%; + } + .col-sm-push-10 { + left: 83.33333333%; + } + .col-sm-push-9 { + left: 75%; + } + .col-sm-push-8 { + left: 66.66666667%; + } + .col-sm-push-7 { + left: 58.33333333%; + } + .col-sm-push-6 { + left: 50%; + } + .col-sm-push-5 { + left: 41.66666667%; + } + .col-sm-push-4 { + left: 33.33333333%; + } + .col-sm-push-3 { + left: 25%; + } + .col-sm-push-2 { + left: 16.66666667%; + } + .col-sm-push-1 { + left: 8.33333333%; + } + .col-sm-push-0 { + left: auto; + } + .col-sm-offset-12 { + margin-left: 100%; + } + .col-sm-offset-11 { + margin-left: 91.66666667%; + } + .col-sm-offset-10 { + margin-left: 83.33333333%; + } + .col-sm-offset-9 { + margin-left: 75%; + } + .col-sm-offset-8 { + margin-left: 66.66666667%; + } + .col-sm-offset-7 { + margin-left: 58.33333333%; + } + .col-sm-offset-6 { + margin-left: 50%; + } + .col-sm-offset-5 { + margin-left: 41.66666667%; + } + .col-sm-offset-4 { + margin-left: 33.33333333%; + } + .col-sm-offset-3 { + margin-left: 25%; + } + .col-sm-offset-2 { + margin-left: 16.66666667%; + } + .col-sm-offset-1 { + margin-left: 8.33333333%; + } + .col-sm-offset-0 { + margin-left: 0%; + } +} +@media (min-width: 992px) { + .col-md-1, + .col-md-2, + .col-md-3, + .col-md-4, + .col-md-5, + .col-md-6, + .col-md-7, + .col-md-8, + .col-md-9, + .col-md-10, + .col-md-11, + .col-md-12 { + float: left; + } + .col-md-12 { + width: 100%; + } + .col-md-11 { + width: 91.66666667%; + } + .col-md-10 { + width: 83.33333333%; + } + .col-md-9 { + width: 75%; + } + .col-md-8 { + width: 66.66666667%; + } + .col-md-7 { + width: 58.33333333%; + } + .col-md-6 { + width: 50%; + } + .col-md-5 { + width: 41.66666667%; + } + .col-md-4 { + width: 33.33333333%; + } + .col-md-3 { + width: 25%; + } + .col-md-2 { + width: 16.66666667%; + } + .col-md-1 { + width: 8.33333333%; + } + .col-md-pull-12 { + right: 100%; + } + .col-md-pull-11 { + right: 91.66666667%; + } + .col-md-pull-10 { + right: 83.33333333%; + } + .col-md-pull-9 { + right: 75%; + } + .col-md-pull-8 { + right: 66.66666667%; + } + .col-md-pull-7 { + right: 58.33333333%; + } + .col-md-pull-6 { + right: 50%; + } + .col-md-pull-5 { + right: 41.66666667%; + } + .col-md-pull-4 { + right: 33.33333333%; + } + .col-md-pull-3 { + right: 25%; + } + .col-md-pull-2 { + right: 16.66666667%; + } + .col-md-pull-1 { + right: 8.33333333%; + } + .col-md-pull-0 { + right: auto; + } + .col-md-push-12 { + left: 100%; + } + .col-md-push-11 { + left: 91.66666667%; + } + .col-md-push-10 { + left: 83.33333333%; + } + .col-md-push-9 { + left: 75%; + } + .col-md-push-8 { + left: 66.66666667%; + } + .col-md-push-7 { + left: 58.33333333%; + } + .col-md-push-6 { + left: 50%; + } + .col-md-push-5 { + left: 41.66666667%; + } + .col-md-push-4 { + left: 33.33333333%; + } + .col-md-push-3 { + left: 25%; + } + .col-md-push-2 { + left: 16.66666667%; + } + .col-md-push-1 { + left: 8.33333333%; + } + .col-md-push-0 { + left: auto; + } + .col-md-offset-12 { + margin-left: 100%; + } + .col-md-offset-11 { + margin-left: 91.66666667%; + } + .col-md-offset-10 { + margin-left: 83.33333333%; + } + .col-md-offset-9 { + margin-left: 75%; + } + .col-md-offset-8 { + margin-left: 66.66666667%; + } + .col-md-offset-7 { + margin-left: 58.33333333%; + } + .col-md-offset-6 { + margin-left: 50%; + } + .col-md-offset-5 { + margin-left: 41.66666667%; + } + .col-md-offset-4 { + margin-left: 33.33333333%; + } + .col-md-offset-3 { + margin-left: 25%; + } + .col-md-offset-2 { + margin-left: 16.66666667%; + } + .col-md-offset-1 { + margin-left: 8.33333333%; + } + .col-md-offset-0 { + margin-left: 0%; + } +} +@media (min-width: 1200px) { + .col-lg-1, + .col-lg-2, + .col-lg-3, + .col-lg-4, + .col-lg-5, + .col-lg-6, + .col-lg-7, + .col-lg-8, + .col-lg-9, + .col-lg-10, + .col-lg-11, + .col-lg-12 { + float: left; + } + .col-lg-12 { + width: 100%; + } + .col-lg-11 { + width: 91.66666667%; + } + .col-lg-10 { + width: 83.33333333%; + } + .col-lg-9 { + width: 75%; + } + .col-lg-8 { + width: 66.66666667%; + } + .col-lg-7 { + width: 58.33333333%; + } + .col-lg-6 { + width: 50%; + } + .col-lg-5 { + width: 41.66666667%; + } + .col-lg-4 { + width: 33.33333333%; + } + .col-lg-3 { + width: 25%; + } + .col-lg-2 { + width: 16.66666667%; + } + .col-lg-1 { + width: 8.33333333%; + } + .col-lg-pull-12 { + right: 100%; + } + .col-lg-pull-11 { + right: 91.66666667%; + } + .col-lg-pull-10 { + right: 83.33333333%; + } + .col-lg-pull-9 { + right: 75%; + } + .col-lg-pull-8 { + right: 66.66666667%; + } + .col-lg-pull-7 { + right: 58.33333333%; + } + .col-lg-pull-6 { + right: 50%; + } + .col-lg-pull-5 { + right: 41.66666667%; + } + .col-lg-pull-4 { + right: 33.33333333%; + } + .col-lg-pull-3 { + right: 25%; + } + .col-lg-pull-2 { + right: 16.66666667%; + } + .col-lg-pull-1 { + right: 8.33333333%; + } + .col-lg-pull-0 { + right: auto; + } + .col-lg-push-12 { + left: 100%; + } + .col-lg-push-11 { + left: 91.66666667%; + } + .col-lg-push-10 { + left: 83.33333333%; + } + .col-lg-push-9 { + left: 75%; + } + .col-lg-push-8 { + left: 66.66666667%; + } + .col-lg-push-7 { + left: 58.33333333%; + } + .col-lg-push-6 { + left: 50%; + } + .col-lg-push-5 { + left: 41.66666667%; + } + .col-lg-push-4 { + left: 33.33333333%; + } + .col-lg-push-3 { + left: 25%; + } + .col-lg-push-2 { + left: 16.66666667%; + } + .col-lg-push-1 { + left: 8.33333333%; + } + .col-lg-push-0 { + left: auto; + } + .col-lg-offset-12 { + margin-left: 100%; + } + .col-lg-offset-11 { + margin-left: 91.66666667%; + } + .col-lg-offset-10 { + margin-left: 83.33333333%; + } + .col-lg-offset-9 { + margin-left: 75%; + } + .col-lg-offset-8 { + margin-left: 66.66666667%; + } + .col-lg-offset-7 { + margin-left: 58.33333333%; + } + .col-lg-offset-6 { + margin-left: 50%; + } + .col-lg-offset-5 { + margin-left: 41.66666667%; + } + .col-lg-offset-4 { + margin-left: 33.33333333%; + } + .col-lg-offset-3 { + margin-left: 25%; + } + .col-lg-offset-2 { + margin-left: 16.66666667%; + } + .col-lg-offset-1 { + margin-left: 8.33333333%; + } + .col-lg-offset-0 { + margin-left: 0%; + } +} +.table { + width: 100%; + max-width: 100%; + margin-bottom: 20px; + font-size: 14px; +} +.table thead { + font-size: 12px; +} +.table > thead > tr > th, +.table > tbody > tr > th, +.table > tfoot > tr > th, +.table > thead > tr > td, +.table > tbody > tr > td, +.table > tfoot > tr > td { + padding: 8px; + line-height: 1.42857143; + vertical-align: top; + border-top: 1px solid #343741; +} +.table > thead > tr > th { + vertical-align: bottom; + border-bottom: 1px solid #343741; +} +.table > caption + thead > tr:first-child > th, +.table > colgroup + thead > tr:first-child > th, +.table > thead:first-child > tr:first-child > th, +.table > caption + thead > tr:first-child > td, +.table > colgroup + thead > tr:first-child > td, +.table > thead:first-child > tr:first-child > td { + border-top: 0; +} +.table > tbody + tbody { + border-top: 2px solid #343741; +} +.table .table { + background-color: #1D1E24; +} +.table-condensed > thead > tr > th, +.table-condensed > tbody > tr > th, +.table-condensed > tfoot > tr > th, +.table-condensed > thead > tr > td, +.table-condensed > tbody > tr > td, +.table-condensed > tfoot > tr > td { + padding: 5px; + font-size: 12px; +} +.table-bordered { + border: 1px solid #343741; +} +.table-bordered > thead > tr > th, +.table-bordered > tbody > tr > th, +.table-bordered > tfoot > tr > th, +.table-bordered > thead > tr > td, +.table-bordered > tbody > tr > td, +.table-bordered > tfoot > tr > td { + border: 1px solid #343741; +} +.table-bordered > thead > tr > th, +.table-bordered > thead > tr > td { + border-bottom-width: 2px; +} +.table-striped > tbody > tr:nth-of-type(odd) { + background-color: #343741; +} +.table-hover > tbody > tr:hover { + background-color: #343741; +} +table col[class*="col-"] { + position: static; + float: none; + display: table-column; +} +table td[class*="col-"], +table th[class*="col-"] { + position: static; + float: none; + display: table-cell; +} +.table > thead > tr > td.active, +.table > tbody > tr > td.active, +.table > tfoot > tr > td.active, +.table > thead > tr > th.active, +.table > tbody > tr > th.active, +.table > tfoot > tr > th.active, +.table > thead > tr.active > td, +.table > tbody > tr.active > td, +.table > tfoot > tr.active > td, +.table > thead > tr.active > th, +.table > tbody > tr.active > th, +.table > tfoot > tr.active > th { + background-color: #343741; +} +.table-hover > tbody > tr > td.active:hover, +.table-hover > tbody > tr > th.active:hover, +.table-hover > tbody > tr.active:hover > td, +.table-hover > tbody > tr:hover > .active, +.table-hover > tbody > tr.active:hover > th { + background-color: #292b33; +} +.table > thead > tr > td.success, +.table > tbody > tr > td.success, +.table > tfoot > tr > td.success, +.table > thead > tr > th.success, +.table > tbody > tr > th.success, +.table > tfoot > tr > th.success, +.table > thead > tr.success > td, +.table > tbody > tr.success > td, +.table > tfoot > tr.success > td, +.table > thead > tr.success > th, +.table > tbody > tr.success > th, +.table > tfoot > tr.success > th { + background-color: #7DE2D1; +} +.table-hover > tbody > tr > td.success:hover, +.table-hover > tbody > tr > th.success:hover, +.table-hover > tbody > tr.success:hover > td, +.table-hover > tbody > tr:hover > .success, +.table-hover > tbody > tr.success:hover > th { + background-color: #68ddca; +} +.table > thead > tr > td.info, +.table > tbody > tr > td.info, +.table > tfoot > tr > td.info, +.table > thead > tr > th.info, +.table > tbody > tr > th.info, +.table > tfoot > tr > th.info, +.table > thead > tr.info > td, +.table > tbody > tr.info > td, +.table > tfoot > tr.info > td, +.table > thead > tr.info > th, +.table > tbody > tr.info > th, +.table > tfoot > tr.info > th { + background-color: #1BA9F5; +} +.table-hover > tbody > tr > td.info:hover, +.table-hover > tbody > tr > th.info:hover, +.table-hover > tbody > tr.info:hover > td, +.table-hover > tbody > tr:hover > .info, +.table-hover > tbody > tr.info:hover > th { + background-color: #0a9dec; +} +.table > thead > tr > td.warning, +.table > tbody > tr > td.warning, +.table > tfoot > tr > td.warning, +.table > thead > tr > th.warning, +.table > tbody > tr > th.warning, +.table > tfoot > tr > th.warning, +.table > thead > tr.warning > td, +.table > tbody > tr.warning > td, +.table > tfoot > tr.warning > td, +.table > thead > tr.warning > th, +.table > tbody > tr.warning > th, +.table > tfoot > tr.warning > th { + background-color: #FF977A; +} +.table-hover > tbody > tr > td.warning:hover, +.table-hover > tbody > tr > th.warning:hover, +.table-hover > tbody > tr.warning:hover > td, +.table-hover > tbody > tr:hover > .warning, +.table-hover > tbody > tr.warning:hover > th { + background-color: #ff8361; +} +.table > thead > tr > td.danger, +.table > tbody > tr > td.danger, +.table > tfoot > tr > td.danger, +.table > thead > tr > th.danger, +.table > tbody > tr > th.danger, +.table > tfoot > tr > th.danger, +.table > thead > tr.danger > td, +.table > tbody > tr.danger > td, +.table > tfoot > tr.danger > td, +.table > thead > tr.danger > th, +.table > tbody > tr.danger > th, +.table > tfoot > tr.danger > th { + background-color: #FF6666; +} +.table-hover > tbody > tr > td.danger:hover, +.table-hover > tbody > tr > th.danger:hover, +.table-hover > tbody > tr.danger:hover > td, +.table-hover > tbody > tr:hover > .danger, +.table-hover > tbody > tr.danger:hover > th { + background-color: #ff4c4c; +} +.table-responsive { + overflow-x: auto; + min-height: 0.01%; +} +@media screen and (max-width: 767px) { + .table-responsive { + width: 100%; + margin-bottom: 15px; + overflow-y: hidden; + -ms-overflow-style: -ms-autohiding-scrollbar; + border: 1px solid #343741; + } + .table-responsive > .table { + margin-bottom: 0; + } + .table-responsive > .table > thead > tr > th, + .table-responsive > .table > tbody > tr > th, + .table-responsive > .table > tfoot > tr > th, + .table-responsive > .table > thead > tr > td, + .table-responsive > .table > tbody > tr > td, + .table-responsive > .table > tfoot > tr > td { + white-space: nowrap; + } + .table-responsive > .table-bordered { + border: 0; + } + .table-responsive > .table-bordered > thead > tr > th:first-child, + .table-responsive > .table-bordered > tbody > tr > th:first-child, + .table-responsive > .table-bordered > tfoot > tr > th:first-child, + .table-responsive > .table-bordered > thead > tr > td:first-child, + .table-responsive > .table-bordered > tbody > tr > td:first-child, + .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; + } + .table-responsive > .table-bordered > thead > tr > th:last-child, + .table-responsive > .table-bordered > tbody > tr > th:last-child, + .table-responsive > .table-bordered > tfoot > tr > th:last-child, + .table-responsive > .table-bordered > thead > tr > td:last-child, + .table-responsive > .table-bordered > tbody > tr > td:last-child, + .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; + } + .table-responsive > .table-bordered > tbody > tr:last-child > th, + .table-responsive > .table-bordered > tfoot > tr:last-child > th, + .table-responsive > .table-bordered > tbody > tr:last-child > td, + .table-responsive > .table-bordered > tfoot > tr:last-child > td { + border-bottom: 0; + } +} +.form-control { + display: block; + width: 100%; + height: 32px; + padding: 5px 15px; + font-size: 14px; + line-height: 1.42857143; + color: #F5F7FA; + background-color: #1a1a20; + background-image: none; + border: 1px solid #343741; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; +} +.form-control:focus { + border-color: #1BA9F5; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(27, 169, 245, 0.6); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(27, 169, 245, 0.6); +} +.form-control::-moz-placeholder { + color: #535966; + opacity: 1; +} +.form-control:-ms-input-placeholder { + color: #535966; +} +.form-control::-webkit-input-placeholder { + color: #535966; +} +.form-control::-ms-expand { + border: 0; + background-color: transparent; +} +.form-control[disabled], +.form-control[readonly], +fieldset[disabled] .form-control { + background-color: #343741; + opacity: 1; +} +.form-control[disabled], +fieldset[disabled] .form-control { + cursor: not-allowed; +} +textarea.form-control { + height: auto; +} +.form-group:not(:empty) { + margin-bottom: 15px; +} +.radio, +.checkbox { + position: relative; + display: block; + margin-top: 10px; + margin-bottom: 10px; +} +.radio label, +.checkbox label { + min-height: 20px; + padding-left: 20px; + margin-bottom: 0; + font-weight: normal; + cursor: pointer; +} +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + position: absolute; + margin-left: -20px; + margin-top: 4px \9; +} +.radio + .radio, +.checkbox + .checkbox { + margin-top: -5px; +} +.radio-inline, +.checkbox-inline { + position: relative; + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + vertical-align: middle; + font-weight: normal; + cursor: pointer; +} +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; +} +.radio-inline.disabled, +.checkbox-inline.disabled, +fieldset[disabled] .radio-inline, +fieldset[disabled] .checkbox-inline { + cursor: not-allowed; +} +.radio.disabled label, +.checkbox.disabled label, +fieldset[disabled] .radio label, +fieldset[disabled] .checkbox label { + cursor: not-allowed; +} +.form-control-static { + padding-top: 6px; + padding-bottom: 6px; + margin-bottom: 0; + min-height: 34px; +} +.form-control-static.input-lg, +.form-control-static.input-sm { + padding-left: 0; + padding-right: 0; +} +.input-sm { + height: 32px; + padding: 6px 9px; + font-size: 12px; + line-height: 1.5; + border-radius: 4px; +} +select.input-sm { + height: 32px; + line-height: 32px; +} +textarea.input-sm, +select[multiple].input-sm { + height: auto; +} +.form-group-sm .form-control { + height: 32px; + padding: 6px 9px; + font-size: 12px; + line-height: 1.5; + border-radius: 4px; +} +.form-group-sm select.form-control { + height: 32px; + line-height: 32px; +} +.form-group-sm textarea.form-control, +.form-group-sm select[multiple].form-control { + height: auto; +} +.form-group-sm .form-control-static { + height: 32px; + min-height: 32px; + padding: 7px 9px; + font-size: 12px; + line-height: 1.5; +} +.input-lg { + height: 62px; + padding: 18px 27px; + font-size: 18px; + line-height: 1.3333333; + border-radius: 4px; +} +select.input-lg { + height: 62px; + line-height: 62px; +} +textarea.input-lg, +select[multiple].input-lg { + height: auto; +} +.form-group-lg .form-control { + height: 62px; + padding: 18px 27px; + font-size: 18px; + line-height: 1.3333333; + border-radius: 4px; +} +.form-group-lg select.form-control { + height: 62px; + line-height: 62px; +} +.form-group-lg textarea.form-control, +.form-group-lg select[multiple].form-control { + height: auto; +} +.form-group-lg .form-control-static { + height: 62px; + min-height: 38px; + padding: 19px 27px; + font-size: 18px; + line-height: 1.3333333; +} +.has-feedback { + position: relative; +} +.has-feedback .form-control { + padding-right: 40px; +} +.form-control-feedback { + position: absolute; + top: 0; + right: 0; + z-index: 2; + display: block; + width: 32px; + height: 32px; + line-height: 32px; + text-align: center; + pointer-events: none; +} +.input-lg + .form-control-feedback, +.input-group-lg + .form-control-feedback, +.form-group-lg .form-control + .form-control-feedback { + width: 62px; + height: 62px; + line-height: 62px; +} +.input-sm + .form-control-feedback, +.input-group-sm + .form-control-feedback, +.form-group-sm .form-control + .form-control-feedback { + width: 32px; + height: 32px; + line-height: 32px; +} +.has-success .help-block, +.has-success .control-label, +.has-success .radio, +.has-success .checkbox, +.has-success .radio-inline, +.has-success .checkbox-inline, +.has-success.radio label, +.has-success.checkbox label, +.has-success.radio-inline label, +.has-success.checkbox-inline label { + color: #1D1E24; +} +.has-success .form-control { + border-color: #1D1E24; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-success .form-control:focus { + border-color: #060608; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #4b4d5c; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #4b4d5c; +} +.has-success .input-group-addon { + color: #1D1E24; + border-color: #1D1E24; + background-color: #7DE2D1; +} +.has-success .form-control-feedback { + color: #1D1E24; +} +.has-warning .help-block, +.has-warning .control-label, +.has-warning .radio, +.has-warning .checkbox, +.has-warning .radio-inline, +.has-warning .checkbox-inline, +.has-warning.radio label, +.has-warning.checkbox label, +.has-warning.radio-inline label, +.has-warning.checkbox-inline label { + color: #1D1E24; +} +.has-warning .form-control { + border-color: #1D1E24; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-warning .form-control:focus { + border-color: #060608; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #4b4d5c; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #4b4d5c; +} +.has-warning .input-group-addon { + color: #1D1E24; + border-color: #1D1E24; + background-color: #FF977A; +} +.has-warning .form-control-feedback { + color: #1D1E24; +} +.has-error .help-block, +.has-error .control-label, +.has-error .radio, +.has-error .checkbox, +.has-error .radio-inline, +.has-error .checkbox-inline, +.has-error.radio label, +.has-error.checkbox label, +.has-error.radio-inline label, +.has-error.checkbox-inline label { + color: #1D1E24; +} +.has-error .form-control { + border-color: #1D1E24; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-error .form-control:focus { + border-color: #060608; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #4b4d5c; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #4b4d5c; +} +.has-error .input-group-addon { + color: #1D1E24; + border-color: #1D1E24; + background-color: #FF6666; +} +.has-error .form-control-feedback { + color: #1D1E24; +} +.has-feedback label ~ .form-control-feedback { + top: 25px; +} +.has-feedback label.sr-only ~ .form-control-feedback { + top: 0; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 10px; + color: #ffffff; +} +@media (min-width: 768px) { + .form-inline .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .form-inline .form-control-static { + display: inline-block; + } + .form-inline .input-group { + display: inline-table; + vertical-align: middle; + } + .form-inline .input-group .input-group-addon, + .form-inline .input-group .form-control { + width: auto; + } + .form-inline .input-group > .form-control { + width: 100%; + } + .form-inline .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio, + .form-inline .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio label, + .form-inline .checkbox label { + padding-left: 0; + } + .form-inline .radio input[type="radio"], + .form-inline .checkbox input[type="checkbox"] { + position: relative; + margin-left: 0; + } + .form-inline .has-feedback .form-control-feedback { + top: 0; + } +} +.form-horizontal .radio, +.form-horizontal .checkbox, +.form-horizontal .radio-inline, +.form-horizontal .checkbox-inline { + margin-top: 0; + margin-bottom: 0; + padding-top: 6px; +} +.form-horizontal .radio, +.form-horizontal .checkbox { + min-height: 26px; +} +.form-horizontal .form-group { + margin-left: -15px; + margin-right: -15px; +} +@media (min-width: 768px) { + .form-horizontal .control-label { + text-align: right; + margin-bottom: 0; + padding-top: 6px; + } +} +.form-horizontal .has-feedback .form-control-feedback { + right: 15px; +} +@media (min-width: 768px) { + .form-horizontal .form-group-lg .control-label { + padding-top: 19px; + font-size: 18px; + } +} +@media (min-width: 768px) { + .form-horizontal .form-group-sm .control-label { + padding-top: 7px; + font-size: 12px; + } +} +.text-left { + text-align: left; +} +.text-right { + text-align: right; +} +.text-center { + text-align: center; +} +.text-muted { + color: #3e434d; +} +.text-primary { + color: #F5F7FA; +} +a.text-primary:hover, +a.text-primary:focus { + color: #d3dce9; +} +.text-success { + color: #1D1E24; +} +a.text-success:hover, +a.text-success:focus { + color: #060608; +} +.text-info { + color: #1D1E24; +} +a.text-info:hover, +a.text-info:focus { + color: #060608; +} +.text-warning { + color: #1D1E24; +} +a.text-warning:hover, +a.text-warning:focus { + color: #060608; +} +.text-danger { + color: #1D1E24; +} +a.text-danger:hover, +a.text-danger:focus { + color: #060608; +} +.bg-info { + background-color: #1BA9F5; +} +a.bg-info:hover, +a.bg-info:focus { + background-color: #098dd4; +} +.list-unstyled { + padding-left: 0; + list-style: none; +} +@media (min-width: 0) { + .dl-horizontal dt { + float: left; + width: 160px; + clear: left; + text-align: right; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .dl-horizontal dd { + margin-left: 180px; + } +} +.fade { + opacity: 0; + -webkit-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} +.fade.in { + opacity: 1; +} +.collapse { + display: none; +} +.collapse.in { + display: block; +} +tr.collapse.in { + display: table-row; +} +tbody.collapse.in { + display: table-row-group; +} +.collapsing { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition-property: height, visibility; + transition-property: height, visibility; + -webkit-transition-duration: 0.35s; + transition-duration: 0.35s; + -webkit-transition-timing-function: ease; + transition-timing-function: ease; +} +/** + * ui/angular-ui-select depends upon these styles. Don't use them in your markup. + * Please use the UI Framework styles instead. + */ +.btn { + display: inline-block; + margin-bottom: 0; + font-weight: normal; + text-align: center; + vertical-align: middle; + touch-action: manipulation; + cursor: pointer; + background-image: none; + border: 1px solid transparent; + white-space: nowrap; + padding: 5px 15px; + font-size: 14px; + line-height: 1.42857143; + border-radius: 4px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.btn:focus, +.btn:active:focus, +.btn.active:focus, +.btn.focus, +.btn:active.focus, +.btn.active.focus { + box-shadow: 0 0 0 1px white, 0 0 0 2px #0079a5; + /* 3 */ +} +.btn:hover, +.btn:focus, +.btn.focus { + color: #1D1E24; + text-decoration: none; +} +.btn:active, +.btn.active { + outline: 0; + background-image: none; + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} +.btn.disabled, +.btn[disabled], +fieldset[disabled] .btn { + cursor: not-allowed; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + box-shadow: none; +} +a.btn.disabled, +fieldset[disabled] a.btn { + pointer-events: none; +} +.btn-default { + color: #1D1E24; + background-color: #1BA9F5; + border-color: #1BA9F5; +} +.btn-default:focus, +.btn-default.focus { + color: #1D1E24; + background-color: #098dd4; + border-color: #065c8a; +} +.btn-default:hover { + color: #1D1E24; + background-color: #098dd4; + border-color: #0987ca; +} +.btn-default:active, +.btn-default.active, +.open > .dropdown-toggle.btn-default { + color: #1D1E24; + background-color: #098dd4; + border-color: #0987ca; +} +.btn-default:active:hover, +.btn-default.active:hover, +.open > .dropdown-toggle.btn-default:hover, +.btn-default:active:focus, +.btn-default.active:focus, +.open > .dropdown-toggle.btn-default:focus, +.btn-default:active.focus, +.btn-default.active.focus, +.open > .dropdown-toggle.btn-default.focus { + color: #1D1E24; + background-color: #0876b2; + border-color: #065c8a; +} +.btn-default:active, +.btn-default.active, +.open > .dropdown-toggle.btn-default { + background-image: none; +} +.btn-default.disabled:hover, +.btn-default[disabled]:hover, +fieldset[disabled] .btn-default:hover, +.btn-default.disabled:focus, +.btn-default[disabled]:focus, +fieldset[disabled] .btn-default:focus, +.btn-default.disabled.focus, +.btn-default[disabled].focus, +fieldset[disabled] .btn-default.focus { + background-color: #1BA9F5; + border-color: #1BA9F5; +} +.btn-default .badge { + color: #1BA9F5; + background-color: #1D1E24; +} +.btn-primary { + color: #1D1E24; + background-color: #1BA9F5; + border-color: #1BA9F5; +} +.btn-primary:focus, +.btn-primary.focus { + color: #1D1E24; + background-color: #098dd4; + border-color: #065c8a; +} +.btn-primary:hover { + color: #1D1E24; + background-color: #098dd4; + border-color: #0987ca; +} +.btn-primary:active, +.btn-primary.active, +.open > .dropdown-toggle.btn-primary { + color: #1D1E24; + background-color: #098dd4; + border-color: #0987ca; +} +.btn-primary:active:hover, +.btn-primary.active:hover, +.open > .dropdown-toggle.btn-primary:hover, +.btn-primary:active:focus, +.btn-primary.active:focus, +.open > .dropdown-toggle.btn-primary:focus, +.btn-primary:active.focus, +.btn-primary.active.focus, +.open > .dropdown-toggle.btn-primary.focus { + color: #1D1E24; + background-color: #0876b2; + border-color: #065c8a; +} +.btn-primary:active, +.btn-primary.active, +.open > .dropdown-toggle.btn-primary { + background-image: none; +} +.btn-primary.disabled:hover, +.btn-primary[disabled]:hover, +fieldset[disabled] .btn-primary:hover, +.btn-primary.disabled:focus, +.btn-primary[disabled]:focus, +fieldset[disabled] .btn-primary:focus, +.btn-primary.disabled.focus, +.btn-primary[disabled].focus, +fieldset[disabled] .btn-primary.focus { + background-color: #1BA9F5; + border-color: #1BA9F5; +} +.btn-primary .badge { + color: #1BA9F5; + background-color: #1D1E24; +} +.btn-xs { + padding: 1px 5px; + font-size: 12px; + line-height: 1.5; + border-radius: 4px; +} +.navbar { + position: relative; + min-height: 45px; + margin-bottom: 0px; + border: 1px solid transparent; +} +@media (min-width: 0) { + .navbar { + border-radius: 4px; + } +} +@media (min-width: 0) { + .navbar-header { + float: left; + } +} +.navbar-collapse { + overflow-x: visible; + padding-right: 10px; + padding-left: 10px; + border-top: 1px solid transparent; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); + -webkit-overflow-scrolling: touch; +} +.navbar-collapse.in { + overflow-y: auto; +} +@media (min-width: 0) { + .navbar-collapse { + width: auto; + border-top: 0; + box-shadow: none; + } + .navbar-collapse.collapse { + display: block !important; + height: auto !important; + padding-bottom: 0; + overflow: visible !important; + } + .navbar-collapse.in { + overflow-y: visible; + } + .navbar-fixed-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + padding-left: 0; + padding-right: 0; + } +} +.navbar-fixed-top .navbar-collapse, +.navbar-fixed-bottom .navbar-collapse { + max-height: 340px; +} +@media (max-device-width: 480px) and (orientation: landscape) { + .navbar-fixed-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + max-height: 200px; + } +} +.container > .navbar-header, +.container-fluid > .navbar-header, +.container > .navbar-collapse, +.container-fluid > .navbar-collapse { + margin-right: -10px; + margin-left: -10px; +} +@media (min-width: 0) { + .container > .navbar-header, + .container-fluid > .navbar-header, + .container > .navbar-collapse, + .container-fluid > .navbar-collapse { + margin-right: 0; + margin-left: 0; + } +} +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1050; +} +@media (min-width: 0) { + .navbar-fixed-top, + .navbar-fixed-bottom { + border-radius: 0; + } +} +.navbar-fixed-top { + top: 0; + border-width: 0 0 1px; +} +.navbar-fixed-bottom { + bottom: 0; + margin-bottom: 0; + border-width: 1px 0 0; +} +.navbar-brand { + float: left; + padding: 12.5px 10px; + font-size: 18px; + line-height: 20px; + height: 45px; +} +.navbar-brand:hover, +.navbar-brand:focus { + text-decoration: none; +} +.navbar-brand > img { + display: block; +} +@media (min-width: 0) { + .navbar > .container .navbar-brand, + .navbar > .container-fluid .navbar-brand { + margin-left: -10px; + } +} +.navbar-toggle { + position: relative; + float: right; + margin-right: 10px; + padding: 9px 10px; + margin-top: 5.5px; + margin-bottom: 5.5px; + background-color: transparent; + background-image: none; + border: 1px solid transparent; + border-radius: 4px; +} +.navbar-toggle:focus { + outline: 0; +} +.navbar-toggle .icon-bar { + display: block; + width: 22px; + height: 2px; + border-radius: 1px; +} +.navbar-toggle .icon-bar + .icon-bar { + margin-top: 4px; +} +@media (min-width: 0) { + .navbar-toggle { + display: none; + } +} +.navbar-nav { + margin: 6.25px -10px; +} +.navbar-nav > li > a { + padding-top: 10px; + padding-bottom: 10px; + line-height: 20px; +} +@media (max-width: -1) { + .navbar-nav .open .dropdown-menu { + position: static; + float: none; + width: auto; + margin-top: 0; + background-color: transparent; + border: 0; + box-shadow: none; + } + .navbar-nav .open .dropdown-menu > li > a, + .navbar-nav .open .dropdown-menu .dropdown-header { + padding: 5px 15px 5px 25px; + } + .navbar-nav .open .dropdown-menu > li > a { + line-height: 20px; + } + .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-nav .open .dropdown-menu > li > a:focus { + background-image: none; + } +} +@media (min-width: 0) { + .navbar-nav { + float: left; + margin: 0; + } + .navbar-nav > li { + float: left; + } + .navbar-nav > li > a { + padding-top: 12.5px; + padding-bottom: 12.5px; + } +} +.navbar-form { + margin-left: -10px; + margin-right: -10px; + padding: 10px 10px; + border-top: 1px solid transparent; + border-bottom: 1px solid transparent; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + margin-top: 6.5px; + margin-bottom: 6.5px; +} +@media (min-width: 768px) { + .navbar-form .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .navbar-form .form-control-static { + display: inline-block; + } + .navbar-form .input-group { + display: inline-table; + vertical-align: middle; + } + .navbar-form .input-group .input-group-addon, + .navbar-form .input-group .form-control { + width: auto; + } + .navbar-form .input-group > .form-control { + width: 100%; + } + .navbar-form .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio, + .navbar-form .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio label, + .navbar-form .checkbox label { + padding-left: 0; + } + .navbar-form .radio input[type="radio"], + .navbar-form .checkbox input[type="checkbox"] { + position: relative; + margin-left: 0; + } + .navbar-form .has-feedback .form-control-feedback { + top: 0; + } +} +@media (max-width: -1) { + .navbar-form .form-group { + margin-bottom: 5px; + } + .navbar-form .form-group:last-child { + margin-bottom: 0; + } +} +@media (min-width: 0) { + .navbar-form { + width: auto; + border: 0; + margin-left: 0; + margin-right: 0; + padding-top: 0; + padding-bottom: 0; + -webkit-box-shadow: none; + box-shadow: none; + } +} +.navbar-nav > li > .dropdown-menu { + margin-top: 0; + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { + margin-bottom: 0; + border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.navbar-text { + margin-top: 12.5px; + margin-bottom: 12.5px; +} +@media (min-width: 0) { + .navbar-text { + float: left; + margin-left: 10px; + margin-right: 10px; + } +} +@media (min-width: 0) { + .navbar-left { + float: left !important; + } + .navbar-right { + float: right !important; + margin-right: -10px; + } + .navbar-right ~ .navbar-right { + margin-right: 0; + } +} +.navbar-default { + background-color: #000000; + border-color: transparent; +} +.navbar-default .navbar-brand { + color: #D4DAE5; +} +.navbar-default .navbar-brand:hover, +.navbar-default .navbar-brand:focus { + color: #D4DAE5; + background-color: transparent; +} +.navbar-default .navbar-text { + color: #D4DAE5; +} +.navbar-default .navbar-nav > li > a { + color: #D4DAE5; +} +.navbar-default .navbar-nav > li > a:hover, +.navbar-default .navbar-nav > li > a:focus { + color: #D4DAE5; + background-color: transparent; +} +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + color: #F5F7FA; + background-color: transparent; +} +.navbar-default .navbar-nav > .disabled > a, +.navbar-default .navbar-nav > .disabled > a:hover, +.navbar-default .navbar-nav > .disabled > a:focus { + color: #D4DAE5; + background-color: transparent; +} +.navbar-default .navbar-toggle { + border-color: #000000; +} +.navbar-default .navbar-toggle:hover, +.navbar-default .navbar-toggle:focus { + background-color: #000000; +} +.navbar-default .navbar-toggle .icon-bar { + background-color: #1D1E24; +} +.navbar-default .navbar-collapse, +.navbar-default .navbar-form { + border-color: transparent; +} +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .open > a:hover, +.navbar-default .navbar-nav > .open > a:focus { + background-color: transparent; + color: #F5F7FA; +} +@media (max-width: -1) { + .navbar-default .navbar-nav .open .dropdown-menu > li > a { + color: #D4DAE5; + } + .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { + color: #D4DAE5; + background-color: transparent; + } + .navbar-default .navbar-nav .open .dropdown-menu > .active > a, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #F5F7FA; + background-color: transparent; + } + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #D4DAE5; + background-color: transparent; + } +} +.navbar-default .navbar-link { + color: #D4DAE5; +} +.navbar-default .navbar-link:hover { + color: #D4DAE5; +} +.navbar-inverse { + background-color: #F5F7FA; + border-color: #d3dce9; +} +.navbar-inverse .navbar-brand { + color: #1D1E24; +} +.navbar-inverse .navbar-brand:hover, +.navbar-inverse .navbar-brand:focus { + color: #1D1E24; + background-color: #ffffff; +} +.navbar-inverse .navbar-text { + color: #1D1E24; +} +.navbar-inverse .navbar-nav > li > a { + color: #343741; +} +.navbar-inverse .navbar-nav > li > a:hover, +.navbar-inverse .navbar-nav > li > a:focus { + color: #1D1E24; + background-color: #ffffff; +} +.navbar-inverse .navbar-nav > .active > a, +.navbar-inverse .navbar-nav > .active > a:hover, +.navbar-inverse .navbar-nav > .active > a:focus { + color: #1D1E24; + background-color: #D4DAE5; +} +.navbar-inverse .navbar-nav > .disabled > a, +.navbar-inverse .navbar-nav > .disabled > a:hover, +.navbar-inverse .navbar-nav > .disabled > a:focus { + color: #3e434d; + background-color: transparent; +} +.navbar-inverse .navbar-toggle { + border-color: #d3dce9; +} +.navbar-inverse .navbar-toggle:hover, +.navbar-inverse .navbar-toggle:focus { + background-color: #d3dce9; +} +.navbar-inverse .navbar-toggle .icon-bar { + background-color: #1D1E24; +} +.navbar-inverse .navbar-collapse, +.navbar-inverse .navbar-form { + border-color: #dde4ee; +} +.navbar-inverse .navbar-nav > .open > a, +.navbar-inverse .navbar-nav > .open > a:hover, +.navbar-inverse .navbar-nav > .open > a:focus { + background-color: #D4DAE5; + color: #1D1E24; +} +@media (max-width: -1) { + .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { + border-color: #d3dce9; + } + .navbar-inverse .navbar-nav .open .dropdown-menu .divider { + background-color: #d3dce9; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { + color: #343741; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { + color: #1D1E24; + background-color: #ffffff; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #1D1E24; + background-color: #D4DAE5; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #3e434d; + background-color: transparent; + } +} +.navbar-inverse .navbar-link { + color: #343741; +} +.navbar-inverse .navbar-link:hover { + color: #1D1E24; +} +.close { + float: right; + font-size: 21px; + font-weight: bold; + line-height: 1; + color: #FFF; + text-shadow: none; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover, +.close:focus { + color: #FFF; + text-decoration: none; + cursor: pointer; + opacity: 0.5; + filter: alpha(opacity=50); +} +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} +.modal-open { + overflow: hidden; +} +.modal { + display: none; + overflow: hidden; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1070; + -webkit-overflow-scrolling: touch; + outline: 0; +} +.modal.fade .modal-dialog { + -webkit-transform: translate(0, -25%); + -ms-transform: translate(0, -25%); + -o-transform: translate(0, -25%); + transform: translate(0, -25%); + -webkit-transition: -webkit-transform 0.3s ease-out; + -moz-transition: -moz-transform 0.3s ease-out; + -o-transition: -o-transform 0.3s ease-out; + transition: transform 0.3s ease-out; +} +.modal.in .modal-dialog { + -webkit-transform: translate(0, 0); + -ms-transform: translate(0, 0); + -o-transform: translate(0, 0); + transform: translate(0, 0); +} +.modal-open .modal { + overflow-x: hidden; + overflow-y: auto; +} +.modal-dialog { + position: relative; + width: auto; + margin: 10px; +} +.modal-content { + position: relative; + background-color: #1D1E24; + border: 1px solid #535966; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 4px; + -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + background-clip: padding-box; + outline: 0; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1060; + background-color: #FFF; +} +.modal-backdrop.fade { + opacity: 0; + filter: alpha(opacity=0); +} +.modal-backdrop.in { + opacity: 0.5; + filter: alpha(opacity=50); +} +.modal-header { + padding: 15px; + border-bottom: 1px solid #e5e5e5; +} +.modal-header .close { + margin-top: -2px; +} +.modal-title { + margin: 0; + line-height: 1.42857143; +} +.modal-body { + position: relative; + padding: 15px; +} +.modal-footer { + padding: 15px; + text-align: right; + border-top: 1px solid #e5e5e5; +} +.modal-scrollbar-measure { + position: absolute; + top: -9999px; + width: 50px; + height: 50px; + overflow: scroll; +} +@media (min-width: 768px) { + .modal-dialog { + width: 600px; + margin: 30px auto; + } + .modal-content { + -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); + } + .modal-sm { + width: 300px; + } +} +@media (min-width: 992px) { + .modal-lg { + width: 900px; + } +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +.progress { + overflow: hidden; + height: 20px; + margin-bottom: 20px; + background-color: #2d3039; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} +.progress-bar { + float: left; + width: 0%; + height: 100%; + font-size: 12px; + line-height: 20px; + color: #1D1E24; + text-align: center; + background-color: #54B399; + -webkit-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .progress-bar, +.progress-bar-striped { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-size: 40px 40px; +} +.progress.active .progress-bar, +.progress-bar.active { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-bar-success { + background-color: #7DE2D1; +} +.progress-striped .progress-bar-success { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-info { + background-color: #1BA9F5; +} +.progress-striped .progress-bar-info { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-warning { + background-color: #FF977A; +} +.progress-striped .progress-bar-warning { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-danger { + background-color: #FF6666; +} +.progress-striped .progress-bar-danger { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.list-group { + margin-bottom: 20px; + padding-left: 0; +} +.list-group-item { + position: relative; + display: block; + padding: 10px 15px; + margin-bottom: -1px; + background-color: #1D1E24; + border: 1px solid #343741; +} +.list-group-item:first-child { + border-top-right-radius: 4px; + border-top-left-radius: 4px; +} +.list-group-item:last-child { + margin-bottom: 0; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} +.list-group-item--noBorder { + border-top: 0; +} +a.list-group-item, +button.list-group-item { + color: #D4DAE5; +} +a.list-group-item .list-group-item-heading, +button.list-group-item .list-group-item-heading { + color: #F5F7FA; +} +a.list-group-item:hover, +button.list-group-item:hover, +a.list-group-item:focus, +button.list-group-item:focus { + text-decoration: none; + color: #D4DAE5; + background-color: #25262E; +} +button.list-group-item { + width: 100%; + text-align: left; +} +.list-group-item.disabled, +.list-group-item.disabled:hover, +.list-group-item.disabled:focus { + background-color: #343741; + color: #3e434d; + cursor: not-allowed; +} +.list-group-item.disabled .list-group-item-heading, +.list-group-item.disabled:hover .list-group-item-heading, +.list-group-item.disabled:focus .list-group-item-heading { + color: inherit; +} +.list-group-item.disabled .list-group-item-text, +.list-group-item.disabled:hover .list-group-item-text, +.list-group-item.disabled:focus .list-group-item-text { + color: #3e434d; +} +.list-group-item.active, +.list-group-item.active:hover, +.list-group-item.active:focus { + z-index: 2; + color: #F5F7FA; + background-color: #F5F7FA; + border-color: #F5F7FA; +} +.list-group-item.active .list-group-item-heading, +.list-group-item.active:hover .list-group-item-heading, +.list-group-item.active:focus .list-group-item-heading, +.list-group-item.active .list-group-item-heading > small, +.list-group-item.active:hover .list-group-item-heading > small, +.list-group-item.active:focus .list-group-item-heading > small, +.list-group-item.active .list-group-item-heading > .small, +.list-group-item.active:hover .list-group-item-heading > .small, +.list-group-item.active:focus .list-group-item-heading > .small { + color: inherit; +} +.list-group-item.active .list-group-item-text, +.list-group-item.active:hover .list-group-item-text, +.list-group-item.active:focus .list-group-item-text { + color: #ffffff; +} +.list-group-item-success { + color: #1D1E24; + background-color: #7DE2D1; +} +a.list-group-item-success, +button.list-group-item-success { + color: #1D1E24; +} +a.list-group-item-success .list-group-item-heading, +button.list-group-item-success .list-group-item-heading { + color: inherit; +} +a.list-group-item-success:hover, +button.list-group-item-success:hover, +a.list-group-item-success:focus, +button.list-group-item-success:focus { + color: #1D1E24; + background-color: #68ddca; +} +a.list-group-item-success.active, +button.list-group-item-success.active, +a.list-group-item-success.active:hover, +button.list-group-item-success.active:hover, +a.list-group-item-success.active:focus, +button.list-group-item-success.active:focus { + color: #fff; + background-color: #1D1E24; + border-color: #1D1E24; +} +.list-group-item-info { + color: #1D1E24; + background-color: #1BA9F5; +} +a.list-group-item-info, +button.list-group-item-info { + color: #1D1E24; +} +a.list-group-item-info .list-group-item-heading, +button.list-group-item-info .list-group-item-heading { + color: inherit; +} +a.list-group-item-info:hover, +button.list-group-item-info:hover, +a.list-group-item-info:focus, +button.list-group-item-info:focus { + color: #1D1E24; + background-color: #0a9dec; +} +a.list-group-item-info.active, +button.list-group-item-info.active, +a.list-group-item-info.active:hover, +button.list-group-item-info.active:hover, +a.list-group-item-info.active:focus, +button.list-group-item-info.active:focus { + color: #fff; + background-color: #1D1E24; + border-color: #1D1E24; +} +.list-group-item-warning { + color: #1D1E24; + background-color: #FF977A; +} +a.list-group-item-warning, +button.list-group-item-warning { + color: #1D1E24; +} +a.list-group-item-warning .list-group-item-heading, +button.list-group-item-warning .list-group-item-heading { + color: inherit; +} +a.list-group-item-warning:hover, +button.list-group-item-warning:hover, +a.list-group-item-warning:focus, +button.list-group-item-warning:focus { + color: #1D1E24; + background-color: #ff8361; +} +a.list-group-item-warning.active, +button.list-group-item-warning.active, +a.list-group-item-warning.active:hover, +button.list-group-item-warning.active:hover, +a.list-group-item-warning.active:focus, +button.list-group-item-warning.active:focus { + color: #fff; + background-color: #1D1E24; + border-color: #1D1E24; +} +.list-group-item-danger { + color: #1D1E24; + background-color: #FF6666; +} +a.list-group-item-danger, +button.list-group-item-danger { + color: #1D1E24; +} +a.list-group-item-danger .list-group-item-heading, +button.list-group-item-danger .list-group-item-heading { + color: inherit; +} +a.list-group-item-danger:hover, +button.list-group-item-danger:hover, +a.list-group-item-danger:focus, +button.list-group-item-danger:focus { + color: #1D1E24; + background-color: #ff4c4c; +} +a.list-group-item-danger.active, +button.list-group-item-danger.active, +a.list-group-item-danger.active:hover, +button.list-group-item-danger.active:hover, +a.list-group-item-danger.active:focus, +button.list-group-item-danger.active:focus { + color: #fff; + background-color: #1D1E24; + border-color: #1D1E24; +} +.list-group-item-heading { + margin-top: 0; + margin-bottom: 5px; +} +.list-group-item-text { + margin-bottom: 0; + line-height: 1.3; +} +.nav { + margin-bottom: 0; + padding-left: 0; + list-style: none; +} +.nav > li { + position: relative; + display: block; +} +.nav > li > a { + position: relative; + display: block; + padding: 10px 15px; +} +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #343741; +} +.nav > li.disabled > a { + color: #3e434d; +} +.nav > li.disabled > a:hover, +.nav > li.disabled > a:focus { + color: #3e434d; + text-decoration: none; + background-color: transparent; + cursor: not-allowed; +} +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + background-color: #343741; + border-color: #1BA9F5; +} +.nav .nav-divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.nav > li > a > img { + max-width: none; +} +.nav-tabs { + border-bottom: 1px solid #343741; +} +.nav-tabs > li { + float: left; + margin-bottom: -1px; +} +.nav-tabs > li > a { + margin-right: 2px; + line-height: 1.42857143; + border: 1px solid transparent; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #343741; + background-color: #1D1E24; +} +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + color: #F5F7FA; + background-color: #1D1E24; + border: 1px solid #343741; + border-bottom-color: transparent; + cursor: default; +} +.nav-tabs.nav-justified { + width: 100%; + border-bottom: 0; +} +.nav-tabs.nav-justified > li { + float: none; +} +.nav-tabs.nav-justified > li > a { + text-align: center; + margin-bottom: 5px; +} +.nav-tabs.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-tabs.nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs.nav-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs.nav-justified > .active > a, +.nav-tabs.nav-justified > .active > a:hover, +.nav-tabs.nav-justified > .active > a:focus { + border: 1px solid #1D1E24; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li > a { + border-bottom: 1px solid #1D1E24; + border-radius: 4px 4px 0 0; + } + .nav-tabs.nav-justified > .active > a, + .nav-tabs.nav-justified > .active > a:hover, + .nav-tabs.nav-justified > .active > a:focus { + border-bottom-color: #1D1E24; + } +} +.nav-pills > li { + float: left; +} +.nav-pills > li > a { + border-radius: 4px; +} +.nav-pills > li + li { + margin-left: 2px; +} +.nav-pills > li.active > a, +.nav-pills > li.active > a:hover, +.nav-pills > li.active > a:focus { + color: #1D1E24; + background-color: #1BA9F5; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li + li { + margin-top: 2px; + margin-left: 0; +} +.nav-justified { + width: 100%; +} +.nav-justified > li { + float: none; +} +.nav-justified > li > a { + text-align: center; + margin-bottom: 5px; +} +.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs-justified { + border-bottom: 0; +} +.nav-tabs-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs-justified > .active > a, +.nav-tabs-justified > .active > a:hover, +.nav-tabs-justified > .active > a:focus { + border: 1px solid #1D1E24; +} +@media (min-width: 768px) { + .nav-tabs-justified > li > a { + border-bottom: 1px solid #1D1E24; + border-radius: 4px 4px 0 0; + } + .nav-tabs-justified > .active > a, + .nav-tabs-justified > .active > a:hover, + .nav-tabs-justified > .active > a:focus { + border-bottom-color: #1D1E24; + } +} +.tab-content > .tab-pane { + display: none; +} +.tab-content > .active { + display: block; +} +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.alert { + padding: 15px; + margin-bottom: 20px; + border: 1px solid transparent; + border-radius: 4px; +} +.alert h4 { + margin-top: 0; + color: inherit; +} +.alert .alert-link { + font-weight: bold; +} +.alert > p, +.alert > ul { + margin-bottom: 0; +} +.alert > p + p { + margin-top: 5px; +} +.alert-dismissable, +.alert-dismissible { + padding-right: 35px; +} +.alert-dismissable .close, +.alert-dismissible .close { + position: relative; + top: -2px; + right: -21px; + color: inherit; +} +.alert-success { + background-color: #7DE2D1; + border-color: #53d9c2; + color: #1D1E24; +} +.alert-success hr { + border-top-color: #3ed4bb; +} +.alert-success .alert-link { + color: #060608; +} +.alert-info { + background-color: #1BA9F5; + border-color: #098dd4; + color: #1D1E24; +} +.alert-info hr { + border-top-color: #087dbb; +} +.alert-info .alert-link { + color: #060608; +} +.alert-warning { + background-color: #FF977A; + border-color: #ff6f47; + color: #1D1E24; +} +.alert-warning hr { + border-top-color: #ff5b2e; +} +.alert-warning .alert-link { + color: #060608; +} +.alert-danger { + background-color: #FF6666; + border-color: #ff3333; + color: #1D1E24; +} +.alert-danger hr { + border-top-color: #ff1919; +} +.alert-danger .alert-link { + color: #060608; +} +.bsTooltip { + position: absolute; + z-index: 1040; + display: block; + font-family: 'Open Sans', Helvetica, Arial, sans-serif; + font-style: normal; + font-weight: normal; + letter-spacing: normal; + line-break: auto; + line-height: 1.42857143; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + white-space: normal; + word-break: normal; + word-spacing: normal; + word-wrap: normal; + font-size: 12px; + opacity: 0; + filter: alpha(opacity=0); +} +.bsTooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.bsTooltip.top { + margin-top: -3px; + padding: 5px 0; +} +.bsTooltip.right { + margin-left: 3px; + padding: 0 5px; +} +.bsTooltip.bottom { + margin-top: 3px; + padding: 5px 0; +} +.bsTooltip.left { + margin-left: -3px; + padding: 0 5px; +} +.bsTooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #fff; + text-align: center; + background-color: #000; + border-radius: 4px; +} +.bsTooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.bsTooltip.top .bsTooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-width: 5px 5px 0; + border-top-color: #000; +} +.bsTooltip.top-left .bsTooltip-arrow { + bottom: 0; + right: 5px; + margin-bottom: -5px; + border-width: 5px 5px 0; + border-top-color: #000; +} +.bsTooltip.top-right .bsTooltip-arrow { + bottom: 0; + left: 5px; + margin-bottom: -5px; + border-width: 5px 5px 0; + border-top-color: #000; +} +.bsTooltip.right .bsTooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-width: 5px 5px 5px 0; + border-right-color: #000; +} +.bsTooltip.left .bsTooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-width: 5px 0 5px 5px; + border-left-color: #000; +} +.bsTooltip.bottom .bsTooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000; +} +.bsTooltip.bottom-left .bsTooltip-arrow { + top: 0; + right: 5px; + margin-top: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000; +} +.bsTooltip.bottom-right .bsTooltip-arrow { + top: 0; + left: 5px; + margin-top: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000; +} +.visible-xs, +.visible-sm, +.visible-md, +.visible-lg { + display: none !important; +} +.visible-xs-block, +.visible-xs-inline, +.visible-xs-inline-block, +.visible-sm-block, +.visible-sm-inline, +.visible-sm-inline-block, +.visible-md-block, +.visible-md-inline, +.visible-md-inline-block, +.visible-lg-block, +.visible-lg-inline, +.visible-lg-inline-block { + display: none !important; +} +@media (max-width: 767px) { + .visible-xs { + display: block !important; + } + table.visible-xs { + display: table !important; + } + tr.visible-xs { + display: table-row !important; + } + th.visible-xs, + td.visible-xs { + display: table-cell !important; + } +} +@media (max-width: 767px) { + .visible-xs-block { + display: block !important; + } +} +@media (max-width: 767px) { + .visible-xs-inline { + display: inline !important; + } +} +@media (max-width: 767px) { + .visible-xs-inline-block { + display: inline-block !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm { + display: block !important; + } + table.visible-sm { + display: table !important; + } + tr.visible-sm { + display: table-row !important; + } + th.visible-sm, + td.visible-sm { + display: table-cell !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-block { + display: block !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-inline { + display: inline !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-inline-block { + display: inline-block !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md { + display: block !important; + } + table.visible-md { + display: table !important; + } + tr.visible-md { + display: table-row !important; + } + th.visible-md, + td.visible-md { + display: table-cell !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-block { + display: block !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-inline { + display: inline !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-inline-block { + display: inline-block !important; + } +} +@media (min-width: 1200px) { + .visible-lg { + display: block !important; + } + table.visible-lg { + display: table !important; + } + tr.visible-lg { + display: table-row !important; + } + th.visible-lg, + td.visible-lg { + display: table-cell !important; + } +} +@media (min-width: 1200px) { + .visible-lg-block { + display: block !important; + } +} +@media (min-width: 1200px) { + .visible-lg-inline { + display: inline !important; + } +} +@media (min-width: 1200px) { + .visible-lg-inline-block { + display: inline-block !important; + } +} +@media (max-width: 767px) { + .hidden-xs { + display: none !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .hidden-sm { + display: none !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-md { + display: none !important; + } +} +@media (min-width: 1200px) { + .hidden-lg { + display: none !important; + } +} +.visible-print { + display: none !important; +} +@media print { + .visible-print { + display: block !important; + } + table.visible-print { + display: table !important; + } + tr.visible-print { + display: table-row !important; + } + th.visible-print, + td.visible-print { + display: table-cell !important; + } +} +.visible-print-block { + display: none !important; +} +@media print { + .visible-print-block { + display: block !important; + } +} +.visible-print-inline { + display: none !important; +} +@media print { + .visible-print-inline { + display: inline !important; + } +} +.visible-print-inline-block { + display: none !important; +} +@media print { + .visible-print-inline-block { + display: inline-block !important; + } +} +@media print { + .hidden-print { + display: none !important; + } +} +.caret { + display: inline-block; + width: 0; + height: 0; + margin-left: 2px; + vertical-align: middle; + border-top: 4px dashed; + border-top: 4px solid \9; + border-right: 4px solid transparent; + border-left: 4px solid transparent; +} +.dropup, +.dropdown { + position: relative; +} +.dropdown-toggle:focus { + outline: 0; +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + list-style: none; + font-size: 14px; + text-align: left; + background-color: #1D1E24; + border: 1px solid #343741; + border-radius: 4px; + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.1); + background-clip: padding-box; +} +.dropdown-menu.pull-right { + right: 0; + left: auto; +} +.dropdown-menu .divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #343741; +} +.dropdown-menu > li > a, +.dropdown-menu > li > button { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 1.42857143; + color: #ababab; + white-space: nowrap; +} +.dropdown-menu > li > button { + appearance: none; + background: none; + border: none; + width: 100%; + text-align: left; +} +.dropdown-menu > li > a:hover, +.dropdown-menu > li > button:hover, +.dropdown-menu > li > a:focus, +.dropdown-menu > li > button:focus { + text-decoration: none; + color: #1D1E24; + background-color: #F5F7FA; +} +.dropdown-menu > .active > button, +.dropdown-menu > .active > a, +.dropdown-menu > .active > button:hover, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > button:focus, +.dropdown-menu > .active > a:focus { + color: #1D1E24; + text-decoration: none; + outline: 0; + background-color: #F5F7FA; +} +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #535966; +} +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + cursor: not-allowed; +} +.open > .dropdown-menu { + display: block; +} +.open > a { + outline: 0; +} +.dropdown-menu-right { + left: auto; + right: 0; +} +.dropdown-menu-left { + left: 0; + right: auto; +} +.dropdown-header { + display: block; + padding: 3px 20px; + font-size: 12px; + line-height: 1.42857143; + color: #535966; + white-space: nowrap; +} +.dropdown-backdrop { + position: fixed; + left: 0; + right: 0; + bottom: 0; + top: 0; + z-index: 990; +} +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0; + border-bottom: 4px dashed; + border-bottom: 4px solid \9; + content: ""; +} +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +@media (min-width: 0) { + .navbar-right .dropdown-menu { + left: auto; + right: 0; + } + .navbar-right .dropdown-menu-left { + left: 0; + right: auto; + } +} +.input-group { + position: relative; + display: table; + border-collapse: separate; +} +.input-group[class*="col-"] { + float: none; + padding-left: 0; + padding-right: 0; +} +.input-group .form-control { + position: relative; + z-index: 2; + float: left; + width: 100%; + margin-bottom: 0; +} +.input-group .form-control:focus { + z-index: 3; +} +.input-group-lg > .form-control, +.input-group-lg > .input-group-addon { + height: 62px; + padding: 18px 27px; + font-size: 18px; + line-height: 1.3333333; + border-radius: 4px; +} +select.input-group-lg > .form-control, +select.input-group-lg > .input-group-addon { + height: 62px; + line-height: 62px; +} +textarea.input-group-lg > .form-control, +textarea.input-group-lg > .input-group-addon, +select[multiple].input-group-lg > .form-control, +select[multiple].input-group-lg > .input-group-addon { + height: auto; +} +.input-group-sm > .form-control, +.input-group-sm > .input-group-addon { + height: 32px; + padding: 6px 9px; + font-size: 12px; + line-height: 1.5; + border-radius: 4px; +} +select.input-group-sm > .form-control, +select.input-group-sm > .input-group-addon { + height: 32px; + line-height: 32px; +} +textarea.input-group-sm > .form-control, +textarea.input-group-sm > .input-group-addon, +select[multiple].input-group-sm > .form-control, +select[multiple].input-group-sm > .input-group-addon { + height: auto; +} +.input-group-addon, +.input-group .form-control { + display: table-cell; +} +.input-group-addon:not(:first-child):not(:last-child), +.input-group .form-control:not(:first-child):not(:last-child) { + border-radius: 0; +} +.input-group-addon { + width: 1%; + white-space: nowrap; + vertical-align: middle; +} +.input-group-addon { + padding: 5px 15px; + font-size: 14px; + font-weight: normal; + line-height: 1; + color: #F5F7FA; + text-align: center; + background-color: #343741; + border: 1px solid #343741; + border-radius: 4px; +} +.input-group-addon.input-sm { + padding: 6px 9px; + font-size: 12px; + border-radius: 4px; +} +.input-group-addon.input-lg { + padding: 18px 27px; + font-size: 18px; + border-radius: 4px; +} +.input-group-addon input[type="radio"], +.input-group-addon input[type="checkbox"] { + margin-top: 0; +} +.input-group .form-control:first-child, +.input-group-addon:first-child { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.input-group-addon:first-child { + border-right: 0; +} +.input-group .form-control:last-child, +.input-group-addon:last-child { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.input-group-addon:last-child { + border-left: 0; +} +.pagination { + display: inline-block; + padding-left: 0; + margin: 20px 0; + border-radius: 4px; +} +.pagination > li { + display: inline; +} +.pagination > li > a, +.pagination > li > span { + position: relative; + float: left; + padding: 5px 15px; + line-height: 1.42857143; + text-decoration: none; + color: #1BA9F5; + background-color: transparent; + border: 1px solid transparent; + margin-left: -1px; +} +.pagination > li:first-child > a, +.pagination > li:first-child > span { + margin-left: 0; + border-bottom-left-radius: 4px; + border-top-left-radius: 4px; +} +.pagination > li:last-child > a, +.pagination > li:last-child > span { + border-bottom-right-radius: 4px; + border-top-right-radius: 4px; +} +.pagination > li > a:hover, +.pagination > li > span:hover, +.pagination > li > a:focus, +.pagination > li > span:focus { + z-index: 2; + color: #1BA9F5; + background-color: rgba(0, 0, 0, 0); + border-color: transparent; +} +.pagination > .active > a, +.pagination > .active > span, +.pagination > .active > a:hover, +.pagination > .active > span:hover, +.pagination > .active > a:focus, +.pagination > .active > span:focus { + z-index: 3; + color: #F5F7FA; + background-color: rgba(0, 0, 0, 0); + border-color: transparent; + cursor: default; +} +.pagination > .disabled > span, +.pagination > .disabled > span:hover, +.pagination > .disabled > span:focus, +.pagination > .disabled > a, +.pagination > .disabled > a:hover, +.pagination > .disabled > a:focus { + color: #F5F7FA; + background-color: rgba(38, 38, 38, 0); + border-color: transparent; + cursor: not-allowed; +} +.pagination-lg > li > a, +.pagination-lg > li > span { + padding: 18px 27px; + font-size: 18px; + line-height: 1.3333333; +} +.pagination-lg > li:first-child > a, +.pagination-lg > li:first-child > span { + border-bottom-left-radius: 4px; + border-top-left-radius: 4px; +} +.pagination-lg > li:last-child > a, +.pagination-lg > li:last-child > span { + border-bottom-right-radius: 4px; + border-top-right-radius: 4px; +} +.pagination-sm > li > a, +.pagination-sm > li > span { + padding: 6px 9px; + font-size: 12px; + line-height: 1.5; +} +.pagination-sm > li:first-child > a, +.pagination-sm > li:first-child > span { + border-bottom-left-radius: 4px; + border-top-left-radius: 4px; +} +.pagination-sm > li:last-child > a, +.pagination-sm > li:last-child > span { + border-bottom-right-radius: 4px; + border-top-right-radius: 4px; +} +.pager { + padding-left: 0; + margin: 20px 0; + list-style: none; + text-align: center; +} +.pager li { + display: inline; +} +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: transparent; + border: 1px solid transparent; + border-radius: 0; +} +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: rgba(0, 0, 0, 0); +} +.pager .next > a, +.pager .next > span { + float: right; +} +.pager .previous > a, +.pager .previous > span { + float: left; +} +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #1D1E24; + background-color: transparent; + cursor: not-allowed; +} +.label { + display: inline; + padding: 0.2em 0.6em 0.3em; + font-size: 75%; + font-weight: bold; + line-height: 1; + color: #1D1E24; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: 0.25em; +} +a.label:hover, +a.label:focus { + color: #1D1E24; + text-decoration: none; + cursor: pointer; +} +.label:empty { + display: none; +} +.label-default { + background-color: #1BA9F5; +} +.label-default[href]:hover, +.label-default[href]:focus { + background-color: #098dd4; +} +.label-primary { + background-color: #F5F7FA; +} +.label-primary[href]:hover, +.label-primary[href]:focus { + background-color: #d3dce9; +} +.label-success { + background-color: #7DE2D1; +} +.label-success[href]:hover, +.label-success[href]:focus { + background-color: #53d9c2; +} +.label-info { + background-color: #1BA9F5; +} +.label-info[href]:hover, +.label-info[href]:focus { + background-color: #098dd4; +} +.label-warning { + background-color: #FF977A; +} +.label-warning[href]:hover, +.label-warning[href]:focus { + background-color: #ff6f47; +} +.label-danger { + background-color: #FF6666; +} +.label-danger[href]:hover, +.label-danger[href]:focus { + background-color: #ff3333; +} +.panel { + margin-bottom: 20px; + background-color: #1D1E24; + border: 1px solid transparent; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); +} +.panel-body { + padding: 15px; +} +.panel-heading { + padding: 10px 15px; + border-bottom: 1px solid transparent; + border-top-right-radius: 3px; + border-top-left-radius: 3px; +} +.panel-heading > .dropdown .dropdown-toggle { + color: inherit; +} +.panel-title { + margin-top: 0; + margin-bottom: 0; + font-size: 16px; + color: inherit; +} +.panel-title > a, +.panel-title > small, +.panel-title > .small, +.panel-title > small > a, +.panel-title > .small > a { + color: inherit; +} +.panel-footer { + padding: 10px 15px; + background-color: #25262E; + border-top: 1px solid #343741; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .list-group, +.panel > .panel-collapse > .list-group { + margin-bottom: 0; +} +.panel > .list-group .list-group-item, +.panel > .panel-collapse > .list-group .list-group-item { + border-width: 1px 0; + border-radius: 0; +} +.panel > .list-group:first-child .list-group-item:first-child, +.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child { + border-top: 0; + border-top-right-radius: 3px; + border-top-left-radius: 3px; +} +.panel > .list-group:last-child .list-group-item:last-child, +.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child { + border-bottom: 0; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child { + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.panel-heading + .list-group .list-group-item:first-child { + border-top-width: 0; +} +.list-group + .panel-footer { + border-top-width: 0; +} +.panel > .table, +.panel > .table-responsive > .table, +.panel > .panel-collapse > .table { + margin-bottom: 0; +} +.panel > .table caption, +.panel > .table-responsive > .table caption, +.panel > .panel-collapse > .table caption { + padding-left: 15px; + padding-right: 15px; +} +.panel > .table:first-child, +.panel > .table-responsive:first-child > .table:first-child { + border-top-right-radius: 3px; + border-top-left-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child { + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child td:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child { + border-top-left-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child { + border-top-right-radius: 3px; +} +.panel > .table:last-child, +.panel > .table-responsive:last-child > .table:last-child { + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child { + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child { + border-bottom-left-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child { + border-bottom-right-radius: 3px; +} +.panel > .panel-body + .table, +.panel > .panel-body + .table-responsive, +.panel > .table + .panel-body, +.panel > .table-responsive + .panel-body { + border-top: 1px solid #343741; +} +.panel > .table > tbody:first-child > tr:first-child th, +.panel > .table > tbody:first-child > tr:first-child td { + border-top: 0; +} +.panel > .table-bordered, +.panel > .table-responsive > .table-bordered { + border: 0; +} +.panel > .table-bordered > thead > tr > th:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, +.panel > .table-bordered > tbody > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, +.panel > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-bordered > thead > tr > td:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, +.panel > .table-bordered > tbody > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, +.panel > .table-bordered > tfoot > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; +} +.panel > .table-bordered > thead > tr > th:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, +.panel > .table-bordered > tbody > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, +.panel > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-bordered > thead > tr > td:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, +.panel > .table-bordered > tbody > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, +.panel > .table-bordered > tfoot > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; +} +.panel > .table-bordered > thead > tr:first-child > td, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > td, +.panel > .table-bordered > tbody > tr:first-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, +.panel > .table-bordered > thead > tr:first-child > th, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > th, +.panel > .table-bordered > tbody > tr:first-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th { + border-bottom: 0; +} +.panel > .table-bordered > tbody > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, +.panel > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-bordered > tbody > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, +.panel > .table-bordered > tfoot > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th { + border-bottom: 0; +} +.panel > .table-responsive { + border: 0; + margin-bottom: 0; +} +.panel-group { + margin-bottom: 20px; +} +.panel-group .panel { + margin-bottom: 0; + border-radius: 4px; +} +.panel-group .panel + .panel { + margin-top: 5px; +} +.panel-group .panel-heading { + border-bottom: 0; +} +.panel-group .panel-heading + .panel-collapse > .panel-body, +.panel-group .panel-heading + .panel-collapse > .list-group { + border-top: 1px solid #343741; +} +.panel-group .panel-footer { + border-top: 0; +} +.panel-group .panel-footer + .panel-collapse .panel-body { + border-bottom: 1px solid #343741; +} +.panel-default { + border-color: #343741; +} +.panel-default > .panel-heading { + color: #ababab; + background-color: #25262E; + border-color: #343741; +} +.panel-default > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #343741; +} +.panel-default > .panel-heading .badge { + color: #25262E; + background-color: #ababab; +} +.panel-default > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #343741; +} +.panel-primary { + border-color: #F5F7FA; +} +.panel-primary > .panel-heading { + color: #1D1E24; + background-color: #F5F7FA; + border-color: #F5F7FA; +} +.panel-primary > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #F5F7FA; +} +.panel-primary > .panel-heading .badge { + color: #F5F7FA; + background-color: #1D1E24; +} +.panel-primary > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #F5F7FA; +} +.panel-success { + border-color: #53d9c2; +} +.panel-success > .panel-heading { + color: #1D1E24; + background-color: #7DE2D1; + border-color: #53d9c2; +} +.panel-success > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #53d9c2; +} +.panel-success > .panel-heading .badge { + color: #7DE2D1; + background-color: #1D1E24; +} +.panel-success > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #53d9c2; +} +.panel-info { + border-color: #098dd4; +} +.panel-info > .panel-heading { + color: #1D1E24; + background-color: #1BA9F5; + border-color: #098dd4; +} +.panel-info > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #098dd4; +} +.panel-info > .panel-heading .badge { + color: #1BA9F5; + background-color: #1D1E24; +} +.panel-info > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #098dd4; +} +.panel-warning { + border-color: #ff6f47; +} +.panel-warning > .panel-heading { + color: #1D1E24; + background-color: #FF977A; + border-color: #ff6f47; +} +.panel-warning > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #ff6f47; +} +.panel-warning > .panel-heading .badge { + color: #FF977A; + background-color: #1D1E24; +} +.panel-warning > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #ff6f47; +} +.panel-danger { + border-color: #ff3333; +} +.panel-danger > .panel-heading { + color: #1D1E24; + background-color: #FF6666; + border-color: #ff3333; +} +.panel-danger > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #ff3333; +} +.panel-danger > .panel-heading .badge { + color: #FF6666; + background-color: #1D1E24; +} +.panel-danger > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #ff3333; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + max-width: 276px; + padding: 1px; + font-family: 'Open Sans', Helvetica, Arial, sans-serif; + font-style: normal; + font-weight: normal; + letter-spacing: normal; + line-break: auto; + line-height: 1.42857143; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + white-space: normal; + word-break: normal; + word-spacing: normal; + word-wrap: normal; + font-size: 14px; + background-color: #1D1E24; + background-clip: padding-box; + border: 1px solid #343741; + border-radius: 4px; + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.1); +} +.popover.top { + margin-top: -10px; +} +.popover.right { + margin-left: 10px; +} +.popover.bottom { + margin-top: 10px; +} +.popover.left { + margin-left: -10px; +} +.popover-title { + margin: 0; + padding: 8px 14px; + font-size: 14px; + background-color: #16171c; + border-bottom: 1px solid #0b0b0d; + border-radius: 3px 3px 0 0; +} +.popover-content { + padding: 9px 14px; +} +.popover > .arrow, +.popover > .arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.popover > .arrow { + border-width: 11px; +} +.popover > .arrow:after { + border-width: 10px; + content: ""; +} +.popover.top > .arrow { + left: 50%; + margin-left: -11px; + border-bottom-width: 0; + border-top-color: #070708; + border-top-color: #343741; + bottom: -11px; +} +.popover.top > .arrow:after { + content: " "; + bottom: 1px; + margin-left: -10px; + border-bottom-width: 0; + border-top-color: #1D1E24; +} +.popover.right > .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-left-width: 0; + border-right-color: #070708; + border-right-color: #343741; +} +.popover.right > .arrow:after { + content: " "; + left: 1px; + bottom: -10px; + border-left-width: 0; + border-right-color: #1D1E24; +} +.popover.bottom > .arrow { + left: 50%; + margin-left: -11px; + border-top-width: 0; + border-bottom-color: #070708; + border-bottom-color: #343741; + top: -11px; +} +.popover.bottom > .arrow:after { + content: " "; + top: 1px; + margin-left: -10px; + border-top-width: 0; + border-bottom-color: #1D1E24; +} +.popover.left > .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-right-width: 0; + border-left-color: #070708; + border-left-color: #343741; +} +.popover.left > .arrow:after { + content: " "; + right: 1px; + border-right-width: 0; + border-left-color: #1D1E24; + bottom: -10px; +} +.clearfix:before, +.clearfix:after, +.container:before, +.container:after, +.container-fluid:before, +.container-fluid:after, +.row:before, +.row:after, +.form-horizontal .form-group:before, +.form-horizontal .form-group:after, +.dl-horizontal dd:before, +.dl-horizontal dd:after, +.navbar:before, +.navbar:after, +.navbar-header:before, +.navbar-header:after, +.navbar-collapse:before, +.navbar-collapse:after, +.modal-header:before, +.modal-header:after, +.modal-footer:before, +.modal-footer:after, +.nav:before, +.nav:after, +.pager:before, +.pager:after, +.panel-body:before, +.panel-body:after { + content: " "; + display: table; +} +.clearfix:after, +.container:after, +.container-fluid:after, +.row:after, +.form-horizontal .form-group:after, +.dl-horizontal dd:after, +.navbar:after, +.navbar-header:after, +.navbar-collapse:after, +.modal-header:after, +.modal-footer:after, +.nav:after, +.pager:after, +.panel-body:after { + clear: both; +} +.center-block { + display: block; + margin-left: auto; + margin-right: auto; +} +.pull-right { + float: right !important; +} +.pull-left { + float: left !important; +} +.hide { + display: none !important; +} +.show { + display: block !important; +} +.invisible { + visibility: hidden; +} +.text-hide { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} +.hidden { + display: none !important; +} +.affix { + position: fixed; +} +.navbar > .container-fluid > .navbar-nav:not(.pull-right):first-child, +.navbar > .container-fluid > .navbar-form:not(.pull-right):first-child { + margin-left: -15px; + margin-top: 4px; +} +.navbar { + border-width: 0; +} +.navbar-btn-link { + margin: 0; + border-radius: 0; +} +@media (max-width: 768px) { + .navbar-btn-link { + width: 100%; + text-align: left; + } +} +.navbar-default .badge { + background-color: #1D1E24; + color: #000000; +} +.navbar-inverse .kbnGlobalNav__logoBrand { + height: 45px; + width: 252px; + background-color: #ffffff; +} +.navbar-inverse .kbnGlobalNav__smallLogoBrand { + height: 45px; + width: 45px; + background-color: #ffffff; +} +.navbar-inverse .badge { + background-color: #1D1E24; + color: #ffffff; +} +.navbar-brand { + cursor: default; + font-size: 1.8em; + user-select: none; +} +.navbar-nav { + font-size: 12px; +} +.navbar-nav > .active > a { + border-bottom-color: #ababab; + background-color: transparent; +} +.navbar-toggle { + margin-top: 4px; +} +.text-primary, +.text-primary:hover { + color: #F5F7FA; +} +.text-success, +.text-success:hover { + color: #7DE2D1; +} +.text-danger, +.text-danger:hover { + color: #FF6666; +} +.text-warning, +.text-warning:hover { + color: #FF977A; +} +.text-info, +.text-info:hover { + color: #1BA9F5; +} +table .success, +.table .success, +table .warning, +.table .warning, +table .danger, +.table .danger, +table .info, +.table .info { + color: #1D1E24; +} +table .success a, +.table .success a, +table .warning a, +.table .warning a, +table .danger a, +.table .danger a, +table .info a, +.table .info a { + color: #1D1E24; +} +.table-bordered > thead > tr > th, +.table-bordered > tbody > tr > th, +.table-bordered > tfoot > tr > th, +.table-bordered > thead > tr > td, +.table-bordered > tbody > tr > td, +.table-bordered > tfoot > tr > td { + border: 1px solid #343741; +} +.form-control, +input { + border-width: 1px; + -webkit-box-shadow: none; + box-shadow: none; +} +.form-control:focus, +input:focus { + -webkit-box-shadow: none; + box-shadow: none; +} +.has-warning .help-block, +.has-warning .control-label, +.has-warning .radio, +.has-warning .checkbox, +.has-warning .radio-inline, +.has-warning .checkbox-inline, +.has-warning .form-control-feedback { + color: #FF977A; +} +.has-warning .form-control, +.has-warning .form-control:focus { + border: 1px solid; + border-color: #FF977A; +} +.has-warning .input-group-addon { + border-color: #FF977A; +} +.has-error .help-block, +.has-error .control-label, +.has-error .radio, +.has-error .checkbox, +.has-error .radio-inline, +.has-error .checkbox-inline, +.has-error .form-control-feedback { + color: #FF6666; +} +.has-error .form-control, +.has-error .form-control:focus { + border: 1px solid; + border-color: #FF6666; +} +.has-error .input-group-addon { + border-color: #FF6666; +} +.has-success .help-block, +.has-success .control-label, +.has-success .radio, +.has-success .checkbox, +.has-success .radio-inline, +.has-success .checkbox-inline, +.has-success .form-control-feedback { + color: #7DE2D1; +} +.has-success .form-control, +.has-success .form-control:focus { + border: solid #7DE2D1; +} +.has-success .input-group-addon { + border-color: #7DE2D1; +} +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + border-color: transparent; +} +.pager a, +.pager a:hover { + color: #1D1E24; +} +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + background-color: rgba(38, 38, 38, 0); +} +.panel { + border-radius: 0; + -webkit-box-shadow: 0 0 0 rgba(0, 0, 0, 0); + box-shadow: 0 0 0 rgba(0, 0, 0, 0); +} +.progress { + -webkit-box-shadow: none; + box-shadow: none; +} +.progress .progress-bar { + font-size: 10px; + line-height: 10px; +} +.well { + -webkit-box-shadow: none; + box-shadow: none; +} diff --git a/src/core/server/core_app/assets/legacy_light_theme.css b/src/core/server/core_app/assets/legacy_light_theme.css new file mode 100644 index 0000000000000..c5c639f60e3be --- /dev/null +++ b/src/core/server/core_app/assets/legacy_light_theme.css @@ -0,0 +1,4419 @@ +/*! + * Bootstrap v3.3.6 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +/* @notice + * This product bundles bootstrap@3.3.6 which is available under a + * "MIT" license. + * + * The MIT License (MIT) + * + * Copyright (c) 2011-2015 Twitter, Inc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +.container { + margin-right: auto; + margin-left: auto; + padding-left: 15px; + padding-right: 15px; +} +@media (min-width: 768px) { + .container { + width: 750px; + } +} +@media (min-width: 992px) { + .container { + width: 970px; + } +} +@media (min-width: 1200px) { + .container { + width: 1170px; + } +} +.container-fluid { + margin-right: auto; + margin-left: auto; + padding-left: 15px; + padding-right: 15px; +} +.row { + margin-left: -15px; + margin-right: -15px; +} +.col-xs-1, +.col-sm-1, +.col-md-1, +.col-lg-1, +.col-xs-2, +.col-sm-2, +.col-md-2, +.col-lg-2, +.col-xs-3, +.col-sm-3, +.col-md-3, +.col-lg-3, +.col-xs-4, +.col-sm-4, +.col-md-4, +.col-lg-4, +.col-xs-5, +.col-sm-5, +.col-md-5, +.col-lg-5, +.col-xs-6, +.col-sm-6, +.col-md-6, +.col-lg-6, +.col-xs-7, +.col-sm-7, +.col-md-7, +.col-lg-7, +.col-xs-8, +.col-sm-8, +.col-md-8, +.col-lg-8, +.col-xs-9, +.col-sm-9, +.col-md-9, +.col-lg-9, +.col-xs-10, +.col-sm-10, +.col-md-10, +.col-lg-10, +.col-xs-11, +.col-sm-11, +.col-md-11, +.col-lg-11, +.col-xs-12, +.col-sm-12, +.col-md-12, +.col-lg-12 { + position: relative; + min-height: 1px; + padding-left: 15px; + padding-right: 15px; +} +.col-xs-1, +.col-xs-2, +.col-xs-3, +.col-xs-4, +.col-xs-5, +.col-xs-6, +.col-xs-7, +.col-xs-8, +.col-xs-9, +.col-xs-10, +.col-xs-11, +.col-xs-12 { + float: left; +} +.col-xs-12 { + width: 100%; +} +.col-xs-11 { + width: 91.66666667%; +} +.col-xs-10 { + width: 83.33333333%; +} +.col-xs-9 { + width: 75%; +} +.col-xs-8 { + width: 66.66666667%; +} +.col-xs-7 { + width: 58.33333333%; +} +.col-xs-6 { + width: 50%; +} +.col-xs-5 { + width: 41.66666667%; +} +.col-xs-4 { + width: 33.33333333%; +} +.col-xs-3 { + width: 25%; +} +.col-xs-2 { + width: 16.66666667%; +} +.col-xs-1 { + width: 8.33333333%; +} +.col-xs-pull-12 { + right: 100%; +} +.col-xs-pull-11 { + right: 91.66666667%; +} +.col-xs-pull-10 { + right: 83.33333333%; +} +.col-xs-pull-9 { + right: 75%; +} +.col-xs-pull-8 { + right: 66.66666667%; +} +.col-xs-pull-7 { + right: 58.33333333%; +} +.col-xs-pull-6 { + right: 50%; +} +.col-xs-pull-5 { + right: 41.66666667%; +} +.col-xs-pull-4 { + right: 33.33333333%; +} +.col-xs-pull-3 { + right: 25%; +} +.col-xs-pull-2 { + right: 16.66666667%; +} +.col-xs-pull-1 { + right: 8.33333333%; +} +.col-xs-pull-0 { + right: auto; +} +.col-xs-push-12 { + left: 100%; +} +.col-xs-push-11 { + left: 91.66666667%; +} +.col-xs-push-10 { + left: 83.33333333%; +} +.col-xs-push-9 { + left: 75%; +} +.col-xs-push-8 { + left: 66.66666667%; +} +.col-xs-push-7 { + left: 58.33333333%; +} +.col-xs-push-6 { + left: 50%; +} +.col-xs-push-5 { + left: 41.66666667%; +} +.col-xs-push-4 { + left: 33.33333333%; +} +.col-xs-push-3 { + left: 25%; +} +.col-xs-push-2 { + left: 16.66666667%; +} +.col-xs-push-1 { + left: 8.33333333%; +} +.col-xs-push-0 { + left: auto; +} +.col-xs-offset-12 { + margin-left: 100%; +} +.col-xs-offset-11 { + margin-left: 91.66666667%; +} +.col-xs-offset-10 { + margin-left: 83.33333333%; +} +.col-xs-offset-9 { + margin-left: 75%; +} +.col-xs-offset-8 { + margin-left: 66.66666667%; +} +.col-xs-offset-7 { + margin-left: 58.33333333%; +} +.col-xs-offset-6 { + margin-left: 50%; +} +.col-xs-offset-5 { + margin-left: 41.66666667%; +} +.col-xs-offset-4 { + margin-left: 33.33333333%; +} +.col-xs-offset-3 { + margin-left: 25%; +} +.col-xs-offset-2 { + margin-left: 16.66666667%; +} +.col-xs-offset-1 { + margin-left: 8.33333333%; +} +.col-xs-offset-0 { + margin-left: 0%; +} +@media (min-width: 768px) { + .col-sm-1, + .col-sm-2, + .col-sm-3, + .col-sm-4, + .col-sm-5, + .col-sm-6, + .col-sm-7, + .col-sm-8, + .col-sm-9, + .col-sm-10, + .col-sm-11, + .col-sm-12 { + float: left; + } + .col-sm-12 { + width: 100%; + } + .col-sm-11 { + width: 91.66666667%; + } + .col-sm-10 { + width: 83.33333333%; + } + .col-sm-9 { + width: 75%; + } + .col-sm-8 { + width: 66.66666667%; + } + .col-sm-7 { + width: 58.33333333%; + } + .col-sm-6 { + width: 50%; + } + .col-sm-5 { + width: 41.66666667%; + } + .col-sm-4 { + width: 33.33333333%; + } + .col-sm-3 { + width: 25%; + } + .col-sm-2 { + width: 16.66666667%; + } + .col-sm-1 { + width: 8.33333333%; + } + .col-sm-pull-12 { + right: 100%; + } + .col-sm-pull-11 { + right: 91.66666667%; + } + .col-sm-pull-10 { + right: 83.33333333%; + } + .col-sm-pull-9 { + right: 75%; + } + .col-sm-pull-8 { + right: 66.66666667%; + } + .col-sm-pull-7 { + right: 58.33333333%; + } + .col-sm-pull-6 { + right: 50%; + } + .col-sm-pull-5 { + right: 41.66666667%; + } + .col-sm-pull-4 { + right: 33.33333333%; + } + .col-sm-pull-3 { + right: 25%; + } + .col-sm-pull-2 { + right: 16.66666667%; + } + .col-sm-pull-1 { + right: 8.33333333%; + } + .col-sm-pull-0 { + right: auto; + } + .col-sm-push-12 { + left: 100%; + } + .col-sm-push-11 { + left: 91.66666667%; + } + .col-sm-push-10 { + left: 83.33333333%; + } + .col-sm-push-9 { + left: 75%; + } + .col-sm-push-8 { + left: 66.66666667%; + } + .col-sm-push-7 { + left: 58.33333333%; + } + .col-sm-push-6 { + left: 50%; + } + .col-sm-push-5 { + left: 41.66666667%; + } + .col-sm-push-4 { + left: 33.33333333%; + } + .col-sm-push-3 { + left: 25%; + } + .col-sm-push-2 { + left: 16.66666667%; + } + .col-sm-push-1 { + left: 8.33333333%; + } + .col-sm-push-0 { + left: auto; + } + .col-sm-offset-12 { + margin-left: 100%; + } + .col-sm-offset-11 { + margin-left: 91.66666667%; + } + .col-sm-offset-10 { + margin-left: 83.33333333%; + } + .col-sm-offset-9 { + margin-left: 75%; + } + .col-sm-offset-8 { + margin-left: 66.66666667%; + } + .col-sm-offset-7 { + margin-left: 58.33333333%; + } + .col-sm-offset-6 { + margin-left: 50%; + } + .col-sm-offset-5 { + margin-left: 41.66666667%; + } + .col-sm-offset-4 { + margin-left: 33.33333333%; + } + .col-sm-offset-3 { + margin-left: 25%; + } + .col-sm-offset-2 { + margin-left: 16.66666667%; + } + .col-sm-offset-1 { + margin-left: 8.33333333%; + } + .col-sm-offset-0 { + margin-left: 0%; + } +} +@media (min-width: 992px) { + .col-md-1, + .col-md-2, + .col-md-3, + .col-md-4, + .col-md-5, + .col-md-6, + .col-md-7, + .col-md-8, + .col-md-9, + .col-md-10, + .col-md-11, + .col-md-12 { + float: left; + } + .col-md-12 { + width: 100%; + } + .col-md-11 { + width: 91.66666667%; + } + .col-md-10 { + width: 83.33333333%; + } + .col-md-9 { + width: 75%; + } + .col-md-8 { + width: 66.66666667%; + } + .col-md-7 { + width: 58.33333333%; + } + .col-md-6 { + width: 50%; + } + .col-md-5 { + width: 41.66666667%; + } + .col-md-4 { + width: 33.33333333%; + } + .col-md-3 { + width: 25%; + } + .col-md-2 { + width: 16.66666667%; + } + .col-md-1 { + width: 8.33333333%; + } + .col-md-pull-12 { + right: 100%; + } + .col-md-pull-11 { + right: 91.66666667%; + } + .col-md-pull-10 { + right: 83.33333333%; + } + .col-md-pull-9 { + right: 75%; + } + .col-md-pull-8 { + right: 66.66666667%; + } + .col-md-pull-7 { + right: 58.33333333%; + } + .col-md-pull-6 { + right: 50%; + } + .col-md-pull-5 { + right: 41.66666667%; + } + .col-md-pull-4 { + right: 33.33333333%; + } + .col-md-pull-3 { + right: 25%; + } + .col-md-pull-2 { + right: 16.66666667%; + } + .col-md-pull-1 { + right: 8.33333333%; + } + .col-md-pull-0 { + right: auto; + } + .col-md-push-12 { + left: 100%; + } + .col-md-push-11 { + left: 91.66666667%; + } + .col-md-push-10 { + left: 83.33333333%; + } + .col-md-push-9 { + left: 75%; + } + .col-md-push-8 { + left: 66.66666667%; + } + .col-md-push-7 { + left: 58.33333333%; + } + .col-md-push-6 { + left: 50%; + } + .col-md-push-5 { + left: 41.66666667%; + } + .col-md-push-4 { + left: 33.33333333%; + } + .col-md-push-3 { + left: 25%; + } + .col-md-push-2 { + left: 16.66666667%; + } + .col-md-push-1 { + left: 8.33333333%; + } + .col-md-push-0 { + left: auto; + } + .col-md-offset-12 { + margin-left: 100%; + } + .col-md-offset-11 { + margin-left: 91.66666667%; + } + .col-md-offset-10 { + margin-left: 83.33333333%; + } + .col-md-offset-9 { + margin-left: 75%; + } + .col-md-offset-8 { + margin-left: 66.66666667%; + } + .col-md-offset-7 { + margin-left: 58.33333333%; + } + .col-md-offset-6 { + margin-left: 50%; + } + .col-md-offset-5 { + margin-left: 41.66666667%; + } + .col-md-offset-4 { + margin-left: 33.33333333%; + } + .col-md-offset-3 { + margin-left: 25%; + } + .col-md-offset-2 { + margin-left: 16.66666667%; + } + .col-md-offset-1 { + margin-left: 8.33333333%; + } + .col-md-offset-0 { + margin-left: 0%; + } +} +@media (min-width: 1200px) { + .col-lg-1, + .col-lg-2, + .col-lg-3, + .col-lg-4, + .col-lg-5, + .col-lg-6, + .col-lg-7, + .col-lg-8, + .col-lg-9, + .col-lg-10, + .col-lg-11, + .col-lg-12 { + float: left; + } + .col-lg-12 { + width: 100%; + } + .col-lg-11 { + width: 91.66666667%; + } + .col-lg-10 { + width: 83.33333333%; + } + .col-lg-9 { + width: 75%; + } + .col-lg-8 { + width: 66.66666667%; + } + .col-lg-7 { + width: 58.33333333%; + } + .col-lg-6 { + width: 50%; + } + .col-lg-5 { + width: 41.66666667%; + } + .col-lg-4 { + width: 33.33333333%; + } + .col-lg-3 { + width: 25%; + } + .col-lg-2 { + width: 16.66666667%; + } + .col-lg-1 { + width: 8.33333333%; + } + .col-lg-pull-12 { + right: 100%; + } + .col-lg-pull-11 { + right: 91.66666667%; + } + .col-lg-pull-10 { + right: 83.33333333%; + } + .col-lg-pull-9 { + right: 75%; + } + .col-lg-pull-8 { + right: 66.66666667%; + } + .col-lg-pull-7 { + right: 58.33333333%; + } + .col-lg-pull-6 { + right: 50%; + } + .col-lg-pull-5 { + right: 41.66666667%; + } + .col-lg-pull-4 { + right: 33.33333333%; + } + .col-lg-pull-3 { + right: 25%; + } + .col-lg-pull-2 { + right: 16.66666667%; + } + .col-lg-pull-1 { + right: 8.33333333%; + } + .col-lg-pull-0 { + right: auto; + } + .col-lg-push-12 { + left: 100%; + } + .col-lg-push-11 { + left: 91.66666667%; + } + .col-lg-push-10 { + left: 83.33333333%; + } + .col-lg-push-9 { + left: 75%; + } + .col-lg-push-8 { + left: 66.66666667%; + } + .col-lg-push-7 { + left: 58.33333333%; + } + .col-lg-push-6 { + left: 50%; + } + .col-lg-push-5 { + left: 41.66666667%; + } + .col-lg-push-4 { + left: 33.33333333%; + } + .col-lg-push-3 { + left: 25%; + } + .col-lg-push-2 { + left: 16.66666667%; + } + .col-lg-push-1 { + left: 8.33333333%; + } + .col-lg-push-0 { + left: auto; + } + .col-lg-offset-12 { + margin-left: 100%; + } + .col-lg-offset-11 { + margin-left: 91.66666667%; + } + .col-lg-offset-10 { + margin-left: 83.33333333%; + } + .col-lg-offset-9 { + margin-left: 75%; + } + .col-lg-offset-8 { + margin-left: 66.66666667%; + } + .col-lg-offset-7 { + margin-left: 58.33333333%; + } + .col-lg-offset-6 { + margin-left: 50%; + } + .col-lg-offset-5 { + margin-left: 41.66666667%; + } + .col-lg-offset-4 { + margin-left: 33.33333333%; + } + .col-lg-offset-3 { + margin-left: 25%; + } + .col-lg-offset-2 { + margin-left: 16.66666667%; + } + .col-lg-offset-1 { + margin-left: 8.33333333%; + } + .col-lg-offset-0 { + margin-left: 0%; + } +} +.table { + width: 100%; + max-width: 100%; + margin-bottom: 20px; + font-size: 14px; +} +.table thead { + font-size: 12px; +} +.table > thead > tr > th, +.table > tbody > tr > th, +.table > tfoot > tr > th, +.table > thead > tr > td, +.table > tbody > tr > td, +.table > tfoot > tr > td { + padding: 8px; + line-height: 1.42857143; + vertical-align: top; + border-top: 1px solid #D3DAE6; +} +.table > thead > tr > th { + vertical-align: bottom; + border-bottom: 1px solid #D3DAE6; +} +.table > caption + thead > tr:first-child > th, +.table > colgroup + thead > tr:first-child > th, +.table > thead:first-child > tr:first-child > th, +.table > caption + thead > tr:first-child > td, +.table > colgroup + thead > tr:first-child > td, +.table > thead:first-child > tr:first-child > td { + border-top: 0; +} +.table > tbody + tbody { + border-top: 2px solid #D3DAE6; +} +.table .table { + background-color: #FFF; +} +.table-condensed > thead > tr > th, +.table-condensed > tbody > tr > th, +.table-condensed > tfoot > tr > th, +.table-condensed > thead > tr > td, +.table-condensed > tbody > tr > td, +.table-condensed > tfoot > tr > td { + padding: 5px; + font-size: 12px; +} +.table-bordered { + border: 1px solid #D3DAE6; +} +.table-bordered > thead > tr > th, +.table-bordered > tbody > tr > th, +.table-bordered > tfoot > tr > th, +.table-bordered > thead > tr > td, +.table-bordered > tbody > tr > td, +.table-bordered > tfoot > tr > td { + border: 1px solid #D3DAE6; +} +.table-bordered > thead > tr > th, +.table-bordered > thead > tr > td { + border-bottom-width: 2px; +} +.table-striped > tbody > tr:nth-of-type(odd) { + background-color: #D3DAE6; +} +.table-hover > tbody > tr:hover { + background-color: #D3DAE6; +} +table col[class*="col-"] { + position: static; + float: none; + display: table-column; +} +table td[class*="col-"], +table th[class*="col-"] { + position: static; + float: none; + display: table-cell; +} +.table > thead > tr > td.active, +.table > tbody > tr > td.active, +.table > tfoot > tr > td.active, +.table > thead > tr > th.active, +.table > tbody > tr > th.active, +.table > tfoot > tr > th.active, +.table > thead > tr.active > td, +.table > tbody > tr.active > td, +.table > tfoot > tr.active > td, +.table > thead > tr.active > th, +.table > tbody > tr.active > th, +.table > tfoot > tr.active > th { + background-color: #D3DAE6; +} +.table-hover > tbody > tr > td.active:hover, +.table-hover > tbody > tr > th.active:hover, +.table-hover > tbody > tr.active:hover > td, +.table-hover > tbody > tr:hover > .active, +.table-hover > tbody > tr.active:hover > th { + background-color: #c3ccdd; +} +.table > thead > tr > td.success, +.table > tbody > tr > td.success, +.table > tfoot > tr > td.success, +.table > thead > tr > th.success, +.table > tbody > tr > th.success, +.table > tfoot > tr > th.success, +.table > thead > tr.success > td, +.table > tbody > tr.success > td, +.table > tfoot > tr.success > td, +.table > thead > tr.success > th, +.table > tbody > tr.success > th, +.table > tfoot > tr.success > th { + background-color: #017D73; +} +.table-hover > tbody > tr > td.success:hover, +.table-hover > tbody > tr > th.success:hover, +.table-hover > tbody > tr.success:hover > td, +.table-hover > tbody > tr:hover > .success, +.table-hover > tbody > tr.success:hover > th { + background-color: #01645c; +} +.table > thead > tr > td.info, +.table > tbody > tr > td.info, +.table > tfoot > tr > td.info, +.table > thead > tr > th.info, +.table > tbody > tr > th.info, +.table > tfoot > tr > th.info, +.table > thead > tr.info > td, +.table > tbody > tr.info > td, +.table > tfoot > tr.info > td, +.table > thead > tr.info > th, +.table > tbody > tr.info > th, +.table > tfoot > tr.info > th { + background-color: #006BB4; +} +.table-hover > tbody > tr > td.info:hover, +.table-hover > tbody > tr > th.info:hover, +.table-hover > tbody > tr.info:hover > td, +.table-hover > tbody > tr:hover > .info, +.table-hover > tbody > tr.info:hover > th { + background-color: #005c9b; +} +.table > thead > tr > td.warning, +.table > tbody > tr > td.warning, +.table > tfoot > tr > td.warning, +.table > thead > tr > th.warning, +.table > tbody > tr > th.warning, +.table > tfoot > tr > th.warning, +.table > thead > tr.warning > td, +.table > tbody > tr.warning > td, +.table > tfoot > tr.warning > td, +.table > thead > tr.warning > th, +.table > tbody > tr.warning > th, +.table > tfoot > tr.warning > th { + background-color: #F5A700; +} +.table-hover > tbody > tr > td.warning:hover, +.table-hover > tbody > tr > th.warning:hover, +.table-hover > tbody > tr.warning:hover > td, +.table-hover > tbody > tr:hover > .warning, +.table-hover > tbody > tr.warning:hover > th { + background-color: #dc9600; +} +.table > thead > tr > td.danger, +.table > tbody > tr > td.danger, +.table > tfoot > tr > td.danger, +.table > thead > tr > th.danger, +.table > tbody > tr > th.danger, +.table > tfoot > tr > th.danger, +.table > thead > tr.danger > td, +.table > tbody > tr.danger > td, +.table > tfoot > tr.danger > td, +.table > thead > tr.danger > th, +.table > tbody > tr.danger > th, +.table > tfoot > tr.danger > th { + background-color: #BD271E; +} +.table-hover > tbody > tr > td.danger:hover, +.table-hover > tbody > tr > th.danger:hover, +.table-hover > tbody > tr.danger:hover > td, +.table-hover > tbody > tr:hover > .danger, +.table-hover > tbody > tr.danger:hover > th { + background-color: #a7221b; +} +.table-responsive { + overflow-x: auto; + min-height: 0.01%; +} +@media screen and (max-width: 767px) { + .table-responsive { + width: 100%; + margin-bottom: 15px; + overflow-y: hidden; + -ms-overflow-style: -ms-autohiding-scrollbar; + border: 1px solid #D3DAE6; + } + .table-responsive > .table { + margin-bottom: 0; + } + .table-responsive > .table > thead > tr > th, + .table-responsive > .table > tbody > tr > th, + .table-responsive > .table > tfoot > tr > th, + .table-responsive > .table > thead > tr > td, + .table-responsive > .table > tbody > tr > td, + .table-responsive > .table > tfoot > tr > td { + white-space: nowrap; + } + .table-responsive > .table-bordered { + border: 0; + } + .table-responsive > .table-bordered > thead > tr > th:first-child, + .table-responsive > .table-bordered > tbody > tr > th:first-child, + .table-responsive > .table-bordered > tfoot > tr > th:first-child, + .table-responsive > .table-bordered > thead > tr > td:first-child, + .table-responsive > .table-bordered > tbody > tr > td:first-child, + .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; + } + .table-responsive > .table-bordered > thead > tr > th:last-child, + .table-responsive > .table-bordered > tbody > tr > th:last-child, + .table-responsive > .table-bordered > tfoot > tr > th:last-child, + .table-responsive > .table-bordered > thead > tr > td:last-child, + .table-responsive > .table-bordered > tbody > tr > td:last-child, + .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; + } + .table-responsive > .table-bordered > tbody > tr:last-child > th, + .table-responsive > .table-bordered > tfoot > tr:last-child > th, + .table-responsive > .table-bordered > tbody > tr:last-child > td, + .table-responsive > .table-bordered > tfoot > tr:last-child > td { + border-bottom: 0; + } +} +.form-control { + display: block; + width: 100%; + height: 32px; + padding: 5px 15px; + font-size: 14px; + line-height: 1.42857143; + color: #343741; + background-color: #fafbfd; + background-image: none; + border: 1px solid #D3DAE6; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; +} +.form-control:focus { + border-color: #006BB4; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(0, 107, 180, 0.6); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(0, 107, 180, 0.6); +} +.form-control::-moz-placeholder { + color: #98A2B3; + opacity: 1; +} +.form-control:-ms-input-placeholder { + color: #98A2B3; +} +.form-control::-webkit-input-placeholder { + color: #98A2B3; +} +.form-control::-ms-expand { + border: 0; + background-color: transparent; +} +.form-control[disabled], +.form-control[readonly], +fieldset[disabled] .form-control { + background-color: #D3DAE6; + opacity: 1; +} +.form-control[disabled], +fieldset[disabled] .form-control { + cursor: not-allowed; +} +textarea.form-control { + height: auto; +} +.form-group:not(:empty) { + margin-bottom: 15px; +} +.radio, +.checkbox { + position: relative; + display: block; + margin-top: 10px; + margin-bottom: 10px; +} +.radio label, +.checkbox label { + min-height: 20px; + padding-left: 20px; + margin-bottom: 0; + font-weight: normal; + cursor: pointer; +} +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + position: absolute; + margin-left: -20px; + margin-top: 4px \9; +} +.radio + .radio, +.checkbox + .checkbox { + margin-top: -5px; +} +.radio-inline, +.checkbox-inline { + position: relative; + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + vertical-align: middle; + font-weight: normal; + cursor: pointer; +} +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; +} +.radio-inline.disabled, +.checkbox-inline.disabled, +fieldset[disabled] .radio-inline, +fieldset[disabled] .checkbox-inline { + cursor: not-allowed; +} +.radio.disabled label, +.checkbox.disabled label, +fieldset[disabled] .radio label, +fieldset[disabled] .checkbox label { + cursor: not-allowed; +} +.form-control-static { + padding-top: 6px; + padding-bottom: 6px; + margin-bottom: 0; + min-height: 34px; +} +.form-control-static.input-lg, +.form-control-static.input-sm { + padding-left: 0; + padding-right: 0; +} +.input-sm { + height: 32px; + padding: 6px 9px; + font-size: 12px; + line-height: 1.5; + border-radius: 4px; +} +select.input-sm { + height: 32px; + line-height: 32px; +} +textarea.input-sm, +select[multiple].input-sm { + height: auto; +} +.form-group-sm .form-control { + height: 32px; + padding: 6px 9px; + font-size: 12px; + line-height: 1.5; + border-radius: 4px; +} +.form-group-sm select.form-control { + height: 32px; + line-height: 32px; +} +.form-group-sm textarea.form-control, +.form-group-sm select[multiple].form-control { + height: auto; +} +.form-group-sm .form-control-static { + height: 32px; + min-height: 32px; + padding: 7px 9px; + font-size: 12px; + line-height: 1.5; +} +.input-lg { + height: 62px; + padding: 18px 27px; + font-size: 18px; + line-height: 1.3333333; + border-radius: 4px; +} +select.input-lg { + height: 62px; + line-height: 62px; +} +textarea.input-lg, +select[multiple].input-lg { + height: auto; +} +.form-group-lg .form-control { + height: 62px; + padding: 18px 27px; + font-size: 18px; + line-height: 1.3333333; + border-radius: 4px; +} +.form-group-lg select.form-control { + height: 62px; + line-height: 62px; +} +.form-group-lg textarea.form-control, +.form-group-lg select[multiple].form-control { + height: auto; +} +.form-group-lg .form-control-static { + height: 62px; + min-height: 38px; + padding: 19px 27px; + font-size: 18px; + line-height: 1.3333333; +} +.has-feedback { + position: relative; +} +.has-feedback .form-control { + padding-right: 40px; +} +.form-control-feedback { + position: absolute; + top: 0; + right: 0; + z-index: 2; + display: block; + width: 32px; + height: 32px; + line-height: 32px; + text-align: center; + pointer-events: none; +} +.input-lg + .form-control-feedback, +.input-group-lg + .form-control-feedback, +.form-group-lg .form-control + .form-control-feedback { + width: 62px; + height: 62px; + line-height: 62px; +} +.input-sm + .form-control-feedback, +.input-group-sm + .form-control-feedback, +.form-group-sm .form-control + .form-control-feedback { + width: 32px; + height: 32px; + line-height: 32px; +} +.has-success .help-block, +.has-success .control-label, +.has-success .radio, +.has-success .checkbox, +.has-success .radio-inline, +.has-success .checkbox-inline, +.has-success.radio label, +.has-success.checkbox label, +.has-success.radio-inline label, +.has-success.checkbox-inline label { + color: #FFF; +} +.has-success .form-control { + border-color: #FFF; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-success .form-control:focus { + border-color: #e6e6e6; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; +} +.has-success .input-group-addon { + color: #FFF; + border-color: #FFF; + background-color: #017D73; +} +.has-success .form-control-feedback { + color: #FFF; +} +.has-warning .help-block, +.has-warning .control-label, +.has-warning .radio, +.has-warning .checkbox, +.has-warning .radio-inline, +.has-warning .checkbox-inline, +.has-warning.radio label, +.has-warning.checkbox label, +.has-warning.radio-inline label, +.has-warning.checkbox-inline label { + color: #FFF; +} +.has-warning .form-control { + border-color: #FFF; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-warning .form-control:focus { + border-color: #e6e6e6; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; +} +.has-warning .input-group-addon { + color: #FFF; + border-color: #FFF; + background-color: #F5A700; +} +.has-warning .form-control-feedback { + color: #FFF; +} +.has-error .help-block, +.has-error .control-label, +.has-error .radio, +.has-error .checkbox, +.has-error .radio-inline, +.has-error .checkbox-inline, +.has-error.radio label, +.has-error.checkbox label, +.has-error.radio-inline label, +.has-error.checkbox-inline label { + color: #FFF; +} +.has-error .form-control { + border-color: #FFF; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} +.has-error .form-control:focus { + border-color: #e6e6e6; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffffff; +} +.has-error .input-group-addon { + color: #FFF; + border-color: #FFF; + background-color: #BD271E; +} +.has-error .form-control-feedback { + color: #FFF; +} +.has-feedback label ~ .form-control-feedback { + top: 25px; +} +.has-feedback label.sr-only ~ .form-control-feedback { + top: 0; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 10px; + color: #6d7388; +} +@media (min-width: 768px) { + .form-inline .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .form-inline .form-control-static { + display: inline-block; + } + .form-inline .input-group { + display: inline-table; + vertical-align: middle; + } + .form-inline .input-group .input-group-addon, + .form-inline .input-group .form-control { + width: auto; + } + .form-inline .input-group > .form-control { + width: 100%; + } + .form-inline .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio, + .form-inline .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio label, + .form-inline .checkbox label { + padding-left: 0; + } + .form-inline .radio input[type="radio"], + .form-inline .checkbox input[type="checkbox"] { + position: relative; + margin-left: 0; + } + .form-inline .has-feedback .form-control-feedback { + top: 0; + } +} +.form-horizontal .radio, +.form-horizontal .checkbox, +.form-horizontal .radio-inline, +.form-horizontal .checkbox-inline { + margin-top: 0; + margin-bottom: 0; + padding-top: 6px; +} +.form-horizontal .radio, +.form-horizontal .checkbox { + min-height: 26px; +} +.form-horizontal .form-group { + margin-left: -15px; + margin-right: -15px; +} +@media (min-width: 768px) { + .form-horizontal .control-label { + text-align: right; + margin-bottom: 0; + padding-top: 6px; + } +} +.form-horizontal .has-feedback .form-control-feedback { + right: 15px; +} +@media (min-width: 768px) { + .form-horizontal .form-group-lg .control-label { + padding-top: 19px; + font-size: 18px; + } +} +@media (min-width: 768px) { + .form-horizontal .form-group-sm .control-label { + padding-top: 7px; + font-size: 12px; + } +} +.text-left { + text-align: left; +} +.text-right { + text-align: right; +} +.text-center { + text-align: center; +} +.text-muted { + color: #b2bac6; +} +.text-primary { + color: #343741; +} +a.text-primary:hover, +a.text-primary:focus { + color: #1d1f25; +} +.text-success { + color: #FFF; +} +a.text-success:hover, +a.text-success:focus { + color: #e6e6e6; +} +.text-info { + color: #FFF; +} +a.text-info:hover, +a.text-info:focus { + color: #e6e6e6; +} +.text-warning { + color: #FFF; +} +a.text-warning:hover, +a.text-warning:focus { + color: #e6e6e6; +} +.text-danger { + color: #FFF; +} +a.text-danger:hover, +a.text-danger:focus { + color: #e6e6e6; +} +.bg-info { + background-color: #006BB4; +} +a.bg-info:hover, +a.bg-info:focus { + background-color: #004d81; +} +.list-unstyled { + padding-left: 0; + list-style: none; +} +@media (min-width: 0) { + .dl-horizontal dt { + float: left; + width: 160px; + clear: left; + text-align: right; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .dl-horizontal dd { + margin-left: 180px; + } +} +.fade { + opacity: 0; + -webkit-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} +.fade.in { + opacity: 1; +} +.collapse { + display: none; +} +.collapse.in { + display: block; +} +tr.collapse.in { + display: table-row; +} +tbody.collapse.in { + display: table-row-group; +} +.collapsing { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition-property: height, visibility; + transition-property: height, visibility; + -webkit-transition-duration: 0.35s; + transition-duration: 0.35s; + -webkit-transition-timing-function: ease; + transition-timing-function: ease; +} +/** + * ui/angular-ui-select depends upon these styles. Don't use them in your markup. + * Please use the UI Framework styles instead. + */ +.btn { + display: inline-block; + margin-bottom: 0; + font-weight: normal; + text-align: center; + vertical-align: middle; + touch-action: manipulation; + cursor: pointer; + background-image: none; + border: 1px solid transparent; + white-space: nowrap; + padding: 5px 15px; + font-size: 14px; + line-height: 1.42857143; + border-radius: 4px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.btn:focus, +.btn:active:focus, +.btn.active:focus, +.btn.focus, +.btn:active.focus, +.btn.active.focus { + box-shadow: 0 0 0 1px white, 0 0 0 2px #0079a5; + /* 3 */ +} +.btn:hover, +.btn:focus, +.btn.focus { + color: #FFF; + text-decoration: none; +} +.btn:active, +.btn.active { + outline: 0; + background-image: none; + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); +} +.btn.disabled, +.btn[disabled], +fieldset[disabled] .btn { + cursor: not-allowed; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + box-shadow: none; +} +a.btn.disabled, +fieldset[disabled] a.btn { + pointer-events: none; +} +.btn-default { + color: #FFF; + background-color: #006BB4; + border-color: #006BB4; +} +.btn-default:focus, +.btn-default.focus { + color: #FFF; + background-color: #004d81; + border-color: #001f35; +} +.btn-default:hover { + color: #FFF; + background-color: #004d81; + border-color: #004777; +} +.btn-default:active, +.btn-default.active, +.open > .dropdown-toggle.btn-default { + color: #FFF; + background-color: #004d81; + border-color: #004777; +} +.btn-default:active:hover, +.btn-default.active:hover, +.open > .dropdown-toggle.btn-default:hover, +.btn-default:active:focus, +.btn-default.active:focus, +.open > .dropdown-toggle.btn-default:focus, +.btn-default:active.focus, +.btn-default.active.focus, +.open > .dropdown-toggle.btn-default.focus { + color: #FFF; + background-color: #00375d; + border-color: #001f35; +} +.btn-default:active, +.btn-default.active, +.open > .dropdown-toggle.btn-default { + background-image: none; +} +.btn-default.disabled:hover, +.btn-default[disabled]:hover, +fieldset[disabled] .btn-default:hover, +.btn-default.disabled:focus, +.btn-default[disabled]:focus, +fieldset[disabled] .btn-default:focus, +.btn-default.disabled.focus, +.btn-default[disabled].focus, +fieldset[disabled] .btn-default.focus { + background-color: #006BB4; + border-color: #006BB4; +} +.btn-default .badge { + color: #006BB4; + background-color: #FFF; +} +.btn-primary { + color: #FFF; + background-color: #006BB4; + border-color: #006BB4; +} +.btn-primary:focus, +.btn-primary.focus { + color: #FFF; + background-color: #004d81; + border-color: #001f35; +} +.btn-primary:hover { + color: #FFF; + background-color: #004d81; + border-color: #004777; +} +.btn-primary:active, +.btn-primary.active, +.open > .dropdown-toggle.btn-primary { + color: #FFF; + background-color: #004d81; + border-color: #004777; +} +.btn-primary:active:hover, +.btn-primary.active:hover, +.open > .dropdown-toggle.btn-primary:hover, +.btn-primary:active:focus, +.btn-primary.active:focus, +.open > .dropdown-toggle.btn-primary:focus, +.btn-primary:active.focus, +.btn-primary.active.focus, +.open > .dropdown-toggle.btn-primary.focus { + color: #FFF; + background-color: #00375d; + border-color: #001f35; +} +.btn-primary:active, +.btn-primary.active, +.open > .dropdown-toggle.btn-primary { + background-image: none; +} +.btn-primary.disabled:hover, +.btn-primary[disabled]:hover, +fieldset[disabled] .btn-primary:hover, +.btn-primary.disabled:focus, +.btn-primary[disabled]:focus, +fieldset[disabled] .btn-primary:focus, +.btn-primary.disabled.focus, +.btn-primary[disabled].focus, +fieldset[disabled] .btn-primary.focus { + background-color: #006BB4; + border-color: #006BB4; +} +.btn-primary .badge { + color: #006BB4; + background-color: #FFF; +} +.btn-xs { + padding: 1px 5px; + font-size: 12px; + line-height: 1.5; + border-radius: 4px; +} +.navbar { + position: relative; + min-height: 45px; + margin-bottom: 0px; + border: 1px solid transparent; +} +@media (min-width: 0) { + .navbar { + border-radius: 4px; + } +} +@media (min-width: 0) { + .navbar-header { + float: left; + } +} +.navbar-collapse { + overflow-x: visible; + padding-right: 10px; + padding-left: 10px; + border-top: 1px solid transparent; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); + -webkit-overflow-scrolling: touch; +} +.navbar-collapse.in { + overflow-y: auto; +} +@media (min-width: 0) { + .navbar-collapse { + width: auto; + border-top: 0; + box-shadow: none; + } + .navbar-collapse.collapse { + display: block !important; + height: auto !important; + padding-bottom: 0; + overflow: visible !important; + } + .navbar-collapse.in { + overflow-y: visible; + } + .navbar-fixed-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + padding-left: 0; + padding-right: 0; + } +} +.navbar-fixed-top .navbar-collapse, +.navbar-fixed-bottom .navbar-collapse { + max-height: 340px; +} +@media (max-device-width: 480px) and (orientation: landscape) { + .navbar-fixed-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + max-height: 200px; + } +} +.container > .navbar-header, +.container-fluid > .navbar-header, +.container > .navbar-collapse, +.container-fluid > .navbar-collapse { + margin-right: -10px; + margin-left: -10px; +} +@media (min-width: 0) { + .container > .navbar-header, + .container-fluid > .navbar-header, + .container > .navbar-collapse, + .container-fluid > .navbar-collapse { + margin-right: 0; + margin-left: 0; + } +} +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1050; +} +@media (min-width: 0) { + .navbar-fixed-top, + .navbar-fixed-bottom { + border-radius: 0; + } +} +.navbar-fixed-top { + top: 0; + border-width: 0 0 1px; +} +.navbar-fixed-bottom { + bottom: 0; + margin-bottom: 0; + border-width: 1px 0 0; +} +.navbar-brand { + float: left; + padding: 12.5px 10px; + font-size: 18px; + line-height: 20px; + height: 45px; +} +.navbar-brand:hover, +.navbar-brand:focus { + text-decoration: none; +} +.navbar-brand > img { + display: block; +} +@media (min-width: 0) { + .navbar > .container .navbar-brand, + .navbar > .container-fluid .navbar-brand { + margin-left: -10px; + } +} +.navbar-toggle { + position: relative; + float: right; + margin-right: 10px; + padding: 9px 10px; + margin-top: 5.5px; + margin-bottom: 5.5px; + background-color: transparent; + background-image: none; + border: 1px solid transparent; + border-radius: 4px; +} +.navbar-toggle:focus { + outline: 0; +} +.navbar-toggle .icon-bar { + display: block; + width: 22px; + height: 2px; + border-radius: 1px; +} +.navbar-toggle .icon-bar + .icon-bar { + margin-top: 4px; +} +@media (min-width: 0) { + .navbar-toggle { + display: none; + } +} +.navbar-nav { + margin: 6.25px -10px; +} +.navbar-nav > li > a { + padding-top: 10px; + padding-bottom: 10px; + line-height: 20px; +} +@media (max-width: -1) { + .navbar-nav .open .dropdown-menu { + position: static; + float: none; + width: auto; + margin-top: 0; + background-color: transparent; + border: 0; + box-shadow: none; + } + .navbar-nav .open .dropdown-menu > li > a, + .navbar-nav .open .dropdown-menu .dropdown-header { + padding: 5px 15px 5px 25px; + } + .navbar-nav .open .dropdown-menu > li > a { + line-height: 20px; + } + .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-nav .open .dropdown-menu > li > a:focus { + background-image: none; + } +} +@media (min-width: 0) { + .navbar-nav { + float: left; + margin: 0; + } + .navbar-nav > li { + float: left; + } + .navbar-nav > li > a { + padding-top: 12.5px; + padding-bottom: 12.5px; + } +} +.navbar-form { + margin-left: -10px; + margin-right: -10px; + padding: 10px 10px; + border-top: 1px solid transparent; + border-bottom: 1px solid transparent; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + margin-top: 6.5px; + margin-bottom: 6.5px; +} +@media (min-width: 768px) { + .navbar-form .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .navbar-form .form-control-static { + display: inline-block; + } + .navbar-form .input-group { + display: inline-table; + vertical-align: middle; + } + .navbar-form .input-group .input-group-addon, + .navbar-form .input-group .form-control { + width: auto; + } + .navbar-form .input-group > .form-control { + width: 100%; + } + .navbar-form .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio, + .navbar-form .checkbox { + display: inline-block; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio label, + .navbar-form .checkbox label { + padding-left: 0; + } + .navbar-form .radio input[type="radio"], + .navbar-form .checkbox input[type="checkbox"] { + position: relative; + margin-left: 0; + } + .navbar-form .has-feedback .form-control-feedback { + top: 0; + } +} +@media (max-width: -1) { + .navbar-form .form-group { + margin-bottom: 5px; + } + .navbar-form .form-group:last-child { + margin-bottom: 0; + } +} +@media (min-width: 0) { + .navbar-form { + width: auto; + border: 0; + margin-left: 0; + margin-right: 0; + padding-top: 0; + padding-bottom: 0; + -webkit-box-shadow: none; + box-shadow: none; + } +} +.navbar-nav > li > .dropdown-menu { + margin-top: 0; + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { + margin-bottom: 0; + border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.navbar-text { + margin-top: 12.5px; + margin-bottom: 12.5px; +} +@media (min-width: 0) { + .navbar-text { + float: left; + margin-left: 10px; + margin-right: 10px; + } +} +@media (min-width: 0) { + .navbar-left { + float: left !important; + } + .navbar-right { + float: right !important; + margin-right: -10px; + } + .navbar-right ~ .navbar-right { + margin-right: 0; + } +} +.navbar-default { + background-color: #F5F7FA; + border-color: transparent; +} +.navbar-default .navbar-brand { + color: #69707D; +} +.navbar-default .navbar-brand:hover, +.navbar-default .navbar-brand:focus { + color: #69707D; + background-color: transparent; +} +.navbar-default .navbar-text { + color: #69707D; +} +.navbar-default .navbar-nav > li > a { + color: #69707D; +} +.navbar-default .navbar-nav > li > a:hover, +.navbar-default .navbar-nav > li > a:focus { + color: #69707D; + background-color: transparent; +} +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + color: #343741; + background-color: transparent; +} +.navbar-default .navbar-nav > .disabled > a, +.navbar-default .navbar-nav > .disabled > a:hover, +.navbar-default .navbar-nav > .disabled > a:focus { + color: #69707D; + background-color: transparent; +} +.navbar-default .navbar-toggle { + border-color: #d3dce9; +} +.navbar-default .navbar-toggle:hover, +.navbar-default .navbar-toggle:focus { + background-color: #d3dce9; +} +.navbar-default .navbar-toggle .icon-bar { + background-color: #FFF; +} +.navbar-default .navbar-collapse, +.navbar-default .navbar-form { + border-color: transparent; +} +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .open > a:hover, +.navbar-default .navbar-nav > .open > a:focus { + background-color: transparent; + color: #343741; +} +@media (max-width: -1) { + .navbar-default .navbar-nav .open .dropdown-menu > li > a { + color: #69707D; + } + .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { + color: #69707D; + background-color: transparent; + } + .navbar-default .navbar-nav .open .dropdown-menu > .active > a, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #343741; + background-color: transparent; + } + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #69707D; + background-color: transparent; + } +} +.navbar-default .navbar-link { + color: #69707D; +} +.navbar-default .navbar-link:hover { + color: #69707D; +} +.navbar-inverse { + background-color: #343741; + border-color: #1d1f25; +} +.navbar-inverse .navbar-brand { + color: #FFF; +} +.navbar-inverse .navbar-brand:hover, +.navbar-inverse .navbar-brand:focus { + color: #FFF; + background-color: #4b4f5d; +} +.navbar-inverse .navbar-text { + color: #FFF; +} +.navbar-inverse .navbar-nav > li > a { + color: #D3DAE6; +} +.navbar-inverse .navbar-nav > li > a:hover, +.navbar-inverse .navbar-nav > li > a:focus { + color: #FFF; + background-color: #61677a; +} +.navbar-inverse .navbar-nav > .active > a, +.navbar-inverse .navbar-nav > .active > a:hover, +.navbar-inverse .navbar-nav > .active > a:focus { + color: #FFF; + background-color: #69707D; +} +.navbar-inverse .navbar-nav > .disabled > a, +.navbar-inverse .navbar-nav > .disabled > a:hover, +.navbar-inverse .navbar-nav > .disabled > a:focus { + color: #b2bac6; + background-color: transparent; +} +.navbar-inverse .navbar-toggle { + border-color: #1d1f25; +} +.navbar-inverse .navbar-toggle:hover, +.navbar-inverse .navbar-toggle:focus { + background-color: #1d1f25; +} +.navbar-inverse .navbar-toggle .icon-bar { + background-color: #FFF; +} +.navbar-inverse .navbar-collapse, +.navbar-inverse .navbar-form { + border-color: #24262d; +} +.navbar-inverse .navbar-nav > .open > a, +.navbar-inverse .navbar-nav > .open > a:hover, +.navbar-inverse .navbar-nav > .open > a:focus { + background-color: #69707D; + color: #FFF; +} +@media (max-width: -1) { + .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { + border-color: #1d1f25; + } + .navbar-inverse .navbar-nav .open .dropdown-menu .divider { + background-color: #1d1f25; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { + color: #D3DAE6; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { + color: #FFF; + background-color: #61677a; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #FFF; + background-color: #69707D; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #b2bac6; + background-color: transparent; + } +} +.navbar-inverse .navbar-link { + color: #D3DAE6; +} +.navbar-inverse .navbar-link:hover { + color: #FFF; +} +.close { + float: right; + font-size: 21px; + font-weight: bold; + line-height: 1; + color: #000; + text-shadow: none; + opacity: 0.2; + filter: alpha(opacity=20); +} +.close:hover, +.close:focus { + color: #000; + text-decoration: none; + cursor: pointer; + opacity: 0.5; + filter: alpha(opacity=50); +} +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} +.modal-open { + overflow: hidden; +} +.modal { + display: none; + overflow: hidden; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1070; + -webkit-overflow-scrolling: touch; + outline: 0; +} +.modal.fade .modal-dialog { + -webkit-transform: translate(0, -25%); + -ms-transform: translate(0, -25%); + -o-transform: translate(0, -25%); + transform: translate(0, -25%); + -webkit-transition: -webkit-transform 0.3s ease-out; + -moz-transition: -moz-transform 0.3s ease-out; + -o-transition: -o-transform 0.3s ease-out; + transition: transform 0.3s ease-out; +} +.modal.in .modal-dialog { + -webkit-transform: translate(0, 0); + -ms-transform: translate(0, 0); + -o-transform: translate(0, 0); + transform: translate(0, 0); +} +.modal-open .modal { + overflow-x: hidden; + overflow-y: auto; +} +.modal-dialog { + position: relative; + width: auto; + margin: 10px; +} +.modal-content { + position: relative; + background-color: #FFF; + border: 1px solid #98A2B3; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 4px; + -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); + background-clip: padding-box; + outline: 0; +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1060; + background-color: #000; +} +.modal-backdrop.fade { + opacity: 0; + filter: alpha(opacity=0); +} +.modal-backdrop.in { + opacity: 0.5; + filter: alpha(opacity=50); +} +.modal-header { + padding: 15px; + border-bottom: 1px solid #e5e5e5; +} +.modal-header .close { + margin-top: -2px; +} +.modal-title { + margin: 0; + line-height: 1.42857143; +} +.modal-body { + position: relative; + padding: 15px; +} +.modal-footer { + padding: 15px; + text-align: right; + border-top: 1px solid #e5e5e5; +} +.modal-scrollbar-measure { + position: absolute; + top: -9999px; + width: 50px; + height: 50px; + overflow: scroll; +} +@media (min-width: 768px) { + .modal-dialog { + width: 600px; + margin: 30px auto; + } + .modal-content { + -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); + } + .modal-sm { + width: 300px; + } +} +@media (min-width: 992px) { + .modal-lg { + width: 900px; + } +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +.progress { + overflow: hidden; + height: 20px; + margin-bottom: 20px; + background-color: #b8bec8; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} +.progress-bar { + float: left; + width: 0%; + height: 100%; + font-size: 12px; + line-height: 20px; + color: #FFF; + text-align: center; + background-color: #54B399; + -webkit-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} +.progress-striped .progress-bar, +.progress-bar-striped { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-size: 40px 40px; +} +.progress.active .progress-bar, +.progress-bar.active { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-bar-success { + background-color: #017D73; +} +.progress-striped .progress-bar-success { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-info { + background-color: #006BB4; +} +.progress-striped .progress-bar-info { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-warning { + background-color: #F5A700; +} +.progress-striped .progress-bar-warning { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.progress-bar-danger { + background-color: #BD271E; +} +.progress-striped .progress-bar-danger { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} +.list-group { + margin-bottom: 20px; + padding-left: 0; +} +.list-group-item { + position: relative; + display: block; + padding: 10px 15px; + margin-bottom: -1px; + background-color: #FFF; + border: 1px solid #D3DAE6; +} +.list-group-item:first-child { + border-top-right-radius: 4px; + border-top-left-radius: 4px; +} +.list-group-item:last-child { + margin-bottom: 0; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} +.list-group-item--noBorder { + border-top: 0; +} +a.list-group-item, +button.list-group-item { + color: #69707D; +} +a.list-group-item .list-group-item-heading, +button.list-group-item .list-group-item-heading { + color: #343741; +} +a.list-group-item:hover, +button.list-group-item:hover, +a.list-group-item:focus, +button.list-group-item:focus { + text-decoration: none; + color: #69707D; + background-color: #F5F7FA; +} +button.list-group-item { + width: 100%; + text-align: left; +} +.list-group-item.disabled, +.list-group-item.disabled:hover, +.list-group-item.disabled:focus { + background-color: #D3DAE6; + color: #b2bac6; + cursor: not-allowed; +} +.list-group-item.disabled .list-group-item-heading, +.list-group-item.disabled:hover .list-group-item-heading, +.list-group-item.disabled:focus .list-group-item-heading { + color: inherit; +} +.list-group-item.disabled .list-group-item-text, +.list-group-item.disabled:hover .list-group-item-text, +.list-group-item.disabled:focus .list-group-item-text { + color: #b2bac6; +} +.list-group-item.active, +.list-group-item.active:hover, +.list-group-item.active:focus { + z-index: 2; + color: #343741; + background-color: #343741; + border-color: #343741; +} +.list-group-item.active .list-group-item-heading, +.list-group-item.active:hover .list-group-item-heading, +.list-group-item.active:focus .list-group-item-heading, +.list-group-item.active .list-group-item-heading > small, +.list-group-item.active:hover .list-group-item-heading > small, +.list-group-item.active:focus .list-group-item-heading > small, +.list-group-item.active .list-group-item-heading > .small, +.list-group-item.active:hover .list-group-item-heading > .small, +.list-group-item.active:focus .list-group-item-heading > .small { + color: inherit; +} +.list-group-item.active .list-group-item-text, +.list-group-item.active:hover .list-group-item-text, +.list-group-item.active:focus .list-group-item-text { + color: #969bab; +} +.list-group-item-success { + color: #FFF; + background-color: #017D73; +} +a.list-group-item-success, +button.list-group-item-success { + color: #FFF; +} +a.list-group-item-success .list-group-item-heading, +button.list-group-item-success .list-group-item-heading { + color: inherit; +} +a.list-group-item-success:hover, +button.list-group-item-success:hover, +a.list-group-item-success:focus, +button.list-group-item-success:focus { + color: #FFF; + background-color: #01645c; +} +a.list-group-item-success.active, +button.list-group-item-success.active, +a.list-group-item-success.active:hover, +button.list-group-item-success.active:hover, +a.list-group-item-success.active:focus, +button.list-group-item-success.active:focus { + color: #fff; + background-color: #FFF; + border-color: #FFF; +} +.list-group-item-info { + color: #FFF; + background-color: #006BB4; +} +a.list-group-item-info, +button.list-group-item-info { + color: #FFF; +} +a.list-group-item-info .list-group-item-heading, +button.list-group-item-info .list-group-item-heading { + color: inherit; +} +a.list-group-item-info:hover, +button.list-group-item-info:hover, +a.list-group-item-info:focus, +button.list-group-item-info:focus { + color: #FFF; + background-color: #005c9b; +} +a.list-group-item-info.active, +button.list-group-item-info.active, +a.list-group-item-info.active:hover, +button.list-group-item-info.active:hover, +a.list-group-item-info.active:focus, +button.list-group-item-info.active:focus { + color: #fff; + background-color: #FFF; + border-color: #FFF; +} +.list-group-item-warning { + color: #FFF; + background-color: #F5A700; +} +a.list-group-item-warning, +button.list-group-item-warning { + color: #FFF; +} +a.list-group-item-warning .list-group-item-heading, +button.list-group-item-warning .list-group-item-heading { + color: inherit; +} +a.list-group-item-warning:hover, +button.list-group-item-warning:hover, +a.list-group-item-warning:focus, +button.list-group-item-warning:focus { + color: #FFF; + background-color: #dc9600; +} +a.list-group-item-warning.active, +button.list-group-item-warning.active, +a.list-group-item-warning.active:hover, +button.list-group-item-warning.active:hover, +a.list-group-item-warning.active:focus, +button.list-group-item-warning.active:focus { + color: #fff; + background-color: #FFF; + border-color: #FFF; +} +.list-group-item-danger { + color: #FFF; + background-color: #BD271E; +} +a.list-group-item-danger, +button.list-group-item-danger { + color: #FFF; +} +a.list-group-item-danger .list-group-item-heading, +button.list-group-item-danger .list-group-item-heading { + color: inherit; +} +a.list-group-item-danger:hover, +button.list-group-item-danger:hover, +a.list-group-item-danger:focus, +button.list-group-item-danger:focus { + color: #FFF; + background-color: #a7221b; +} +a.list-group-item-danger.active, +button.list-group-item-danger.active, +a.list-group-item-danger.active:hover, +button.list-group-item-danger.active:hover, +a.list-group-item-danger.active:focus, +button.list-group-item-danger.active:focus { + color: #fff; + background-color: #FFF; + border-color: #FFF; +} +.list-group-item-heading { + margin-top: 0; + margin-bottom: 5px; +} +.list-group-item-text { + margin-bottom: 0; + line-height: 1.3; +} +.nav { + margin-bottom: 0; + padding-left: 0; + list-style: none; +} +.nav > li { + position: relative; + display: block; +} +.nav > li > a { + position: relative; + display: block; + padding: 10px 15px; +} +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #D3DAE6; +} +.nav > li.disabled > a { + color: #b2bac6; +} +.nav > li.disabled > a:hover, +.nav > li.disabled > a:focus { + color: #b2bac6; + text-decoration: none; + background-color: transparent; + cursor: not-allowed; +} +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + background-color: #D3DAE6; + border-color: #006BB4; +} +.nav .nav-divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.nav > li > a > img { + max-width: none; +} +.nav-tabs { + border-bottom: 1px solid #D3DAE6; +} +.nav-tabs > li { + float: left; + margin-bottom: -1px; +} +.nav-tabs > li > a { + margin-right: 2px; + line-height: 1.42857143; + border: 1px solid transparent; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #D3DAE6; + background-color: #FFF; +} +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + color: #343741; + background-color: #FFF; + border: 1px solid #D3DAE6; + border-bottom-color: transparent; + cursor: default; +} +.nav-tabs.nav-justified { + width: 100%; + border-bottom: 0; +} +.nav-tabs.nav-justified > li { + float: none; +} +.nav-tabs.nav-justified > li > a { + text-align: center; + margin-bottom: 5px; +} +.nav-tabs.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-tabs.nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs.nav-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs.nav-justified > .active > a, +.nav-tabs.nav-justified > .active > a:hover, +.nav-tabs.nav-justified > .active > a:focus { + border: 1px solid #FFF; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li > a { + border-bottom: 1px solid #FFF; + border-radius: 4px 4px 0 0; + } + .nav-tabs.nav-justified > .active > a, + .nav-tabs.nav-justified > .active > a:hover, + .nav-tabs.nav-justified > .active > a:focus { + border-bottom-color: #FFF; + } +} +.nav-pills > li { + float: left; +} +.nav-pills > li > a { + border-radius: 4px; +} +.nav-pills > li + li { + margin-left: 2px; +} +.nav-pills > li.active > a, +.nav-pills > li.active > a:hover, +.nav-pills > li.active > a:focus { + color: #FFF; + background-color: #006BB4; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li + li { + margin-top: 2px; + margin-left: 0; +} +.nav-justified { + width: 100%; +} +.nav-justified > li { + float: none; +} +.nav-justified > li > a { + text-align: center; + margin-bottom: 5px; +} +.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs-justified { + border-bottom: 0; +} +.nav-tabs-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs-justified > .active > a, +.nav-tabs-justified > .active > a:hover, +.nav-tabs-justified > .active > a:focus { + border: 1px solid #FFF; +} +@media (min-width: 768px) { + .nav-tabs-justified > li > a { + border-bottom: 1px solid #FFF; + border-radius: 4px 4px 0 0; + } + .nav-tabs-justified > .active > a, + .nav-tabs-justified > .active > a:hover, + .nav-tabs-justified > .active > a:focus { + border-bottom-color: #FFF; + } +} +.tab-content > .tab-pane { + display: none; +} +.tab-content > .active { + display: block; +} +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.alert { + padding: 15px; + margin-bottom: 20px; + border: 1px solid transparent; + border-radius: 4px; +} +.alert h4 { + margin-top: 0; + color: inherit; +} +.alert .alert-link { + font-weight: bold; +} +.alert > p, +.alert > ul { + margin-bottom: 0; +} +.alert > p + p { + margin-top: 5px; +} +.alert-dismissable, +.alert-dismissible { + padding-right: 35px; +} +.alert-dismissable .close, +.alert-dismissible .close { + position: relative; + top: -2px; + right: -21px; + color: inherit; +} +.alert-success { + background-color: #017D73; + border-color: #014a44; + color: #FFF; +} +.alert-success hr { + border-top-color: #00312d; +} +.alert-success .alert-link { + color: #e6e6e6; +} +.alert-info { + background-color: #006BB4; + border-color: #004d81; + color: #FFF; +} +.alert-info hr { + border-top-color: #003e68; +} +.alert-info .alert-link { + color: #e6e6e6; +} +.alert-warning { + background-color: #F5A700; + border-color: #c28400; + color: #FFF; +} +.alert-warning hr { + border-top-color: #a97300; +} +.alert-warning .alert-link { + color: #e6e6e6; +} +.alert-danger { + background-color: #BD271E; + border-color: #911e17; + color: #FFF; +} +.alert-danger hr { + border-top-color: #7b1914; +} +.alert-danger .alert-link { + color: #e6e6e6; +} +.bsTooltip { + position: absolute; + z-index: 1040; + display: block; + font-family: 'Open Sans', Helvetica, Arial, sans-serif; + font-style: normal; + font-weight: normal; + letter-spacing: normal; + line-break: auto; + line-height: 1.42857143; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + white-space: normal; + word-break: normal; + word-spacing: normal; + word-wrap: normal; + font-size: 12px; + opacity: 0; + filter: alpha(opacity=0); +} +.bsTooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} +.bsTooltip.top { + margin-top: -3px; + padding: 5px 0; +} +.bsTooltip.right { + margin-left: 3px; + padding: 0 5px; +} +.bsTooltip.bottom { + margin-top: 3px; + padding: 5px 0; +} +.bsTooltip.left { + margin-left: -3px; + padding: 0 5px; +} +.bsTooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #fff; + text-align: center; + background-color: #000; + border-radius: 4px; +} +.bsTooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.bsTooltip.top .bsTooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-width: 5px 5px 0; + border-top-color: #000; +} +.bsTooltip.top-left .bsTooltip-arrow { + bottom: 0; + right: 5px; + margin-bottom: -5px; + border-width: 5px 5px 0; + border-top-color: #000; +} +.bsTooltip.top-right .bsTooltip-arrow { + bottom: 0; + left: 5px; + margin-bottom: -5px; + border-width: 5px 5px 0; + border-top-color: #000; +} +.bsTooltip.right .bsTooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-width: 5px 5px 5px 0; + border-right-color: #000; +} +.bsTooltip.left .bsTooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-width: 5px 0 5px 5px; + border-left-color: #000; +} +.bsTooltip.bottom .bsTooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000; +} +.bsTooltip.bottom-left .bsTooltip-arrow { + top: 0; + right: 5px; + margin-top: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000; +} +.bsTooltip.bottom-right .bsTooltip-arrow { + top: 0; + left: 5px; + margin-top: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000; +} +.visible-xs, +.visible-sm, +.visible-md, +.visible-lg { + display: none !important; +} +.visible-xs-block, +.visible-xs-inline, +.visible-xs-inline-block, +.visible-sm-block, +.visible-sm-inline, +.visible-sm-inline-block, +.visible-md-block, +.visible-md-inline, +.visible-md-inline-block, +.visible-lg-block, +.visible-lg-inline, +.visible-lg-inline-block { + display: none !important; +} +@media (max-width: 767px) { + .visible-xs { + display: block !important; + } + table.visible-xs { + display: table !important; + } + tr.visible-xs { + display: table-row !important; + } + th.visible-xs, + td.visible-xs { + display: table-cell !important; + } +} +@media (max-width: 767px) { + .visible-xs-block { + display: block !important; + } +} +@media (max-width: 767px) { + .visible-xs-inline { + display: inline !important; + } +} +@media (max-width: 767px) { + .visible-xs-inline-block { + display: inline-block !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm { + display: block !important; + } + table.visible-sm { + display: table !important; + } + tr.visible-sm { + display: table-row !important; + } + th.visible-sm, + td.visible-sm { + display: table-cell !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-block { + display: block !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-inline { + display: inline !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .visible-sm-inline-block { + display: inline-block !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md { + display: block !important; + } + table.visible-md { + display: table !important; + } + tr.visible-md { + display: table-row !important; + } + th.visible-md, + td.visible-md { + display: table-cell !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-block { + display: block !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-inline { + display: inline !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .visible-md-inline-block { + display: inline-block !important; + } +} +@media (min-width: 1200px) { + .visible-lg { + display: block !important; + } + table.visible-lg { + display: table !important; + } + tr.visible-lg { + display: table-row !important; + } + th.visible-lg, + td.visible-lg { + display: table-cell !important; + } +} +@media (min-width: 1200px) { + .visible-lg-block { + display: block !important; + } +} +@media (min-width: 1200px) { + .visible-lg-inline { + display: inline !important; + } +} +@media (min-width: 1200px) { + .visible-lg-inline-block { + display: inline-block !important; + } +} +@media (max-width: 767px) { + .hidden-xs { + display: none !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .hidden-sm { + display: none !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-md { + display: none !important; + } +} +@media (min-width: 1200px) { + .hidden-lg { + display: none !important; + } +} +.visible-print { + display: none !important; +} +@media print { + .visible-print { + display: block !important; + } + table.visible-print { + display: table !important; + } + tr.visible-print { + display: table-row !important; + } + th.visible-print, + td.visible-print { + display: table-cell !important; + } +} +.visible-print-block { + display: none !important; +} +@media print { + .visible-print-block { + display: block !important; + } +} +.visible-print-inline { + display: none !important; +} +@media print { + .visible-print-inline { + display: inline !important; + } +} +.visible-print-inline-block { + display: none !important; +} +@media print { + .visible-print-inline-block { + display: inline-block !important; + } +} +@media print { + .hidden-print { + display: none !important; + } +} +.caret { + display: inline-block; + width: 0; + height: 0; + margin-left: 2px; + vertical-align: middle; + border-top: 4px dashed; + border-top: 4px solid \9; + border-right: 4px solid transparent; + border-left: 4px solid transparent; +} +.dropup, +.dropdown { + position: relative; +} +.dropdown-toggle:focus { + outline: 0; +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + list-style: none; + font-size: 14px; + text-align: left; + background-color: #FFF; + border: 1px solid #D3DAE6; + border-radius: 4px; + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.1); + background-clip: padding-box; +} +.dropdown-menu.pull-right { + right: 0; + left: auto; +} +.dropdown-menu .divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #D3DAE6; +} +.dropdown-menu > li > a, +.dropdown-menu > li > button { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 1.42857143; + color: #7b7b7b; + white-space: nowrap; +} +.dropdown-menu > li > button { + appearance: none; + background: none; + border: none; + width: 100%; + text-align: left; +} +.dropdown-menu > li > a:hover, +.dropdown-menu > li > button:hover, +.dropdown-menu > li > a:focus, +.dropdown-menu > li > button:focus { + text-decoration: none; + color: #FFF; + background-color: #343741; +} +.dropdown-menu > .active > button, +.dropdown-menu > .active > a, +.dropdown-menu > .active > button:hover, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > button:focus, +.dropdown-menu > .active > a:focus { + color: #FFF; + text-decoration: none; + outline: 0; + background-color: #343741; +} +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #98A2B3; +} +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + cursor: not-allowed; +} +.open > .dropdown-menu { + display: block; +} +.open > a { + outline: 0; +} +.dropdown-menu-right { + left: auto; + right: 0; +} +.dropdown-menu-left { + left: 0; + right: auto; +} +.dropdown-header { + display: block; + padding: 3px 20px; + font-size: 12px; + line-height: 1.42857143; + color: #98A2B3; + white-space: nowrap; +} +.dropdown-backdrop { + position: fixed; + left: 0; + right: 0; + bottom: 0; + top: 0; + z-index: 990; +} +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0; + border-bottom: 4px dashed; + border-bottom: 4px solid \9; + content: ""; +} +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 2px; +} +@media (min-width: 0) { + .navbar-right .dropdown-menu { + left: auto; + right: 0; + } + .navbar-right .dropdown-menu-left { + left: 0; + right: auto; + } +} +.input-group { + position: relative; + display: table; + border-collapse: separate; +} +.input-group[class*="col-"] { + float: none; + padding-left: 0; + padding-right: 0; +} +.input-group .form-control { + position: relative; + z-index: 2; + float: left; + width: 100%; + margin-bottom: 0; +} +.input-group .form-control:focus { + z-index: 3; +} +.input-group-lg > .form-control, +.input-group-lg > .input-group-addon { + height: 62px; + padding: 18px 27px; + font-size: 18px; + line-height: 1.3333333; + border-radius: 4px; +} +select.input-group-lg > .form-control, +select.input-group-lg > .input-group-addon { + height: 62px; + line-height: 62px; +} +textarea.input-group-lg > .form-control, +textarea.input-group-lg > .input-group-addon, +select[multiple].input-group-lg > .form-control, +select[multiple].input-group-lg > .input-group-addon { + height: auto; +} +.input-group-sm > .form-control, +.input-group-sm > .input-group-addon { + height: 32px; + padding: 6px 9px; + font-size: 12px; + line-height: 1.5; + border-radius: 4px; +} +select.input-group-sm > .form-control, +select.input-group-sm > .input-group-addon { + height: 32px; + line-height: 32px; +} +textarea.input-group-sm > .form-control, +textarea.input-group-sm > .input-group-addon, +select[multiple].input-group-sm > .form-control, +select[multiple].input-group-sm > .input-group-addon { + height: auto; +} +.input-group-addon, +.input-group .form-control { + display: table-cell; +} +.input-group-addon:not(:first-child):not(:last-child), +.input-group .form-control:not(:first-child):not(:last-child) { + border-radius: 0; +} +.input-group-addon { + width: 1%; + white-space: nowrap; + vertical-align: middle; +} +.input-group-addon { + padding: 5px 15px; + font-size: 14px; + font-weight: normal; + line-height: 1; + color: #343741; + text-align: center; + background-color: #D3DAE6; + border: 1px solid #D3DAE6; + border-radius: 4px; +} +.input-group-addon.input-sm { + padding: 6px 9px; + font-size: 12px; + border-radius: 4px; +} +.input-group-addon.input-lg { + padding: 18px 27px; + font-size: 18px; + border-radius: 4px; +} +.input-group-addon input[type="radio"], +.input-group-addon input[type="checkbox"] { + margin-top: 0; +} +.input-group .form-control:first-child, +.input-group-addon:first-child { + border-bottom-right-radius: 0; + border-top-right-radius: 0; +} +.input-group-addon:first-child { + border-right: 0; +} +.input-group .form-control:last-child, +.input-group-addon:last-child { + border-bottom-left-radius: 0; + border-top-left-radius: 0; +} +.input-group-addon:last-child { + border-left: 0; +} +.pagination { + display: inline-block; + padding-left: 0; + margin: 20px 0; + border-radius: 4px; +} +.pagination > li { + display: inline; +} +.pagination > li > a, +.pagination > li > span { + position: relative; + float: left; + padding: 5px 15px; + line-height: 1.42857143; + text-decoration: none; + color: #006BB4; + background-color: transparent; + border: 1px solid transparent; + margin-left: -1px; +} +.pagination > li:first-child > a, +.pagination > li:first-child > span { + margin-left: 0; + border-bottom-left-radius: 4px; + border-top-left-radius: 4px; +} +.pagination > li:last-child > a, +.pagination > li:last-child > span { + border-bottom-right-radius: 4px; + border-top-right-radius: 4px; +} +.pagination > li > a:hover, +.pagination > li > span:hover, +.pagination > li > a:focus, +.pagination > li > span:focus { + z-index: 2; + color: #006BB4; + background-color: rgba(0, 0, 0, 0); + border-color: transparent; +} +.pagination > .active > a, +.pagination > .active > span, +.pagination > .active > a:hover, +.pagination > .active > span:hover, +.pagination > .active > a:focus, +.pagination > .active > span:focus { + z-index: 3; + color: #343741; + background-color: rgba(0, 0, 0, 0); + border-color: transparent; + cursor: default; +} +.pagination > .disabled > span, +.pagination > .disabled > span:hover, +.pagination > .disabled > span:focus, +.pagination > .disabled > a, +.pagination > .disabled > a:hover, +.pagination > .disabled > a:focus { + color: #343741; + background-color: rgba(38, 38, 38, 0); + border-color: transparent; + cursor: not-allowed; +} +.pagination-lg > li > a, +.pagination-lg > li > span { + padding: 18px 27px; + font-size: 18px; + line-height: 1.3333333; +} +.pagination-lg > li:first-child > a, +.pagination-lg > li:first-child > span { + border-bottom-left-radius: 4px; + border-top-left-radius: 4px; +} +.pagination-lg > li:last-child > a, +.pagination-lg > li:last-child > span { + border-bottom-right-radius: 4px; + border-top-right-radius: 4px; +} +.pagination-sm > li > a, +.pagination-sm > li > span { + padding: 6px 9px; + font-size: 12px; + line-height: 1.5; +} +.pagination-sm > li:first-child > a, +.pagination-sm > li:first-child > span { + border-bottom-left-radius: 4px; + border-top-left-radius: 4px; +} +.pagination-sm > li:last-child > a, +.pagination-sm > li:last-child > span { + border-bottom-right-radius: 4px; + border-top-right-radius: 4px; +} +.pager { + padding-left: 0; + margin: 20px 0; + list-style: none; + text-align: center; +} +.pager li { + display: inline; +} +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: transparent; + border: 1px solid transparent; + border-radius: 0; +} +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: rgba(0, 0, 0, 0); +} +.pager .next > a, +.pager .next > span { + float: right; +} +.pager .previous > a, +.pager .previous > span { + float: left; +} +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #FFF; + background-color: transparent; + cursor: not-allowed; +} +.label { + display: inline; + padding: 0.2em 0.6em 0.3em; + font-size: 75%; + font-weight: bold; + line-height: 1; + color: #FFF; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: 0.25em; +} +a.label:hover, +a.label:focus { + color: #FFF; + text-decoration: none; + cursor: pointer; +} +.label:empty { + display: none; +} +.label-default { + background-color: #006BB4; +} +.label-default[href]:hover, +.label-default[href]:focus { + background-color: #004d81; +} +.label-primary { + background-color: #343741; +} +.label-primary[href]:hover, +.label-primary[href]:focus { + background-color: #1d1f25; +} +.label-success { + background-color: #017D73; +} +.label-success[href]:hover, +.label-success[href]:focus { + background-color: #014a44; +} +.label-info { + background-color: #006BB4; +} +.label-info[href]:hover, +.label-info[href]:focus { + background-color: #004d81; +} +.label-warning { + background-color: #F5A700; +} +.label-warning[href]:hover, +.label-warning[href]:focus { + background-color: #c28400; +} +.label-danger { + background-color: #BD271E; +} +.label-danger[href]:hover, +.label-danger[href]:focus { + background-color: #911e17; +} +.panel { + margin-bottom: 20px; + background-color: #FFF; + border: 1px solid transparent; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); +} +.panel-body { + padding: 15px; +} +.panel-heading { + padding: 10px 15px; + border-bottom: 1px solid transparent; + border-top-right-radius: 3px; + border-top-left-radius: 3px; +} +.panel-heading > .dropdown .dropdown-toggle { + color: inherit; +} +.panel-title { + margin-top: 0; + margin-bottom: 0; + font-size: 16px; + color: inherit; +} +.panel-title > a, +.panel-title > small, +.panel-title > .small, +.panel-title > small > a, +.panel-title > .small > a { + color: inherit; +} +.panel-footer { + padding: 10px 15px; + background-color: #F5F7FA; + border-top: 1px solid #D3DAE6; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .list-group, +.panel > .panel-collapse > .list-group { + margin-bottom: 0; +} +.panel > .list-group .list-group-item, +.panel > .panel-collapse > .list-group .list-group-item { + border-width: 1px 0; + border-radius: 0; +} +.panel > .list-group:first-child .list-group-item:first-child, +.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child { + border-top: 0; + border-top-right-radius: 3px; + border-top-left-radius: 3px; +} +.panel > .list-group:last-child .list-group-item:last-child, +.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child { + border-bottom: 0; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child { + border-top-right-radius: 0; + border-top-left-radius: 0; +} +.panel-heading + .list-group .list-group-item:first-child { + border-top-width: 0; +} +.list-group + .panel-footer { + border-top-width: 0; +} +.panel > .table, +.panel > .table-responsive > .table, +.panel > .panel-collapse > .table { + margin-bottom: 0; +} +.panel > .table caption, +.panel > .table-responsive > .table caption, +.panel > .panel-collapse > .table caption { + padding-left: 15px; + padding-right: 15px; +} +.panel > .table:first-child, +.panel > .table-responsive:first-child > .table:first-child { + border-top-right-radius: 3px; + border-top-left-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child { + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child td:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child { + border-top-left-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child { + border-top-right-radius: 3px; +} +.panel > .table:last-child, +.panel > .table-responsive:last-child > .table:last-child { + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child { + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child { + border-bottom-left-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child { + border-bottom-right-radius: 3px; +} +.panel > .panel-body + .table, +.panel > .panel-body + .table-responsive, +.panel > .table + .panel-body, +.panel > .table-responsive + .panel-body { + border-top: 1px solid #D3DAE6; +} +.panel > .table > tbody:first-child > tr:first-child th, +.panel > .table > tbody:first-child > tr:first-child td { + border-top: 0; +} +.panel > .table-bordered, +.panel > .table-responsive > .table-bordered { + border: 0; +} +.panel > .table-bordered > thead > tr > th:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, +.panel > .table-bordered > tbody > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, +.panel > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-bordered > thead > tr > td:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, +.panel > .table-bordered > tbody > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, +.panel > .table-bordered > tfoot > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; +} +.panel > .table-bordered > thead > tr > th:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, +.panel > .table-bordered > tbody > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, +.panel > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-bordered > thead > tr > td:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, +.panel > .table-bordered > tbody > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, +.panel > .table-bordered > tfoot > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; +} +.panel > .table-bordered > thead > tr:first-child > td, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > td, +.panel > .table-bordered > tbody > tr:first-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, +.panel > .table-bordered > thead > tr:first-child > th, +.panel > .table-responsive > .table-bordered > thead > tr:first-child > th, +.panel > .table-bordered > tbody > tr:first-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th { + border-bottom: 0; +} +.panel > .table-bordered > tbody > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, +.panel > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td, +.panel > .table-bordered > tbody > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, +.panel > .table-bordered > tfoot > tr:last-child > th, +.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th { + border-bottom: 0; +} +.panel > .table-responsive { + border: 0; + margin-bottom: 0; +} +.panel-group { + margin-bottom: 20px; +} +.panel-group .panel { + margin-bottom: 0; + border-radius: 4px; +} +.panel-group .panel + .panel { + margin-top: 5px; +} +.panel-group .panel-heading { + border-bottom: 0; +} +.panel-group .panel-heading + .panel-collapse > .panel-body, +.panel-group .panel-heading + .panel-collapse > .list-group { + border-top: 1px solid #D3DAE6; +} +.panel-group .panel-footer { + border-top: 0; +} +.panel-group .panel-footer + .panel-collapse .panel-body { + border-bottom: 1px solid #D3DAE6; +} +.panel-default { + border-color: #D3DAE6; +} +.panel-default > .panel-heading { + color: #7b7b7b; + background-color: #F5F7FA; + border-color: #D3DAE6; +} +.panel-default > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #D3DAE6; +} +.panel-default > .panel-heading .badge { + color: #F5F7FA; + background-color: #7b7b7b; +} +.panel-default > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #D3DAE6; +} +.panel-primary { + border-color: #343741; +} +.panel-primary > .panel-heading { + color: #FFF; + background-color: #343741; + border-color: #343741; +} +.panel-primary > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #343741; +} +.panel-primary > .panel-heading .badge { + color: #343741; + background-color: #FFF; +} +.panel-primary > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #343741; +} +.panel-success { + border-color: #014a44; +} +.panel-success > .panel-heading { + color: #FFF; + background-color: #017D73; + border-color: #014a44; +} +.panel-success > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #014a44; +} +.panel-success > .panel-heading .badge { + color: #017D73; + background-color: #FFF; +} +.panel-success > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #014a44; +} +.panel-info { + border-color: #004d81; +} +.panel-info > .panel-heading { + color: #FFF; + background-color: #006BB4; + border-color: #004d81; +} +.panel-info > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #004d81; +} +.panel-info > .panel-heading .badge { + color: #006BB4; + background-color: #FFF; +} +.panel-info > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #004d81; +} +.panel-warning { + border-color: #c28400; +} +.panel-warning > .panel-heading { + color: #FFF; + background-color: #F5A700; + border-color: #c28400; +} +.panel-warning > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #c28400; +} +.panel-warning > .panel-heading .badge { + color: #F5A700; + background-color: #FFF; +} +.panel-warning > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #c28400; +} +.panel-danger { + border-color: #911e17; +} +.panel-danger > .panel-heading { + color: #FFF; + background-color: #BD271E; + border-color: #911e17; +} +.panel-danger > .panel-heading + .panel-collapse > .panel-body { + border-top-color: #911e17; +} +.panel-danger > .panel-heading .badge { + color: #BD271E; + background-color: #FFF; +} +.panel-danger > .panel-footer + .panel-collapse > .panel-body { + border-bottom-color: #911e17; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + max-width: 276px; + padding: 1px; + font-family: 'Open Sans', Helvetica, Arial, sans-serif; + font-style: normal; + font-weight: normal; + letter-spacing: normal; + line-break: auto; + line-height: 1.42857143; + text-align: left; + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + white-space: normal; + word-break: normal; + word-spacing: normal; + word-wrap: normal; + font-size: 14px; + background-color: #FFF; + background-clip: padding-box; + border: 1px solid #D3DAE6; + border-radius: 4px; + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.1); +} +.popover.top { + margin-top: -10px; +} +.popover.right { + margin-left: 10px; +} +.popover.bottom { + margin-top: 10px; +} +.popover.left { + margin-left: -10px; +} +.popover-title { + margin: 0; + padding: 8px 14px; + font-size: 14px; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + border-radius: 3px 3px 0 0; +} +.popover-content { + padding: 9px 14px; +} +.popover > .arrow, +.popover > .arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.popover > .arrow { + border-width: 11px; +} +.popover > .arrow:after { + border-width: 10px; + content: ""; +} +.popover.top > .arrow { + left: 50%; + margin-left: -11px; + border-bottom-width: 0; + border-top-color: #92a3c1; + border-top-color: #d3dae6; + bottom: -11px; +} +.popover.top > .arrow:after { + content: " "; + bottom: 1px; + margin-left: -10px; + border-bottom-width: 0; + border-top-color: #FFF; +} +.popover.right > .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-left-width: 0; + border-right-color: #92a3c1; + border-right-color: #d3dae6; +} +.popover.right > .arrow:after { + content: " "; + left: 1px; + bottom: -10px; + border-left-width: 0; + border-right-color: #FFF; +} +.popover.bottom > .arrow { + left: 50%; + margin-left: -11px; + border-top-width: 0; + border-bottom-color: #92a3c1; + border-bottom-color: #d3dae6; + top: -11px; +} +.popover.bottom > .arrow:after { + content: " "; + top: 1px; + margin-left: -10px; + border-top-width: 0; + border-bottom-color: #FFF; +} +.popover.left > .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-right-width: 0; + border-left-color: #92a3c1; + border-left-color: #d3dae6; +} +.popover.left > .arrow:after { + content: " "; + right: 1px; + border-right-width: 0; + border-left-color: #FFF; + bottom: -10px; +} +.clearfix:before, +.clearfix:after, +.container:before, +.container:after, +.container-fluid:before, +.container-fluid:after, +.row:before, +.row:after, +.form-horizontal .form-group:before, +.form-horizontal .form-group:after, +.dl-horizontal dd:before, +.dl-horizontal dd:after, +.navbar:before, +.navbar:after, +.navbar-header:before, +.navbar-header:after, +.navbar-collapse:before, +.navbar-collapse:after, +.modal-header:before, +.modal-header:after, +.modal-footer:before, +.modal-footer:after, +.nav:before, +.nav:after, +.pager:before, +.pager:after, +.panel-body:before, +.panel-body:after { + content: " "; + display: table; +} +.clearfix:after, +.container:after, +.container-fluid:after, +.row:after, +.form-horizontal .form-group:after, +.dl-horizontal dd:after, +.navbar:after, +.navbar-header:after, +.navbar-collapse:after, +.modal-header:after, +.modal-footer:after, +.nav:after, +.pager:after, +.panel-body:after { + clear: both; +} +.center-block { + display: block; + margin-left: auto; + margin-right: auto; +} +.pull-right { + float: right !important; +} +.pull-left { + float: left !important; +} +.hide { + display: none !important; +} +.show { + display: block !important; +} +.invisible { + visibility: hidden; +} +.text-hide { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} +.hidden { + display: none !important; +} +.affix { + position: fixed; +} +.navbar > .container-fluid > .navbar-nav:not(.pull-right):first-child, +.navbar > .container-fluid > .navbar-form:not(.pull-right):first-child { + margin-left: -15px; + margin-top: 4px; +} +.navbar { + border-width: 0; +} +.navbar-btn-link { + margin: 0; + border-radius: 0; +} +@media (max-width: 768px) { + .navbar-btn-link { + width: 100%; + text-align: left; + } +} +.navbar-default .badge { + background-color: #FFF; + color: #F5F7FA; +} +.navbar-inverse .kbnGlobalNav__logoBrand { + height: 45px; + width: 252px; + background-color: #4b4f5d; +} +.navbar-inverse .kbnGlobalNav__smallLogoBrand { + height: 45px; + width: 45px; + background-color: #4b4f5d; +} +.navbar-inverse .badge { + background-color: #FFF; + color: #4b4f5d; +} +.navbar-brand { + cursor: default; + font-size: 1.8em; + user-select: none; +} +.navbar-nav { + font-size: 12px; +} +.navbar-nav > .active > a { + border-bottom-color: #7b7b7b; + background-color: transparent; +} +.navbar-toggle { + margin-top: 4px; +} +.text-primary, +.text-primary:hover { + color: #343741; +} +.text-success, +.text-success:hover { + color: #017D73; +} +.text-danger, +.text-danger:hover { + color: #BD271E; +} +.text-warning, +.text-warning:hover { + color: #F5A700; +} +.text-info, +.text-info:hover { + color: #006BB4; +} +table .success, +.table .success, +table .warning, +.table .warning, +table .danger, +.table .danger, +table .info, +.table .info { + color: #FFF; +} +table .success a, +.table .success a, +table .warning a, +.table .warning a, +table .danger a, +.table .danger a, +table .info a, +.table .info a { + color: #FFF; +} +.table-bordered > thead > tr > th, +.table-bordered > tbody > tr > th, +.table-bordered > tfoot > tr > th, +.table-bordered > thead > tr > td, +.table-bordered > tbody > tr > td, +.table-bordered > tfoot > tr > td { + border: 1px solid #D3DAE6; +} +.form-control, +input { + border-width: 1px; + -webkit-box-shadow: none; + box-shadow: none; +} +.form-control:focus, +input:focus { + -webkit-box-shadow: none; + box-shadow: none; +} +.has-warning .help-block, +.has-warning .control-label, +.has-warning .radio, +.has-warning .checkbox, +.has-warning .radio-inline, +.has-warning .checkbox-inline, +.has-warning .form-control-feedback { + color: #F5A700; +} +.has-warning .form-control, +.has-warning .form-control:focus { + border: 1px solid; + border-color: #F5A700; +} +.has-warning .input-group-addon { + border-color: #F5A700; +} +.has-error .help-block, +.has-error .control-label, +.has-error .radio, +.has-error .checkbox, +.has-error .radio-inline, +.has-error .checkbox-inline, +.has-error .form-control-feedback { + color: #BD271E; +} +.has-error .form-control, +.has-error .form-control:focus { + border: 1px solid; + border-color: #BD271E; +} +.has-error .input-group-addon { + border-color: #BD271E; +} +.has-success .help-block, +.has-success .control-label, +.has-success .radio, +.has-success .checkbox, +.has-success .radio-inline, +.has-success .checkbox-inline, +.has-success .form-control-feedback { + color: #017D73; +} +.has-success .form-control, +.has-success .form-control:focus { + border: solid #017D73; +} +.has-success .input-group-addon { + border-color: #017D73; +} +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + border-color: transparent; +} +.pager a, +.pager a:hover { + color: #FFF; +} +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + background-color: rgba(38, 38, 38, 0); +} +.panel { + border-radius: 0; + -webkit-box-shadow: 0 0 0 rgba(0, 0, 0, 0); + box-shadow: 0 0 0 rgba(0, 0, 0, 0); +} +.progress { + -webkit-box-shadow: none; + box-shadow: none; +} +.progress .progress-bar { + font-size: 10px; + line-height: 10px; +} +.well { + -webkit-box-shadow: none; + box-shadow: none; +} diff --git a/src/core/server/rendering/__snapshots__/rendering_service.test.ts.snap b/src/core/server/rendering/__snapshots__/rendering_service.test.ts.snap index eab29731ea524..5ff5d69f96f70 100644 --- a/src/core/server/rendering/__snapshots__/rendering_service.test.ts.snap +++ b/src/core/server/rendering/__snapshots__/rendering_service.test.ts.snap @@ -273,277 +273,3 @@ Object { "version": Any, } `; - -exports[`RenderingService setup() render() renders "legacy" page 1`] = ` -Object { - "anonymousStatusPage": false, - "basePath": "/mock-server-basepath", - "branch": Any, - "buildNumber": Any, - "csp": Object { - "warnLegacyBrowsers": true, - }, - "env": Object { - "mode": Object { - "dev": Any, - "name": Any, - "prod": Any, - }, - "packageInfo": Object { - "branch": Any, - "buildNum": Any, - "buildSha": Any, - "dist": Any, - "version": Any, - }, - }, - "i18n": Object { - "translationsUrl": "/mock-server-basepath/translations/en.json", - }, - "legacyMetadata": Object { - "app": Object {}, - "basePath": "/mock-server-basepath", - "branch": Any, - "buildNum": Any, - "buildSha": Any, - "bundleId": "app:legacy", - "devMode": true, - "nav": Array [], - "serverName": "http-server-test", - "uiSettings": Object { - "defaults": Object { - "registered": Object { - "name": "title", - }, - }, - "user": Object {}, - }, - "version": Any, - }, - "legacyMode": true, - "serverBasePath": "/mock-server-basepath", - "uiPlugins": Array [], - "vars": Object {}, - "version": Any, -} -`; - -exports[`RenderingService setup() render() renders "legacy" page for blank basepath 1`] = ` -Object { - "anonymousStatusPage": false, - "basePath": "", - "branch": Any, - "buildNumber": Any, - "csp": Object { - "warnLegacyBrowsers": true, - }, - "env": Object { - "mode": Object { - "dev": Any, - "name": Any, - "prod": Any, - }, - "packageInfo": Object { - "branch": Any, - "buildNum": Any, - "buildSha": Any, - "dist": Any, - "version": Any, - }, - }, - "i18n": Object { - "translationsUrl": "/translations/en.json", - }, - "legacyMetadata": Object { - "app": Object {}, - "basePath": "", - "branch": Any, - "buildNum": Any, - "buildSha": Any, - "bundleId": "app:legacy", - "devMode": true, - "nav": Array [], - "serverName": "http-server-test", - "uiSettings": Object { - "defaults": Object { - "registered": Object { - "name": "title", - }, - }, - "user": Object {}, - }, - "version": Any, - }, - "legacyMode": true, - "serverBasePath": "/mock-server-basepath", - "uiPlugins": Array [], - "vars": Object {}, - "version": Any, -} -`; - -exports[`RenderingService setup() render() renders "legacy" with custom vars 1`] = ` -Object { - "anonymousStatusPage": false, - "basePath": "/mock-server-basepath", - "branch": Any, - "buildNumber": Any, - "csp": Object { - "warnLegacyBrowsers": true, - }, - "env": Object { - "mode": Object { - "dev": Any, - "name": Any, - "prod": Any, - }, - "packageInfo": Object { - "branch": Any, - "buildNum": Any, - "buildSha": Any, - "dist": Any, - "version": Any, - }, - }, - "i18n": Object { - "translationsUrl": "/mock-server-basepath/translations/en.json", - }, - "legacyMetadata": Object { - "app": Object {}, - "basePath": "/mock-server-basepath", - "branch": Any, - "buildNum": Any, - "buildSha": Any, - "bundleId": "app:legacy", - "devMode": true, - "nav": Array [], - "serverName": "http-server-test", - "uiSettings": Object { - "defaults": Object { - "registered": Object { - "name": "title", - }, - }, - "user": Object {}, - }, - "version": Any, - }, - "legacyMode": true, - "serverBasePath": "/mock-server-basepath", - "uiPlugins": Array [], - "vars": Object { - "fake": "__TEST_TOKEN__", - }, - "version": Any, -} -`; - -exports[`RenderingService setup() render() renders "legacy" with excluded user settings 1`] = ` -Object { - "anonymousStatusPage": false, - "basePath": "/mock-server-basepath", - "branch": Any, - "buildNumber": Any, - "csp": Object { - "warnLegacyBrowsers": true, - }, - "env": Object { - "mode": Object { - "dev": Any, - "name": Any, - "prod": Any, - }, - "packageInfo": Object { - "branch": Any, - "buildNum": Any, - "buildSha": Any, - "dist": Any, - "version": Any, - }, - }, - "i18n": Object { - "translationsUrl": "/mock-server-basepath/translations/en.json", - }, - "legacyMetadata": Object { - "app": Object {}, - "basePath": "/mock-server-basepath", - "branch": Any, - "buildNum": Any, - "buildSha": Any, - "bundleId": "app:legacy", - "devMode": true, - "nav": Array [], - "serverName": "http-server-test", - "uiSettings": Object { - "defaults": Object { - "registered": Object { - "name": "title", - }, - }, - "user": Object {}, - }, - "version": Any, - }, - "legacyMode": true, - "serverBasePath": "/mock-server-basepath", - "uiPlugins": Array [], - "vars": Object {}, - "version": Any, -} -`; - -exports[`RenderingService setup() render() renders "legacy" with excluded user settings and custom vars 1`] = ` -Object { - "anonymousStatusPage": false, - "basePath": "/mock-server-basepath", - "branch": Any, - "buildNumber": Any, - "csp": Object { - "warnLegacyBrowsers": true, - }, - "env": Object { - "mode": Object { - "dev": Any, - "name": Any, - "prod": Any, - }, - "packageInfo": Object { - "branch": Any, - "buildNum": Any, - "buildSha": Any, - "dist": Any, - "version": Any, - }, - }, - "i18n": Object { - "translationsUrl": "/mock-server-basepath/translations/en.json", - }, - "legacyMetadata": Object { - "app": Object {}, - "basePath": "/mock-server-basepath", - "branch": Any, - "buildNum": Any, - "buildSha": Any, - "bundleId": "app:legacy", - "devMode": true, - "nav": Array [], - "serverName": "http-server-test", - "uiSettings": Object { - "defaults": Object { - "registered": Object { - "name": "title", - }, - }, - "user": Object {}, - }, - "version": Any, - }, - "legacyMode": true, - "serverBasePath": "/mock-server-basepath", - "uiPlugins": Array [], - "vars": Object { - "fake": "__TEST_TOKEN__", - }, - "version": Any, -} -`; diff --git a/src/core/server/rendering/rendering_service.test.ts b/src/core/server/rendering/rendering_service.test.ts index 7caf4af850c10..254bafed5b194 100644 --- a/src/core/server/rendering/rendering_service.test.ts +++ b/src/core/server/rendering/rendering_service.test.ts @@ -52,7 +52,6 @@ const INJECTED_METADATA = { }; const { createKibanaRequest, createRawRequest } = httpServerMock; -const legacyApp = { getId: () => 'legacy' }; describe('RenderingService', () => { let service: RenderingService; @@ -126,62 +125,6 @@ describe('RenderingService', () => { expect(data).toMatchSnapshot(INJECTED_METADATA); }); - - it('renders "legacy" page', async () => { - const content = await render(createRawRequest(), uiSettings, { app: legacyApp }); - const dom = load(content); - const data = JSON.parse(dom('kbn-injected-metadata').attr('data')); - - expect(data).toMatchSnapshot(INJECTED_METADATA); - }); - - it('renders "legacy" page for blank basepath', async () => { - mockRenderingSetupDeps.http.basePath.get.mockReturnValueOnce(''); - - const content = await render(createRawRequest(), uiSettings, { app: legacyApp }); - const dom = load(content); - const data = JSON.parse(dom('kbn-injected-metadata').attr('data')); - - expect(data).toMatchSnapshot(INJECTED_METADATA); - }); - - it('renders "legacy" with custom vars', async () => { - const content = await render(createRawRequest(), uiSettings, { - app: legacyApp, - vars: { - fake: '__TEST_TOKEN__', - }, - }); - const dom = load(content); - const data = JSON.parse(dom('kbn-injected-metadata').attr('data')); - - expect(data).toMatchSnapshot(INJECTED_METADATA); - }); - - it('renders "legacy" with excluded user settings', async () => { - const content = await render(createRawRequest(), uiSettings, { - app: legacyApp, - includeUserSettings: false, - }); - const dom = load(content); - const data = JSON.parse(dom('kbn-injected-metadata').attr('data')); - - expect(data).toMatchSnapshot(INJECTED_METADATA); - }); - - it('renders "legacy" with excluded user settings and custom vars', async () => { - const content = await render(createRawRequest(), uiSettings, { - app: legacyApp, - includeUserSettings: false, - vars: { - fake: '__TEST_TOKEN__', - }, - }); - const dom = load(content); - const data = JSON.parse(dom('kbn-injected-metadata').attr('data')); - - expect(data).toMatchSnapshot(INJECTED_METADATA); - }); }); }); }); diff --git a/src/core/server/rendering/rendering_service.tsx b/src/core/server/rendering/rendering_service.tsx index f49952ec713fb..e7ee0b16fce08 100644 --- a/src/core/server/rendering/rendering_service.tsx +++ b/src/core/server/rendering/rendering_service.tsx @@ -69,7 +69,7 @@ export class RenderingService implements CoreService { describe('when file is present and config property is set', () => { describe('when they mismatch', () => { - describe('when syncToFile is true', () => { - it('writes to file and returns the config uuid', async () => { - const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: true }); - expect(uuid).toEqual(DEFAULT_CONFIG_UUID); - expect(writeFile).toHaveBeenCalledWith( - join('data-folder', 'uuid'), - DEFAULT_CONFIG_UUID, - expect.any(Object) - ); - expect(logger.debug).toHaveBeenCalledTimes(1); - expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "Updating Kibana instance UUID to: CONFIG_UUID (was: FILE_UUID)", - ] - `); - }); - }); - - describe('when syncTofile is false', () => { - it('does not write to file and returns the config uuid', async () => { - const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: false }); - expect(uuid).toEqual(DEFAULT_CONFIG_UUID); - expect(writeFile).not.toHaveBeenCalled(); - expect(logger.debug).toHaveBeenCalledTimes(1); - expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "Updating Kibana instance UUID to: CONFIG_UUID (was: FILE_UUID)", - ] - `); - }); - }); - }); - - describe('when they match', () => { - it('does not write to file', async () => { - mockReadFile({ uuid: DEFAULT_CONFIG_UUID }); - const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: true }); - expect(uuid).toEqual(DEFAULT_CONFIG_UUID); - expect(writeFile).not.toHaveBeenCalled(); - expect(logger.debug).toHaveBeenCalledTimes(1); - expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "Kibana instance UUID: CONFIG_UUID", - ] - `); - }); - }); - }); - - describe('when file is not present and config property is set', () => { - describe('when syncToFile is true', () => { - it('writes the uuid to file and returns the config uuid', async () => { - mockReadFile({ error: fileNotFoundError }); - const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: true }); + it('writes to file and returns the config uuid', async () => { + const uuid = await resolveInstanceUuid({ configService, logger }); expect(uuid).toEqual(DEFAULT_CONFIG_UUID); expect(writeFile).toHaveBeenCalledWith( join('data-folder', 'uuid'), @@ -161,32 +109,51 @@ describe('resolveInstanceUuid', () => { expect(logger.debug).toHaveBeenCalledTimes(1); expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(` Array [ - "Setting new Kibana instance UUID: CONFIG_UUID", + "Updating Kibana instance UUID to: CONFIG_UUID (was: FILE_UUID)", ] `); }); }); - describe('when syncToFile is false', () => { - it('does not write the uuid to file and returns the config uuid', async () => { - mockReadFile({ error: fileNotFoundError }); - const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: false }); + describe('when they match', () => { + it('does not write to file', async () => { + mockReadFile({ uuid: DEFAULT_CONFIG_UUID }); + const uuid = await resolveInstanceUuid({ configService, logger }); expect(uuid).toEqual(DEFAULT_CONFIG_UUID); expect(writeFile).not.toHaveBeenCalled(); expect(logger.debug).toHaveBeenCalledTimes(1); expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(` Array [ - "Setting new Kibana instance UUID: CONFIG_UUID", + "Kibana instance UUID: CONFIG_UUID", ] `); }); }); }); + describe('when file is not present and config property is set', () => { + it('writes the uuid to file and returns the config uuid', async () => { + mockReadFile({ error: fileNotFoundError }); + const uuid = await resolveInstanceUuid({ configService, logger }); + expect(uuid).toEqual(DEFAULT_CONFIG_UUID); + expect(writeFile).toHaveBeenCalledWith( + join('data-folder', 'uuid'), + DEFAULT_CONFIG_UUID, + expect.any(Object) + ); + expect(logger.debug).toHaveBeenCalledTimes(1); + expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "Setting new Kibana instance UUID: CONFIG_UUID", + ] + `); + }); + }); + describe('when file is present and config property is not set', () => { it('does not write to file and returns the file uuid', async () => { configService = getConfigService(undefined); - const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: true }); + const uuid = await resolveInstanceUuid({ configService, logger }); expect(uuid).toEqual(DEFAULT_FILE_UUID); expect(writeFile).not.toHaveBeenCalled(); expect(logger.debug).toHaveBeenCalledTimes(1); @@ -203,7 +170,7 @@ describe('resolveInstanceUuid', () => { it('writes new uuid to file and returns new uuid', async () => { mockReadFile({ uuid: UUID_7_6_0_BUG }); configService = getConfigService(undefined); - const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: true }); + const uuid = await resolveInstanceUuid({ configService, logger }); expect(uuid).not.toEqual(UUID_7_6_0_BUG); expect(uuid).toEqual('NEW_UUID'); expect(writeFile).toHaveBeenCalledWith( @@ -229,7 +196,7 @@ describe('resolveInstanceUuid', () => { it('writes config uuid to file and returns config uuid', async () => { mockReadFile({ uuid: UUID_7_6_0_BUG }); configService = getConfigService(DEFAULT_CONFIG_UUID); - const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: true }); + const uuid = await resolveInstanceUuid({ configService, logger }); expect(uuid).not.toEqual(UUID_7_6_0_BUG); expect(uuid).toEqual(DEFAULT_CONFIG_UUID); expect(writeFile).toHaveBeenCalledWith( @@ -253,40 +220,22 @@ describe('resolveInstanceUuid', () => { }); describe('when file is not present and config property is not set', () => { - describe('when syncToFile is true', () => { - it('generates a new uuid and write it to file', async () => { - configService = getConfigService(undefined); - mockReadFile({ error: fileNotFoundError }); - const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: true }); - expect(uuid).toEqual('NEW_UUID'); - expect(writeFile).toHaveBeenCalledWith( - join('data-folder', 'uuid'), - 'NEW_UUID', - expect.any(Object) - ); - expect(logger.debug).toHaveBeenCalledTimes(1); - expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "Setting new Kibana instance UUID: NEW_UUID", - ] - `); - }); - }); - - describe('when syncToFile is false', () => { - it('generates a new uuid and does not write it to file', async () => { - configService = getConfigService(undefined); - mockReadFile({ error: fileNotFoundError }); - const uuid = await resolveInstanceUuid({ configService, logger, syncToFile: false }); - expect(uuid).toEqual('NEW_UUID'); - expect(writeFile).not.toHaveBeenCalled(); - expect(logger.debug).toHaveBeenCalledTimes(1); - expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "Setting new Kibana instance UUID: NEW_UUID", - ] - `); - }); + it('generates a new uuid and write it to file', async () => { + configService = getConfigService(undefined); + mockReadFile({ error: fileNotFoundError }); + const uuid = await resolveInstanceUuid({ configService, logger }); + expect(uuid).toEqual('NEW_UUID'); + expect(writeFile).toHaveBeenCalledWith( + join('data-folder', 'uuid'), + 'NEW_UUID', + expect.any(Object) + ); + expect(logger.debug).toHaveBeenCalledTimes(1); + expect(logger.debug.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "Setting new Kibana instance UUID: NEW_UUID", + ] + `); }); }); @@ -294,7 +243,7 @@ describe('resolveInstanceUuid', () => { it('throws an explicit error for file read errors', async () => { mockReadFile({ error: permissionError }); await expect( - resolveInstanceUuid({ configService, logger, syncToFile: true }) + resolveInstanceUuid({ configService, logger }) ).rejects.toThrowErrorMatchingInlineSnapshot( `"Unable to read Kibana UUID file, please check the uuid.server configuration value in kibana.yml and ensure Kibana has sufficient permissions to read / write to this file. Error was: EACCES"` ); @@ -302,7 +251,7 @@ describe('resolveInstanceUuid', () => { it('throws an explicit error for file write errors', async () => { mockWriteFile(isDirectoryError); await expect( - resolveInstanceUuid({ configService, logger, syncToFile: true }) + resolveInstanceUuid({ configService, logger }) ).rejects.toThrowErrorMatchingInlineSnapshot( `"Unable to write Kibana UUID file, please check the uuid.server configuration value in kibana.yml and ensure Kibana has sufficient permissions to read / write to this file. Error was: EISDIR"` ); diff --git a/src/core/server/uuid/resolve_uuid.ts b/src/core/server/uuid/resolve_uuid.ts index c3e79cc519a1b..36f0eb73b1de7 100644 --- a/src/core/server/uuid/resolve_uuid.ts +++ b/src/core/server/uuid/resolve_uuid.ts @@ -36,11 +36,9 @@ export const UUID_7_6_0_BUG = `ce42b997-a913-4d58-be46-bb1937feedd6`; export async function resolveInstanceUuid({ configService, - syncToFile, logger, }: { configService: IConfigService; - syncToFile: boolean; logger: Logger; }): Promise { const [pathConfig, serverConfig] = await Promise.all([ @@ -65,7 +63,7 @@ export async function resolveInstanceUuid({ } else { logger.debug(`Updating Kibana instance UUID to: ${uuidFromConfig} (was: ${uuidFromFile})`); } - await writeUuidToFile(uuidFilePath, uuidFromConfig, syncToFile); + await writeUuidToFile(uuidFilePath, uuidFromConfig); return uuidFromConfig; } } @@ -73,7 +71,7 @@ export async function resolveInstanceUuid({ const newUuid = uuid.v4(); // no uuid either in config or file, we need to generate and write it. logger.debug(`Setting new Kibana instance UUID: ${newUuid}`); - await writeUuidToFile(uuidFilePath, newUuid, syncToFile); + await writeUuidToFile(uuidFilePath, newUuid); return newUuid; } @@ -105,11 +103,7 @@ async function readUuidFromFile(filepath: string, logger: Logger): Promise ({ resolveInstanceUuid: jest.fn().mockResolvedValue('SOME_UUID'), @@ -47,28 +45,10 @@ describe('UuidService', () => { expect(resolveInstanceUuid).toHaveBeenCalledTimes(1); expect(resolveInstanceUuid).toHaveBeenCalledWith({ configService: coreContext.configService, - syncToFile: true, logger: logger.get('uuid'), }); }); - describe('when cliArgs.optimize is true', () => { - it('calls resolveInstanceUuid with syncToFile: false', async () => { - coreContext = mockCoreContext.create({ - logger, - env: Env.createDefault(getEnvOptions({ cliArgs: { optimize: true } })), - }); - const service = new UuidService(coreContext); - await service.setup(); - expect(resolveInstanceUuid).toHaveBeenCalledTimes(1); - expect(resolveInstanceUuid).toHaveBeenCalledWith({ - configService: coreContext.configService, - syncToFile: false, - logger: logger.get('uuid'), - }); - }); - }); - it('returns the uuid resolved from resolveInstanceUuid', async () => { const service = new UuidService(coreContext); const setup = await service.setup(); diff --git a/src/core/server/uuid/uuid_service.ts b/src/core/server/uuid/uuid_service.ts index 62ed4a19edf5a..d7c1b3331c447 100644 --- a/src/core/server/uuid/uuid_service.ts +++ b/src/core/server/uuid/uuid_service.ts @@ -20,7 +20,7 @@ import { resolveInstanceUuid } from './resolve_uuid'; import { CoreContext } from '../core_context'; import { Logger } from '../logging'; -import { IConfigService, CliArgs } from '../config'; +import { IConfigService } from '../config'; /** * APIs to access the application's instance uuid. @@ -38,19 +38,16 @@ export interface UuidServiceSetup { export class UuidService { private readonly log: Logger; private readonly configService: IConfigService; - private readonly cliArgs: CliArgs; private uuid: string = ''; constructor(core: CoreContext) { this.log = core.logger.get('uuid'); this.configService = core.configService; - this.cliArgs = core.env.cliArgs; } public async setup() { this.uuid = await resolveInstanceUuid({ configService: this.configService, - syncToFile: !this.cliArgs.optimize, logger: this.log, }); diff --git a/src/dev/build/build_distributables.ts b/src/dev/build/build_distributables.ts index 1d41f4c270caa..5e6f6efcb50ca 100644 --- a/src/dev/build/build_distributables.ts +++ b/src/dev/build/build_distributables.ts @@ -73,8 +73,6 @@ export async function buildDistributables(log: ToolingLog, options: BuildOptions await run(Tasks.CreateNoticeFile); await run(Tasks.UpdateLicenseFile); await run(Tasks.RemovePackageJsonDeps); - await run(Tasks.TranspileScss); - await run(Tasks.OptimizeBuild); await run(Tasks.CleanTypescript); await run(Tasks.CleanExtraFilesFromModules); await run(Tasks.CleanEmptyFolders); diff --git a/src/dev/build/tasks/copy_source_task.ts b/src/dev/build/tasks/copy_source_task.ts index 79279997671e5..7a5d84da527db 100644 --- a/src/dev/build/tasks/copy_source_task.ts +++ b/src/dev/build/tasks/copy_source_task.ts @@ -39,7 +39,6 @@ export const CopySource: Task = { '!src/functional_test_runner/**', '!src/dev/**', 'typings/**', - 'webpackShims/**', 'config/kibana.yml', 'config/node.options', 'tsconfig*.json', diff --git a/src/dev/build/tasks/index.ts b/src/dev/build/tasks/index.ts index 4c00e56faee6b..c2a0d74dbfed5 100644 --- a/src/dev/build/tasks/index.ts +++ b/src/dev/build/tasks/index.ts @@ -31,12 +31,10 @@ export * from './install_dependencies_task'; export * from './license_file_task'; export * from './nodejs'; export * from './notice_file_task'; -export * from './optimize_task'; export * from './os_packages'; export * from './patch_native_modules_task'; export * from './path_length_task'; export * from './transpile_babel_task'; -export * from './transpile_scss_task'; export * from './uuid_verification_task'; export * from './verify_env_task'; export * from './write_sha_sums_task'; diff --git a/src/dev/build/tasks/optimize_task.ts b/src/dev/build/tasks/optimize_task.ts deleted file mode 100644 index 98979f376eacd..0000000000000 --- a/src/dev/build/tasks/optimize_task.ts +++ /dev/null @@ -1,52 +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 { deleteAll, copyAll, exec, Task } from '../lib'; -import { getNodeDownloadInfo } from './nodejs'; - -export const OptimizeBuild: Task = { - description: 'Running optimizer', - - async run(config, log, build) { - const tempNodeInstallDir = build.resolvePath('node'); - const platform = config.getPlatformForThisOs(); - - // copy extracted node for this platform into the build temporarily - log.debug('Temporarily installing node.js for', platform.getNodeArch()); - const { extractDir } = getNodeDownloadInfo(config, platform); - await copyAll(extractDir, tempNodeInstallDir); - - const kibanaScript = platform.isWindows() ? '.\\bin\\kibana.bat' : './bin/kibana'; - - const kibanaArgs = ['--env.name=production', '--logging.json=false', '--optimize']; - - log.info('Running bin/kibana to trigger the optimizer'); - - await exec(log, kibanaScript, kibanaArgs, { - cwd: build.resolvePath('.'), - env: { - KBN_CACHE_LOADER_WRITABLE: 'true', - NODE_OPTIONS: '--max-old-space-size=4096', - }, - }); - - // clean up temporary node install - await deleteAll([tempNodeInstallDir], log); - }, -}; diff --git a/src/dev/build/tasks/transpile_scss_task.ts b/src/dev/build/tasks/transpile_scss_task.ts deleted file mode 100644 index e1b0bd0171c92..0000000000000 --- a/src/dev/build/tasks/transpile_scss_task.ts +++ /dev/null @@ -1,33 +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 { Task } from '../lib'; - -// @ts-expect-error buildSass isn't TS yet -import { buildSass } from '../../sass'; - -export const TranspileScss: Task = { - description: 'Transpiling SCSS to CSS', - async run(config, log, build) { - await buildSass({ - log, - kibanaDir: build.resolvePath('.'), - }); - }, -}; diff --git a/src/dev/i18n/README.md b/src/dev/i18n/README.md index 2ef739e655d9b..5c2e996c2a640 100644 --- a/src/dev/i18n/README.md +++ b/src/dev/i18n/README.md @@ -4,7 +4,7 @@ ### Description -The tool is used to extract default messages from all `*.{js, ts, jsx, tsx, html, pug}` files in provided plugins directories to a JSON file. +The tool is used to extract default messages from all `*.{js, ts, jsx, tsx, html }` files in provided plugins directories to a JSON file. It uses Babel to parse code and build an AST for each file or a single JS expression if whole file parsing is impossible. The tool is able to validate, extract and match IDs, default messages and descriptions only if they are defined statically and together, otherwise it will fail with detailed explanation. That means one can't define ID in one place and default message in another, or use function call to dynamically create default message etc. @@ -116,18 +116,6 @@ The `description` is optional, `values` is optional too unless `defaultMessage` * Expression can be parsed only if it is located in syntactically valid JS/TS code. Do not use type assertions in TypeScript for `defaultMessage` or `description` properties, id argument or the second argument of `i18n*` call expression. It is never needed for i18n engine use cases. -* **Pug (.pug)** - - ``` - #{i18n('pluginNamespace.messageId', { - defaultMessage: 'Default message string literal, {key}', - values: { key: 'value' }, - description: 'Message context or description', - })} - ``` - - * Expression in `#{...}` is parsed as a JS expression. - ### Usage ```bash diff --git a/src/dev/i18n/__fixtures__/extract_default_translations/test_plugin_1/test_file_2.pug b/src/dev/i18n/__fixtures__/extract_default_translations/test_plugin_1/test_file_2.pug deleted file mode 100644 index fb61f554a1c70..0000000000000 --- a/src/dev/i18n/__fixtures__/extract_default_translations/test_plugin_1/test_file_2.pug +++ /dev/null @@ -1,10 +0,0 @@ -extends ./chrome.pug - -block content - .kibanaWelcomeView - .kibanaLoaderWrap - .kibanaLoader - .kibanaWelcomeLogoCircle - .kibanaWelcomeLogo - .kibanaWelcomeText - | #{i18n('plugin_1.id_5', { defaultMessage: 'Message 5' })} diff --git a/src/dev/i18n/__snapshots__/extract_default_translations.test.js.snap b/src/dev/i18n/__snapshots__/extract_default_translations.test.js.snap index 2c86934d7c71d..b19b366a8db7b 100644 --- a/src/dev/i18n/__snapshots__/extract_default_translations.test.js.snap +++ b/src/dev/i18n/__snapshots__/extract_default_translations.test.js.snap @@ -30,13 +30,6 @@ Array [ "message": "Message 4", }, ], - Array [ - "plugin_1.id_5", - Object { - "description": undefined, - "message": "Message 5", - }, - ], Array [ "plugin_1.id_7", Object { diff --git a/src/dev/i18n/extract_default_translations.js b/src/dev/i18n/extract_default_translations.js index e70c666422f7b..a0be81a30838d 100644 --- a/src/dev/i18n/extract_default_translations.js +++ b/src/dev/i18n/extract_default_translations.js @@ -19,7 +19,7 @@ import path from 'path'; -import { extractHtmlMessages, extractCodeMessages, extractPugMessages } from './extractors'; +import { extractHtmlMessages, extractCodeMessages } from './extractors'; import { globAsync, readFileAsync, normalizePath } from './utils'; import { createFailError, isFailError } from '@kbn/dev-utils'; @@ -70,7 +70,7 @@ export async function matchEntriesWithExctractors(inputPath, options = {}) { '**/*.d.ts', ].concat(additionalIgnore); - const entries = await globAsync('*.{js,jsx,pug,ts,tsx,html}', { + const entries = await globAsync('*.{js,jsx,ts,tsx,html}', { cwd: inputPath, matchBase: true, ignore, @@ -78,27 +78,24 @@ export async function matchEntriesWithExctractors(inputPath, options = {}) { absolute, }); - const { htmlEntries, codeEntries, pugEntries } = entries.reduce( + const { htmlEntries, codeEntries } = entries.reduce( (paths, entry) => { const resolvedPath = path.resolve(inputPath, entry); if (resolvedPath.endsWith('.html')) { paths.htmlEntries.push(resolvedPath); - } else if (resolvedPath.endsWith('.pug')) { - paths.pugEntries.push(resolvedPath); } else { paths.codeEntries.push(resolvedPath); } return paths; }, - { htmlEntries: [], codeEntries: [], pugEntries: [] } + { htmlEntries: [], codeEntries: [] } ); return [ [htmlEntries, extractHtmlMessages], [codeEntries, extractCodeMessages], - [pugEntries, extractPugMessages], ]; } diff --git a/src/dev/i18n/extractors/__snapshots__/pug.test.js.snap b/src/dev/i18n/extractors/__snapshots__/pug.test.js.snap deleted file mode 100644 index 48c887fc6318c..0000000000000 --- a/src/dev/i18n/extractors/__snapshots__/pug.test.js.snap +++ /dev/null @@ -1,37 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`dev/i18n/extractors/pug extracts messages from pug template with interpolation 1`] = ` -Array [ - "message-id", - Object { - "description": "Message description", - "message": "Default message", - }, -] -`; - -exports[`dev/i18n/extractors/pug extracts messages from pug template without interpolation 1`] = ` -Array [ - "message-id", - Object { - "description": "Message description", - "message": "Default message", - }, -] -`; - -exports[`dev/i18n/extractors/pug throws on empty id 1`] = ` -Array [ - Array [ - [Error: Empty "id" value in i18n() or i18n.translate() is not allowed.], - ], -] -`; - -exports[`dev/i18n/extractors/pug throws on missing default message 1`] = ` -Array [ - Array [ - [Error: Empty defaultMessage in i18n() or i18n.translate() is not allowed ("message-id").], - ], -] -`; diff --git a/src/dev/i18n/extractors/index.js b/src/dev/i18n/extractors/index.js index 48e90de6c6d49..cc8a4b7b27637 100644 --- a/src/dev/i18n/extractors/index.js +++ b/src/dev/i18n/extractors/index.js @@ -19,4 +19,3 @@ export { extractCodeMessages } from './code'; export { extractHtmlMessages } from './html'; -export { extractPugMessages } from './pug'; diff --git a/src/dev/i18n/extractors/pug.js b/src/dev/i18n/extractors/pug.js deleted file mode 100644 index 20fc72a404843..0000000000000 --- a/src/dev/i18n/extractors/pug.js +++ /dev/null @@ -1,74 +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 { parse } from '@babel/parser'; - -import { extractI18nCallMessages } from './i18n_call'; -import { isI18nTranslateFunction, traverseNodes, createParserErrorMessage } from '../utils'; -import { createFailError, isFailError } from '@kbn/dev-utils'; - -/** - * Matches `i18n(...)` in `#{i18n('id', { defaultMessage: 'Message text' })}` - */ -const PUG_I18N_REGEX = /i18n\((([^)']|'([^'\\]|\\.)*')*)\)/g; - -function parsePugExpression(expression) { - let ast; - - try { - ast = parse(expression); - } catch (error) { - if (error instanceof SyntaxError) { - const errorWithContext = createParserErrorMessage(expression, error); - throw createFailError( - `Couldn't parse Pug expression with i18n(...) call:\n${errorWithContext}` - ); - } - - throw error; - } - - return ast; -} - -/** - * Example: `#{i18n('message-id', { defaultMessage: 'Message text' })}` - */ -export function* extractPugMessages(buffer, reporter) { - const expressions = buffer.toString().match(PUG_I18N_REGEX) || []; - - for (const expression of expressions) { - try { - const ast = parsePugExpression(expression); - const node = [...traverseNodes(ast.program.body)].find((node) => - isI18nTranslateFunction(node) - ); - - if (node) { - yield extractI18nCallMessages(node); - } - } catch (error) { - if (!isFailError(error)) { - throw error; - } - - reporter.report(error); - } - } -} diff --git a/src/dev/i18n/extractors/pug.test.js b/src/dev/i18n/extractors/pug.test.js deleted file mode 100644 index 4e81f73cae8bb..0000000000000 --- a/src/dev/i18n/extractors/pug.test.js +++ /dev/null @@ -1,64 +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 { extractPugMessages } from './pug'; - -const report = jest.fn(); - -describe('dev/i18n/extractors/pug', () => { - beforeEach(() => { - report.mockClear(); - }); - - test('extracts messages from pug template with interpolation', () => { - const source = Buffer.from(`\ -#{i18n('message-id', { defaultMessage: 'Default message', description: 'Message description' })} -`); - const [messageObject] = extractPugMessages(source); - - expect(messageObject).toMatchSnapshot(); - }); - - test('extracts messages from pug template without interpolation', () => { - const source = Buffer.from(`\ -.kibanaWelcomeText(data-error-message=i18n('message-id', { defaultMessage: 'Default message', description: 'Message description' })) -`); - const [messageObject] = extractPugMessages(source); - - expect(messageObject).toMatchSnapshot(); - }); - - test('throws on empty id', () => { - const source = Buffer.from(`\ -h1= i18n('', { defaultMessage: 'Default message', description: 'Message description' }) -`); - - expect(() => extractPugMessages(source, { report }).next()).not.toThrow(); - expect(report.mock.calls).toMatchSnapshot(); - }); - - test('throws on missing default message', () => { - const source = Buffer.from(`\ -#{i18n('message-id', { description: 'Message description' })} -`); - - expect(() => extractPugMessages(source, { report }).next()).not.toThrow(); - expect(report.mock.calls).toMatchSnapshot(); - }); -}); diff --git a/src/dev/i18n/tasks/extract_untracked_translations.ts b/src/dev/i18n/tasks/extract_untracked_translations.ts index 39f8a1cc59c6b..21ab47641f2f0 100644 --- a/src/dev/i18n/tasks/extract_untracked_translations.ts +++ b/src/dev/i18n/tasks/extract_untracked_translations.ts @@ -45,7 +45,6 @@ export async function extractUntrackedMessagesTask({ const availablePaths = Object.values(config.paths).flat(); const ignore = availablePaths.concat([ '**/build/**', - '**/webpackShims/**', '**/__fixtures__/**', '**/packages/kbn-i18n/**', '**/packages/kbn-plugin-generator/sao_template/**', diff --git a/src/dev/jest/config.js b/src/dev/jest/config.js index 5249b7d652790..74e1ec5e2b4ed 100644 --- a/src/dev/jest/config.js +++ b/src/dev/jest/config.js @@ -32,6 +32,7 @@ export default { '/src/cli_plugin', '/packages/kbn-test/target/functional_test_runner', '/src/dev', + '/src/optimize', '/src/legacy/utils', '/src/setup_node_env', '/packages', diff --git a/src/dev/precommit_hook/casing_check_config.js b/src/dev/precommit_hook/casing_check_config.js index bdbd600e9aa74..19d03e41ac5a9 100644 --- a/src/dev/precommit_hook/casing_check_config.js +++ b/src/dev/precommit_hook/casing_check_config.js @@ -40,7 +40,7 @@ export const IGNORE_FILE_GLOBS = [ 'x-pack/plugins/canvas/canvas_plugin_src/**/*', 'x-pack/plugins/monitoring/public/lib/jquery_flot/**/*', '**/.*', - '**/{webpackShims,__mocks__}/**/*', + '**/__mocks__/**/*', 'x-pack/docs/**/*', 'src/core/server/core_app/assets/fonts/**/*', 'src/dev/code_coverage/ingest_coverage/integration_tests/mocks/**/*', @@ -99,7 +99,6 @@ export const KEBAB_CASE_DIRECTORY_GLOBS = ['packages/*', 'x-pack']; */ export const IGNORE_DIRECTORY_GLOBS = [ ...KEBAB_CASE_DIRECTORY_GLOBS, - '**/webpackShims', 'src/babel-*', 'packages/*', 'packages/kbn-ui-framework/generator-kui', @@ -143,35 +142,10 @@ export const TEMPORARILY_IGNORED_PATHS = [ 'src/core/server/core_app/assets/favicons/mstile-310x150.png', 'src/core/server/core_app/assets/favicons/mstile-310x310.png', 'src/core/server/core_app/assets/favicons/safari-pinned-tab.svg', - 'src/legacy/ui/public/styles/bootstrap/component-animations.less', - 'src/legacy/ui/public/styles/bootstrap/input-groups.less', - 'src/legacy/ui/public/styles/bootstrap/list-group.less', - 'src/legacy/ui/public/styles/bootstrap/mixins/background-variant.less', - 'src/legacy/ui/public/styles/bootstrap/mixins/border-radius.less', - 'src/legacy/ui/public/styles/bootstrap/mixins/center-block.less', - 'src/legacy/ui/public/styles/bootstrap/mixins/grid-framework.less', - 'src/legacy/ui/public/styles/bootstrap/mixins/hide-text.less', - 'src/legacy/ui/public/styles/bootstrap/mixins/list-group.less', - 'src/legacy/ui/public/styles/bootstrap/mixins/nav-divider.less', - 'src/legacy/ui/public/styles/bootstrap/mixins/nav-vertical-align.less', - 'src/legacy/ui/public/styles/bootstrap/mixins/progress-bar.less', - 'src/legacy/ui/public/styles/bootstrap/mixins/reset-filter.less', - 'src/legacy/ui/public/styles/bootstrap/mixins/reset-text.less', - 'src/legacy/ui/public/styles/bootstrap/mixins/responsive-visibility.less', - 'src/legacy/ui/public/styles/bootstrap/mixins/tab-focus.less', - 'src/legacy/ui/public/styles/bootstrap/mixins/table-row.less', - 'src/legacy/ui/public/styles/bootstrap/mixins/text-emphasis.less', - 'src/legacy/ui/public/styles/bootstrap/mixins/text-overflow.less', - 'src/legacy/ui/public/styles/bootstrap/mixins/vendor-prefixes.less', - 'src/legacy/ui/public/styles/bootstrap/progress-bars.less', - 'src/legacy/ui/public/styles/bootstrap/responsive-utilities.less', 'test/functional/apps/management/exports/_import_objects-conflicts.json', 'packages/kbn-ui-framework/doc_site/src/images/elastic-logo.svg', 'packages/kbn-ui-framework/doc_site/src/images/hint-arrow.svg', 'packages/kbn-ui-framework/doc_site/src/images/react-logo.svg', - 'webpackShims/elasticsearch-browser.js', - 'webpackShims/moment-timezone.js', - 'webpackShims/ui-bootstrap.js', 'x-pack/legacy/plugins/index_management/public/lib/editSettings.js', 'x-pack/legacy/plugins/license_management/public/store/reducers/licenseManagement.js', 'x-pack/plugins/monitoring/public/components/sparkline/__mocks__/plugins/xpack_main/jquery_flot.js', diff --git a/src/dev/sass/build_sass.js b/src/dev/sass/build_sass.js deleted file mode 100644 index 68058043477d0..0000000000000 --- a/src/dev/sass/build_sass.js +++ /dev/null @@ -1,94 +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 { resolve } from 'path'; - -import * as Rx from 'rxjs'; -import { toArray } from 'rxjs/operators'; - -import { createFailError } from '@kbn/dev-utils'; -import { debounce } from 'lodash'; -import { findPluginSpecs } from '../../legacy/plugin_discovery'; -import { collectUiExports } from '../../legacy/ui'; -import { buildAll } from '../../legacy/server/sass/build_all'; -import chokidar from 'chokidar'; - -// TODO: clintandrewhall - Extract and use FSWatcher from legacy/server/sass -const build = async ({ log, kibanaDir, styleSheetPaths, watch }) => { - if (styleSheetPaths.length === 0) { - return; - } - - let bundleCount = 0; - try { - const bundles = await buildAll({ - styleSheets: styleSheetPaths, - log, - buildDir: resolve(kibanaDir, 'built_assets/css'), - sourceMap: true, - }); - - bundles.forEach((bundle) => { - log.debug(`Compiled SCSS: ${bundle.sourcePath} (theme=${bundle.theme})`); - }); - - bundleCount = bundles.length; - } catch (error) { - const { message, line, file } = error; - throw createFailError(`${message} on line ${line} of ${file}`); - } - - log.success('%d scss bundles %s', bundleCount, watch ? 'rebuilt' : 'created'); -}; - -export async function buildSass({ log, kibanaDir, watch }) { - log.info('running plugin discovery in', kibanaDir); - - const scanDirs = [resolve(kibanaDir, 'src/legacy/core_plugins')]; - const paths = [resolve(kibanaDir, 'x-pack')]; - const { spec$, disabledSpec$ } = findPluginSpecs({ plugins: { scanDirs, paths } }); - const allPlugins = await Rx.merge(spec$, disabledSpec$).pipe(toArray()).toPromise(); - const uiExports = collectUiExports(allPlugins); - const { styleSheetPaths } = uiExports; - - log.info('%s %d styleSheetPaths', watch ? 'watching' : 'found', styleSheetPaths.length); - log.verbose(styleSheetPaths); - - if (watch) { - const debouncedBuild = debounce(async (path) => { - let buildPaths = styleSheetPaths; - if (path) { - buildPaths = styleSheetPaths.filter((styleSheetPath) => - path.includes(styleSheetPath.urlImports.publicDir) - ); - } - await build({ log, kibanaDir, styleSheetPaths: buildPaths, watch }); - }); - - const watchPaths = styleSheetPaths.map((styleSheetPath) => styleSheetPath.urlImports.publicDir); - - await build({ log, kibanaDir, styleSheetPaths }); - - chokidar.watch(watchPaths, { ignoreInitial: true }).on('all', (_, path) => { - debouncedBuild(path); - }); - } else { - await build({ log, kibanaDir, styleSheetPaths }); - } -} diff --git a/src/dev/sass/run_build_sass_cli.js b/src/dev/sass/run_build_sass_cli.js deleted file mode 100644 index 439d16178c417..0000000000000 --- a/src/dev/sass/run_build_sass_cli.js +++ /dev/null @@ -1,47 +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 { run } from '@kbn/dev-utils'; -import { REPO_ROOT } from '../constants'; -import { buildSass } from './build_sass'; - -run( - async ({ log, flags: { kibanaDir, watch } }) => { - await buildSass({ - log, - kibanaDir, - watch, - }); - }, - { - description: 'Simple CLI, useful for building scss files outside of the server', - flags: { - default: { - kibanaDir: REPO_ROOT, - watch: false, - }, - string: ['kibanaDir'], - boolean: ['watch'], - help: ` - --kibanaDir The root of the Kibana directory to build sass files in. - --watch Watch the SASS files and recompile them on save. - `, - }, - } -); diff --git a/src/legacy/core_plugins/kibana/index.js b/src/legacy/core_plugins/kibana/index.js index 9648ff29a95e7..2e30bc5ce05ee 100644 --- a/src/legacy/core_plugins/kibana/index.js +++ b/src/legacy/core_plugins/kibana/index.js @@ -18,7 +18,6 @@ */ import Fs from 'fs'; -import { resolve } from 'path'; import { promisify } from 'util'; import { getUiSettingDefaults } from './server/ui_setting_defaults'; @@ -40,7 +39,6 @@ export default function (kibana) { }, uiExports: { - styleSheetPaths: resolve(__dirname, 'public/index.scss'), uiSettingDefaults: getUiSettingDefaults(), }, diff --git a/src/legacy/core_plugins/status_page/index.js b/src/legacy/core_plugins/status_page/index.js deleted file mode 100644 index 5a94eb9c77160..0000000000000 --- a/src/legacy/core_plugins/status_page/index.js +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -export default function (kibana) { - return new kibana.Plugin({ - uiExports: { - app: { - title: 'Legacy Server Status', - main: 'plugins/status_page/status_page', - hidden: true, - url: '/__legacy__/status', - }, - }, - }); -} diff --git a/src/legacy/core_plugins/status_page/package.json b/src/legacy/core_plugins/status_page/package.json deleted file mode 100644 index cecfe30f1173c..0000000000000 --- a/src/legacy/core_plugins/status_page/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "status_page", - "version": "kibana" -} diff --git a/src/legacy/core_plugins/status_page/public/components/render.js b/src/legacy/core_plugins/status_page/public/components/render.js deleted file mode 100644 index dca79d783a29a..0000000000000 --- a/src/legacy/core_plugins/status_page/public/components/render.js +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import React from 'react'; -import { render, unmountComponentAtNode } from 'react-dom'; -import { I18nContext } from 'ui/i18n'; -// just to import eui into legacy -import '@elastic/eui'; - -const STATUS_PAGE_DOM_NODE_ID = 'createStatusPageReact'; - -export function renderStatusPage() { - const node = document.getElementById(STATUS_PAGE_DOM_NODE_ID); - - if (!node) { - return; - } - - render(Foo, node); -} - -export function destroyStatusPage() { - const node = document.getElementById(STATUS_PAGE_DOM_NODE_ID); - node && unmountComponentAtNode(node); -} diff --git a/src/legacy/core_plugins/status_page/public/status_page.html b/src/legacy/core_plugins/status_page/public/status_page.html deleted file mode 100644 index 6e6af4f5bc56d..0000000000000 --- a/src/legacy/core_plugins/status_page/public/status_page.html +++ /dev/null @@ -1 +0,0 @@ -
diff --git a/src/legacy/core_plugins/status_page/public/status_page.js b/src/legacy/core_plugins/status_page/public/status_page.js deleted file mode 100644 index 709164caa9e04..0000000000000 --- a/src/legacy/core_plugins/status_page/public/status_page.js +++ /dev/null @@ -1,33 +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 'ui/i18n'; -import chrome from 'ui/chrome'; -import { npStart } from 'ui/new_platform'; -import { destroyStatusPage, renderStatusPage } from './components/render'; -import template from 'plugins/status_page/status_page.html'; - -npStart.core.chrome.navLinks.enableForcedAppSwitcherNavigation(); - -chrome.setRootTemplate(template).setRootController('ui', function ($scope, buildNum, buildSha) { - $scope.$$postDigest(() => { - renderStatusPage(buildNum, buildSha.substr(0, 8)); - $scope.$on('$destroy', destroyStatusPage); - }); -}); diff --git a/src/legacy/plugin_discovery/plugin_spec/plugin_spec_options.d.ts b/src/legacy/plugin_discovery/plugin_spec/plugin_spec_options.d.ts index d668739436726..e51a355cbc8d2 100644 --- a/src/legacy/plugin_discovery/plugin_spec/plugin_spec_options.d.ts +++ b/src/legacy/plugin_discovery/plugin_spec/plugin_spec_options.d.ts @@ -24,12 +24,8 @@ import { SavedObjectsLegacyManagementDefinition } from '../../../core/server/sav export type InitPluginFunction = (server: Server) => void; export interface UiExports { injectDefaultVars?: (server: Server) => { [key: string]: any }; - styleSheetPaths?: string; savedObjectsManagement?: SavedObjectsLegacyManagementDefinition; mappings?: unknown; - visTypes?: string[]; - interpreter?: string[]; - hacks?: string[]; } export interface PluginSpecOptions { diff --git a/src/legacy/plugin_discovery/types.ts b/src/legacy/plugin_discovery/types.ts index 4d8090a138ffb..283806f69599a 100644 --- a/src/legacy/plugin_discovery/types.ts +++ b/src/legacy/plugin_discovery/types.ts @@ -66,9 +66,7 @@ export interface LegacyPluginOptions { hacks: string[]; visualize: string[]; devTools: string[]; - styleSheetPaths: string; injectDefaultVars: (server: Server) => Record; - noParse: string[]; home: string[]; mappings: any; migrations: any; diff --git a/src/legacy/server/config/schema.js b/src/legacy/server/config/schema.js index 952c35df244c1..6cd3f8dc448b0 100644 --- a/src/legacy/server/config/schema.js +++ b/src/legacy/server/config/schema.js @@ -19,9 +19,6 @@ import Joi from 'joi'; import os from 'os'; -import { join } from 'path'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { getDataPath } from '../../../core/server/path'; // Still used by optimize config schema const HANDLED_IN_NEW_PLATFORM = Joi.any().description( 'This key is handled in the new platform ONLY' @@ -161,28 +158,6 @@ export default () => maximumWaitTimeForAllCollectorsInS: Joi.number().default(60), }).default(), - optimize: Joi.object({ - enabled: Joi.boolean().default(true), - bundleFilter: Joi.string().default('!tests'), - bundleDir: Joi.string().default(join(getDataPath(), 'optimize')), - viewCaching: Joi.boolean().default(Joi.ref('$prod')), - watch: Joi.boolean().default(false), - watchPort: Joi.number().default(5602), - watchHost: Joi.string().hostname().default('localhost'), - watchPrebuild: Joi.boolean().default(false), - watchProxyTimeout: Joi.number().default(10 * 60000), - useBundleCache: Joi.boolean().default(!!process.env.CODE_COVERAGE ? true : Joi.ref('$prod')), - sourceMaps: Joi.when('$prod', { - is: true, - then: Joi.boolean().valid(false), - otherwise: Joi.alternatives() - .try(Joi.string().required(), Joi.boolean()) - .default(!!process.env.CODE_COVERAGE ? 'true' : '#cheap-source-map'), - }), - workers: Joi.number().min(1), - profile: Joi.boolean().default(false), - validateSyntaxOfNodeModules: Joi.boolean().default(true), - }).default(), status: Joi.object({ allowAnonymous: Joi.boolean().default(false), }).default(), diff --git a/src/legacy/server/http/index.js b/src/legacy/server/http/index.js index 2d62d12dfd9f3..0cab1a1609287 100644 --- a/src/legacy/server/http/index.js +++ b/src/legacy/server/http/index.js @@ -18,28 +18,18 @@ */ import { format } from 'url'; -import _ from 'lodash'; import Boom from 'boom'; import { registerHapiPlugins } from './register_hapi_plugins'; import { setupBasePathProvider } from './setup_base_path_provider'; -export default async function (kbnServer, server, config) { +export default async function (kbnServer, server) { server = kbnServer.server; setupBasePathProvider(kbnServer); await registerHapiPlugins(server); - // helper for creating view managers for servers - server.decorate('server', 'setupViews', function (path, engines) { - this.views({ - path: path, - isCached: config.get('optimize.viewCaching'), - engines: _.assign({ pug: require('pug') }, engines || {}), - }); - }); - server.route({ method: 'GET', path: '/{p*}', diff --git a/src/legacy/server/kbn_server.js b/src/legacy/server/kbn_server.js index 1168d24254911..1084521235ea0 100644 --- a/src/legacy/server/kbn_server.js +++ b/src/legacy/server/kbn_server.js @@ -31,13 +31,12 @@ import warningsMixin from './warnings'; import { statusMixin } from './status'; import pidMixin from './pid'; import configCompleteMixin from './config/complete'; -import optimizeMixin from '../../optimize'; +import { optimizeMixin } from '../../optimize'; import * as Plugins from './plugins'; import { savedObjectsMixin } from './saved_objects/saved_objects_mixin'; import { capabilitiesMixin } from './capabilities'; import { serverExtensionsMixin } from './server_extensions'; import { uiMixin } from '../ui'; -import { sassMixin } from './sass'; import { i18nMixin } from './i18n'; /** @@ -111,7 +110,6 @@ export default class KbnServer { // tell the config we are done loading plugins configCompleteMixin, - // setup this.uiBundles uiMixin, // setup saved object routes @@ -120,13 +118,9 @@ export default class KbnServer { // setup capabilities routes capabilitiesMixin, - // ensure that all bundles are built, or that the - // watch bundle server is running + // setup routes that serve the @kbn/optimizer output optimizeMixin, - // transpiles SCSS into CSS - sassMixin, - // initialize the plugins Plugins.initializeMixin, diff --git a/src/legacy/server/sass/__fixtures__/images/img.png b/src/legacy/server/sass/__fixtures__/images/img.png deleted file mode 100644 index c7738a39df3e67c91335dd28b57160e4bb11597f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3820 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 { - const relativePath = relative(root, path); - return { - path, - root, - boundry, - url: join(`${PUBLIC_PATH_PLACEHOLDER}${urlRoot}`, relativePath).replace(/\\/g, '/'), - copyTo: copyRoot ? resolve(copyRoot, relativePath) : undefined, - requestUrl: request.url, - }; -}; - -export class Build { - constructor({ log, sourcePath, targetPath, urlImports, theme }) { - this.log = log; - this.sourcePath = sourcePath; - this.sourceDir = dirname(this.sourcePath); - this.targetPath = targetPath; - this.targetDir = dirname(this.targetPath); - this.urlImports = urlImports; - this.theme = theme; - this.includedFiles = [sourcePath]; - } - - /** - * Glob based on source path - */ - async buildIfIncluded(path) { - if (this.includedFiles && this.includedFiles.includes(path)) { - await this.build(); - return true; - } - - return false; - } - - /** - * Transpiles SASS and writes CSS to output - */ - - async build() { - const scss = await readFile(this.sourcePath); - const relativeGlobalsPath = - this.theme === 'dark' - ? relative(this.sourceDir, DARK_GLOBALS_PATH) - : relative(this.sourceDir, LIGHT_GLOBALS_PATH); - - const rendered = await renderSass({ - file: this.sourcePath, - data: `@import '${relativeGlobalsPath}';\n${scss}`, - outFile: this.targetPath, - sourceMap: true, - outputStyle: 'nested', - sourceMapEmbed: true, - includePaths: [resolve(__dirname, '../../../../node_modules')], - }); - - const processor = postcss([autoprefixer]); - - const urlAssets = []; - - if (this.urlImports) { - processor.use( - postcssUrl({ - url: (request) => { - if (!request.pathname) { - return request.url; - } - - const asset = makeAsset( - request, - request.pathname.startsWith('ui/assets') - ? { - path: resolve(UI_ASSETS_DIR, relative('ui/assets', request.pathname)), - root: UI_ASSETS_DIR, - boundry: UI_ASSETS_DIR, - urlRoot: `ui/`, - } - : { - path: resolve(this.sourceDir, request.pathname), - root: this.sourceDir, - boundry: this.urlImports.publicDir, - urlRoot: this.urlImports.urlBase, - copyRoot: this.targetDir, - } - ); - - if ( - !urlAssets.some(({ path, copyTo }) => path === asset.path && copyTo === asset.copyTo) - ) { - urlAssets.push(asset); - } - - return asset.url; - }, - }) - ); - } - - const prefixed = await processor.process(rendered.css, { - from: this.sourcePath, - }); - - this.includedFiles = [...rendered.stats.includedFiles, ...urlAssets.map(({ path }) => path)]; - - // verify that asset sources exist and import is valid before writing anything - await Promise.all( - urlAssets.map(async (asset) => { - try { - await access(asset.path); - } catch (e) { - throw this._makeError( - 'Invalid url() in css output', - `url("${asset.requestUrl}") resolves to "${asset.path}", which does not exist.\n` + - ` Make sure that the request is relative to "${asset.root}"` - ); - } - - if (!isPathInside(asset.path, asset.boundry)) { - throw this._makeError( - 'Invalid url() in css output', - `url("${asset.requestUrl}") resolves to "${asset.path}"\n` + - ` which is outside of "${asset.boundry}"` - ); - } - }) - ); - - // write css - await mkdirAsync(this.targetDir, { recursive: true }); - await writeFile(this.targetPath, prefixed.css); - - // copy non-shared urlAssets - await Promise.all( - urlAssets.map(async (asset) => { - if (!asset.copyTo) { - return; - } - - await mkdirAsync(dirname(asset.copyTo), { recursive: true }); - await copyFile(asset.path, asset.copyTo); - }) - ); - - return this; - } - - _makeError(title, message) { - const error = new Error(`${chalk.red(`${title} [${this.sourcePath}]`)}\n\n ${message}\n`); - error.file = this.sourcePath; - return error; - } -} diff --git a/src/legacy/server/sass/build.test.js b/src/legacy/server/sass/build.test.js deleted file mode 100644 index 155c300bf3036..0000000000000 --- a/src/legacy/server/sass/build.test.js +++ /dev/null @@ -1,119 +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 { dirname, resolve } from 'path'; -import { readFileSync } from 'fs'; -import globby from 'globby'; - -import del from 'del'; - -import { Build } from './build'; - -const TMP = resolve(__dirname, '__tmp__'); -const FIXTURE = resolve(__dirname, '__fixtures__/index.scss'); - -afterEach(async () => { - await del(TMP); -}); - -it('builds light themed SASS', async () => { - // Increased timeout from 5000ms due to intermittent timeout failures - jest.setTimeout(60000); - const targetPath = resolve(TMP, 'style.css'); - await new Build({ - sourcePath: FIXTURE, - log: { - info: () => {}, - warn: () => {}, - error: () => {}, - }, - theme: 'light', - targetPath, - }).build(); - - expect(readFileSync(targetPath, 'utf8').replace(/(\/\*# sourceMappingURL=).*( \*\/)/, '$1...$2')) - .toMatchInlineSnapshot(` - "foo bar { - display: flex; - background: #e6f0f8 url(./images/img.png) url(ui/assets/favicons/favicon.ico); } - /*# sourceMappingURL=... */" - `); -}); - -it('builds dark themed SASS', async () => { - const targetPath = resolve(TMP, 'style.css'); - await new Build({ - sourcePath: FIXTURE, - log: { - info: () => {}, - warn: () => {}, - error: () => {}, - }, - theme: 'dark', - targetPath, - }).build(); - - expect(readFileSync(targetPath, 'utf8').replace(/(\/\*# sourceMappingURL=).*( \*\/)/, '$1...$2')) - .toMatchInlineSnapshot(` - "foo bar { - display: flex; - background: #232635 url(./images/img.png) url(ui/assets/favicons/favicon.ico); } - /*# sourceMappingURL=... */" - `); -}); - -it('rewrites url imports', async () => { - const targetPath = resolve(TMP, 'style.css'); - await new Build({ - sourcePath: FIXTURE, - log: { - info: () => {}, - warn: () => {}, - error: () => {}, - }, - theme: 'dark', - targetPath, - urlImports: { - publicDir: dirname(FIXTURE), - urlBase: 'foo/bar', - }, - }).build(); - - expect(readFileSync(targetPath, 'utf8').replace(/(\/\*# sourceMappingURL=).*( \*\/)/, '$1...$2')) - .toMatchInlineSnapshot(` - "foo bar { - display: flex; - background: #232635 url(__REPLACE_WITH_PUBLIC_PATH__foo/bar/images/img.png) url(__REPLACE_WITH_PUBLIC_PATH__ui/favicons/favicon.ico); } - /*# sourceMappingURL=... */" - `); - - expect( - Buffer.compare( - readFileSync(resolve(TMP, 'images/img.png')), - readFileSync(resolve(dirname(FIXTURE), 'images/img.png')) - ) - ).toBe(0); - - expect(await globby('**/*', { cwd: TMP })).toMatchInlineSnapshot(` - Array [ - "style.css", - "images/img.png", - ] - `); -}); diff --git a/src/legacy/server/sass/build_all.js b/src/legacy/server/sass/build_all.js deleted file mode 100644 index dac6ac87a40d3..0000000000000 --- a/src/legacy/server/sass/build_all.js +++ /dev/null @@ -1,45 +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 { resolve } from 'path'; - -import { Build } from './build'; - -export async function buildAll({ styleSheets, log, buildDir }) { - const bundles = await Promise.all( - styleSheets.map(async (styleSheet) => { - if (!styleSheet.localPath.endsWith('.scss')) { - return; - } - - const bundle = new Build({ - sourcePath: styleSheet.localPath, - log, - theme: styleSheet.theme, - targetPath: resolve(buildDir, styleSheet.publicPath), - urlImports: styleSheet.urlImports, - }); - await bundle.build(); - - return bundle; - }) - ); - - return bundles.filter((v) => v); -} diff --git a/src/legacy/server/sass/index.js b/src/legacy/server/sass/index.js deleted file mode 100644 index 001457d110276..0000000000000 --- a/src/legacy/server/sass/index.js +++ /dev/null @@ -1,137 +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 { IS_KIBANA_DISTRIBUTABLE } from '../../utils'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { fromRoot } from '../../../core/server/utils'; - -export async function sassMixin(kbnServer, server, config) { - if (process.env.kbnWorkerType === 'optmzr') { - return; - } - - /** - * Build assets - * - * SCSS is only transpiled while running from source - */ - - if (IS_KIBANA_DISTRIBUTABLE) { - return; - } - - const { buildAll } = require('./build_all'); - let scssBundles = []; - let trackedFiles = new Set(); - - const log = { - info: (msg) => server.log(['info', 'scss'], msg), - warn: (msg) => server.log(['warn', 'scss'], msg), - error: (msg) => server.log(['error', 'scss'], msg), - }; - - try { - scssBundles = await buildAll({ - styleSheets: kbnServer.uiExports.styleSheetPaths, - log, - buildDir: fromRoot('built_assets/css'), - }); - - scssBundles.forEach((bundle) => { - bundle.includedFiles.forEach((file) => trackedFiles.add(file)); - server.log(['info', 'scss'], `Compiled CSS: ${bundle.sourcePath} (theme=${bundle.theme})`); - }); - } catch (error) { - const { message, line, file } = error; - if (!file) { - throw error; - } - - trackedFiles.add(file); - server.log(['error', 'scss'], `${message}${line ? ` on line ${line} of ${file}` : ''}`); - } - - /** - * Setup Watchers - * - * Similar to the optimizer, we only setup watchers while in development mode - */ - - if (!config.get('env').dev) { - return; - } - - const { FSWatcher } = require('chokidar'); - const watcher = new FSWatcher({ ignoreInitial: true }); - - watcher.add([...trackedFiles]); - - watcher.on('all', async (event, path) => { - const currentlyTrackedFiles = new Set(); - - server.log(['debug', 'scss'], `${path} triggered ${event}`); - - // build bundles containing the changed file - await Promise.all( - scssBundles.map(async (bundle) => { - try { - if (await bundle.buildIfIncluded(path)) { - server.log(['info', 'scss'], `Compiled ${bundle.sourcePath} due to change in ${path}`); - } - // if the bundle rebuilt, includedFiles is the new set; otherwise includedFiles is unchanged and remains tracked - bundle.includedFiles.forEach((file) => currentlyTrackedFiles.add(file)); - } catch (error) { - const { message, line, file } = error; - if (!file) { - throw error; - } - - currentlyTrackedFiles.add(file); - server.log(['error', 'scss'], `${message}${line ? ` on line ${line} of ${file}` : ''}`); - } - }, []) - ); - - /** - * update watchers - */ - - // un-watch files no longer included in any bundle - trackedFiles.forEach((file) => { - if (currentlyTrackedFiles.has(file)) { - return; - } - - watcher.unwatch(file); - server.log(['debug', 'scss'], `No longer watching ${file}`); - }); - - // watch files not previously included in any bundle - currentlyTrackedFiles.forEach((file) => { - if (trackedFiles.has(file)) { - return; - } - - watcher.add(file); - server.log(['debug', 'scss'], `Now watching ${file}`); - }); - - trackedFiles = currentlyTrackedFiles; - }); -} diff --git a/src/legacy/server/views/index.pug b/src/legacy/server/views/index.pug deleted file mode 100644 index 8711217ec6a74..0000000000000 --- a/src/legacy/server/views/index.pug +++ /dev/null @@ -1,6 +0,0 @@ -html - head - title Kibana Status - body - h1 Kibana Status Page - p Statusy stuff goes here... it's going to be totally awesome! diff --git a/src/legacy/ui/public/UI_SYSTEMS.md b/src/legacy/ui/public/UI_SYSTEMS.md deleted file mode 100644 index 8462b2c8f4144..0000000000000 --- a/src/legacy/ui/public/UI_SYSTEMS.md +++ /dev/null @@ -1,8 +0,0 @@ -# UI Systems - -In this directory you'll find various UI systems you can use to craft effective user experiences within Kibana. - -## ui/notify - -* [banners](notify/banners/BANNERS.md) -* [toastNotifications](../../../plugins/kibana_legacy/public/notify/toasts/TOAST_NOTIFICATIONS.md) diff --git a/src/legacy/ui/public/chrome/__mocks__/index.js b/src/legacy/ui/public/chrome/__mocks__/index.js index d6f0df83a0e3d..cf977cd2c9f81 100644 --- a/src/legacy/ui/public/chrome/__mocks__/index.js +++ b/src/legacy/ui/public/chrome/__mocks__/index.js @@ -60,12 +60,6 @@ const internals = _.defaults(_.cloneDeep(metadata), { const waitForBootstrap = new Promise((resolve) => { chrome.bootstrap = function (targetDomElement) { - // import chrome nav controls and hacks now so that they are executed after - // everything else, can safely import the chrome, and interact with services - // and such setup by all other modules - require('uiExports/chromeNavControls'); - require('uiExports/hacks'); - // sets attribute on body for stylesheet sandboxing document.body.setAttribute('id', `${internals.app.id}-app`); diff --git a/src/legacy/ui/public/chrome/chrome.js b/src/legacy/ui/public/chrome/chrome.js index 0640017f7806a..cdb0734f61622 100644 --- a/src/legacy/ui/public/chrome/chrome.js +++ b/src/legacy/ui/public/chrome/chrome.js @@ -81,12 +81,6 @@ npStart.core.chrome.setAppTitle(chrome.getAppTitle()); const waitForBootstrap = new Promise((resolve) => { chrome.bootstrap = function (targetDomElement) { - // import chrome nav controls and hacks now so that they are executed after - // everything else, can safely import the chrome, and interact with services - // and such setup by all other modules - require('uiExports/chromeNavControls'); - require('uiExports/hacks'); - // sets attribute on body for stylesheet sandboxing document.body.setAttribute('id', `${internals.app.id}-app`); diff --git a/src/legacy/ui/public/styles/bootstrap/_colors_dark.less b/src/legacy/ui/public/styles/bootstrap/_colors_dark.less deleted file mode 100644 index 677a829cd5d1e..0000000000000 --- a/src/legacy/ui/public/styles/bootstrap/_colors_dark.less +++ /dev/null @@ -1,20 +0,0 @@ -//== Colors -// -//## Gray and brand colors for use across Bootstrap. -@white: #1D1E24; -@blue: #1BA9F5; - -@brand-primary: #F5F7FA; -@brand-success: #7DE2D1; -@brand-info: @blue; -@brand-warning: #FF977A; -@brand-danger: #FF6666; - -@gray-base: #FFF; -@gray-darker: #F5F7FA; -@gray-dark: #ababab; -@gray5: #D4DAE5; -@gray: #535966; -@gray-light: darken(#535966, 9%); -@gray-lighter: #343741; -@gray-lightest: #25262E; diff --git a/src/legacy/ui/public/styles/bootstrap/_colors_light.less b/src/legacy/ui/public/styles/bootstrap/_colors_light.less deleted file mode 100644 index adea876322f0d..0000000000000 --- a/src/legacy/ui/public/styles/bootstrap/_colors_light.less +++ /dev/null @@ -1,20 +0,0 @@ -//== Colors -// -//## Gray and brand colors for use across Bootstrap. -@white: #FFF; -@blue: #006BB4; - -@brand-primary: #343741; -@brand-success: #017D73; -@brand-info: @blue; -@brand-warning: #F5A700; -@brand-danger: #BD271E; - -@gray-base: #000; -@gray-darker: #343741; -@gray-dark: #7b7b7b; -@gray5: #69707D; -@gray: #98A2B3; -@gray-light: lighten(#98A2B3, 9%); // ~#b4b4b4 -@gray-lighter: #D3DAE6; -@gray-lightest: #F5F7FA; diff --git a/src/legacy/ui/public/styles/bootstrap/_custom_variables.less b/src/legacy/ui/public/styles/bootstrap/_custom_variables.less deleted file mode 100644 index a348e7bfa86b8..0000000000000 --- a/src/legacy/ui/public/styles/bootstrap/_custom_variables.less +++ /dev/null @@ -1,443 +0,0 @@ -//== Scaffolding -// -// ## Settings for some of the most global styles. - -//** Background color for ``. -@body-bg: @white; -//** Global text color on ``. -@text-color: @brand-primary; - - -//** Global textual link color. -@link-color: @blue; -@link-hover-color: darken(@link-color, 10%); -@link-hover-decoration: none; - -//== Typography -// -//## Font, line-height, and color for body text, headings, and more. -@font-family-sans-serif: 'Open Sans', Helvetica, Arial, sans-serif; -//** Default monospace fonts for ``, ``, and `

`.
-@font-family-monospace:   'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace;
-
-//** By default, this inherits from the ``.
-@headings-font-family:    @font-family-base;
-@headings-font-weight:    400;
-@headings-line-height:    1.3;
-
-//-- Iconography
-//
-//## Specify custom locations of the include Glyphicons icon font. Useful for those including Bootstrap via Bower.
-
-@icon-font-path:          "../fonts/";
-@icon-font-name:          "glyphicons-halflings-regular";
-@icon-font-svg-id:        "glyphicons_halflingsregular";
-
-//== Components
-//
-//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
-
-@padding-base-vertical:     5px;
-@padding-base-horizontal:   15px;
-
-@padding-large-vertical:    18px;
-@padding-large-horizontal:  27px;
-
-@padding-small-vertical:    6px;
-@padding-small-horizontal:  9px;
-
-@padding-xs-vertical:       1px;
-@padding-xs-horizontal:     5px;
-
-@border-radius-base:        4px;
-@border-radius-large:       4px;
-@border-radius-small:       4px;
-
-//** Global color for active items (e.g., navs or dropdowns).
-@component-active-color:    @white;
-
-
-//== Tables
-//
-//## Customizes the `.table` component with basic values, each used across all table variations.
-
-//** Background color used for `.table-striped`.
-@table-bg-accent:           @gray-lighter;
-//** Background color used for `.table-hover`.
-@table-bg-hover:            @gray-lighter;
-//** Border color for table and cell borders.
-@table-border-color:        @gray-lighter;
-
-
-//== Buttons
-//
-//## For each of Bootstrap's buttons, define text, background and border color.
-
-@btn-default-color:         @white;
-@btn-default-bg:            @blue;
-@btn-default-border:        @blue;
-
-@btn-primary-color:         @white;
-@btn-primary-bg:            @blue;
-@btn-primary-border:        @blue;
-
-@btn-success-color:         @btn-default-color;
-@btn-success-bg:            @blue;
-@btn-success-border:        @blue;
-
-@btn-info-color:            @btn-default-color;
-@btn-info-bg:               @brand-info;
-@btn-info-border:           @btn-info-bg;
-
-@btn-warning-color:         @btn-default-color;
-@btn-warning-bg:            @brand-warning;
-@btn-warning-border:        @btn-warning-bg;
-
-@btn-danger-color:          @btn-default-color;
-@btn-danger-bg:             @brand-danger;
-@btn-danger-border:         @btn-danger-bg;
-
-
-//== Forms
-//
-//##
-
-
-//** `` background color
-@input-bg:                       lighten(@gray-lightest, 1.5%);
-//** Placeholder text color
-@input-color-placeholder:        @gray;
-
-//** Text color for ``s
-@input-color:                     @text-color;
-//** `` border color
-@input-border:                    @gray-lighter;
-//** Border color for inputs on focus
-@input-border-focus:              @blue;
-
-@legend-color:                    @text-color;
-@legend-border-color:             transparent;
-
-
-//== Dropdowns
-//
-//## Dropdown menu container and contents.
-
-//** Background for the dropdown menu.
-@dropdown-bg:                   @white;
-//** Dropdown menu `border-color`.
-@dropdown-border:               @gray-lighter;
-//** Dropdown menu `border-color` **for IE8**.
-@dropdown-fallback-border:      @gray-lighter;
-//** Divider color for between dropdown items.
-@dropdown-divider-bg:           @gray-lighter;
-
-//** Hover color for dropdown links.
-@dropdown-link-hover-color:     @white;
-//** Hover background for dropdown links.
-@dropdown-link-hover-bg:        @dropdown-link-active-bg;
-
-//** Active dropdown menu item text color.
-@dropdown-link-active-color:    @white;
-
-//** Disabled dropdown menu item background color.
-@dropdown-link-disabled-color:  @gray;
-
-//** Text color for headers within dropdown menus.
-@dropdown-header-color:         @gray;
-
-// Note: Deprecated @dropdown-caret-color as of v3.1.0
-@dropdown-caret-color:          @gray-base;
-
-
-//-- Z-index master list
-//
-// Warning: Avoid customizing these values. They're used for a bird's eye view
-// of components dependent on the z-axis and are designed to all work together.
-//
-// Note: These variables are not generated into the Customizer.
-
-@zindex-dropdown:          1000;
-@zindex-popover:           1010;
-@zindex-typeahead:         1030;
-@zindex-tooltip:           1040;
-@zindex-navbar-fixed:      1050;
-@zindex-modal-background:  1060;
-@zindex-modal:             1070;
-
-
-//== Navbar
-//
-//##
-
-// Basics of a navbar
-@navbar-height:                    45px;
-@navbar-margin:                    @padding-small-vertical;
-@navbar-margin-bottom:             0px;
-@navbar-border-radius:             @border-radius-base;
-@navbar-padding-horizontal:        10px;
-
-// Default theme
-@navbar-default-bg:                     @gray-lightest;
-@navbar-default-color:                  @gray5;
-@navbar-default-border:                 transparent;
-@navbar-default-link-color:             @gray5;
-@navbar-default-link-hover-color:       @gray5;
-@navbar-default-link-active-color:      @brand-primary;
-@navbar-default-link-active-bg:         transparent;
-@navbar-default-link-disabled-color:    @gray5;
-
-// Navbar brand label
-@navbar-default-brand-color:            @navbar-default-link-color;
-@navbar-default-brand-hover-color:      @navbar-default-link-hover-color;
-@navbar-default-brand-hover-bg:         transparent;
-
-// Navbar toggle
-@navbar-default-toggle-hover-bg:        darken(@navbar-default-bg, 10%);
-@navbar-default-toggle-icon-bar-bg:     @white;
-@navbar-default-toggle-border-color:    darken(@navbar-default-bg, 10%);
-
-
-// Inverted navbar
-// Reset inverted navbar basics
-@navbar-inverse-link-active-bg:         @gray5;
-@navbar-inverse-color:                  @white;
-@navbar-inverse-bg:                     @gray-darker;
-@navbar-inverse-border:                 darken(@navbar-inverse-bg, 10%);
-
-// Inverted navbar links
-@navbar-inverse-link-color:             @gray-lighter;
-@navbar-inverse-link-hover-color:       @white;
-@navbar-inverse-link-hover-bg:          lighten(@navbar-inverse-bg, 20%);
-@navbar-inverse-link-active-color:      @white;
-@navbar-inverse-link-disabled-color:    @gray-light;
-@navbar-inverse-link-disabled-bg:       transparent;
-
-// Inverted navbar brand label
-@navbar-inverse-brand-color:            @white;
-@navbar-inverse-brand-bg:               lighten(@navbar-inverse-bg, 10%);
-@navbar-inverse-brand-hover-color:      @navbar-inverse-brand-color;
-@navbar-inverse-brand-hover-bg:         @navbar-inverse-brand-bg;
-
-// Inverted navbar toggle
-@navbar-inverse-toggle-hover-bg:        darken(@navbar-inverse-bg, 10%);
-@navbar-inverse-toggle-icon-bar-bg:     @white;
-@navbar-inverse-toggle-border-color:    darken(@navbar-inverse-bg, 10%);
-
-@navbar-default-badge-bg: @white;
-@navbar-default-badge-color: @navbar-default-bg;
-@navbar-inverse-badge-bg: @white;
-@navbar-inverse-badge-color: lighten(@navbar-inverse-bg, 10%);
-@navbar-nav-active-link-border: @body-bg;
-
-//== Navs
-//
-//##
-
-//== Tabs
-@nav-tabs-border-color:                           @gray-lighter;
-@nav-tabs-link-hover-border-color:                @white;
-@nav-tabs-active-link-hover-bg:                   @white;
-@nav-tabs-active-link-hover-color:                @brand-primary;
-@nav-tabs-active-link-hover-border-color:         @white;
-@nav-tabs-justified-link-border-color:            @white;
-
-//== Pills
-@nav-pills-active-link-hover-bg:                  @blue;
-@nav-pills-active-link-hover-color:               @white;
-
-//== Pagination
-//
-//##
-
-@pagination-color:                      @link-color;
-@pagination-bg:                         transparent;
-@pagination-border:                     transparent;
-@pagination-hover-color:                @link-color;
-@pagination-hover-bg:                   darken(transparent, 15%);
-@pagination-hover-border:               transparent;
-@pagination-active-color:               @text-color;
-@pagination-active-bg:                  darken(transparent, 15%);
-@pagination-active-border:              transparent;
-@pagination-disabled-color:             @gray-darker;
-@pagination-disabled-bg:                lighten(transparent, 15%);
-@pagination-disabled-border:            transparent;
-
-
-//== Pager
-//
-//##
-
-@pager-disabled-color:                 @white;
-@pager-border-radius:                  0;
-
-
-//== Form states and alerts
-//
-//## Define colors for form feedback states and, by default, alerts.
-
-@state-success-text:                    @white;
-@state-success-bg:                      @brand-success;
-@state-success-border:                  darken(@brand-success, 10%);
-@state-info-text:                       @white;
-@state-info-bg:                         @brand-info;
-@state-info-border:                     darken(@brand-info, 10%);
-@state-warning-text:                    @white;
-@state-warning-bg:                      @brand-warning;
-@state-warning-border:                  darken(@brand-warning, 10%);
-@state-danger-text:                     @white;
-@state-danger-bg:                       @brand-danger;
-@state-danger-border:                   darken(@brand-danger, 10%);
-
-
-//== Tooltips
-//
-//##
-
-@tooltip-opacity:                       .8;
-
-//== Popovers
-//
-//##
-
-//** Popover body background color
-@popover-bg:                            @white;
-//** Popover border color
-@popover-border-color:                  @gray-lighter;
-//** Popover fallback border color
-@popover-fallback-border-color:         @gray-lighter;
-//** Popover outer arrow fallback color
-@popover-arrow-outer-fallback-color:    darken(@popover-fallback-border-color, 20%);
-
-//== Labels
-//
-//##
-
-//** Default label background color
-@label-default-bg:                      @btn-default-bg;
-//** Default label text color
-@label-color:                           @white;
-//** Default text color of a linked label
-@label-link-hover-color:                @white;
-
-
-//== Modals
-//
-//##
-
-//** Background color of modal content area
-@modal-content-bg:                      @white;
-//** Modal content border color **for IE8**
-@modal-content-fallback-border-color:   @gray;
-//** Modal backdrop background color
-@modal-backdrop-bg:                     @gray-base;
-
-
-//== Progress bars
-//
-//##
-
-//** Background color of the whole progress component
-@progress-bg:                 @gray-lighter;
-//** Progress bar text color
-@progress-bar-color:          @white;
-
-//** Background color of the whole progress component
-@progress-bg:                           shade(@gray-lighter, 13%);
-//** Default progress bar color
-@progress-bar-bg:                       #54B399;
-
-//== List group
-//
-//##
-
-//** Background color on `.list-group-item`
-@list-group-bg:                         @white;
-//** `.list-group-item` border color
-@list-group-border:                     @gray-lighter;
-//** Text color of active list items
-@list-group-active-color:               @text-color;
-
-@list-group-link-color:                 @gray5;
-@list-group-link-heading-color:         @brand-primary;
-
-
-//== Panels
-//
-//##
-
-@panel-bg:                              @white;
-//** Border color for elements within panels
-@panel-inner-border:                    @gray-lighter;
-@panel-default-border:                  @gray-lighter;
-@panel-primary-text:                    @white;
-
-
-//== Thumbnails
-//
-//##
-
-//** Thumbnail border color
-@thumbnail-border:                      @gray-lighter;
-
-
-//== Wells
-//
-//##
-
-@well-bg:                               #F5F7FA;
-@well-border:                           transparent;
-
-
-//== Badges
-//
-//##
-
-@badge-color:                           @white;
-//** Linked badge text color on hover
-@badge-link-hover-color:                @white;
-@badge-bg:                              @brand-primary;
-//** Badge text color in active nav link
-@badge-active-color:                    @brand-primary;
-//** Badge background color in active nav link
-@badge-active-bg:                       @white;
-
-
-//== Breadcrumbs
-//
-//##
-
-//** Breadcrumb background color
-@breadcrumb-bg:                         @gray-lighter;
-//** Breadcrumb text color
-@breadcrumb-color:                      @gray-light;
-//** Text color of current page in the breadcrumb
-@breadcrumb-active-color:               @gray;
-
-
-//== Close
-//
-//##
-
-@close-color:                           @gray-base;
-@close-text-shadow:                     none;
-
-
-//== Code
-//
-//##
-
-@kbd-color:                             @white;
-@kbd-bg:                                @brand-primary;
-@pre-bg:                                @gray-lighter;
-@pre-color:                             @gray-darker;
-@pre-border-color:                      @gray-lighter;
-
-//== Type
-//
-//##
-
-//** Headings small color
-@headings-small-color:                  @brand-primary;
-//** Page header border color
-@page-header-border-color:              transparent;
diff --git a/src/legacy/ui/public/styles/bootstrap/_custom_variables_dark_overrides.less b/src/legacy/ui/public/styles/bootstrap/_custom_variables_dark_overrides.less
deleted file mode 100644
index c546e447c705d..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/_custom_variables_dark_overrides.less
+++ /dev/null
@@ -1,4 +0,0 @@
-@navbar-default-bg: darken(@gray-lighter, 50%);
-
-//** `` background color
-@input-bg: darken(@gray-lightest, 5%);
diff --git a/src/legacy/ui/public/styles/bootstrap/_overrides.less b/src/legacy/ui/public/styles/bootstrap/_overrides.less
deleted file mode 100644
index ae0edd12a7015..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/_overrides.less
+++ /dev/null
@@ -1,252 +0,0 @@
-// Navbar =====================================================================
-
-.navbar > .container-fluid {
-  > .navbar-nav,
-  > .navbar-form {
-    &:not(.pull-right):first-child {
-      // This is how .navbar-brand accomplishes it's solid placement
-      margin-left: -15px;
-      margin-top: 4px;
-    }
-  }
-}
-
-.navbar {
-  border-width: 0;
-}
-
-  .navbar-btn-link {
-    margin: 0;
-    border-radius: 0;
-
-    @media (max-width: @screen-sm-min) {
-      width: 100%;
-      text-align: left;
-    }
-  }
-
-  .navbar-default {
-    .badge {
-      background-color: @navbar-default-badge-bg;
-      color: @navbar-default-badge-color;
-    }
-  }
-
-  .navbar-inverse {
-    .kbnGlobalNav__logoBrand {
-      height: @navbar-height;
-      width: 252px;
-      background-color: @navbar-inverse-brand-bg;
-    }
-
-    .kbnGlobalNav__smallLogoBrand {
-      height: @navbar-height;
-      width: 45px;
-      background-color: @navbar-inverse-brand-bg;
-    }
-
-    .badge {
-      background-color: @navbar-inverse-badge-bg;
-      color: @navbar-inverse-badge-color;
-    }
-  }
-
-  .navbar-brand {
-    cursor: default;
-    font-size: 1.8em;
-    user-select: none;
-  }
-
-  .navbar-nav {
-    font-size: @font-size-small;
-
-    & > .active > a {
-      border-bottom-color: @gray-dark;
-      background-color: transparent;
-    }
-  }
-
-  .navbar-toggle {
-    margin-top: 4px;
-  }
-
-
-// Typography =================================================================
-
-.text-primary,
-.text-primary:hover {
-  color: @brand-primary;
-}
-
-.text-success,
-.text-success:hover {
-  color: @brand-success;
-}
-
-.text-danger,
-.text-danger:hover {
-  color: @brand-danger;
-}
-
-.text-warning,
-.text-warning:hover {
-  color: @brand-warning;
-}
-
-.text-info,
-.text-info:hover {
-  color: @brand-info;
-}
-
-// Tables =====================================================================
-
-table,
-.table {
-
-  .success,
-  .warning,
-  .danger,
-  .info {
-    color: @white;
-
-    a {
-      color: @white;
-    }
-  }
-}
-
-  .table-bordered > thead > tr > th,
-  .table-bordered > tbody > tr > th,
-  .table-bordered > tfoot > tr > th,
-  .table-bordered > thead > tr > td,
-  .table-bordered > tbody > tr > td,
-  .table-bordered > tfoot > tr > td {
-    border: 1px solid @table-border-color;
-  }
-
-// Forms ======================================================================
-
-.form-control,
-input {
-  border-width: 1px;
-  .box-shadow(none);
-
-  &:focus {
-    .box-shadow(none);
-  }
-}
-
-.has-warning {
-  .help-block,
-  .control-label,
-  .radio,
-  .checkbox,
-  .radio-inline,
-  .checkbox-inline,
-  .form-control-feedback {
-    color: @brand-warning;
-  }
-
-  .form-control,
-  .form-control:focus {
-    border: 1px solid;
-    border-color: @brand-warning;
-  }
-
-  .input-group-addon {
-    border-color: @brand-warning;
-  }
-}
-
-.has-error {
-  .help-block,
-  .control-label,
-  .radio,
-  .checkbox,
-  .radio-inline,
-  .checkbox-inline,
-  .form-control-feedback {
-    color: @brand-danger;
-  }
-
-  .form-control,
-  .form-control:focus {
-    border: 1px solid;
-    border-color: @brand-danger;
-  }
-
-  .input-group-addon {
-    border-color: @brand-danger;
-  }
-}
-
-.has-success {
-  .help-block,
-  .control-label,
-  .radio,
-  .checkbox,
-  .radio-inline,
-  .checkbox-inline,
-  .form-control-feedback {
-    color: @brand-success;
-  }
-
-  .form-control,
-  .form-control:focus {
-    border: solid @brand-success;
-  }
-
-  .input-group-addon {
-    border-color: @brand-success;
-  }
-}
-
-// Navs =======================================================================
-
-.nav {
-  .open > a,
-  .open > a:hover,
-  .open > a:focus {
-    border-color: transparent;
-  }
-}
-
-.pager {
-  a,
-  a:hover {
-    color: @white;
-  }
-
-  .disabled {
-    &>a,
-    &>a:hover,
-    &>a:focus,
-    &>span {
-      background-color: @pagination-disabled-bg;
-    }
-  }
-}
-
-
-// Panel =================================================================
-
-.panel {
-  border-radius: 0;
-  .box-shadow(0 0 0 rgba(0,0,0,0));
-}
-
-// Progress bars ==============================================================
-
-.progress {
-  .box-shadow(none);
-  .progress-bar {
-    font-size: 10px;
-    line-height: 10px;
-  }
-}
-
-// Containers =================================================================
-
-.well {
-  .box-shadow(none);
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/alerts.less b/src/legacy/ui/public/styles/bootstrap/alerts.less
deleted file mode 100644
index c4199db927e79..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/alerts.less
+++ /dev/null
@@ -1,73 +0,0 @@
-//
-// Alerts
-// --------------------------------------------------
-
-
-// Base styles
-// -------------------------
-
-.alert {
-  padding: @alert-padding;
-  margin-bottom: @line-height-computed;
-  border: 1px solid transparent;
-  border-radius: @alert-border-radius;
-
-  // Headings for larger alerts
-  h4 {
-    margin-top: 0;
-    // Specified for the h4 to prevent conflicts of changing @headings-color
-    color: inherit;
-  }
-
-  // Provide class for links that match alerts
-  .alert-link {
-    font-weight: @alert-link-font-weight;
-  }
-
-  // Improve alignment and spacing of inner content
-  > p,
-  > ul {
-    margin-bottom: 0;
-  }
-
-  > p + p {
-    margin-top: 5px;
-  }
-}
-
-// Dismissible alerts
-//
-// Expand the right padding and account for the close button's positioning.
-
-.alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0.
-.alert-dismissible {
-  padding-right: (@alert-padding + 20);
-
-  // Adjust close link position
-  .close {
-    position: relative;
-    top: -2px;
-    right: -21px;
-    color: inherit;
-  }
-}
-
-// Alternate styles
-//
-// Generate contextual modifier classes for colorizing the alert.
-
-.alert-success {
-  .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);
-}
-
-.alert-info {
-  .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);
-}
-
-.alert-warning {
-  .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);
-}
-
-.alert-danger {
-  .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/bootstrap_dark.less b/src/legacy/ui/public/styles/bootstrap/bootstrap_dark.less
deleted file mode 100644
index 459efed37dd75..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/bootstrap_dark.less
+++ /dev/null
@@ -1,77 +0,0 @@
-/*!
- * Bootstrap v3.3.6 (http://getbootstrap.com)
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- */
-
-/* @notice
- * This product bundles bootstrap@3.3.6 which is available under a
- * "MIT" license.
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2011-2015 Twitter, Inc
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-// PLANNED FOR REMOVAL
-// We are trying to remove bootstrap. The below are the files we're currently using.
-// There's an audit in the comments to cover what's left to remove.
-
-// Core variables and mixins
-@import "variables.less";
-@import "_colors_dark.less";
-@import "_custom_variables.less";
-@import "_custom_variables_dark_overrides.less";
-@import "mixins.less";
-
-// Hard to remove, used in many places
-@import "grid.less"; // Used in a lot of places
-@import "tables.less"; // Used in a lot of places
-@import "forms.less"; // Used in a lot of places
-
-// Easy to remove
-@import "type.less"; // Can be search / replaced with EUI
-@import "component-animations.less"; // Used in angular bootstrap
-@import "buttons.less";
-@import "navbar.less"; // Used in Graph
-@import "close.less"; // Only in angular-bootstrap
-@import "modals.less"; // Only in angular-bootstrap
-@import "progress-bars.less"; // Used in ML, angular-bootstrap
-@import "list-group.less"; // Used in Timelion, Graph
-@import "navs.less"; // Used in ML
-@import "alerts.less"; // Only in angular-bootstrap
-@import "tooltip.less"; // Only in angular-bootstrap
-@import "responsive-utilities.less"; // Minimal usage
-
-// Decent usage in multiple areas
-@import "dropdowns.less"; // Used in console, watcher
-@import "input-groups.less"; // Used in ML, typeahead, reporting, graph
-@import "pagination.less";
-@import "pager.less";
-@import "labels.less"; // Hard to judge usage because of generic selector names
-@import "panels.less"; // Used in ML, dashboards, notify, angular-bootstrap
-@import "popovers.less"; // Hard to judge usage because of generic selector names
-
-// Utility classes
-@import "utilities.less";
-
-// OVERRIDES
-@import "_overrides.less";
diff --git a/src/legacy/ui/public/styles/bootstrap/bootstrap_light.less b/src/legacy/ui/public/styles/bootstrap/bootstrap_light.less
deleted file mode 100644
index e049b62f3dc2c..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/bootstrap_light.less
+++ /dev/null
@@ -1,76 +0,0 @@
-/*!
- * Bootstrap v3.3.6 (http://getbootstrap.com)
- * Copyright 2011-2015 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- */
-
-/* @notice
- * This product bundles bootstrap@3.3.6 which is available under a
- * "MIT" license.
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2011-2015 Twitter, Inc
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-// PLANNED FOR REMOVAL
-// We are trying to remove bootstrap. The below are the files we're currently using.
-// There's an audit in the comments to cover what's left to remove.
-
-// Core variables and mixins
-@import "variables.less";
-@import "_colors_light.less";
-@import "_custom_variables.less";
-@import "mixins.less";
-
-// Hard to remove, used in many places
-@import "grid.less"; // Used in a lot of places
-@import "tables.less"; // Used in a lot of places
-@import "forms.less"; // Used in a lot of places
-
-// Easy to remove
-@import "type.less"; // Can be search / replaced with EUI
-@import "component-animations.less"; // Used in angular bootstrap
-@import "buttons.less";
-@import "navbar.less"; // Used in Graph
-@import "close.less"; // Only in angular-bootstrap
-@import "modals.less"; // Only in angular-bootstrap
-@import "progress-bars.less"; // Used in ML, angular-bootstrap
-@import "list-group.less"; // Used in Timelion, Graph
-@import "navs.less"; // Used in ML
-@import "alerts.less"; // Only in angular-bootstrap
-@import "tooltip.less"; // Only in angular-bootstrap
-@import "responsive-utilities.less"; // Minimal usage
-
-// Decent usage in multiple areas
-@import "dropdowns.less"; // Used in console, datepicker, watcher
-@import "input-groups.less"; // Used in ML, typeahead, reporting, graph
-@import "pagination.less";
-@import "pager.less";
-@import "labels.less"; // Hard to judge usage because of generic selector names
-@import "panels.less"; // Used in ML, dashboards, notify, angular-bootstrap
-@import "popovers.less"; // Hard to judge usage because of generic selector names
-
-// Utility classes
-@import "utilities.less";
-
-// OVERRIDES
-@import "_overrides.less";
diff --git a/src/legacy/ui/public/styles/bootstrap/buttons.less b/src/legacy/ui/public/styles/bootstrap/buttons.less
deleted file mode 100644
index 04bc13b0d9c6e..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/buttons.less
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- * ui/angular-ui-select depends upon these styles. Don't use them in your markup.
- * Please use the UI Framework styles instead.
- */
-
-.btn {
-  display: inline-block;
-  margin-bottom: 0; // For input.btn
-  font-weight: @btn-font-weight;
-  text-align: center;
-  vertical-align: middle;
-  touch-action: manipulation;
-  cursor: pointer;
-  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214
-  border: 1px solid transparent;
-  white-space: nowrap;
-  .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @btn-border-radius-base);
-  .user-select(none);
-
-  &,
-  &:active,
-  &.active {
-    &:focus,
-    &.focus {
-      .tab-focus();
-    }
-  }
-
-  &:hover,
-  &:focus,
-  &.focus {
-    color: @btn-default-color;
-    text-decoration: none;
-  }
-
-  &:active,
-  &.active {
-    outline: 0;
-    background-image: none;
-    .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));
-  }
-
-  &.disabled,
-  &[disabled],
-  fieldset[disabled] & {
-    cursor: @cursor-disabled;
-    .opacity(.65);
-    .box-shadow(none);
-  }
-
-  a& {
-    &.disabled,
-    fieldset[disabled] & {
-      pointer-events: none; // Future-proof disabling of clicks on `` elements
-    }
-  }
-}
-
-.btn-default {
-  .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border);
-}
-
-.btn-primary {
-  .button-variant(@btn-primary-color; @btn-primary-bg; @btn-primary-border);
-}
-
-.btn-xs {
-  .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @btn-border-radius-small);
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/close.less b/src/legacy/ui/public/styles/bootstrap/close.less
deleted file mode 100644
index 6d5bfe087aed3..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/close.less
+++ /dev/null
@@ -1,34 +0,0 @@
-//
-// Close icons
-// --------------------------------------------------
-
-
-.close {
-  float: right;
-  font-size: (@font-size-base * 1.5);
-  font-weight: @close-font-weight;
-  line-height: 1;
-  color: @close-color;
-  text-shadow: @close-text-shadow;
-  .opacity(.2);
-
-  &:hover,
-  &:focus {
-    color: @close-color;
-    text-decoration: none;
-    cursor: pointer;
-    .opacity(.5);
-  }
-
-  // Additional properties for button version
-  // iOS requires the button element instead of an anchor tag.
-  // If you want the anchor version, it requires `href="#"`.
-  // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile
-  button& {
-    padding: 0;
-    cursor: pointer;
-    background: transparent;
-    border: 0;
-    -webkit-appearance: none;
-  }
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/component-animations.less b/src/legacy/ui/public/styles/bootstrap/component-animations.less
deleted file mode 100644
index 0bcee910ac5f2..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/component-animations.less
+++ /dev/null
@@ -1,33 +0,0 @@
-//
-// Component animations
-// --------------------------------------------------
-
-// Heads up!
-//
-// We don't use the `.opacity()` mixin here since it causes a bug with text
-// fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552.
-
-.fade {
-  opacity: 0;
-  .transition(opacity .15s linear);
-  &.in {
-    opacity: 1;
-  }
-}
-
-.collapse {
-  display: none;
-
-  &.in      { display: block; }
-  tr&.in    { display: table-row; }
-  tbody&.in { display: table-row-group; }
-}
-
-.collapsing {
-  position: relative;
-  height: 0;
-  overflow: hidden;
-  .transition-property(~"height, visibility");
-  .transition-duration(.35s);
-  .transition-timing-function(ease);
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/dropdowns.less b/src/legacy/ui/public/styles/bootstrap/dropdowns.less
deleted file mode 100644
index b0376eb4a6317..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/dropdowns.less
+++ /dev/null
@@ -1,227 +0,0 @@
-//
-// Dropdown menus
-// --------------------------------------------------
-
-
-// Dropdown arrow/caret
-.caret {
-  display: inline-block;
-  width: 0;
-  height: 0;
-  margin-left: 2px;
-  vertical-align: middle;
-  border-top:   @caret-width-base dashed;
-  border-top:   @caret-width-base solid ~"\9"; // IE8
-  border-right: @caret-width-base solid transparent;
-  border-left:  @caret-width-base solid transparent;
-}
-
-// The dropdown wrapper (div)
-.dropup,
-.dropdown {
-  position: relative;
-}
-
-// Prevent the focus on the dropdown toggle when closing dropdowns
-.dropdown-toggle:focus {
-  outline: 0;
-}
-
-// The dropdown menu (ul)
-.dropdown-menu {
-  position: absolute;
-  top: 100%;
-  left: 0;
-  z-index: @zindex-dropdown;
-  display: none; // none by default, but block on "open" of the menu
-  float: left;
-  min-width: 160px;
-  padding: 5px 0;
-  margin: 2px 0 0; // override default ul
-  list-style: none;
-  font-size: @font-size-base;
-  text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)
-  background-color: @dropdown-bg;
-  border: 1px solid @dropdown-fallback-border; // IE8 fallback
-  border: 1px solid @dropdown-border;
-  border-radius: @border-radius-base;
-  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.1);
-  background-clip: padding-box;
-
-  // Aligns the dropdown menu to right
-  //
-  // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]`
-  &.pull-right {
-    right: 0;
-    left: auto;
-  }
-
-  // Dividers (basically an hr) within the dropdown
-  .divider {
-    .nav-divider(@dropdown-divider-bg);
-  }
-
-  // Links within the dropdown menu
-  > li > a,
-  > li > button {
-    display: block;
-    padding: 3px 20px;
-    clear: both;
-    font-weight: normal;
-    line-height: @line-height-base;
-    color: @dropdown-link-color;
-    white-space: nowrap; // prevent links from randomly breaking onto new lines
-  }
-
-  > li > button {
-    appearance: none;
-    background: none;
-    border: none;
-    width: 100%;
-    text-align: left;
-  }
-}
-
-// Hover/Focus state
-.dropdown-menu > li > a,
-.dropdown-menu > li > button {
-  &:hover,
-  &:focus {
-    text-decoration: none;
-    color: @dropdown-link-hover-color;
-    background-color: @dropdown-link-hover-bg;
-  }
-}
-
-// Active state
-.dropdown-menu > .active > button,
-.dropdown-menu > .active > a {
-  &,
-  &:hover,
-  &:focus {
-    color: @dropdown-link-active-color;
-    text-decoration: none;
-    outline: 0;
-    background-color: @dropdown-link-active-bg;
-  }
-}
-
-// Disabled state
-//
-// Gray out text and ensure the hover/focus state remains gray
-
-.dropdown-menu > .disabled > a {
-  &,
-  &:hover,
-  &:focus {
-    color: @dropdown-link-disabled-color;
-  }
-
-  // Nuke hover/focus effects
-  &:hover,
-  &:focus {
-    text-decoration: none;
-    background-color: transparent;
-    background-image: none; // Remove CSS gradient
-    .reset-filter();
-    cursor: @cursor-disabled;
-  }
-}
-
-// Open state for the dropdown
-.open {
-  // Show the menu
-  > .dropdown-menu {
-    display: block;
-  }
-
-  // Remove the outline when :focus is triggered
-  > a {
-    outline: 0;
-  }
-}
-
-// Menu positioning
-//
-// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown
-// menu with the parent.
-.dropdown-menu-right {
-  left: auto; // Reset the default from `.dropdown-menu`
-  right: 0;
-}
-// With v3, we enabled auto-flipping if you have a dropdown within a right
-// aligned nav component. To enable the undoing of that, we provide an override
-// to restore the default dropdown menu alignment.
-//
-// This is only for left-aligning a dropdown menu within a `.navbar-right` or
-// `.pull-right` nav component.
-.dropdown-menu-left {
-  left: 0;
-  right: auto;
-}
-
-// Dropdown section headers
-.dropdown-header {
-  display: block;
-  padding: 3px 20px;
-  font-size: @font-size-small;
-  line-height: @line-height-base;
-  color: @dropdown-header-color;
-  white-space: nowrap; // as with > li > a
-}
-
-// Backdrop to catch body clicks on mobile, etc.
-.dropdown-backdrop {
-  position: fixed;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  top: 0;
-  z-index: (@zindex-dropdown - 10);
-}
-
-// Right aligned dropdowns
-.pull-right > .dropdown-menu {
-  right: 0;
-  left: auto;
-}
-
-// Allow for dropdowns to go bottom up (aka, dropup-menu)
-//
-// Just add .dropup after the standard .dropdown class and you're set, bro.
-// TODO: abstract this so that the navbar fixed styles are not placed here?
-
-.dropup,
-.navbar-fixed-bottom .dropdown {
-  // Reverse the caret
-  .caret {
-    border-top: 0;
-    border-bottom: @caret-width-base dashed;
-    border-bottom: @caret-width-base solid ~"\9"; // IE8
-    content: "";
-  }
-  // Different positioning for bottom up menu
-  .dropdown-menu {
-    top: auto;
-    bottom: 100%;
-    margin-bottom: 2px;
-  }
-}
-
-
-// Component alignment
-//
-// Reiterate per navbar.less and the modified component alignment there.
-
-@media (min-width: @grid-float-breakpoint) {
-  .navbar-right {
-    .dropdown-menu {
-      .dropdown-menu-right();
-    }
-    // Necessary for overrides of the default right aligned menu.
-    // Will remove come v4 in all likelihood.
-    .dropdown-menu-left {
-      .dropdown-menu-left();
-    }
-  }
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/forms.less b/src/legacy/ui/public/styles/bootstrap/forms.less
deleted file mode 100644
index 20636ec6f22cf..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/forms.less
+++ /dev/null
@@ -1,470 +0,0 @@
-//
-// Forms
-// --------------------------------------------------
-
-
-// Common form controls
-//
-// Shared size and type resets for form controls. Apply `.form-control` to any
-// of the following form controls:
-//
-// select
-// textarea
-// input[type="text"]
-// input[type="password"]
-// input[type="datetime"]
-// input[type="datetime-local"]
-// input[type="date"]
-// input[type="month"]
-// input[type="time"]
-// input[type="week"]
-// input[type="number"]
-// input[type="email"]
-// input[type="url"]
-// input[type="search"]
-// input[type="tel"]
-// input[type="color"]
-
-.form-control {
-  display: block;
-  width: 100%;
-  height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border)
-  padding: @padding-base-vertical @padding-base-horizontal;
-  font-size: @font-size-base;
-  line-height: @line-height-base;
-  color: @input-color;
-  background-color: @input-bg;
-  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214
-  border: 1px solid @input-border;
-  border-radius: @input-border-radius-base; // Note: This has no effect on s in CSS.
-  .box-shadow(inset 0 1px 1px rgba(0,0,0,.075));
-  .transition(~"border-color ease-in-out .15s, box-shadow ease-in-out .15s");
-
-  // Customize the `:focus` state to imitate native WebKit styles.
-  .form-control-focus();
-
-  // Placeholder
-  .placeholder();
-
-  // Unstyle the caret on ``
-// element gets special love because it's special, and that's a fact!
-.input-size(@input-height; @padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {
-  height: @input-height;
-  padding: @padding-vertical @padding-horizontal;
-  font-size: @font-size;
-  line-height: @line-height;
-  border-radius: @border-radius;
-
-  select& {
-    height: @input-height;
-    line-height: @input-height;
-  }
-
-  textarea&,
-  select[multiple]& {
-    height: auto;
-  }
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/gradients.less b/src/legacy/ui/public/styles/bootstrap/mixins/gradients.less
deleted file mode 100644
index 0b88a89cc56a6..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/gradients.less
+++ /dev/null
@@ -1,59 +0,0 @@
-// Gradients
-
-#gradient {
-
-  // Horizontal gradient, from left to right
-  //
-  // Creates two color stops, start and end, by specifying a color and position for each color stop.
-  // Color stops are not available in IE9 and below.
-  .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {
-    background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+
-    background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12
-    background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+
-    background-repeat: repeat-x;
-    filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",argb(@start-color),argb(@end-color))); // IE9 and down
-  }
-
-  // Vertical gradient, from top to bottom
-  //
-  // Creates two color stops, start and end, by specifying a color and position for each color stop.
-  // Color stops are not available in IE9 and below.
-  .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {
-    background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent);  // Safari 5.1-6, Chrome 10+
-    background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent);  // Opera 12
-    background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+
-    background-repeat: repeat-x;
-    filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@start-color),argb(@end-color))); // IE9 and down
-  }
-
-  .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {
-    background-repeat: repeat-x;
-    background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+
-    background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12
-    background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+
-  }
-  .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {
-    background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);
-    background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);
-    background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);
-    background-repeat: no-repeat;
-    filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback
-  }
-  .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {
-    background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);
-    background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);
-    background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);
-    background-repeat: no-repeat;
-    filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback
-  }
-  .radial(@inner-color: #555; @outer-color: #333) {
-    background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);
-    background-image: radial-gradient(circle, @inner-color, @outer-color);
-    background-repeat: no-repeat;
-  }
-  .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {
-    background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);
-    background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);
-    background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);
-  }
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/grid-framework.less b/src/legacy/ui/public/styles/bootstrap/mixins/grid-framework.less
deleted file mode 100644
index 8c23eed24e60e..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/grid-framework.less
+++ /dev/null
@@ -1,91 +0,0 @@
-// Framework grid generation
-//
-// Used only by Bootstrap to generate the correct number of grid classes given
-// any value of `@grid-columns`.
-
-.make-grid-columns() {
-  // Common styles for all sizes of grid columns, widths 1-12
-  .col(@index) { // initial
-    @item: ~".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}";
-    .col((@index + 1), @item);
-  }
-  .col(@index, @list) when (@index =< @grid-columns) { // general; "=<" isn't a typo
-    @item: ~".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}";
-    .col((@index + 1), ~"@{list}, @{item}");
-  }
-  .col(@index, @list) when (@index > @grid-columns) { // terminal
-    @{list} {
-      position: relative;
-      // Prevent columns from collapsing when empty
-      min-height: 1px;
-      // Inner gutter via padding
-      padding-left:  ceil((@grid-gutter-width / 2));
-      padding-right: floor((@grid-gutter-width / 2));
-    }
-  }
-  .col(1); // kickstart it
-}
-
-.float-grid-columns(@class) {
-  .col(@index) { // initial
-    @item: ~".col-@{class}-@{index}";
-    .col((@index + 1), @item);
-  }
-  .col(@index, @list) when (@index =< @grid-columns) { // general
-    @item: ~".col-@{class}-@{index}";
-    .col((@index + 1), ~"@{list}, @{item}");
-  }
-  .col(@index, @list) when (@index > @grid-columns) { // terminal
-    @{list} {
-      float: left;
-    }
-  }
-  .col(1); // kickstart it
-}
-
-.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {
-  .col-@{class}-@{index} {
-    width: percentage((@index / @grid-columns));
-  }
-}
-.calc-grid-column(@index, @class, @type) when (@type = push) and (@index > 0) {
-  .col-@{class}-push-@{index} {
-    left: percentage((@index / @grid-columns));
-  }
-}
-.calc-grid-column(@index, @class, @type) when (@type = push) and (@index = 0) {
-  .col-@{class}-push-0 {
-    left: auto;
-  }
-}
-.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index > 0) {
-  .col-@{class}-pull-@{index} {
-    right: percentage((@index / @grid-columns));
-  }
-}
-.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index = 0) {
-  .col-@{class}-pull-0 {
-    right: auto;
-  }
-}
-.calc-grid-column(@index, @class, @type) when (@type = offset) {
-  .col-@{class}-offset-@{index} {
-    margin-left: percentage((@index / @grid-columns));
-  }
-}
-
-// Basic looping in LESS
-.loop-grid-columns(@index, @class, @type) when (@index >= 0) {
-  .calc-grid-column(@index, @class, @type);
-  // next iteration
-  .loop-grid-columns((@index - 1), @class, @type);
-}
-
-// Create grid for specific class
-.make-grid(@class) {
-  .float-grid-columns(@class);
-  .loop-grid-columns(@grid-columns, @class, width);
-  .loop-grid-columns(@grid-columns, @class, pull);
-  .loop-grid-columns(@grid-columns, @class, push);
-  .loop-grid-columns(@grid-columns, @class, offset);
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/grid.less b/src/legacy/ui/public/styles/bootstrap/mixins/grid.less
deleted file mode 100644
index df496d0b3c1a9..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/grid.less
+++ /dev/null
@@ -1,122 +0,0 @@
-// Grid system
-//
-// Generate semantic grid columns with these mixins.
-
-// Centered container element
-.container-fixed(@gutter: @grid-gutter-width) {
-  margin-right: auto;
-  margin-left: auto;
-  padding-left:  floor((@gutter / 2));
-  padding-right: ceil((@gutter / 2));
-  &:extend(.clearfix all);
-}
-
-// Creates a wrapper for a series of columns
-.make-row(@gutter: @grid-gutter-width) {
-  margin-left:  ceil((@gutter / -2));
-  margin-right: floor((@gutter / -2));
-  &:extend(.clearfix all);
-}
-
-// Generate the extra small columns
-.make-xs-column(@columns; @gutter: @grid-gutter-width) {
-  position: relative;
-  float: left;
-  width: percentage((@columns / @grid-columns));
-  min-height: 1px;
-  padding-left:  (@gutter / 2);
-  padding-right: (@gutter / 2);
-}
-.make-xs-column-offset(@columns) {
-  margin-left: percentage((@columns / @grid-columns));
-}
-.make-xs-column-push(@columns) {
-  left: percentage((@columns / @grid-columns));
-}
-.make-xs-column-pull(@columns) {
-  right: percentage((@columns / @grid-columns));
-}
-
-// Generate the small columns
-.make-sm-column(@columns; @gutter: @grid-gutter-width) {
-  position: relative;
-  min-height: 1px;
-  padding-left:  (@gutter / 2);
-  padding-right: (@gutter / 2);
-
-  @media (min-width: @screen-sm-min) {
-    float: left;
-    width: percentage((@columns / @grid-columns));
-  }
-}
-.make-sm-column-offset(@columns) {
-  @media (min-width: @screen-sm-min) {
-    margin-left: percentage((@columns / @grid-columns));
-  }
-}
-.make-sm-column-push(@columns) {
-  @media (min-width: @screen-sm-min) {
-    left: percentage((@columns / @grid-columns));
-  }
-}
-.make-sm-column-pull(@columns) {
-  @media (min-width: @screen-sm-min) {
-    right: percentage((@columns / @grid-columns));
-  }
-}
-
-// Generate the medium columns
-.make-md-column(@columns; @gutter: @grid-gutter-width) {
-  position: relative;
-  min-height: 1px;
-  padding-left:  (@gutter / 2);
-  padding-right: (@gutter / 2);
-
-  @media (min-width: @screen-md-min) {
-    float: left;
-    width: percentage((@columns / @grid-columns));
-  }
-}
-.make-md-column-offset(@columns) {
-  @media (min-width: @screen-md-min) {
-    margin-left: percentage((@columns / @grid-columns));
-  }
-}
-.make-md-column-push(@columns) {
-  @media (min-width: @screen-md-min) {
-    left: percentage((@columns / @grid-columns));
-  }
-}
-.make-md-column-pull(@columns) {
-  @media (min-width: @screen-md-min) {
-    right: percentage((@columns / @grid-columns));
-  }
-}
-
-// Generate the large columns
-.make-lg-column(@columns; @gutter: @grid-gutter-width) {
-  position: relative;
-  min-height: 1px;
-  padding-left:  (@gutter / 2);
-  padding-right: (@gutter / 2);
-
-  @media (min-width: @screen-lg-min) {
-    float: left;
-    width: percentage((@columns / @grid-columns));
-  }
-}
-.make-lg-column-offset(@columns) {
-  @media (min-width: @screen-lg-min) {
-    margin-left: percentage((@columns / @grid-columns));
-  }
-}
-.make-lg-column-push(@columns) {
-  @media (min-width: @screen-lg-min) {
-    left: percentage((@columns / @grid-columns));
-  }
-}
-.make-lg-column-pull(@columns) {
-  @media (min-width: @screen-lg-min) {
-    right: percentage((@columns / @grid-columns));
-  }
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/hide-text.less b/src/legacy/ui/public/styles/bootstrap/mixins/hide-text.less
deleted file mode 100644
index 2bb84a3b444fc..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/hide-text.less
+++ /dev/null
@@ -1,21 +0,0 @@
-// CSS image replacement
-//
-// Heads up! v3 launched with only `.hide-text()`, but per our pattern for
-// mixins being reused as classes with the same name, this doesn't hold up. As
-// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`.
-//
-// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757
-
-// Deprecated as of v3.0.1 (has been removed in v4)
-.hide-text() {
-  font: ~"0/0" a;
-  color: transparent;
-  text-shadow: none;
-  background-color: transparent;
-  border: 0;
-}
-
-// New mixin to use as of v3.0.1
-.text-hide() {
-  .hide-text();
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/image.less b/src/legacy/ui/public/styles/bootstrap/mixins/image.less
deleted file mode 100644
index f233cb3e199f2..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/image.less
+++ /dev/null
@@ -1,33 +0,0 @@
-// Image Mixins
-// - Responsive image
-// - Retina image
-
-
-// Responsive image
-//
-// Keep images from scaling beyond the width of their parents.
-.img-responsive(@display: block) {
-  display: @display;
-  max-width: 100%; // Part 1: Set a maximum relative to the parent
-  height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching
-}
-
-
-// Retina image
-//
-// Short retina mixin for setting background-image and -size. Note that the
-// spelling of `min--moz-device-pixel-ratio` is intentional.
-.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {
-  background-image: url("@{file-1x}");
-
-  @media
-  only screen and (-webkit-min-device-pixel-ratio: 2),
-  only screen and (   min--moz-device-pixel-ratio: 2),
-  only screen and (     -o-min-device-pixel-ratio: 2/1),
-  only screen and (        min-device-pixel-ratio: 2),
-  only screen and (                min-resolution: 192dpi),
-  only screen and (                min-resolution: 2dppx) {
-    background-image: url("@{file-2x}");
-    background-size: @width-1x @height-1x;
-  }
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/labels.less b/src/legacy/ui/public/styles/bootstrap/mixins/labels.less
deleted file mode 100644
index 9f7a67ee3d08a..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/labels.less
+++ /dev/null
@@ -1,12 +0,0 @@
-// Labels
-
-.label-variant(@color) {
-  background-color: @color;
-
-  &[href] {
-    &:hover,
-    &:focus {
-      background-color: darken(@color, 10%);
-    }
-  }
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/list-group.less b/src/legacy/ui/public/styles/bootstrap/mixins/list-group.less
deleted file mode 100644
index 03aa19069d954..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/list-group.less
+++ /dev/null
@@ -1,30 +0,0 @@
-// List Groups
-
-.list-group-item-variant(@state; @background; @color) {
-  .list-group-item-@{state} {
-    color: @color;
-    background-color: @background;
-
-    a&,
-    button& {
-      color: @color;
-
-      .list-group-item-heading {
-        color: inherit;
-      }
-
-      &:hover,
-      &:focus {
-        color: @color;
-        background-color: darken(@background, 5%);
-      }
-      &.active,
-      &.active:hover,
-      &.active:focus {
-        color: #fff;
-        background-color: @color;
-        border-color: @color;
-      }
-    }
-  }
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/nav-divider.less b/src/legacy/ui/public/styles/bootstrap/mixins/nav-divider.less
deleted file mode 100644
index feb1e9ed0dad8..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/nav-divider.less
+++ /dev/null
@@ -1,10 +0,0 @@
-// Horizontal dividers
-//
-// Dividers (basically an hr) within dropdowns and nav lists
-
-.nav-divider(@color: #e5e5e5) {
-  height: 1px;
-  margin: ((@line-height-computed / 2) - 1) 0;
-  overflow: hidden;
-  background-color: @color;
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/nav-vertical-align.less b/src/legacy/ui/public/styles/bootstrap/mixins/nav-vertical-align.less
deleted file mode 100644
index d458c78613e6d..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/nav-vertical-align.less
+++ /dev/null
@@ -1,9 +0,0 @@
-// Navbar vertical align
-//
-// Vertically center elements in the navbar.
-// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.
-
-.navbar-vertical-align(@element-height) {
-  margin-top: ((@navbar-height - @element-height) / 2);
-  margin-bottom: ((@navbar-height - @element-height) / 2);
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/opacity.less b/src/legacy/ui/public/styles/bootstrap/mixins/opacity.less
deleted file mode 100644
index 33ed25ce6763d..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/opacity.less
+++ /dev/null
@@ -1,8 +0,0 @@
-// Opacity
-
-.opacity(@opacity) {
-  opacity: @opacity;
-  // IE8 filter
-  @opacity-ie: (@opacity * 100);
-  filter: ~"alpha(opacity=@{opacity-ie})";
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/pagination.less b/src/legacy/ui/public/styles/bootstrap/mixins/pagination.less
deleted file mode 100644
index 618804f2dee3e..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/pagination.less
+++ /dev/null
@@ -1,24 +0,0 @@
-// Pagination
-
-.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {
-  > li {
-    > a,
-    > span {
-      padding: @padding-vertical @padding-horizontal;
-      font-size: @font-size;
-      line-height: @line-height;
-    }
-    &:first-child {
-      > a,
-      > span {
-        .border-left-radius(@border-radius);
-      }
-    }
-    &:last-child {
-      > a,
-      > span {
-        .border-right-radius(@border-radius);
-      }
-    }
-  }
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/panels.less b/src/legacy/ui/public/styles/bootstrap/mixins/panels.less
deleted file mode 100644
index 49ee10d4ad39d..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/panels.less
+++ /dev/null
@@ -1,24 +0,0 @@
-// Panels
-
-.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) {
-  border-color: @border;
-
-  & > .panel-heading {
-    color: @heading-text-color;
-    background-color: @heading-bg-color;
-    border-color: @heading-border;
-
-    + .panel-collapse > .panel-body {
-      border-top-color: @border;
-    }
-    .badge {
-      color: @heading-bg-color;
-      background-color: @heading-text-color;
-    }
-  }
-  & > .panel-footer {
-    + .panel-collapse > .panel-body {
-      border-bottom-color: @border;
-    }
-  }
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/progress-bar.less b/src/legacy/ui/public/styles/bootstrap/mixins/progress-bar.less
deleted file mode 100644
index f07996a34dbc1..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/progress-bar.less
+++ /dev/null
@@ -1,10 +0,0 @@
-// Progress bars
-
-.progress-bar-variant(@color) {
-  background-color: @color;
-
-  // Deprecated parent class requirement as of v3.2.0
-  .progress-striped & {
-    #gradient > .striped();
-  }
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/reset-filter.less b/src/legacy/ui/public/styles/bootstrap/mixins/reset-filter.less
deleted file mode 100644
index 68cdb5e18602a..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/reset-filter.less
+++ /dev/null
@@ -1,8 +0,0 @@
-// Reset filters for IE
-//
-// When you need to remove a gradient background, do not forget to use this to reset
-// the IE filter for IE9 and below.
-
-.reset-filter() {
-  filter: e(%("progid:DXImageTransform.Microsoft.gradient(enabled = false)"));
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/reset-text.less b/src/legacy/ui/public/styles/bootstrap/mixins/reset-text.less
deleted file mode 100644
index 58dd4d19b4d1f..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/reset-text.less
+++ /dev/null
@@ -1,18 +0,0 @@
-.reset-text() {
-  font-family: @font-family-base;
-  // We deliberately do NOT reset font-size.
-  font-style: normal;
-  font-weight: normal;
-  letter-spacing: normal;
-  line-break: auto;
-  line-height: @line-height-base;
-  text-align: left; // Fallback for where `start` is not supported
-  text-align: start;
-  text-decoration: none;
-  text-shadow: none;
-  text-transform: none;
-  white-space: normal;
-  word-break: normal;
-  word-spacing: normal;
-  word-wrap: normal;
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/resize.less b/src/legacy/ui/public/styles/bootstrap/mixins/resize.less
deleted file mode 100644
index 3acd3afdbacbb..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/resize.less
+++ /dev/null
@@ -1,6 +0,0 @@
-// Resize anything
-
-.resizable(@direction) {
-  resize: @direction; // Options: horizontal, vertical, both
-  overflow: auto; // Per CSS3 UI, `resize` only applies when `overflow` isn't `visible`
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/responsive-visibility.less b/src/legacy/ui/public/styles/bootstrap/mixins/responsive-visibility.less
deleted file mode 100644
index ecf1e979fd25c..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/responsive-visibility.less
+++ /dev/null
@@ -1,15 +0,0 @@
-// Responsive utilities
-
-//
-// More easily include all the states for responsive-utilities.less.
-.responsive-visibility() {
-  display: block !important;
-  table&  { display: table !important; }
-  tr&     { display: table-row !important; }
-  th&,
-  td&     { display: table-cell !important; }
-}
-
-.responsive-invisibility() {
-  display: none !important;
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/size.less b/src/legacy/ui/public/styles/bootstrap/mixins/size.less
deleted file mode 100644
index a8be650896068..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/size.less
+++ /dev/null
@@ -1,10 +0,0 @@
-// Sizing shortcuts
-
-.size(@width; @height) {
-  width: @width;
-  height: @height;
-}
-
-.square(@size) {
-  .size(@size; @size);
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/tab-focus.less b/src/legacy/ui/public/styles/bootstrap/mixins/tab-focus.less
deleted file mode 100644
index a868f344d7bec..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/tab-focus.less
+++ /dev/null
@@ -1,5 +0,0 @@
-// WebKit-style focus
-
-.tab-focus() {
-  box-shadow: 0 0 0 1px white, 0 0 0 2px #0079a5; /* 3 */
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/table-row.less b/src/legacy/ui/public/styles/bootstrap/mixins/table-row.less
deleted file mode 100644
index 0f287f1a8bdf5..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/table-row.less
+++ /dev/null
@@ -1,28 +0,0 @@
-// Tables
-
-.table-row-variant(@state; @background) {
-  // Exact selectors below required to override `.table-striped` and prevent
-  // inheritance to nested tables.
-  .table > thead > tr,
-  .table > tbody > tr,
-  .table > tfoot > tr {
-    > td.@{state},
-    > th.@{state},
-    &.@{state} > td,
-    &.@{state} > th {
-      background-color: @background;
-    }
-  }
-
-  // Hover states for `.table-hover`
-  // Note: this is not available for cells or rows within `thead` or `tfoot`.
-  .table-hover > tbody > tr {
-    > td.@{state}:hover,
-    > th.@{state}:hover,
-    &.@{state}:hover > td,
-    &:hover > .@{state},
-    &.@{state}:hover > th {
-      background-color: darken(@background, 5%);
-    }
-  }
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/text-emphasis.less b/src/legacy/ui/public/styles/bootstrap/mixins/text-emphasis.less
deleted file mode 100644
index 9e8a77a6985f0..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/text-emphasis.less
+++ /dev/null
@@ -1,9 +0,0 @@
-// Typography
-
-.text-emphasis-variant(@color) {
-  color: @color;
-  a&:hover,
-  a&:focus {
-    color: darken(@color, 10%);
-  }
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/text-overflow.less b/src/legacy/ui/public/styles/bootstrap/mixins/text-overflow.less
deleted file mode 100644
index c11ad2fb7471d..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/text-overflow.less
+++ /dev/null
@@ -1,8 +0,0 @@
-// Text overflow
-// Requires inline-block or block for proper styling
-
-.text-overflow() {
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/mixins/vendor-prefixes.less b/src/legacy/ui/public/styles/bootstrap/mixins/vendor-prefixes.less
deleted file mode 100644
index 2b5e74b99ed68..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/mixins/vendor-prefixes.less
+++ /dev/null
@@ -1,227 +0,0 @@
-// Vendor Prefixes
-//
-// All vendor mixins are deprecated as of v3.2.0 due to the introduction of
-// Autoprefixer in our Gruntfile. They have been removed in v4.
-
-// - Animations
-// - Backface visibility
-// - Box shadow
-// - Box sizing
-// - Content columns
-// - Hyphens
-// - Placeholder text
-// - Transformations
-// - Transitions
-// - User Select
-
-
-// Animations
-.animation(@animation) {
-  -webkit-animation: @animation;
-       -o-animation: @animation;
-          animation: @animation;
-}
-.animation-name(@name) {
-  -webkit-animation-name: @name;
-          animation-name: @name;
-}
-.animation-duration(@duration) {
-  -webkit-animation-duration: @duration;
-          animation-duration: @duration;
-}
-.animation-timing-function(@timing-function) {
-  -webkit-animation-timing-function: @timing-function;
-          animation-timing-function: @timing-function;
-}
-.animation-delay(@delay) {
-  -webkit-animation-delay: @delay;
-          animation-delay: @delay;
-}
-.animation-iteration-count(@iteration-count) {
-  -webkit-animation-iteration-count: @iteration-count;
-          animation-iteration-count: @iteration-count;
-}
-.animation-direction(@direction) {
-  -webkit-animation-direction: @direction;
-          animation-direction: @direction;
-}
-.animation-fill-mode(@fill-mode) {
-  -webkit-animation-fill-mode: @fill-mode;
-          animation-fill-mode: @fill-mode;
-}
-
-// Backface visibility
-// Prevent browsers from flickering when using CSS 3D transforms.
-// Default value is `visible`, but can be changed to `hidden`
-
-.backface-visibility(@visibility) {
-  -webkit-backface-visibility: @visibility;
-     -moz-backface-visibility: @visibility;
-          backface-visibility: @visibility;
-}
-
-// Drop shadows
-//
-// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's
-// supported browsers that have box shadow capabilities now support it.
-
-.box-shadow(@shadow) {
-  -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1
-          box-shadow: @shadow;
-}
-
-// Box sizing
-.box-sizing(@boxmodel) {
-  -webkit-box-sizing: @boxmodel;
-     -moz-box-sizing: @boxmodel;
-          box-sizing: @boxmodel;
-}
-
-// CSS3 Content Columns
-.content-columns(@column-count; @column-gap: @grid-gutter-width) {
-  -webkit-column-count: @column-count;
-     -moz-column-count: @column-count;
-          column-count: @column-count;
-  -webkit-column-gap: @column-gap;
-     -moz-column-gap: @column-gap;
-          column-gap: @column-gap;
-}
-
-// Optional hyphenation
-.hyphens(@mode: auto) {
-  word-wrap: break-word;
-  -webkit-hyphens: @mode;
-     -moz-hyphens: @mode;
-      -ms-hyphens: @mode; // IE10+
-       -o-hyphens: @mode;
-          hyphens: @mode;
-}
-
-// Placeholder text
-.placeholder(@color: @input-color-placeholder) {
-  // Firefox
-  &::-moz-placeholder {
-    color: @color;
-    opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526
-  }
-  &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+
-  &::-webkit-input-placeholder  { color: @color; } // Safari and Chrome
-}
-
-// Transformations
-.scale(@ratio) {
-  -webkit-transform: scale(@ratio);
-      -ms-transform: scale(@ratio); // IE9 only
-       -o-transform: scale(@ratio);
-          transform: scale(@ratio);
-}
-.scale(@ratioX; @ratioY) {
-  -webkit-transform: scale(@ratioX, @ratioY);
-      -ms-transform: scale(@ratioX, @ratioY); // IE9 only
-       -o-transform: scale(@ratioX, @ratioY);
-          transform: scale(@ratioX, @ratioY);
-}
-.scaleX(@ratio) {
-  -webkit-transform: scaleX(@ratio);
-      -ms-transform: scaleX(@ratio); // IE9 only
-       -o-transform: scaleX(@ratio);
-          transform: scaleX(@ratio);
-}
-.scaleY(@ratio) {
-  -webkit-transform: scaleY(@ratio);
-      -ms-transform: scaleY(@ratio); // IE9 only
-       -o-transform: scaleY(@ratio);
-          transform: scaleY(@ratio);
-}
-.skew(@x; @y) {
-  -webkit-transform: skewX(@x) skewY(@y);
-      -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+
-       -o-transform: skewX(@x) skewY(@y);
-          transform: skewX(@x) skewY(@y);
-}
-.translate(@x; @y) {
-  -webkit-transform: translate(@x, @y);
-      -ms-transform: translate(@x, @y); // IE9 only
-       -o-transform: translate(@x, @y);
-          transform: translate(@x, @y);
-}
-.translate3d(@x; @y; @z) {
-  -webkit-transform: translate3d(@x, @y, @z);
-          transform: translate3d(@x, @y, @z);
-}
-.rotate(@degrees) {
-  -webkit-transform: rotate(@degrees);
-      -ms-transform: rotate(@degrees); // IE9 only
-       -o-transform: rotate(@degrees);
-          transform: rotate(@degrees);
-}
-.rotateX(@degrees) {
-  -webkit-transform: rotateX(@degrees);
-      -ms-transform: rotateX(@degrees); // IE9 only
-       -o-transform: rotateX(@degrees);
-          transform: rotateX(@degrees);
-}
-.rotateY(@degrees) {
-  -webkit-transform: rotateY(@degrees);
-      -ms-transform: rotateY(@degrees); // IE9 only
-       -o-transform: rotateY(@degrees);
-          transform: rotateY(@degrees);
-}
-.perspective(@perspective) {
-  -webkit-perspective: @perspective;
-     -moz-perspective: @perspective;
-          perspective: @perspective;
-}
-.perspective-origin(@perspective) {
-  -webkit-perspective-origin: @perspective;
-     -moz-perspective-origin: @perspective;
-          perspective-origin: @perspective;
-}
-.transform-origin(@origin) {
-  -webkit-transform-origin: @origin;
-     -moz-transform-origin: @origin;
-      -ms-transform-origin: @origin; // IE9 only
-          transform-origin: @origin;
-}
-
-
-// Transitions
-
-.transition(@transition) {
-  -webkit-transition: @transition;
-       -o-transition: @transition;
-          transition: @transition;
-}
-.transition-property(@transition-property) {
-  -webkit-transition-property: @transition-property;
-          transition-property: @transition-property;
-}
-.transition-delay(@transition-delay) {
-  -webkit-transition-delay: @transition-delay;
-          transition-delay: @transition-delay;
-}
-.transition-duration(@transition-duration) {
-  -webkit-transition-duration: @transition-duration;
-          transition-duration: @transition-duration;
-}
-.transition-timing-function(@timing-function) {
-  -webkit-transition-timing-function: @timing-function;
-          transition-timing-function: @timing-function;
-}
-.transition-transform(@transition) {
-  -webkit-transition: -webkit-transform @transition;
-     -moz-transition: -moz-transform @transition;
-       -o-transition: -o-transform @transition;
-          transition: transform @transition;
-}
-
-
-// User select
-// For selecting text on the page
-
-.user-select(@select) {
-  -webkit-user-select: @select;
-     -moz-user-select: @select;
-      -ms-user-select: @select; // IE10+
-          user-select: @select;
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/modals.less b/src/legacy/ui/public/styles/bootstrap/modals.less
deleted file mode 100644
index 232b7b5f8b501..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/modals.less
+++ /dev/null
@@ -1,136 +0,0 @@
-//
-// Modals
-// --------------------------------------------------
-
-// .modal-open      - body class for killing the scroll
-// .modal           - container to scroll within
-// .modal-dialog    - positioning shell for the actual modal
-// .modal-content   - actual modal w/ bg and corners and shit
-
-// Kill the scroll on the body
-.modal-open {
-  overflow: hidden;
-}
-
-// Container that the modal scrolls within
-.modal {
-  display: none;
-  overflow: hidden;
-  position: fixed;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  z-index: @zindex-modal;
-  -webkit-overflow-scrolling: touch;
-
-  // Prevent Chrome on Windows from adding a focus outline. For details, see
-  // https://github.com/twbs/bootstrap/pull/10951.
-  outline: 0;
-
-  // When fading in the modal, animate it to slide down
-  &.fade .modal-dialog {
-    .translate(0, -25%);
-    .transition-transform(~"0.3s ease-out");
-  }
-  &.in .modal-dialog { .translate(0, 0) }
-}
-.modal-open .modal {
-  overflow-x: hidden;
-  overflow-y: auto;
-}
-
-// Shell div to position the modal with bottom padding
-.modal-dialog {
-  position: relative;
-  width: auto;
-  margin: 10px;
-}
-
-// Actual modal
-.modal-content {
-  position: relative;
-  background-color: @modal-content-bg;
-  border: 1px solid @modal-content-fallback-border-color; //old browsers fallback (ie8 etc)
-  border: 1px solid @modal-content-border-color;
-  border-radius: @border-radius-large;
-  .box-shadow(0 3px 9px rgba(0,0,0,.5));
-  background-clip: padding-box;
-  // Remove focus outline from opened modal
-  outline: 0;
-}
-
-// Modal background
-.modal-backdrop {
-  position: fixed;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  z-index: @zindex-modal-background;
-  background-color: @modal-backdrop-bg;
-  // Fade for backdrop
-  &.fade { .opacity(0); }
-  &.in { .opacity(@modal-backdrop-opacity); }
-}
-
-// Modal header
-// Top section of the modal w/ title and dismiss
-.modal-header {
-  padding: @modal-title-padding;
-  border-bottom: 1px solid @modal-header-border-color;
-  &:extend(.clearfix all);
-}
-// Close icon
-.modal-header .close {
-  margin-top: -2px;
-}
-
-// Title text within header
-.modal-title {
-  margin: 0;
-  line-height: @modal-title-line-height;
-}
-
-// Modal body
-// Where all modal content resides (sibling of .modal-header and .modal-footer)
-.modal-body {
-  position: relative;
-  padding: @modal-inner-padding;
-}
-
-// Footer (for actions)
-.modal-footer {
-  padding: @modal-inner-padding;
-  text-align: right; // right align buttons
-  border-top: 1px solid @modal-footer-border-color;
-  &:extend(.clearfix all); // clear it in case folks use .pull-* classes on buttons
-}
-
-// Measure scrollbar width for padding body during modal show/hide
-.modal-scrollbar-measure {
-  position: absolute;
-  top: -9999px;
-  width: 50px;
-  height: 50px;
-  overflow: scroll;
-}
-
-// Scale up the modal
-@media (min-width: @screen-sm-min) {
-  // Automatically set modal's width for larger viewports
-  .modal-dialog {
-    width: @modal-md;
-    margin: 30px auto;
-  }
-  .modal-content {
-    .box-shadow(0 5px 15px rgba(0,0,0,.5));
-  }
-
-  // Modal sizes
-  .modal-sm { width: @modal-sm; }
-}
-
-@media (min-width: @screen-md-min) {
-  .modal-lg { width: @modal-lg; }
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/navbar.less b/src/legacy/ui/public/styles/bootstrap/navbar.less
deleted file mode 100644
index b1c279c1ae109..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/navbar.less
+++ /dev/null
@@ -1,603 +0,0 @@
-//
-// Navbars
-// --------------------------------------------------
-
-
-// Wrapper and base class
-//
-// Provide a static navbar from which we expand to create full-width, fixed, and
-// other navbar variations.
-
-.navbar {
-  position: relative;
-  min-height: @navbar-height; // Ensure a navbar always shows (e.g., without a .navbar-brand in collapsed mode)
-  margin-bottom: @navbar-margin-bottom;
-  border: 1px solid transparent;
-
-  // Prevent floats from breaking the navbar
-  &:extend(.clearfix all);
-
-  @media (min-width: @grid-float-breakpoint) {
-    border-radius: @navbar-border-radius;
-  }
-}
-
-
-// Navbar heading
-//
-// Groups `.navbar-brand` and `.navbar-toggle` into a single component for easy
-// styling of responsive aspects.
-
-.navbar-header {
-  &:extend(.clearfix all);
-
-  @media (min-width: @grid-float-breakpoint) {
-    float: left;
-  }
-}
-
-
-// Navbar collapse (body)
-//
-// Group your navbar content into this for easy collapsing and expanding across
-// various device sizes. By default, this content is collapsed when <768px, but
-// will expand past that for a horizontal display.
-//
-// To start (on mobile devices) the navbar links, forms, and buttons are stacked
-// vertically and include a `max-height` to overflow in case you have too much
-// content for the user's viewport.
-
-.navbar-collapse {
-  overflow-x: visible;
-  padding-right: @navbar-padding-horizontal;
-  padding-left:  @navbar-padding-horizontal;
-  border-top: 1px solid transparent;
-  box-shadow: inset 0 1px 0 rgba(255,255,255,.1);
-  &:extend(.clearfix all);
-  -webkit-overflow-scrolling: touch;
-
-  &.in {
-    overflow-y: auto;
-  }
-
-  @media (min-width: @grid-float-breakpoint) {
-    width: auto;
-    border-top: 0;
-    box-shadow: none;
-
-    &.collapse {
-      display: block !important;
-      height: auto !important;
-      padding-bottom: 0; // Override default setting
-      overflow: visible !important;
-    }
-
-    &.in {
-      overflow-y: visible;
-    }
-
-    // Undo the collapse side padding for navbars with containers to ensure
-    // alignment of right-aligned contents.
-    .navbar-fixed-top &,
-    .navbar-fixed-bottom & {
-      padding-left: 0;
-      padding-right: 0;
-    }
-  }
-}
-
-.navbar-fixed-top,
-.navbar-fixed-bottom {
-  .navbar-collapse {
-    max-height: @navbar-collapse-max-height;
-
-    @media (max-device-width: @screen-xs-min) and (orientation: landscape) {
-      max-height: 200px;
-    }
-  }
-}
-
-
-// Both navbar header and collapse
-//
-// When a container is present, change the behavior of the header and collapse.
-
-.container,
-.container-fluid {
-  > .navbar-header,
-  > .navbar-collapse {
-    margin-right: -@navbar-padding-horizontal;
-    margin-left:  -@navbar-padding-horizontal;
-
-    @media (min-width: @grid-float-breakpoint) {
-      margin-right: 0;
-      margin-left:  0;
-    }
-  }
-}
-
-
-//
-// Navbar alignment options
-//
-// Display the navbar across the entirety of the page or fixed it to the top or
-// bottom of the page.
-
-// Fix the top/bottom navbars when screen real estate supports it
-.navbar-fixed-top,
-.navbar-fixed-bottom {
-  position: fixed;
-  right: 0;
-  left: 0;
-  z-index: @zindex-navbar-fixed;
-
-  // Undo the rounded corners
-  @media (min-width: @grid-float-breakpoint) {
-    border-radius: 0;
-  }
-}
-.navbar-fixed-top {
-  top: 0;
-  border-width: 0 0 1px;
-}
-.navbar-fixed-bottom {
-  bottom: 0;
-  margin-bottom: 0; // override .navbar defaults
-  border-width: 1px 0 0;
-}
-
-
-// Brand/project name
-
-.navbar-brand {
-  float: left;
-  padding: @navbar-padding-vertical @navbar-padding-horizontal;
-  font-size: @font-size-large;
-  line-height: @line-height-computed;
-  height: @navbar-height;
-
-  &:hover,
-  &:focus {
-    text-decoration: none;
-  }
-
-  > img {
-    display: block;
-  }
-
-  @media (min-width: @grid-float-breakpoint) {
-    .navbar > .container &,
-    .navbar > .container-fluid & {
-      margin-left: -@navbar-padding-horizontal;
-    }
-  }
-}
-
-
-// Navbar toggle
-//
-// Custom button for toggling the `.navbar-collapse`, powered by the collapse
-// JavaScript plugin.
-
-.navbar-toggle {
-  position: relative;
-  float: right;
-  margin-right: @navbar-padding-horizontal;
-  padding: 9px 10px;
-  .navbar-vertical-align(34px);
-  background-color: transparent;
-  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214
-  border: 1px solid transparent;
-  border-radius: @border-radius-base;
-
-  // We remove the `outline` here, but later compensate by attaching `:hover`
-  // styles to `:focus`.
-  &:focus {
-    outline: 0;
-  }
-
-  // Bars
-  .icon-bar {
-    display: block;
-    width: 22px;
-    height: 2px;
-    border-radius: 1px;
-  }
-  .icon-bar + .icon-bar {
-    margin-top: 4px;
-  }
-
-  @media (min-width: @grid-float-breakpoint) {
-    display: none;
-  }
-}
-
-
-// Navbar nav links
-//
-// Builds on top of the `.nav` components with its own modifier class to make
-// the nav the full height of the horizontal nav (above 768px).
-
-.navbar-nav {
-  margin: (@navbar-padding-vertical / 2) -@navbar-padding-horizontal;
-
-  > li > a {
-    padding-top:    10px;
-    padding-bottom: 10px;
-    line-height: @line-height-computed;
-  }
-
-  @media (max-width: @grid-float-breakpoint-max) {
-    // Dropdowns get custom display when collapsed
-    .open .dropdown-menu {
-      position: static;
-      float: none;
-      width: auto;
-      margin-top: 0;
-      background-color: transparent;
-      border: 0;
-      box-shadow: none;
-      > li > a,
-      .dropdown-header {
-        padding: 5px 15px 5px 25px;
-      }
-      > li > a {
-        line-height: @line-height-computed;
-        &:hover,
-        &:focus {
-          background-image: none;
-        }
-      }
-    }
-  }
-
-  // Uncollapse the nav
-  @media (min-width: @grid-float-breakpoint) {
-    float: left;
-    margin: 0;
-
-    > li {
-      float: left;
-      > a {
-        padding-top:    @navbar-padding-vertical;
-        padding-bottom: @navbar-padding-vertical;
-      }
-    }
-  }
-}
-
-
-// Navbar form
-//
-// Extension of the `.form-inline` with some extra flavor for optimum display in
-// our navbars.
-
-.navbar-form {
-  margin-left: -@navbar-padding-horizontal;
-  margin-right: -@navbar-padding-horizontal;
-  padding: 10px @navbar-padding-horizontal;
-  border-top: 1px solid transparent;
-  border-bottom: 1px solid transparent;
-  @shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);
-  .box-shadow(@shadow);
-
-  // Mixin behavior for optimum display
-  .form-inline();
-
-  .form-group {
-    @media (max-width: @grid-float-breakpoint-max) {
-      margin-bottom: 5px;
-
-      &:last-child {
-        margin-bottom: 0;
-      }
-    }
-  }
-
-  // Vertically center in expanded, horizontal navbar
-  .navbar-vertical-align(@input-height-base);
-
-  // Undo 100% width for pull classes
-  @media (min-width: @grid-float-breakpoint) {
-    width: auto;
-    border: 0;
-    margin-left: 0;
-    margin-right: 0;
-    padding-top: 0;
-    padding-bottom: 0;
-    .box-shadow(none);
-  }
-}
-
-
-// Dropdown menus
-
-// Menu position and menu carets
-.navbar-nav > li > .dropdown-menu {
-  margin-top: 0;
-  .border-top-radius(0);
-}
-// Menu position and menu caret support for dropups via extra dropup class
-.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {
-  margin-bottom: 0;
-  .border-top-radius(@navbar-border-radius);
-  .border-bottom-radius(0);
-}
-
-
-// Text in navbars
-//
-// Add a class to make any element properly align itself vertically within the navbars.
-
-.navbar-text {
-  .navbar-vertical-align(@line-height-computed);
-
-  @media (min-width: @grid-float-breakpoint) {
-    float: left;
-    margin-left: @navbar-padding-horizontal;
-    margin-right: @navbar-padding-horizontal;
-  }
-}
-
-
-// Component alignment
-//
-// Repurpose the pull utilities as their own navbar utilities to avoid specificity
-// issues with parents and chaining. Only do this when the navbar is uncollapsed
-// though so that navbar contents properly stack and align in mobile.
-//
-// Declared after the navbar components to ensure more specificity on the margins.
-
-@media (min-width: @grid-float-breakpoint) {
-  .navbar-left  { .pull-left(); }
-  .navbar-right {
-    .pull-right();
-    margin-right: -@navbar-padding-horizontal;
-
-    ~ .navbar-right {
-      margin-right: 0;
-    }
-  }
-}
-
-
-// Alternate navbars
-// --------------------------------------------------
-
-// Default navbar
-.navbar-default {
-  background-color: @navbar-default-bg;
-  border-color: @navbar-default-border;
-
-  .navbar-brand {
-    color: @navbar-default-brand-color;
-    &:hover,
-    &:focus {
-      color: @navbar-default-brand-hover-color;
-      background-color: @navbar-default-brand-hover-bg;
-    }
-  }
-
-  .navbar-text {
-    color: @navbar-default-color;
-  }
-
-  .navbar-nav {
-    > li > a {
-      color: @navbar-default-link-color;
-
-      &:hover,
-      &:focus {
-        color: @navbar-default-link-hover-color;
-        background-color: @navbar-default-link-hover-bg;
-      }
-    }
-    > .active > a {
-      &,
-      &:hover,
-      &:focus {
-        color: @navbar-default-link-active-color;
-        background-color: @navbar-default-link-active-bg;
-      }
-    }
-    > .disabled > a {
-      &,
-      &:hover,
-      &:focus {
-        color: @navbar-default-link-disabled-color;
-        background-color: @navbar-default-link-disabled-bg;
-      }
-    }
-  }
-
-  .navbar-toggle {
-    border-color: @navbar-default-toggle-border-color;
-    &:hover,
-    &:focus {
-      background-color: @navbar-default-toggle-hover-bg;
-    }
-    .icon-bar {
-      background-color: @navbar-default-toggle-icon-bar-bg;
-    }
-  }
-
-  .navbar-collapse,
-  .navbar-form {
-    border-color: @navbar-default-border;
-  }
-
-  // Dropdown menu items
-  .navbar-nav {
-    // Remove background color from open dropdown
-    > .open > a {
-      &,
-      &:hover,
-      &:focus {
-        background-color: @navbar-default-link-active-bg;
-        color: @navbar-default-link-active-color;
-      }
-    }
-
-    @media (max-width: @grid-float-breakpoint-max) {
-      // Dropdowns get custom display when collapsed
-      .open .dropdown-menu {
-        > li > a {
-          color: @navbar-default-link-color;
-          &:hover,
-          &:focus {
-            color: @navbar-default-link-hover-color;
-            background-color: @navbar-default-link-hover-bg;
-          }
-        }
-        > .active > a {
-          &,
-          &:hover,
-          &:focus {
-            color: @navbar-default-link-active-color;
-            background-color: @navbar-default-link-active-bg;
-          }
-        }
-        > .disabled > a {
-          &,
-          &:hover,
-          &:focus {
-            color: @navbar-default-link-disabled-color;
-            background-color: @navbar-default-link-disabled-bg;
-          }
-        }
-      }
-    }
-  }
-
-
-  // Links in navbars
-  //
-  // Add a class to ensure links outside the navbar nav are colored correctly.
-
-  .navbar-link {
-    color: @navbar-default-link-color;
-    &:hover {
-      color: @navbar-default-link-hover-color;
-    }
-  }
-}
-
-// Inverse navbar
-
-.navbar-inverse {
-  background-color: @navbar-inverse-bg;
-  border-color: @navbar-inverse-border;
-
-  .navbar-brand {
-    color: @navbar-inverse-brand-color;
-    &:hover,
-    &:focus {
-      color: @navbar-inverse-brand-hover-color;
-      background-color: @navbar-inverse-brand-hover-bg;
-    }
-  }
-
-  .navbar-text {
-    color: @navbar-inverse-color;
-  }
-
-  .navbar-nav {
-    > li > a {
-      color: @navbar-inverse-link-color;
-
-      &:hover,
-      &:focus {
-        color: @navbar-inverse-link-hover-color;
-        background-color: @navbar-inverse-link-hover-bg;
-      }
-    }
-    > .active > a {
-      &,
-      &:hover,
-      &:focus {
-        color: @navbar-inverse-link-active-color;
-        background-color: @navbar-inverse-link-active-bg;
-      }
-    }
-    > .disabled > a {
-      &,
-      &:hover,
-      &:focus {
-        color: @navbar-inverse-link-disabled-color;
-        background-color: @navbar-inverse-link-disabled-bg;
-      }
-    }
-  }
-
-  // Darken the responsive nav toggle
-  .navbar-toggle {
-    border-color: @navbar-inverse-toggle-border-color;
-    &:hover,
-    &:focus {
-      background-color: @navbar-inverse-toggle-hover-bg;
-    }
-    .icon-bar {
-      background-color: @navbar-inverse-toggle-icon-bar-bg;
-    }
-  }
-
-  .navbar-collapse,
-  .navbar-form {
-    border-color: darken(@navbar-inverse-bg, 7%);
-  }
-
-  // Dropdowns
-  .navbar-nav {
-    > .open > a {
-      &,
-      &:hover,
-      &:focus {
-        background-color: @navbar-inverse-link-active-bg;
-        color: @navbar-inverse-link-active-color;
-      }
-    }
-
-    @media (max-width: @grid-float-breakpoint-max) {
-      // Dropdowns get custom display
-      .open .dropdown-menu {
-        > .dropdown-header {
-          border-color: @navbar-inverse-border;
-        }
-        .divider {
-          background-color: @navbar-inverse-border;
-        }
-        > li > a {
-          color: @navbar-inverse-link-color;
-          &:hover,
-          &:focus {
-            color: @navbar-inverse-link-hover-color;
-            background-color: @navbar-inverse-link-hover-bg;
-          }
-        }
-        > .active > a {
-          &,
-          &:hover,
-          &:focus {
-            color: @navbar-inverse-link-active-color;
-            background-color: @navbar-inverse-link-active-bg;
-          }
-        }
-        > .disabled > a {
-          &,
-          &:hover,
-          &:focus {
-            color: @navbar-inverse-link-disabled-color;
-            background-color: @navbar-inverse-link-disabled-bg;
-          }
-        }
-      }
-    }
-  }
-
-  .navbar-link {
-    color: @navbar-inverse-link-color;
-    &:hover {
-      color: @navbar-inverse-link-hover-color;
-    }
-  }
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/navs.less b/src/legacy/ui/public/styles/bootstrap/navs.less
deleted file mode 100644
index b8df31c60039e..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/navs.less
+++ /dev/null
@@ -1,243 +0,0 @@
-//
-// Navs
-// --------------------------------------------------
-
-
-// Base class
-// --------------------------------------------------
-
-.nav {
-  margin-bottom: 0;
-  padding-left: 0; // Override default ul/ol
-  list-style: none;
-  &:extend(.clearfix all);
-
-  > li {
-    position: relative;
-    display: block;
-
-    > a {
-      position: relative;
-      display: block;
-      padding: @nav-link-padding;
-      &:hover,
-      &:focus {
-        text-decoration: none;
-        background-color: @nav-link-hover-bg;
-      }
-    }
-
-    // Disabled state sets text to gray and nukes hover/tab effects
-    &.disabled > a {
-      color: @nav-disabled-link-color;
-
-      &:hover,
-      &:focus {
-        color: @nav-disabled-link-hover-color;
-        text-decoration: none;
-        background-color: transparent;
-        cursor: @cursor-disabled;
-      }
-    }
-  }
-
-  // Open dropdowns
-  .open > a {
-    &,
-    &:hover,
-    &:focus {
-      background-color: @nav-link-hover-bg;
-      border-color: @link-color;
-    }
-  }
-
-  // Nav dividers (deprecated with v3.0.1)
-  //
-  // This should have been removed in v3 with the dropping of `.nav-list`, but
-  // we missed it. We don't currently support this anywhere, but in the interest
-  // of maintaining backward compatibility in case you use it, it's deprecated.
-  .nav-divider {
-    .nav-divider();
-  }
-
-  // Prevent IE8 from misplacing imgs
-  //
-  // See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989
-  > li > a > img {
-    max-width: none;
-  }
-}
-
-
-// Tabs
-// -------------------------
-
-// Give the tabs something to sit on
-.nav-tabs {
-  border-bottom: 1px solid @nav-tabs-border-color;
-  > li {
-    float: left;
-    // Make the list-items overlay the bottom border
-    margin-bottom: -1px;
-
-    // Actual tabs (as links)
-    > a {
-      margin-right: 2px;
-      line-height: @line-height-base;
-      border: 1px solid transparent;
-      border-radius: @border-radius-base @border-radius-base 0 0;
-      &:hover {
-        border-color: @gray-lighter;
-        background-color: @white;
-      }
-    }
-
-    // Active state, and its :hover to override normal :hover
-    &.active > a {
-      &,
-      &:hover,
-      &:focus {
-        color: @brand-primary;
-        background-color: @white;
-        border: 1px solid @gray-lighter;
-        border-bottom-color: transparent;
-        cursor: default;
-      }
-    }
-  }
-  // pulling this in mainly for less shorthand
-  &.nav-justified {
-    .nav-justified();
-    .nav-tabs-justified();
-  }
-}
-
-
-// Pills
-// -------------------------
-.nav-pills {
-  > li {
-    float: left;
-
-    // Links rendered as pills
-    > a {
-      border-radius: @nav-pills-border-radius;
-    }
-    + li {
-      margin-left: 2px;
-    }
-
-    // Active state
-    &.active > a {
-      &,
-      &:hover,
-      &:focus {
-        color: @nav-pills-active-link-hover-color;
-        background-color: @nav-pills-active-link-hover-bg;
-      }
-    }
-  }
-}
-
-
-// Stacked pills
-.nav-stacked {
-  > li {
-    float: none;
-    + li {
-      margin-top: 2px;
-      margin-left: 0; // no need for this gap between nav items
-    }
-  }
-}
-
-
-// Nav variations
-// --------------------------------------------------
-
-// Justified nav links
-// -------------------------
-
-.nav-justified {
-  width: 100%;
-
-  > li {
-    float: none;
-    > a {
-      text-align: center;
-      margin-bottom: 5px;
-    }
-  }
-
-  > .dropdown .dropdown-menu {
-    top: auto;
-    left: auto;
-  }
-
-  @media (min-width: @screen-sm-min) {
-    > li {
-      display: table-cell;
-      width: 1%;
-      > a {
-        margin-bottom: 0;
-      }
-    }
-  }
-}
-
-// Move borders to anchors instead of bottom of list
-//
-// Mixin for adding on top the shared `.nav-justified` styles for our tabs
-.nav-tabs-justified {
-  border-bottom: 0;
-
-  > li > a {
-    // Override margin from .nav-tabs
-    margin-right: 0;
-    border-radius: @border-radius-base;
-  }
-
-  > .active > a,
-  > .active > a:hover,
-  > .active > a:focus {
-    border: 1px solid @nav-tabs-justified-link-border-color;
-  }
-
-  @media (min-width: @screen-sm-min) {
-    > li > a {
-      border-bottom: 1px solid @nav-tabs-justified-link-border-color;
-      border-radius: @border-radius-base @border-radius-base 0 0;
-    }
-    > .active > a,
-    > .active > a:hover,
-    > .active > a:focus {
-      border-bottom-color: @nav-tabs-justified-active-link-border-color;
-    }
-  }
-}
-
-
-// Tabbable tabs
-// -------------------------
-
-// Hide tabbable panes to start, show them when `.active`
-.tab-content {
-  > .tab-pane {
-    display: none;
-  }
-  > .active {
-    display: block;
-  }
-}
-
-
-// Dropdowns
-// -------------------------
-
-// Specific dropdowns
-.nav-tabs .dropdown-menu {
-  // make dropdown border overlap tab border
-  margin-top: -1px;
-  // Remove the top rounded corners here since there is a hard edge above the menu
-  .border-top-radius(0);
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/pager.less b/src/legacy/ui/public/styles/bootstrap/pager.less
deleted file mode 100644
index 41abaaadc5dc6..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/pager.less
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-// Pager pagination
-// --------------------------------------------------
-
-
-.pager {
-  padding-left: 0;
-  margin: @line-height-computed 0;
-  list-style: none;
-  text-align: center;
-  &:extend(.clearfix all);
-  li {
-    display: inline;
-    > a,
-    > span {
-      display: inline-block;
-      padding: 5px 14px;
-      background-color: @pager-bg;
-      border: 1px solid @pager-border;
-      border-radius: @pager-border-radius;
-    }
-
-    > a:hover,
-    > a:focus {
-      text-decoration: none;
-      background-color: @pager-hover-bg;
-    }
-  }
-
-  .next {
-    > a,
-    > span {
-      float: right;
-    }
-  }
-
-  .previous {
-    > a,
-    > span {
-      float: left;
-    }
-  }
-
-  .disabled {
-    > a,
-    > a:hover,
-    > a:focus,
-    > span {
-      color: @pager-disabled-color;
-      background-color: @pager-bg;
-      cursor: @cursor-disabled;
-    }
-  }
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/pagination.less b/src/legacy/ui/public/styles/bootstrap/pagination.less
deleted file mode 100644
index 31f77aae4ed7b..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/pagination.less
+++ /dev/null
@@ -1,89 +0,0 @@
-//
-// Pagination (multiple pages)
-// --------------------------------------------------
-.pagination {
-  display: inline-block;
-  padding-left: 0;
-  margin: @line-height-computed 0;
-  border-radius: @border-radius-base;
-
-  > li {
-    display: inline; // Remove list-style and block-level defaults
-    > a,
-    > span {
-      position: relative;
-      float: left; // Collapse white-space
-      padding: @padding-base-vertical @padding-base-horizontal;
-      line-height: @line-height-base;
-      text-decoration: none;
-      color: @pagination-color;
-      background-color: @pagination-bg;
-      border: 1px solid @pagination-border;
-      margin-left: -1px;
-    }
-    &:first-child {
-      > a,
-      > span {
-        margin-left: 0;
-        .border-left-radius(@border-radius-base);
-      }
-    }
-    &:last-child {
-      > a,
-      > span {
-        .border-right-radius(@border-radius-base);
-      }
-    }
-  }
-
-  > li > a,
-  > li > span {
-    &:hover,
-    &:focus {
-      z-index: 2;
-      color: @pagination-hover-color;
-      background-color: @pagination-hover-bg;
-      border-color: @pagination-hover-border;
-    }
-  }
-
-  > .active > a,
-  > .active > span {
-    &,
-    &:hover,
-    &:focus {
-      z-index: 3;
-      color: @pagination-active-color;
-      background-color: @pagination-active-bg;
-      border-color: @pagination-active-border;
-      cursor: default;
-    }
-  }
-
-  > .disabled {
-    > span,
-    > span:hover,
-    > span:focus,
-    > a,
-    > a:hover,
-    > a:focus {
-      color: @pagination-disabled-color;
-      background-color: @pagination-disabled-bg;
-      border-color: @pagination-disabled-border;
-      cursor: @cursor-disabled;
-    }
-  }
-}
-
-// Sizing
-// --------------------------------------------------
-
-// Large
-.pagination-lg {
-  .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);
-}
-
-// Small
-.pagination-sm {
-  .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/panels.less b/src/legacy/ui/public/styles/bootstrap/panels.less
deleted file mode 100644
index 425eb5e642c15..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/panels.less
+++ /dev/null
@@ -1,271 +0,0 @@
-//
-// Panels
-// --------------------------------------------------
-
-
-// Base class
-.panel {
-  margin-bottom: @line-height-computed;
-  background-color: @panel-bg;
-  border: 1px solid transparent;
-  border-radius: @panel-border-radius;
-  .box-shadow(0 1px 1px rgba(0,0,0,.05));
-}
-
-// Panel contents
-.panel-body {
-  padding: @panel-body-padding;
-  &:extend(.clearfix all);
-}
-
-// Optional heading
-.panel-heading {
-  padding: @panel-heading-padding;
-  border-bottom: 1px solid transparent;
-  .border-top-radius((@panel-border-radius - 1));
-
-  > .dropdown .dropdown-toggle {
-    color: inherit;
-  }
-}
-
-// Within heading, strip any `h*` tag of its default margins for spacing.
-.panel-title {
-  margin-top: 0;
-  margin-bottom: 0;
-  font-size: ceil((@font-size-base * 1.125));
-  color: inherit;
-
-  > a,
-  > small,
-  > .small,
-  > small > a,
-  > .small > a {
-    color: inherit;
-  }
-}
-
-// Optional footer (stays gray in every modifier class)
-.panel-footer {
-  padding: @panel-footer-padding;
-  background-color: @panel-footer-bg;
-  border-top: 1px solid @panel-inner-border;
-  .border-bottom-radius((@panel-border-radius - 1));
-}
-
-
-// List groups in panels
-//
-// By default, space out list group content from panel headings to account for
-// any kind of custom content between the two.
-
-.panel {
-  > .list-group,
-  > .panel-collapse > .list-group {
-    margin-bottom: 0;
-
-    .list-group-item {
-      border-width: 1px 0;
-      border-radius: 0;
-    }
-
-    // Add border top radius for first one
-    &:first-child {
-      .list-group-item:first-child {
-        border-top: 0;
-        .border-top-radius((@panel-border-radius - 1));
-      }
-    }
-
-    // Add border bottom radius for last one
-    &:last-child {
-      .list-group-item:last-child {
-        border-bottom: 0;
-        .border-bottom-radius((@panel-border-radius - 1));
-      }
-    }
-  }
-  > .panel-heading + .panel-collapse > .list-group {
-    .list-group-item:first-child {
-      .border-top-radius(0);
-    }
-  }
-}
-// Collapse space between when there's no additional content.
-.panel-heading + .list-group {
-  .list-group-item:first-child {
-    border-top-width: 0;
-  }
-}
-.list-group + .panel-footer {
-  border-top-width: 0;
-}
-
-// Tables in panels
-//
-// Place a non-bordered `.table` within a panel (not within a `.panel-body`) and
-// watch it go full width.
-
-.panel {
-  > .table,
-  > .table-responsive > .table,
-  > .panel-collapse > .table {
-    margin-bottom: 0;
-
-    caption {
-      padding-left: @panel-body-padding;
-      padding-right: @panel-body-padding;
-    }
-  }
-  // Add border top radius for first one
-  > .table:first-child,
-  > .table-responsive:first-child > .table:first-child {
-    .border-top-radius((@panel-border-radius - 1));
-
-    > thead:first-child,
-    > tbody:first-child {
-      > tr:first-child {
-        border-top-left-radius: (@panel-border-radius - 1);
-        border-top-right-radius: (@panel-border-radius - 1);
-
-        td:first-child,
-        th:first-child {
-          border-top-left-radius: (@panel-border-radius - 1);
-        }
-        td:last-child,
-        th:last-child {
-          border-top-right-radius: (@panel-border-radius - 1);
-        }
-      }
-    }
-  }
-  // Add border bottom radius for last one
-  > .table:last-child,
-  > .table-responsive:last-child > .table:last-child {
-    .border-bottom-radius((@panel-border-radius - 1));
-
-    > tbody:last-child,
-    > tfoot:last-child {
-      > tr:last-child {
-        border-bottom-left-radius: (@panel-border-radius - 1);
-        border-bottom-right-radius: (@panel-border-radius - 1);
-
-        td:first-child,
-        th:first-child {
-          border-bottom-left-radius: (@panel-border-radius - 1);
-        }
-        td:last-child,
-        th:last-child {
-          border-bottom-right-radius: (@panel-border-radius - 1);
-        }
-      }
-    }
-  }
-  > .panel-body + .table,
-  > .panel-body + .table-responsive,
-  > .table + .panel-body,
-  > .table-responsive + .panel-body {
-    border-top: 1px solid @table-border-color;
-  }
-  > .table > tbody:first-child > tr:first-child th,
-  > .table > tbody:first-child > tr:first-child td {
-    border-top: 0;
-  }
-  > .table-bordered,
-  > .table-responsive > .table-bordered {
-    border: 0;
-    > thead,
-    > tbody,
-    > tfoot {
-      > tr {
-        > th:first-child,
-        > td:first-child {
-          border-left: 0;
-        }
-        > th:last-child,
-        > td:last-child {
-          border-right: 0;
-        }
-      }
-    }
-    > thead,
-    > tbody {
-      > tr:first-child {
-        > td,
-        > th {
-          border-bottom: 0;
-        }
-      }
-    }
-    > tbody,
-    > tfoot {
-      > tr:last-child {
-        > td,
-        > th {
-          border-bottom: 0;
-        }
-      }
-    }
-  }
-  > .table-responsive {
-    border: 0;
-    margin-bottom: 0;
-  }
-}
-
-
-// Collapsable panels (aka, accordion)
-//
-// Wrap a series of panels in `.panel-group` to turn them into an accordion with
-// the help of our collapse JavaScript plugin.
-
-.panel-group {
-  margin-bottom: @line-height-computed;
-
-  // Tighten up margin so it's only between panels
-  .panel {
-    margin-bottom: 0;
-    border-radius: @panel-border-radius;
-
-    + .panel {
-      margin-top: 5px;
-    }
-  }
-
-  .panel-heading {
-    border-bottom: 0;
-
-    + .panel-collapse > .panel-body,
-    + .panel-collapse > .list-group {
-      border-top: 1px solid @panel-inner-border;
-    }
-  }
-
-  .panel-footer {
-    border-top: 0;
-    + .panel-collapse .panel-body {
-      border-bottom: 1px solid @panel-inner-border;
-    }
-  }
-}
-
-
-// Contextual variations
-.panel-default {
-  .panel-variant(@panel-default-border; @panel-default-text; @panel-default-heading-bg; @panel-default-border);
-}
-.panel-primary {
-  .panel-variant(@panel-primary-border; @panel-primary-text; @panel-primary-heading-bg; @panel-primary-border);
-}
-.panel-success {
-  .panel-variant(@panel-success-border; @panel-success-text; @panel-success-heading-bg; @panel-success-border);
-}
-.panel-info {
-  .panel-variant(@panel-info-border; @panel-info-text; @panel-info-heading-bg; @panel-info-border);
-}
-.panel-warning {
-  .panel-variant(@panel-warning-border; @panel-warning-text; @panel-warning-heading-bg; @panel-warning-border);
-}
-.panel-danger {
-  .panel-variant(@panel-danger-border; @panel-danger-text; @panel-danger-heading-bg; @panel-danger-border);
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/popovers.less b/src/legacy/ui/public/styles/bootstrap/popovers.less
deleted file mode 100644
index 0791dc323d0fd..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/popovers.less
+++ /dev/null
@@ -1,131 +0,0 @@
-//
-// Popovers
-// --------------------------------------------------
-
-
-.popover {
-  position: absolute;
-  top: 0;
-  left: 0;
-  z-index: @zindex-popover;
-  display: none;
-  max-width: @popover-max-width;
-  padding: 1px;
-  // Our parent element can be arbitrary since popovers are by default inserted as a sibling of their target element.
-  // So reset our font and text properties to avoid inheriting weird values.
-  .reset-text();
-  font-size: @font-size-base;
-
-  background-color: @popover-bg;
-  background-clip: padding-box;
-  border: 1px solid @popover-fallback-border-color;
-  border: 1px solid @popover-border-color;
-  border-radius: @border-radius-large;
-  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.1);
-
-  // Offset the popover to account for the popover arrow
-  &.top     { margin-top: -@popover-arrow-width; }
-  &.right   { margin-left: @popover-arrow-width; }
-  &.bottom  { margin-top: @popover-arrow-width; }
-  &.left    { margin-left: -@popover-arrow-width; }
-}
-
-.popover-title {
-  margin: 0; // reset heading margin
-  padding: 8px 14px;
-  font-size: @font-size-base;
-  background-color: @popover-title-bg;
-  border-bottom: 1px solid darken(@popover-title-bg, 5%);
-  border-radius: (@border-radius-large - 1) (@border-radius-large - 1) 0 0;
-}
-
-.popover-content {
-  padding: 9px 14px;
-}
-
-// Arrows
-//
-// .arrow is outer, .arrow:after is inner
-
-.popover > .arrow {
-  &,
-  &:after {
-    position: absolute;
-    display: block;
-    width: 0;
-    height: 0;
-    border-color: transparent;
-    border-style: solid;
-  }
-}
-.popover > .arrow {
-  border-width: @popover-arrow-outer-width;
-}
-.popover > .arrow:after {
-  border-width: @popover-arrow-width;
-  content: "";
-}
-
-.popover {
-  &.top > .arrow {
-    left: 50%;
-    margin-left: -@popover-arrow-outer-width;
-    border-bottom-width: 0;
-    border-top-color: @popover-arrow-outer-fallback-color; // IE8 fallback
-    border-top-color: @popover-arrow-outer-color;
-    bottom: -@popover-arrow-outer-width;
-    &:after {
-      content: " ";
-      bottom: 1px;
-      margin-left: -@popover-arrow-width;
-      border-bottom-width: 0;
-      border-top-color: @popover-arrow-color;
-    }
-  }
-  &.right > .arrow {
-    top: 50%;
-    left: -@popover-arrow-outer-width;
-    margin-top: -@popover-arrow-outer-width;
-    border-left-width: 0;
-    border-right-color: @popover-arrow-outer-fallback-color; // IE8 fallback
-    border-right-color: @popover-arrow-outer-color;
-    &:after {
-      content: " ";
-      left: 1px;
-      bottom: -@popover-arrow-width;
-      border-left-width: 0;
-      border-right-color: @popover-arrow-color;
-    }
-  }
-  &.bottom > .arrow {
-    left: 50%;
-    margin-left: -@popover-arrow-outer-width;
-    border-top-width: 0;
-    border-bottom-color: @popover-arrow-outer-fallback-color; // IE8 fallback
-    border-bottom-color: @popover-arrow-outer-color;
-    top: -@popover-arrow-outer-width;
-    &:after {
-      content: " ";
-      top: 1px;
-      margin-left: -@popover-arrow-width;
-      border-top-width: 0;
-      border-bottom-color: @popover-arrow-color;
-    }
-  }
-
-  &.left > .arrow {
-    top: 50%;
-    right: -@popover-arrow-outer-width;
-    margin-top: -@popover-arrow-outer-width;
-    border-right-width: 0;
-    border-left-color: @popover-arrow-outer-fallback-color; // IE8 fallback
-    border-left-color: @popover-arrow-outer-color;
-    &:after {
-      content: " ";
-      right: 1px;
-      border-right-width: 0;
-      border-left-color: @popover-arrow-color;
-      bottom: -@popover-arrow-width;
-    }
-  }
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/progress-bars.less b/src/legacy/ui/public/styles/bootstrap/progress-bars.less
deleted file mode 100644
index 282c59a099d66..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/progress-bars.less
+++ /dev/null
@@ -1,86 +0,0 @@
-//
-// Progress bars
-// --------------------------------------------------
-
-
-// Bar animations
-// -------------------------
-
-// WebKit
-@-webkit-keyframes progress-bar-stripes {
-  from  { background-position: 40px 0; }
-  to    { background-position: 0 0; }
-}
-
-// Spec and IE10+
-@keyframes progress-bar-stripes {
-  from  { background-position: 40px 0; }
-  to    { background-position: 0 0; }
-}
-
-
-// Bar itself
-// -------------------------
-
-// Outer container
-.progress {
-  overflow: hidden;
-  height: @line-height-computed;
-  margin-bottom: @line-height-computed;
-  background-color: @progress-bg;
-  border-radius: @progress-border-radius;
-  .box-shadow(inset 0 1px 2px rgba(0,0,0,.1));
-}
-
-// Bar of progress
-.progress-bar {
-  float: left;
-  width: 0%;
-  height: 100%;
-  font-size: @font-size-small;
-  line-height: @line-height-computed;
-  color: @progress-bar-color;
-  text-align: center;
-  background-color: @progress-bar-bg;
-  .transition(width .6s ease);
-}
-
-// Striped bars
-//
-// `.progress-striped .progress-bar` is deprecated as of v3.2.0 in favor of the
-// `.progress-bar-striped` class, which you just add to an existing
-// `.progress-bar`.
-.progress-striped .progress-bar,
-.progress-bar-striped {
-  #gradient > .striped();
-  background-size: 40px 40px;
-}
-
-// Call animation for the active one
-//
-// `.progress.active .progress-bar` is deprecated as of v3.2.0 in favor of the
-// `.progress-bar.active` approach.
-.progress.active .progress-bar,
-.progress-bar.active {
-  .animation(progress-bar-stripes 2s linear infinite);
-}
-
-
-// Variations
-// -------------------------
-
-.progress-bar-success {
-  .progress-bar-variant(@progress-bar-success-bg);
-}
-
-.progress-bar-info {
-  .progress-bar-variant(@progress-bar-info-bg);
-}
-
-.progress-bar-warning {
-  .progress-bar-variant(@progress-bar-warning-bg);
-}
-
-.progress-bar-danger {
-  .progress-bar-variant(@progress-bar-danger-bg);
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/responsive-utilities.less b/src/legacy/ui/public/styles/bootstrap/responsive-utilities.less
deleted file mode 100644
index aa192b6282513..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/responsive-utilities.less
+++ /dev/null
@@ -1,173 +0,0 @@
-//
-// Responsive: Utility classes
-// --------------------------------------------------
-
-// Visibility utilities
-// Note: Deprecated .visible-xs, .visible-sm, .visible-md, and .visible-lg as of v3.2.0
-.visible-xs,
-.visible-sm,
-.visible-md,
-.visible-lg {
-  .responsive-invisibility();
-}
-
-.visible-xs-block,
-.visible-xs-inline,
-.visible-xs-inline-block,
-.visible-sm-block,
-.visible-sm-inline,
-.visible-sm-inline-block,
-.visible-md-block,
-.visible-md-inline,
-.visible-md-inline-block,
-.visible-lg-block,
-.visible-lg-inline,
-.visible-lg-inline-block {
-  display: none !important;
-}
-
-.visible-xs {
-  @media (max-width: @screen-xs-max) {
-    .responsive-visibility();
-  }
-}
-.visible-xs-block {
-  @media (max-width: @screen-xs-max) {
-    display: block !important;
-  }
-}
-.visible-xs-inline {
-  @media (max-width: @screen-xs-max) {
-    display: inline !important;
-  }
-}
-.visible-xs-inline-block {
-  @media (max-width: @screen-xs-max) {
-    display: inline-block !important;
-  }
-}
-
-.visible-sm {
-  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {
-    .responsive-visibility();
-  }
-}
-.visible-sm-block {
-  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {
-    display: block !important;
-  }
-}
-.visible-sm-inline {
-  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {
-    display: inline !important;
-  }
-}
-.visible-sm-inline-block {
-  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {
-    display: inline-block !important;
-  }
-}
-
-.visible-md {
-  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {
-    .responsive-visibility();
-  }
-}
-.visible-md-block {
-  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {
-    display: block !important;
-  }
-}
-.visible-md-inline {
-  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {
-    display: inline !important;
-  }
-}
-.visible-md-inline-block {
-  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {
-    display: inline-block !important;
-  }
-}
-
-.visible-lg {
-  @media (min-width: @screen-lg-min) {
-    .responsive-visibility();
-  }
-}
-.visible-lg-block {
-  @media (min-width: @screen-lg-min) {
-    display: block !important;
-  }
-}
-.visible-lg-inline {
-  @media (min-width: @screen-lg-min) {
-    display: inline !important;
-  }
-}
-.visible-lg-inline-block {
-  @media (min-width: @screen-lg-min) {
-    display: inline-block !important;
-  }
-}
-
-.hidden-xs {
-  @media (max-width: @screen-xs-max) {
-    .responsive-invisibility();
-  }
-}
-.hidden-sm {
-  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {
-    .responsive-invisibility();
-  }
-}
-.hidden-md {
-  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {
-    .responsive-invisibility();
-  }
-}
-.hidden-lg {
-  @media (min-width: @screen-lg-min) {
-    .responsive-invisibility();
-  }
-}
-
-
-// Print utilities
-//
-// Media queries are placed on the inside to be mixin-friendly.
-
-// Note: Deprecated .visible-print as of v3.2.0
-.visible-print {
-  .responsive-invisibility();
-
-  @media print {
-    .responsive-visibility();
-  }
-}
-.visible-print-block {
-  display: none !important;
-
-  @media print {
-    display: block !important;
-  }
-}
-.visible-print-inline {
-  display: none !important;
-
-  @media print {
-    display: inline !important;
-  }
-}
-.visible-print-inline-block {
-  display: none !important;
-
-  @media print {
-    display: inline-block !important;
-  }
-}
-
-.hidden-print {
-  @media print {
-    .responsive-invisibility();
-  }
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/tables.less b/src/legacy/ui/public/styles/bootstrap/tables.less
deleted file mode 100644
index 917196b3c711d..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/tables.less
+++ /dev/null
@@ -1,227 +0,0 @@
-//
-// Tables
-// --------------------------------------------------
-
-
-// Baseline styles
-
-.table {
-  width: 100%;
-  max-width: 100%;
-  margin-bottom: @line-height-computed;
-  font-size: 14px;
-
-  thead {
-    font-size: 12px;
-  }
-
-  // Cells
-  > thead,
-  > tbody,
-  > tfoot {
-    > tr {
-      > th,
-      > td {
-        padding: @table-cell-padding;
-        line-height: @line-height-base;
-        vertical-align: top;
-        border-top: 1px solid @table-border-color;
-      }
-    }
-  }
-  // Bottom align for column headings
-  > thead > tr > th {
-    vertical-align: bottom;
-    border-bottom: 1px solid @table-border-color;
-  }
-  // Remove top border from thead by default
-  > caption + thead,
-  > colgroup + thead,
-  > thead:first-child {
-    > tr:first-child {
-      > th,
-      > td {
-        border-top: 0;
-      }
-    }
-  }
-  // Account for multiple tbody instances
-  > tbody + tbody {
-    border-top: 2px solid @table-border-color;
-  }
-
-  // Nesting
-  .table {
-    background-color: @body-bg;
-  }
-}
-
-
-// Condensed table w/ half padding
-
-.table-condensed {
-  > thead,
-  > tbody,
-  > tfoot {
-    > tr {
-      > th,
-      > td {
-        padding: @table-condensed-cell-padding;
-        font-size: 12px;
-      }
-    }
-  }
-}
-
-
-// Bordered version
-//
-// Add borders all around the table and between all the columns.
-
-.table-bordered {
-  border: 1px solid @table-border-color;
-  > thead,
-  > tbody,
-  > tfoot {
-    > tr {
-      > th,
-      > td {
-        border: 1px solid @table-border-color;
-      }
-    }
-  }
-  > thead > tr {
-    > th,
-    > td {
-      border-bottom-width: 2px;
-    }
-  }
-}
-
-
-// Zebra-striping
-//
-// Default zebra-stripe styles (alternating gray and transparent backgrounds)
-
-.table-striped {
-  > tbody > tr:nth-of-type(odd) {
-    background-color: @table-bg-accent;
-  }
-}
-
-
-// Hover effect
-//
-// Placed here since it has to come after the potential zebra striping
-
-.table-hover {
-  > tbody > tr:hover {
-    background-color: @table-bg-hover;
-  }
-}
-
-
-// Table cell sizing
-//
-// Reset default table behavior
-
-table col[class*="col-"] {
-  position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)
-  float: none;
-  display: table-column;
-}
-table {
-  td,
-  th {
-    &[class*="col-"] {
-      position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)
-      float: none;
-      display: table-cell;
-    }
-  }
-}
-
-
-// Table backgrounds
-//
-// Exact selectors below required to override `.table-striped` and prevent
-// inheritance to nested tables.
-
-// Generate the contextual variants
-.table-row-variant(active; @table-bg-active);
-.table-row-variant(success; @state-success-bg);
-.table-row-variant(info; @state-info-bg);
-.table-row-variant(warning; @state-warning-bg);
-.table-row-variant(danger; @state-danger-bg);
-
-
-// Responsive tables
-//
-// Wrap your tables in `.table-responsive` and we'll make them mobile friendly
-// by enabling horizontal scrolling. Only applies <768px. Everything above that
-// will display normally.
-
-.table-responsive {
-  overflow-x: auto;
-  min-height: 0.01%; // Workaround for IE9 bug (see https://github.com/twbs/bootstrap/issues/14837)
-
-  @media screen and (max-width: @screen-xs-max) {
-    width: 100%;
-    margin-bottom: (@line-height-computed * 0.75);
-    overflow-y: hidden;
-    -ms-overflow-style: -ms-autohiding-scrollbar;
-    border: 1px solid @table-border-color;
-
-    // Tighten up spacing
-    > .table {
-      margin-bottom: 0;
-
-      // Ensure the content doesn't wrap
-      > thead,
-      > tbody,
-      > tfoot {
-        > tr {
-          > th,
-          > td {
-            white-space: nowrap;
-          }
-        }
-      }
-    }
-
-    // Special overrides for the bordered tables
-    > .table-bordered {
-      border: 0;
-
-      // Nuke the appropriate borders so that the parent can handle them
-      > thead,
-      > tbody,
-      > tfoot {
-        > tr {
-          > th:first-child,
-          > td:first-child {
-            border-left: 0;
-          }
-          > th:last-child,
-          > td:last-child {
-            border-right: 0;
-          }
-        }
-      }
-
-      // Only nuke the last row's bottom-border in `tbody` and `tfoot` since
-      // chances are there will be only one `tr` in a `thead` and that would
-      // remove the border altogether.
-      > tbody,
-      > tfoot {
-        > tr:last-child {
-          > th,
-          > td {
-            border-bottom: 0;
-          }
-        }
-      }
-
-    }
-  }
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/tooltip.less b/src/legacy/ui/public/styles/bootstrap/tooltip.less
deleted file mode 100644
index a85617d38b263..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/tooltip.less
+++ /dev/null
@@ -1,101 +0,0 @@
-//
-// Tooltips
-// --------------------------------------------------
-
-
-// Base class
-.bsTooltip {
-  position: absolute;
-  z-index: @zindex-tooltip;
-  display: block;
-  // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.
-  // So reset our font and text properties to avoid inheriting weird values.
-  .reset-text();
-  font-size: @font-size-small;
-
-  .opacity(0);
-
-  &.in     { .opacity(@tooltip-opacity); }
-  &.top    { margin-top:  -3px; padding: @tooltip-arrow-width 0; }
-  &.right  { margin-left:  3px; padding: 0 @tooltip-arrow-width; }
-  &.bottom { margin-top:   3px; padding: @tooltip-arrow-width 0; }
-  &.left   { margin-left: -3px; padding: 0 @tooltip-arrow-width; }
-}
-
-// Wrapper for the tooltip content
-.bsTooltip-inner {
-  max-width: @tooltip-max-width;
-  padding: 3px 8px;
-  color: @tooltip-color;
-  text-align: center;
-  background-color: @tooltip-bg;
-  border-radius: @border-radius-base;
-}
-
-// Arrows
-.bsTooltip-arrow {
-  position: absolute;
-  width: 0;
-  height: 0;
-  border-color: transparent;
-  border-style: solid;
-}
-// Note: Deprecated .top-left, .top-right, .bottom-left, and .bottom-right as of v3.3.1
-.bsTooltip {
-  &.top .bsTooltip-arrow {
-    bottom: 0;
-    left: 50%;
-    margin-left: -@tooltip-arrow-width;
-    border-width: @tooltip-arrow-width @tooltip-arrow-width 0;
-    border-top-color: @tooltip-arrow-color;
-  }
-  &.top-left .bsTooltip-arrow {
-    bottom: 0;
-    right: @tooltip-arrow-width;
-    margin-bottom: -@tooltip-arrow-width;
-    border-width: @tooltip-arrow-width @tooltip-arrow-width 0;
-    border-top-color: @tooltip-arrow-color;
-  }
-  &.top-right .bsTooltip-arrow {
-    bottom: 0;
-    left: @tooltip-arrow-width;
-    margin-bottom: -@tooltip-arrow-width;
-    border-width: @tooltip-arrow-width @tooltip-arrow-width 0;
-    border-top-color: @tooltip-arrow-color;
-  }
-  &.right .bsTooltip-arrow {
-    top: 50%;
-    left: 0;
-    margin-top: -@tooltip-arrow-width;
-    border-width: @tooltip-arrow-width @tooltip-arrow-width @tooltip-arrow-width 0;
-    border-right-color: @tooltip-arrow-color;
-  }
-  &.left .bsTooltip-arrow {
-    top: 50%;
-    right: 0;
-    margin-top: -@tooltip-arrow-width;
-    border-width: @tooltip-arrow-width 0 @tooltip-arrow-width @tooltip-arrow-width;
-    border-left-color: @tooltip-arrow-color;
-  }
-  &.bottom .bsTooltip-arrow {
-    top: 0;
-    left: 50%;
-    margin-left: -@tooltip-arrow-width;
-    border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;
-    border-bottom-color: @tooltip-arrow-color;
-  }
-  &.bottom-left .bsTooltip-arrow {
-    top: 0;
-    right: @tooltip-arrow-width;
-    margin-top: -@tooltip-arrow-width;
-    border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;
-    border-bottom-color: @tooltip-arrow-color;
-  }
-  &.bottom-right .bsTooltip-arrow {
-    top: 0;
-    left: @tooltip-arrow-width;
-    margin-top: -@tooltip-arrow-width;
-    border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;
-    border-bottom-color: @tooltip-arrow-color;
-  }
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/type.less b/src/legacy/ui/public/styles/bootstrap/type.less
deleted file mode 100644
index 08be0615b04c1..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/type.less
+++ /dev/null
@@ -1,63 +0,0 @@
-//
-// Typography
-// --------------------------------------------------
-
-
-// Alignment
-.text-left           { text-align: left; }
-.text-right          { text-align: right; }
-.text-center         { text-align: center; }
-
-// Contextual colors
-.text-muted {
-  color: @text-muted;
-}
-.text-primary {
-  .text-emphasis-variant(@brand-primary);
-}
-.text-success {
-  .text-emphasis-variant(@state-success-text);
-}
-.text-info {
-  .text-emphasis-variant(@state-info-text);
-}
-.text-warning {
-  .text-emphasis-variant(@state-warning-text);
-}
-.text-danger {
-  .text-emphasis-variant(@state-danger-text);
-}
-
-.bg-info {
-  .bg-variant(@state-info-bg);
-}
-
-// Unstyled keeps list items block level, just removes default browser padding and list-style
-.list-unstyled {
-  padding-left: 0;
-  list-style: none;
-}
-
-// Horizontal description lists
-//
-// Defaults to being stacked without any of the below styles applied, until the
-// grid breakpoint is reached (default of ~768px).
-
-.dl-horizontal {
-  dd {
-    &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present
-  }
-
-  @media (min-width: @dl-horizontal-breakpoint) {
-    dt {
-      float: left;
-      width: (@dl-horizontal-offset - 20);
-      clear: left;
-      text-align: right;
-      .text-overflow();
-    }
-    dd {
-      margin-left: @dl-horizontal-offset;
-    }
-  }
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/utilities.less b/src/legacy/ui/public/styles/bootstrap/utilities.less
deleted file mode 100644
index 7a8ca27a8ff54..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/utilities.less
+++ /dev/null
@@ -1,55 +0,0 @@
-//
-// Utility classes
-// --------------------------------------------------
-
-
-// Floats
-// -------------------------
-
-.clearfix {
-  .clearfix();
-}
-.center-block {
-  .center-block();
-}
-.pull-right {
-  float: right !important;
-}
-.pull-left {
-  float: left !important;
-}
-
-
-// Toggling content
-// -------------------------
-
-// Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1
-.hide {
-  display: none !important;
-}
-.show {
-  display: block !important;
-}
-.invisible {
-  visibility: hidden;
-}
-.text-hide {
-  .text-hide();
-}
-
-
-// Hide from screenreaders and browsers
-//
-// Credit: HTML5 Boilerplate
-
-.hidden {
-  display: none !important;
-}
-
-
-// For Affix plugin
-// -------------------------
-
-.affix {
-  position: fixed;
-}
diff --git a/src/legacy/ui/public/styles/bootstrap/variables.less b/src/legacy/ui/public/styles/bootstrap/variables.less
deleted file mode 100644
index 129beaaee5bb8..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap/variables.less
+++ /dev/null
@@ -1,852 +0,0 @@
-//
-// Variables
-// --------------------------------------------------
-
-
-//== Colors
-//
-//## Gray and brand colors for use across Bootstrap.
-
-@gray-base:              #000;
-@gray-darker:            lighten(@gray-base, 13.5%); // #222
-@gray-dark:              lighten(@gray-base, 20%);   // #333
-@gray:                   lighten(@gray-base, 33.5%); // #555
-@gray-light:             lighten(@gray-base, 46.7%); // #777
-@gray-lighter:           lighten(@gray-base, 93.5%); // #eee
-@gray-lightest:          lighten(@gray-base, 98%);
-
-@brand-primary:         darken(#428bca, 6.5%); // #337ab7
-@brand-success:         #5cb85c;
-@brand-info:            #5bc0de;
-@brand-warning:         #f0ad4e;
-@brand-danger:          #d9534f;
-
-
-//== Scaffolding
-//
-//## Settings for some of the most global styles.
-
-//** Background color for ``.
-@body-bg:               #fff;
-//** Global text color on ``.
-@text-color:            @gray-dark;
-
-//** Global textual link color.
-@link-color:            @brand-primary;
-//** Link hover color set via `darken()` function.
-@link-hover-color:      darken(@link-color, 15%);
-//** Link hover decoration.
-@link-hover-decoration: underline;
-
-
-//== Typography
-//
-//## Font, line-height, and color for body text, headings, and more.
-
-@font-family-sans-serif:  "Helvetica Neue", Helvetica, Arial, sans-serif;
-@font-family-serif:       Georgia, "Times New Roman", Times, serif;
-//** Default monospace fonts for ``, ``, and `
`.
-@font-family-monospace:   Menlo, Monaco, Consolas, "Courier New", monospace;
-@font-family-base:        @font-family-sans-serif;
-
-@font-size-base:          14px;
-@font-size-large:         ceil((@font-size-base * 1.25)); // ~18px
-@font-size-small:         ceil((@font-size-base * 0.85)); // ~12px
-
-@font-size-h1:            floor((@font-size-base * 2.6)); // ~36px
-@font-size-h2:            floor((@font-size-base * 2.15)); // ~30px
-@font-size-h3:            ceil((@font-size-base * 1.7)); // ~24px
-@font-size-h4:            ceil((@font-size-base * 1.25)); // ~18px
-@font-size-h5:            @font-size-base;
-@font-size-h6:            ceil((@font-size-base * 0.85)); // ~12px
-
-//** Unit-less `line-height` for use in components like buttons.
-@line-height-base:        1.428571429; // 20/14
-//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
-@line-height-computed:    floor((@font-size-base * @line-height-base)); // ~20px
-
-//** By default, this inherits from the ``.
-@headings-font-family:    inherit;
-@headings-font-weight:    500;
-@headings-line-height:    1.1;
-@headings-color:          inherit;
-
-
-//== Iconography
-//
-//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
-
-//** Load fonts from this directory.
-@icon-font-path:          "../fonts/";
-//** File name for all font files.
-@icon-font-name:          "glyphicons-halflings-regular";
-//** Element ID within SVG icon file.
-@icon-font-svg-id:        "glyphicons_halflingsregular";
-
-
-//== Components
-//
-//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
-
-@padding-base-vertical:     6px;
-@padding-base-horizontal:   12px;
-
-@padding-large-vertical:    10px;
-@padding-large-horizontal:  16px;
-
-@padding-small-vertical:    5px;
-@padding-small-horizontal:  10px;
-
-@padding-xs-vertical:       1px;
-@padding-xs-horizontal:     5px;
-
-@line-height-large:         1.3333333; // extra decimals for Win 8.1 Chrome
-@line-height-small:         1.5;
-
-@border-radius-base:        4px;
-@border-radius-large:       6px;
-@border-radius-small:       3px;
-
-//** Global color for active items (e.g., navs or dropdowns).
-@component-active-color:    #fff;
-//** Global background color for active items (e.g., navs or dropdowns).
-@component-active-bg:       @brand-primary;
-
-//** Width of the `border` for generating carets that indicator dropdowns.
-@caret-width-base:          4px;
-//** Carets increase slightly in size for larger components.
-@caret-width-large:         5px;
-
-
-//== Tables
-//
-//## Customizes the `.table` component with basic values, each used across all table variations.
-
-//** Padding for ``s and ``s.
-@table-cell-padding:            8px;
-//** Padding for cells in `.table-condensed`.
-@table-condensed-cell-padding:  5px;
-
-//** Default background color used for all tables.
-@table-bg:                      transparent;
-//** Background color used for `.table-striped`.
-@table-bg-accent:               #f9f9f9;
-//** Background color used for `.table-hover`.
-@table-bg-hover:                @gray-lightest;
-@table-bg-active:               @table-bg-hover;
-
-//** Border color for table and cell borders.
-@table-border-color:            #ddd;
-
-
-//== Buttons
-//
-//## For each of Bootstrap's buttons, define text, background and border color.
-
-@btn-font-weight:                normal;
-
-@btn-default-color:              #333;
-@btn-default-bg:                 #fff;
-@btn-default-border:             #ccc;
-
-@btn-primary-color:              #fff;
-@btn-primary-bg:                 @brand-primary;
-@btn-primary-border:             darken(@btn-primary-bg, 5%);
-
-@btn-success-color:              #fff;
-@btn-success-bg:                 @brand-success;
-@btn-success-border:             darken(@btn-success-bg, 5%);
-
-@btn-info-color:                 #fff;
-@btn-info-bg:                    @brand-info;
-@btn-info-border:                darken(@btn-info-bg, 5%);
-
-@btn-warning-color:              #fff;
-@btn-warning-bg:                 @brand-warning;
-@btn-warning-border:             darken(@btn-warning-bg, 5%);
-
-@btn-danger-color:               #fff;
-@btn-danger-bg:                  @brand-danger;
-@btn-danger-border:              darken(@btn-danger-bg, 5%);
-
-@btn-link-disabled-color:        @gray-light;
-
-// Allows for customizing button radius independently from global border radius
-@btn-border-radius-base:         @border-radius-base;
-@btn-border-radius-large:        @border-radius-large;
-@btn-border-radius-small:        @border-radius-small;
-
-
-//== Forms
-//
-//##
-
-//** `` background color
-@input-bg:                       #fff;
-//** `` background color
-@input-bg-disabled:              @gray-lighter;
-
-//** Text color for ``s
-@input-color:                    @gray;
-//** `` border color
-@input-border:                   #ccc;
-
-//** Default `.form-control` border radius
-// This has no effect on ``s in CSS.
-@input-border-radius-base:       @border-radius-base;
-//** Large `.form-control` border radius
-@input-border-radius-large:      @border-radius-large;
-//** Small `.form-control` border radius
-@input-border-radius-small:      @border-radius-small;
-
-//** Border color for inputs on focus
-@input-border-focus:             #66afe9;
-
-//** Placeholder text color
-@input-color-placeholder:        #999;
-
-//** Default `.form-control` height
-@input-height-base:              (@line-height-computed + (@padding-base-vertical * 2) + 2);
-//** Large `.form-control` height
-@input-height-large:             (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);
-//** Small `.form-control` height
-@input-height-small:             (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);
-
-//** `.form-group` margin
-@form-group-margin-bottom:       15px;
-
-@legend-color:                   @gray-dark;
-@legend-border-color:            #e5e5e5;
-
-//** Background color for textual input addons
-@input-group-addon-bg:           @gray-lighter;
-//** Border color for textual input addons
-@input-group-addon-border-color: @input-border;
-
-//** Disabled cursor for form controls and buttons.
-@cursor-disabled:                not-allowed;
-
-
-//== Dropdowns
-//
-//## Dropdown menu container and contents.
-
-//** Background for the dropdown menu.
-@dropdown-bg:                    #fff;
-//** Dropdown menu `border-color`.
-@dropdown-border:                rgba(0,0,0,.15);
-//** Dropdown menu `border-color` **for IE8**.
-@dropdown-fallback-border:       #ccc;
-//** Divider color for between dropdown items.
-@dropdown-divider-bg:            #e5e5e5;
-
-//** Dropdown link text color.
-@dropdown-link-color:            @gray-dark;
-//** Hover color for dropdown links.
-@dropdown-link-hover-color:      darken(@gray-dark, 5%);
-//** Hover background for dropdown links.
-@dropdown-link-hover-bg:         @gray-lightest;
-
-//** Active dropdown menu item text color.
-@dropdown-link-active-color:     @component-active-color;
-//** Active dropdown menu item background color.
-@dropdown-link-active-bg:        @component-active-bg;
-
-//** Disabled dropdown menu item background color.
-@dropdown-link-disabled-color:   @gray-light;
-
-//** Text color for headers within dropdown menus.
-@dropdown-header-color:          @gray-light;
-
-//** Deprecated `@dropdown-caret-color` as of v3.1.0
-@dropdown-caret-color:           #000;
-
-
-//-- Z-index master list
-//
-// Warning: Avoid customizing these values. They're used for a bird's eye view
-// of components dependent on the z-axis and are designed to all work together.
-//
-// Note: These variables are not generated into the Customizer.
-
-@zindex-navbar:            1000;
-@zindex-dropdown:          1000;
-@zindex-popover:           1060;
-@zindex-tooltip:           1070;
-@zindex-navbar-fixed:      1030;
-@zindex-modal-background:  1040;
-@zindex-modal:             1050;
-
-
-//== Media queries breakpoints
-//
-//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
-
-// Extra small screen / phone
-//** Deprecated `@screen-xs` as of v3.0.1
-@screen-xs:                  480px;
-//** Deprecated `@screen-xs-min` as of v3.2.0
-@screen-xs-min:              @screen-xs;
-//** Deprecated `@screen-phone` as of v3.0.1
-@screen-phone:               @screen-xs-min;
-
-// Small screen / tablet
-//** Deprecated `@screen-sm` as of v3.0.1
-@screen-sm:                  768px;
-@screen-sm-min:              @screen-sm;
-//** Deprecated `@screen-tablet` as of v3.0.1
-@screen-tablet:              @screen-sm-min;
-
-// Medium screen / desktop
-//** Deprecated `@screen-md` as of v3.0.1
-@screen-md:                  992px;
-@screen-md-min:              @screen-md;
-//** Deprecated `@screen-desktop` as of v3.0.1
-@screen-desktop:             @screen-md-min;
-
-// Large screen / wide desktop
-//** Deprecated `@screen-lg` as of v3.0.1
-@screen-lg:                  1200px;
-@screen-lg-min:              @screen-lg;
-//** Deprecated `@screen-lg-desktop` as of v3.0.1
-@screen-lg-desktop:          @screen-lg-min;
-
-// So media queries don't overlap when required, provide a maximum
-@screen-xs-max:              (@screen-sm-min - 1);
-@screen-sm-max:              (@screen-md-min - 1);
-@screen-md-max:              (@screen-lg-min - 1);
-
-
-//== Grid system
-//
-//## Define your custom responsive grid.
-
-//** Number of columns in the grid.
-@grid-columns:              12;
-//** Padding between columns. Gets divided in half for the left and right.
-@grid-gutter-width:         30px;
-// Navbar collapse
-//** Point at which the navbar becomes uncollapsed.
-@grid-float-breakpoint:     0;
-//** Point at which the navbar begins collapsing.
-@grid-float-breakpoint-max: (@grid-float-breakpoint - 1);
-
-
-//== Container sizes
-//
-//## Define the maximum width of `.container` for different screen sizes.
-
-// Small screen / tablet
-@container-tablet:             (720px + @grid-gutter-width);
-//** For `@screen-sm-min` and up.
-@container-sm:                 @container-tablet;
-
-// Medium screen / desktop
-@container-desktop:            (940px + @grid-gutter-width);
-//** For `@screen-md-min` and up.
-@container-md:                 @container-desktop;
-
-// Large screen / wide desktop
-@container-large-desktop:      (1140px + @grid-gutter-width);
-//** For `@screen-lg-min` and up.
-@container-lg:                 @container-large-desktop;
-
-
-//== Navbar
-//
-//##
-
-// Basics of a navbar
-@navbar-height:                    48px;
-@navbar-margin-bottom:             @line-height-computed;
-@navbar-border-radius:             @border-radius-base;
-@navbar-padding-horizontal:        floor((@grid-gutter-width / 2));
-@navbar-padding-vertical:          ((@navbar-height - @line-height-computed) / 2);
-@navbar-collapse-max-height:       340px;
-
-@navbar-default-color:             #777;
-@navbar-default-bg:                #f8f8f8;
-@navbar-default-border:            darken(@navbar-default-bg, 6.5%);
-
-// Navbar links
-@navbar-default-link-color:                #777;
-@navbar-default-link-hover-color:          #333;
-@navbar-default-link-hover-bg:             transparent;
-@navbar-default-link-active-color:         #555;
-@navbar-default-link-active-bg:            darken(@navbar-default-bg, 6.5%);
-@navbar-default-link-disabled-color:       #ccc;
-@navbar-default-link-disabled-bg:          transparent;
-
-// Navbar brand label
-@navbar-default-brand-color:               @navbar-default-link-color;
-@navbar-default-brand-hover-color:         darken(@navbar-default-brand-color, 10%);
-@navbar-default-brand-hover-bg:            transparent;
-
-// Navbar toggle
-@navbar-default-toggle-hover-bg:           #ddd;
-@navbar-default-toggle-icon-bar-bg:        #888;
-@navbar-default-toggle-border-color:       #ddd;
-
-
-//=== Inverted navbar
-// Reset inverted navbar basics
-@navbar-inverse-color:                      lighten(@gray-light, 15%);
-@navbar-inverse-bg:                         #222;
-@navbar-inverse-border:                     darken(@navbar-inverse-bg, 10%);
-
-// Inverted navbar links
-@navbar-inverse-link-color:                 lighten(@gray-light, 15%);
-@navbar-inverse-link-hover-color:           #fff;
-@navbar-inverse-link-hover-bg:              transparent;
-@navbar-inverse-link-active-color:          @navbar-inverse-link-hover-color;
-@navbar-inverse-link-active-bg:             darken(@navbar-inverse-bg, 10%);
-@navbar-inverse-link-disabled-color:        #444;
-@navbar-inverse-link-disabled-bg:           transparent;
-
-// Inverted navbar brand label
-@navbar-inverse-brand-color:                @navbar-inverse-link-color;
-@navbar-inverse-brand-hover-color:          #fff;
-@navbar-inverse-brand-hover-bg:             transparent;
-
-// Inverted navbar toggle
-@navbar-inverse-toggle-hover-bg:            #333;
-@navbar-inverse-toggle-icon-bar-bg:         #fff;
-@navbar-inverse-toggle-border-color:        #333;
-
-
-//== Navs
-//
-//##
-
-//=== Shared nav styles
-@nav-link-padding:                          10px 15px;
-@nav-link-hover-bg:                         @gray-lighter;
-
-@nav-disabled-link-color:                   @gray-light;
-@nav-disabled-link-hover-color:             @gray-light;
-
-//== Tabs
-@nav-tabs-border-color:                     #ddd;
-
-@nav-tabs-link-hover-border-color:          @gray-lighter;
-
-@nav-tabs-active-link-hover-bg:             #fff;;
-@nav-tabs-active-link-hover-color:          @gray;
-@nav-tabs-active-link-hover-border-color:   #ddd;
-
-@nav-tabs-justified-link-border-color:            #ddd;
-@nav-tabs-justified-active-link-border-color:     @body-bg;
-
-//== Pills
-@nav-pills-border-radius:                   @border-radius-base;
-@nav-pills-active-link-hover-bg:            @component-active-bg;
-@nav-pills-active-link-hover-color:         @component-active-color;
-
-
-//== Pagination
-//
-//##
-
-@pagination-color:                     @link-color;
-@pagination-bg:                        #fff;
-@pagination-border:                    #ddd;
-
-@pagination-hover-color:               @link-hover-color;
-@pagination-hover-bg:                  @gray-lighter;
-@pagination-hover-border:              #ddd;
-
-@pagination-active-color:              #fff;
-@pagination-active-bg:                 @brand-primary;
-@pagination-active-border:             @brand-primary;
-
-@pagination-disabled-color:            @gray-light;
-@pagination-disabled-bg:               #fff;
-@pagination-disabled-border:           #ddd;
-
-
-//== Pager
-//
-//##
-
-@pager-bg:                             @pagination-bg;
-@pager-border:                         @pagination-border;
-@pager-border-radius:                  15px;
-
-@pager-hover-bg:                       @pagination-hover-bg;
-
-@pager-active-bg:                      @pagination-active-bg;
-@pager-active-color:                   @pagination-active-color;
-
-@pager-disabled-color:                 @pagination-disabled-color;
-
-
-//== Jumbotron
-//
-//##
-
-@jumbotron-padding:              30px;
-@jumbotron-color:                inherit;
-@jumbotron-bg:                   @gray-lighter;
-@jumbotron-heading-color:        inherit;
-@jumbotron-font-size:            ceil((@font-size-base * 1.5));
-@jumbotron-heading-font-size:    ceil((@font-size-base * 4.5));
-
-
-//== Form states and alerts
-//
-//## Define colors for form feedback states and, by default, alerts.
-
-@state-success-text:             #3c763d;
-@state-success-bg:               #dff0d8;
-@state-success-border:           darken(spin(@state-success-bg, -10), 5%);
-
-@state-info-text:                #31708f;
-@state-info-bg:                  #d9edf7;
-@state-info-border:              darken(spin(@state-info-bg, -10), 7%);
-
-@state-warning-text:             #8a6d3b;
-@state-warning-bg:               #fcf8e3;
-@state-warning-border:           darken(spin(@state-warning-bg, -10), 5%);
-
-@state-danger-text:              #a94442;
-@state-danger-bg:                #f2dede;
-@state-danger-border:            darken(spin(@state-danger-bg, -10), 5%);
-
-
-//== Tooltips
-//
-//##
-
-//** Tooltip max width
-@tooltip-max-width:           200px;
-//** Tooltip text color
-@tooltip-color:               #fff;
-//** Tooltip background color
-@tooltip-bg:                  #000;
-@tooltip-opacity:             .9;
-
-//** Tooltip arrow width
-@tooltip-arrow-width:         5px;
-//** Tooltip arrow color
-@tooltip-arrow-color:         @tooltip-bg;
-
-
-//== Popovers
-//
-//##
-
-//** Popover body background color
-@popover-bg:                          #fff;
-//** Popover maximum width
-@popover-max-width:                   276px;
-//** Popover border color
-@popover-border-color:                rgba(0,0,0,.2);
-//** Popover fallback border color
-@popover-fallback-border-color:       #ccc;
-
-//** Popover title background color
-@popover-title-bg:                    darken(@popover-bg, 3%);
-
-//** Popover arrow width
-@popover-arrow-width:                 10px;
-//** Popover arrow color
-@popover-arrow-color:                 @popover-bg;
-
-//** Popover outer arrow width
-@popover-arrow-outer-width:           (@popover-arrow-width + 1);
-//** Popover outer arrow color
-@popover-arrow-outer-color:           fadein(@popover-border-color, 5%);
-//** Popover outer arrow fallback color
-@popover-arrow-outer-fallback-color:  darken(@popover-fallback-border-color, 20%);
-
-
-//== Labels
-//
-//##
-
-//** Default label background color
-@label-default-bg:            @gray-light;
-//** Primary label background color
-@label-primary-bg:            @brand-primary;
-//** Success label background color
-@label-success-bg:            @brand-success;
-//** Info label background color
-@label-info-bg:               @brand-info;
-//** Warning label background color
-@label-warning-bg:            @brand-warning;
-//** Danger label background color
-@label-danger-bg:             @brand-danger;
-
-//** Default label text color
-@label-color:                 #fff;
-//** Default text color of a linked label
-@label-link-hover-color:      #fff;
-
-
-//== Modals
-//
-//##
-
-//** Padding applied to the modal body
-@modal-inner-padding:         15px;
-
-//** Padding applied to the modal title
-@modal-title-padding:         15px;
-//** Modal title line-height
-@modal-title-line-height:     @line-height-base;
-
-//** Background color of modal content area
-@modal-content-bg:                             #fff;
-//** Modal content border color
-@modal-content-border-color:                   rgba(0,0,0,.2);
-//** Modal content border color **for IE8**
-@modal-content-fallback-border-color:          #999;
-
-//** Modal backdrop background color
-@modal-backdrop-bg:           #000;
-//** Modal backdrop opacity
-@modal-backdrop-opacity:      .5;
-//** Modal header border color
-@modal-header-border-color:   #e5e5e5;
-//** Modal footer border color
-@modal-footer-border-color:   @modal-header-border-color;
-
-@modal-lg:                    900px;
-@modal-md:                    600px;
-@modal-sm:                    300px;
-
-
-//== Alerts
-//
-//## Define alert colors, border radius, and padding.
-
-@alert-padding:               15px;
-@alert-border-radius:         @border-radius-base;
-@alert-link-font-weight:      bold;
-
-@alert-success-bg:            @state-success-bg;
-@alert-success-text:          @state-success-text;
-@alert-success-border:        @state-success-border;
-
-@alert-info-bg:               @state-info-bg;
-@alert-info-text:             @state-info-text;
-@alert-info-border:           @state-info-border;
-
-@alert-warning-bg:            @state-warning-bg;
-@alert-warning-text:          @state-warning-text;
-@alert-warning-border:        @state-warning-border;
-
-@alert-danger-bg:             @state-danger-bg;
-@alert-danger-text:           @state-danger-text;
-@alert-danger-border:         @state-danger-border;
-
-
-//== Progress bars
-//
-//##
-
-//** Background color of the whole progress component
-@progress-bg:                 @gray-lightest;
-//** Progress bar text color
-@progress-bar-color:          #fff;
-//** Variable for setting rounded corners on progress bar.
-@progress-border-radius:      @border-radius-base;
-
-//** Default progress bar color
-@progress-bar-bg:             @brand-primary;
-//** Success progress bar color
-@progress-bar-success-bg:     @brand-success;
-//** Warning progress bar color
-@progress-bar-warning-bg:     @brand-warning;
-//** Danger progress bar color
-@progress-bar-danger-bg:      @brand-danger;
-//** Info progress bar color
-@progress-bar-info-bg:        @brand-info;
-
-
-//== List group
-//
-//##
-
-//** Background color on `.list-group-item`
-@list-group-bg:                 #fff;
-//** `.list-group-item` border color
-@list-group-border:             #ddd;
-//** List group border radius
-@list-group-border-radius:      @border-radius-base;
-
-//** Background color of single list items on hover
-@list-group-hover-bg:           @gray-lightest;
-//** Text color of active list items
-@list-group-active-color:       @component-active-color;
-//** Background color of active list items
-@list-group-active-bg:          @component-active-bg;
-//** Border color of active list elements
-@list-group-active-border:      @list-group-active-bg;
-//** Text color for content within active list items
-@list-group-active-text-color:  lighten(@list-group-active-bg, 40%);
-
-//** Text color of disabled list items
-@list-group-disabled-color:      @gray-light;
-//** Background color of disabled list items
-@list-group-disabled-bg:         @gray-lighter;
-//** Text color for content within disabled list items
-@list-group-disabled-text-color: @list-group-disabled-color;
-
-@list-group-link-color:         #555;
-@list-group-link-hover-color:   @list-group-link-color;
-@list-group-link-heading-color: #333;
-
-
-//== Panels
-//
-//##
-
-@panel-bg:                    #fff;
-@panel-body-padding:          15px;
-@panel-heading-padding:       10px 15px;
-@panel-footer-padding:        @panel-heading-padding;
-@panel-border-radius:         @border-radius-base;
-
-//** Border color for elements within panels
-@panel-inner-border:          #ddd;
-@panel-footer-bg:             @gray-lightest;
-
-@panel-default-text:          @gray-dark;
-@panel-default-border:        #ddd;
-@panel-default-heading-bg:    @gray-lightest;
-
-@panel-primary-text:          #fff;
-@panel-primary-border:        @brand-primary;
-@panel-primary-heading-bg:    @brand-primary;
-
-@panel-success-text:          @state-success-text;
-@panel-success-border:        @state-success-border;
-@panel-success-heading-bg:    @state-success-bg;
-
-@panel-info-text:             @state-info-text;
-@panel-info-border:           @state-info-border;
-@panel-info-heading-bg:       @state-info-bg;
-
-@panel-warning-text:          @state-warning-text;
-@panel-warning-border:        @state-warning-border;
-@panel-warning-heading-bg:    @state-warning-bg;
-
-@panel-danger-text:           @state-danger-text;
-@panel-danger-border:         @state-danger-border;
-@panel-danger-heading-bg:     @state-danger-bg;
-
-
-//== Thumbnails
-//
-//##
-
-//** Padding around the thumbnail image
-@thumbnail-padding:           4px;
-//** Thumbnail background color
-@thumbnail-bg:                @body-bg;
-//** Thumbnail border color
-@thumbnail-border:            #ddd;
-//** Thumbnail border radius
-@thumbnail-border-radius:     @border-radius-base;
-
-//** Custom text color for thumbnail captions
-@thumbnail-caption-color:     @text-color;
-//** Padding around the thumbnail caption
-@thumbnail-caption-padding:   9px;
-
-
-//== Wells
-//
-//##
-
-@well-bg:                     @gray-lightest;
-@well-border:                 darken(@well-bg, 7%);
-
-
-//== Badges
-//
-//##
-
-@badge-color:                 #fff;
-//** Linked badge text color on hover
-@badge-link-hover-color:      #fff;
-@badge-bg:                    @gray-light;
-
-//** Badge text color in active nav link
-@badge-active-color:          @link-color;
-//** Badge background color in active nav link
-@badge-active-bg:             #fff;
-
-@badge-font-weight:           bold;
-@badge-line-height:           1;
-@badge-border-radius:         10px;
-
-
-//== Breadcrumbs
-//
-//##
-
-@breadcrumb-padding-vertical:   8px;
-@breadcrumb-padding-horizontal: 15px;
-//** Breadcrumb background color
-@breadcrumb-bg:                 @gray-lightest;
-//** Breadcrumb text color
-@breadcrumb-color:              #ccc;
-//** Text color of current page in the breadcrumb
-@breadcrumb-active-color:       @gray-light;
-//** Textual separator for between breadcrumb elements
-@breadcrumb-separator:          "/";
-
-
-//== Close
-//
-//##
-
-@close-font-weight:           bold;
-@close-color:                 #000;
-@close-text-shadow:           0 1px 0 #fff;
-
-
-//== Code
-//
-//##
-
-@code-color:                  #c7254e;
-@code-bg:                     #f9f2f4;
-
-@kbd-color:                   #fff;
-@kbd-bg:                      #333;
-
-@pre-bg:                      @gray-lightest;
-@pre-color:                   @gray-dark;
-@pre-border-color:            #ccc;
-@pre-scrollable-max-height:   340px;
-
-
-//== Type
-//
-//##
-
-//** Horizontal offset for forms and lists.
-@component-offset-horizontal: 180px;
-//** Text muted color
-@text-muted:                  @gray-light;
-//** Abbreviations and acronyms border color
-@abbr-border-color:           @gray-light;
-//** Headings small color
-@headings-small-color:        @gray-light;
-//** Blockquote small color
-@blockquote-small-color:      @gray-light;
-//** Blockquote font size
-@blockquote-font-size:        (@font-size-base * 1.25);
-//** Blockquote border color
-@blockquote-border-color:     @gray-lighter;
-//** Page header border color
-@page-header-border-color:    @gray-lighter;
-//** Width of horizontal description list titles
-@dl-horizontal-offset:        @component-offset-horizontal;
-//** Point at which .dl-horizontal becomes horizontal
-@dl-horizontal-breakpoint:    @grid-float-breakpoint;
-//** Horizontal line color.
-@hr-border:                   @gray-lighter;
diff --git a/src/legacy/ui/public/styles/bootstrap_dark.less b/src/legacy/ui/public/styles/bootstrap_dark.less
deleted file mode 100644
index a0079df56a4e2..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap_dark.less
+++ /dev/null
@@ -1,4 +0,0 @@
-//
-// COMPILER FOR BOOTSTRAP
-
-@import "~ui/styles/bootstrap/bootstrap_dark";
diff --git a/src/legacy/ui/public/styles/bootstrap_light.less b/src/legacy/ui/public/styles/bootstrap_light.less
deleted file mode 100644
index 101be5f3c898f..0000000000000
--- a/src/legacy/ui/public/styles/bootstrap_light.less
+++ /dev/null
@@ -1,5 +0,0 @@
-//
-// COMPILER FOR BOOTSTRAP
-
-@import "~ui/styles/bootstrap/bootstrap_light";
-
diff --git a/src/legacy/ui/ui_bundles/__tests__/app_entry_template.js b/src/legacy/ui/ui_bundles/__tests__/app_entry_template.js
deleted file mode 100644
index 8a9b74df92e76..0000000000000
--- a/src/legacy/ui/ui_bundles/__tests__/app_entry_template.js
+++ /dev/null
@@ -1,45 +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 sinon from 'sinon';
-import expect from '@kbn/expect';
-
-import { appEntryTemplate } from '../app_entry_template';
-
-function createMockBundle() {
-  return {
-    getContext: sinon.stub().returns(''),
-    getRequires: sinon.stub().returns([]),
-  };
-}
-
-describe('ui bundles / appEntryTemplate', () => {
-  it('embeds bundle.getContext() result', () => {
-    const bundle = createMockBundle();
-    bundle.getContext.returns('foo bar baz');
-    expect(appEntryTemplate(bundle)).to.contain('foo bar baz');
-  });
-
-  it('joins requires into list', () => {
-    const bundle = createMockBundle();
-    const requires = ['foo', 'bar', 'baz'];
-    bundle.getRequires.returns(requires);
-    expect(appEntryTemplate(bundle)).to.contain(requires.join('\n  '));
-  });
-});
diff --git a/src/legacy/ui/ui_bundles/__tests__/ui_bundle.js b/src/legacy/ui/ui_bundles/__tests__/ui_bundle.js
deleted file mode 100644
index 96ae6c448256e..0000000000000
--- a/src/legacy/ui/ui_bundles/__tests__/ui_bundle.js
+++ /dev/null
@@ -1,50 +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 expect from '@kbn/expect';
-
-import { UiBundle } from '../ui_bundle';
-
-describe('ui bundles / UiBundle', () => {
-  describe('#getRequires', () => {
-    it('returns modules option as a list of require calls', () => {
-      const bundle = new UiBundle({
-        modules: ['a', 'b', 'c'],
-      });
-
-      expect(bundle.getRequires()).to.eql([`require('a');`, `require('b');`, `require('c');`]);
-    });
-
-    it('does not sort modules', () => {
-      const bundle = new UiBundle({
-        modules: ['c', 'a', 'b'],
-      });
-
-      expect(bundle.getRequires()).to.eql([`require('c');`, `require('a');`, `require('b');`]);
-    });
-
-    it('converts \\ to /', () => {
-      const bundle = new UiBundle({
-        modules: ['a\\b\\c', 'd/e/f'],
-      });
-
-      expect(bundle.getRequires()).to.eql([`require('a/b/c');`, `require('d/e/f');`]);
-    });
-  });
-});
diff --git a/src/legacy/ui/ui_bundles/app_entry_template.js b/src/legacy/ui/ui_bundles/app_entry_template.js
deleted file mode 100644
index a48de9a8cf7ee..0000000000000
--- a/src/legacy/ui/ui_bundles/app_entry_template.js
+++ /dev/null
@@ -1,66 +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 { apmImport, apmInit } from '../apm';
-
-export const appEntryTemplate = (bundle) => `
-/**
- * Kibana entry file
- *
- * This is programmatically created and updated, do not modify
- *
- * Any changes to this file should be kept in sync with
- * src/core/public/entry_point.ts
- *
- * context: ${bundle.getContext()}
- */
-
-${apmImport()}
-import { i18n } from '@kbn/i18n';
-import { CoreSystem } from '__kibanaCore__'
-
-const injectedMetadata = JSON.parse(document.querySelector('kbn-injected-metadata').getAttribute('data'));
-
-${apmInit('injectedMetadata.vars.apmConfig')}
-
-i18n.load(injectedMetadata.i18n.translationsUrl)
-  .catch(e => e)
-  .then((i18nError) => {
-    const coreSystem = new CoreSystem({
-      injectedMetadata,
-      rootDomElement: document.body,
-      browserSupportsCsp: !window.__kbnCspNotEnforced__,
-      requireLegacyFiles: () => {
-        ${bundle.getRequires().join('\n  ')}
-      },
-      requireLegacyBootstrapModule: () => require('ui/chrome'),
-      requireNewPlatformShimModule: () => require('ui/new_platform'),
-    });
-
-    coreSystem
-      .setup()
-      .then((coreSetup) => {
-        if (i18nError) {
-          coreSetup.fatalErrors.add(i18nError);
-        }
-
-        return coreSystem.start();
-      });
-  });
-`;
diff --git a/src/legacy/ui/ui_bundles/ui_bundle.js b/src/legacy/ui/ui_bundles/ui_bundle.js
deleted file mode 100644
index 4e853ad410efe..0000000000000
--- a/src/legacy/ui/ui_bundles/ui_bundle.js
+++ /dev/null
@@ -1,125 +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 { fromNode as fcb } from 'bluebird';
-import { readFile, writeFile, stat } from 'fs';
-
-// We normalize all path separators to `/` in generated files
-function normalizePath(path) {
-  return path.replace(/[\\\/]+/g, '/');
-}
-
-export class UiBundle {
-  constructor(options) {
-    const { id, modules, template, controller, extendConfig } = options;
-
-    this._id = id;
-    this._modules = modules;
-    this._template = template;
-    this._controller = controller;
-    this._extendConfig = extendConfig;
-  }
-
-  getId() {
-    return this._id;
-  }
-
-  getContext() {
-    return this._controller.getContext();
-  }
-
-  getEntryPath() {
-    return this._controller.resolvePath(`${this.getId()}.entry.js`);
-  }
-
-  getStylePath() {
-    return this._controller.resolvePath(`${this.getId()}.style.css`);
-  }
-
-  getOutputPath() {
-    return this._controller.resolvePath(`${this.getId()}.bundle.js`);
-  }
-
-  getRequires() {
-    return this._modules.map((module) => `require('${normalizePath(module)}');`);
-  }
-
-  renderContent() {
-    return this._template(this);
-  }
-
-  async readEntryFile() {
-    try {
-      const content = await fcb((cb) => readFile(this.getEntryPath(), cb));
-      return content.toString('utf8');
-    } catch (e) {
-      return null;
-    }
-  }
-
-  async writeEntryFile() {
-    return await fcb((cb) => writeFile(this.getEntryPath(), this.renderContent(), 'utf8', cb));
-  }
-
-  async touchStyleFile() {
-    return await fcb((cb) => writeFile(this.getStylePath(), '', 'utf8', cb));
-  }
-
-  /**
-   * Determine if the cache for this bundle is valid by
-   * checking that the entry file exists, has the content we
-   * expect based on the argument for this bundle, and that both
-   * the style file and output for this bundle exist. In this
-   * scenario we assume the cache is valid.
-   *
-   * When the `optimize.useBundleCache` config is set to `false`
-   * (the default when running in development) we don't even call
-   * this method and bundles are always recreated.
-   */
-  async isCacheValid() {
-    if ((await this.readEntryFile()) !== this.renderContent()) {
-      return false;
-    }
-
-    try {
-      await fcb((cb) => stat(this.getOutputPath(), cb));
-      await fcb((cb) => stat(this.getStylePath(), cb));
-      return true;
-    } catch (e) {
-      return false;
-    }
-  }
-
-  toJSON() {
-    return {
-      id: this._id,
-      modules: this._modules,
-      entryPath: this.getEntryPath(),
-      outputPath: this.getOutputPath(),
-    };
-  }
-
-  getExtendedConfig(webpackConfig) {
-    if (!this._extendConfig) {
-      return webpackConfig;
-    }
-
-    return this._extendConfig(webpackConfig);
-  }
-}
diff --git a/src/legacy/ui/ui_bundles/ui_bundles_controller.js b/src/legacy/ui/ui_bundles/ui_bundles_controller.js
deleted file mode 100644
index dadb28cbb2f3a..0000000000000
--- a/src/legacy/ui/ui_bundles/ui_bundles_controller.js
+++ /dev/null
@@ -1,255 +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 { resolve, relative, isAbsolute } from 'path';
-import { createHash } from 'crypto';
-import { promisify } from 'util';
-import { existsSync, mkdir } from 'fs';
-
-import del from 'del';
-import { makeRe } from 'minimatch';
-import jsonStableStringify from 'json-stable-stringify';
-
-import { IS_KIBANA_DISTRIBUTABLE } from '../../utils';
-// eslint-disable-next-line @kbn/eslint/no-restricted-paths
-import { fromRoot } from '../../../core/server/utils';
-import { UiBundle } from './ui_bundle';
-import { appEntryTemplate } from './app_entry_template';
-
-const mkdirAsync = promisify(mkdir);
-const REPO_ROOT = fromRoot();
-
-function getWebpackAliases(pluginSpecs) {
-  return pluginSpecs.reduce((aliases, spec) => {
-    const publicDir = spec.getPublicDir();
-
-    if (!publicDir) {
-      return aliases;
-    }
-
-    return {
-      ...aliases,
-      [`plugins/${spec.getId()}`]: publicDir,
-    };
-  }, {});
-}
-
-// Recursively clone appExtensions, sorting array and normalizing absolute paths
-function stableCloneAppExtensions(appExtensions) {
-  return Object.fromEntries(
-    Object.entries(appExtensions).map(([extensionType, moduleIds]) => [
-      extensionType,
-      moduleIds
-        .map((moduleId) => {
-          if (isAbsolute(moduleId)) {
-            moduleId = `absolute:${relative(REPO_ROOT, moduleId)}`;
-          }
-          return moduleId.replace(/\\/g, '/');
-        })
-        .sort((a, b) => a.localeCompare(b)),
-    ])
-  );
-}
-
-export class UiBundlesController {
-  constructor(kbnServer) {
-    const { config, uiApps, uiExports, pluginSpecs } = kbnServer;
-
-    this._workingDir = config.get('optimize.bundleDir');
-    this._env = config.get('env.name');
-    this._validateSyntaxOfNodeModules = config.get('optimize.validateSyntaxOfNodeModules');
-    this._context = {
-      env: config.get('env.name'),
-      sourceMaps: config.get('optimize.sourceMaps'),
-      kbnVersion: config.get('pkg.version'),
-      buildNum: config.get('pkg.buildNum'),
-      appExtensions: stableCloneAppExtensions(uiExports.appExtensions),
-    };
-
-    this._filter = makeRe(config.get('optimize.bundleFilter') || '*', {
-      noglobstar: true,
-      noext: true,
-      matchBase: true,
-    });
-
-    this._appExtensions = uiExports.appExtensions || {};
-
-    this._webpackAliases = {
-      ...getWebpackAliases(pluginSpecs),
-      ...uiExports.webpackAliases,
-    };
-    this._webpackPluginProviders = uiExports.webpackPluginProviders;
-    this._webpackNoParseRules = uiExports.webpackNoParseRules;
-    this._postLoaders = [];
-    this._bundles = [];
-
-    // create a bundle for each uiApp
-    for (const uiApp of uiApps) {
-      this.add({
-        id: uiApp.getId(),
-        modules: [uiApp.getMainModuleId()],
-        template: appEntryTemplate,
-      });
-    }
-  }
-
-  add(bundleSpec) {
-    const { id, modules, template, extendConfig } = bundleSpec;
-
-    if (this._filter.test(id)) {
-      this._bundles.push(
-        new UiBundle({
-          id,
-          modules,
-          template,
-          controller: this,
-          extendConfig,
-        })
-      );
-    }
-  }
-
-  isDevMode() {
-    return this._env === 'development';
-  }
-
-  shouldValidateSyntaxOfNodeModules() {
-    return !!this._validateSyntaxOfNodeModules;
-  }
-
-  getWebpackPluginProviders() {
-    return this._webpackPluginProviders || [];
-  }
-
-  getWebpackNoParseRules() {
-    return this._webpackNoParseRules;
-  }
-
-  getWorkingDir() {
-    return this._workingDir;
-  }
-
-  addPostLoader(loaderSpec) {
-    this._postLoaders.push(loaderSpec);
-  }
-
-  getPostLoaders() {
-    return this._postLoaders;
-  }
-
-  getAliases() {
-    return this._webpackAliases;
-  }
-
-  getAppExtensions() {
-    return this._appExtensions;
-  }
-
-  getContext() {
-    return jsonStableStringify(this._context, {
-      space: '  ',
-    });
-  }
-
-  resolvePath(...args) {
-    return resolve(this._workingDir, ...args);
-  }
-
-  async resetBundleDir() {
-    if (!existsSync(this._workingDir)) {
-      // create a fresh working directory
-      await mkdirAsync(this._workingDir, { recursive: true });
-    } else {
-      // delete all children of the working directory
-      await del(this.resolvePath('*'), {
-        // since we know that `this.resolvePath()` is going to return an absolute path based on the `optimize.bundleDir`
-        // and since we don't want to require that users specify a bundleDir that is within the cwd or limit the cwd
-        // directory used to run Kibana in any way we use force here
-        force: true,
-      });
-    }
-
-    // write the entry/style files for each bundle
-    for (const bundle of this._bundles) {
-      await bundle.writeEntryFile();
-      await bundle.touchStyleFile();
-    }
-  }
-
-  getCacheDirectory(...subPath) {
-    return this.resolvePath(
-      '../../built_assets/.cache/ui_bundles',
-      !IS_KIBANA_DISTRIBUTABLE ? this.hashBundleEntries() : '',
-      ...subPath
-    );
-  }
-
-  getDescription() {
-    const ids = this.getIds();
-    switch (ids.length) {
-      case 0:
-        return '0 bundles';
-      case 1:
-        return `bundle for ${ids[0]}`;
-      default:
-        const last = ids.pop();
-        const commas = ids.join(', ');
-        return `bundles for ${commas} and ${last}`;
-    }
-  }
-
-  hashBundleEntries() {
-    const hash = createHash('sha1');
-
-    for (const bundle of this._bundles) {
-      hash.update(`bundleEntryPath:${bundle.getEntryPath()}`);
-      hash.update(`bundleEntryContent:${bundle.renderContent()}`);
-    }
-
-    return hash.digest('hex');
-  }
-
-  async areAllBundleCachesValid() {
-    for (const bundle of this._bundles) {
-      if (!(await bundle.isCacheValid())) {
-        return false;
-      }
-    }
-
-    return true;
-  }
-
-  toWebpackEntries() {
-    return this._bundles.reduce(
-      (entries, bundle) => ({
-        ...entries,
-        [bundle.getId()]: bundle.getEntryPath(),
-      }),
-      {}
-    );
-  }
-
-  getIds() {
-    return this._bundles.map((bundle) => bundle.getId());
-  }
-
-  getExtendedConfig(webpackConfig) {
-    return this._bundles.reduce((acc, bundle) => bundle.getExtendedConfig(acc), webpackConfig);
-  }
-}
diff --git a/src/legacy/ui/ui_bundles/ui_bundles_mixin.js b/src/legacy/ui/ui_bundles/ui_bundles_mixin.js
deleted file mode 100644
index 6127cb9ecd143..0000000000000
--- a/src/legacy/ui/ui_bundles/ui_bundles_mixin.js
+++ /dev/null
@@ -1,29 +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 { UiBundlesController } from './ui_bundles_controller';
-
-export async function uiBundlesMixin(kbnServer) {
-  kbnServer.uiBundles = new UiBundlesController(kbnServer);
-
-  const { uiBundleProviders = [] } = kbnServer.uiExports;
-  for (const spec of uiBundleProviders) {
-    await spec(kbnServer);
-  }
-}
diff --git a/src/legacy/ui/ui_exports/__tests__/collect_ui_exports.js b/src/legacy/ui/ui_exports/__tests__/collect_ui_exports.js
index 3686a2dad8f24..5b2af9f82333c 100644
--- a/src/legacy/ui/ui_exports/__tests__/collect_ui_exports.js
+++ b/src/legacy/ui/ui_exports/__tests__/collect_ui_exports.js
@@ -34,7 +34,6 @@ const specs = new PluginPack({
       new Plugin({
         id: 'test',
         uiExports: {
-          visTypes: ['plugin/test/visType1', 'plugin/test/visType2', 'plugin/test/visType3'],
           savedObjectSchemas: {
             foo: {
               isNamespaceAgnostic: true,
@@ -45,7 +44,6 @@ const specs = new PluginPack({
       new Plugin({
         id: 'test2',
         uiExports: {
-          visTypes: ['plugin/test2/visType1', 'plugin/test2/visType2', 'plugin/test2/visType3'],
           savedObjectSchemas: {
             bar: {
               isNamespaceAgnostic: true,
@@ -61,16 +59,6 @@ describe('plugin discovery', () => {
   describe('collectUiExports()', () => {
     it('merges uiExports from all provided plugin specs', () => {
       const uiExports = collectUiExports(specs);
-      const exported = uiExports.appExtensions.visTypes.sort((a, b) => a.localeCompare(b));
-
-      expect(exported).to.eql([
-        'plugin/test/visType1',
-        'plugin/test/visType2',
-        'plugin/test/visType3',
-        'plugin/test2/visType1',
-        'plugin/test2/visType2',
-        'plugin/test2/visType3',
-      ]);
 
       expect(uiExports.savedObjectSchemas).to.eql({
         foo: {
diff --git a/src/legacy/ui/ui_exports/ui_export_defaults.js b/src/legacy/ui/ui_exports/ui_export_defaults.js
index 348f4ee77fab4..227954155ce88 100644
--- a/src/legacy/ui/ui_exports/ui_export_defaults.js
+++ b/src/legacy/ui/ui_exports/ui_export_defaults.js
@@ -17,30 +17,4 @@
  * under the License.
  */
 
-import { dirname, resolve } from 'path';
-const ROOT = dirname(require.resolve('../../../../package.json'));
-
-export const UI_EXPORT_DEFAULTS = {
-  webpackNoParseRules: [
-    /node_modules[\/\\](angular|elasticsearch-browser)[\/\\]/,
-    /node_modules[\/\\](mocha|moment)[\/\\]/,
-    /node_modules[\/\\]vega[\/\\]build[\/\\]vega\.js$/,
-  ],
-
-  webpackAliases: {
-    ui: resolve(ROOT, 'src/legacy/ui/public'),
-    __kibanaCore__$: resolve(ROOT, 'src/core/public'),
-  },
-
-  styleSheetPaths: ['light', 'dark'].map((theme) => ({
-    theme,
-    localPath: resolve(ROOT, 'src/core/public/index.scss'),
-    publicPath: `core.${theme}.css`,
-    urlImports: {
-      urlBase: 'built_assets/css/',
-      publicDir: resolve(ROOT, 'src/core/public'),
-    },
-  })),
-
-  appExtensions: {},
-};
+export const UI_EXPORT_DEFAULTS = {};
diff --git a/src/legacy/ui/ui_exports/ui_export_types/index.js b/src/legacy/ui/ui_exports/ui_export_types/index.js
index 03b8301fcfab2..9ff6a53f4afb9 100644
--- a/src/legacy/ui/ui_exports/ui_export_types/index.js
+++ b/src/legacy/ui/ui_exports/ui_export_types/index.js
@@ -29,46 +29,8 @@ export {
 
 export { taskDefinitions } from './task_definitions';
 
-export { app, apps } from './ui_apps';
-
-export {
-  visTypes,
-  visEditorTypes,
-  interpreter,
-  savedObjectTypes,
-  embeddableActions,
-  embeddableFactories,
-  fieldFormats,
-  fieldFormatEditors,
-  inspectorViews,
-  chromeNavControls,
-  navbarExtensions,
-  contextMenuActions,
-  managementSections,
-  indexManagement,
-  devTools,
-  docViews,
-  hacks,
-  home,
-  canvas,
-  visTypeEnhancers,
-  aliases,
-  visualize,
-  search,
-  shareContextMenuExtensions,
-} from './ui_app_extensions';
-
 export { link, links } from './ui_nav_links';
 
-export { styleSheetPaths } from './style_sheet_paths';
-
 export { uiSettingDefaults } from './ui_settings';
 
 export { unknown } from './unknown';
-
-export {
-  noParse,
-  __globalImportAliases__,
-  __bundleProvider__,
-  __webpackPluginProvider__,
-} from './webpack_customizations';
diff --git a/src/legacy/ui/ui_exports/ui_export_types/style_sheet_paths.js b/src/legacy/ui/ui_exports/ui_export_types/style_sheet_paths.js
deleted file mode 100644
index 405a1310d29c5..0000000000000
--- a/src/legacy/ui/ui_exports/ui_export_types/style_sheet_paths.js
+++ /dev/null
@@ -1,97 +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 { existsSync } from 'fs';
-import { flatConcatAtType } from './reduce';
-import { mapSpec, wrap } from './modify_reduce';
-
-const OK_EXTNAMES = ['.css', '.scss'];
-
-function getUrlBase(pluginSpec) {
-  return `plugins/${pluginSpec.getId()}`;
-}
-
-function getPublicPath(pluginSpec, localPath) {
-  // get the path of the stylesheet relative to the public dir for the plugin
-  let relativePath = path.relative(pluginSpec.getPublicDir(), localPath);
-
-  // replace back slashes on windows
-  relativePath = relativePath.split('\\').join('/');
-
-  return `${getUrlBase(pluginSpec)}/${relativePath}`;
-}
-
-function getStyleSheetPath(pluginSpec, localPath, theme) {
-  const extname = path.extname(localPath);
-  const localCssPath = localPath.slice(0, -extname.length) + `.${theme}.css`;
-
-  return {
-    theme,
-    localPath: existsSync(localCssPath) ? localCssPath : localPath,
-    publicPath: getPublicPath(pluginSpec, localCssPath),
-    urlImports: {
-      urlBase: `built_assets/css/${getUrlBase(pluginSpec)}`,
-      publicDir: pluginSpec.getPublicDir(),
-    },
-  };
-}
-
-function normalize(localPath, type, pluginSpec) {
-  const pluginId = pluginSpec.getId();
-  const publicDir = path.normalize(pluginSpec.getPublicDir());
-  const extname = path.extname(localPath);
-
-  if (!OK_EXTNAMES.includes(extname)) {
-    throw new Error(
-      `[plugin:${pluginId}] uiExports.styleSheetPaths supported extensions [${OK_EXTNAMES.join(
-        ', '
-      )}], got "${extname}"`
-    );
-  }
-
-  if (!path.isAbsolute(localPath)) {
-    throw new Error(
-      `[plugin:${pluginId}] uiExports.styleSheetPaths must be an absolute path, got "${localPath}"`
-    );
-  }
-
-  if (!path.normalize(localPath).startsWith(publicDir)) {
-    throw new Error(
-      `[plugin:${pluginId}] uiExports.styleSheetPaths must be child of publicDir [${publicDir}]`
-    );
-  }
-
-  if (extname === '.css') {
-    // when the localPath points to a css file, assume it will be included in every theme
-    // and don't create ligkt/dark variations of it
-    return {
-      theme: '*',
-      localPath: localPath,
-      publicPath: getPublicPath(pluginSpec, localPath),
-    };
-  }
-
-  return [
-    getStyleSheetPath(pluginSpec, localPath, 'light'),
-    getStyleSheetPath(pluginSpec, localPath, 'dark'),
-  ];
-}
-
-export const styleSheetPaths = wrap(mapSpec(normalize), flatConcatAtType);
diff --git a/src/legacy/ui/ui_exports/ui_export_types/style_sheet_paths.test.js b/src/legacy/ui/ui_exports/ui_export_types/style_sheet_paths.test.js
deleted file mode 100644
index 6a1fa7bdf3633..0000000000000
--- a/src/legacy/ui/ui_exports/ui_export_types/style_sheet_paths.test.js
+++ /dev/null
@@ -1,139 +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 { resolve } from 'path';
-import { tmpdir } from 'os';
-import { styleSheetPaths } from './style_sheet_paths';
-
-const dir = tmpdir();
-const pluginSpec = {
-  getId: jest.fn(() => 'test'),
-  getPublicDir: jest.fn(() => resolve(dir, 'kibana/public')),
-};
-
-expect.addSnapshotSerializer({
-  test: (value) => typeof value === 'string' && value.startsWith(dir),
-  print: (value) => value.replace(dir, '').replace(/\\/g, '/'),
-});
-
-describe('uiExports.styleSheetPaths', () => {
-  it('does not support relative paths', () => {
-    expect(() => styleSheetPaths([], 'public/bar.css', 'styleSheetPaths', pluginSpec)).toThrowError(
-      /\[plugin:test\] uiExports.styleSheetPaths must be an absolute path/
-    );
-  });
-
-  it('path must be child of public path', () => {
-    expect(() =>
-      styleSheetPaths([], '/another/public/bar.css', 'styleSheetPaths', pluginSpec)
-    ).toThrowError(/\[plugin:test\] uiExports.styleSheetPaths must be child of publicDir/);
-  });
-
-  it('only supports css or scss extensions', () => {
-    expect(() =>
-      styleSheetPaths([], '/kibana/public/bar.bad', 'styleSheetPaths', pluginSpec)
-    ).toThrowError(
-      '[plugin:test] uiExports.styleSheetPaths supported extensions [.css, .scss], got ".bad"'
-    );
-  });
-
-  it('provides publicPath for scss extensions', () => {
-    const localPath = resolve(dir, 'kibana/public/bar.scss');
-    const uiExports = styleSheetPaths([], localPath, 'styleSheetPaths', pluginSpec);
-
-    expect(uiExports.styleSheetPaths).toMatchInlineSnapshot(`
-Array [
-  Object {
-    "localPath": /kibana/public/bar.scss,
-    "publicPath": "plugins/test/bar.light.css",
-    "theme": "light",
-    "urlImports": Object {
-      "publicDir": /kibana/public,
-      "urlBase": "built_assets/css/plugins/test",
-    },
-  },
-  Object {
-    "localPath": /kibana/public/bar.scss,
-    "publicPath": "plugins/test/bar.dark.css",
-    "theme": "dark",
-    "urlImports": Object {
-      "publicDir": /kibana/public,
-      "urlBase": "built_assets/css/plugins/test",
-    },
-  },
-]
-`);
-  });
-
-  it('provides publicPath for css extensions', () => {
-    const localPath = resolve(dir, 'kibana/public/bar.scss');
-    const uiExports = styleSheetPaths([], localPath, 'styleSheetPaths', pluginSpec);
-
-    expect(uiExports.styleSheetPaths).toMatchInlineSnapshot(`
-Array [
-  Object {
-    "localPath": /kibana/public/bar.scss,
-    "publicPath": "plugins/test/bar.light.css",
-    "theme": "light",
-    "urlImports": Object {
-      "publicDir": /kibana/public,
-      "urlBase": "built_assets/css/plugins/test",
-    },
-  },
-  Object {
-    "localPath": /kibana/public/bar.scss,
-    "publicPath": "plugins/test/bar.dark.css",
-    "theme": "dark",
-    "urlImports": Object {
-      "publicDir": /kibana/public,
-      "urlBase": "built_assets/css/plugins/test",
-    },
-  },
-]
-`);
-  });
-
-  it('should normalize mixed slashes', () => {
-    const localPath = resolve(dir, 'kibana/public\\bar.scss');
-    const uiExports = styleSheetPaths([], localPath, 'styleSheetPaths', pluginSpec);
-
-    expect(uiExports.styleSheetPaths).toMatchInlineSnapshot(`
-Array [
-  Object {
-    "localPath": /kibana/public/bar.scss,
-    "publicPath": "plugins/test/../public/bar.light.css",
-    "theme": "light",
-    "urlImports": Object {
-      "publicDir": /kibana/public,
-      "urlBase": "built_assets/css/plugins/test",
-    },
-  },
-  Object {
-    "localPath": /kibana/public/bar.scss,
-    "publicPath": "plugins/test/../public/bar.dark.css",
-    "theme": "dark",
-    "urlImports": Object {
-      "publicDir": /kibana/public,
-      "urlBase": "built_assets/css/plugins/test",
-    },
-  },
-]
-`);
-  });
-});
diff --git a/src/legacy/ui/ui_exports/ui_export_types/ui_app_extensions.js b/src/legacy/ui/ui_exports/ui_export_types/ui_app_extensions.js
deleted file mode 100644
index fe5695d5b3410..0000000000000
--- a/src/legacy/ui/ui_exports/ui_export_types/ui_app_extensions.js
+++ /dev/null
@@ -1,66 +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 { flatConcatValuesAtType } from './reduce';
-import { mapSpec, alias, wrap } from './modify_reduce';
-
-/**
- *  Reducer "preset" that merges named "first-class" appExtensions by
- *  converting them into objects and then concatenating the values of those objects
- *  @type {Function}
- */
-const appExtension = wrap(
-  mapSpec((spec, type) => ({ [type]: spec })),
-  alias('appExtensions'),
-  flatConcatValuesAtType
-);
-
-// plain extension groups produce lists of modules that will be required by the entry
-// files to include extensions of specific types into specific apps
-export const visTypes = appExtension;
-
-export const visEditorTypes = appExtension;
-export const savedObjectTypes = appExtension;
-export const embeddableActions = appExtension;
-export const embeddableFactories = appExtension;
-export const contextMenuActions = appExtension;
-export const fieldFormats = appExtension;
-export const fieldFormatEditors = appExtension;
-export const chromeNavControls = appExtension;
-export const navbarExtensions = appExtension;
-export const managementSections = appExtension;
-export const indexManagement = appExtension;
-export const devTools = appExtension;
-export const docViews = appExtension;
-export const hacks = appExtension;
-export const home = appExtension;
-export const canvas = appExtension;
-export const inspectorViews = appExtension;
-export const search = appExtension;
-export const shareContextMenuExtensions = appExtension;
-// Add a visualize app extension that should be used for visualize specific stuff
-export const visualize = appExtension;
-export const interpreter = appExtension;
-
-// aliases visTypeEnhancers to the visTypes group
-export const visTypeEnhancers = wrap(alias('visTypes'), appExtension);
-
-// adhoc extension groups can define new extension groups on the fly
-// so that plugins could concat their own
-export const aliases = flatConcatValuesAtType;
diff --git a/src/legacy/ui/ui_exports/ui_export_types/ui_apps.js b/src/legacy/ui/ui_exports/ui_export_types/ui_apps.js
deleted file mode 100644
index 639a5a7c58e18..0000000000000
--- a/src/legacy/ui/ui_exports/ui_export_types/ui_apps.js
+++ /dev/null
@@ -1,70 +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 { flatConcatAtType } from './reduce';
-import { alias, mapSpec, wrap } from './modify_reduce';
-
-function applySpecDefaults(spec, type, pluginSpec) {
-  const pluginId = pluginSpec.getId();
-  const {
-    id = pluginId,
-    main,
-    title,
-    order = 0,
-    description = '',
-    icon,
-    euiIconType,
-    hidden = false,
-    linkToLastSubUrl = true,
-    listed = !hidden,
-    url = `/app/${id}`,
-    category,
-  } = spec;
-
-  if (spec.injectVars) {
-    throw new Error(
-      `[plugin:${pluginId}] uiExports.app.injectVars has been removed. Use server.injectUiAppVars('${id}', () => { ... })`
-    );
-  }
-
-  if (spec.uses) {
-    throw new Error(
-      `[plugin:${pluginId}] uiExports.app.uses has been removed. Import these uiExport types with "import 'uiExports/{type}'"`
-    );
-  }
-
-  return {
-    pluginId,
-    id,
-    main,
-    title,
-    order,
-    description,
-    icon,
-    euiIconType,
-    hidden,
-    linkToLastSubUrl,
-    listed,
-    url,
-    category,
-  };
-}
-
-export const apps = wrap(alias('uiAppSpecs'), mapSpec(applySpecDefaults), flatConcatAtType);
-export const app = wrap(alias('uiAppSpecs'), mapSpec(applySpecDefaults), flatConcatAtType);
diff --git a/src/legacy/ui/ui_exports/ui_export_types/webpack_customizations.js b/src/legacy/ui/ui_exports/ui_export_types/webpack_customizations.js
deleted file mode 100644
index 3f3ff8b97999c..0000000000000
--- a/src/legacy/ui/ui_exports/ui_export_types/webpack_customizations.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { isAbsolute } from 'path';
-
-import { escapeRegExp } from 'lodash';
-
-import { flatConcatAtType, mergeAtType } from './reduce';
-import { alias, wrap, uniqueKeys, mapSpec } from './modify_reduce';
-
-export const __globalImportAliases__ = wrap(
-  alias('webpackAliases'),
-  uniqueKeys('__globalImportAliases__'),
-  mergeAtType
-);
-export const __bundleProvider__ = wrap(alias('uiBundleProviders'), flatConcatAtType);
-export const __webpackPluginProvider__ = wrap(alias('webpackPluginProviders'), flatConcatAtType);
-export const noParse = wrap(
-  alias('webpackNoParseRules'),
-  mapSpec((rule) => {
-    if (typeof rule === 'string') {
-      return new RegExp(`${isAbsolute(rule) ? '^' : ''}${escapeRegExp(rule)}`);
-    }
-
-    if (rule instanceof RegExp) {
-      return rule;
-    }
-
-    throw new Error('Expected noParse rule to be a string or regexp');
-  }),
-  flatConcatAtType
-);
diff --git a/src/legacy/ui/ui_mixin.js b/src/legacy/ui/ui_mixin.js
index 831c2c5deb829..432c4f02bc3e6 100644
--- a/src/legacy/ui/ui_mixin.js
+++ b/src/legacy/ui/ui_mixin.js
@@ -18,13 +18,11 @@
  */
 
 import { uiAppsMixin } from './ui_apps';
-import { uiBundlesMixin } from './ui_bundles';
 import { uiRenderMixin } from './ui_render';
 import { uiSettingsMixin } from './ui_settings';
 
 export async function uiMixin(kbnServer) {
   await kbnServer.mixin(uiAppsMixin);
-  await kbnServer.mixin(uiBundlesMixin);
   await kbnServer.mixin(uiSettingsMixin);
   await kbnServer.mixin(uiRenderMixin);
 }
diff --git a/src/legacy/ui/ui_render/bootstrap/template.js.hbs b/src/legacy/ui/ui_render/bootstrap/template.js.hbs
index bbca051ce31a1..89c7125b39e36 100644
--- a/src/legacy/ui/ui_render/bootstrap/template.js.hbs
+++ b/src/legacy/ui/ui_render/bootstrap/template.js.hbs
@@ -77,14 +77,9 @@ if (window.__kbnStrictCsp__ && window.__kbnCspNotEnforced__) {
         '{{this}}',
       {{/each}}
     ], function () {
-      {{#unless legacyBundlePath}}
-        __kbnBundles__.get('entry/core/public').__kbnBootstrap__();
-      {{/unless}}
+      __kbnBundles__.get('entry/core/public').__kbnBootstrap__();
 
       load([
-        {{#if legacyBundlePath}}
-          '{{legacyBundlePath}}',
-        {{/if}}
         {{#each styleSheetPaths}}
           '{{this}}',
         {{/each}}
diff --git a/src/legacy/ui/ui_render/ui_render_mixin.js b/src/legacy/ui/ui_render/ui_render_mixin.js
index 12ae6390fdc22..23fb6028f84db 100644
--- a/src/legacy/ui/ui_render/ui_render_mixin.js
+++ b/src/legacy/ui/ui_render/ui_render_mixin.js
@@ -19,7 +19,6 @@
 
 import { createHash } from 'crypto';
 import Boom from 'boom';
-import Path from 'path';
 import { i18n } from '@kbn/i18n';
 import * as UiSharedDeps from '@kbn/ui-shared-deps';
 import { AppBootstrap } from './bootstrap';
@@ -37,9 +36,6 @@ import { getApmConfig } from '../apm';
  * @param {KbnServer['config']} config
  */
 export function uiRenderMixin(kbnServer, server, config) {
-  // render all views from ./views
-  server.setupViews(Path.resolve(__dirname, 'views'));
-
   const translationsCache = { translations: null, hash: null };
   server.route({
     path: '/translations/{locale}.json',
@@ -76,17 +72,13 @@ export function uiRenderMixin(kbnServer, server, config) {
     const authEnabled = !!server.auth.settings.default;
 
     server.route({
-      path: '/bundles/app/{id}/bootstrap.js',
+      path: '/bootstrap.js',
       method: 'GET',
       config: {
         tags: ['api'],
         auth: authEnabled ? { mode: 'try' } : false,
       },
       async handler(request, h) {
-        const { id } = request.params;
-        const app = server.getUiAppById(id) || server.getHiddenUiAppById(id);
-        const isCore = !app;
-
         const uiSettings = request.getUiSettingsService();
 
         const darkMode =
@@ -114,29 +106,14 @@ export function uiRenderMixin(kbnServer, server, config) {
                   ? `${regularBundlePath}/kbn-ui-shared-deps/${UiSharedDeps.darkCssDistFilename}`
                   : `${regularBundlePath}/kbn-ui-shared-deps/${UiSharedDeps.darkV8CssDistFilename}`,
                 `${basePath}/node_modules/@kbn/ui-framework/dist/kui_dark.css`,
-                `${regularBundlePath}/dark_theme.style.css`,
+                `${basePath}/ui/legacy_dark_theme.css`,
               ]
             : [
                 themeVersion === 'v7'
                   ? `${regularBundlePath}/kbn-ui-shared-deps/${UiSharedDeps.lightCssDistFilename}`
                   : `${regularBundlePath}/kbn-ui-shared-deps/${UiSharedDeps.lightV8CssDistFilename}`,
                 `${basePath}/node_modules/@kbn/ui-framework/dist/kui_light.css`,
-                `${regularBundlePath}/light_theme.style.css`,
-              ]),
-          ...(isCore
-            ? []
-            : [
-                `${regularBundlePath}/${app.getId()}.style.css`,
-                ...kbnServer.uiExports.styleSheetPaths
-                  .filter(
-                    (path) => path.theme === '*' || path.theme === (darkMode ? 'dark' : 'light')
-                  )
-                  .map((path) =>
-                    path.localPath.endsWith('.scss')
-                      ? `${basePath}/${buildHash}/built_assets/css/${path.publicPath}`
-                      : `${basePath}/${path.publicPath}`
-                  )
-                  .reverse(),
+                `${basePath}/ui/legacy_light_theme.css`,
               ]),
         ];
 
@@ -182,7 +159,6 @@ export function uiRenderMixin(kbnServer, server, config) {
             jsDependencyPaths,
             styleSheetPaths,
             publicPathMap,
-            legacyBundlePath: isCore ? undefined : `${regularBundlePath}/${app.getId()}.bundle.js`,
           },
         });
 
diff --git a/src/optimize/base_optimizer.js b/src/optimize/base_optimizer.js
deleted file mode 100644
index 74973887ae9c1..0000000000000
--- a/src/optimize/base_optimizer.js
+++ /dev/null
@@ -1,520 +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 { writeFile } from 'fs';
-import os from 'os';
-
-import Boom from 'boom';
-import MiniCssExtractPlugin from 'mini-css-extract-plugin';
-import TerserPlugin from 'terser-webpack-plugin';
-import webpack from 'webpack';
-import Stats from 'webpack/lib/Stats';
-import * as threadLoader from 'thread-loader';
-import webpackMerge from 'webpack-merge';
-import WrapperPlugin from 'wrapper-webpack-plugin';
-import * as UiSharedDeps from '@kbn/ui-shared-deps';
-
-import { IS_KIBANA_DISTRIBUTABLE } from '../legacy/utils';
-import { fromRoot } from '../core/server/utils';
-import { PUBLIC_PATH_PLACEHOLDER } from './public_path_placeholder';
-
-const POSTCSS_CONFIG_PATH = require.resolve('./postcss.config.js');
-const BABEL_PRESET_PATH = require.resolve('@kbn/babel-preset/webpack_preset');
-const ISTANBUL_PRESET_PATH = require.resolve('@kbn/babel-preset/istanbul_preset');
-const EMPTY_MODULE_PATH = require.resolve('./intentionally_empty_module.js');
-const BABEL_EXCLUDE_RE = [/[\/\\](webpackShims|node_modules|bower_components)[\/\\]/];
-const STATS_WARNINGS_FILTER = new RegExp(
-  [
-    '(export .* was not found in)',
-    '|(chunk .* \\[mini-css-extract-plugin\\]\\\nConflicting order between:)',
-  ].join('')
-);
-const IS_CODE_COVERAGE = !!process.env.CODE_COVERAGE;
-
-const LEGACY_PRESETS = {
-  plugins: [require.resolve('@babel/plugin-transform-modules-commonjs')],
-};
-
-function recursiveIssuer(m) {
-  if (m.issuer) {
-    return recursiveIssuer(m.issuer);
-  } else if (m.name) {
-    return m.name;
-  } else {
-    return false;
-  }
-}
-
-export default class BaseOptimizer {
-  constructor(opts) {
-    this.logWithMetadata = opts.logWithMetadata || (() => null);
-    this.uiBundles = opts.uiBundles;
-    this.profile = opts.profile || false;
-    this.workers = opts.workers;
-
-    switch (opts.sourceMaps) {
-      case true:
-        this.sourceMaps = 'source-map';
-        break;
-
-      case 'fast':
-        this.sourceMaps = 'cheap-module-eval-source-map';
-        break;
-
-      default:
-        this.sourceMaps = opts.sourceMaps || false;
-        break;
-    }
-
-    // Run some pre loading in order to prevent
-    // high delay when booting thread loader workers
-    this.warmupThreadLoaderPool();
-  }
-
-  async init() {
-    if (this.compiler) {
-      return this;
-    }
-
-    const compilerConfig = this.getConfig();
-    this.compiler = webpack(compilerConfig);
-
-    // register the webpack compiler hooks
-    // for the base optimizer
-    this.registerCompilerHooks();
-
-    return this;
-  }
-
-  registerCompilerHooks() {
-    this.registerCompilerDoneHook();
-  }
-
-  registerCompilerDoneHook() {
-    this.compiler.hooks.done.tap('base_optimizer-done', (stats) => {
-      // We are not done while we have an additional
-      // compilation pass to run
-      // We also don't need to emit the stats if we don't have
-      // the profile option set
-      if (!this.profile || stats.compilation.needAdditionalPass) {
-        return;
-      }
-
-      const path = this.uiBundles.resolvePath('stats.json');
-      const content = JSON.stringify(stats.toJson());
-      writeFile(path, content, function (err) {
-        if (err) throw err;
-      });
-    });
-  }
-
-  warmupThreadLoaderPool() {
-    const baseModules = ['babel-loader', BABEL_PRESET_PATH, LEGACY_PRESETS];
-
-    threadLoader.warmup(
-      // pool options, like passed to loader options
-      // must match loader options to boot the correct pool
-      this.getThreadLoaderPoolConfig(),
-      [
-        // modules to load on the pool
-        ...baseModules,
-      ]
-    );
-  }
-
-  getThreadPoolCpuCount() {
-    if (this.workers) {
-      return this.workers;
-    }
-
-    const cpus = os.cpus();
-    if (!cpus) {
-      // sometimes this call returns undefined so we fall back to 1: https://github.com/nodejs/node/issues/19022
-      return 1;
-    }
-
-    return Math.max(1, Math.min(cpus.length - 1, 3));
-  }
-
-  getThreadLoaderPoolConfig() {
-    // Calculate the node options from the NODE_OPTIONS env var
-    const parsedNodeOptions = process.env.NODE_OPTIONS ? process.env.NODE_OPTIONS.split(/\s/) : [];
-
-    return {
-      name: 'optimizer-thread-loader-main-pool',
-      workers: this.getThreadPoolCpuCount(),
-      workerParallelJobs: 20,
-      // This is a safe check in order to set
-      // the parent node options applied from
-      // the NODE_OPTIONS env var for every launched worker.
-      // Otherwise, if the user sets max_old_space_size, as they
-      // are used to, into NODE_OPTIONS, it won't affect the workers.
-      workerNodeArgs: parsedNodeOptions,
-      poolParallelJobs: this.getThreadPoolCpuCount() * 20,
-      poolTimeout: this.uiBundles.isDevMode() ? Infinity : 2000,
-    };
-  }
-
-  getConfig() {
-    function getStyleLoaderExtractor() {
-      return [MiniCssExtractPlugin.loader];
-    }
-
-    function getStyleLoaders(preProcessors = [], postProcessors = []) {
-      return [
-        ...postProcessors,
-        {
-          loader: 'css-loader',
-          options: {
-            // importLoaders needs to know the number of loaders that follow this one,
-            // so we add 1 (for the postcss-loader) to the length of the preProcessors
-            // array that we merge into this array
-            importLoaders: 1 + preProcessors.length,
-          },
-        },
-        {
-          loader: 'postcss-loader',
-          options: {
-            config: {
-              path: POSTCSS_CONFIG_PATH,
-            },
-          },
-        },
-        ...preProcessors,
-      ];
-    }
-
-    /**
-     * Adds a cache loader if we're running in dev mode. The reason we're not adding
-     * the cache-loader when running in production mode is that it creates cache
-     * files in data/optimize/.cache that are not necessary for distributable versions
-     * of Kibana and just make compressing and extracting it more difficult.
-     */
-    const maybeAddCacheLoader = (cacheName, loaders) => {
-      return [
-        {
-          loader: 'cache-loader',
-          options: {
-            cacheContext: fromRoot('.'),
-            cacheDirectory: this.uiBundles.getCacheDirectory(cacheName),
-            readOnly: process.env.KBN_CACHE_LOADER_WRITABLE ? false : IS_KIBANA_DISTRIBUTABLE,
-          },
-        },
-        ...loaders,
-      ];
-    };
-
-    /**
-     * Creates the selection rules for a loader that will only pass for
-     * source files that are eligible for automatic transpilation.
-     */
-    const createSourceFileResourceSelector = (test) => {
-      return [
-        {
-          test,
-          exclude: BABEL_EXCLUDE_RE.concat(this.uiBundles.getWebpackNoParseRules()),
-        },
-        {
-          test,
-          include: /[\/\\]node_modules[\/\\]x-pack[\/\\]/,
-          exclude: /[\/\\]node_modules[\/\\]x-pack[\/\\](.+?[\/\\])*node_modules[\/\\]/,
-        },
-      ];
-    };
-
-    const commonConfig = {
-      mode: 'development',
-      node: { fs: 'empty' },
-      context: fromRoot('.'),
-      cache: true,
-      entry: {
-        ...this.uiBundles.toWebpackEntries(),
-        light_theme: [require.resolve('../legacy/ui/public/styles/bootstrap_light.less')],
-        dark_theme: [require.resolve('../legacy/ui/public/styles/bootstrap_dark.less')],
-      },
-
-      devtool: this.sourceMaps,
-      profile: this.profile || false,
-
-      output: {
-        futureEmitAssets: true, // TODO: remove on webpack 5
-        path: this.uiBundles.getWorkingDir(),
-        filename: '[name].bundle.js',
-        sourceMapFilename: '[file].map',
-        publicPath: PUBLIC_PATH_PLACEHOLDER,
-        devtoolModuleFilenameTemplate: '[absolute-resource-path]',
-      },
-
-      optimization: {
-        splitChunks: {
-          cacheGroups: {
-            light_theme: {
-              name: 'light_theme',
-              test: (m) =>
-                m.constructor.name === 'CssModule' && recursiveIssuer(m) === 'light_theme',
-              chunks: 'all',
-              enforce: true,
-            },
-            dark_theme: {
-              name: 'dark_theme',
-              test: (m) =>
-                m.constructor.name === 'CssModule' && recursiveIssuer(m) === 'dark_theme',
-              chunks: 'all',
-              enforce: true,
-            },
-          },
-        },
-        noEmitOnErrors: true,
-      },
-
-      plugins: [
-        new MiniCssExtractPlugin({
-          filename: '[name].style.css',
-        }),
-
-        // ignore scss imports in new-platform code that finds its way into legacy bundles
-        new webpack.NormalModuleReplacementPlugin(/\.scss$/, (resource) => {
-          resource.request = EMPTY_MODULE_PATH;
-        }),
-
-        // replace imports for `uiExports/*` modules with a synthetic module
-        // created by create_ui_exports_module.js
-        new webpack.NormalModuleReplacementPlugin(/^uiExports\//, (resource) => {
-          // the map of uiExport types to module ids
-          const extensions = this.uiBundles.getAppExtensions();
-
-          // everything following the first / in the request is
-          // treated as a type of appExtension
-          const type = resource.request.slice(resource.request.indexOf('/') + 1);
-
-          resource.request = [
-            // the "val-loader" is used to execute create_ui_exports_module
-            // and use its return value as the source for the module in the
-            // bundle. This allows us to bypass writing to the file system
-            require.resolve('val-loader'),
-            '!',
-            require.resolve('./create_ui_exports_module'),
-            '?',
-            // this JSON is parsed by create_ui_exports_module and determines
-            // what require() calls it will execute within the bundle
-            JSON.stringify({ type, modules: extensions[type] || [] }),
-          ].join('');
-        }),
-
-        ...this.uiBundles.getWebpackPluginProviders().map((provider) => provider(webpack)),
-      ],
-
-      module: {
-        rules: [
-          {
-            test: /\.less$/,
-            use: [
-              ...getStyleLoaderExtractor(),
-              ...getStyleLoaders(['less-loader'], maybeAddCacheLoader('less', [])),
-            ],
-          },
-          {
-            test: /\.css$/,
-            use: [
-              ...getStyleLoaderExtractor(),
-              ...getStyleLoaders([], maybeAddCacheLoader('css', [])),
-            ],
-          },
-          {
-            test: /\.(html|tmpl)$/,
-            loader: 'raw-loader',
-          },
-          {
-            test: /\.(woff|woff2|ttf|eot|svg|ico|png|jpg|gif|jpeg)(\?|$)/,
-            loader: 'url-loader',
-            options: {
-              limit: 8192,
-            },
-          },
-          {
-            resource: createSourceFileResourceSelector(/\.(js|tsx?)$/),
-            use: maybeAddCacheLoader('babel', [
-              {
-                loader: 'thread-loader',
-                options: this.getThreadLoaderPoolConfig(),
-              },
-              {
-                loader: 'babel-loader',
-                options: {
-                  babelrc: false,
-                  presets: this.getPresets(),
-                },
-              },
-            ]),
-          },
-          ...this.uiBundles.getPostLoaders().map((loader) => ({
-            enforce: 'post',
-            ...loader,
-          })),
-        ],
-        noParse: this.uiBundles.getWebpackNoParseRules(),
-      },
-
-      resolve: {
-        extensions: ['.js', '.ts', '.tsx', '.json'],
-        mainFields: ['browser', 'browserify', 'main'],
-        modules: [
-          'webpackShims',
-          fromRoot('webpackShims'),
-
-          'node_modules',
-          fromRoot('node_modules'),
-        ],
-        alias: {
-          ...this.uiBundles.getAliases(),
-          tinymath: require.resolve('tinymath/lib/tinymath.es5.js'),
-        },
-      },
-
-      performance: {
-        // NOTE: we are disabling this as those hints
-        // are more tailored for the final bundles result
-        // and not for the webpack compilations performance itself
-        hints: false,
-      },
-
-      externals: {
-        ...UiSharedDeps.externals,
-      },
-    };
-
-    // when running from the distributable define an environment variable we can use
-    // to exclude chunks of code, modules, etc.
-    const isDistributableConfig = {
-      plugins: [
-        new webpack.DefinePlugin({
-          'process.env': {
-            IS_KIBANA_DISTRIBUTABLE: `"true"`,
-          },
-        }),
-      ],
-    };
-
-    const watchingConfig = {
-      plugins: [
-        new webpack.WatchIgnorePlugin([
-          // When our bundle entry files are fresh they cause webpack
-          // to think they might have changed since the watcher was
-          // initialized, which triggers a second compilation on startup.
-          // Since we can't reliably update these files anyway, we can
-          // just ignore them in the watcher and prevent the extra compilation
-          /bundles[\/\\].+\.entry\.js/,
-        ]),
-      ],
-    };
-
-    const coverageConfig = {
-      plugins: [
-        new WrapperPlugin({
-          test: /commons\.bundle\.js$/, // only wrap output of bundle files with '.js' extension
-          header: `
-            window.flushCoverageToLog = function () {
-              if (window.__coverage__) {
-                console.log('coveragejson:' + btoa(JSON.stringify(window.__coverage__)));
-              }
-            };
-            window.addEventListener('beforeunload', window.flushCoverageToLog);
-          `,
-        }),
-      ],
-    };
-
-    // in production we set the process.env.NODE_ENV and run
-    // the terser minimizer over our bundles
-    const productionConfig = {
-      mode: 'production',
-      optimization: {
-        minimizer: [
-          new TerserPlugin({
-            parallel: false,
-            sourceMap: false,
-            cache: false,
-            extractComments: false,
-            terserOptions: {
-              compress: false,
-              mangle: false,
-            },
-          }),
-        ],
-      },
-    };
-
-    return this.uiBundles.getExtendedConfig(
-      webpackMerge(
-        IS_CODE_COVERAGE ? coverageConfig : {},
-        commonConfig,
-        IS_KIBANA_DISTRIBUTABLE ? isDistributableConfig : {},
-        this.uiBundles.isDevMode() ? watchingConfig : productionConfig
-      )
-    );
-  }
-
-  isFailure(stats) {
-    if (stats.hasErrors()) {
-      return true;
-    }
-
-    const { warnings } = stats.toJson({ all: false, warnings: true });
-
-    // 1 - when typescript doesn't do a full type check, as we have the ts-loader
-    // configured here, it does not have enough information to determine
-    // whether an imported name is a type or not, so when the name is then
-    // exported, typescript has no choice but to emit the export. Fortunately,
-    // the extraneous export should not be harmful, so we just suppress these warnings
-    // https://github.com/TypeStrong/ts-loader#transpileonly-boolean-defaultfalse
-    //
-    // 2 - Mini Css Extract plugin tracks the order for each css import we have
-    // through the project (and it's successive imports) since version 0.4.2.
-    // In case we have the same imports more than one time with different
-    // sequences, this plugin will throw a warning. This should not be harmful,
-    // but the an issue was opened and can be followed on:
-    // https://github.com/webpack-contrib/mini-css-extract-plugin/issues/250#issuecomment-415345126
-    const filteredWarnings = Stats.filterWarnings(warnings, STATS_WARNINGS_FILTER);
-
-    return filteredWarnings.length > 0;
-  }
-
-  failedStatsToError(stats) {
-    const details = stats.toString({
-      ...Stats.presetToOptions('minimal'),
-      colors: true,
-      warningsFilter: STATS_WARNINGS_FILTER,
-    });
-
-    return Boom.internal(
-      `Optimizations failure.\n${details.split('\n').join('\n    ')}\n`,
-      stats.toJson({
-        warningsFilter: STATS_WARNINGS_FILTER,
-        ...Stats.presetToOptions('detailed'),
-        maxModules: 1000,
-      })
-    );
-  }
-
-  getPresets() {
-    return IS_CODE_COVERAGE
-      ? [ISTANBUL_PRESET_PATH, BABEL_PRESET_PATH, LEGACY_PRESETS]
-      : [BABEL_PRESET_PATH, LEGACY_PRESETS];
-  }
-}
diff --git a/src/optimize/bundles_route/__tests__/fixtures/outside_output.js b/src/optimize/bundles_route/__fixtures__/outside_output.js
similarity index 100%
rename from src/optimize/bundles_route/__tests__/fixtures/outside_output.js
rename to src/optimize/bundles_route/__fixtures__/outside_output.js
diff --git a/src/optimize/bundles_route/__tests__/fixtures/output/image.png b/src/optimize/bundles_route/__fixtures__/plugin/foo/image.png
similarity index 100%
rename from src/optimize/bundles_route/__tests__/fixtures/output/image.png
rename to src/optimize/bundles_route/__fixtures__/plugin/foo/image.png
diff --git a/src/optimize/bundles_route/__tests__/fixtures/plugin/no_placeholder/no_placeholder.plugin.js b/src/optimize/bundles_route/__fixtures__/plugin/foo/plugin.js
similarity index 100%
rename from src/optimize/bundles_route/__tests__/fixtures/plugin/no_placeholder/no_placeholder.plugin.js
rename to src/optimize/bundles_route/__fixtures__/plugin/foo/plugin.js
diff --git a/src/optimize/bundles_route/__tests__/bundles_route.js b/src/optimize/bundles_route/__tests__/bundles_route.js
deleted file mode 100644
index 5b42b658300fe..0000000000000
--- a/src/optimize/bundles_route/__tests__/bundles_route.js
+++ /dev/null
@@ -1,440 +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 { resolve } from 'path';
-import { readFileSync } from 'fs';
-import crypto from 'crypto';
-
-import Chance from 'chance';
-import expect from '@kbn/expect';
-import Hapi from 'hapi';
-import Inert from 'inert';
-import sinon from 'sinon';
-
-import { createBundlesRoute } from '../bundles_route';
-import { PUBLIC_PATH_PLACEHOLDER } from '../../public_path_placeholder';
-
-const chance = new Chance();
-const outputFixture = resolve(__dirname, './fixtures/output');
-const pluginNoPlaceholderFixture = resolve(__dirname, './fixtures/plugin/no_placeholder');
-
-const randomWordsCache = new Set();
-const uniqueRandomWord = () => {
-  const word = chance.word();
-
-  if (randomWordsCache.has(word)) {
-    return uniqueRandomWord();
-  }
-
-  randomWordsCache.add(word);
-  return word;
-};
-
-function replaceAll(source, replace, replaceWith) {
-  return source.split(replace).join(replaceWith);
-}
-
-describe('optimizer/bundle route', () => {
-  const sandbox = sinon.createSandbox();
-
-  function createServer(options = {}) {
-    const {
-      regularBundlesPath = outputFixture,
-      basePublicPath = '',
-      builtCssPath = outputFixture,
-      npUiPluginPublicDirs = [],
-      buildHash = '1234',
-      isDist = false,
-    } = options;
-
-    const server = new Hapi.Server();
-    server.register([Inert]);
-
-    server.route(
-      createBundlesRoute({
-        regularBundlesPath,
-        basePublicPath,
-        builtCssPath,
-        npUiPluginPublicDirs,
-        buildHash,
-        isDist,
-      })
-    );
-
-    return server;
-  }
-
-  afterEach(() => sandbox.restore());
-
-  describe('validation', () => {
-    it('validates that regularBundlesPath is an absolute path', () => {
-      expect(() => {
-        createBundlesRoute({
-          regularBundlesPath: null,
-          basePublicPath: '',
-        });
-      }).to.throwError(/absolute path/);
-      expect(() => {
-        createBundlesRoute({
-          regularBundlesPath: './relative',
-          basePublicPath: '',
-        });
-      }).to.throwError(/absolute path/);
-      expect(() => {
-        createBundlesRoute({
-          regularBundlesPath: 1234,
-          basePublicPath: '',
-        });
-      }).to.throwError(/absolute path/);
-      expect(() => {
-        createBundlesRoute({
-          regularBundlesPath: '/absolute/path',
-          basePublicPath: '',
-        });
-      }).to.not.throwError();
-    });
-    it('validates that basePublicPath is valid', () => {
-      expect(() => {
-        createBundlesRoute({
-          regularBundlesPath: '/bundles',
-          basePublicPath: 123,
-        });
-      }).to.throwError(/string/);
-      expect(() => {
-        createBundlesRoute({
-          regularBundlesPath: '/bundles',
-          basePublicPath: {},
-        });
-      }).to.throwError(/string/);
-      expect(() => {
-        createBundlesRoute({
-          regularBundlesPath: '/bundles',
-          basePublicPath: '/a/',
-        });
-      }).to.throwError(/start and not end with a \//);
-      expect(() => {
-        createBundlesRoute({
-          regularBundlesPath: '/bundles',
-          basePublicPath: 'a/',
-        });
-      }).to.throwError(/start and not end with a \//);
-      expect(() => {
-        createBundlesRoute({
-          regularBundlesPath: '/bundles',
-          basePublicPath: '/a',
-        });
-      }).to.not.throwError();
-      expect(() => {
-        createBundlesRoute({
-          regularBundlesPath: '/bundles',
-          basePublicPath: '',
-        });
-      }).to.not.throwError();
-    });
-  });
-
-  describe('image', () => {
-    it('responds with exact file data', async () => {
-      const server = createServer();
-      const response = await server.inject({
-        url: '/1234/bundles/image.png',
-      });
-
-      expect(response.statusCode).to.be(200);
-      const image = readFileSync(resolve(outputFixture, 'image.png'));
-      expect(response.headers).to.have.property('content-length', image.length);
-      expect(response.headers).to.have.property('content-type', 'image/png');
-      expect(image).to.eql(response.rawPayload);
-    });
-  });
-
-  describe('js file without placeholder', () => {
-    it('responds with no content-length and exact file data', async () => {
-      const server = createServer();
-      const response = await server.inject({
-        url: '/1234/bundles/no_placeholder.js',
-      });
-
-      expect(response.statusCode).to.be(200);
-      expect(response.headers).to.not.have.property('content-length');
-      expect(response.headers).to.have.property(
-        'content-type',
-        'application/javascript; charset=utf-8'
-      );
-      expect(readFileSync(resolve(outputFixture, 'no_placeholder.js'))).to.eql(response.rawPayload);
-    });
-  });
-
-  describe('js file with placeholder', () => {
-    it('responds with no content-length and modifiedfile data ', async () => {
-      const basePublicPath = `/${uniqueRandomWord()}`;
-      const server = createServer({ basePublicPath });
-
-      const response = await server.inject({
-        url: '/1234/bundles/with_placeholder.js',
-      });
-
-      expect(response.statusCode).to.be(200);
-      const source = readFileSync(resolve(outputFixture, 'with_placeholder.js'), 'utf8');
-      expect(response.headers).to.not.have.property('content-length');
-      expect(response.headers).to.have.property(
-        'content-type',
-        'application/javascript; charset=utf-8'
-      );
-      expect(response.result.indexOf(source)).to.be(-1);
-      expect(response.result).to.be(
-        replaceAll(source, PUBLIC_PATH_PLACEHOLDER, `${basePublicPath}/1234/bundles/`)
-      );
-    });
-  });
-
-  describe('css file without placeholder', () => {
-    it('responds with no content-length and exact file data', async () => {
-      const server = createServer();
-      const response = await server.inject({
-        url: '/1234/bundles/no_placeholder.css',
-      });
-
-      expect(response.statusCode).to.be(200);
-      expect(response.headers).to.not.have.property('content-length');
-      expect(response.headers).to.have.property('content-type', 'text/css; charset=utf-8');
-      expect(readFileSync(resolve(outputFixture, 'no_placeholder.css'))).to.eql(
-        response.rawPayload
-      );
-    });
-  });
-
-  describe('css file with placeholder', () => {
-    it('responds with no content-length and modified file data', async () => {
-      const basePublicPath = `/${uniqueRandomWord()}`;
-      const server = createServer({ basePublicPath });
-
-      const response = await server.inject({
-        url: '/1234/bundles/with_placeholder.css',
-      });
-
-      expect(response.statusCode).to.be(200);
-      const source = readFileSync(resolve(outputFixture, 'with_placeholder.css'), 'utf8');
-      expect(response.headers).to.not.have.property('content-length');
-      expect(response.headers).to.have.property('content-type', 'text/css; charset=utf-8');
-      expect(response.result.indexOf(source)).to.be(-1);
-      expect(response.result).to.be(
-        replaceAll(source, PUBLIC_PATH_PLACEHOLDER, `${basePublicPath}/1234/bundles/`)
-      );
-    });
-  });
-
-  describe('js file outside regularBundlesPath', () => {
-    it('responds with a 404', async () => {
-      const server = createServer();
-
-      const response = await server.inject({
-        url: '/1234/bundles/../outside_output.js',
-      });
-
-      expect(response.statusCode).to.be(404);
-      expect(response.result).to.eql({
-        error: 'Not Found',
-        message: 'Not Found',
-        statusCode: 404,
-      });
-    });
-  });
-
-  describe('missing js file', () => {
-    it('responds with 404', async () => {
-      const server = createServer();
-
-      const response = await server.inject({
-        url: '/1234/bundles/non_existent.js',
-      });
-
-      expect(response.statusCode).to.be(404);
-      expect(response.result).to.eql({
-        error: 'Not Found',
-        message: 'Not Found',
-        statusCode: 404,
-      });
-    });
-  });
-
-  describe('missing regularBundlesPath', () => {
-    it('responds with 404', async () => {
-      const server = createServer({
-        regularBundlesPath: resolve(__dirname, 'fixtures/not_really_output'),
-      });
-
-      const response = await server.inject({
-        url: '/1234/bundles/with_placeholder.js',
-      });
-
-      expect(response.statusCode).to.be(404);
-      expect(response.result).to.eql({
-        error: 'Not Found',
-        message: 'Not Found',
-        statusCode: 404,
-      });
-    });
-  });
-
-  describe('etag', () => {
-    it('only calculates hash of file on first request', async () => {
-      const createHash = sandbox.spy(crypto, 'createHash');
-
-      const server = createServer();
-
-      sinon.assert.notCalled(createHash);
-      const resp1 = await server.inject({
-        url: '/1234/bundles/no_placeholder.js',
-      });
-
-      sinon.assert.calledOnce(createHash);
-      createHash.resetHistory();
-      expect(resp1.statusCode).to.be(200);
-
-      const resp2 = await server.inject({
-        url: '/1234/bundles/no_placeholder.js',
-      });
-
-      sinon.assert.notCalled(createHash);
-      expect(resp2.statusCode).to.be(200);
-    });
-
-    it('is unique per basePublicPath although content is the same (by default)', async () => {
-      const basePublicPath1 = `/${uniqueRandomWord()}`;
-      const basePublicPath2 = `/${uniqueRandomWord()}`;
-
-      const [resp1, resp2] = await Promise.all([
-        createServer({ basePublicPath: basePublicPath1 }).inject({
-          url: '/1234/bundles/no_placeholder.js',
-        }),
-        createServer({ basePublicPath: basePublicPath2 }).inject({
-          url: '/1234/bundles/no_placeholder.js',
-        }),
-      ]);
-
-      expect(resp1.statusCode).to.be(200);
-      expect(resp2.statusCode).to.be(200);
-
-      expect(resp1.rawPayload).to.eql(resp2.rawPayload);
-
-      expect(resp1.headers.etag).to.be.a('string');
-      expect(resp2.headers.etag).to.be.a('string');
-      expect(resp1.headers.etag).to.not.eql(resp2.headers.etag);
-    });
-  });
-
-  describe('cache control', () => {
-    it('responds with 304 when etag and last modified are sent back', async () => {
-      const server = createServer();
-      const resp = await server.inject({
-        url: '/1234/bundles/with_placeholder.js',
-      });
-
-      expect(resp.statusCode).to.be(200);
-
-      const resp2 = await server.inject({
-        url: '/1234/bundles/with_placeholder.js',
-        headers: {
-          'if-modified-since': resp.headers['last-modified'],
-          'if-none-match': resp.headers.etag,
-        },
-      });
-
-      expect(resp2.statusCode).to.be(304);
-      expect(resp2.result).to.have.length(0);
-    });
-  });
-
-  describe('kibana platform assets', () => {
-    describe('caching', () => {
-      describe('for non-distributable mode', () => {
-        it('uses "etag" header to invalidate cache', async () => {
-          const basePublicPath = `/${uniqueRandomWord()}`;
-
-          const npUiPluginPublicDirs = [
-            {
-              id: 'no_placeholder',
-              path: pluginNoPlaceholderFixture,
-            },
-          ];
-          const responce = await createServer({ basePublicPath, npUiPluginPublicDirs }).inject({
-            url: '/1234/bundles/plugin/no_placeholder/no_placeholder.plugin.js',
-          });
-
-          expect(responce.statusCode).to.be(200);
-
-          expect(responce.headers.etag).to.be.a('string');
-          expect(responce.headers['cache-control']).to.be('must-revalidate');
-        });
-
-        it('creates the same "etag" header for the same content with the same basePath', async () => {
-          const npUiPluginPublicDirs = [
-            {
-              id: 'no_placeholder',
-              path: pluginNoPlaceholderFixture,
-            },
-          ];
-          const [resp1, resp2] = await Promise.all([
-            createServer({ basePublicPath: '', npUiPluginPublicDirs }).inject({
-              url: '/1234/bundles/plugin/no_placeholder/no_placeholder.plugin.js',
-            }),
-            createServer({ basePublicPath: '', npUiPluginPublicDirs }).inject({
-              url: '/1234/bundles/plugin/no_placeholder/no_placeholder.plugin.js',
-            }),
-          ]);
-
-          expect(resp1.statusCode).to.be(200);
-          expect(resp2.statusCode).to.be(200);
-
-          expect(resp1.rawPayload).to.eql(resp2.rawPayload);
-
-          expect(resp1.headers.etag).to.be.a('string');
-          expect(resp2.headers.etag).to.be.a('string');
-          expect(resp1.headers.etag).to.eql(resp2.headers.etag);
-        });
-      });
-
-      describe('for distributable mode', () => {
-        it('commands to cache assets for each release for a year', async () => {
-          const basePublicPath = `/${uniqueRandomWord()}`;
-
-          const npUiPluginPublicDirs = [
-            {
-              id: 'no_placeholder',
-              path: pluginNoPlaceholderFixture,
-            },
-          ];
-          const responce = await createServer({
-            basePublicPath,
-            npUiPluginPublicDirs,
-            isDist: true,
-          }).inject({
-            url: '/1234/bundles/plugin/no_placeholder/no_placeholder.plugin.js',
-          });
-
-          expect(responce.statusCode).to.be(200);
-
-          expect(responce.headers.etag).to.be(undefined);
-          expect(responce.headers['cache-control']).to.be('max-age=31536000');
-        });
-      });
-    });
-  });
-});
diff --git a/src/optimize/bundles_route/__tests__/fixtures/output/no_placeholder.css b/src/optimize/bundles_route/__tests__/fixtures/output/no_placeholder.css
deleted file mode 100644
index 31d9cc2684a72..0000000000000
--- a/src/optimize/bundles_route/__tests__/fixtures/output/no_placeholder.css
+++ /dev/null
@@ -1,3 +0,0 @@
-body {
-  background-color: goldenrod;
-}
diff --git a/src/optimize/bundles_route/__tests__/fixtures/output/no_placeholder.js b/src/optimize/bundles_route/__tests__/fixtures/output/no_placeholder.js
deleted file mode 100644
index bf04a775a1a8a..0000000000000
--- a/src/optimize/bundles_route/__tests__/fixtures/output/no_placeholder.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.
- */
-
-console.log('chunk2');
diff --git a/src/optimize/bundles_route/__tests__/fixtures/output/with_placeholder.css b/src/optimize/bundles_route/__tests__/fixtures/output/with_placeholder.css
deleted file mode 100644
index 5b5979850daf7..0000000000000
--- a/src/optimize/bundles_route/__tests__/fixtures/output/with_placeholder.css
+++ /dev/null
@@ -1,3 +0,0 @@
-body {
-  background-image: url(__REPLACE_WITH_PUBLIC_PATH__/image.png);
-}
diff --git a/src/optimize/bundles_route/__tests__/fixtures/output/with_placeholder.js b/src/optimize/bundles_route/__tests__/fixtures/output/with_placeholder.js
deleted file mode 100644
index 1862127904a4c..0000000000000
--- a/src/optimize/bundles_route/__tests__/fixtures/output/with_placeholder.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.
- */
-
-console.log('__REPLACE_WITH_PUBLIC_PATH__');
diff --git a/src/optimize/bundles_route/__tests__/fixtures/plugin/placeholder/placeholder.plugin.js b/src/optimize/bundles_route/__tests__/fixtures/plugin/placeholder/placeholder.plugin.js
deleted file mode 100644
index 8c959f9b4779f..0000000000000
--- a/src/optimize/bundles_route/__tests__/fixtures/plugin/placeholder/placeholder.plugin.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.
- */
-
-module.exports = '__REPLACE_WITH_PUBLIC_PATH__/FOO';
diff --git a/src/optimize/bundles_route/bundles_route.test.ts b/src/optimize/bundles_route/bundles_route.test.ts
new file mode 100644
index 0000000000000..8cf4e9d72685c
--- /dev/null
+++ b/src/optimize/bundles_route/bundles_route.test.ts
@@ -0,0 +1,307 @@
+/*
+ * 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 { resolve } from 'path';
+import { readFileSync } from 'fs';
+import crypto from 'crypto';
+
+import Chance from 'chance';
+import Hapi from 'hapi';
+import Inert from 'inert';
+
+import { createBundlesRoute } from './bundles_route';
+
+const chance = new Chance();
+const fooPluginFixture = resolve(__dirname, './__fixtures__/plugin/foo');
+const createHashMock = jest.spyOn(crypto, 'createHash');
+
+const randomWordsCache = new Set();
+const uniqueRandomWord = (): string => {
+  const word = chance.word();
+
+  if (randomWordsCache.has(word)) {
+    return uniqueRandomWord();
+  }
+
+  randomWordsCache.add(word);
+  return word;
+};
+
+function createServer({
+  basePublicPath = '',
+  isDist = false,
+}: {
+  basePublicPath?: string;
+  isDist?: boolean;
+} = {}) {
+  const buildHash = '1234';
+  const npUiPluginPublicDirs = [
+    {
+      id: 'foo',
+      path: fooPluginFixture,
+    },
+  ];
+
+  const server = new Hapi.Server();
+  server.register([Inert]);
+
+  server.route(
+    createBundlesRoute({
+      basePublicPath,
+      npUiPluginPublicDirs,
+      buildHash,
+      isDist,
+    })
+  );
+
+  return server;
+}
+
+beforeEach(() => {
+  jest.clearAllMocks();
+});
+
+describe('validation', () => {
+  it('validates that basePublicPath is valid', () => {
+    expect(() => {
+      createServer({
+        // @ts-expect-error intentionally trying to break things
+        basePublicPath: 123,
+      });
+    }).toThrowErrorMatchingInlineSnapshot(`"basePublicPath must be a string"`);
+    expect(() => {
+      createServer({
+        // @ts-expect-error intentionally trying to break things
+        basePublicPath: {},
+      });
+    }).toThrowErrorMatchingInlineSnapshot(`"basePublicPath must be a string"`);
+    expect(() => {
+      createServer({
+        basePublicPath: '/a/',
+      });
+    }).toThrowErrorMatchingInlineSnapshot(
+      `"basePublicPath must be empty OR start and not end with a /"`
+    );
+    expect(() => {
+      createServer({
+        basePublicPath: 'a/',
+      });
+    }).toThrowErrorMatchingInlineSnapshot(
+      `"basePublicPath must be empty OR start and not end with a /"`
+    );
+    expect(() => {
+      createServer({
+        basePublicPath: '/a',
+      });
+    }).not.toThrowError();
+    expect(() => {
+      createServer({
+        basePublicPath: '',
+      });
+    }).not.toThrowError();
+  });
+});
+
+describe('image', () => {
+  it('responds with exact file data', async () => {
+    const server = createServer();
+    const response = await server.inject({
+      url: '/1234/bundles/plugin/foo/image.png',
+    });
+
+    expect(response.statusCode).toBe(200);
+    const image = readFileSync(resolve(fooPluginFixture, 'image.png'));
+    expect(response.headers).toHaveProperty('content-length', image.length);
+    expect(response.headers).toHaveProperty('content-type', 'image/png');
+    expect(image).toEqual(response.rawPayload);
+  });
+});
+
+describe('js file', () => {
+  it('responds with no content-length and exact file data', async () => {
+    const server = createServer();
+    const response = await server.inject({
+      url: '/1234/bundles/plugin/foo/plugin.js',
+    });
+
+    expect(response.statusCode).toBe(200);
+    expect(response.headers).not.toHaveProperty('content-length');
+    expect(response.headers).toHaveProperty(
+      'content-type',
+      'application/javascript; charset=utf-8'
+    );
+    expect(readFileSync(resolve(fooPluginFixture, 'plugin.js'))).toEqual(response.rawPayload);
+  });
+});
+
+describe('js file outside plugin', () => {
+  it('responds with a 404', async () => {
+    const server = createServer();
+
+    const response = await server.inject({
+      url: '/1234/bundles/plugin/foo/../outside_output.js',
+    });
+
+    expect(response.statusCode).toBe(404);
+    expect(response.result).toEqual({
+      error: 'Not Found',
+      message: 'Not Found',
+      statusCode: 404,
+    });
+  });
+});
+
+describe('missing js file', () => {
+  it('responds with 404', async () => {
+    const server = createServer();
+
+    const response = await server.inject({
+      url: '/1234/bundles/plugin/foo/non_existent.js',
+    });
+
+    expect(response.statusCode).toBe(404);
+    expect(response.result).toEqual({
+      error: 'Not Found',
+      message: 'Not Found',
+      statusCode: 404,
+    });
+  });
+});
+
+describe('etag', () => {
+  it('only calculates hash of file on first request', async () => {
+    const server = createServer();
+
+    expect(createHashMock).not.toHaveBeenCalled();
+    const resp1 = await server.inject({
+      url: '/1234/bundles/plugin/foo/plugin.js',
+    });
+
+    expect(createHashMock).toHaveBeenCalledTimes(1);
+    createHashMock.mockClear();
+    expect(resp1.statusCode).toBe(200);
+
+    const resp2 = await server.inject({
+      url: '/1234/bundles/plugin/foo/plugin.js',
+    });
+
+    expect(createHashMock).not.toHaveBeenCalled();
+    expect(resp2.statusCode).toBe(200);
+  });
+
+  it('is unique per basePublicPath although content is the same (by default)', async () => {
+    const basePublicPath1 = `/${uniqueRandomWord()}`;
+    const basePublicPath2 = `/${uniqueRandomWord()}`;
+
+    const [resp1, resp2] = await Promise.all([
+      createServer({ basePublicPath: basePublicPath1 }).inject({
+        url: '/1234/bundles/plugin/foo/plugin.js',
+      }),
+      createServer({ basePublicPath: basePublicPath2 }).inject({
+        url: '/1234/bundles/plugin/foo/plugin.js',
+      }),
+    ]);
+
+    expect(resp1.statusCode).toBe(200);
+    expect(resp2.statusCode).toBe(200);
+
+    expect(resp1.rawPayload).toEqual(resp2.rawPayload);
+
+    expect(resp1.headers.etag).toEqual(expect.any(String));
+    expect(resp2.headers.etag).toEqual(expect.any(String));
+    expect(resp1.headers.etag).not.toEqual(resp2.headers.etag);
+  });
+});
+
+describe('cache control', () => {
+  it('responds with 304 when etag and last modified are sent back', async () => {
+    const server = createServer();
+    const resp = await server.inject({
+      url: '/1234/bundles/plugin/foo/plugin.js',
+    });
+
+    expect(resp.statusCode).toBe(200);
+
+    const resp2 = await server.inject({
+      url: '/1234/bundles/plugin/foo/plugin.js',
+      headers: {
+        'if-modified-since': resp.headers['last-modified'],
+        'if-none-match': resp.headers.etag,
+      },
+    });
+
+    expect(resp2.statusCode).toBe(304);
+    expect(resp2.result).toHaveLength(0);
+  });
+});
+
+describe('caching', () => {
+  describe('for non-distributable mode', () => {
+    it('uses "etag" header to invalidate cache', async () => {
+      const basePublicPath = `/${uniqueRandomWord()}`;
+
+      const responce = await createServer({ basePublicPath }).inject({
+        url: '/1234/bundles/plugin/foo/plugin.js',
+      });
+
+      expect(responce.statusCode).toBe(200);
+
+      expect(responce.headers.etag).toEqual(expect.any(String));
+      expect(responce.headers['cache-control']).toBe('must-revalidate');
+    });
+
+    it('creates the same "etag" header for the same content with the same basePath', async () => {
+      const [resp1, resp2] = await Promise.all([
+        createServer({ basePublicPath: '' }).inject({
+          url: '/1234/bundles/plugin/foo/plugin.js',
+        }),
+        createServer({ basePublicPath: '' }).inject({
+          url: '/1234/bundles/plugin/foo/plugin.js',
+        }),
+      ]);
+
+      expect(resp1.statusCode).toBe(200);
+      expect(resp2.statusCode).toBe(200);
+
+      expect(resp1.rawPayload).toEqual(resp2.rawPayload);
+
+      expect(resp1.headers.etag).toEqual(expect.any(String));
+      expect(resp2.headers.etag).toEqual(expect.any(String));
+      expect(resp1.headers.etag).toEqual(resp2.headers.etag);
+    });
+  });
+
+  describe('for distributable mode', () => {
+    it('commands to cache assets for each release for a year', async () => {
+      const basePublicPath = `/${uniqueRandomWord()}`;
+
+      const responce = await createServer({
+        basePublicPath,
+        isDist: true,
+      }).inject({
+        url: '/1234/bundles/plugin/foo/plugin.js',
+      });
+
+      expect(responce.statusCode).toBe(200);
+
+      expect(responce.headers.etag).toBe(undefined);
+      expect(responce.headers['cache-control']).toBe('max-age=31536000');
+    });
+  });
+});
diff --git a/src/optimize/bundles_route/bundles_route.ts b/src/optimize/bundles_route/bundles_route.ts
index 8c1092efed252..6d618fba50ccf 100644
--- a/src/optimize/bundles_route/bundles_route.ts
+++ b/src/optimize/bundles_route/bundles_route.ts
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-import { isAbsolute, extname, join } from 'path';
+import { extname, join } from 'path';
 
 import Hapi from 'hapi';
 import * as UiSharedDeps from '@kbn/ui-shared-deps';
@@ -28,9 +28,7 @@ import { assertIsNpUiPluginPublicDirs, NpUiPluginPublicDirs } from '../np_ui_plu
 import { fromRoot } from '../../core/server/utils';
 
 /**
- *  Creates the routes that serves files from `bundlesPath`. If the
- *  file is js or css then it is searched for instances of
- *  PUBLIC_PATH_PLACEHOLDER and replaces them with `publicPath`.
+ *  Creates the routes that serves files from `bundlesPath`.
  *
  *  @param {Object} options
  *  @property {Array<{id,path}>} options.npUiPluginPublicDirs array of ids and paths that should be served for new platform plugins
@@ -40,16 +38,12 @@ import { fromRoot } from '../../core/server/utils';
  *  @return Array.of({Hapi.Route})
  */
 export function createBundlesRoute({
-  regularBundlesPath,
   basePublicPath,
-  builtCssPath,
   npUiPluginPublicDirs = [],
   buildHash,
   isDist = false,
 }: {
-  regularBundlesPath: string;
   basePublicPath: string;
-  builtCssPath: string;
   npUiPluginPublicDirs?: NpUiPluginPublicDirs;
   buildHash: string;
   isDist?: boolean;
@@ -60,12 +54,6 @@ export function createBundlesRoute({
   const fileHashCache = new FileHashCache();
   assertIsNpUiPluginPublicDirs(npUiPluginPublicDirs);
 
-  if (typeof regularBundlesPath !== 'string' || !isAbsolute(regularBundlesPath)) {
-    throw new TypeError(
-      'regularBundlesPath must be an absolute path to the directory containing the regular bundles'
-    );
-  }
-
   if (typeof basePublicPath !== 'string') {
     throw new TypeError('basePublicPath must be a string');
   }
@@ -80,7 +68,6 @@ export function createBundlesRoute({
       routePath: `/${buildHash}/bundles/kbn-ui-shared-deps/`,
       bundlesPath: UiSharedDeps.distDir,
       fileHashCache,
-      replacePublicPath: false,
       isDist,
     }),
     ...npUiPluginPublicDirs.map(({ id, path }) =>
@@ -89,7 +76,6 @@ export function createBundlesRoute({
         routePath: `/${buildHash}/bundles/plugin/${id}/`,
         bundlesPath: path,
         fileHashCache,
-        replacePublicPath: false,
         isDist,
       })
     ),
@@ -98,21 +84,6 @@ export function createBundlesRoute({
       routePath: `/${buildHash}/bundles/core/`,
       bundlesPath: fromRoot(join('src', 'core', 'target', 'public')),
       fileHashCache,
-      replacePublicPath: false,
-      isDist,
-    }),
-    buildRouteForBundles({
-      publicPath: `${basePublicPath}/${buildHash}/bundles/`,
-      routePath: `/${buildHash}/bundles/`,
-      bundlesPath: regularBundlesPath,
-      fileHashCache,
-      isDist,
-    }),
-    buildRouteForBundles({
-      publicPath: `${basePublicPath}/`,
-      routePath: `/${buildHash}/built_assets/css/`,
-      bundlesPath: builtCssPath,
-      fileHashCache,
       isDist,
     }),
   ];
@@ -123,14 +94,12 @@ function buildRouteForBundles({
   routePath,
   bundlesPath,
   fileHashCache,
-  replacePublicPath = true,
   isDist,
 }: {
   publicPath: string;
   routePath: string;
   bundlesPath: string;
   fileHashCache: FileHashCache;
-  replacePublicPath?: boolean;
   isDist: boolean;
 }) {
   return {
@@ -153,7 +122,6 @@ function buildRouteForBundles({
               bundlesPath,
               fileHashCache,
               publicPath,
-              replacePublicPath,
               isDist,
             });
           },
diff --git a/src/optimize/bundles_route/dynamic_asset_response.ts b/src/optimize/bundles_route/dynamic_asset_response.ts
index 2f5395341abb1..ce839b33ccac0 100644
--- a/src/optimize/bundles_route/dynamic_asset_response.ts
+++ b/src/optimize/bundles_route/dynamic_asset_response.ts
@@ -27,8 +27,6 @@ import Hapi from 'hapi';
 
 import { FileHashCache } from './file_hash_cache';
 import { getFileHash } from './file_hash';
-// @ts-ignore
-import { replacePlaceholder } from '../public_path_placeholder';
 
 const MINUTE = 60;
 const HOUR = 60 * MINUTE;
@@ -86,8 +84,6 @@ async function selectCompressedFile(acceptEncodingHeader: string | undefined, pa
  *   - stream file to response
  *
  *  It differs from Inert in some important ways:
- *   - the PUBLIC_PATH_PLACEHOLDER is replaced with the correct
- *     public path as the response is streamed
  *   - cached hash/etag is based on the file on disk, but modified
  *     by the public path so that individual public paths have
  *     different etags, but can share a cache
@@ -98,7 +94,6 @@ export async function createDynamicAssetResponse({
   bundlesPath,
   publicPath,
   fileHashCache,
-  replacePublicPath,
   isDist,
 }: {
   request: Hapi.Request;
@@ -106,7 +101,6 @@ export async function createDynamicAssetResponse({
   bundlesPath: string;
   publicPath: string;
   fileHashCache: FileHashCache;
-  replacePublicPath: boolean;
   isDist: boolean;
 }) {
   let fd: number | undefined;
@@ -128,15 +122,13 @@ export async function createDynamicAssetResponse({
     const stat = await asyncFstat(fd);
     const hash = isDist ? undefined : await getFileHash(fileHashCache, path, stat, fd);
 
-    const read = Fs.createReadStream(null as any, {
+    const content = Fs.createReadStream(null as any, {
       fd,
       start: 0,
       autoClose: true,
     });
     fd = undefined; // read stream is now responsible for fd
 
-    const content = replacePublicPath ? replacePlaceholder(read, publicPath) : read;
-
     const response = h
       .response(content)
       .takeover()
diff --git a/src/optimize/bundles_route/proxy_bundles_route.ts b/src/optimize/bundles_route/proxy_bundles_route.ts
index 108d253d45202..a5cd32333e495 100644
--- a/src/optimize/bundles_route/proxy_bundles_route.ts
+++ b/src/optimize/bundles_route/proxy_bundles_route.ts
@@ -26,10 +26,7 @@ export function createProxyBundlesRoute({
   port: number;
   buildHash: string;
 }) {
-  return [
-    buildProxyRouteForBundles(`/${buildHash}/bundles/`, host, port),
-    buildProxyRouteForBundles(`/${buildHash}/built_assets/css/`, host, port),
-  ];
+  return [buildProxyRouteForBundles(`/${buildHash}/bundles/`, host, port)];
 }
 
 function buildProxyRouteForBundles(routePath: string, host: string, port: number) {
diff --git a/src/optimize/create_ui_exports_module.js b/src/optimize/create_ui_exports_module.js
deleted file mode 100644
index d20814b10931b..0000000000000
--- a/src/optimize/create_ui_exports_module.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-// We normalize all path separators to `/` in generated files
-function normalizePath(path) {
-  return path.replace(/[\\\/]+/g, '/');
-}
-
-module.exports = function () {
-  if (!module.id.includes('?')) {
-    throw new Error('create_ui_exports_module loaded without JSON args in module.id');
-  }
-
-  const { type, modules } = JSON.parse(module.id.slice(module.id.indexOf('?') + 1));
-  const comment = `// dynamically generated to load ${type} uiExports from plugins`;
-  const requires = modules
-    .sort((a, b) => a.localeCompare(b))
-    .map((m) => `require('${normalizePath(m)}')`)
-    .join('\n        ');
-
-  return {
-    code: `${comment}\n${requires}\n`,
-  };
-};
diff --git a/src/optimize/fs_optimizer.js b/src/optimize/fs_optimizer.js
deleted file mode 100644
index 71a4c85a9e5a5..0000000000000
--- a/src/optimize/fs_optimizer.js
+++ /dev/null
@@ -1,41 +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 BaseOptimizer from './base_optimizer';
-import { fromNode } from 'bluebird';
-
-export default class FsOptimizer extends BaseOptimizer {
-  async run() {
-    if (!this.compiler) {
-      await this.init();
-    }
-
-    await fromNode((cb) => {
-      this.compiler.run((err, stats) => {
-        if (err || !stats) return cb(err);
-
-        if (this.isFailure(stats)) {
-          return cb(this.failedStatsToError(stats));
-        } else {
-          cb(null, stats);
-        }
-      });
-    });
-  }
-}
diff --git a/src/optimize/index.js b/src/optimize/index.js
deleted file mode 100644
index 363f81a6a3a96..0000000000000
--- a/src/optimize/index.js
+++ /dev/null
@@ -1,21 +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 { optimizeMixin } from './optimize_mixin';
-export default optimizeMixin;
diff --git a/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/create_build_test_plugin/public/hack.js b/src/optimize/index.ts
similarity index 94%
rename from packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/create_build_test_plugin/public/hack.js
rename to src/optimize/index.ts
index dbeba25f9dfec..73d2b9765f451 100644
--- a/packages/kbn-plugin-helpers/src/tasks/build/integration_tests/__fixtures__/create_build_test_plugin/public/hack.js
+++ b/src/optimize/index.ts
@@ -17,4 +17,4 @@
  * under the License.
  */
 
-console.log('this is my hack');
+export { optimizeMixin } from './optimize_mixin';
diff --git a/src/optimize/intentionally_empty_module.js b/src/optimize/intentionally_empty_module.js
deleted file mode 100644
index 9880b336e76e5..0000000000000
--- a/src/optimize/intentionally_empty_module.js
+++ /dev/null
@@ -1,18 +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.
- */
diff --git a/src/optimize/optimize_mixin.ts b/src/optimize/optimize_mixin.ts
index 947c918a567f5..37f8b08dde3b8 100644
--- a/src/optimize/optimize_mixin.ts
+++ b/src/optimize/optimize_mixin.ts
@@ -19,10 +19,7 @@
 
 import Hapi from 'hapi';
 
-// @ts-ignore not TS yet
-import FsOptimizer from './fs_optimizer';
 import { createBundlesRoute } from './bundles_route';
-import { fromRoot } from '../core/server/utils';
 import { getNpUiPluginPublicDirs } from './np_ui_plugin_public_dirs';
 import KbnServer, { KibanaConfig } from '../legacy/server/kbn_server';
 
@@ -31,67 +28,12 @@ export const optimizeMixin = async (
   server: Hapi.Server,
   config: KibanaConfig
 ) => {
-  if (!config.get('optimize.enabled')) return;
-
-  // the watch optimizer sets up two threads, one is the server listening
-  // on 5601 and the other is a server listening on 5602 that builds the
-  // bundles in a "middleware" style.
-  //
-  // the server listening on 5601 may be restarted a number of times, depending
-  // on the watch setup managed by the cli. It proxies all bundles/*
-  // requests to the other server. The server on 5602 is long running, in order
-  // to prevent complete rebuilds of the optimize content.
-  const watch = config.get('optimize.watch');
-  if (watch) {
-    // eslint-disable-next-line @typescript-eslint/no-var-requires
-    return await kbnServer.mixin(require('./watch/watch'));
-  }
-
-  const { uiBundles } = kbnServer;
   server.route(
     createBundlesRoute({
-      regularBundlesPath: uiBundles.getWorkingDir(),
       basePublicPath: config.get('server.basePath'),
-      builtCssPath: fromRoot('built_assets/css'),
       npUiPluginPublicDirs: getNpUiPluginPublicDirs(kbnServer),
       buildHash: kbnServer.newPlatform.env.packageInfo.buildNum.toString(),
       isDist: kbnServer.newPlatform.env.packageInfo.dist,
     })
   );
-
-  // in prod, only bundle when something is missing or invalid
-  const reuseCache = config.get('optimize.useBundleCache')
-    ? await uiBundles.areAllBundleCachesValid()
-    : false;
-
-  // we might not have any work to do
-  if (reuseCache) {
-    server.log(['debug', 'optimize'], `All bundles are cached and ready to go!`);
-    return;
-  }
-
-  await uiBundles.resetBundleDir();
-
-  // only require the FsOptimizer when we need to
-  const optimizer = new FsOptimizer({
-    logWithMetadata: server.logWithMetadata,
-    uiBundles,
-    profile: config.get('optimize.profile'),
-    sourceMaps: config.get('optimize.sourceMaps'),
-    workers: config.get('optimize.workers'),
-  });
-
-  server.log(
-    ['info', 'optimize'],
-    `Optimizing and caching ${uiBundles.getDescription()}. This may take a few minutes`
-  );
-
-  const start = Date.now();
-  await optimizer.run();
-  const seconds = ((Date.now() - start) / 1000).toFixed(2);
-
-  server.log(
-    ['info', 'optimize'],
-    `Optimization of ${uiBundles.getDescription()} complete in ${seconds} seconds`
-  );
 };
diff --git a/src/optimize/postcss.config.js b/src/optimize/postcss.config.js
deleted file mode 100644
index 571bae86dee37..0000000000000
--- a/src/optimize/postcss.config.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-module.exports = {
-  plugins: [require('autoprefixer')()],
-};
diff --git a/src/optimize/public_path_placeholder.ts b/src/optimize/public_path_placeholder.ts
deleted file mode 100644
index d5f57a1586774..0000000000000
--- a/src/optimize/public_path_placeholder.ts
+++ /dev/null
@@ -1,57 +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 Stream from 'stream';
-import Fs from 'fs';
-
-import * as Rx from 'rxjs';
-import { take, takeUntil } from 'rxjs/operators';
-import { createReplaceStream } from '../legacy/utils';
-
-export const PUBLIC_PATH_PLACEHOLDER = '__REPLACE_WITH_PUBLIC_PATH__';
-
-interface ClosableTransform extends Stream.Transform {
-  close(): void;
-}
-
-export function replacePlaceholder(read: Stream.Readable, replacement: string) {
-  const replace = createReplaceStream(PUBLIC_PATH_PLACEHOLDER, replacement);
-
-  // handle errors on the read stream by proxying them
-  // to the replace stream so that the consumer can
-  // choose what to do with them.
-  Rx.fromEvent(read, 'error')
-    .pipe(take(1), takeUntil(Rx.fromEvent(read, 'end')))
-    .forEach((error) => {
-      replace.emit('error', error);
-      replace.end();
-    });
-
-  const closableReplace: ClosableTransform = Object.assign(replace, {
-    close: () => {
-      read.unpipe();
-
-      if ('close' in read) {
-        (read as Fs.ReadStream).close();
-      }
-    },
-  });
-
-  return read.pipe(closableReplace);
-}
diff --git a/src/optimize/watch/optmzr_role.js b/src/optimize/watch/optmzr_role.js
deleted file mode 100644
index 0057c04219ec6..0000000000000
--- a/src/optimize/watch/optmzr_role.js
+++ /dev/null
@@ -1,74 +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 WatchServer from './watch_server';
-import WatchOptimizer, { STATUS } from './watch_optimizer';
-import { getNpUiPluginPublicDirs } from '../np_ui_plugin_public_dirs';
-
-export default async (kbnServer, kibanaHapiServer, config) => {
-  const logWithMetadata = (tags, message, metadata) =>
-    kibanaHapiServer.logWithMetadata(tags, message, metadata);
-
-  const watchOptimizer = new WatchOptimizer({
-    logWithMetadata,
-    uiBundles: kbnServer.uiBundles,
-    profile: config.get('optimize.profile'),
-    sourceMaps: config.get('optimize.sourceMaps'),
-    workers: config.get('optimize.workers'),
-    prebuild: config.get('optimize.watchPrebuild'),
-  });
-
-  const server = new WatchServer(
-    config.get('optimize.watchHost'),
-    config.get('optimize.watchPort'),
-    config.get('server.basePath'),
-    watchOptimizer,
-    getNpUiPluginPublicDirs(kbnServer),
-    kbnServer.newPlatform.env.packageInfo.buildNum.toString()
-  );
-
-  watchOptimizer.status$.subscribe({
-    next(status) {
-      process.send([
-        'OPTIMIZE_STATUS',
-        {
-          success: status.type === STATUS.SUCCESS,
-        },
-      ]);
-    },
-  });
-
-  let ready = false;
-
-  const sendReady = () => {
-    if (!process.connected) return;
-    process.send(['WORKER_BROADCAST', { optimizeReady: ready }]);
-  };
-
-  process.on('message', (msg) => {
-    if (msg && msg.optimizeReady === '?') sendReady();
-  });
-
-  sendReady();
-
-  await server.init();
-
-  ready = true;
-  sendReady();
-};
diff --git a/src/optimize/watch/proxy_role.js b/src/optimize/watch/proxy_role.js
deleted file mode 100644
index ce2d63aa2eff0..0000000000000
--- a/src/optimize/watch/proxy_role.js
+++ /dev/null
@@ -1,57 +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 { createProxyBundlesRoute } from '../bundles_route';
-import { fromNode } from 'bluebird';
-import { get, once } from 'lodash';
-
-export default (kbnServer, server, config) => {
-  server.route(
-    createProxyBundlesRoute({
-      host: config.get('optimize.watchHost'),
-      port: config.get('optimize.watchPort'),
-      buildHash: kbnServer.newPlatform.env.packageInfo.buildNum.toString(),
-    })
-  );
-
-  return fromNode((cb) => {
-    const timeout = setTimeout(() => {
-      cb(new Error('Timeout waiting for the optimizer to become ready'));
-    }, config.get('optimize.watchProxyTimeout'));
-
-    const waiting = once(() => {
-      server.log(['info', 'optimize'], 'Waiting for optimizer to be ready');
-    });
-
-    if (!process.connected) return;
-
-    process.send(['WORKER_BROADCAST', { optimizeReady: '?' }]);
-    process.on('message', (msg) => {
-      switch (get(msg, 'optimizeReady')) {
-        case true:
-          clearTimeout(timeout);
-          cb();
-          break;
-        case false:
-          waiting();
-          break;
-      }
-    });
-  });
-};
diff --git a/src/optimize/watch/watch.js b/src/optimize/watch/watch.js
deleted file mode 100644
index 7774577fb7677..0000000000000
--- a/src/optimize/watch/watch.js
+++ /dev/null
@@ -1,51 +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 { isWorker } from 'cluster';
-
-export default async (kbnServer) => {
-  if (!isWorker) {
-    throw new Error(`watch optimization is only available when using the "--dev" cli flag`);
-  }
-
-  /**
-   * When running in watch mode two processes run in one of the following modes:
-   *
-   * optmzr: this process runs the WatchOptimizer and the WatchServer
-   *   which serves the WatchOptimizer's output and blocks requests
-   *   while the optimizer is running
-   *
-   * server: this process runs the entire kibana server and proxies
-   *   all requests for /bundles/* to the optmzr process
-   *
-   * @param  {string} process.env.kbnWorkerType
-   */
-  switch (process.env.kbnWorkerType) {
-    case 'optmzr':
-      await kbnServer.mixin(require('./optmzr_role'));
-      break;
-
-    case 'server':
-      await kbnServer.mixin(require('./proxy_role'));
-      break;
-
-    default:
-      throw new Error(`unknown kbnWorkerType "${process.env.kbnWorkerType}"`);
-  }
-};
diff --git a/src/optimize/watch/watch_optimizer.js b/src/optimize/watch/watch_optimizer.js
deleted file mode 100644
index 000c03ffb34fe..0000000000000
--- a/src/optimize/watch/watch_optimizer.js
+++ /dev/null
@@ -1,192 +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 BaseOptimizer from '../base_optimizer';
-import { createBundlesRoute } from '../bundles_route';
-import { fromRoot } from '../../core/server/utils';
-import * as Rx from 'rxjs';
-import { mergeMap, take } from 'rxjs/operators';
-
-export const STATUS = {
-  RUNNING: 'optimizer running',
-  SUCCESS: 'optimizer completed successfully',
-  FAILURE: 'optimizer failed with stats',
-  FATAL: 'optimizer failed without stats',
-};
-
-export default class WatchOptimizer extends BaseOptimizer {
-  constructor(opts) {
-    super(opts);
-    this.prebuild = opts.prebuild || false;
-    this.status$ = new Rx.ReplaySubject(1);
-  }
-
-  async init() {
-    this.initializing = true;
-    this.initialBuildComplete = false;
-
-    // log status changes
-    this.status$.subscribe(this.onStatusChangeHandler);
-    await this.uiBundles.resetBundleDir();
-    await super.init();
-
-    this.compiler.watch({ aggregateTimeout: 200 }, this.compilerWatchErrorHandler);
-
-    if (this.prebuild) {
-      await this.onceBuildOutcome();
-    }
-
-    this.initializing = false;
-  }
-
-  /**
-   *
-   * Extends the base_optimizer registerCompilerHooks function
-   * calling extended function also adding a new register function
-   *
-   * It gets called by super.init()
-   */
-  registerCompilerHooks() {
-    super.registerCompilerHooks();
-    this.registerCompilerWatchRunHook();
-  }
-
-  registerCompilerWatchRunHook() {
-    this.compiler.hooks.watchRun.tap('watch_optimizer-watchRun', () => {
-      this.status$.next({
-        type: STATUS.RUNNING,
-      });
-    });
-  }
-
-  registerCompilerDoneHook() {
-    super.registerCompilerDoneHook();
-
-    this.compiler.hooks.done.tap('watch_optimizer-done', (stats) => {
-      if (stats.compilation.needAdditionalPass) {
-        return;
-      }
-
-      this.initialBuildComplete = true;
-      const seconds = parseFloat((stats.endTime - stats.startTime) / 1000).toFixed(2);
-
-      if (this.isFailure(stats)) {
-        this.status$.next({
-          type: STATUS.FAILURE,
-          seconds,
-          error: this.failedStatsToError(stats),
-        });
-      } else {
-        this.status$.next({
-          type: STATUS.SUCCESS,
-          seconds,
-        });
-      }
-    });
-  }
-
-  bindToServer(server, basePath, npUiPluginPublicDirs, buildHash) {
-    // pause all requests received while the compiler is running
-    // and continue once an outcome is reached (aborting the request
-    // with an error if it was a failure).
-    server.ext('onRequest', async (request, h) => {
-      await this.onceBuildOutcome();
-      return h.continue;
-    });
-
-    server.route(
-      createBundlesRoute({
-        npUiPluginPublicDirs: npUiPluginPublicDirs,
-        buildHash,
-        regularBundlesPath: this.compiler.outputPath,
-        basePublicPath: basePath,
-        builtCssPath: fromRoot('built_assets/css'),
-      })
-    );
-  }
-
-  async onceBuildOutcome() {
-    return await this.status$.pipe(mergeMap(this.mapStatusToOutcomes), take(1)).toPromise();
-  }
-
-  mapStatusToOutcomes({ type, error }) {
-    switch (type) {
-      case STATUS.RUNNING:
-        return [];
-
-      case STATUS.SUCCESS:
-        return [true];
-
-      case STATUS.FAILURE:
-      case STATUS.FATAL:
-        return Rx.throwError(error);
-    }
-  }
-
-  compilerWatchErrorHandler = (error) => {
-    if (error) {
-      this.status$.next({
-        type: STATUS.FATAL,
-        error,
-      });
-    }
-  };
-
-  onStatusChangeHandler = ({ type, seconds, error }) => {
-    switch (type) {
-      case STATUS.RUNNING:
-        if (!this.initialBuildComplete) {
-          this.logWithMetadata(['info', 'optimize'], `Optimization started`, {
-            bundles: this.uiBundles.getIds(),
-          });
-        }
-        break;
-
-      case STATUS.SUCCESS:
-        this.logWithMetadata(['info', 'optimize'], `Optimization success in ${seconds} seconds`, {
-          bundles: this.uiBundles.getIds(),
-          status: 'success',
-          seconds,
-        });
-        break;
-
-      case STATUS.FAILURE:
-        // errors during initialization to the server, unlike the rest of the
-        // errors produced here. Lets not muddy the console with extra errors
-        if (!this.initializing) {
-          this.logWithMetadata(
-            ['fatal', 'optimize'],
-            `Optimization failed in ${seconds} seconds${error}`,
-            {
-              bundles: this.uiBundles.getIds(),
-              status: 'failed',
-              seconds,
-              err: error,
-            }
-          );
-        }
-        break;
-
-      case STATUS.FATAL:
-        this.logWithMetadata('fatal', error);
-        process.exit(1);
-        break;
-    }
-  };
-}
diff --git a/src/optimize/watch/watch_server.js b/src/optimize/watch/watch_server.js
deleted file mode 100644
index 81e04a5b83956..0000000000000
--- a/src/optimize/watch/watch_server.js
+++ /dev/null
@@ -1,47 +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 { Server } from 'hapi';
-import { registerHapiPlugins } from '../../legacy/server/http/register_hapi_plugins';
-
-export default class WatchServer {
-  constructor(host, port, basePath, optimizer, npUiPluginPublicDirs, buildHash) {
-    this.basePath = basePath;
-    this.optimizer = optimizer;
-    this.npUiPluginPublicDirs = npUiPluginPublicDirs;
-    this.buildHash = buildHash;
-    this.server = new Server({
-      host: host,
-      port: port,
-    });
-
-    registerHapiPlugins(this.server);
-  }
-
-  async init() {
-    await this.optimizer.init();
-    this.optimizer.bindToServer(
-      this.server,
-      this.basePath,
-      this.npUiPluginPublicDirs,
-      this.buildHash
-    );
-    await this.server.start();
-  }
-}
diff --git a/src/plugins/timelion/public/flot.js b/src/plugins/timelion/public/flot.js
deleted file mode 100644
index 1ccb40c93a3d6..0000000000000
--- a/src/plugins/timelion/public/flot.js
+++ /dev/null
@@ -1,26 +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 './webpackShims/jquery.flot';
-import './webpackShims/jquery.flot.time';
-import './webpackShims/jquery.flot.symbol';
-import './webpackShims/jquery.flot.crosshair';
-import './webpackShims/jquery.flot.selection';
-import './webpackShims/jquery.flot.stack';
-import './webpackShims/jquery.flot.axislabels';
diff --git a/src/dev/sass/index.js b/src/plugins/timelion/public/flot/index.js
similarity index 78%
rename from src/dev/sass/index.js
rename to src/plugins/timelion/public/flot/index.js
index f172370280fcb..a066fd3ab8607 100644
--- a/src/dev/sass/index.js
+++ b/src/plugins/timelion/public/flot/index.js
@@ -17,4 +17,10 @@
  * under the License.
  */
 
-export { buildSass } from './build_sass';
+import './jquery.flot';
+import './jquery.flot.time';
+import './jquery.flot.symbol';
+import './jquery.flot.crosshair';
+import './jquery.flot.selection';
+import './jquery.flot.stack';
+import './jquery.flot.axislabels';
diff --git a/src/plugins/timelion/public/webpackShims/jquery.flot.axislabels.js b/src/plugins/timelion/public/flot/jquery.flot.axislabels.js
similarity index 100%
rename from src/plugins/timelion/public/webpackShims/jquery.flot.axislabels.js
rename to src/plugins/timelion/public/flot/jquery.flot.axislabels.js
diff --git a/src/plugins/timelion/public/webpackShims/jquery.flot.crosshair.js b/src/plugins/timelion/public/flot/jquery.flot.crosshair.js
similarity index 100%
rename from src/plugins/timelion/public/webpackShims/jquery.flot.crosshair.js
rename to src/plugins/timelion/public/flot/jquery.flot.crosshair.js
diff --git a/src/plugins/timelion/public/webpackShims/jquery.flot.js b/src/plugins/timelion/public/flot/jquery.flot.js
similarity index 100%
rename from src/plugins/timelion/public/webpackShims/jquery.flot.js
rename to src/plugins/timelion/public/flot/jquery.flot.js
diff --git a/src/plugins/timelion/public/webpackShims/jquery.flot.selection.js b/src/plugins/timelion/public/flot/jquery.flot.selection.js
similarity index 100%
rename from src/plugins/timelion/public/webpackShims/jquery.flot.selection.js
rename to src/plugins/timelion/public/flot/jquery.flot.selection.js
diff --git a/src/plugins/timelion/public/webpackShims/jquery.flot.stack.js b/src/plugins/timelion/public/flot/jquery.flot.stack.js
similarity index 100%
rename from src/plugins/timelion/public/webpackShims/jquery.flot.stack.js
rename to src/plugins/timelion/public/flot/jquery.flot.stack.js
diff --git a/src/plugins/timelion/public/webpackShims/jquery.flot.symbol.js b/src/plugins/timelion/public/flot/jquery.flot.symbol.js
similarity index 100%
rename from src/plugins/timelion/public/webpackShims/jquery.flot.symbol.js
rename to src/plugins/timelion/public/flot/jquery.flot.symbol.js
diff --git a/src/plugins/timelion/public/webpackShims/jquery.flot.time.js b/src/plugins/timelion/public/flot/jquery.flot.time.js
similarity index 100%
rename from src/plugins/timelion/public/webpackShims/jquery.flot.time.js
rename to src/plugins/timelion/public/flot/jquery.flot.time.js
diff --git a/src/plugins/vis_type_timelion/public/flot.js b/src/plugins/vis_type_timelion/public/flot.js
deleted file mode 100644
index 1ccb40c93a3d6..0000000000000
--- a/src/plugins/vis_type_timelion/public/flot.js
+++ /dev/null
@@ -1,26 +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 './webpackShims/jquery.flot';
-import './webpackShims/jquery.flot.time';
-import './webpackShims/jquery.flot.symbol';
-import './webpackShims/jquery.flot.crosshair';
-import './webpackShims/jquery.flot.selection';
-import './webpackShims/jquery.flot.stack';
-import './webpackShims/jquery.flot.axislabels';
diff --git a/src/legacy/ui/ui_bundles/index.js b/src/plugins/vis_type_timelion/public/flot/index.js
similarity index 78%
rename from src/legacy/ui/ui_bundles/index.js
rename to src/plugins/vis_type_timelion/public/flot/index.js
index b6afcf71a1114..a066fd3ab8607 100644
--- a/src/legacy/ui/ui_bundles/index.js
+++ b/src/plugins/vis_type_timelion/public/flot/index.js
@@ -17,4 +17,10 @@
  * under the License.
  */
 
-export { uiBundlesMixin } from './ui_bundles_mixin';
+import './jquery.flot';
+import './jquery.flot.time';
+import './jquery.flot.symbol';
+import './jquery.flot.crosshair';
+import './jquery.flot.selection';
+import './jquery.flot.stack';
+import './jquery.flot.axislabels';
diff --git a/src/plugins/vis_type_timelion/public/webpackShims/jquery.flot.axislabels.js b/src/plugins/vis_type_timelion/public/flot/jquery.flot.axislabels.js
similarity index 100%
rename from src/plugins/vis_type_timelion/public/webpackShims/jquery.flot.axislabels.js
rename to src/plugins/vis_type_timelion/public/flot/jquery.flot.axislabels.js
diff --git a/src/plugins/vis_type_timelion/public/webpackShims/jquery.flot.crosshair.js b/src/plugins/vis_type_timelion/public/flot/jquery.flot.crosshair.js
similarity index 100%
rename from src/plugins/vis_type_timelion/public/webpackShims/jquery.flot.crosshair.js
rename to src/plugins/vis_type_timelion/public/flot/jquery.flot.crosshair.js
diff --git a/src/plugins/vis_type_timelion/public/webpackShims/jquery.flot.js b/src/plugins/vis_type_timelion/public/flot/jquery.flot.js
similarity index 100%
rename from src/plugins/vis_type_timelion/public/webpackShims/jquery.flot.js
rename to src/plugins/vis_type_timelion/public/flot/jquery.flot.js
diff --git a/src/plugins/vis_type_timelion/public/webpackShims/jquery.flot.selection.js b/src/plugins/vis_type_timelion/public/flot/jquery.flot.selection.js
similarity index 100%
rename from src/plugins/vis_type_timelion/public/webpackShims/jquery.flot.selection.js
rename to src/plugins/vis_type_timelion/public/flot/jquery.flot.selection.js
diff --git a/src/plugins/vis_type_timelion/public/webpackShims/jquery.flot.stack.js b/src/plugins/vis_type_timelion/public/flot/jquery.flot.stack.js
similarity index 100%
rename from src/plugins/vis_type_timelion/public/webpackShims/jquery.flot.stack.js
rename to src/plugins/vis_type_timelion/public/flot/jquery.flot.stack.js
diff --git a/src/plugins/vis_type_timelion/public/webpackShims/jquery.flot.symbol.js b/src/plugins/vis_type_timelion/public/flot/jquery.flot.symbol.js
similarity index 100%
rename from src/plugins/vis_type_timelion/public/webpackShims/jquery.flot.symbol.js
rename to src/plugins/vis_type_timelion/public/flot/jquery.flot.symbol.js
diff --git a/src/plugins/vis_type_timelion/public/webpackShims/jquery.flot.time.js b/src/plugins/vis_type_timelion/public/flot/jquery.flot.time.js
similarity index 100%
rename from src/plugins/vis_type_timelion/public/webpackShims/jquery.flot.time.js
rename to src/plugins/vis_type_timelion/public/flot/jquery.flot.time.js
diff --git a/src/test_utils/kbn_server.ts b/src/test_utils/kbn_server.ts
index 6a20261421b5b..e337a469f17e6 100644
--- a/src/test_utils/kbn_server.ts
+++ b/src/test_utils/kbn_server.ts
@@ -49,7 +49,6 @@ const DEFAULTS_SETTINGS = {
   },
   logging: { silent: true },
   plugins: {},
-  optimize: { enabled: false },
   migrations: { skip: true },
 };
 
@@ -76,9 +75,11 @@ export function createRootWithSettings(
       watch: false,
       repl: false,
       basePath: false,
-      optimize: false,
       runExamples: false,
       oss: true,
+      disableOptimizer: true,
+      cache: true,
+      dist: false,
       ...cliArgs,
     },
     isDevClusterMaster: false,
diff --git a/test/api_integration/config.js b/test/api_integration/config.js
index 071e7fc6ba3fd..a7d31b8b2acce 100644
--- a/test/api_integration/config.js
+++ b/test/api_integration/config.js
@@ -35,7 +35,6 @@ export default async function ({ readConfigFile }) {
       ...functionalConfig.get('kbnTestServer'),
       serverArgs: [
         ...functionalConfig.get('kbnTestServer.serverArgs'),
-        '--optimize.enabled=false',
         '--elasticsearch.healthCheck.delay=3600000',
         '--server.xsrf.disableProtection=true',
         '--server.compression.referrerWhitelist=["some-host.com"]',
diff --git a/test/common/config.js b/test/common/config.js
index 9b58da4473738..6a62151b12814 100644
--- a/test/common/config.js
+++ b/test/common/config.js
@@ -19,7 +19,7 @@
 
 import path from 'path';
 import { format as formatUrl } from 'url';
-import { OPTIMIZE_BUNDLE_DIR, esTestConfig, kbnTestConfig, kibanaServerTestUser } from '@kbn/test';
+import { esTestConfig, kbnTestConfig, kibanaServerTestUser } from '@kbn/test';
 import { services } from './services';
 
 export default function () {
@@ -38,19 +38,12 @@ export default function () {
     },
 
     kbnTestServer: {
-      buildArgs: ['--optimize.useBundleCache=true'],
-      sourceArgs: [
-        '--no-base-path',
-        '--env.name=development',
-        `--optimize.bundleDir=${OPTIMIZE_BUNDLE_DIR}`,
-      ],
+      buildArgs: [],
+      sourceArgs: ['--no-base-path', '--env.name=development'],
       serverArgs: [
         '--logging.json=false',
         `--server.port=${kbnTestConfig.getPort()}`,
-        `--optimize.watchPort=${kbnTestConfig.getPort() + 10}`,
-        '--optimize.watchPrebuild=true',
         '--status.allowAnonymous=true',
-        '--optimize.enabled=true',
         `--elasticsearch.hosts=${formatUrl(servers.elasticsearch)}`,
         `--elasticsearch.username=${kibanaServerTestUser.username}`,
         `--elasticsearch.password=${kibanaServerTestUser.password}`,
diff --git a/test/functional/apps/bundles/index.js b/test/functional/apps/bundles/index.js
index f106ea895c2e6..b9c64dae2064c 100644
--- a/test/functional/apps/bundles/index.js
+++ b/test/functional/apps/bundles/index.js
@@ -62,12 +62,5 @@ export default function ({ getService }) {
         .set('Accept-Encoding', 'gzip;q=1.0, br;q=0.5')
         .expect(200)
         .expect('Content-Encoding', 'gzip'));
-
-    it('returns gzip files when no brotli version exists', () =>
-      supertest
-        .get(`/${buildNum}/bundles/light_theme.style.css`) // legacy optimizer does not create brotli outputs
-        .set('Accept-Encoding', 'gzip, br')
-        .expect(200)
-        .expect('Content-Encoding', 'gzip'));
   });
 }
diff --git a/test/plugin_functional/plugins/core_plugin_legacy/index.ts b/test/plugin_functional/plugins/core_plugin_legacy/index.ts
deleted file mode 100644
index 9584927c3cc89..0000000000000
--- a/test/plugin_functional/plugins/core_plugin_legacy/index.ts
+++ /dev/null
@@ -1,50 +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 KbnServer from 'src/legacy/server/kbn_server';
-
-// eslint-disable-next-line import/no-default-export
-export default function (kibana: any) {
-  return new kibana.Plugin({
-    id: 'core_plugin_legacy',
-    require: ['kibana'],
-    uiExports: {
-      app: {
-        id: 'core_legacy_compat',
-        title: 'Core Legacy Compat',
-        description: 'This is a sample plugin to test core to legacy compatibility',
-        main: 'plugins/core_plugin_legacy/index',
-      },
-    },
-    init(server: KbnServer) {
-      const { http } = server.newPlatform.setup.core;
-      const router = http.createRouter();
-
-      router.get({ path: '/api/np-http-in-legacy', validate: false }, async (context, req, res) => {
-        const response = await context.core.elasticsearch.legacy.client.callAsInternalUser('ping');
-        return res.ok({ body: `Pong in legacy via new platform: ${response}` });
-      });
-
-      router.get({ path: '/api/np-context-in-legacy', validate: false }, (context, req, res) => {
-        const contexts = Object.keys(context);
-        return res.ok({ body: { contexts } });
-      });
-    },
-  });
-}
diff --git a/test/plugin_functional/plugins/core_plugin_legacy/package.json b/test/plugin_functional/plugins/core_plugin_legacy/package.json
deleted file mode 100644
index 41c311e8d7153..0000000000000
--- a/test/plugin_functional/plugins/core_plugin_legacy/package.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  "name": "core_plugin_legacy",
-  "version": "1.0.0",
-  "main": "index.ts",
-  "kibana": {
-    "version": "kibana",
-    "templateVersion": "1.0.0"
-  },
-  "license": "Apache-2.0",
-  "scripts": {
-    "kbn": "node ../../../../scripts/kbn.js",
-    "build": "rm -rf './target' && tsc"
-  },
-  "devDependencies": {
-    "typescript": "3.9.5"
-  }
-}
diff --git a/test/plugin_functional/plugins/core_plugin_legacy/public/application.tsx b/test/plugin_functional/plugins/core_plugin_legacy/public/application.tsx
deleted file mode 100644
index ade618ca6cc46..0000000000000
--- a/test/plugin_functional/plugins/core_plugin_legacy/public/application.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Licensed to Elasticsearch B.V. under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch B.V. licenses this file to you under
- * the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import React from 'react';
-import ReactDOM from 'react-dom';
-
-import { AppMountContext, AppMountParameters } from 'kibana/public';
-
-const App = () => 

core_legacy_compat

; - -export const renderApp = ( - context: AppMountContext, - { appBasePath, element }: AppMountParameters -) => { - ReactDOM.render(, element); - - return () => ReactDOM.unmountComponentAtNode(element); -}; diff --git a/test/plugin_functional/plugins/core_plugin_legacy/public/index.ts b/test/plugin_functional/plugins/core_plugin_legacy/public/index.ts deleted file mode 100644 index 51b5d2aaf3587..0000000000000 --- a/test/plugin_functional/plugins/core_plugin_legacy/public/index.ts +++ /dev/null @@ -1,29 +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 { npSetup } from 'ui/new_platform'; - -npSetup.core.application.register({ - id: 'core_legacy_compat', - title: 'Core Legacy Compat', - async mount(context, params) { - const { renderApp } = await import('./application'); - return renderApp(context, params); - }, -}); diff --git a/test/plugin_functional/plugins/core_plugin_legacy/tsconfig.json b/test/plugin_functional/plugins/core_plugin_legacy/tsconfig.json deleted file mode 100644 index 1ba21f11b7de2..0000000000000 --- a/test/plugin_functional/plugins/core_plugin_legacy/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "../../../../tsconfig.json", - "compilerOptions": { - "outDir": "./target", - "skipLibCheck": true - }, - "include": [ - "index.ts", - "public/**/*.ts", - "public/**/*.tsx", - "server/**/*.ts", - "../../../../typings/**/*", - ], - "exclude": [] -} diff --git a/test/plugin_functional/plugins/legacy_plugin/index.ts b/test/plugin_functional/plugins/legacy_plugin/index.ts deleted file mode 100644 index fe171cb24e7b7..0000000000000 --- a/test/plugin_functional/plugins/legacy_plugin/index.ts +++ /dev/null @@ -1,34 +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. - */ - -// eslint-disable-next-line import/no-default-export -export default function (kibana: any) { - return new kibana.Plugin({ - id: 'legacy_plugin', - require: ['kibana'], - uiExports: { - app: { - id: 'legacy_app', - title: 'Legacy App', - description: 'This is a sample plugin to test legacy apps', - main: 'plugins/legacy_plugin/index', - }, - }, - }); -} diff --git a/test/plugin_functional/plugins/legacy_plugin/package.json b/test/plugin_functional/plugins/legacy_plugin/package.json deleted file mode 100644 index c8ec7ffac865b..0000000000000 --- a/test/plugin_functional/plugins/legacy_plugin/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "legacy_plugin", - "version": "1.0.0", - "main": "index.tsx", - "kibana": { - "version": "kibana", - "templateVersion": "1.0.0" - }, - "license": "Apache-2.0", - "scripts": { - "kbn": "node ../../../../scripts/kbn.js", - "build": "rm -rf './target' && tsc" - }, - "devDependencies": { - "typescript": "3.9.5" - } -} diff --git a/test/plugin_functional/plugins/legacy_plugin/public/index.tsx b/test/plugin_functional/plugins/legacy_plugin/public/index.tsx deleted file mode 100644 index aa1b6b068d588..0000000000000 --- a/test/plugin_functional/plugins/legacy_plugin/public/index.tsx +++ /dev/null @@ -1,35 +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 { IScope } from 'angular'; -import React from 'react'; -import ReactDOM from 'react-dom'; - -import chrome from 'ui/chrome'; - -const App = () =>

legacy_app

; - -chrome.setRootController('legacy_app', ($scope: IScope, $element: JQLite) => { - const element = $element[0]; - - ReactDOM.render(, element); - $scope.$on('$destroy', () => { - ReactDOM.unmountComponentAtNode(element); - }); -}); diff --git a/test/plugin_functional/plugins/legacy_plugin/tsconfig.json b/test/plugin_functional/plugins/legacy_plugin/tsconfig.json deleted file mode 100644 index 1ba21f11b7de2..0000000000000 --- a/test/plugin_functional/plugins/legacy_plugin/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "../../../../tsconfig.json", - "compilerOptions": { - "outDir": "./target", - "skipLibCheck": true - }, - "include": [ - "index.ts", - "public/**/*.ts", - "public/**/*.tsx", - "server/**/*.ts", - "../../../../typings/**/*", - ], - "exclude": [] -} diff --git a/test/plugin_functional/test_suites/core_plugins/application_leave_confirm.ts b/test/plugin_functional/test_suites/core_plugins/application_leave_confirm.ts index 98c59717fcac0..7c1e2bc561ac8 100644 --- a/test/plugin_functional/test_suites/core_plugins/application_leave_confirm.ts +++ b/test/plugin_functional/test_suites/core_plugins/application_leave_confirm.ts @@ -54,26 +54,5 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide expect(await browser.getCurrentUrl()).to.eql(getKibanaUrl('/app/appleave2')); }); }); - - describe('when navigating to a legacy app', () => { - it('prevents navigation if user click cancel on the alert dialog', async () => { - await PageObjects.common.navigateToApp('appleave1'); - await appsMenu.clickLink('Core Legacy Compat', { closeCollapsibleNav: false }); - - const alert = await browser.getAlert(); - expect(alert).not.to.eql(null); - alert!.dismiss(); - expect(await browser.getCurrentUrl()).to.eql(getKibanaUrl('/app/appleave1')); - }); - it('allows navigation if user click leave on the alert dialog', async () => { - await PageObjects.common.navigateToApp('appleave1'); - await appsMenu.clickLink('Core Legacy Compat', { closeCollapsibleNav: false }); - - const alert = await browser.getAlert(); - expect(alert).not.to.eql(null); - alert!.accept(); - expect(await browser.getCurrentUrl()).to.eql(getKibanaUrl('/app/core_legacy_compat')); - }); - }); }); } diff --git a/test/plugin_functional/test_suites/core_plugins/index.ts b/test/plugin_functional/test_suites/core_plugins/index.ts index cc498fa10818f..3d7cc751175c6 100644 --- a/test/plugin_functional/test_suites/core_plugins/index.ts +++ b/test/plugin_functional/test_suites/core_plugins/index.ts @@ -22,7 +22,6 @@ export default function ({ loadTestFile }: PluginFunctionalProviderContext) { describe('core plugins', () => { loadTestFile(require.resolve('./applications')); loadTestFile(require.resolve('./elasticsearch_client')); - loadTestFile(require.resolve('./legacy_plugins')); loadTestFile(require.resolve('./server_plugins')); loadTestFile(require.resolve('./ui_plugins')); loadTestFile(require.resolve('./ui_settings')); diff --git a/test/plugin_functional/test_suites/core_plugins/legacy_plugins.ts b/test/plugin_functional/test_suites/core_plugins/legacy_plugins.ts deleted file mode 100644 index d03185796000f..0000000000000 --- a/test/plugin_functional/test_suites/core_plugins/legacy_plugins.ts +++ /dev/null @@ -1,52 +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 expect from '@kbn/expect'; -import { PluginFunctionalProviderContext } from '../../services'; - -export default function ({ getService, getPageObjects }: PluginFunctionalProviderContext) { - const PageObjects = getPageObjects(['common']); - const testSubjects = getService('testSubjects'); - const supertest = getService('supertest'); - - describe('legacy plugins', () => { - describe('http', () => { - it('has access to New Platform HTTP service', async () => { - await supertest - .get('/api/np-http-in-legacy') - .expect(200) - .expect('Pong in legacy via new platform: true'); - }); - - it('has access to New Platform HTTP context providers', async () => { - await supertest - .get('/api/np-context-in-legacy') - .expect(200) - .expect(JSON.stringify({ contexts: ['core', 'pluginA'] })); - }); - }); - - describe('application service compatibility layer', () => { - it('can render legacy apps', async () => { - await PageObjects.common.navigateToApp('core_legacy_compat'); - expect(await testSubjects.exists('coreLegacyCompatH1')).to.be(true); - }); - }); - }); -} diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index 08fd576c036a4..5b83d2d565411 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -104,42 +104,6 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide expect(await exists('renderingHeader')).to.be(true); }); - it('renders "legacy" application', async () => { - await navigateTo('/render/legacy_app'); - - const [loadingMessage, legacyMode, userSettings] = await Promise.all([ - findLoadingMessage(), - getLegacyMode(), - getUserSettings(), - ]); - - expect(legacyMode).to.be(true); - expect(userSettings).to.not.be.empty(); - - await find.waitForElementStale(loadingMessage); - - expect(await exists('legacyAppH1')).to.be(true); - expect(await exists('renderingHeader')).to.be(false); - }); - - it('renders "legacy" application without user settings', async () => { - await navigateTo('/render/legacy_app?includeUserSettings=false'); - - const [loadingMessage, legacyMode, userSettings] = await Promise.all([ - findLoadingMessage(), - getLegacyMode(), - getUserSettings(), - ]); - - expect(legacyMode).to.be(true); - expect(userSettings).to.be.empty(); - - await find.waitForElementStale(loadingMessage); - - expect(await exists('legacyAppH1')).to.be(true); - expect(await exists('renderingHeader')).to.be(false); - }); - it('navigates between standard application and one with custom appRoute', async () => { await navigateTo('/'); await find.waitForElementStale(await findLoadingMessage()); diff --git a/test/scripts/jenkins_xpack.sh b/test/scripts/jenkins_xpack.sh index 77480554f738c..6a56b11344af5 100755 --- a/test/scripts/jenkins_xpack.sh +++ b/test/scripts/jenkins_xpack.sh @@ -3,12 +3,6 @@ source test/scripts/jenkins_test_setup.sh if [[ -z "$CODE_COVERAGE" ]] ; then - echo " -> Building legacy styles for x-pack canvas storyshot tests" - cd "$KIBANA_DIR" - node scripts/build_sass - echo "" - echo "" - echo " -> Running jest tests" cd "$XPACK_DIR" checks-reporter-with-killswitch "X-Pack Jest" node --max-old-space-size=6144 scripts/jest --ci --verbose diff --git a/test/server_integration/config.js b/test/server_integration/config.js index aa9266321664c..b4571dfe68ec4 100644 --- a/test/server_integration/config.js +++ b/test/server_integration/config.js @@ -43,7 +43,6 @@ export default async function ({ readConfigFile }) { ...functionalConfig.get('kbnTestServer'), serverArgs: [ ...functionalConfig.get('kbnTestServer.serverArgs'), - '--optimize.enabled=true', '--elasticsearch.healthCheck.delay=3600000', '--server.xsrf.disableProtection=true', ], diff --git a/test/server_integration/http/cache/index.js b/test/server_integration/http/cache/index.js index 8cca8cf7bd99d..5299ce361327e 100644 --- a/test/server_integration/http/cache/index.js +++ b/test/server_integration/http/cache/index.js @@ -37,10 +37,7 @@ export default function ({ getService }) { }); it('allows the bootstrap bundles to be cached', async () => { - await supertest - .get('/bundles/app/any-old-id-works/bootstrap.js') - .expect('Cache-Control', 'must-revalidate') - .expect(200); + await supertest.get('/bootstrap.js').expect('Cache-Control', 'must-revalidate').expect(200); }); }); } diff --git a/webpackShims/.eslintrc b/webpackShims/.eslintrc deleted file mode 100644 index 4e9ed6ff84316..0000000000000 --- a/webpackShims/.eslintrc +++ /dev/null @@ -1,2 +0,0 @@ -rules: - no-var: 0 diff --git a/webpackShims/ace.js b/webpackShims/ace.js deleted file mode 100644 index 61f319be574dd..0000000000000 --- a/webpackShims/ace.js +++ /dev/null @@ -1,24 +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. - */ - -require('brace'); -require('brace/mode/json'); -require('../node_modules/@elastic/ui-ace/ui-ace'); - -module.exports = window.ace; diff --git a/webpackShims/elasticsearch.js b/webpackShims/elasticsearch.js deleted file mode 100644 index d0ab61818d7a7..0000000000000 --- a/webpackShims/elasticsearch.js +++ /dev/null @@ -1,23 +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. - */ - -module.exports = false; -throw new Error( - 'The elasticsearch npm module is not designed for use in the browser. Please use elasticsearch-browser' -); diff --git a/webpackShims/lru-cache.js b/webpackShims/lru-cache.js deleted file mode 100644 index 9cc11a516378e..0000000000000 --- a/webpackShims/lru-cache.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. - */ - -module.exports = require('../node_modules/lru-cache'); diff --git a/webpackShims/mocha.js b/webpackShims/mocha.js deleted file mode 100644 index 9ab12381b643c..0000000000000 --- a/webpackShims/mocha.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. - */ - -module.exports = require('../node_modules/mocha/mocha.js'); diff --git a/webpackShims/sinon.js b/webpackShims/sinon.js deleted file mode 100644 index e201f405fb127..0000000000000 --- a/webpackShims/sinon.js +++ /dev/null @@ -1,21 +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. - */ - -require('script-loader!../node_modules/sinon/pkg/sinon.js'); -module.exports = window.sinon; diff --git a/x-pack/.kibana-plugin-helpers.json b/x-pack/.kibana-plugin-helpers.json index ca0cae6dd3ca3..c73f2ec595a2a 100644 --- a/x-pack/.kibana-plugin-helpers.json +++ b/x-pack/.kibana-plugin-helpers.json @@ -19,7 +19,6 @@ "legacy/plugins/**/*", "legacy/server/**/*", "typings/**/*", - "webpackShims/*", "!**/README.md", "!__tests__", "!__tests__/**/*", diff --git a/x-pack/legacy/plugins/security/index.ts b/x-pack/legacy/plugins/security/index.ts index addeef34f63bf..3ab5126e52c5f 100644 --- a/x-pack/legacy/plugins/security/index.ts +++ b/x-pack/legacy/plugins/security/index.ts @@ -13,7 +13,6 @@ export const security = (kibana: Record) => publicDir: resolve(__dirname, 'public'), require: ['kibana'], configPrefix: 'xpack.security', - uiExports: { hacks: ['plugins/security/hacks/legacy'] }, config: (Joi: Root) => Joi.object({ enabled: Joi.boolean().default(true) }) .unknown() diff --git a/x-pack/legacy/plugins/security/public/hacks/legacy.ts b/x-pack/legacy/plugins/security/public/hacks/legacy.ts deleted file mode 100644 index ca7e3b7ce5190..0000000000000 --- a/x-pack/legacy/plugins/security/public/hacks/legacy.ts +++ /dev/null @@ -1,64 +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 { uiModules } from 'ui/modules'; -import { npSetup, npStart } from 'ui/new_platform'; -import routes from 'ui/routes'; -import { isSystemApiRequest } from '../../../../../../src/plugins/kibana_legacy/public'; -import { SecurityPluginSetup } from '../../../../../plugins/security/public'; - -const securityPluginSetup = (npSetup.plugins as any).security as SecurityPluginSetup; -if (securityPluginSetup) { - routes.when('/account', { - template: '
', - controller: () => npStart.core.application.navigateToApp('security_account'), - }); - - const getNextParameter = () => { - const { location } = window; - const next = encodeURIComponent(`${location.pathname}${location.search}${location.hash}`); - return `&next=${next}`; - }; - - const getProviderParameter = (tenant: string) => { - const key = `${tenant}/session_provider`; - const providerName = sessionStorage.getItem(key); - return providerName ? `&provider=${encodeURIComponent(providerName)}` : ''; - }; - - const module = uiModules.get('security', []); - module.config(($httpProvider: ng.IHttpProvider) => { - $httpProvider.interceptors.push(($q, $window, Promise) => { - const isAnonymous = npSetup.core.http.anonymousPaths.isAnonymous(window.location.pathname); - - function interceptorFactory(responseHandler: (response: ng.IHttpResponse) => any) { - return function interceptor(response: ng.IHttpResponse) { - if (!isAnonymous && !isSystemApiRequest(response.config)) { - securityPluginSetup.sessionTimeout.extend(response.config.url); - } - - if (response.status !== 401 || isAnonymous) { - return responseHandler(response); - } - - const { logoutUrl, tenant } = securityPluginSetup.__legacyCompat; - const next = getNextParameter(); - const provider = getProviderParameter(tenant); - - $window.location.href = `${logoutUrl}?msg=SESSION_EXPIRED${next}${provider}`; - - return Promise.halt(); - }; - } - - return { - response: interceptorFactory((response) => response), - responseError: interceptorFactory($q.reject), - }; - }); - }); -} diff --git a/x-pack/legacy/plugins/spaces/index.ts b/x-pack/legacy/plugins/spaces/index.ts index 79c57e564b4e1..40339f198df6d 100644 --- a/x-pack/legacy/plugins/spaces/index.ts +++ b/x-pack/legacy/plugins/spaces/index.ts @@ -25,10 +25,6 @@ export const spaces = (kibana: Record) => .default(); }, uiExports: { - managementSections: [], - apps: [], - hacks: ['plugins/spaces/legacy'], - home: [], injectDefaultVars(server: Server) { return { serverBasePath: server.config().get('server.basePath'), diff --git a/x-pack/legacy/plugins/spaces/public/legacy.ts b/x-pack/legacy/plugins/spaces/public/legacy.ts deleted file mode 100644 index 277d6a10547b2..0000000000000 --- a/x-pack/legacy/plugins/spaces/public/legacy.ts +++ /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 { npSetup } from 'ui/new_platform'; -import routes from 'ui/routes'; -import { SpacesPluginSetup } from '../../../../plugins/spaces/public'; - -const spaces = (npSetup.plugins as any).spaces as SpacesPluginSetup; -if (spaces) { - routes.when('/management/spaces/list', { redirectTo: '/management/kibana/spaces' }); - routes.when('/management/spaces/create', { redirectTo: '/management/kibana/spaces/create' }); - routes.when('/management/spaces/edit/:spaceId', { - redirectTo: '/management/kibana/spaces/edit/:spaceId', - }); -} diff --git a/x-pack/legacy/plugins/xpack_main/index.js b/x-pack/legacy/plugins/xpack_main/index.js index b3d4a5fa8214b..b83c5a5ff606e 100644 --- a/x-pack/legacy/plugins/xpack_main/index.js +++ b/x-pack/legacy/plugins/xpack_main/index.js @@ -5,7 +5,6 @@ */ import { resolve } from 'path'; -import dedent from 'dedent'; import { mirrorPluginStatus } from '../../server/lib/mirror_plugin_status'; import { replaceInjectedVars } from './server/lib/replace_injected_vars'; import { setupXPackMain } from './server/lib/setup_xpack_main'; @@ -35,7 +34,6 @@ export const xpackMain = (kibana) => { }, uiExports: { - hacks: ['plugins/xpack_main/hacks/check_xpack_info_change'], replaceInjectedVars, injectDefaultVars(server) { const config = server.config(); @@ -45,15 +43,6 @@ export const xpackMain = (kibana) => { spacesEnabled: config.get('xpack.spaces.enabled'), }; }, - __webpackPluginProvider__(webpack) { - return new webpack.BannerPlugin({ - banner: dedent` - /*! 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. */ - `, - raw: true, - }); - }, }, init(server) { diff --git a/x-pack/legacy/plugins/xpack_main/public/components/index.js b/x-pack/legacy/plugins/xpack_main/public/components/index.js deleted file mode 100644 index 0fe056ec0d46f..0000000000000 --- a/x-pack/legacy/plugins/xpack_main/public/components/index.js +++ /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. - */ - -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -export { LicenseStatus } from '../../../../../plugins/license_management/public/application/sections/license_dashboard/license_status/license_status'; - -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -export { AddLicense } from '../../../../../plugins/license_management/public/application/sections/license_dashboard/add_license/add_license'; - -/* - * For to link to management - */ -export { BASE_PATH as MANAGEMENT_BASE_PATH } from '../../../../../plugins/license_management/common/constants'; diff --git a/x-pack/legacy/plugins/xpack_main/public/hacks/check_xpack_info_change.js b/x-pack/legacy/plugins/xpack_main/public/hacks/check_xpack_info_change.js deleted file mode 100644 index 9047cdc15e93c..0000000000000 --- a/x-pack/legacy/plugins/xpack_main/public/hacks/check_xpack_info_change.js +++ /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 { identity } from 'lodash'; -import { uiModules } from 'ui/modules'; -import { Path } from 'plugins/xpack_main/services/path'; -import { xpackInfo } from 'plugins/xpack_main/services/xpack_info'; -import { xpackInfoSignature } from 'plugins/xpack_main/services/xpack_info_signature'; - -const module = uiModules.get('xpack_main', []); - -module.factory('checkXPackInfoChange', ($q, Private, $injector) => { - /** - * Intercept each network response to look for the kbn-xpack-sig header. - * When that header is detected, compare its value with the value cached - * in the browser storage. When the value is new, call `xpackInfo.refresh()` - * so that it will pull down the latest x-pack info - * - * @param {object} response - the angular $http response object - * @param {function} handleResponse - callback, expects to receive the response - * @return - */ - function interceptor(response, handleResponse) { - if (Path.isUnauthenticated()) { - return handleResponse(response); - } - - const currentSignature = response.headers('kbn-xpack-sig'); - const cachedSignature = xpackInfoSignature.get(); - - if (currentSignature && cachedSignature !== currentSignature) { - // Signature from the server differ from the signature of our - // cached info, so we need to refresh it. - // Intentionally swallowing this error - // because nothing catches it and it's an ugly console error. - xpackInfo.refresh($injector).catch(() => {}); - } - - return handleResponse(response); - } - - return { - response: (response) => interceptor(response, identity), - responseError: (response) => interceptor(response, $q.reject), - }; -}); - -module.config(($httpProvider) => { - $httpProvider.interceptors.push('checkXPackInfoChange'); -}); diff --git a/x-pack/legacy/plugins/xpack_main/public/jquery_flot/index.js b/x-pack/legacy/plugins/xpack_main/public/jquery_flot/index.js deleted file mode 100644 index abf060aca8c08..0000000000000 --- a/x-pack/legacy/plugins/xpack_main/public/jquery_flot/index.js +++ /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 { default } from './jquery_flot'; diff --git a/x-pack/legacy/plugins/xpack_main/public/jquery_flot/jquery_flot.js b/x-pack/legacy/plugins/xpack_main/public/jquery_flot/jquery_flot.js deleted file mode 100644 index 696ff500f3c28..0000000000000 --- a/x-pack/legacy/plugins/xpack_main/public/jquery_flot/jquery_flot.js +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import $ from 'jquery'; -if (window) { - window.jQuery = $; -} -import 'ui/flot-charts/jquery.flot'; - -// load flot plugins -// avoid the `canvas` plugin, it causes blurry fonts -import 'ui/flot-charts/jquery.flot.time'; -import 'ui/flot-charts/jquery.flot.crosshair'; -import 'ui/flot-charts/jquery.flot.selection'; - -export default $; diff --git a/x-pack/legacy/plugins/xpack_main/public/services/__tests__/_mock_window.js b/x-pack/legacy/plugins/xpack_main/public/services/__tests__/_mock_window.js deleted file mode 100644 index 5e4e0dbf6c6be..0000000000000 --- a/x-pack/legacy/plugins/xpack_main/public/services/__tests__/_mock_window.js +++ /dev/null @@ -1,23 +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. - */ - -const items = {}; -export const mockWindow = { - sessionStorage: { - setItem(key, value) { - items[key] = value; - }, - getItem(key) { - return items[key]; - }, - removeItem(key) { - delete items[key]; - }, - }, - location: { - pathname: '', - }, -}; diff --git a/x-pack/legacy/plugins/xpack_main/public/services/__tests__/xpack_info.js b/x-pack/legacy/plugins/xpack_main/public/services/__tests__/xpack_info.js deleted file mode 100644 index e951590c399e1..0000000000000 --- a/x-pack/legacy/plugins/xpack_main/public/services/__tests__/xpack_info.js +++ /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 expect from '@kbn/expect'; -import { xpackInfo } from 'plugins/xpack_main/services/xpack_info'; - -const XPACK_INFO_KEY = 'xpackMain.info'; - -describe('xpack_info service', () => { - afterEach(() => { - sessionStorage.clear(); - }); - - it('updates the stored xpack info', () => { - const updatedXPackInfo = { - foo: { - bar: 17, - }, - }; - xpackInfo.setAll(updatedXPackInfo); - expect(sessionStorage.getItem(XPACK_INFO_KEY)).to.be(JSON.stringify(updatedXPackInfo)); - expect(xpackInfo.get('foo.bar')).to.be(17); - }); - - it('clears the stored xpack info', () => { - const updatedXPackInfo = { - foo: { - bar: 17, - }, - }; - xpackInfo.setAll(updatedXPackInfo); - expect(xpackInfo.get('foo.bar')).not.to.be(null); - - xpackInfo.clear(); - expect(sessionStorage.getItem(XPACK_INFO_KEY)).to.be(null); - expect(xpackInfo.get('foo.bar')).to.be(undefined); - }); - - it('defaults to the provided default value if the requested path is not found', () => { - xpackInfo.setAll({ foo: 'bar' }); - expect(xpackInfo.get('foo.baz', 17)).to.be(17); - }); -}); diff --git a/x-pack/legacy/plugins/xpack_main/public/services/__tests__/xpack_info_signature.js b/x-pack/legacy/plugins/xpack_main/public/services/__tests__/xpack_info_signature.js deleted file mode 100644 index 3a8bd99257995..0000000000000 --- a/x-pack/legacy/plugins/xpack_main/public/services/__tests__/xpack_info_signature.js +++ /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 expect from '@kbn/expect'; -import { xpackInfoSignature } from 'plugins/xpack_main/services/xpack_info_signature'; - -describe('xpack_info_signature service', () => { - it('updates the stored xpack info signature', () => { - const updatedXPackInfoSignature = 'foobar'; - xpackInfoSignature.set(updatedXPackInfoSignature); - expect(xpackInfoSignature.get()).to.be(updatedXPackInfoSignature); - }); - - it('clears the stored xpack info signature', () => { - const updatedXPackInfoSignature = 'foobar'; - xpackInfoSignature.set(updatedXPackInfoSignature); - expect(xpackInfoSignature.get()).not.to.be(undefined); - xpackInfoSignature.clear(); - expect(xpackInfoSignature.get()).to.be(null); - }); -}); diff --git a/x-pack/legacy/plugins/xpack_main/public/services/path.js b/x-pack/legacy/plugins/xpack_main/public/services/path.js deleted file mode 100644 index d2fe550178e61..0000000000000 --- a/x-pack/legacy/plugins/xpack_main/public/services/path.js +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import chrome from 'ui/chrome'; - -export const Path = { - isUnauthenticated() { - const path = chrome.removeBasePath(window.location.pathname); - return ( - path === '/login' || - path === '/logout' || - path === '/security/logged_out' || - path === '/status' - ); - }, -}; diff --git a/x-pack/legacy/plugins/xpack_main/public/services/xpack_info.js b/x-pack/legacy/plugins/xpack_main/public/services/xpack_info.js deleted file mode 100644 index 8e514b7040520..0000000000000 --- a/x-pack/legacy/plugins/xpack_main/public/services/xpack_info.js +++ /dev/null @@ -1,76 +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 { get } from 'lodash'; -import chrome from 'ui/chrome'; -import { xpackInfoSignature } from './xpack_info_signature'; -import { convertKeysToCamelCaseDeep } from '../../../../server/lib/key_case_converter'; - -const XPACK_INFO_KEY = 'xpackMain.info'; - -export class XPackInfo { - constructor(initialInfo = {}) { - this.inProgressRefreshPromise = null; - this.setAll(initialInfo); - } - - get = (path, defaultValue = undefined) => { - const xpackInfoValuesJson = window.sessionStorage.getItem(XPACK_INFO_KEY); - const xpackInfoValues = xpackInfoValuesJson ? JSON.parse(xpackInfoValuesJson) : {}; - return get(xpackInfoValues, path, defaultValue); - }; - - setAll = (updatedXPackInfo) => { - // The decision to convert kebab-case/snake-case keys to camel-case keys stemmed from an old - // convention of using kebabe-case/snake-case in API response bodies but camel-case in JS - // objects. See pull #29304 for more info. - const camelCasedXPackInfo = convertKeysToCamelCaseDeep(updatedXPackInfo); - // guarding sessionStorage for testing - typeof sessionStorage !== 'undefined' && - sessionStorage.setItem(XPACK_INFO_KEY, JSON.stringify(camelCasedXPackInfo)); - }; - - clear = () => { - sessionStorage.removeItem(XPACK_INFO_KEY); - }; - - refresh = ($injector) => { - if (this.inProgressRefreshPromise) { - return this.inProgressRefreshPromise; - } - - // store the promise in a shared location so that calls to - // refresh() before this is complete will get the same promise - const $http = $injector.get('$http'); - this.inProgressRefreshPromise = $http - .get(chrome.addBasePath('/api/xpack/v1/info')) - .catch((err) => { - // if we are unable to fetch the updated info, we should - // prevent reusing stale info - this.clear(); - xpackInfoSignature.clear(); - throw err; - }) - .then((xpackInfoResponse) => { - this.setAll(xpackInfoResponse.data); - xpackInfoSignature.set(xpackInfoResponse.headers('kbn-xpack-sig')); - }) - .finally(() => { - this.inProgressRefreshPromise = null; - }); - return this.inProgressRefreshPromise; - }; - - getLicense = () => { - return this.get('license', { - isActive: false, - type: undefined, - expiryDateInMillis: undefined, - }); - }; -} - -export const xpackInfo = new XPackInfo(chrome.getInjected('xpackInitialInfo')); diff --git a/x-pack/legacy/plugins/xpack_main/public/services/xpack_info_signature.js b/x-pack/legacy/plugins/xpack_main/public/services/xpack_info_signature.js deleted file mode 100644 index 75aba933d37e1..0000000000000 --- a/x-pack/legacy/plugins/xpack_main/public/services/xpack_info_signature.js +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -const XPACK_INFO_SIG_KEY = 'xpackMain.infoSignature'; - -export const xpackInfoSignature = { - get() { - return sessionStorage.getItem(XPACK_INFO_SIG_KEY); - }, - set(updatedXPackInfoSignature) { - sessionStorage.setItem(XPACK_INFO_SIG_KEY, updatedXPackInfoSignature); - }, - clear() { - sessionStorage.removeItem(XPACK_INFO_SIG_KEY); - }, -}; diff --git a/x-pack/plugins/canvas/public/components/datasource/datasource_preview/datasource_preview.js b/x-pack/plugins/canvas/public/components/datasource/datasource_preview/datasource_preview.js index 13cd2c5cd11f7..75f2736be3946 100644 --- a/x-pack/plugins/canvas/public/components/datasource/datasource_preview/datasource_preview.js +++ b/x-pack/plugins/canvas/public/components/datasource/datasource_preview/datasource_preview.js @@ -5,7 +5,6 @@ */ import React from 'react'; -import { FormattedMessage } from '@kbn/i18n/react'; import PropTypes from 'prop-types'; import { EuiOverlayMask, @@ -18,6 +17,7 @@ import { EuiEmptyPrompt, EuiSpacer, } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; import { Datatable } from '../../datatable'; import { Error } from '../../error'; import { ComponentStrings } from '../../../../i18n'; diff --git a/x-pack/plugins/canvas/public/expression_types/arg_types/font.js b/x-pack/plugins/canvas/public/expression_types/arg_types/font.js index 5d0e6b3dd688e..553d6c4ab5642 100644 --- a/x-pack/plugins/canvas/public/expression_types/arg_types/font.js +++ b/x-pack/plugins/canvas/public/expression_types/arg_types/font.js @@ -6,8 +6,8 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { set } from '@elastic/safer-lodash-set'; import { get, mapValues } from 'lodash'; +import { set } from '@elastic/safer-lodash-set'; import { openSans } from '../../../common/lib/fonts'; import { templateFromReactComponent } from '../../lib/template_from_react_component'; import { TextStylePicker } from '../../components/text_style_picker'; diff --git a/x-pack/plugins/canvas/scripts/shareable_runtime.js b/x-pack/plugins/canvas/scripts/shareable_runtime.js index f867e4dc77a11..a5f5f953727ac 100644 --- a/x-pack/plugins/canvas/scripts/shareable_runtime.js +++ b/x-pack/plugins/canvas/scripts/shareable_runtime.js @@ -30,12 +30,6 @@ run( buffer: false, }; - log.info('pre-req: Ensuring Kibana SCSS is built.'); - // Ensure SASS has been built completely before building the runtime. - execa.sync(process.execPath, ['scripts/build_sass'], { - ...options, - }); - const webpackConfig = path.resolve(SHAREABLE_RUNTIME_SRC, 'webpack.config.js'); const clean = () => { diff --git a/x-pack/plugins/canvas/scripts/storybook.js b/x-pack/plugins/canvas/scripts/storybook.js index 671de53d74407..23703810569b6 100644 --- a/x-pack/plugins/canvas/scripts/storybook.js +++ b/x-pack/plugins/canvas/scripts/storybook.js @@ -12,11 +12,6 @@ const storybook = require('@storybook/react/standalone'); const execa = require('execa'); const { DLL_OUTPUT } = require('./../storybook/constants'); -const options = { - stdio: ['ignore', 'inherit', 'inherit'], - buffer: false, -}; - const storybookOptions = { configDir: path.resolve(__dirname, './../storybook'), mode: 'dev', @@ -35,12 +30,6 @@ run( } } - // Ensure SASS dependencies have been built before doing anything. - execa.sync(process.execPath, ['scripts/build_sass'], { - cwd: path.resolve(__dirname, '../../../..'), - ...options, - }); - // Build the DLL if necessary. if (fs.existsSync(DLL_OUTPUT)) { log.info('storybook: DLL exists from previous build; skipping'); @@ -101,12 +90,6 @@ run( log.info('storybook: Starting Storybook'); - // Watch the SASS sheets for changes - execa(process.execPath, ['scripts/build_sass', '--watch'], { - cwd: path.resolve(__dirname, '../../../..'), - ...options, - }); - if (addon) { execa('node', ['scripts/build', '--watch'], { cwd: path.resolve(__dirname, '../storybook/addon'), diff --git a/x-pack/plugins/canvas/shareable_runtime/index.ts b/x-pack/plugins/canvas/shareable_runtime/index.ts index 11ada0a468cb2..6e32bd9014d46 100644 --- a/x-pack/plugins/canvas/shareable_runtime/index.ts +++ b/x-pack/plugins/canvas/shareable_runtime/index.ts @@ -5,23 +5,8 @@ */ export * from './api'; -import '../../../../built_assets/css/plugins/kibana/index.light.css'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import '../../../../src/core/server/core_app/assets/legacy_light_theme.css'; import '../public/style/index.scss'; import '@elastic/eui/dist/eui_theme_light.css'; import '@kbn/ui-framework/dist/kui_light.css'; - -const css = require.context( - '../../../../built_assets/css', - true, - /\.\/plugins\/(?!canvas).*light\.css/ -); -css.keys().forEach((filename) => { - css(filename); -}); - -const uiStyles = require.context( - '../../../../src/legacy/ui/public/styles', - false, - /[\/\\](?!mixins|variables|_|\.|bootstrap_(light|dark))[^\/\\]+\.less/ -); -uiStyles.keys().forEach((key) => uiStyles(key)); diff --git a/x-pack/plugins/canvas/shareable_runtime/webpack.config.js b/x-pack/plugins/canvas/shareable_runtime/webpack.config.js index 43e422a161569..3517c958b27b8 100644 --- a/x-pack/plugins/canvas/shareable_runtime/webpack.config.js +++ b/x-pack/plugins/canvas/shareable_runtime/webpack.config.js @@ -43,6 +43,7 @@ module.exports = { 'src/legacy/core_plugins/interpreter/public/types' ), tinymath: path.resolve(KIBANA_ROOT, 'node_modules/tinymath/lib/tinymath.es5.js'), + core_app_image_assets: path.resolve(KIBANA_ROOT, 'src/core/public/core_app/images'), }, extensions: ['.js', '.json', '.ts', '.tsx', '.scss'], }, @@ -123,22 +124,6 @@ module.exports = { }, ], }, - { - test: /\.less$/, - use: [ - { loader: 'style-loader' }, - { loader: 'css-loader', options: { importLoaders: 2 } }, - { - loader: 'postcss-loader', - options: { - config: { - path: require.resolve('./postcss.config.js'), - }, - }, - }, - { loader: 'less-loader' }, - ], - }, { test: /\.scss$/, exclude: [/node_modules/, /\.module\.s(a|c)ss$/], @@ -161,34 +146,13 @@ module.exports = { }, }, }, - { - loader: 'resolve-url-loader', - options: { - // eslint-disable-next-line no-unused-vars - join: (_, __) => (uri, base) => { - if (!base) { - return null; - } - - // manually force ui/* urls in legacy styles to resolve to ui/legacy/public - if (uri.startsWith('ui/') && base.split(path.sep).includes('legacy')) { - return path.resolve(KIBANA_ROOT, 'src/legacy/ui/public', uri.replace('ui/', '')); - } - - return null; - }, - }, - }, { loader: 'sass-loader', options: { - // must always be enabled as long as we're using the `resolve-url-loader` to - // rewrite `ui/*` urls. They're dropped by subsequent loaders though - sourceMap: true, prependData(loaderContext) { return `@import ${stringifyRequest( loaderContext, - path.resolve(KIBANA_ROOT, 'src/legacy/ui/public/styles/_globals_v7light.scss') + path.resolve(KIBANA_ROOT, 'src/core/public/core_app/styles/_globals_v7light.scss') )};\n`; }, webpackImporter: false, diff --git a/x-pack/plugins/canvas/storybook/constants.js b/x-pack/plugins/canvas/storybook/constants.js index 258bf208ed877..ff0162bf0a200 100644 --- a/x-pack/plugins/canvas/storybook/constants.js +++ b/x-pack/plugins/canvas/storybook/constants.js @@ -8,12 +8,10 @@ const path = require('path'); const DLL_NAME = 'canvas_storybook_dll'; const KIBANA_ROOT = path.resolve(__dirname, '../../../..'); -const BUILT_ASSETS = path.resolve(KIBANA_ROOT, 'built_assets'); -const DLL_OUTPUT = path.resolve(BUILT_ASSETS, DLL_NAME); +const DLL_OUTPUT = path.resolve(KIBANA_ROOT, 'built_assets', DLL_NAME); module.exports = { DLL_NAME, KIBANA_ROOT, - BUILT_ASSETS, DLL_OUTPUT, }; diff --git a/x-pack/plugins/canvas/storybook/dll_contexts.js b/x-pack/plugins/canvas/storybook/dll_contexts.js index 85f2ab66cab88..02ceafd0b3983 100644 --- a/x-pack/plugins/canvas/storybook/dll_contexts.js +++ b/x-pack/plugins/canvas/storybook/dll_contexts.js @@ -8,24 +8,8 @@ // is also require'd in the Storybook config so that the Storybook Webpack instance // is aware of them, and can load them from the DLL. -// Pull in the built CSS produced by the Kibana server, but not -// the Canvas CSS-- we want that in the HMR service. -const css = require.context( - '../../../../built_assets/css', - true, - /\.\/plugins\/(?!canvas).*light\.css/ -); -css.keys().forEach((filename) => { - css(filename); -}); - -// Include Legacy styles -const uiStyles = require.context( - '../../../../src/legacy/ui/public/styles', - false, - /[\/\\](?!mixins|variables|_|\.|bootstrap_(light|dark))[^\/\\]+\.less/ -); -uiStyles.keys().forEach((key) => uiStyles(key)); +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +require('../../../../src/core/server/core_app/assets/legacy_light_theme.css'); const json = require.context('../shareable_runtime/test/workpads', false, /\.json$/); json.keys().forEach((key) => json(key)); diff --git a/x-pack/plugins/canvas/storybook/preview.ts b/x-pack/plugins/canvas/storybook/preview.ts index fc194664c84b8..5eb40cad86d32 100644 --- a/x-pack/plugins/canvas/storybook/preview.ts +++ b/x-pack/plugins/canvas/storybook/preview.ts @@ -25,12 +25,3 @@ startServices({ }); addDecorators(); - -// Only gather and require CSS files related to Canvas. The other CSS files -// are built into the DLL. -const css = require.context( - '../../../../built_assets/css', - true, - /plugins\/(?=canvas).*light\.css/ -); -css.keys().forEach((filename) => css(filename)); diff --git a/x-pack/plugins/canvas/storybook/webpack.config.js b/x-pack/plugins/canvas/storybook/webpack.config.js index 1321ade30bbde..c9817de649c25 100644 --- a/x-pack/plugins/canvas/storybook/webpack.config.js +++ b/x-pack/plugins/canvas/storybook/webpack.config.js @@ -57,7 +57,10 @@ module.exports = async ({ config: storybookConfig }) => { prependData(loaderContext) { return `@import ${stringifyRequest( loaderContext, - path.resolve(KIBANA_ROOT, 'src/legacy/ui/public/styles/_globals_v7light.scss') + path.resolve( + KIBANA_ROOT, + 'src/core/public/core_app/styles/_globals_v7light.scss' + ) )};\n`; }, sassOptions: { diff --git a/x-pack/plugins/canvas/storybook/webpack.dll.config.js b/x-pack/plugins/canvas/storybook/webpack.dll.config.js index 4e54750f08eea..b830f72692ede 100644 --- a/x-pack/plugins/canvas/storybook/webpack.dll.config.js +++ b/x-pack/plugins/canvas/storybook/webpack.dll.config.js @@ -103,22 +103,6 @@ module.exports = { }, ], }, - { - test: /\.less$/, - use: [ - { loader: 'style-loader' }, - { loader: 'css-loader', options: { importLoaders: 2 } }, - { - loader: 'postcss-loader', - options: { - config: { - path: require.resolve('@kbn/optimizer/postcss.config.js'), - }, - }, - }, - { loader: 'less-loader' }, - ], - }, { test: /\.(woff|woff2|ttf|eot|svg|ico)(\?|$)/, loader: 'file-loader', diff --git a/x-pack/plugins/graph/public/application.ts b/x-pack/plugins/graph/public/application.ts index b249fe2be32c7..a9ba464016157 100644 --- a/x-pack/plugins/graph/public/application.ts +++ b/x-pack/plugins/graph/public/application.ts @@ -9,7 +9,11 @@ // They can stay even after NP cutover import angular from 'angular'; import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular'; -import '../../../../webpackShims/ace'; + +import 'brace'; +import 'brace/mode/json'; +import '@elastic/ui-ace/ui-ace'; + // required for i18nIdDirective and `ngSanitize` angular module import 'angular-sanitize'; // required for ngRoute diff --git a/x-pack/test/api_integration/config.ts b/x-pack/test/api_integration/config.ts index 71c5bb82accef..3b4654fc357c0 100644 --- a/x-pack/test/api_integration/config.ts +++ b/x-pack/test/api_integration/config.ts @@ -26,7 +26,6 @@ export async function getApiIntegrationConfig({ readConfigFile }: FtrConfigProvi serverArgs: [ ...xPackFunctionalTestsConfig.get('kbnTestServer.serverArgs'), '--xpack.security.session.idleTimeout=3600000', // 1 hour - '--optimize.enabled=false', '--telemetry.optIn=true', '--xpack.ingestManager.enabled=true', '--xpack.ingestManager.fleet.pollingRequestTimeout=5000', // 5 seconds diff --git a/x-pack/test/login_selector_api_integration/config.ts b/x-pack/test/login_selector_api_integration/config.ts index 67bc2e6f17b56..fb711a8bef488 100644 --- a/x-pack/test/login_selector_api_integration/config.ts +++ b/x-pack/test/login_selector_api_integration/config.ts @@ -112,7 +112,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { serverArgs: [ ...xPackAPITestsConfig.get('kbnTestServer.serverArgs'), `--plugin-path=${oidcIdPPlugin}`, - '--optimize.enabled=false', '--server.ssl.enabled=true', `--server.ssl.key=${KBN_KEY_PATH}`, `--server.ssl.certificate=${KBN_CERT_PATH}`, diff --git a/x-pack/test/saml_api_integration/config.ts b/x-pack/test/saml_api_integration/config.ts index 1bc85a803a7c2..9edadca4c1667 100644 --- a/x-pack/test/saml_api_integration/config.ts +++ b/x-pack/test/saml_api_integration/config.ts @@ -49,7 +49,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { ...xPackAPITestsConfig.get('kbnTestServer'), serverArgs: [ ...xPackAPITestsConfig.get('kbnTestServer.serverArgs'), - '--optimize.enabled=false', `--xpack.security.authc.providers=${JSON.stringify(['saml', 'basic'])}`, '--xpack.security.authc.saml.realm=saml1', '--xpack.security.authc.saml.maxRedirectURLSize=100b', diff --git a/x-pack/test/saved_object_api_integration/common/config.ts b/x-pack/test/saved_object_api_integration/common/config.ts index 378f27082d9e0..4bae8e48173e4 100644 --- a/x-pack/test/saved_object_api_integration/common/config.ts +++ b/x-pack/test/saved_object_api_integration/common/config.ts @@ -53,7 +53,6 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) ...config.xpack.api.get('kbnTestServer'), serverArgs: [ ...config.xpack.api.get('kbnTestServer.serverArgs'), - '--optimize.enabled=false', '--server.xsrf.disableProtection=true', `--plugin-path=${path.join(__dirname, 'fixtures', 'saved_object_test_plugin')}`, ...disabledPlugins.map((key) => `--xpack.${key}.enabled=false`), diff --git a/x-pack/test/spaces_api_integration/common/config.ts b/x-pack/test/spaces_api_integration/common/config.ts index 89a49c7d3d4fa..d734c5a6ba422 100644 --- a/x-pack/test/spaces_api_integration/common/config.ts +++ b/x-pack/test/spaces_api_integration/common/config.ts @@ -62,7 +62,6 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) ...config.xpack.api.get('kbnTestServer'), serverArgs: [ ...config.xpack.api.get('kbnTestServer.serverArgs'), - '--optimize.enabled=false', // disable anonymouse access so that we're testing both on and off in different suites '--status.allowAnonymous=false', '--server.xsrf.disableProtection=true', diff --git a/x-pack/test/token_api_integration/config.js b/x-pack/test/token_api_integration/config.js index 31ec2f1bc6bfb..3e78a98067a8f 100644 --- a/x-pack/test/token_api_integration/config.js +++ b/x-pack/test/token_api_integration/config.js @@ -32,7 +32,6 @@ export default async function ({ readConfigFile }) { ...xPackAPITestsConfig.get('kbnTestServer'), serverArgs: [ ...xPackAPITestsConfig.get('kbnTestServer.serverArgs'), - '--optimize.enabled=false', '--xpack.security.authc.providers=["token"]', ], }, diff --git a/x-pack/test/upgrade_assistant_integration/config.js b/x-pack/test/upgrade_assistant_integration/config.js index 386e34f4f98b7..d11b39ff74e35 100644 --- a/x-pack/test/upgrade_assistant_integration/config.js +++ b/x-pack/test/upgrade_assistant_integration/config.js @@ -31,13 +31,7 @@ export default async function ({ readConfigFile }) { junit: { reportName: 'X-Pack Upgrade Assistant Integration Tests', }, - kbnTestServer: { - ...xPackFunctionalTestsConfig.get('kbnTestServer'), - serverArgs: [ - ...xPackFunctionalTestsConfig.get('kbnTestServer.serverArgs'), - '--optimize.enabled=false', - ], - }, + kbnTestServer: xPackFunctionalTestsConfig.get('kbnTestServer'), esTestCluster: { ...xPackFunctionalTestsConfig.get('esTestCluster'), dataArchive: path.resolve(__dirname, './fixtures/data_archives/upgrade_assistant.zip'), diff --git a/yarn.lock b/yarn.lock index 42c4b800e6b0c..3a6f59fa8ef3f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3399,7 +3399,7 @@ 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": +"@types/babel-types@*": version "7.0.4" resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-7.0.4.tgz#bfd5b0d0d1ba13e351dff65b6e52783b816826c8" integrity sha512-WiZhq3SVJHFRgRYLXvpf65XnV6ipVHhnNaNvE8yCimejrGglkg38kEj0JcizqwSHxmPSjcTlig/6JouxLGEhGw== @@ -3462,13 +3462,6 @@ dependencies: "@types/babel-types" "*" -"@types/babylon@^6.16.2": - version "6.16.3" - resolved "https://registry.yarnpkg.com/@types/babylon/-/babylon-6.16.3.tgz#c2937813a89fcb5e79a00062fc4a8b143e7237bb" - integrity sha512-lyJ8sW1PbY3uwuvpOBZ9zMYKshMnQpXmeDHh8dj9j2nJm/xrW0FgB5gLSYOArj5X0IfaXnmhFoJnhS4KbqIMug== - dependencies: - "@types/babel-types" "*" - "@types/base64-js@^1.2.5": version "1.2.5" resolved "https://registry.yarnpkg.com/@types/base64-js/-/base64-js-1.2.5.tgz#582b2476169a6cba460a214d476c744441d873d5" @@ -4243,13 +4236,6 @@ dependencies: "@types/node" "*" -"@types/node-sass@^4.11.0": - version "4.11.0" - resolved "https://registry.yarnpkg.com/@types/node-sass/-/node-sass-4.11.0.tgz#b0372075546e83f39df52bd37359eab00165a04d" - integrity sha512-uNpVWhwVmbB5luE7b8vxcJwu5np75YkVTBJS0O3ar+hrxqLfyhOKXg9NYBwJ6mMQX/V6/8d6mMZTB7x2r5x9Bw== - dependencies: - "@types/node" "*" - "@types/node@*", "@types/node@8.10.54", "@types/node@>=10.17.17 <10.20.0", "@types/node@>=8.9.0", "@types/node@^12.0.2": version "10.17.26" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.26.tgz#a8a119960bff16b823be4c617da028570779bcfd" @@ -5332,13 +5318,6 @@ accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" -acorn-globals@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf" - integrity sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8= - dependencies: - acorn "^4.0.4" - acorn-globals@^4.3.0, acorn-globals@^4.3.2: version "4.3.4" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" @@ -5383,16 +5362,11 @@ acorn@5.X, acorn@^5.0.3, acorn@^5.5.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e" integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg== -acorn@^3.0.4, acorn@^3.1.0: +acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" integrity sha1-ReN/s56No/JbruP/U2niu18iAXo= -acorn@^4.0.4, acorn@~4.0.2: - version "4.0.13" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" - integrity sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c= - acorn@^6.0.1, acorn@^6.0.4, acorn@^6.2.1: version "6.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" @@ -5418,17 +5392,6 @@ address@^1.0.1: resolved "https://registry.yarnpkg.com/address/-/address-1.0.3.tgz#b5f50631f8d6cec8bd20c963963afb55e06cbce9" integrity sha512-z55ocwKBRLryBs394Sm3ushTtBeg6VAeuku7utSoSnsJKvKcnXFIyC6vh27n3rXyxSgkJBBCAvyOn7gSUcTYjg== -adjust-sourcemap-loader@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/adjust-sourcemap-loader/-/adjust-sourcemap-loader-2.0.0.tgz#6471143af75ec02334b219f54bc7970c52fb29a4" - integrity sha512-4hFsTsn58+YjrU9qKzML2JSSDqKvN8mUGQ0nNIrfPi8hmIONT4L3uUaT6MKdMsZ9AjsU6D2xDkZxCkbQPxChrA== - dependencies: - assert "1.4.1" - camelcase "5.0.0" - loader-utils "1.2.3" - object-path "0.11.4" - regex-parser "2.2.10" - adm-zip@0.4.16: version "0.4.16" resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.16.tgz#cf4c508fdffab02c269cbc7f471a875f05570365" @@ -6185,11 +6148,6 @@ aria-query@3.0.0, aria-query@^3.0.0: ast-types-flow "0.0.7" commander "^2.11.0" -arity-n@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/arity-n/-/arity-n-1.0.4.tgz#d9e76b11733e08569c0847ae7b39b2860b30b745" - integrity sha1-2edrEXM+CFacCEeuezmyhgswt0U= - arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" @@ -6442,7 +6400,7 @@ assert-plus@^0.2.0: resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" integrity sha1-104bh+ev/A24qttwIfP+SBAasjQ= -assert@1.4.1, assert@^1.1.1: +assert@^1.1.1: version "1.4.1" resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" integrity sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE= @@ -6530,16 +6488,11 @@ async-foreach@^0.1.3: resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI= -async-limiter@^1.0.0: +async-limiter@^1.0.0, async-limiter@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== -async-limiter@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" - integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== - async-retry@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.2.3.tgz#a6521f338358d322b1a0012b79030c6f411d1ce0" @@ -6566,33 +6519,12 @@ async-value@^1.2.2: resolved "https://registry.yarnpkg.com/async-value/-/async-value-1.2.2.tgz#84517a1e7cb6b1a5b5e181fa31be10437b7fb125" integrity sha1-hFF6Hny2saW14YH6Mb4QQ3t/sSU= -async@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/async/-/async-2.4.0.tgz#4990200f18ea5b837c2cc4f8c031a6985c385611" - integrity sha1-SZAgDxjqW4N8LMT4wDGmmFw4VhE= - dependencies: - lodash "^4.14.0" - async@^1.4.2, async@^1.5.2, async@~1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= -async@^2.0.0, async@^2.1.4: - version "2.6.0" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4" - integrity sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw== - 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: +async@^2.0.0, async@^2.1.4, async@^2.6.0, async@^2.6.1, async@^2.6.2, async@^2.6.3: version "2.6.3" resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== @@ -7832,11 +7764,6 @@ buffer-indexof@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== -buffer-json@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/buffer-json/-/buffer-json-2.0.0.tgz#f73e13b1e42f196fe2fd67d001c7d7107edd7c23" - integrity sha512-+jjPFVqyfF1esi9fvfUs3NqM0pH1ziZ36VP4hmA/y/Ssfo/5w5xHKfTw9BwQjoJ1w/oVtpLomqwUHKdefGyuHw== - buffer-xor@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" @@ -8001,18 +7928,6 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" -cache-loader@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cache-loader/-/cache-loader-4.1.0.tgz#9948cae353aec0a1fcb1eafda2300816ec85387e" - integrity sha512-ftOayxve0PwKzBF/GLsZNC9fJBXl8lkZE3TOsjkboHfVHVkL39iUEs1FO07A33mizmci5Dudt38UZrrYXDtbhw== - dependencies: - buffer-json "^2.0.0" - find-cache-dir "^3.0.0" - loader-utils "^1.2.3" - mkdirp "^0.5.1" - neo-async "^2.6.1" - schema-utils "^2.0.0" - cacheable-lookup@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-2.0.1.tgz#87be64a18b925234875e10a9bb1ebca4adce6b38" @@ -8166,16 +8081,6 @@ camelcase-keys@^6.2.2: map-obj "^4.0.0" quick-lru "^4.0.1" -camelcase@5.0.0, camelcase@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" - integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== - -camelcase@5.3.1, camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - camelcase@^1.0.2: version "1.2.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" @@ -8196,6 +8101,11 @@ camelcase@^4.0.0, camelcase@^4.1.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= +camelcase@^5.0.0, camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + camelcase@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.0.0.tgz#5259f7c30e35e278f1bdc2a4d91230b37cad981e" @@ -8436,13 +8346,6 @@ character-entities@^1.0.0: resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.1.tgz#f76871be5ef66ddb7f8f8e3478ecc374c27d6dca" integrity sha1-92hxvl72bdt/j440eOzDdMJ9bco= -character-parser@^2.1.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/character-parser/-/character-parser-2.2.0.tgz#c7ce28f36d4bcd9744e5ffc2c5fcde1c73261fc0" - integrity sha1-x84o821LzZdE5f/CxfzeHHMmH8A= - dependencies: - is-regex "^1.0.3" - character-reference-invalid@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.1.tgz#942835f750e4ec61a308e60c2ef8cc1011202efc" @@ -8512,7 +8415,7 @@ cheerio@^1.0.0-rc.3: lodash "^4.15.0" parse5 "^3.0.1" -chokidar@2.1.2, chokidar@^2.0.2, chokidar@^2.0.4: +chokidar@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.2.tgz#9c23ea40b01638439e0513864d362aeacc5ad058" integrity sha512-IwXUx0FXc5ibYmPC2XeEj5mpXoV66sR+t3jqu2NS2GYwCktt3KF1/Qqjws/NkegajBA4RbZ5+DDwlOiJsxDHEg== @@ -8561,7 +8464,7 @@ chokidar@3.3.0: optionalDependencies: fsevents "~2.1.1" -chokidar@^2.0.0, chokidar@^2.1.2, chokidar@^2.1.8: +chokidar@^2.0.0, chokidar@^2.0.4, chokidar@^2.1.2, chokidar@^2.1.8: version "2.1.8" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== @@ -8580,10 +8483,10 @@ chokidar@^2.0.0, chokidar@^2.1.2, chokidar@^2.1.8: optionalDependencies: fsevents "^1.2.7" -chokidar@^3.2.2: - version "3.3.1" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.1.tgz#c84e5b3d18d9a4d77558fef466b1bf16bbeb3450" - integrity sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg== +chokidar@^3.2.2, chokidar@^3.4.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.1.tgz#e905bdecf10eaa0a0b1db0c664481cc4cbc22ba1" + integrity sha512-TQTJyr2stihpC4Sya9hs2Xh+O2wf+igjL36Y75xx2WdHuiICcn/XJza46Jwt0eT5hVpQOzo3FpY3cj3RVYLX0g== dependencies: anymatch "~3.1.1" braces "~3.0.2" @@ -8591,7 +8494,7 @@ chokidar@^3.2.2: is-binary-path "~2.1.0" is-glob "~4.0.1" normalize-path "~3.0.0" - readdirp "~3.3.0" + readdirp "~3.4.0" optionalDependencies: fsevents "~2.1.2" @@ -8688,7 +8591,7 @@ classnames@2.x: resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" integrity sha1-+zgB1FNGdknvNgPH1hoCvRKb3m0= -clean-css@4.2.x, clean-css@^4.1.11: +clean-css@4.2.x: version "4.2.1" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17" integrity sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g== @@ -9116,15 +9019,10 @@ colors@1.0.3: resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= -colors@^1.1.2, colors@^1.3.2: - version "1.3.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d" - integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg== - -colors@^1.2.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.2.tgz#2df8ff573dfbf255af562f8ce7181d6b971a359b" - integrity sha512-rhP0JSBGYvpcNQj4s5AdShMeE5ahMop96cTeDl/v9qQQm2fYClE2QXZRi8wLzc+GmXSxdIqqbOIAhyObEXDbfQ== +colors@^1.1.2, colors@^1.2.1, colors@^1.3.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== colors@~1.1.2: version "1.1.2" @@ -9242,13 +9140,6 @@ component-emitter@^1.2.0, component-emitter@^1.2.1: resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= -compose-function@3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/compose-function/-/compose-function-3.0.3.tgz#9ed675f13cc54501d30950a486ff6a7ba3ab185f" - integrity sha1-ntZ18TzFRQHTCVCkhv9qe6OrGF8= - dependencies: - arity-n "^1.0.4" - compress-commons@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-2.1.1.tgz#9410d9a534cf8435e3fbbb7c6ce48de2dc2f0610" @@ -9450,16 +9341,6 @@ constant-case@^2.0.0: snake-case "^2.1.0" upper-case "^1.1.1" -constantinople@^3.0.1, constantinople@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/constantinople/-/constantinople-3.1.2.tgz#d45ed724f57d3d10500017a7d3a889c1381ae647" - integrity sha512-yePcBqEFhLOqSBtwYOGGS1exHo/s1xjekXiinh4itpNQGCu4KA1euPh1fg07N2wMITZXQkBz75Ntdt1ctGZouw== - dependencies: - "@types/babel-types" "^7.0.0" - "@types/babylon" "^6.16.2" - babel-types "^6.26.0" - babylon "^6.18.0" - constants-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" @@ -9514,23 +9395,13 @@ contour_plot@^0.0.1: resolved "https://registry.yarnpkg.com/contour_plot/-/contour_plot-0.0.1.tgz#475870f032b8e338412aa5fc507880f0bf495c77" integrity sha1-R1hw8DK44zhBKqX8UHiA8L9JXHc= -convert-source-map@1.7.0, convert-source-map@^1.5.1, convert-source-map@^1.6.0, convert-source-map@^1.7.0: +convert-source-map@1.X, convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.5.1, convert-source-map@^1.6.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.X, convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.5.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" - integrity sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU= - -convert-source-map@^0.3.3: - version "0.3.5" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-0.3.5.tgz#f1d802950af7dd2631a1febe0596550c86ab3190" - integrity sha1-8dgClQr33SYxof6+BZZVDIarMZA= - cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" @@ -10059,7 +9930,7 @@ css.escape@^1.5.1: resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" integrity sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s= -css@2.X, css@^2.0.0, css@^2.2.1, css@^2.2.4: +css@2.X, css@^2.2.1, css@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" integrity sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw== @@ -10120,11 +9991,6 @@ csstype@^2.2.0, csstype@^2.5.5, csstype@^2.5.7, csstype@^2.6.7: resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.7.tgz#20b0024c20b6718f4eda3853a1f5a1cce7f5e4a5" integrity sha512-9Mcn9sFbGBAdmimWb2gLVDtFJzeKtDGIr76TUqmjZrw9LFXBMSU70lcs+C0/7fyCd6iBDqmksUcCOUIkisPHsQ== -cuint@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/cuint/-/cuint-0.2.2.tgz#408086d409550c2631155619e9fa7bcadc3b991b" - integrity sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs= - currently-unhandled@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" @@ -10492,7 +10358,7 @@ debug@3.1.0, debug@=3.1.0: dependencies: ms "2.0.0" -debug@3.2.6, debug@3.X, debug@^3.0.0, debug@^3.1.0, debug@^3.2.5, debug@^3.2.6: +debug@3.2.6, debug@3.X, debug@^3.0.0, debug@^3.1.0, debug@^3.1.1, debug@^3.2.5, debug@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== @@ -10854,11 +10720,6 @@ delete-empty@^2.0.0: relative "^3.0.2" rimraf "^2.6.2" -depd@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" - integrity sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k= - depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -11195,11 +11056,6 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -doctypes@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/doctypes/-/doctypes-1.1.0.tgz#ea80b106a87538774e8a3a4a5afe293de489e0a9" - integrity sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk= - dom-converter@~0.2: version "0.2.0" resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" @@ -11970,7 +11826,7 @@ es6-error@^4.0.1: resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== -es6-iterator@2.0.3, es6-iterator@^2.0.1, es6-iterator@~2.0.1, es6-iterator@~2.0.3: +es6-iterator@^2.0.1, es6-iterator@~2.0.1, 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= @@ -13232,7 +13088,7 @@ file-exists-dazinatorfork@^1.0.2: resolved "https://registry.yarnpkg.com/file-exists-dazinatorfork/-/file-exists-dazinatorfork-1.0.2.tgz#cd8d0d85f63e39dc81eceb0b687c44a2cca95c47" integrity sha512-r70c72ln2YHzQINNfxDp02hAhbGkt1HffZ+Du8oetWDLjDtFja/Lm10lUaSh9e+wD+7VDvPee0b0C9SAy8pWZg== -file-loader@4.2.0, file-loader@^4.2.0: +file-loader@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-4.2.0.tgz#5fb124d2369d7075d70a9a5abecd12e60a95215e" integrity sha512-+xZnaK5R8kBJrHK0/6HRlrKNamvVS5rjyuju+rnyxRGuwUJwpAMsVzUl5dz6rK8brkzjV6JpcFNjp6NqV0g1OQ== @@ -14163,20 +14019,13 @@ getopts@^2.2.5: resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.2.5.tgz#67a0fe471cacb9c687d817cab6450b96dde8313b" integrity sha512-9jb7AW5p3in+IiJWhQiZmmwkpLaR/ccTWdWQCtZM66HJcHHLegowh4q4tSD7gouUyeNvFWRavfK9GXosQHDpFA== -getos@3.2.1: +getos@3.2.1, getos@^3.1.0: version "3.2.1" resolved "https://registry.yarnpkg.com/getos/-/getos-3.2.1.tgz#0134d1f4e00eb46144c5a9c0ac4dc087cbb27dc5" integrity sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q== dependencies: async "^3.2.0" -getos@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/getos/-/getos-3.1.0.tgz#db3aa4df15a3295557ce5e81aa9e3e5cdfaa6567" - integrity sha512-i9vrxtDu5DlLVFcrbqUqGWYlZN/zZ4pGMICCAcZoYsX3JA54nYp8r5EThw5K+m2q3wszkx4Th746JstspB0H4Q== - dependencies: - async "2.4.0" - getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" @@ -14322,7 +14171,7 @@ glob-watcher@5.0.3, glob-watcher@^5.0.3: just-debounce "^1.0.0" object.defaults "^1.1.0" -glob@7.1.3, glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@~7.1.1: +glob@7.1.3: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== @@ -14334,7 +14183,7 @@ glob@7.1.3, glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@~7.1.1: once "^1.3.0" path-is-absolute "^1.0.0" -glob@7.1.4, glob@~7.1.4: +glob@7.1.4: version "7.1.4" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== @@ -14357,7 +14206,7 @@ glob@^6.0.1, glob@^6.0.4: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.5, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.1.6: +glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.1.1, glob@~7.1.4, glob@~7.1.6: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== @@ -15711,10 +15560,10 @@ html-encoding-sniffer@^1.0.2: dependencies: whatwg-encoding "^1.0.1" -html-entities@^1.2.0, html-entities@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" - integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8= +html-entities@^1.2.0, html-entities@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.3.1.tgz#fb9a1a4b5b14c5daba82d3e34c6ae4fe701a0e44" + integrity sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA== html-escaper@^2.0.0: version "2.0.2" @@ -15812,7 +15661,7 @@ http-deceiver@^1.2.7: resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= -http-errors@1.6.3, http-errors@~1.6.3: +http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: version "1.6.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= @@ -15822,7 +15671,7 @@ http-errors@1.6.3, http-errors@~1.6.3: setprototypeof "1.1.0" statuses ">= 1.4.0 < 2" -http-errors@1.7.2, http-errors@~1.7.2: +http-errors@1.7.2: version "1.7.2" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== @@ -15833,17 +15682,7 @@ http-errors@1.7.2, http-errors@~1.7.2: statuses ">= 1.5.0 < 2" toidentifier "1.0.0" -http-errors@~1.6.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" - integrity sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY= - dependencies: - depd "1.1.1" - inherits "2.0.3" - setprototypeof "1.0.3" - statuses ">= 1.3.1 < 2" - -http-errors@~1.7.0: +http-errors@~1.7.0, http-errors@~1.7.2: version "1.7.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== @@ -15866,10 +15705,10 @@ http-https@^1.0.0: resolved "https://registry.yarnpkg.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b" integrity sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs= -http-parser-js@>=0.4.0: - version "0.4.11" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.11.tgz#5b720849c650903c27e521633d94696ee95f3529" - integrity sha512-QCR5O2AjjMW8Mo4HyI1ctFcv+O99j/0g367V3YoVnrNw5hkDvAWZD0lWGcc+F4yN3V55USPCVix4efb75HxFfA== +http-parser-js@>=0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.2.tgz#da2e31d237b393aae72ace43882dd7e270a8ff77" + integrity sha512-opCO9ASqg5Wy2FNo7A0sxy71yGbbkJJXLdgMK04Tcypw9jr2MgWbyubb0+WdmDmGnFflO7fRbqbaihh/ENDlRQ== http-proxy-agent@^2.1.0: version "2.1.0" @@ -16828,14 +16667,6 @@ is-dom@^1.0.9: resolved "https://registry.yarnpkg.com/is-dom/-/is-dom-1.0.9.tgz#483832d52972073de12b9fe3f60320870da8370d" integrity sha1-SDgy1SlyBz3hK5/j9gMghw2oNw0= -is-expression@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-expression/-/is-expression-3.0.0.tgz#39acaa6be7fd1f3471dc42c7416e61c24317ac9f" - integrity sha1-Oayqa+f9HzRx3ELHQW5hwkMXrJ8= - dependencies: - acorn "~4.0.2" - object-assign "^4.0.1" - 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" @@ -17159,7 +16990,7 @@ is-redirect@^1.0.0: resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ= -is-regex@^1.0.3, is-regex@^1.0.4, is-regex@^1.0.5, is-regex@~1.0.5: +is-regex@^1.0.4, is-regex@^1.0.5, is-regex@~1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== @@ -17440,7 +17271,7 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -istanbul-instrumenter-loader@3.0.1, istanbul-instrumenter-loader@^3.0.1: +istanbul-instrumenter-loader@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/istanbul-instrumenter-loader/-/istanbul-instrumenter-loader-3.0.1.tgz#9957bd59252b373fae5c52b7b5188e6fde2a0949" integrity sha512-a5SPObZgS0jB/ixaKSMdn6n/gXSrK2S6q/UfRJBT3e6gQmVjwZROTODQsYW5ZNwOu78hG62Y3fWlebaVOL0C+w== @@ -18214,11 +18045,6 @@ js-sha3@0.8.0: resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== -js-stringify@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/js-stringify/-/js-stringify-1.0.2.tgz#1736fddfd9724f28a3682adc6230ae7e4e9679db" - integrity sha1-Fzb939lyTyijaCrcYjCufk6Weds= - js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" @@ -18536,7 +18362,7 @@ jstransformer-handlebars@^1.0.0: dependencies: handlebars "^4.0.1" -jstransformer@1.0.0, jstransformer@^1.0.0: +jstransformer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/jstransformer/-/jstransformer-1.0.0.tgz#ed8bf0921e2f3f1ed4d5c1a44f68709ed24722c3" integrity sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM= @@ -18878,15 +18704,6 @@ leaflet@1.5.1: resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.5.1.tgz#9afb9d963d66c870066b1342e7a06f92840f46bf" integrity sha512-ekM9KAeG99tYisNBg0IzEywAlp0hYI5XRipsqRXyRTeuU8jcuntilpp+eFf5gaE0xubc9RuSNIVtByEKwqFV0w== -less-loader@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/less-loader/-/less-loader-5.0.0.tgz#498dde3a6c6c4f887458ee9ed3f086a12ad1b466" - integrity sha512-bquCU89mO/yWLaUq0Clk7qCsKhsF/TZpJUzETRvJa9KSVEL9SO3ovCvdEHISBhrC81OwC8QSVX7E0bzElZj9cg== - dependencies: - clone "^2.1.1" - loader-utils "^1.1.0" - pify "^4.0.1" - "less@npm:@elastic/less@2.7.3-kibana": version "2.7.3-kibana" resolved "https://registry.yarnpkg.com/@elastic/less/-/less-2.7.3-kibana.tgz#3de5e0b06bb095b1cc1149043d67f8dc36272d23" @@ -19160,7 +18977,7 @@ load-source-map@^1.0.0: semver "^5.3.0" source-map "^0.5.6" -loader-runner@^2.3.1, loader-runner@^2.4.0: +loader-runner@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== @@ -19476,7 +19293,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@4.17.11, lodash@4.17.19, lodash@>4.17.4, lodash@^4, lodash@^4.0.0, lodash@^4.0.1, lodash@^4.10.0, lodash@^4.11.1, lodash@^4.14.0, lodash@^4.15.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.16, lodash@^4.17.19, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@~4.17.10, lodash@~4.17.15, lodash@~4.17.5: +lodash@4.17.11, lodash@4.17.19, lodash@>4.17.4, lodash@^4, lodash@^4.0.0, lodash@^4.0.1, lodash@^4.10.0, lodash@^4.11.1, lodash@^4.15.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.16, lodash@^4.17.19, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@~4.17.10, lodash@~4.17.15, lodash@~4.17.5: version "4.17.19" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== @@ -19571,10 +19388,10 @@ logform@^2.2.0: ms "^2.1.1" triple-beam "^1.3.0" -loglevel@^1.6.4: - version "1.6.4" - resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.4.tgz#f408f4f006db8354d0577dcf6d33485b3cb90d56" - integrity sha512-p0b6mOGKcGa+7nnmKbpzR6qloPbrgLcnio++E+14Vo/XffOGwZtRpUhr8dTH/x2oCMmEoIU0Zwm3ZauhvYD17g== +loglevel@^1.6.8: + version "1.6.8" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.8.tgz#8a25fb75d092230ecd4457270d80b54e28011171" + integrity sha512-bsU7+gc9AJ2SqpzxwU3+1fedl8zAntbtC5XYlt3s2j1hJcn2PsXSmgN8TaLG/J1/2mod4+cE/3vNL70/c1RNCA== loglevelnext@^1.0.1: version "1.0.5" @@ -20257,15 +20074,10 @@ mime@1.6.0, mime@^1.2.11, mime@^1.3.4, mime@^1.4.1: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mime@^2.0.3, mime@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.3.1.tgz#b1621c54d63b97c47d3cfe7f7215f7d64517c369" - integrity sha512-OEUllcVoydBHGN1z84yfQDimn58pZNNNXgZlHXSboxMlFvgI6MXSWpWKpFRra7H1HxpVhHTkrghfRW49k6yjeg== - -mime@^2.4.2, mime@^2.4.4: - version "2.4.4" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" - integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== +mime@^2.0.3, mime@^2.4.4: + version "2.4.6" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.6.tgz#e5b407c90db442f2beb5b162373d07b69affa4d1" + integrity sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA== mimic-fn@^1.0.0: version "1.2.0" @@ -20389,12 +20201,12 @@ minimist@1.1.x: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8" integrity sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag= -minimist@1.2.0, minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@~1.2.0: +minimist@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= -minimist@1.2.5, minimist@^1.2.5: +minimist@1.2.5, minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5, minimist@~1.2.0: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== @@ -20504,7 +20316,7 @@ mkdirp@0.5.3: dependencies: minimist "^1.2.5" -mkdirp@0.5.4, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.4, mkdirp@~0.5.0, mkdirp@~0.5.1: +mkdirp@0.5.4, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.4, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.4.tgz#fd01504a6797ec5c9be81ff43d204961ed64a512" integrity sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw== @@ -21655,11 +21467,6 @@ object-path-immutable@^3.1.1: dependencies: is-plain-object "3.0.0" -object-path@0.11.4: - version "0.11.4" - resolved "https://registry.yarnpkg.com/object-path/-/object-path-0.11.4.tgz#370ae752fbf37de3ea70a861c23bba8915691949" - integrity sha1-NwrnUvvzfePqcKhhwju6iRVpGUk= - object-values@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/object-values/-/object-values-1.0.0.tgz#72af839630119e5b98c3b02bb8c27e3237158105" @@ -22772,7 +22579,7 @@ phin@^2.9.1: resolved "https://registry.yarnpkg.com/phin/-/phin-2.9.3.tgz#f9b6ac10a035636fb65dfc576aaaa17b8743125c" integrity sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA== -picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.0.7, picomatch@^2.2.1: +picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1: version "2.2.2" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== @@ -22961,14 +22768,14 @@ popper.js@^1.14.4: resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.14.7.tgz#e31ec06cfac6a97a53280c3e55e4e0c860e7738e" integrity sha512-4q1hNvoUre/8srWsH7hnoSJ5xVmIL4qgz+s4qf2TnJIMyZFUFMGH+9vE7mXynAlHSZ/NdTmmow86muD0myUkVQ== -portfinder@^1.0.24: - version "1.0.24" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.24.tgz#11efbc6865f12f37624b6531ead1d809ed965cfa" - integrity sha512-ekRl7zD2qxYndYflwiryJwMioBI7LI7rVXg3EnLK3sjkouT5eOuhS3gS255XxBksa30VG8UPZYZCdgfGOfkSUg== +portfinder@^1.0.26: + version "1.0.27" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.27.tgz#a41333c116b5e5f3d380f9745ac2f35084c4c758" + integrity sha512-bJ3U3MThKnyJ9Dx1Idtm5pQmxXqw08+XOHhi/Lie8OF1OlhVaBFhsntAIhkZYjfDcCzszSr0w1yCbccThhzgxQ== dependencies: - async "^1.5.2" - debug "^2.2.0" - mkdirp "0.5.x" + async "^2.6.2" + debug "^3.1.1" + mkdirp "^0.5.1" posix-character-classes@^0.1.0: version "0.1.1" @@ -23049,17 +22856,6 @@ postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2: indexes-of "^1.0.1" uniq "^1.0.1" -postcss-url@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/postcss-url/-/postcss-url-8.0.0.tgz#7b10059bd12929cdbb1971c60f61a0e5af86b4ca" - integrity sha512-E2cbOQ5aii2zNHh8F6fk1cxls7QVFZjLPSrqvmiza8OuXLzIpErij8BDS5Y3STPfJgpIMNCPEr8JlKQWEoozUw== - dependencies: - mime "^2.3.1" - minimatch "^3.0.4" - mkdirp "^0.5.0" - postcss "^7.0.2" - xxhashjs "^0.2.1" - postcss-value-parser@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.0.tgz#99a983d365f7b2ad8d0f9b8c3094926eab4b936d" @@ -23084,25 +22880,7 @@ postcss-values-parser@^1.5.0: indexes-of "^1.0.1" uniq "^1.0.1" -postcss@7.0.21: - version "7.0.21" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.21.tgz#06bb07824c19c2021c5d056d5b10c35b989f7e17" - integrity sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ== - dependencies: - chalk "^2.4.2" - source-map "^0.6.1" - supports-color "^6.1.0" - -postcss@^7.0.0, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.2, postcss@^7.0.23, postcss@^7.0.26, postcss@^7.0.5, postcss@^7.0.6: - version "7.0.26" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.26.tgz#5ed615cfcab35ba9bbb82414a4fa88ea10429587" - integrity sha512-IY4oRjpXWYshuTDFxMVkJDtWIk2LhsTlu8bZnbEJA4+bYT16Lvpo8Qv6EvDumhYRgzjZl489pmsY3qVgJQ08nA== - dependencies: - chalk "^2.4.2" - source-map "^0.6.1" - supports-color "^6.1.0" - -postcss@^7.0.32: +postcss@^7.0.0, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.2, postcss@^7.0.23, postcss@^7.0.26, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: version "7.0.32" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.32.tgz#4310d6ee347053da3433db2be492883d62cec59d" integrity sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw== @@ -23457,111 +23235,6 @@ public-encrypt@^4.0.0: parse-asn1 "^5.0.0" randombytes "^2.0.1" -pug-attrs@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pug-attrs/-/pug-attrs-2.0.4.tgz#b2f44c439e4eb4ad5d4ef25cac20d18ad28cc336" - integrity sha512-TaZ4Z2TWUPDJcV3wjU3RtUXMrd3kM4Wzjbe3EWnSsZPsJ3LDI0F3yCnf2/W7PPFF+edUFQ0HgDL1IoxSz5K8EQ== - dependencies: - constantinople "^3.0.1" - js-stringify "^1.0.1" - pug-runtime "^2.0.5" - -pug-code-gen@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/pug-code-gen/-/pug-code-gen-2.0.2.tgz#ad0967162aea077dcf787838d94ed14acb0217c2" - integrity sha512-kROFWv/AHx/9CRgoGJeRSm+4mLWchbgpRzTEn8XCiwwOy6Vh0gAClS8Vh5TEJ9DBjaP8wCjS3J6HKsEsYdvaCw== - dependencies: - constantinople "^3.1.2" - doctypes "^1.1.0" - js-stringify "^1.0.1" - pug-attrs "^2.0.4" - pug-error "^1.3.3" - pug-runtime "^2.0.5" - void-elements "^2.0.1" - with "^5.0.0" - -pug-error@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/pug-error/-/pug-error-1.3.3.tgz#f342fb008752d58034c185de03602dd9ffe15fa6" - integrity sha512-qE3YhESP2mRAWMFJgKdtT5D7ckThRScXRwkfo+Erqga7dyJdY3ZquspprMCj/9sJ2ijm5hXFWQE/A3l4poMWiQ== - -pug-filters@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/pug-filters/-/pug-filters-3.1.1.tgz#ab2cc82db9eeccf578bda89130e252a0db026aa7" - integrity sha512-lFfjNyGEyVWC4BwX0WyvkoWLapI5xHSM3xZJFUhx4JM4XyyRdO8Aucc6pCygnqV2uSgJFaJWW3Ft1wCWSoQkQg== - dependencies: - clean-css "^4.1.11" - constantinople "^3.0.1" - jstransformer "1.0.0" - pug-error "^1.3.3" - pug-walk "^1.1.8" - resolve "^1.1.6" - uglify-js "^2.6.1" - -pug-lexer@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/pug-lexer/-/pug-lexer-4.1.0.tgz#531cde48c7c0b1fcbbc2b85485c8665e31489cfd" - integrity sha512-i55yzEBtjm0mlplW4LoANq7k3S8gDdfC6+LThGEvsK4FuobcKfDAwt6V4jKPH9RtiE3a2Akfg5UpafZ1OksaPA== - dependencies: - character-parser "^2.1.1" - is-expression "^3.0.0" - pug-error "^1.3.3" - -pug-linker@^3.0.6: - version "3.0.6" - resolved "https://registry.yarnpkg.com/pug-linker/-/pug-linker-3.0.6.tgz#f5bf218b0efd65ce6670f7afc51658d0f82989fb" - integrity sha512-bagfuHttfQOpANGy1Y6NJ+0mNb7dD2MswFG2ZKj22s8g0wVsojpRlqveEQHmgXXcfROB2RT6oqbPYr9EN2ZWzg== - dependencies: - pug-error "^1.3.3" - pug-walk "^1.1.8" - -pug-load@^2.0.12: - version "2.0.12" - resolved "https://registry.yarnpkg.com/pug-load/-/pug-load-2.0.12.tgz#d38c85eb85f6e2f704dea14dcca94144d35d3e7b" - integrity sha512-UqpgGpyyXRYgJs/X60sE6SIf8UBsmcHYKNaOccyVLEuT6OPBIMo6xMPhoJnqtB3Q3BbO4Z3Bjz5qDsUWh4rXsg== - dependencies: - object-assign "^4.1.0" - pug-walk "^1.1.8" - -pug-parser@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/pug-parser/-/pug-parser-5.0.1.tgz#03e7ada48b6840bd3822f867d7d90f842d0ffdc9" - integrity sha512-nGHqK+w07p5/PsPIyzkTQfzlYfuqoiGjaoqHv1LjOv2ZLXmGX1O+4Vcvps+P4LhxZ3drYSljjq4b+Naid126wA== - dependencies: - pug-error "^1.3.3" - token-stream "0.0.1" - -pug-runtime@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/pug-runtime/-/pug-runtime-2.0.5.tgz#6da7976c36bf22f68e733c359240d8ae7a32953a" - integrity sha512-P+rXKn9un4fQY77wtpcuFyvFaBww7/91f3jHa154qU26qFAnOe6SW1CbIDcxiG5lLK9HazYrMCCuDvNgDQNptw== - -pug-strip-comments@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/pug-strip-comments/-/pug-strip-comments-1.0.4.tgz#cc1b6de1f6e8f5931cf02ec66cdffd3f50eaf8a8" - integrity sha512-i5j/9CS4yFhSxHp5iKPHwigaig/VV9g+FgReLJWWHEHbvKsbqL0oP/K5ubuLco6Wu3Kan5p7u7qk8A4oLLh6vw== - dependencies: - pug-error "^1.3.3" - -pug-walk@^1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/pug-walk/-/pug-walk-1.1.8.tgz#b408f67f27912f8c21da2f45b7230c4bd2a5ea7a" - integrity sha512-GMu3M5nUL3fju4/egXwZO0XLi6fW/K3T3VTgFQ14GxNi8btlxgT5qZL//JwZFm/2Fa64J/PNS8AZeys3wiMkVA== - -pug@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pug/-/pug-2.0.4.tgz#ee7682ec0a60494b38d48a88f05f3b0ac931377d" - integrity sha512-XhoaDlvi6NIzL49nu094R2NA6P37ijtgMDuWE+ofekDChvfKnzFal60bhSdiy8y2PBO6fmz3oMEIcfpBVRUdvw== - dependencies: - pug-code-gen "^2.0.2" - pug-filters "^3.1.1" - pug-lexer "^4.1.0" - pug-linker "^3.0.6" - pug-load "^2.0.12" - pug-parser "^5.0.1" - pug-runtime "^2.0.5" - pug-strip-comments "^1.0.4" - puid@1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/puid/-/puid-1.0.7.tgz#fa638a737d7b20419059d93965aed36ca20e1c84" @@ -23823,16 +23496,11 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" -range-parser@^1.2.1, range-parser@~1.2.1: +range-parser@^1.2.1, range-parser@~1.2.0, range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== -range-parser@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" - integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= - raw-body@2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" @@ -23869,11 +23537,6 @@ raw-loader@3.1.0, raw-loader@^3.1.0: loader-utils "^1.1.0" schema-utils "^2.0.1" -raw-loader@~0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa" - integrity sha1-DD0L6u2KAclm2Xh793goElKpeao= - rbush@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/rbush/-/rbush-3.0.1.tgz#5fafa8a79b3b9afdfe5008403a720cc1de882ecf" @@ -24897,12 +24560,12 @@ readdirp@~3.2.0: dependencies: picomatch "^2.0.4" -readdirp@~3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.3.0.tgz#984458d13a1e42e2e9f5841b129e162f369aff17" - integrity sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ== +readdirp@~3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.4.0.tgz#9fdccdf9e9155805449221ac645e8303ab5b9ada" + integrity sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ== dependencies: - picomatch "^2.0.7" + picomatch "^2.2.1" readline2@^1.0.1: version "1.0.1" @@ -25206,11 +24869,6 @@ regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" -regex-parser@2.2.10: - version "2.2.10" - resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.2.10.tgz#9e66a8f73d89a107616e63b39d4deddfee912b37" - integrity sha512-8t6074A68gHfU8Neftl0Le6KTDwfGAj7IyjPIMSfikI2wJUTHDMaIq42bUsfVnj8mhx0R+45rdUXHGpN164avA== - regexp.prototype.flags@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz#6b30724e306a27833eeb171b66ac8890ba37e41c" @@ -25778,22 +25436,6 @@ resolve-protobuf-schema@^2.1.0: dependencies: protocol-buffers-schema "^3.3.1" -resolve-url-loader@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/resolve-url-loader/-/resolve-url-loader-3.1.1.tgz#28931895fa1eab9be0647d3b2958c100ae3c0bf0" - integrity sha512-K1N5xUjj7v0l2j/3Sgs5b8CjrrgtC70SmdCuZiJ8tSyb5J+uk3FoeZ4b7yTnH6j7ngI+Bc5bldHJIa8hYdu2gQ== - dependencies: - adjust-sourcemap-loader "2.0.0" - camelcase "5.3.1" - compose-function "3.0.3" - convert-source-map "1.7.0" - es6-iterator "2.0.3" - loader-utils "1.2.3" - postcss "7.0.21" - rework "1.0.1" - rework-visit "1.0.0" - source-map "0.6.1" - resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" @@ -25904,19 +25546,6 @@ reusify@^1.0.0: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rework-visit@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/rework-visit/-/rework-visit-1.0.0.tgz#9945b2803f219e2f7aca00adb8bc9f640f842c9a" - integrity sha1-mUWygD8hni96ygCtuLyfZA+ELJo= - -rework@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/rework/-/rework-1.0.1.tgz#30806a841342b54510aa4110850cd48534144aa7" - integrity sha1-MIBqhBNCtUUQqkEQhQzUhTQUSqc= - dependencies: - convert-source-map "^0.3.3" - css "^2.0.0" - right-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" @@ -25924,35 +25553,28 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2, rimraf@^2.2.0, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.6.1, rimraf@^2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" - integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w== +rimraf@2, rimraf@^2.2.0, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== dependencies: - glob "^7.0.5" + glob "^7.1.3" -rimraf@2.6.3, rimraf@^2.6.3, rimraf@~2.6.2: +rimraf@2.6.3, rimraf@~2.6.2: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== dependencies: glob "^7.1.3" -rimraf@3.0.0, rimraf@^3.0.0: +rimraf@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.0.tgz#614176d4b3010b75e5c390eb0ee96f6dc0cebb9b" integrity sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg== dependencies: glob "^7.1.3" -rimraf@^2.5.4, rimraf@^2.7.1: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - -rimraf@^3.0.2: +rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -26131,6 +25753,11 @@ safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, s resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-buffer@>=5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + safe-buffer@~5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" @@ -26342,13 +25969,6 @@ screenfull@^5.0.0: resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.0.0.tgz#5c2010c0e84fd4157bf852877698f90b8cbe96f6" integrity sha512-yShzhaIoE9OtOhWVyBBffA6V98CDCoyHTsp8228blmqYy1Z5bddzE/4FPiJKlr8DVR4VBiiUyfPzIQPIYDkeMA== -script-loader@0.7.2: - version "0.7.2" - resolved "https://registry.yarnpkg.com/script-loader/-/script-loader-0.7.2.tgz#2016db6f86f25f5cf56da38915d83378bb166ba7" - integrity sha512-UMNLEvgOAQuzK8ji8qIscM3GIrRCWN6MmMXGD4SD5l6cSycgGsCo0tX5xRnfQcoghqct0tjHjcykgI1PyBE2aA== - dependencies: - raw-loader "~0.5.1" - scss-tokenizer@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1" @@ -26634,11 +26254,6 @@ setimmediate@^1.0.4, setimmediate@^1.0.5: resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= -setprototypeof@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" - integrity sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ= - setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" @@ -26978,13 +26593,14 @@ sockjs-client@1.4.0: json3 "^3.3.2" url-parse "^1.4.3" -sockjs@0.3.19: - version "0.3.19" - resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.19.tgz#d976bbe800af7bd20ae08598d582393508993c0d" - integrity sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw== +sockjs@0.3.20: + version "0.3.20" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.20.tgz#b26a283ec562ef8b2687b44033a4eeceac75d855" + integrity sha512-SpmVOVpdq0DJc0qArhF3E5xsxvaiqGNb73XfgBpK1y3UD5gs8DSo8aCTsuT5pX8rssdc2NDIzANwP9eCAiSdTA== dependencies: faye-websocket "^0.10.0" - uuid "^3.0.1" + uuid "^3.4.0" + websocket-driver "0.6.5" sort-keys@^1.0.0: version "1.1.2" @@ -27056,11 +26672,6 @@ source-map@0.5.6: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" integrity sha1-dc449SvwczxafwwRjYEzSiu19BI= -source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - source-map@^0.4.2: version "0.4.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" @@ -27073,6 +26684,11 @@ source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6, sour resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + source-map@^0.7.3: version "0.7.3" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" @@ -27211,10 +26827,10 @@ spdy-transport@^3.0.0: readable-stream "^3.0.6" wbuf "^1.7.3" -spdy@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.1.tgz#6f12ed1c5db7ea4f24ebb8b89ba58c87c08257f2" - integrity sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA== +spdy@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" + integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== dependencies: debug "^4.1.0" handle-thing "^2.0.0" @@ -27417,16 +27033,16 @@ stats-lite@^2.2.0: dependencies: isnumber "~1.0.0" -"statuses@>= 1.3.1 < 2", statuses@~1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" - integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== - "statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= +statuses@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== + stdout-stream@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.0.tgz#a2c7c8587e54d9427ea9edb3ac3f2cd522df378b" @@ -28400,7 +28016,7 @@ terser-webpack-plugin@^1.4.3: webpack-sources "^1.4.0" worker-farm "^1.7.0" -terser-webpack-plugin@^2.1.2, terser-webpack-plugin@^2.3.4: +terser-webpack-plugin@^2.1.2: version "2.3.7" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-2.3.7.tgz#4910ff5d1a872168cc7fa6cd3749e2b0d60a8a0b" integrity sha512-xzYyaHUNhzgaAdBsXxk2Yvo/x1NJdslUaussK3fdpBbvttm1iIwU+c26dj9UxJcwk2c5UWt5F55MUTIA8BE7Dg== @@ -28463,15 +28079,6 @@ textextensions@2: resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.2.0.tgz#38ac676151285b658654581987a0ce1a4490d286" integrity sha512-j5EMxnryTvKxwH2Cq+Pb43tsf6sdEgw6Pdwxk83mPaq0ToeFJt6WE4J3s5BqY7vmjlLgkgXvhtXUxo80FyBhCA== -thread-loader@^2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/thread-loader/-/thread-loader-2.1.3.tgz#cbd2c139fc2b2de6e9d28f62286ab770c1acbdda" - integrity sha512-wNrVKH2Lcf8ZrWxDF/khdlLlsTMczdcwPA9VEK4c2exlEPynYWxi9op3nPTo5lAnDIkE0rQEB3VBP+4Zncc9Hg== - dependencies: - loader-runner "^2.3.1" - loader-utils "^1.1.0" - neo-async "^2.6.0" - throat@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" @@ -28819,11 +28426,6 @@ toidentifier@1.0.0: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== -token-stream@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/token-stream/-/token-stream-0.0.1.tgz#ceeefc717a76c4316f126d0b9dbaa55d7e7df01a" - integrity sha1-zu78cXp2xDFvEm0LnbqlXX598Bo= - topo@3.x.x: version "3.0.0" resolved "https://registry.yarnpkg.com/topo/-/topo-3.0.0.tgz#37e48c330efeac784538e0acd3e62ca5e231fe7a" @@ -29159,15 +28761,7 @@ type-fest@^0.8.0, type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -type-is@~1.6.16: - version "1.6.16" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" - integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.18" - -type-is@~1.6.17, type-is@~1.6.18: +type-is@~1.6.16, type-is@~1.6.17, type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== @@ -29258,7 +28852,7 @@ uglify-js@3.4.x, uglify-js@^3.1.4: commander "~2.17.1" source-map "~0.6.1" -uglify-js@^2.6.1, uglify-js@^2.6.2: +uglify-js@^2.6.2: version "2.8.29" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" integrity sha1-KcVzMUgFe7Th913zW3qcty5qWd0= @@ -29887,7 +29481,7 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= -uuid@3.3.2, uuid@^3.0.1, uuid@^3.3.2: +uuid@3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== @@ -29897,12 +29491,7 @@ uuid@^2.0.1: resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" integrity sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho= -uuid@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" - integrity sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g== - -uuid@^3.1.0, uuid@^3.3.3: +uuid@^3.0.0, uuid@^3.1.0, uuid@^3.3.2, uuid@^3.3.3, uuid@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== @@ -30509,11 +30098,6 @@ vm-browserify@^1.0.1: resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.0.tgz#bd76d6a23323e2ca8ffa12028dc04559c75f9019" integrity sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw== -void-elements@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" - integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w= - vscode-jsonrpc@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz#a7bf74ef3254d0a0c272fab15c82128e378b3be9" @@ -30622,14 +30206,23 @@ warning@^4.0.2, warning@^4.0.3: dependencies: loose-envify "^1.0.0" +watchpack-chokidar2@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz#9948a1866cbbd6cb824dea13a7ed691f6c8ddff0" + integrity sha512-9TyfOyN/zLUbA288wZ8IsMZ+6cbzvsNyEzSBp6e/zkifi6xxbl8SmQ/CxQq32k8NNqrdVEVUVSEf56L4rQ/ZxA== + dependencies: + chokidar "^2.1.8" + watchpack@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" - integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA== + version "1.7.2" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.2.tgz#c02e4d4d49913c3e7e122c3325365af9d331e9aa" + integrity sha512-ymVbbQP40MFTp+cNMvpyBpBtygHnPzPkHqoIwRRj/0B8KhqQwV8LaKjtbaxF2lK4vl8zN9wCxS46IFCU5K4W0g== dependencies: - chokidar "^2.0.2" graceful-fs "^4.1.2" neo-async "^2.5.0" + optionalDependencies: + chokidar "^3.4.0" + watchpack-chokidar2 "^2.0.0" wbuf@^1.1.0: version "1.7.2" @@ -30679,17 +30272,7 @@ webpack-cli@^3.3.10: v8-compile-cache "2.0.3" yargs "13.2.4" -webpack-dev-middleware@^3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.0.tgz#ef751d25f4e9a5c8a35da600c5fda3582b5c6cff" - integrity sha512-qvDesR1QZRIAZHOE3iQ4CXLZZSQ1lAUsSpnQmlB1PBfoN/xdRjmge3Dok0W4IdaVLJOGJy3sGI4sZHwjRU0PCA== - dependencies: - memory-fs "^0.4.1" - mime "^2.4.2" - range-parser "^1.2.1" - webpack-log "^2.0.0" - -webpack-dev-middleware@^3.7.2: +webpack-dev-middleware@^3.7.0, webpack-dev-middleware@^3.7.2: version "3.7.2" resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz#0019c3db716e3fa5cecbf64f2ab88a74bab331f3" integrity sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw== @@ -30701,9 +30284,9 @@ webpack-dev-middleware@^3.7.2: webpack-log "^2.0.0" webpack-dev-server@^3.8.2: - version "3.8.2" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.8.2.tgz#3292427bf6510da9a3ac2d500b924a4197667ff9" - integrity sha512-0xxogS7n5jHDQWy0WST0q6Ykp7UGj4YvWh+HVN71JoE7BwPxMZrwgraBvmdEMbDVMBzF0u+mEzn8TQzBm5NYJQ== + version "3.11.0" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.11.0.tgz#8f154a3bce1bcfd1cc618ef4e703278855e7ff8c" + integrity sha512-PUxZ+oSTxogFQgkTtFndEtJIPNmml7ExwufBZ9L2/Xyyd5PnOL5UreWe5ZT7IU25DSdykL9p1MLQzmLh2ljSeg== dependencies: ansi-html "0.0.7" bonjour "^3.5.0" @@ -30713,31 +30296,31 @@ webpack-dev-server@^3.8.2: debug "^4.1.1" del "^4.1.1" express "^4.17.1" - html-entities "^1.2.1" + html-entities "^1.3.1" http-proxy-middleware "0.19.1" import-local "^2.0.0" internal-ip "^4.3.0" ip "^1.1.5" is-absolute-url "^3.0.3" killable "^1.0.1" - loglevel "^1.6.4" + loglevel "^1.6.8" opn "^5.5.0" p-retry "^3.0.1" - portfinder "^1.0.24" + portfinder "^1.0.26" schema-utils "^1.0.0" selfsigned "^1.10.7" semver "^6.3.0" serve-index "^1.9.1" - sockjs "0.3.19" + sockjs "0.3.20" sockjs-client "1.4.0" - spdy "^4.0.1" + spdy "^4.0.2" strip-ansi "^3.0.1" supports-color "^6.1.0" url "^0.11.0" webpack-dev-middleware "^3.7.2" webpack-log "^2.0.0" ws "^6.2.1" - yargs "12.0.5" + yargs "^13.3.2" webpack-hot-middleware@^2.25.0: version "2.25.0" @@ -30767,7 +30350,7 @@ webpack-log@^2.0.0: ansi-colors "^3.0.0" uuid "^3.3.2" -webpack-merge@4.2.2, webpack-merge@^4.2.2: +webpack-merge@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.2.tgz#a27c52ea783d1398afd2087f547d7b9d2f43634d" integrity sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g== @@ -30818,12 +30401,20 @@ webpack@^4.33.0, webpack@^4.38.0, webpack@^4.41.5: watchpack "^1.6.0" webpack-sources "^1.4.1" +websocket-driver@0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.6.5.tgz#5cb2556ceb85f4373c6d8238aa691c8454e13a36" + integrity sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY= + dependencies: + websocket-extensions ">=0.1.1" + websocket-driver@>=0.5.1: - version "0.7.0" - resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.0.tgz#0caf9d2d755d93aee049d4bdd0d3fe2cca2a24eb" - integrity sha1-DK+dLXVdk67gSdS90NP+LMoqJOs= + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== dependencies: - http-parser-js ">=0.4.0" + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" websocket-extensions ">=0.1.1" websocket-extensions@>=0.1.1: @@ -30934,28 +30525,14 @@ which-typed-array@^1.1.2: has-symbols "^1.0.1" is-typed-array "^1.1.3" -which@1, which@1.3.1, which@^1.2.9, which@^1.3.1, which@~1.3.0: +which@1, which@1.3.1, which@^1.2.14, which@^1.2.8, which@^1.2.9, which@^1.3.1, which@~1.3.0: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== dependencies: isexe "^2.0.0" -which@^1.2.14, which@^1.2.8: - version "1.3.0" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" - integrity sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg== - dependencies: - isexe "^2.0.0" - -which@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.1.tgz#f1cf94d07a8e571b6ff006aeb91d0300c47ef0a4" - integrity sha512-N7GBZOTswtB9lkQBZA4+zAXrjEIWAUOB93AvzUiudRzRxhUdLURQ7D/gAIMY1gatT/LTbmbcv8SiYazy3eYB7w== - dependencies: - isexe "^2.0.0" - -which@^2.0.2: +which@^2.0.1, which@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== @@ -31072,14 +30649,6 @@ winston@^3.3.3: triple-beam "^1.3.0" winston-transport "^4.4.0" -with@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/with/-/with-5.1.1.tgz#fa4daa92daf32c4ea94ed453c81f04686b575dfe" - integrity sha1-+k2qktrzLE6pTtRTyB8EaGtXXf4= - dependencies: - acorn "^3.1.0" - acorn-globals "^3.0.0" - word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" @@ -31159,13 +30728,6 @@ wrap-fn@^0.1.0: dependencies: co "3.1.0" -wrapper-webpack-plugin@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrapper-webpack-plugin/-/wrapper-webpack-plugin-2.1.0.tgz#2b5d80f46af84c9eeb707d08796a115e233adeac" - integrity sha512-e+2FhSYGCxhDq3PcUw5mRhH+8vcYa+9d9AuLChJUZ9ZbUPhQOHZ/O2dnN98iTqeUuvrzSSOv13+x/NhrAm5JEg== - dependencies: - webpack-sources "^1.1.0" - wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -31405,13 +30967,6 @@ xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= -xxhashjs@^0.2.1: - version "0.2.2" - resolved "https://registry.yarnpkg.com/xxhashjs/-/xxhashjs-0.2.2.tgz#8a6251567621a1c46a5ae204da0249c7f8caa9d8" - integrity sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw== - dependencies: - cuint "^0.2.2" - y18n@^3.2.0, y18n@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" @@ -31508,24 +31063,6 @@ yargs-unparser@1.6.0: lodash "^4.17.15" yargs "^13.3.0" -yargs@12.0.5, yargs@^12.0.5: - version "12.0.5" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" - integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== - dependencies: - cliui "^4.0.0" - decamelize "^1.2.0" - find-up "^3.0.0" - get-caller-file "^1.0.1" - os-locale "^3.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1 || ^4.0.0" - yargs-parser "^11.1.1" - yargs@13.2.4: version "13.2.4" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.4.tgz#0b562b794016eb9651b98bd37acf364aa5d6dc83" @@ -31543,7 +31080,7 @@ yargs@13.2.4: y18n "^4.0.0" yargs-parser "^13.1.0" -yargs@13.3.2, yargs@^13.2.2, yargs@^13.3.0: +yargs@13.3.2, yargs@^13.2.2, yargs@^13.3.0, yargs@^13.3.2: version "13.3.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== @@ -31579,24 +31116,25 @@ yargs@4.8.1: y18n "^3.2.1" yargs-parser "^2.4.1" -yargs@^15.0.2, yargs@^15.1.0, yargs@^15.3.1, yargs@~15.3.1: - version "15.3.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b" - integrity sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA== +yargs@^12.0.5: + version "12.0.5" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" + integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== dependencies: - cliui "^6.0.0" + cliui "^4.0.0" decamelize "^1.2.0" - find-up "^4.1.0" - get-caller-file "^2.0.1" + find-up "^3.0.0" + get-caller-file "^1.0.1" + os-locale "^3.0.0" require-directory "^2.1.1" - require-main-filename "^2.0.0" + require-main-filename "^1.0.1" set-blocking "^2.0.0" - string-width "^4.2.0" + string-width "^2.0.0" which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^18.1.1" + y18n "^3.2.1 || ^4.0.0" + yargs-parser "^11.1.1" -yargs@^15.4.0: +yargs@^15.0.2, yargs@^15.1.0, yargs@^15.3.1, yargs@^15.4.0: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== @@ -31645,6 +31183,23 @@ yargs@^7.0.0, yargs@^7.1.0: y18n "^3.2.1" yargs-parser "5.0.0-security.0" +yargs@~15.3.1: + version "15.3.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b" + integrity sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^18.1.1" + yargs@~3.10.0: version "3.10.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" From cdc7d255616074b60d633660f19bf97b50334801 Mon Sep 17 00:00:00 2001 From: Zacqary Adam Xeper Date: Thu, 13 Aug 2020 12:21:29 -0500 Subject: [PATCH 22/53] [Metrics UI] Fix inventory footer misalignment (#74707) --- .../inventory_view/components/layout.tsx | 72 ++++++++++--------- .../components/nodes_overview.tsx | 3 + .../inventory_view/components/waffle/map.tsx | 11 ++- 3 files changed, 52 insertions(+), 34 deletions(-) diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/layout.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/layout.tsx index ad92c054ee459..47616c7f4f7fd 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/layout.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/layout.tsx @@ -8,6 +8,7 @@ import React, { useCallback, useEffect } from 'react'; import { useInterval } from 'react-use'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { AutoSizer } from '../../../../components/auto_sizer'; import { convertIntervalToString } from '../../../../utils/convert_interval_to_string'; import { NodesOverview } from './nodes_overview'; import { calculateBoundsFromNodes } from '../lib/calculate_bounds_from_nodes'; @@ -110,37 +111,44 @@ export const Layout = () => { - - - - - - - - + {({ measureRef, bounds: { height = 0 } }) => ( + <> + - - - - - - + + + + + + + + + + + + + + + )} + @@ -159,9 +167,9 @@ const TopActionContainer = euiStyled.div` const BottomActionContainer = euiStyled.div` background-color: ${(props) => props.theme.eui.euiPageBackgroundColor}; padding: ${(props) => props.theme.eui.paddingSizes.m} ${(props) => - props.theme.eui.paddingSizes.m} ${(props) => props.theme.eui.paddingSizes.s}; - position: absolute; + props.theme.eui.paddingSizes.m}; + position: fixed; left: 0; - bottom: 4px; + bottom: 0; right: 0; `; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/nodes_overview.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/nodes_overview.tsx index 723e8e581cdaa..a705a0be3a39e 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/nodes_overview.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/nodes_overview.tsx @@ -34,6 +34,7 @@ interface Props { boundsOverride: InfraWaffleMapBounds; autoBounds: boolean; formatter: InfraFormatter; + bottomMargin: number; } export const NodesOverview = ({ @@ -48,6 +49,7 @@ export const NodesOverview = ({ options, formatter, onDrilldown, + bottomMargin, }: Props) => { const handleDrilldown = useCallback( (filter: string) => { @@ -118,6 +120,7 @@ export const NodesOverview = ({ onFilter={handleDrilldown} bounds={bounds} dataBounds={dataBounds} + bottomMargin={bottomMargin} /> ); diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/map.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/map.tsx index 5838317f07100..89b1b9b2211d9 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/map.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/map.tsx @@ -26,6 +26,7 @@ interface Props { onFilter: (filter: string) => void; bounds: InfraWaffleMapBounds; dataBounds: InfraWaffleMapBounds; + bottomMargin: number; } export const Map: React.FC = ({ @@ -37,6 +38,7 @@ export const Map: React.FC = ({ bounds, nodeType, dataBounds, + bottomMargin, }) => { const sortedNodes = sortNodes(options.sort, nodes); const map = nodesToWaffleMap(sortedNodes); @@ -45,7 +47,11 @@ export const Map: React.FC = ({ {({ measureRef, content: { width = 0, height = 0 } }) => { const groupsWithLayout = applyWaffleMapLayout(map, width, height); return ( - measureRef(el)} data-test-subj="waffleMap"> + measureRef(el)} + bottomMargin={bottomMargin} + data-test-subj="waffleMap" + > {groupsWithLayout.map((group) => { if (isWaffleMapGroupWithGroups(group)) { @@ -86,13 +92,14 @@ export const Map: React.FC = ({ ); }; -const WaffleMapOuterContainer = euiStyled.div` +const WaffleMapOuterContainer = euiStyled.div<{ bottomMargin: number }>` flex: 1 0 0%; display: flex; justify-content: flex-start; flex-direction: column; overflow-x: hidden; overflow-y: auto; + margin-bottom: ${(props) => props.bottomMargin}px; `; const WaffleMapInnerContainer = euiStyled.div` From ad3d87517f882dc0f32ec365692ba4dea502217c Mon Sep 17 00:00:00 2001 From: Ryan Keairns Date: Thu, 13 Aug 2020 12:38:57 -0500 Subject: [PATCH 23/53] Add kibana-core-ui-designers team (#74970) --- .github/CODEOWNERS | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6863b91858ff6..1f076e3c84001 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -8,7 +8,7 @@ /x-pack/plugins/lens/ @elastic/kibana-app /x-pack/plugins/graph/ @elastic/kibana-app /src/plugins/dashboard/ @elastic/kibana-app -/src/plugins/dashboard/**/*.scss @elastic/kibana-core-ui +/src/plugins/dashboard/**/*.scss @elastic/kibana-core-ui-designers /src/plugins/discover/ @elastic/kibana-app /src/plugins/input_control_vis/ @elastic/kibana-app /src/plugins/kibana_legacy/ @elastic/kibana-app @@ -70,7 +70,7 @@ # Canvas /x-pack/plugins/canvas/ @elastic/kibana-canvas -/x-pack/plugins/canvas/**/*.scss @elastic/kibana-core-ui +/x-pack/plugins/canvas/**/*.scss @elastic/kibana-core-ui-designers /x-pack/test/functional/apps/canvas/ @elastic/kibana-canvas # Core UI @@ -80,7 +80,7 @@ /src/plugins/home/server/services/ @elastic/kibana-core-ui # Exclude tutorial resources folder for now because they are not owned by Kibana app and most will move out soon /src/legacy/core_plugins/kibana/public/home/*.ts @elastic/kibana-core-ui -/src/legacy/core_plugins/kibana/public/home/**/*.scss @elastic/kibana-core-ui +/src/legacy/core_plugins/kibana/public/home/**/*.scss @elastic/kibana-core-ui-designers /src/legacy/core_plugins/kibana/public/home/np_ready/ @elastic/kibana-core-ui # Observability UIs @@ -165,14 +165,14 @@ # Security /src/core/server/csp/ @elastic/kibana-security @elastic/kibana-platform /x-pack/legacy/plugins/security/ @elastic/kibana-security -/x-pack/legacy/plugins/security/**/*.scss @elastic/kibana-core-ui +/x-pack/legacy/plugins/security/**/*.scss @elastic/kibana-core-ui-designers /x-pack/legacy/plugins/spaces/ @elastic/kibana-security -/x-pack/legacy/plugins/spaces/**/*.scss @elastic/kibana-core-ui +/x-pack/legacy/plugins/spaces/**/*.scss @elastic/kibana-core-ui-designers /x-pack/plugins/spaces/ @elastic/kibana-security -/x-pack/plugins/spaces/**/*.scss @elastic/kibana-core-ui +/x-pack/plugins/spaces/**/*.scss @elastic/kibana-core-ui-designers /x-pack/plugins/encrypted_saved_objects/ @elastic/kibana-security /x-pack/plugins/security/ @elastic/kibana-security -/x-pack/plugins/security/**/*.scss @elastic/kibana-core-ui +/x-pack/plugins/security/**/*.scss @elastic/kibana-core-ui-designers /x-pack/test/api_integration/apis/security/ @elastic/kibana-security # Kibana Localization From 479a991b988cbfeefab8bb4754718e727b009009 Mon Sep 17 00:00:00 2001 From: Melissa Alvarez Date: Thu, 13 Aug 2020 14:17:33 -0400 Subject: [PATCH 24/53] [ML] DF Analytics: allow failed job to be stopped by force via the UI (#74710) * allow force stop from ui if job is failed * update wording in confirm modal --- .../components/action_stop/index.ts | 2 + .../action_stop/stop_button_modal.tsx | 56 +++++++++++++++++++ .../action_stop/use_force_stop_action.ts | 38 +++++++++++++ .../components/analytics_list/use_actions.tsx | 16 +++++- 4 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_stop/stop_button_modal.tsx create mode 100644 x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_stop/use_force_stop_action.ts diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_stop/index.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_stop/index.ts index 858b6c70501b3..ce03305e3d859 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_stop/index.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_stop/index.ts @@ -5,3 +5,5 @@ */ export { StopButton } from './stop_button'; +export { StopButtonModal } from './stop_button_modal'; +export { useForceStopAction } from './use_force_stop_action'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_stop/stop_button_modal.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_stop/stop_button_modal.tsx new file mode 100644 index 0000000000000..387f42cc85ef3 --- /dev/null +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_stop/stop_button_modal.tsx @@ -0,0 +1,56 @@ +/* + * 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 } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiConfirmModal, EuiOverlayMask, EUI_MODAL_CONFIRM_BUTTON } from '@elastic/eui'; + +import { ForceStopAction } from './use_force_stop_action'; + +export const StopButtonModal: FC = ({ + closeModal, + item, + forceStopAndCloseModal, +}) => { + return ( + <> + {item !== undefined && ( + + +

+ +

+
+
+ )} + + ); +}; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_stop/use_force_stop_action.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_stop/use_force_stop_action.ts new file mode 100644 index 0000000000000..5a4e748948731 --- /dev/null +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_stop/use_force_stop_action.ts @@ -0,0 +1,38 @@ +/* + * 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 { DataFrameAnalyticsListRow } from '../analytics_list/common'; +import { stopAnalytics } from '../../services/analytics_service'; + +export type ForceStopAction = ReturnType; +export const useForceStopAction = () => { + const [isModalVisible, setModalVisible] = useState(false); + + const [item, setItem] = useState(); + + const closeModal = () => setModalVisible(false); + const forceStopAndCloseModal = () => { + if (item !== undefined) { + setModalVisible(false); + stopAnalytics(item); + } + }; + + const openModal = (newItem: DataFrameAnalyticsListRow) => { + setItem(newItem); + setModalVisible(true); + }; + + return { + closeModal, + isModalVisible, + item, + openModal, + forceStopAndCloseModal, + }; +}; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/use_actions.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/use_actions.tsx index 373b9991d4d3c..d355335039085 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/use_actions.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/use_actions.tsx @@ -21,12 +21,13 @@ import { EditButtonFlyout, } from '../action_edit'; import { useStartAction, StartButton, StartButtonModal } from '../action_start'; -import { StopButton } from '../action_stop'; +import { StopButton, useForceStopAction, StopButtonModal } from '../action_stop'; import { getViewAction } from '../action_view'; import { isCompletedAnalyticsJob, isDataFrameAnalyticsRunning, + isDataFrameAnalyticsFailed, DataFrameAnalyticsListRow, } from './common'; @@ -53,11 +54,13 @@ export const useActions = ( const deleteAction = useDeleteAction(); const editAction = useEditAction(); const startAction = useStartAction(); + const stopAction = useForceStopAction(); /* eslint-disable react-hooks/rules-of-hooks */ modals = ( <> {startAction.isModalVisible && } + {stopAction.isModalVisible && } {deleteAction.isModalVisible && } {isEditActionFlyoutVisible(editAction) && } @@ -78,7 +81,10 @@ export const useActions = ( ...[ { render: (item: DataFrameAnalyticsListRow) => { - if (!isDataFrameAnalyticsRunning(item.stats.state)) { + if ( + !isDataFrameAnalyticsRunning(item.stats.state) && + !isDataFrameAnalyticsFailed(item.stats.state) + ) { return ( { if (canStartStopDataFrameAnalytics) { - stopAnalytics(item); + if (isDataFrameAnalyticsFailed(item.stats.state)) { + stopAction.openModal(item); + } else { + stopAnalytics(item); + } } }} /> From 250a0b17b03f8924462d484c2254a5af7d64f1ff Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 13 Aug 2020 11:41:52 -0700 Subject: [PATCH 25/53] attempt excluding a codeowners directory --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 1f076e3c84001..5a8271302a72b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -118,6 +118,7 @@ # Operations /src/dev/ @elastic/kibana-operations +!/src/dev/i18n/ @elastic/kibana-operations /src/setup_node_env/ @elastic/kibana-operations /src/optimize/ @elastic/kibana-operations /packages/*eslint*/ @elastic/kibana-operations From c34e30ed0b29938228659afc57c6ec1f155ad47b Mon Sep 17 00:00:00 2001 From: Michael Olorunnisola Date: Thu, 13 Aug 2020 14:55:43 -0400 Subject: [PATCH 26/53] [Security Solution][Resolver] Graph Control Tests and Update Simulator Selectors (#74680) Co-authored-by: oatkiller --- .../resolver/test_utilities/extend_jest.ts | 65 ++++++ .../test_utilities/simulator/index.tsx | 97 +++----- .../simulator/mock_resolver.tsx | 15 +- .../resolver/view/clickthrough.test.tsx | 37 +-- .../resolver/view/graph_controls.test.tsx | 221 ++++++++++++++++++ .../public/resolver/view/graph_controls.tsx | 25 +- .../public/resolver/view/panel.test.tsx | 24 +- 7 files changed, 379 insertions(+), 105 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/resolver/view/graph_controls.test.tsx diff --git a/x-pack/plugins/security_solution/public/resolver/test_utilities/extend_jest.ts b/x-pack/plugins/security_solution/public/resolver/test_utilities/extend_jest.ts index 9fc7af38beb42..df8f32d15a7ab 100644 --- a/x-pack/plugins/security_solution/public/resolver/test_utilities/extend_jest.ts +++ b/x-pack/plugins/security_solution/public/resolver/test_utilities/extend_jest.ts @@ -17,6 +17,7 @@ declare global { namespace jest { interface Matchers { toYieldEqualTo(expectedYield: T extends AsyncIterable ? E : never): Promise; + toYieldObjectEqualTo(expectedYield: unknown): Promise; } } } @@ -57,6 +58,70 @@ expect.extend({ } } + // Use `pass` as set in the above loop (or initialized to `false`) + // See https://jestjs.io/docs/en/expect#custom-matchers-api and https://jestjs.io/docs/en/expect#thisutils + const message = pass + ? () => + `${this.utils.matcherHint(matcherName, undefined, undefined, options)}\n\n` + + `Expected: not ${this.utils.printExpected(expected)}\n${ + this.utils.stringify(expected) !== this.utils.stringify(received[received.length - 1]!) + ? `Received: ${this.utils.printReceived(received[received.length - 1])}` + : '' + }` + : () => + `${this.utils.matcherHint(matcherName, undefined, undefined, options)}\n\nCompared ${ + received.length + } yields.\n\n${received + .map( + (next, index) => + `yield ${index + 1}:\n\n${this.utils.printDiffOrStringify( + expected, + next, + 'Expected', + 'Received', + this.expand + )}` + ) + .join(`\n\n`)}`; + + return { message, pass }; + }, + /** + * A custom matcher that takes an async generator and compares each value it yields to an expected value. + * This uses the same equality logic as `toMatchObject`. + * If any yielded value equals the expected value, the matcher will pass. + * If the generator ends with none of the yielded values matching, it will fail. + */ + async toYieldObjectEqualTo( + this: jest.MatcherContext, + receivedIterable: AsyncIterable, + expected: T + ): Promise<{ pass: boolean; message: () => string }> { + // Used in printing out the pass or fail message + const matcherName = 'toSometimesYieldEqualTo'; + const options: jest.MatcherHintOptions = { + comment: 'deep equality with any yielded value', + isNot: this.isNot, + promise: this.promise, + }; + // The last value received: Used in printing the message + const received: T[] = []; + + // Set to true if the test passes. + let pass: boolean = false; + + // Async iterate over the iterable + for await (const next of receivedIterable) { + // keep track of all received values. Used in pass and fail messages + received.push(next); + // Use deep equals to compare the value to the expected value + if ((this.equals(next, expected), [this.utils.iterableEquality, this.utils.subsetEquality])) { + // If the value is equal, break + pass = true; + break; + } + } + // Use `pass` as set in the above loop (or initialized to `false`) // See https://jestjs.io/docs/en/expect#custom-matchers-api and https://jestjs.io/docs/en/expect#thisutils const message = pass diff --git a/x-pack/plugins/security_solution/public/resolver/test_utilities/simulator/index.tsx b/x-pack/plugins/security_solution/public/resolver/test_utilities/simulator/index.tsx index cae6a18576ebd..355b53e374092 100644 --- a/x-pack/plugins/security_solution/public/resolver/test_utilities/simulator/index.tsx +++ b/x-pack/plugins/security_solution/public/resolver/test_utilities/simulator/index.tsx @@ -14,8 +14,9 @@ import { spyMiddlewareFactory } from '../spy_middleware_factory'; import { resolverMiddlewareFactory } from '../../store/middleware'; import { resolverReducer } from '../../store/reducer'; import { MockResolver } from './mock_resolver'; -import { ResolverState, DataAccessLayer, SpyMiddleware } from '../../types'; +import { ResolverState, DataAccessLayer, SpyMiddleware, SideEffectSimulator } from '../../types'; import { ResolverAction } from '../../store/actions'; +import { sideEffectSimulatorFactory } from '../../view/side_effect_simulator_factory'; /** * Test a Resolver instance using jest, enzyme, and a mock data layer. @@ -43,6 +44,11 @@ export class Simulator { * This is used by `debugActions`. */ private readonly spyMiddleware: SpyMiddleware; + /** + * Simulator which allows you to explicitly simulate resize events and trigger animation frames + */ + private readonly sideEffectSimulator: SideEffectSimulator; + constructor({ dataAccessLayer, resolverComponentInstanceID, @@ -87,11 +93,14 @@ export class Simulator { // Used for `KibanaContextProvider` const coreStart: CoreStart = coreMock.createStart(); + this.sideEffectSimulator = sideEffectSimulatorFactory(); + // Render Resolver via the `MockResolver` component, using `enzyme`. this.wrapper = mount( { + return this.resolveWrapper(() => this.domNodes(`[data-test-subj="${selector}"]`)); } /** - * The icon element for the node detail title. + * Given a 'data-test-subj' selector, it will return the domNode */ - public nodeDetailViewTitleIcon(): ReactWrapper { - return this.domNodes('[data-test-subj="resolver:node-detail:title-icon"]'); + public testSubject(selector: string): ReactWrapper { + return this.domNodes(`[data-test-subj="${selector}"]`); } /** @@ -297,7 +266,7 @@ export class Simulator { public async resolveWrapper( wrapperFactory: () => ReactWrapper, predicate: (wrapper: ReactWrapper) => boolean = (wrapper) => wrapper.length > 0 - ): Promise { + ): Promise { for await (const wrapper of this.map(wrapperFactory)) { if (predicate(wrapper)) { return wrapper; diff --git a/x-pack/plugins/security_solution/public/resolver/test_utilities/simulator/mock_resolver.tsx b/x-pack/plugins/security_solution/public/resolver/test_utilities/simulator/mock_resolver.tsx index 7de7cf48e6039..5d5a414761dbf 100644 --- a/x-pack/plugins/security_solution/public/resolver/test_utilities/simulator/mock_resolver.tsx +++ b/x-pack/plugins/security_solution/public/resolver/test_utilities/simulator/mock_resolver.tsx @@ -6,7 +6,7 @@ /* eslint-disable react/display-name */ -import React, { useMemo, useEffect, useState, useCallback } from 'react'; +import React, { useEffect, useState, useCallback } from 'react'; import { Router } from 'react-router-dom'; import { I18nProvider } from '@kbn/i18n/react'; import { Provider } from 'react-redux'; @@ -17,7 +17,6 @@ import { ResolverState, SideEffectSimulator, ResolverProps } from '../../types'; import { ResolverAction } from '../../store/actions'; import { ResolverWithoutProviders } from '../../view/resolver_without_providers'; import { SideEffectContext } from '../../view/side_effect_context'; -import { sideEffectSimulatorFactory } from '../../view/side_effect_simulator_factory'; type MockResolverProps = { /** @@ -38,6 +37,10 @@ type MockResolverProps = { history: React.ComponentProps['history']; /** Pass a resolver store. See `storeFactory` and `mockDataAccessLayer` */ store: Store; + /** + * Pass the side effect simulator which handles animations and resizing. See `sideEffectSimulatorFactory` + */ + sideEffectSimulator: SideEffectSimulator; /** * All the props from `ResolverWithoutStore` can be passed. These aren't defaulted to anything (you might want to test what happens when they aren't present.) */ @@ -66,8 +69,6 @@ export const MockResolver = React.memo((props: MockResolverProps) => { setResolverElement(element); }, []); - const simulator: SideEffectSimulator = useMemo(() => sideEffectSimulatorFactory(), []); - // Resize the Resolver element to match the passed in props. Resolver is size dependent. useEffect(() => { if (resolverElement) { @@ -84,15 +85,15 @@ export const MockResolver = React.memo((props: MockResolverProps) => { return this; }, }; - simulator.controls.simulateElementResize(resolverElement, size); + props.sideEffectSimulator.controls.simulateElementResize(resolverElement, size); } - }, [props.rasterWidth, props.rasterHeight, simulator.controls, resolverElement]); + }, [props.rasterWidth, props.rasterHeight, props.sideEffectSimulator.controls, resolverElement]); return ( - + ({ - graphElements: simulator.graphElement().length, - graphLoadingElements: simulator.graphLoadingElement().length, - graphErrorElements: simulator.graphErrorElement().length, + graphElements: simulator.testSubject('resolver:graph').length, + graphLoadingElements: simulator.testSubject('resolver:graph:loading').length, + graphErrorElements: simulator.testSubject('resolver:graph:error').length, })) ).toYieldEqualTo({ // it should have 1 graph element, an no error or loading elements. @@ -72,8 +72,12 @@ describe('Resolver, when analyzing a tree that has no ancestors and 2 children', }); it(`should show links to the 3 nodes (with icons) in the node list.`, async () => { - await expect(simulator.map(() => simulator.nodeListNodeLinkText().length)).toYieldEqualTo(3); - await expect(simulator.map(() => simulator.nodeListNodeLinkIcons().length)).toYieldEqualTo(3); + await expect( + simulator.map(() => simulator.testSubject('resolver:node-list:node-link:title').length) + ).toYieldEqualTo(3); + await expect( + simulator.map(() => simulator.testSubject('resolver:node-list:node-link:title').length) + ).toYieldEqualTo(3); }); describe("when the second child node's first button has been clicked", () => { @@ -131,9 +135,9 @@ describe('Resolver, when analyzing a tree that has two related events for the or beforeEach(async () => { await expect( simulator.map(() => ({ - graphElements: simulator.graphElement().length, - graphLoadingElements: simulator.graphLoadingElement().length, - graphErrorElements: simulator.graphErrorElement().length, + graphElements: simulator.testSubject('resolver:graph').length, + graphLoadingElements: simulator.testSubject('resolver:graph:loading').length, + graphErrorElements: simulator.testSubject('resolver:graph:error').length, originNode: simulator.processNodeElements({ entityID: entityIDs.origin }).length, })) ).toYieldEqualTo({ @@ -147,7 +151,10 @@ describe('Resolver, when analyzing a tree that has two related events for the or it('should render a related events button', async () => { await expect( simulator.map(() => ({ - relatedEventButtons: simulator.processNodeRelatedEventButton(entityIDs.origin).length, + relatedEventButtons: simulator.processNodeChildElements( + entityIDs.origin, + 'resolver:submenu:button' + ).length, })) ).toYieldEqualTo({ relatedEventButtons: 1, @@ -156,7 +163,7 @@ describe('Resolver, when analyzing a tree that has two related events for the or describe('when the related events button is clicked', () => { beforeEach(async () => { const button = await simulator.resolveWrapper(() => - simulator.processNodeRelatedEventButton(entityIDs.origin) + simulator.processNodeChildElements(entityIDs.origin, 'resolver:submenu:button') ); if (button) { button.simulate('click'); @@ -164,17 +171,19 @@ describe('Resolver, when analyzing a tree that has two related events for the or }); it('should open the submenu and display exactly one option with the correct count', async () => { await expect( - simulator.map(() => simulator.processNodeSubmenuItems().map((node) => node.text())) + simulator.map(() => + simulator.testSubject('resolver:map:node-submenu-item').map((node) => node.text()) + ) ).toYieldEqualTo(['2 registry']); await expect( - simulator.map(() => simulator.processNodeSubmenuItems().length) + simulator.map(() => simulator.testSubject('resolver:map:node-submenu-item').length) ).toYieldEqualTo(1); }); }); describe('and when the related events button is clicked again', () => { beforeEach(async () => { const button = await simulator.resolveWrapper(() => - simulator.processNodeRelatedEventButton(entityIDs.origin) + simulator.processNodeChildElements(entityIDs.origin, 'resolver:submenu:button') ); if (button) { button.simulate('click'); @@ -182,7 +191,7 @@ describe('Resolver, when analyzing a tree that has two related events for the or }); it('should close the submenu', async () => { await expect( - simulator.map(() => simulator.processNodeSubmenuItems().length) + simulator.map(() => simulator.testSubject('resolver:map:node-submenu-item').length) ).toYieldEqualTo(0); }); }); diff --git a/x-pack/plugins/security_solution/public/resolver/view/graph_controls.test.tsx b/x-pack/plugins/security_solution/public/resolver/view/graph_controls.test.tsx new file mode 100644 index 0000000000000..6497cc2971980 --- /dev/null +++ b/x-pack/plugins/security_solution/public/resolver/view/graph_controls.test.tsx @@ -0,0 +1,221 @@ +/* + * 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 { Simulator } from '../test_utilities/simulator'; +import { noAncestorsTwoChildren } from '../data_access_layer/mocks/no_ancestors_two_children'; +import { nudgeAnimationDuration } from '../store/camera/scaling_constants'; +import '../test_utilities/extend_jest'; + +describe('graph controls: when relsover is loaded with an origin node', () => { + let simulator: Simulator; + let originEntityID: string; + let originNodeStyle: () => AsyncIterable; + const resolverComponentInstanceID = 'graph-controls-test'; + + const originalPositionStyle: Readonly<{ left: string; top: string }> = { + left: '746.93132px', + top: '535.5792px', + }; + const originalSizeStyle: Readonly<{ width: string; height: string }> = { + width: '360px', + height: '120px', + }; + + beforeEach(async () => { + const { + metadata: { databaseDocumentID, entityIDs }, + dataAccessLayer, + } = noAncestorsTwoChildren(); + + simulator = new Simulator({ + dataAccessLayer, + databaseDocumentID, + resolverComponentInstanceID, + }); + originEntityID = entityIDs.origin; + + originNodeStyle = () => + simulator.map(() => { + const wrapper = simulator.processNodeElements({ entityID: originEntityID }); + // `getDOMNode` can only be called on a wrapper of a single node: https://enzymejs.github.io/enzyme/docs/api/ReactWrapper/getDOMNode.html + if (wrapper.length === 1) { + return wrapper.getDOMNode().style; + } + return null; + }); + }); + + it('should display all cardinal panning buttons and the center button', async () => { + await expect( + simulator.map(() => ({ + westPanButton: simulator.testSubject('resolver:graph-controls:west-button').length, + southPanButton: simulator.testSubject('resolver:graph-controls:south-button').length, + eastPanButton: simulator.testSubject('resolver:graph-controls:east-button').length, + northPanButton: simulator.testSubject('resolver:graph-controls:north-button').length, + centerButton: simulator.testSubject('resolver:graph-controls:center-button').length, + })) + ).toYieldEqualTo({ + westPanButton: 1, + southPanButton: 1, + eastPanButton: 1, + northPanButton: 1, + centerButton: 1, + }); + }); + + it('should display the zoom buttons and slider', async () => { + await expect( + simulator.map(() => ({ + zoomInButton: simulator.testSubject('resolver:graph-controls:zoom-in').length, + zoomOutButton: simulator.testSubject('resolver:graph-controls:zoom-out').length, + zoomSlider: simulator.testSubject('resolver:graph-controls:zoom-slider').length, + })) + ).toYieldEqualTo({ + zoomInButton: 1, + zoomOutButton: 1, + zoomSlider: 1, + }); + }); + + it("should show the origin node in it's original position", async () => { + await expect(originNodeStyle()).toYieldObjectEqualTo(originalPositionStyle); + }); + + describe('when the user clicks the west panning button', () => { + beforeEach(async () => { + (await simulator.resolve('resolver:graph-controls:west-button'))!.simulate('click'); + simulator.runAnimationFramesTimeFromNow(nudgeAnimationDuration); + }); + + it('should show the origin node further left on the screen', async () => { + await expect(originNodeStyle()).toYieldObjectEqualTo({ + left: '796.93132px', + top: '535.5792px', + }); + }); + }); + + describe('when the user clicks the south panning button', () => { + beforeEach(async () => { + (await simulator.resolve('resolver:graph-controls:south-button'))!.simulate('click'); + simulator.runAnimationFramesTimeFromNow(nudgeAnimationDuration); + }); + + it('should show the origin node lower on the screen', async () => { + await expect(originNodeStyle()).toYieldObjectEqualTo({ + left: '746.93132px', + top: '485.5792px', + }); + }); + }); + + describe('when the user clicks the east panning button', () => { + beforeEach(async () => { + (await simulator.resolve('resolver:graph-controls:east-button'))!.simulate('click'); + simulator.runAnimationFramesTimeFromNow(nudgeAnimationDuration); + }); + + it('should show the origin node further right on the screen', async () => { + await expect(originNodeStyle()).toYieldObjectEqualTo({ + left: '696.93132px', + top: '535.5792px', + }); + }); + }); + + describe('when the user clicks the north panning button', () => { + beforeEach(async () => { + (await simulator.resolve('resolver:graph-controls:north-button'))!.simulate('click'); + simulator.runAnimationFramesTimeFromNow(nudgeAnimationDuration); + }); + + it('should show the origin node higher on the screen', async () => { + await expect(originNodeStyle()).toYieldObjectEqualTo({ + left: '746.93132px', + top: '585.5792px', + }); + }); + }); + + describe('when the user clicks the center panning button', () => { + beforeEach(async () => { + (await simulator.resolve('resolver:graph-controls:north-button'))!.simulate('click'); + simulator.runAnimationFramesTimeFromNow(nudgeAnimationDuration); + (await simulator.resolve('resolver:graph-controls:center-button'))!.simulate('click'); + simulator.runAnimationFramesTimeFromNow(nudgeAnimationDuration); + }); + + it("should return the origin node to it's original position", async () => { + await expect(originNodeStyle()).toYieldObjectEqualTo(originalPositionStyle); + }); + }); + + it('should show the origin node as larger on the screen', async () => { + await expect(originNodeStyle()).toYieldObjectEqualTo(originalSizeStyle); + }); + + describe('when the zoom in button is clicked', () => { + beforeEach(async () => { + (await simulator.resolve('resolver:graph-controls:zoom-in'))!.simulate('click'); + simulator.runAnimationFramesTimeFromNow(nudgeAnimationDuration); + }); + + it('should show the origin node as larger on the screen', async () => { + await expect(originNodeStyle()).toYieldObjectEqualTo({ + width: '427.7538290724795px', + height: '142.5846096908265px', + }); + }); + }); + + describe('when the zoom out button is clicked', () => { + beforeEach(async () => { + (await simulator.resolve('resolver:graph-controls:zoom-out'))!.simulate('click'); + simulator.runAnimationFramesTimeFromNow(nudgeAnimationDuration); + }); + + it('should show the origin node as smaller on the screen', async () => { + await expect(originNodeStyle()).toYieldObjectEqualTo({ + width: '303.0461709275204px', + height: '101.01539030917347px', + }); + }); + }); + + describe('when the slider is moved upwards', () => { + beforeEach(async () => { + await expect(originNodeStyle()).toYieldObjectEqualTo(originalSizeStyle); + + (await simulator.resolve('resolver:graph-controls:zoom-slider'))!.simulate('change', { + target: { value: 0.8 }, + }); + simulator.runAnimationFramesTimeFromNow(nudgeAnimationDuration); + }); + + it('should show the origin node as large on the screen', async () => { + await expect(originNodeStyle()).toYieldObjectEqualTo({ + width: '525.6000000000001px', + height: '175.20000000000005px', + }); + }); + }); + + describe('when the slider is moved downwards', () => { + beforeEach(async () => { + (await simulator.resolve('resolver:graph-controls:zoom-slider'))!.simulate('change', { + target: { value: 0.2 }, + }); + simulator.runAnimationFramesTimeFromNow(nudgeAnimationDuration); + }); + + it('should show the origin node as smaller on the screen', async () => { + await expect(originNodeStyle()).toYieldObjectEqualTo({ + width: '201.60000000000002px', + height: '67.2px', + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/resolver/view/graph_controls.tsx b/x-pack/plugins/security_solution/public/resolver/view/graph_controls.tsx index c2a7bbaacbf1d..610deef07775b 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/graph_controls.tsx +++ b/x-pack/plugins/security_solution/public/resolver/view/graph_controls.tsx @@ -125,12 +125,13 @@ const GraphControlsComponent = React.memo( className={className} graphControlsBackground={colorMap.graphControlsBackground} graphControlsIconColor={colorMap.graphControls} + data-test-subj="resolver:graph-controls" >
- - diff --git a/x-pack/plugins/security_solution/public/resolver/view/panel.test.tsx b/x-pack/plugins/security_solution/public/resolver/view/panel.test.tsx index 4d391a6c9ce59..21b5a30ee9890 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/panel.test.tsx +++ b/x-pack/plugins/security_solution/public/resolver/view/panel.test.tsx @@ -72,8 +72,8 @@ describe(`Resolver: when analyzing a tree with no ancestors and two children, an it('should show the node details for the origin', async () => { await expect( simulator().map(() => { - const titleWrapper = simulator().nodeDetailViewTitle(); - const titleIconWrapper = simulator().nodeDetailViewTitleIcon(); + const titleWrapper = simulator().testSubject('resolver:node-detail:title'); + const titleIconWrapper = simulator().testSubject('resolver:node-detail:title-icon'); return { title: titleWrapper.exists() ? titleWrapper.text() : null, titleIcon: titleIconWrapper.exists() ? titleIconWrapper.text() : null, @@ -122,17 +122,17 @@ describe(`Resolver: when analyzing a tree with no ancestors and two children, an }); it('should have 3 nodes (with icons) in the node list', async () => { - await expect(simulator().map(() => simulator().nodeListNodeLinkText().length)).toYieldEqualTo( - 3 - ); - await expect(simulator().map(() => simulator().nodeListNodeLinkIcons().length)).toYieldEqualTo( - 3 - ); + await expect( + simulator().map(() => simulator().testSubject('resolver:node-list:node-link:title').length) + ).toYieldEqualTo(3); + await expect( + simulator().map(() => simulator().testSubject('resolver:node-list:node-link:icon').length) + ).toYieldEqualTo(3); }); describe('when there is an item in the node list and its text has been clicked', () => { beforeEach(async () => { - const nodeLinks = await simulator().resolveWrapper(() => simulator().nodeListNodeLinkText()); + const nodeLinks = await simulator().resolve('resolver:node-list:node-link:title'); expect(nodeLinks).toBeTruthy(); if (nodeLinks) { nodeLinks.first().simulate('click'); @@ -158,8 +158,8 @@ describe(`Resolver: when analyzing a tree with no ancestors and two children, an }); describe('and when the node list link has been clicked', () => { beforeEach(async () => { - const nodeListLink = await simulator().resolveWrapper(() => - simulator().nodeDetailBreadcrumbNodeListLink() + const nodeListLink = await simulator().resolve( + 'resolver:node-detail:breadcrumbs:node-list-link' ); if (nodeListLink) { nodeListLink.simulate('click'); @@ -169,7 +169,7 @@ describe(`Resolver: when analyzing a tree with no ancestors and two children, an await expect( simulator().map(() => { return simulator() - .nodeListNodeLinkText() + .testSubject('resolver:node-list:node-link:title') .map((node) => node.text()); }) ).toYieldEqualTo(['c', 'd', 'e']); From fe017f52dd5b64ab8d5945cd8a4483a350651850 Mon Sep 17 00:00:00 2001 From: Luke Elmers Date: Thu, 13 Aug 2020 13:38:16 -0600 Subject: [PATCH 27/53] Make data.search.aggs available on the server. (#74472) --- ...lugins-data-public.baseformatterspublic.md | 2 +- ...ibana-plugin-plugins-data-public.search.md | 8 +- ...in-plugins-data-server.aggconfigoptions.md | 13 + ...ugin-plugins-data-server.agggrouplabels.md | 15 + ...plugin-plugins-data-server.agggroupname.md | 11 + ...lugin-plugins-data-server.agggroupnames.md | 15 + ...ana-plugin-plugins-data-server.aggparam.md | 11 + ...gins-data-server.aggparamoption.display.md | 11 + ...gins-data-server.aggparamoption.enabled.md | 22 ++ ...ugin-plugins-data-server.aggparamoption.md | 25 ++ ...-plugins-data-server.aggparamoption.val.md | 11 + ...-data-server.aggparamtype._constructor_.md | 20 ++ ...ns-data-server.aggparamtype.allowedaggs.md | 11 + ...lugins-data-server.aggparamtype.makeagg.md | 11 + ...plugin-plugins-data-server.aggparamtype.md | 25 ++ ...plugin-plugins-data-server.bucket_types.md | 28 ++ ...a-plugin-plugins-data-server.iaggconfig.md | 15 + ...ana-plugin-plugins-data-server.iaggtype.md | 11 + ...gin-plugins-data-server.ifieldparamtype.md | 11 + ...ugin-plugins-data-server.imetricaggtype.md | 11 + ...n-plugins-data-server.isearchsetup.aggs.md | 11 + ...plugin-plugins-data-server.isearchsetup.md | 1 + ...n-plugins-data-server.isearchstart.aggs.md | 11 + ...plugin-plugins-data-server.isearchstart.md | 1 + .../kibana-plugin-plugins-data-server.md | 18 + ...plugin-plugins-data-server.metric_types.md | 38 +++ ...-server.optionedparamtype._constructor_.md | 20 ++ ...n-plugins-data-server.optionedparamtype.md | 24 ++ ...s-data-server.optionedparamtype.options.md | 11 + ...-data-server.optionedvalueprop.disabled.md | 11 + ...a-server.optionedvalueprop.iscompatible.md | 11 + ...n-plugins-data-server.optionedvalueprop.md | 21 ++ ...gins-data-server.optionedvalueprop.text.md | 11 + ...ins-data-server.optionedvalueprop.value.md | 11 + ...plugin-plugins-data-server.plugin.setup.md | 10 +- ...ibana-plugin-plugins-data-server.search.md | 20 ++ ...s-data-server.tabbedaggcolumn.aggconfig.md | 11 + ...-plugins-data-server.tabbedaggcolumn.id.md | 11 + ...gin-plugins-data-server.tabbedaggcolumn.md | 22 ++ ...lugins-data-server.tabbedaggcolumn.name.md | 11 + ...plugin-plugins-data-server.tabbedaggrow.md | 13 + ...plugins-data-server.tabbedtable.columns.md | 11 + ...-plugin-plugins-data-server.tabbedtable.md | 21 ++ ...in-plugins-data-server.tabbedtable.rows.md | 11 + .../new_platform/new_platform.karma_mock.js | 14 +- .../common/field_formats/converters/source.ts | 2 +- .../field_formats/field_formats_registry.ts | 2 +- .../data/common/field_formats/mocks.ts | 1 + src/plugins/data/common/index.ts | 2 - .../index_patterns/fields/field_list.ts | 3 +- .../fields/index_pattern_field.ts | 11 +- .../search/aggs/agg_config.test.ts | 5 +- .../search/aggs/agg_config.ts | 5 +- .../search/aggs/agg_configs.test.ts | 5 +- .../search/aggs/agg_configs.ts | 5 +- .../search/aggs/agg_groups.ts | 0 .../search/aggs/agg_params.test.ts | 0 .../search/aggs/agg_params.ts | 0 .../search/aggs/agg_type.test.ts | 0 .../search/aggs/agg_type.ts | 2 +- .../search/aggs/agg_types.ts | 86 +++-- .../search/aggs/agg_types_registry.test.ts | 60 ++-- .../search/aggs/agg_types_registry.ts | 46 ++- .../common/search/aggs/aggs_service.test.ts | 217 ++++++++++++ .../data/common/search/aggs/aggs_service.ts | 92 ++++++ .../search/aggs/buckets/_interval_options.ts | 0 .../_terms_other_bucket_helper.test.ts | 0 .../buckets/_terms_other_bucket_helper.ts | 0 .../search/aggs/buckets/bucket_agg_type.ts | 0 .../search/aggs/buckets/bucket_agg_types.ts | 0 .../create_filter/date_histogram.test.ts | 19 +- .../buckets/create_filter/date_histogram.ts | 0 .../buckets/create_filter/date_range.test.ts | 17 +- .../aggs/buckets/create_filter/date_range.ts | 0 .../buckets/create_filter/filters.test.ts | 12 +- .../aggs/buckets/create_filter/filters.ts | 0 .../buckets/create_filter/histogram.test.ts | 21 +- .../aggs/buckets/create_filter/histogram.ts | 12 +- .../buckets/create_filter/ip_range.test.ts | 3 +- .../aggs/buckets/create_filter/ip_range.ts | 0 .../aggs/buckets/create_filter/range.test.ts | 30 +- .../aggs/buckets/create_filter/range.ts | 12 +- .../aggs/buckets/create_filter/terms.test.ts | 3 +- .../aggs/buckets/create_filter/terms.ts | 0 .../search/aggs/buckets/date_histogram.ts | 41 ++- .../aggs/buckets/date_histogram_fn.test.ts | 0 .../search/aggs/buckets/date_histogram_fn.ts | 0 .../search/aggs/buckets/date_range.test.ts | 22 +- .../search/aggs/buckets/date_range.ts | 14 +- .../search/aggs/buckets/date_range_fn.test.ts | 0 .../search/aggs/buckets/date_range_fn.ts | 0 .../search/aggs/buckets/filter.ts | 0 .../search/aggs/buckets/filter_fn.test.ts | 0 .../search/aggs/buckets/filter_fn.ts | 0 .../search/aggs/buckets/filters.test.ts | 18 +- .../search/aggs/buckets/filters.ts | 11 +- .../search/aggs/buckets/filters_fn.test.ts | 0 .../search/aggs/buckets/filters_fn.ts | 0 .../search/aggs/buckets/geo_hash.test.ts | 0 .../search/aggs/buckets/geo_hash.ts | 0 .../search/aggs/buckets/geo_hash_fn.test.ts | 0 .../search/aggs/buckets/geo_hash_fn.ts | 0 .../search/aggs/buckets/geo_tile.ts | 0 .../search/aggs/buckets/geo_tile_fn.test.ts | 0 .../search/aggs/buckets/geo_tile_fn.ts | 0 .../search/aggs/buckets/histogram.test.ts | 32 +- .../search/aggs/buckets/histogram.ts | 22 +- .../search/aggs/buckets/histogram_fn.test.ts | 0 .../search/aggs/buckets/histogram_fn.ts | 0 .../search/aggs/buckets/index.ts | 1 + .../search/aggs/buckets/ip_range.ts | 0 .../search/aggs/buckets/ip_range_fn.test.ts | 0 .../search/aggs/buckets/ip_range_fn.ts | 0 .../search/aggs/buckets/lib/cidr_mask.test.ts | 0 .../search/aggs/buckets/lib/cidr_mask.ts | 2 +- .../search/aggs/buckets/lib/date_range.ts | 0 .../aggs/buckets/lib/extended_bounds.ts | 0 .../search/aggs/buckets/lib/geo_point.ts | 0 .../search/aggs/buckets/lib/ip_range.ts | 0 .../time_buckets/calc_auto_interval.test.ts | 0 .../lib/time_buckets/calc_auto_interval.ts | 0 .../lib/time_buckets/calc_es_interval.ts | 2 +- .../aggs/buckets/lib/time_buckets/index.ts | 0 .../lib/time_buckets/time_buckets.test.ts | 0 .../buckets/lib/time_buckets/time_buckets.ts | 2 +- .../buckets/migrate_include_exclude_format.ts | 0 .../search/aggs/buckets/range.test.ts | 18 +- .../search/aggs/buckets/range.ts | 14 +- .../search/aggs/buckets/range_fn.test.ts | 0 .../search/aggs/buckets/range_fn.ts | 0 .../search/aggs/buckets/range_key.ts | 0 .../aggs/buckets/significant_terms.test.ts | 3 +- .../search/aggs/buckets/significant_terms.ts | 0 .../aggs/buckets/significant_terms_fn.test.ts | 0 .../aggs/buckets/significant_terms_fn.ts | 0 .../search/aggs/buckets/terms.test.ts | 0 .../search/aggs/buckets/terms.ts | 0 .../search/aggs/buckets/terms_fn.test.ts | 0 .../search/aggs/buckets/terms_fn.ts | 0 .../search/aggs/index.test.ts | 32 +- src/plugins/data/common/search/aggs/index.ts | 14 +- .../search/aggs/metrics/avg.ts | 0 .../search/aggs/metrics/avg_fn.test.ts | 0 .../search/aggs/metrics/avg_fn.ts | 0 .../search/aggs/metrics/bucket_avg.ts | 0 .../search/aggs/metrics/bucket_avg_fn.test.ts | 0 .../search/aggs/metrics/bucket_avg_fn.ts | 0 .../search/aggs/metrics/bucket_max.ts | 0 .../search/aggs/metrics/bucket_max_fn.test.ts | 0 .../search/aggs/metrics/bucket_max_fn.ts | 0 .../search/aggs/metrics/bucket_min.ts | 0 .../search/aggs/metrics/bucket_min_fn.test.ts | 0 .../search/aggs/metrics/bucket_min_fn.ts | 0 .../search/aggs/metrics/bucket_sum.ts | 0 .../search/aggs/metrics/bucket_sum_fn.test.ts | 0 .../search/aggs/metrics/bucket_sum_fn.ts | 0 .../search/aggs/metrics/cardinality.ts | 0 .../aggs/metrics/cardinality_fn.test.ts | 0 .../search/aggs/metrics/cardinality_fn.ts | 0 .../search/aggs/metrics/count.ts | 0 .../search/aggs/metrics/count_fn.test.ts | 0 .../search/aggs/metrics/count_fn.ts | 0 .../search/aggs/metrics/cumulative_sum.ts | 0 .../aggs/metrics/cumulative_sum_fn.test.ts | 0 .../search/aggs/metrics/cumulative_sum_fn.ts | 0 .../search/aggs/metrics/derivative.ts | 0 .../search/aggs/metrics/derivative_fn.test.ts | 0 .../search/aggs/metrics/derivative_fn.ts | 0 .../search/aggs/metrics/geo_bounds.ts | 0 .../search/aggs/metrics/geo_bounds_fn.test.ts | 0 .../search/aggs/metrics/geo_bounds_fn.ts | 0 .../search/aggs/metrics/geo_centroid.ts | 0 .../aggs/metrics/geo_centroid_fn.test.ts | 0 .../search/aggs/metrics/geo_centroid_fn.ts | 0 .../search/aggs/metrics/index.ts | 0 .../lib/get_response_agg_config_class.ts | 0 .../metrics/lib/make_nested_label.test.ts | 0 .../aggs/metrics/lib/make_nested_label.ts | 0 .../aggs/metrics/lib/nested_agg_helpers.ts | 0 .../aggs/metrics/lib/ordinal_suffix.test.ts | 0 .../search/aggs/metrics/lib/ordinal_suffix.ts | 0 .../metrics/lib/parent_pipeline_agg_helper.ts | 0 .../metrics/lib/parent_pipeline_agg_writer.ts | 0 .../lib/sibling_pipeline_agg_helper.ts | 0 .../lib/sibling_pipeline_agg_writer.ts | 0 .../search/aggs/metrics/max.ts | 0 .../search/aggs/metrics/max_fn.test.ts | 0 .../search/aggs/metrics/max_fn.ts | 0 .../search/aggs/metrics/median.test.ts | 3 +- .../search/aggs/metrics/median.ts | 0 .../search/aggs/metrics/median_fn.test.ts | 0 .../search/aggs/metrics/median_fn.ts | 0 .../search/aggs/metrics/metric_agg_type.ts | 0 .../search/aggs/metrics/metric_agg_types.ts | 0 .../search/aggs/metrics/min.ts | 0 .../search/aggs/metrics/min_fn.test.ts | 0 .../search/aggs/metrics/min_fn.ts | 0 .../search/aggs/metrics/moving_avg.ts | 0 .../search/aggs/metrics/moving_avg_fn.test.ts | 0 .../search/aggs/metrics/moving_avg_fn.ts | 0 .../aggs/metrics/parent_pipeline.test.ts | 0 .../aggs/metrics/percentile_ranks.test.ts | 19 +- .../search/aggs/metrics/percentile_ranks.ts | 26 +- .../aggs/metrics/percentile_ranks_fn.test.ts | 0 .../aggs/metrics/percentile_ranks_fn.ts | 0 .../search/aggs/metrics/percentiles.test.ts | 2 +- .../search/aggs/metrics/percentiles.ts | 0 .../aggs/metrics/percentiles_fn.test.ts | 0 .../search/aggs/metrics/percentiles_fn.ts | 0 .../aggs/metrics/percentiles_get_value.ts | 0 .../search/aggs/metrics/serial_diff.ts | 0 .../aggs/metrics/serial_diff_fn.test.ts | 0 .../search/aggs/metrics/serial_diff_fn.ts | 0 .../aggs/metrics/sibling_pipeline.test.ts | 0 .../search/aggs/metrics/std_deviation.test.ts | 2 +- .../search/aggs/metrics/std_deviation.ts | 0 .../aggs/metrics/std_deviation_fn.test.ts | 0 .../search/aggs/metrics/std_deviation_fn.ts | 0 .../search/aggs/metrics/sum.ts | 0 .../search/aggs/metrics/sum_fn.test.ts | 0 .../search/aggs/metrics/sum_fn.ts | 0 .../search/aggs/metrics/top_hit.test.ts | 2 +- .../search/aggs/metrics/top_hit.ts | 0 .../search/aggs/metrics/top_hit_fn.test.ts | 0 .../search/aggs/metrics/top_hit_fn.ts | 0 .../search/aggs/param_types/agg.ts | 0 .../search/aggs/param_types/base.ts | 3 +- .../search/aggs/param_types/field.test.ts | 0 .../search/aggs/param_types/field.ts | 4 +- .../search/aggs/param_types/index.ts | 0 .../search/aggs/param_types/json.test.ts | 0 .../search/aggs/param_types/json.ts | 0 .../search/aggs/param_types/optioned.test.ts | 0 .../search/aggs/param_types/optioned.ts | 0 .../search/aggs/param_types/string.test.ts | 0 .../search/aggs/param_types/string.ts | 0 .../aggs/test_helpers/function_wrapper.ts | 0 .../search/aggs/test_helpers/index.ts | 4 +- .../test_helpers/mock_agg_types_registry.ts | 81 +++-- src/plugins/data/common/search/aggs/types.ts | 157 +++++++++ .../utils/calculate_auto_time_expression.ts | 15 +- .../date_histogram_interval.test.ts | 0 .../date_histogram_interval.ts | 0 .../{ => utils}/date_interval_utils/index.ts | 0 .../invalid_es_calendar_interval_error.ts | 0 .../invalid_es_interval_format_error.ts | 0 .../is_valid_es_interval.ts | 0 .../date_interval_utils/is_valid_interval.ts | 0 .../least_common_interval.test.ts | 0 .../least_common_interval.ts | 0 .../least_common_multiple.test.ts | 0 .../least_common_multiple.ts | 0 .../parse_es_interval.test.ts | 0 .../date_interval_utils/parse_es_interval.ts | 0 .../parse_interval.test.ts | 0 .../date_interval_utils/parse_interval.ts | 0 .../date_interval_utils/to_absolute_dates.ts | 2 +- .../aggs/utils/get_format_with_aggs.test.ts | 5 +- .../search/aggs/utils/get_format_with_aggs.ts | 9 +- .../search/aggs/utils/get_parsed_value.ts | 0 .../search/aggs/utils/index.ts | 2 + .../aggs/{ => utils}/ipv4_address.test.ts | 0 .../search/aggs/{ => utils}/ipv4_address.ts | 0 .../search/aggs/utils/prop_filter.test.ts | 0 .../search/aggs/utils/prop_filter.ts | 0 .../search/aggs/utils/to_angular_json.ts | 0 .../data/common/search/expressions/index.ts | 1 + .../utils/courier_inspector_stats.ts | 2 +- .../common/search/expressions/utils/index.ts | 20 ++ src/plugins/data/common/search/index.ts | 9 +- .../search/tabify/buckets.test.ts | 0 .../search/tabify/buckets.ts | 0 .../search/tabify/get_columns.test.ts | 0 .../search/tabify/get_columns.ts | 0 .../{public => common}/search/tabify/index.ts | 0 .../search/tabify/response_writer.test.ts | 0 .../search/tabify/response_writer.ts | 0 .../search/tabify/tabify.test.ts | 2 +- .../search/tabify/tabify.ts | 0 .../{public => common}/search/tabify/types.ts | 0 .../public/field_formats/utils/deserialize.ts | 2 +- src/plugins/data/public/index.ts | 62 ++-- src/plugins/data/public/mocks.ts | 2 +- src/plugins/data/public/plugin.ts | 19 +- src/plugins/data/public/public.api.md | 14 +- .../public/search/aggs/aggs_service.test.ts | 182 +++++++++++ .../data/public/search/aggs/aggs_service.ts | 152 +++++++++ src/plugins/data/public/search/aggs/index.ts | 11 +- src/plugins/data/public/search/aggs/mocks.ts | 19 +- src/plugins/data/public/search/aggs/types.ts | 130 +------- .../build_tabular_inspector_data.ts | 2 +- .../search/expressions/create_filter.test.ts | 14 +- .../search/expressions/create_filter.ts | 4 +- .../data/public/search/expressions/esaggs.ts | 14 +- .../public/search/expressions/utils/index.ts | 1 - .../expressions/utils/serialize_agg_config.ts | 2 +- src/plugins/data/public/search/index.ts | 2 - .../data/public/search/search_service.test.ts | 11 +- .../data/public/search/search_service.ts | 94 ++---- src/plugins/data/public/search/types.ts | 16 +- src/plugins/data/public/types.ts | 12 - src/plugins/data/server/index.ts | 51 +++ src/plugins/data/server/plugin.ts | 37 ++- .../server/search/aggs/aggs_service.test.ts | 113 +++++++ .../data/server/search/aggs/aggs_service.ts | 122 +++++++ src/plugins/data/server/search/aggs/index.ts | 21 ++ src/plugins/data/server/search/aggs/mocks.ts | 81 +++++ src/plugins/data/server/search/aggs/types.ts | 27 ++ src/plugins/data/server/search/index.ts | 2 + src/plugins/data/server/search/mocks.ts | 9 +- .../data/server/search/search_service.test.ts | 21 +- .../data/server/search/search_service.ts | 39 ++- src/plugins/data/server/search/types.ts | 3 + src/plugins/data/server/server.api.md | 309 ++++++++++++++++-- .../definitions/date_histogram.test.tsx | 10 +- 315 files changed, 2712 insertions(+), 831 deletions(-) create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggconfigoptions.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.agggrouplabels.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.agggroupname.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.agggroupnames.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparam.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamoption.display.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamoption.enabled.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamoption.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamoption.val.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamtype._constructor_.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamtype.allowedaggs.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamtype.makeagg.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamtype.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.bucket_types.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iaggconfig.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iaggtype.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.ifieldparamtype.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.imetricaggtype.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.aggs.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.aggs.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.metric_types.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedparamtype._constructor_.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedparamtype.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedparamtype.options.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedvalueprop.disabled.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedvalueprop.iscompatible.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedvalueprop.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedvalueprop.text.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedvalueprop.value.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.aggconfig.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.id.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.name.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggrow.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.columns.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.rows.md rename src/plugins/data/{public => common}/search/aggs/agg_config.test.ts (98%) rename src/plugins/data/{public => common}/search/aggs/agg_config.ts (99%) rename src/plugins/data/{public => common}/search/aggs/agg_configs.test.ts (98%) rename src/plugins/data/{public => common}/search/aggs/agg_configs.ts (98%) rename src/plugins/data/{public => common}/search/aggs/agg_groups.ts (100%) rename src/plugins/data/{public => common}/search/aggs/agg_params.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/agg_params.ts (100%) rename src/plugins/data/{public => common}/search/aggs/agg_type.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/agg_type.ts (99%) rename src/plugins/data/{public => common}/search/aggs/agg_types.ts (66%) rename src/plugins/data/{public => common}/search/aggs/agg_types_registry.test.ts (54%) rename src/plugins/data/{public => common}/search/aggs/agg_types_registry.ts (57%) create mode 100644 src/plugins/data/common/search/aggs/aggs_service.test.ts create mode 100644 src/plugins/data/common/search/aggs/aggs_service.ts rename src/plugins/data/{public => common}/search/aggs/buckets/_interval_options.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/_terms_other_bucket_helper.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/_terms_other_bucket_helper.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/bucket_agg_type.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/bucket_agg_types.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/create_filter/date_histogram.test.ts (87%) rename src/plugins/data/{public => common}/search/aggs/buckets/create_filter/date_histogram.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/create_filter/date_range.test.ts (78%) rename src/plugins/data/{public => common}/search/aggs/buckets/create_filter/date_range.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/create_filter/filters.test.ts (83%) rename src/plugins/data/{public => common}/search/aggs/buckets/create_filter/filters.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/create_filter/histogram.test.ts (77%) rename src/plugins/data/{public => common}/search/aggs/buckets/create_filter/histogram.ts (80%) rename src/plugins/data/{public => common}/search/aggs/buckets/create_filter/ip_range.test.ts (96%) rename src/plugins/data/{public => common}/search/aggs/buckets/create_filter/ip_range.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/create_filter/range.test.ts (73%) rename src/plugins/data/{public => common}/search/aggs/buckets/create_filter/range.ts (78%) rename src/plugins/data/{public => common}/search/aggs/buckets/create_filter/terms.test.ts (97%) rename src/plugins/data/{public => common}/search/aggs/buckets/create_filter/terms.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/date_histogram.ts (92%) rename src/plugins/data/{public => common}/search/aggs/buckets/date_histogram_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/date_histogram_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/date_range.test.ts (84%) rename src/plugins/data/{public => common}/search/aggs/buckets/date_range.ts (88%) rename src/plugins/data/{public => common}/search/aggs/buckets/date_range_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/date_range_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/filter.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/filter_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/filter_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/filters.test.ts (93%) rename src/plugins/data/{public => common}/search/aggs/buckets/filters.ts (90%) rename src/plugins/data/{public => common}/search/aggs/buckets/filters_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/filters_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/geo_hash.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/geo_hash.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/geo_hash_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/geo_hash_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/geo_tile.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/geo_tile_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/geo_tile_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/histogram.test.ts (90%) rename src/plugins/data/{public => common}/search/aggs/buckets/histogram.ts (93%) rename src/plugins/data/{public => common}/search/aggs/buckets/histogram_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/histogram_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/index.ts (97%) rename src/plugins/data/{public => common}/search/aggs/buckets/ip_range.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/ip_range_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/ip_range_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/lib/cidr_mask.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/lib/cidr_mask.ts (97%) rename src/plugins/data/{public => common}/search/aggs/buckets/lib/date_range.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/lib/extended_bounds.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/lib/geo_point.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/lib/ip_range.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/lib/time_buckets/calc_auto_interval.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/lib/time_buckets/calc_auto_interval.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/lib/time_buckets/calc_es_interval.ts (97%) rename src/plugins/data/{public => common}/search/aggs/buckets/lib/time_buckets/index.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/lib/time_buckets/time_buckets.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/lib/time_buckets/time_buckets.ts (99%) rename src/plugins/data/{public => common}/search/aggs/buckets/migrate_include_exclude_format.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/range.test.ts (79%) rename src/plugins/data/{public => common}/search/aggs/buckets/range.ts (90%) rename src/plugins/data/{public => common}/search/aggs/buckets/range_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/range_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/range_key.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/significant_terms.test.ts (95%) rename src/plugins/data/{public => common}/search/aggs/buckets/significant_terms.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/significant_terms_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/significant_terms_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/terms.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/terms.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/terms_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/buckets/terms_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/index.test.ts (63%) rename src/plugins/data/{public => common}/search/aggs/metrics/avg.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/avg_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/avg_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/bucket_avg.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/bucket_avg_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/bucket_avg_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/bucket_max.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/bucket_max_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/bucket_max_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/bucket_min.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/bucket_min_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/bucket_min_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/bucket_sum.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/bucket_sum_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/bucket_sum_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/cardinality.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/cardinality_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/cardinality_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/count.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/count_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/count_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/cumulative_sum.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/cumulative_sum_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/cumulative_sum_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/derivative.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/derivative_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/derivative_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/geo_bounds.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/geo_bounds_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/geo_bounds_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/geo_centroid.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/geo_centroid_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/geo_centroid_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/index.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/lib/get_response_agg_config_class.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/lib/make_nested_label.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/lib/make_nested_label.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/lib/nested_agg_helpers.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/lib/ordinal_suffix.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/lib/ordinal_suffix.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/lib/parent_pipeline_agg_writer.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/lib/sibling_pipeline_agg_writer.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/max.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/max_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/max_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/median.test.ts (94%) rename src/plugins/data/{public => common}/search/aggs/metrics/median.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/median_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/median_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/metric_agg_type.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/metric_agg_types.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/min.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/min_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/min_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/moving_avg.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/moving_avg_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/moving_avg_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/parent_pipeline.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/percentile_ranks.test.ts (77%) rename src/plugins/data/{public => common}/search/aggs/metrics/percentile_ranks.ts (86%) rename src/plugins/data/{public => common}/search/aggs/metrics/percentile_ranks_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/percentile_ranks_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/percentiles.test.ts (96%) rename src/plugins/data/{public => common}/search/aggs/metrics/percentiles.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/percentiles_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/percentiles_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/percentiles_get_value.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/serial_diff.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/serial_diff_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/serial_diff_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/sibling_pipeline.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/std_deviation.test.ts (97%) rename src/plugins/data/{public => common}/search/aggs/metrics/std_deviation.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/std_deviation_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/std_deviation_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/sum.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/sum_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/sum_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/top_hit.test.ts (99%) rename src/plugins/data/{public => common}/search/aggs/metrics/top_hit.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/top_hit_fn.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/metrics/top_hit_fn.ts (100%) rename src/plugins/data/{public => common}/search/aggs/param_types/agg.ts (100%) rename src/plugins/data/{public => common}/search/aggs/param_types/base.ts (96%) rename src/plugins/data/{public => common}/search/aggs/param_types/field.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/param_types/field.ts (96%) rename src/plugins/data/{public => common}/search/aggs/param_types/index.ts (100%) rename src/plugins/data/{public => common}/search/aggs/param_types/json.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/param_types/json.ts (100%) rename src/plugins/data/{public => common}/search/aggs/param_types/optioned.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/param_types/optioned.ts (100%) rename src/plugins/data/{public => common}/search/aggs/param_types/string.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/param_types/string.ts (100%) rename src/plugins/data/{public => common}/search/aggs/test_helpers/function_wrapper.ts (100%) rename src/plugins/data/{public => common}/search/aggs/test_helpers/index.ts (86%) rename src/plugins/data/{public => common}/search/aggs/test_helpers/mock_agg_types_registry.ts (52%) create mode 100644 src/plugins/data/common/search/aggs/types.ts rename src/plugins/data/{public => common}/search/aggs/utils/calculate_auto_time_expression.ts (71%) rename src/plugins/data/common/search/aggs/{ => utils}/date_interval_utils/date_histogram_interval.test.ts (100%) rename src/plugins/data/common/search/aggs/{ => utils}/date_interval_utils/date_histogram_interval.ts (100%) rename src/plugins/data/common/search/aggs/{ => utils}/date_interval_utils/index.ts (100%) rename src/plugins/data/common/search/aggs/{ => utils}/date_interval_utils/invalid_es_calendar_interval_error.ts (100%) rename src/plugins/data/common/search/aggs/{ => utils}/date_interval_utils/invalid_es_interval_format_error.ts (100%) rename src/plugins/data/common/search/aggs/{ => utils}/date_interval_utils/is_valid_es_interval.ts (100%) rename src/plugins/data/common/search/aggs/{ => utils}/date_interval_utils/is_valid_interval.ts (100%) rename src/plugins/data/common/search/aggs/{ => utils}/date_interval_utils/least_common_interval.test.ts (100%) rename src/plugins/data/common/search/aggs/{ => utils}/date_interval_utils/least_common_interval.ts (100%) rename src/plugins/data/common/search/aggs/{ => utils}/date_interval_utils/least_common_multiple.test.ts (100%) rename src/plugins/data/common/search/aggs/{ => utils}/date_interval_utils/least_common_multiple.ts (100%) rename src/plugins/data/common/search/aggs/{ => utils}/date_interval_utils/parse_es_interval.test.ts (100%) rename src/plugins/data/common/search/aggs/{ => utils}/date_interval_utils/parse_es_interval.ts (100%) rename src/plugins/data/common/search/aggs/{ => utils}/date_interval_utils/parse_interval.test.ts (100%) rename src/plugins/data/common/search/aggs/{ => utils}/date_interval_utils/parse_interval.ts (100%) rename src/plugins/data/common/search/aggs/{ => utils}/date_interval_utils/to_absolute_dates.ts (95%) rename src/plugins/data/{public => common}/search/aggs/utils/get_format_with_aggs.test.ts (95%) rename src/plugins/data/{public => common}/search/aggs/utils/get_format_with_aggs.ts (95%) rename src/plugins/data/{public => common}/search/aggs/utils/get_parsed_value.ts (100%) rename src/plugins/data/{public => common}/search/aggs/utils/index.ts (93%) rename src/plugins/data/common/search/aggs/{ => utils}/ipv4_address.test.ts (100%) rename src/plugins/data/common/search/aggs/{ => utils}/ipv4_address.ts (100%) rename src/plugins/data/{public => common}/search/aggs/utils/prop_filter.test.ts (100%) rename src/plugins/data/{public => common}/search/aggs/utils/prop_filter.ts (100%) rename src/plugins/data/{public => common}/search/aggs/utils/to_angular_json.ts (100%) rename src/plugins/data/{public => common}/search/expressions/utils/courier_inspector_stats.ts (98%) create mode 100644 src/plugins/data/common/search/expressions/utils/index.ts rename src/plugins/data/{public => common}/search/tabify/buckets.test.ts (100%) rename src/plugins/data/{public => common}/search/tabify/buckets.ts (100%) rename src/plugins/data/{public => common}/search/tabify/get_columns.test.ts (100%) rename src/plugins/data/{public => common}/search/tabify/get_columns.ts (100%) rename src/plugins/data/{public => common}/search/tabify/index.ts (100%) rename src/plugins/data/{public => common}/search/tabify/response_writer.test.ts (100%) rename src/plugins/data/{public => common}/search/tabify/response_writer.ts (100%) rename src/plugins/data/{public => common}/search/tabify/tabify.test.ts (98%) rename src/plugins/data/{public => common}/search/tabify/tabify.ts (100%) rename src/plugins/data/{public => common}/search/tabify/types.ts (100%) create mode 100644 src/plugins/data/public/search/aggs/aggs_service.test.ts create mode 100644 src/plugins/data/public/search/aggs/aggs_service.ts create mode 100644 src/plugins/data/server/search/aggs/aggs_service.test.ts create mode 100644 src/plugins/data/server/search/aggs/aggs_service.ts create mode 100644 src/plugins/data/server/search/aggs/index.ts create mode 100644 src/plugins/data/server/search/aggs/mocks.ts create mode 100644 src/plugins/data/server/search/aggs/types.ts diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.baseformatterspublic.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.baseformatterspublic.md index 25f046983cbce..1aa9f460c4fac 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.baseformatterspublic.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.baseformatterspublic.md @@ -7,5 +7,5 @@ Signature: ```typescript -baseFormattersPublic: (import("../../common").FieldFormatInstanceType | typeof DateNanosFormat | typeof DateFormat)[] +baseFormattersPublic: (import("../../common").FieldFormatInstanceType | typeof DateFormat | typeof DateNanosFormat)[] ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md index 6c8f7fbdb170b..22dc92c275670 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md @@ -14,7 +14,7 @@ search: { intervalOptions: ({ display: string; val: string; - enabled(agg: import("./search/aggs/buckets/bucket_agg_type").IBucketAggConfig): boolean | "" | undefined; + enabled(agg: import("../common").IBucketAggConfig): boolean | "" | undefined; } | { display: string; val: string; @@ -23,9 +23,9 @@ search: { InvalidEsIntervalFormatError: typeof InvalidEsIntervalFormatError; Ipv4Address: typeof Ipv4Address; isDateHistogramBucketAggConfig: typeof isDateHistogramBucketAggConfig; - isNumberType: (agg: import("./search").AggConfig) => boolean; - isStringType: (agg: import("./search").AggConfig) => boolean; - isType: (...types: string[]) => (agg: import("./search").AggConfig) => boolean; + isNumberType: (agg: import("../common").AggConfig) => boolean; + isStringType: (agg: import("../common").AggConfig) => boolean; + isType: (...types: string[]) => (agg: import("../common").AggConfig) => boolean; isValidEsInterval: typeof isValidEsInterval; isValidInterval: typeof isValidInterval; parentPipelineType: string; diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggconfigoptions.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggconfigoptions.md new file mode 100644 index 0000000000000..effb2e798ad6f --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggconfigoptions.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [AggConfigOptions](./kibana-plugin-plugins-data-server.aggconfigoptions.md) + +## AggConfigOptions type + +Signature: + +```typescript +export declare type AggConfigOptions = Assign; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.agggrouplabels.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.agggrouplabels.md new file mode 100644 index 0000000000000..cf0caee6ac33e --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.agggrouplabels.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [AggGroupLabels](./kibana-plugin-plugins-data-server.agggrouplabels.md) + +## AggGroupLabels variable + +Signature: + +```typescript +AggGroupLabels: { + buckets: string; + metrics: string; + none: string; +} +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.agggroupname.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.agggroupname.md new file mode 100644 index 0000000000000..403294eba1367 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.agggroupname.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [AggGroupName](./kibana-plugin-plugins-data-server.agggroupname.md) + +## AggGroupName type + +Signature: + +```typescript +export declare type AggGroupName = $Values; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.agggroupnames.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.agggroupnames.md new file mode 100644 index 0000000000000..11d194723c521 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.agggroupnames.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [AggGroupNames](./kibana-plugin-plugins-data-server.agggroupnames.md) + +## AggGroupNames variable + +Signature: + +```typescript +AggGroupNames: Readonly<{ + Buckets: "buckets"; + Metrics: "metrics"; + None: "none"; +}> +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparam.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparam.md new file mode 100644 index 0000000000000..893501666b9a0 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparam.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [AggParam](./kibana-plugin-plugins-data-server.aggparam.md) + +## AggParam type + +Signature: + +```typescript +export declare type AggParam = BaseParamType; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamoption.display.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamoption.display.md new file mode 100644 index 0000000000000..1030056e16afe --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamoption.display.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [AggParamOption](./kibana-plugin-plugins-data-server.aggparamoption.md) > [display](./kibana-plugin-plugins-data-server.aggparamoption.display.md) + +## AggParamOption.display property + +Signature: + +```typescript +display: string; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamoption.enabled.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamoption.enabled.md new file mode 100644 index 0000000000000..8b1fcc4a1bbd0 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamoption.enabled.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [AggParamOption](./kibana-plugin-plugins-data-server.aggparamoption.md) > [enabled](./kibana-plugin-plugins-data-server.aggparamoption.enabled.md) + +## AggParamOption.enabled() method + +Signature: + +```typescript +enabled?(agg: AggConfig): boolean; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| agg | AggConfig | | + +Returns: + +`boolean` + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamoption.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamoption.md new file mode 100644 index 0000000000000..a7ddcf395cab4 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamoption.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [AggParamOption](./kibana-plugin-plugins-data-server.aggparamoption.md) + +## AggParamOption interface + +Signature: + +```typescript +export interface AggParamOption +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [display](./kibana-plugin-plugins-data-server.aggparamoption.display.md) | string | | +| [val](./kibana-plugin-plugins-data-server.aggparamoption.val.md) | string | | + +## Methods + +| Method | Description | +| --- | --- | +| [enabled(agg)](./kibana-plugin-plugins-data-server.aggparamoption.enabled.md) | | + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamoption.val.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamoption.val.md new file mode 100644 index 0000000000000..2c87c91c294d9 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamoption.val.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [AggParamOption](./kibana-plugin-plugins-data-server.aggparamoption.md) > [val](./kibana-plugin-plugins-data-server.aggparamoption.val.md) + +## AggParamOption.val property + +Signature: + +```typescript +val: string; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamtype._constructor_.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamtype._constructor_.md new file mode 100644 index 0000000000000..2e1b16855987e --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamtype._constructor_.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [AggParamType](./kibana-plugin-plugins-data-server.aggparamtype.md) > [(constructor)](./kibana-plugin-plugins-data-server.aggparamtype._constructor_.md) + +## AggParamType.(constructor) + +Constructs a new instance of the `AggParamType` class + +Signature: + +```typescript +constructor(config: Record); +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| config | Record<string, any> | | + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamtype.allowedaggs.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamtype.allowedaggs.md new file mode 100644 index 0000000000000..36179a9ce3569 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamtype.allowedaggs.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [AggParamType](./kibana-plugin-plugins-data-server.aggparamtype.md) > [allowedAggs](./kibana-plugin-plugins-data-server.aggparamtype.allowedaggs.md) + +## AggParamType.allowedAggs property + +Signature: + +```typescript +allowedAggs: string[]; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamtype.makeagg.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamtype.makeagg.md new file mode 100644 index 0000000000000..bd5d2fca77659 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamtype.makeagg.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [AggParamType](./kibana-plugin-plugins-data-server.aggparamtype.md) > [makeAgg](./kibana-plugin-plugins-data-server.aggparamtype.makeagg.md) + +## AggParamType.makeAgg property + +Signature: + +```typescript +makeAgg: (agg: TAggConfig, state?: AggConfigSerialized) => TAggConfig; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamtype.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamtype.md new file mode 100644 index 0000000000000..00c1906dd880b --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.aggparamtype.md @@ -0,0 +1,25 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [AggParamType](./kibana-plugin-plugins-data-server.aggparamtype.md) + +## AggParamType class + +Signature: + +```typescript +export declare class AggParamType extends BaseParamType +``` + +## Constructors + +| Constructor | Modifiers | Description | +| --- | --- | --- | +| [(constructor)(config)](./kibana-plugin-plugins-data-server.aggparamtype._constructor_.md) | | Constructs a new instance of the AggParamType class | + +## Properties + +| Property | Modifiers | Type | Description | +| --- | --- | --- | --- | +| [allowedAggs](./kibana-plugin-plugins-data-server.aggparamtype.allowedaggs.md) | | string[] | | +| [makeAgg](./kibana-plugin-plugins-data-server.aggparamtype.makeagg.md) | | (agg: TAggConfig, state?: AggConfigSerialized) => TAggConfig | | + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.bucket_types.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.bucket_types.md new file mode 100644 index 0000000000000..568e435754545 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.bucket_types.md @@ -0,0 +1,28 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [BUCKET\_TYPES](./kibana-plugin-plugins-data-server.bucket_types.md) + +## BUCKET\_TYPES enum + +Signature: + +```typescript +export declare enum BUCKET_TYPES +``` + +## Enumeration Members + +| Member | Value | Description | +| --- | --- | --- | +| DATE\_HISTOGRAM | "date_histogram" | | +| DATE\_RANGE | "date_range" | | +| FILTER | "filter" | | +| FILTERS | "filters" | | +| GEOHASH\_GRID | "geohash_grid" | | +| GEOTILE\_GRID | "geotile_grid" | | +| HISTOGRAM | "histogram" | | +| IP\_RANGE | "ip_range" | | +| RANGE | "range" | | +| SIGNIFICANT\_TERMS | "significant_terms" | | +| TERMS | "terms" | | + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iaggconfig.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iaggconfig.md new file mode 100644 index 0000000000000..261b6e0b3bac1 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iaggconfig.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IAggConfig](./kibana-plugin-plugins-data-server.iaggconfig.md) + +## IAggConfig type + + AggConfig + + This class represents an aggregation, which is displayed in the left-hand nav of the Visualize app. + +Signature: + +```typescript +export declare type IAggConfig = AggConfig; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iaggtype.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iaggtype.md new file mode 100644 index 0000000000000..d5868e1b0917e --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iaggtype.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IAggType](./kibana-plugin-plugins-data-server.iaggtype.md) + +## IAggType type + +Signature: + +```typescript +export declare type IAggType = AggType; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.ifieldparamtype.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.ifieldparamtype.md new file mode 100644 index 0000000000000..4937245647f4e --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.ifieldparamtype.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IFieldParamType](./kibana-plugin-plugins-data-server.ifieldparamtype.md) + +## IFieldParamType type + +Signature: + +```typescript +export declare type IFieldParamType = FieldParamType; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.imetricaggtype.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.imetricaggtype.md new file mode 100644 index 0000000000000..ae779c2b1510f --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.imetricaggtype.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IMetricAggType](./kibana-plugin-plugins-data-server.imetricaggtype.md) + +## IMetricAggType type + +Signature: + +```typescript +export declare type IMetricAggType = MetricAggType; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.aggs.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.aggs.md new file mode 100644 index 0000000000000..86bd4ab694e11 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.aggs.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchSetup](./kibana-plugin-plugins-data-server.isearchsetup.md) > [aggs](./kibana-plugin-plugins-data-server.isearchsetup.aggs.md) + +## ISearchSetup.aggs property + +Signature: + +```typescript +aggs: AggsSetup; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.md index d9749bc44f45a..e5b11a0b997ea 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.md @@ -14,6 +14,7 @@ export interface ISearchSetup | Property | Type | Description | | --- | --- | --- | +| [aggs](./kibana-plugin-plugins-data-server.isearchsetup.aggs.md) | AggsSetup | | | [registerSearchStrategy](./kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md) | (name: string, strategy: ISearchStrategy) => void | Extension point exposed for other plugins to register their own search strategies. | | [usage](./kibana-plugin-plugins-data-server.isearchsetup.usage.md) | SearchUsage | Used internally for telemetry | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.aggs.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.aggs.md new file mode 100644 index 0000000000000..8da429a07708c --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.aggs.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchStart](./kibana-plugin-plugins-data-server.isearchstart.md) > [aggs](./kibana-plugin-plugins-data-server.isearchstart.aggs.md) + +## ISearchStart.aggs property + +Signature: + +```typescript +aggs: AggsStart; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.md index 308ce3cb568bc..3762da963d4d9 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.md @@ -14,6 +14,7 @@ export interface ISearchStart | Property | Type | Description | | --- | --- | --- | +| [aggs](./kibana-plugin-plugins-data-server.isearchstart.aggs.md) | AggsStart | | | [getSearchStrategy](./kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md) | (name: string) => ISearchStrategy | Get other registered search strategies. For example, if a new strategy needs to use the already-registered ES search strategy, it can use this function to accomplish that. | | [search](./kibana-plugin-plugins-data-server.isearchstart.search.md) | (context: RequestHandlerContext, request: IKibanaSearchRequest, options: ISearchOptions) => Promise<IKibanaSearchResponse> | | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md index f472064c87755..0292e08063fbb 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md @@ -8,15 +8,19 @@ | Class | Description | | --- | --- | +| [AggParamType](./kibana-plugin-plugins-data-server.aggparamtype.md) | | | [IndexPatternsFetcher](./kibana-plugin-plugins-data-server.indexpatternsfetcher.md) | | +| [OptionedParamType](./kibana-plugin-plugins-data-server.optionedparamtype.md) | | | [Plugin](./kibana-plugin-plugins-data-server.plugin.md) | | ## Enumerations | Enumeration | Description | | --- | --- | +| [BUCKET\_TYPES](./kibana-plugin-plugins-data-server.bucket_types.md) | | | [ES\_FIELD\_TYPES](./kibana-plugin-plugins-data-server.es_field_types.md) | \* | | [KBN\_FIELD\_TYPES](./kibana-plugin-plugins-data-server.kbn_field_types.md) | \* | +| [METRIC\_TYPES](./kibana-plugin-plugins-data-server.metric_types.md) | | ## Functions @@ -33,6 +37,7 @@ | Interface | Description | | --- | --- | +| [AggParamOption](./kibana-plugin-plugins-data-server.aggparamoption.md) | | | [EsQueryConfig](./kibana-plugin-plugins-data-server.esqueryconfig.md) | | | [FieldFormatConfig](./kibana-plugin-plugins-data-server.fieldformatconfig.md) | | | [Filter](./kibana-plugin-plugins-data-server.filter.md) | | @@ -48,17 +53,22 @@ | [ISearchStart](./kibana-plugin-plugins-data-server.isearchstart.md) | | | [ISearchStrategy](./kibana-plugin-plugins-data-server.isearchstrategy.md) | Search strategy interface contains a search method that takes in a request and returns a promise that resolves to a response. | | [KueryNode](./kibana-plugin-plugins-data-server.kuerynode.md) | | +| [OptionedValueProp](./kibana-plugin-plugins-data-server.optionedvalueprop.md) | | | [PluginSetup](./kibana-plugin-plugins-data-server.pluginsetup.md) | | | [PluginStart](./kibana-plugin-plugins-data-server.pluginstart.md) | | | [Query](./kibana-plugin-plugins-data-server.query.md) | | | [RefreshInterval](./kibana-plugin-plugins-data-server.refreshinterval.md) | | | [SearchUsage](./kibana-plugin-plugins-data-server.searchusage.md) | | +| [TabbedAggColumn](./kibana-plugin-plugins-data-server.tabbedaggcolumn.md) | \* | +| [TabbedTable](./kibana-plugin-plugins-data-server.tabbedtable.md) | \* | | [TimeRange](./kibana-plugin-plugins-data-server.timerange.md) | | ## Variables | Variable | Description | | --- | --- | +| [AggGroupLabels](./kibana-plugin-plugins-data-server.agggrouplabels.md) | | +| [AggGroupNames](./kibana-plugin-plugins-data-server.agggroupnames.md) | | | [castEsToKbnFieldTypeName](./kibana-plugin-plugins-data-server.castestokbnfieldtypename.md) | Get the KbnFieldType name for an esType string | | [config](./kibana-plugin-plugins-data-server.config.md) | | | [esFilters](./kibana-plugin-plugins-data-server.esfilters.md) | | @@ -73,8 +83,16 @@ | Type Alias | Description | | --- | --- | +| [AggConfigOptions](./kibana-plugin-plugins-data-server.aggconfigoptions.md) | | +| [AggGroupName](./kibana-plugin-plugins-data-server.agggroupname.md) | | +| [AggParam](./kibana-plugin-plugins-data-server.aggparam.md) | | | [EsaggsExpressionFunctionDefinition](./kibana-plugin-plugins-data-server.esaggsexpressionfunctiondefinition.md) | | | [FieldFormatsGetConfigFn](./kibana-plugin-plugins-data-server.fieldformatsgetconfigfn.md) | | +| [IAggConfig](./kibana-plugin-plugins-data-server.iaggconfig.md) | AggConfig This class represents an aggregation, which is displayed in the left-hand nav of the Visualize app. | +| [IAggType](./kibana-plugin-plugins-data-server.iaggtype.md) | | | [IFieldFormatsRegistry](./kibana-plugin-plugins-data-server.ifieldformatsregistry.md) | | +| [IFieldParamType](./kibana-plugin-plugins-data-server.ifieldparamtype.md) | | +| [IMetricAggType](./kibana-plugin-plugins-data-server.imetricaggtype.md) | | | [ParsedInterval](./kibana-plugin-plugins-data-server.parsedinterval.md) | | +| [TabbedAggRow](./kibana-plugin-plugins-data-server.tabbedaggrow.md) | \* | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.metric_types.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.metric_types.md new file mode 100644 index 0000000000000..49df98b6d70a1 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.metric_types.md @@ -0,0 +1,38 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [METRIC\_TYPES](./kibana-plugin-plugins-data-server.metric_types.md) + +## METRIC\_TYPES enum + +Signature: + +```typescript +export declare enum METRIC_TYPES +``` + +## Enumeration Members + +| Member | Value | Description | +| --- | --- | --- | +| AVG | "avg" | | +| AVG\_BUCKET | "avg_bucket" | | +| CARDINALITY | "cardinality" | | +| COUNT | "count" | | +| CUMULATIVE\_SUM | "cumulative_sum" | | +| DERIVATIVE | "derivative" | | +| GEO\_BOUNDS | "geo_bounds" | | +| GEO\_CENTROID | "geo_centroid" | | +| MAX | "max" | | +| MAX\_BUCKET | "max_bucket" | | +| MEDIAN | "median" | | +| MIN | "min" | | +| MIN\_BUCKET | "min_bucket" | | +| MOVING\_FN | "moving_avg" | | +| PERCENTILE\_RANKS | "percentile_ranks" | | +| PERCENTILES | "percentiles" | | +| SERIAL\_DIFF | "serial_diff" | | +| STD\_DEV | "std_dev" | | +| SUM | "sum" | | +| SUM\_BUCKET | "sum_bucket" | | +| TOP\_HITS | "top_hits" | | + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedparamtype._constructor_.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedparamtype._constructor_.md new file mode 100644 index 0000000000000..3b2fd2218709a --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedparamtype._constructor_.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [OptionedParamType](./kibana-plugin-plugins-data-server.optionedparamtype.md) > [(constructor)](./kibana-plugin-plugins-data-server.optionedparamtype._constructor_.md) + +## OptionedParamType.(constructor) + +Constructs a new instance of the `OptionedParamType` class + +Signature: + +```typescript +constructor(config: Record); +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| config | Record<string, any> | | + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedparamtype.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedparamtype.md new file mode 100644 index 0000000000000..6bf2ef4baa915 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedparamtype.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [OptionedParamType](./kibana-plugin-plugins-data-server.optionedparamtype.md) + +## OptionedParamType class + +Signature: + +```typescript +export declare class OptionedParamType extends BaseParamType +``` + +## Constructors + +| Constructor | Modifiers | Description | +| --- | --- | --- | +| [(constructor)(config)](./kibana-plugin-plugins-data-server.optionedparamtype._constructor_.md) | | Constructs a new instance of the OptionedParamType class | + +## Properties + +| Property | Modifiers | Type | Description | +| --- | --- | --- | --- | +| [options](./kibana-plugin-plugins-data-server.optionedparamtype.options.md) | | OptionedValueProp[] | | + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedparamtype.options.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedparamtype.options.md new file mode 100644 index 0000000000000..868619ad5a9e0 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedparamtype.options.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [OptionedParamType](./kibana-plugin-plugins-data-server.optionedparamtype.md) > [options](./kibana-plugin-plugins-data-server.optionedparamtype.options.md) + +## OptionedParamType.options property + +Signature: + +```typescript +options: OptionedValueProp[]; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedvalueprop.disabled.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedvalueprop.disabled.md new file mode 100644 index 0000000000000..e0a21a8727614 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedvalueprop.disabled.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [OptionedValueProp](./kibana-plugin-plugins-data-server.optionedvalueprop.md) > [disabled](./kibana-plugin-plugins-data-server.optionedvalueprop.disabled.md) + +## OptionedValueProp.disabled property + +Signature: + +```typescript +disabled?: boolean; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedvalueprop.iscompatible.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedvalueprop.iscompatible.md new file mode 100644 index 0000000000000..de3ecc0b97a64 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedvalueprop.iscompatible.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [OptionedValueProp](./kibana-plugin-plugins-data-server.optionedvalueprop.md) > [isCompatible](./kibana-plugin-plugins-data-server.optionedvalueprop.iscompatible.md) + +## OptionedValueProp.isCompatible property + +Signature: + +```typescript +isCompatible: (agg: IAggConfig) => boolean; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedvalueprop.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedvalueprop.md new file mode 100644 index 0000000000000..ef2440035c83b --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedvalueprop.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [OptionedValueProp](./kibana-plugin-plugins-data-server.optionedvalueprop.md) + +## OptionedValueProp interface + +Signature: + +```typescript +export interface OptionedValueProp +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [disabled](./kibana-plugin-plugins-data-server.optionedvalueprop.disabled.md) | boolean | | +| [isCompatible](./kibana-plugin-plugins-data-server.optionedvalueprop.iscompatible.md) | (agg: IAggConfig) => boolean | | +| [text](./kibana-plugin-plugins-data-server.optionedvalueprop.text.md) | string | | +| [value](./kibana-plugin-plugins-data-server.optionedvalueprop.value.md) | string | | + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedvalueprop.text.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedvalueprop.text.md new file mode 100644 index 0000000000000..0a2b3ac708038 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedvalueprop.text.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [OptionedValueProp](./kibana-plugin-plugins-data-server.optionedvalueprop.md) > [text](./kibana-plugin-plugins-data-server.optionedvalueprop.text.md) + +## OptionedValueProp.text property + +Signature: + +```typescript +text: string; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedvalueprop.value.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedvalueprop.value.md new file mode 100644 index 0000000000000..76618558d0479 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.optionedvalueprop.value.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [OptionedValueProp](./kibana-plugin-plugins-data-server.optionedvalueprop.md) > [value](./kibana-plugin-plugins-data-server.optionedvalueprop.value.md) + +## OptionedValueProp.value property + +Signature: + +```typescript +value: string; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md index a6fdfdf6891c8..18fca3d2c8a66 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md @@ -7,10 +7,10 @@ Signature: ```typescript -setup(core: CoreSetup, { usageCollection }: DataPluginSetupDependencies): { +setup(core: CoreSetup, { expressions, usageCollection }: DataPluginSetupDependencies): { search: ISearchSetup; fieldFormats: { - register: (customFieldFormat: import("../common").FieldFormatInstanceType) => number; + register: (customFieldFormat: import("../public").FieldFormatInstanceType) => number; }; }; ``` @@ -19,15 +19,15 @@ setup(core: CoreSetup, { usageCollection }: DataPluginS | Parameter | Type | Description | | --- | --- | --- | -| core | CoreSetup<object, DataPluginStart> | | -| { usageCollection } | DataPluginSetupDependencies | | +| core | CoreSetup<DataPluginStartDependencies, DataPluginStart> | | +| { expressions, usageCollection } | DataPluginSetupDependencies | | Returns: `{ search: ISearchSetup; fieldFormats: { - register: (customFieldFormat: import("../common").FieldFormatInstanceType) => number; + register: (customFieldFormat: import("../public").FieldFormatInstanceType) => number; }; }` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.search.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.search.md index 09563358100b3..9e38ce3f64f38 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.search.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.search.md @@ -9,15 +9,35 @@ ```typescript search: { aggs: { + CidrMask: typeof CidrMask; dateHistogramInterval: typeof dateHistogramInterval; + intervalOptions: ({ + display: string; + val: string; + enabled(agg: import("../common").IBucketAggConfig): boolean | "" | undefined; + } | { + display: string; + val: string; + })[]; InvalidEsCalendarIntervalError: typeof InvalidEsCalendarIntervalError; InvalidEsIntervalFormatError: typeof InvalidEsIntervalFormatError; Ipv4Address: typeof Ipv4Address; + isNumberType: (agg: import("../common").AggConfig) => boolean; + isStringType: (agg: import("../common").AggConfig) => boolean; + isType: (...types: string[]) => (agg: import("../common").AggConfig) => boolean; isValidEsInterval: typeof isValidEsInterval; isValidInterval: typeof isValidInterval; + parentPipelineType: string; parseEsInterval: typeof parseEsInterval; parseInterval: typeof parseInterval; + propFilter: typeof propFilter; + siblingPipelineType: string; + termsAggFilter: string[]; toAbsoluteDates: typeof toAbsoluteDates; }; + getRequestInspectorStats: typeof getRequestInspectorStats; + getResponseInspectorStats: typeof getResponseInspectorStats; + tabifyAggResponse: typeof tabifyAggResponse; + tabifyGetColumns: typeof tabifyGetColumns; } ``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.aggconfig.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.aggconfig.md new file mode 100644 index 0000000000000..9870f7380e16a --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.aggconfig.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [TabbedAggColumn](./kibana-plugin-plugins-data-server.tabbedaggcolumn.md) > [aggConfig](./kibana-plugin-plugins-data-server.tabbedaggcolumn.aggconfig.md) + +## TabbedAggColumn.aggConfig property + +Signature: + +```typescript +aggConfig: IAggConfig; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.id.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.id.md new file mode 100644 index 0000000000000..4f5a964a07a0c --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.id.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [TabbedAggColumn](./kibana-plugin-plugins-data-server.tabbedaggcolumn.md) > [id](./kibana-plugin-plugins-data-server.tabbedaggcolumn.id.md) + +## TabbedAggColumn.id property + +Signature: + +```typescript +id: string; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.md new file mode 100644 index 0000000000000..5e47f745fa17a --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [TabbedAggColumn](./kibana-plugin-plugins-data-server.tabbedaggcolumn.md) + +## TabbedAggColumn interface + +\* + +Signature: + +```typescript +export interface TabbedAggColumn +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [aggConfig](./kibana-plugin-plugins-data-server.tabbedaggcolumn.aggconfig.md) | IAggConfig | | +| [id](./kibana-plugin-plugins-data-server.tabbedaggcolumn.id.md) | string | | +| [name](./kibana-plugin-plugins-data-server.tabbedaggcolumn.name.md) | string | | + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.name.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.name.md new file mode 100644 index 0000000000000..8a07e2708066f --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggcolumn.name.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [TabbedAggColumn](./kibana-plugin-plugins-data-server.tabbedaggcolumn.md) > [name](./kibana-plugin-plugins-data-server.tabbedaggcolumn.name.md) + +## TabbedAggColumn.name property + +Signature: + +```typescript +name: string; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggrow.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggrow.md new file mode 100644 index 0000000000000..d592aeff89639 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedaggrow.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [TabbedAggRow](./kibana-plugin-plugins-data-server.tabbedaggrow.md) + +## TabbedAggRow type + +\* + +Signature: + +```typescript +export declare type TabbedAggRow = Record; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.columns.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.columns.md new file mode 100644 index 0000000000000..55f079c581c8b --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.columns.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [TabbedTable](./kibana-plugin-plugins-data-server.tabbedtable.md) > [columns](./kibana-plugin-plugins-data-server.tabbedtable.columns.md) + +## TabbedTable.columns property + +Signature: + +```typescript +columns: TabbedAggColumn[]; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.md new file mode 100644 index 0000000000000..1bb055a2a3ce9 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [TabbedTable](./kibana-plugin-plugins-data-server.tabbedtable.md) + +## TabbedTable interface + +\* + +Signature: + +```typescript +export interface TabbedTable +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [columns](./kibana-plugin-plugins-data-server.tabbedtable.columns.md) | TabbedAggColumn[] | | +| [rows](./kibana-plugin-plugins-data-server.tabbedtable.rows.md) | TabbedAggRow[] | | + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.rows.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.rows.md new file mode 100644 index 0000000000000..b783919a26573 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tabbedtable.rows.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [TabbedTable](./kibana-plugin-plugins-data-server.tabbedtable.md) > [rows](./kibana-plugin-plugins-data-server.tabbedtable.rows.md) + +## TabbedTable.rows property + +Signature: + +```typescript +rows: TabbedAggRow[]; +``` 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 35380ada51a0a..5ef1149146afe 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 @@ -26,7 +26,7 @@ import { getAggTypes, AggConfigs, // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../src/plugins/data/public/search/aggs'; +} from '../../../../../src/plugins/data/common/search/aggs'; import { ComponentRegistry } from '../../../../../src/plugins/advanced_settings/public/'; import { UI_SETTINGS } from '../../../../../src/plugins/data/public/'; import { @@ -184,12 +184,13 @@ const mockAggTypesRegistry = () => { const registry = new AggTypesRegistry(); const registrySetup = registry.setup(); const aggTypes = getAggTypes({ - uiSettings: mockCoreSetup.uiSettings, - query: querySetup, - getInternalStartServices: () => ({ - fieldFormats: getFieldFormatsRegistry(mockCoreStart), - notifications: mockCoreStart.notifications, + calculateBounds: sinon.fake(), + getConfig: sinon.fake(), + getFieldFormatsStart: () => ({ + deserialize: sinon.fake(), + getDefaultInstance: sinon.fake(), }), + isDefaultTimezone: () => true, }); aggTypes.buckets.forEach((type) => registrySetup.registerBucket(type)); aggTypes.metrics.forEach((type) => registrySetup.registerMetric(type)); @@ -240,7 +241,6 @@ export const npSetup = { query: querySetup, search: { aggs: { - calculateAutoTimeExpression: sinon.fake(), types: aggTypesRegistry.setup(), }, __LEGACY: { diff --git a/src/plugins/data/common/field_formats/converters/source.ts b/src/plugins/data/common/field_formats/converters/source.ts index f00261e00971a..9c81bb011e127 100644 --- a/src/plugins/data/common/field_formats/converters/source.ts +++ b/src/plugins/data/common/field_formats/converters/source.ts @@ -22,7 +22,7 @@ import { shortenDottedString } from '../../utils'; import { KBN_FIELD_TYPES } from '../../kbn_field_types/types'; import { FieldFormat } from '../field_format'; import { TextContextTypeConvert, HtmlContextTypeConvert, FIELD_FORMAT_IDS } from '../types'; -import { UI_SETTINGS } from '../../'; +import { UI_SETTINGS } from '../../constants'; /** * Remove all of the whitespace between html tags diff --git a/src/plugins/data/common/field_formats/field_formats_registry.ts b/src/plugins/data/common/field_formats/field_formats_registry.ts index 84bedd2f9dee0..4b847ebc358d7 100644 --- a/src/plugins/data/common/field_formats/field_formats_registry.ts +++ b/src/plugins/data/common/field_formats/field_formats_registry.ts @@ -33,7 +33,7 @@ import { baseFormatters } from './constants/base_formatters'; import { FieldFormat } from './field_format'; import { SerializedFieldFormat } from '../../../expressions/common/types'; import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '../types'; -import { UI_SETTINGS } from '../'; +import { UI_SETTINGS } from '../constants'; export class FieldFormatsRegistry { protected fieldFormats: Map = new Map(); diff --git a/src/plugins/data/common/field_formats/mocks.ts b/src/plugins/data/common/field_formats/mocks.ts index 9bbaefe2d146a..ddf9cf246ec7d 100644 --- a/src/plugins/data/common/field_formats/mocks.ts +++ b/src/plugins/data/common/field_formats/mocks.ts @@ -24,6 +24,7 @@ export const fieldFormatsMock: IFieldFormatsRegistry = { getByFieldType: jest.fn(), getDefaultConfig: jest.fn(), getDefaultInstance: jest.fn().mockImplementation(() => ({ + convert: jest.fn().mockImplementation((t: string) => t), getConverterFor: jest.fn().mockImplementation(() => (t: string) => t), })) as any, getDefaultInstanceCacheResolver: jest.fn(), diff --git a/src/plugins/data/common/index.ts b/src/plugins/data/common/index.ts index ca6bc965d48c5..bc7080e7d450b 100644 --- a/src/plugins/data/common/index.ts +++ b/src/plugins/data/common/index.ts @@ -25,7 +25,5 @@ export * from './index_patterns'; export * from './kbn_field_types'; export * from './query'; export * from './search'; -export * from './search/aggs'; -export * from './search/expressions'; export * from './types'; export * from './utils'; diff --git a/src/plugins/data/common/index_patterns/fields/field_list.ts b/src/plugins/data/common/index_patterns/fields/field_list.ts index 172da9f9ca43f..34bd69230a2e4 100644 --- a/src/plugins/data/common/index_patterns/fields/field_list.ts +++ b/src/plugins/data/common/index_patterns/fields/field_list.ts @@ -18,10 +18,11 @@ */ import { findIndex } from 'lodash'; -import { IFieldType, shortenDottedString } from '../../../common'; +import { IFieldType } from './types'; import { IndexPatternField } from './index_pattern_field'; import { OnNotification, FieldSpec } from '../types'; import { IndexPattern } from '../index_patterns'; +import { shortenDottedString } from '../../utils'; type FieldMap = Map; diff --git a/src/plugins/data/common/index_patterns/fields/index_pattern_field.ts b/src/plugins/data/common/index_patterns/fields/index_pattern_field.ts index 679de103f8019..965f1a7f63065 100644 --- a/src/plugins/data/common/index_patterns/fields/index_pattern_field.ts +++ b/src/plugins/data/common/index_patterns/fields/index_pattern_field.ts @@ -18,13 +18,10 @@ */ import { i18n } from '@kbn/i18n'; -import { - IFieldType, - KbnFieldType, - getKbnFieldType, - KBN_FIELD_TYPES, - FieldFormat, -} from '../../../common'; +import { KbnFieldType, getKbnFieldType } from '../../kbn_field_types'; +import { KBN_FIELD_TYPES } from '../../kbn_field_types/types'; +import { FieldFormat } from '../../field_formats'; +import { IFieldType } from './types'; import { OnNotification, FieldSpec } from '../types'; import { IndexPattern } from '../index_patterns'; diff --git a/src/plugins/data/public/search/aggs/agg_config.test.ts b/src/plugins/data/common/search/aggs/agg_config.test.ts similarity index 98% rename from src/plugins/data/public/search/aggs/agg_config.test.ts rename to src/plugins/data/common/search/aggs/agg_config.test.ts index f9279e06d14a9..a443eacee731c 100644 --- a/src/plugins/data/public/search/aggs/agg_config.test.ts +++ b/src/plugins/data/common/search/aggs/agg_config.test.ts @@ -25,7 +25,8 @@ import { AggType } from './agg_type'; import { AggTypesRegistryStart } from './agg_types_registry'; import { mockAggTypesRegistry } from './test_helpers'; import { MetricAggType } from './metrics/metric_agg_type'; -import { IndexPattern, IIndexPatternFieldList } from '../../index_patterns'; +import { IndexPattern } from '../../index_patterns/index_patterns/index_pattern'; +import { IIndexPatternFieldList } from '../../index_patterns/fields'; describe('AggConfig', () => { let indexPattern: IndexPattern; @@ -622,7 +623,7 @@ describe('AggConfig', () => { it('creates a subexpression for param types other than "agg" which have specified toExpressionAst', () => { // Overwrite the `ranges` param in the `range` agg with a mock toExpressionAst function - const range: MetricAggType = typesRegistry.get('range'); + const range = typesRegistry.get('range') as MetricAggType; range.expressionName = 'aggRange'; const rangesParam = range.params.find((p) => p.name === 'ranges'); rangesParam!.toExpressionAst = (val: any) => ({ diff --git a/src/plugins/data/public/search/aggs/agg_config.ts b/src/plugins/data/common/search/aggs/agg_config.ts similarity index 99% rename from src/plugins/data/public/search/aggs/agg_config.ts rename to src/plugins/data/common/search/aggs/agg_config.ts index 31618eac18e98..b5747ce7bb9bd 100644 --- a/src/plugins/data/public/search/aggs/agg_config.ts +++ b/src/plugins/data/common/search/aggs/agg_config.ts @@ -20,16 +20,17 @@ import _ from 'lodash'; import { i18n } from '@kbn/i18n'; import { Assign, Ensure } from '@kbn/utility-types'; + +import { FetchOptions, ISearchSource } from 'src/plugins/data/public'; import { ExpressionAstFunction, ExpressionAstArgument, SerializedFieldFormat, } from 'src/plugins/expressions/common'; + import { IAggType } from './agg_type'; import { writeParams } from './agg_params'; import { IAggConfigs } from './agg_configs'; -import { FetchOptions } from '../fetch'; -import { ISearchSource } from '../search_source'; type State = string | number | boolean | null | undefined | SerializableState; diff --git a/src/plugins/data/public/search/aggs/agg_configs.test.ts b/src/plugins/data/common/search/aggs/agg_configs.test.ts similarity index 98% rename from src/plugins/data/public/search/aggs/agg_configs.test.ts rename to src/plugins/data/common/search/aggs/agg_configs.test.ts index ff0cc3341929e..803ccc70b98a7 100644 --- a/src/plugins/data/public/search/aggs/agg_configs.test.ts +++ b/src/plugins/data/common/search/aggs/agg_configs.test.ts @@ -22,8 +22,9 @@ import { AggConfig } from './agg_config'; import { AggConfigs } from './agg_configs'; import { AggTypesRegistryStart } from './agg_types_registry'; import { mockAggTypesRegistry } from './test_helpers'; -import { IndexPatternField, IndexPattern } from '../../index_patterns'; -import { stubIndexPattern, stubIndexPatternWithFields } from '../../../public/stubs'; +import type { IndexPatternField } from '../../index_patterns'; +import { IndexPattern } from '../../index_patterns/index_patterns/index_pattern'; +import { stubIndexPattern, stubIndexPatternWithFields } from '../../../common/stubs'; describe('AggConfigs', () => { let indexPattern: IndexPattern; diff --git a/src/plugins/data/public/search/aggs/agg_configs.ts b/src/plugins/data/common/search/aggs/agg_configs.ts similarity index 98% rename from src/plugins/data/public/search/aggs/agg_configs.ts rename to src/plugins/data/common/search/aggs/agg_configs.ts index b272dfd3c7468..203eda3a907ee 100644 --- a/src/plugins/data/public/search/aggs/agg_configs.ts +++ b/src/plugins/data/common/search/aggs/agg_configs.ts @@ -20,13 +20,12 @@ import _ from 'lodash'; import { Assign } from '@kbn/utility-types'; +import { FetchOptions, ISearchSource } from 'src/plugins/data/public'; import { AggConfig, AggConfigSerialized, IAggConfig } from './agg_config'; import { IAggType } from './agg_type'; import { AggTypesRegistryStart } from './agg_types_registry'; import { AggGroupNames } from './agg_groups'; -import { IndexPattern } from '../../index_patterns'; -import { ISearchSource } from '../search_source'; -import { FetchOptions } from '../fetch'; +import { IndexPattern } from '../../index_patterns/index_patterns/index_pattern'; import { TimeRange } from '../../../common'; function removeParentAggs(obj: any) { diff --git a/src/plugins/data/public/search/aggs/agg_groups.ts b/src/plugins/data/common/search/aggs/agg_groups.ts similarity index 100% rename from src/plugins/data/public/search/aggs/agg_groups.ts rename to src/plugins/data/common/search/aggs/agg_groups.ts diff --git a/src/plugins/data/public/search/aggs/agg_params.test.ts b/src/plugins/data/common/search/aggs/agg_params.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/agg_params.test.ts rename to src/plugins/data/common/search/aggs/agg_params.test.ts diff --git a/src/plugins/data/public/search/aggs/agg_params.ts b/src/plugins/data/common/search/aggs/agg_params.ts similarity index 100% rename from src/plugins/data/public/search/aggs/agg_params.ts rename to src/plugins/data/common/search/aggs/agg_params.ts diff --git a/src/plugins/data/public/search/aggs/agg_type.test.ts b/src/plugins/data/common/search/aggs/agg_type.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/agg_type.test.ts rename to src/plugins/data/common/search/aggs/agg_type.test.ts diff --git a/src/plugins/data/public/search/aggs/agg_type.ts b/src/plugins/data/common/search/aggs/agg_type.ts similarity index 99% rename from src/plugins/data/public/search/aggs/agg_type.ts rename to src/plugins/data/common/search/aggs/agg_type.ts index de7ca48e71d57..0ba2bb66e7758 100644 --- a/src/plugins/data/public/search/aggs/agg_type.ts +++ b/src/plugins/data/common/search/aggs/agg_type.ts @@ -20,6 +20,7 @@ import { constant, noop, identity } from 'lodash'; import { i18n } from '@kbn/i18n'; +import { ISearchSource } from 'src/plugins/data/public'; import { SerializedFieldFormat } from 'src/plugins/expressions/common'; import type { RequestAdapter } from 'src/plugins/inspector/common'; @@ -28,7 +29,6 @@ import { AggConfig } from './agg_config'; import { IAggConfigs } from './agg_configs'; import { BaseParamType } from './param_types/base'; import { AggParamType } from './param_types/agg'; -import { ISearchSource } from '../search_source'; export interface AggTypeConfig< TAggConfig extends AggConfig = AggConfig, diff --git a/src/plugins/data/public/search/aggs/agg_types.ts b/src/plugins/data/common/search/aggs/agg_types.ts similarity index 66% rename from src/plugins/data/public/search/aggs/agg_types.ts rename to src/plugins/data/common/search/aggs/agg_types.ts index 2820ae495f318..8565de13aed5b 100644 --- a/src/plugins/data/public/search/aggs/agg_types.ts +++ b/src/plugins/data/common/search/aggs/agg_types.ts @@ -17,9 +17,9 @@ * under the License. */ -import { IUiSettingsClient } from 'src/core/public'; -import { TimeRange, TimeRangeBounds } from '../../../common'; -import { GetInternalStartServicesFn } from '../../types'; +import { FieldFormatsStartCommon } from '../../field_formats'; +import { BUCKET_TYPES } from './buckets'; +import { METRIC_TYPES } from './metrics'; import { getCountMetricAgg } from './metrics/count'; import { getAvgMetricAgg } from './metrics/avg'; @@ -39,7 +39,7 @@ import { getCumulativeSumMetricAgg } from './metrics/cumulative_sum'; import { getMovingAvgMetricAgg } from './metrics/moving_avg'; import { getSerialDiffMetricAgg } from './metrics/serial_diff'; -import { getDateHistogramBucketAgg } from './buckets/date_histogram'; +import { getDateHistogramBucketAgg, CalculateBoundsFn } from './buckets/date_histogram'; import { getHistogramBucketAgg } from './buckets/histogram'; import { getRangeBucketAgg } from './buckets/range'; import { getDateRangeBucketAgg } from './buckets/date_range'; @@ -55,52 +55,50 @@ import { getBucketAvgMetricAgg } from './metrics/bucket_avg'; import { getBucketMinMetricAgg } from './metrics/bucket_min'; import { getBucketMaxMetricAgg } from './metrics/bucket_max'; +/** @internal */ export interface AggTypesDependencies { - calculateBounds: (timeRange: TimeRange) => TimeRangeBounds; - getInternalStartServices: GetInternalStartServicesFn; - uiSettings: IUiSettingsClient; + calculateBounds: CalculateBoundsFn; + getConfig: (key: string) => T; + getFieldFormatsStart: () => Pick; + isDefaultTimezone: () => boolean; } -export const getAggTypes = ({ - calculateBounds, - getInternalStartServices, - uiSettings, -}: AggTypesDependencies) => ({ +export const getAggTypes = () => ({ metrics: [ - getCountMetricAgg(), - getAvgMetricAgg(), - getSumMetricAgg(), - getMedianMetricAgg(), - getMinMetricAgg(), - getMaxMetricAgg(), - getStdDeviationMetricAgg(), - getCardinalityMetricAgg(), - getPercentilesMetricAgg(), - getPercentileRanksMetricAgg({ getInternalStartServices }), - getTopHitMetricAgg(), - getDerivativeMetricAgg(), - getCumulativeSumMetricAgg(), - getMovingAvgMetricAgg(), - getSerialDiffMetricAgg(), - getBucketAvgMetricAgg(), - getBucketSumMetricAgg(), - getBucketMinMetricAgg(), - getBucketMaxMetricAgg(), - getGeoBoundsMetricAgg(), - getGeoCentroidMetricAgg(), + { name: METRIC_TYPES.COUNT, fn: getCountMetricAgg }, + { name: METRIC_TYPES.AVG, fn: getAvgMetricAgg }, + { name: METRIC_TYPES.SUM, fn: getSumMetricAgg }, + { name: METRIC_TYPES.MEDIAN, fn: getMedianMetricAgg }, + { name: METRIC_TYPES.MIN, fn: getMinMetricAgg }, + { name: METRIC_TYPES.MAX, fn: getMaxMetricAgg }, + { name: METRIC_TYPES.STD_DEV, fn: getStdDeviationMetricAgg }, + { name: METRIC_TYPES.CARDINALITY, fn: getCardinalityMetricAgg }, + { name: METRIC_TYPES.PERCENTILES, fn: getPercentilesMetricAgg }, + { name: METRIC_TYPES.PERCENTILE_RANKS, fn: getPercentileRanksMetricAgg }, + { name: METRIC_TYPES.TOP_HITS, fn: getTopHitMetricAgg }, + { name: METRIC_TYPES.DERIVATIVE, fn: getDerivativeMetricAgg }, + { name: METRIC_TYPES.CUMULATIVE_SUM, fn: getCumulativeSumMetricAgg }, + { name: METRIC_TYPES.MOVING_FN, fn: getMovingAvgMetricAgg }, + { name: METRIC_TYPES.SERIAL_DIFF, fn: getSerialDiffMetricAgg }, + { name: METRIC_TYPES.AVG_BUCKET, fn: getBucketAvgMetricAgg }, + { name: METRIC_TYPES.SUM_BUCKET, fn: getBucketSumMetricAgg }, + { name: METRIC_TYPES.MIN_BUCKET, fn: getBucketMinMetricAgg }, + { name: METRIC_TYPES.MAX_BUCKET, fn: getBucketMaxMetricAgg }, + { name: METRIC_TYPES.GEO_BOUNDS, fn: getGeoBoundsMetricAgg }, + { name: METRIC_TYPES.GEO_CENTROID, fn: getGeoCentroidMetricAgg }, ], buckets: [ - getDateHistogramBucketAgg({ calculateBounds, uiSettings }), - getHistogramBucketAgg({ uiSettings, getInternalStartServices }), - getRangeBucketAgg({ getInternalStartServices }), - getDateRangeBucketAgg({ uiSettings }), - getIpRangeBucketAgg(), - getTermsBucketAgg(), - getFilterBucketAgg(), - getFiltersBucketAgg({ uiSettings }), - getSignificantTermsBucketAgg(), - getGeoHashBucketAgg(), - getGeoTitleBucketAgg(), + { name: BUCKET_TYPES.DATE_HISTOGRAM, fn: getDateHistogramBucketAgg }, + { name: BUCKET_TYPES.HISTOGRAM, fn: getHistogramBucketAgg }, + { name: BUCKET_TYPES.RANGE, fn: getRangeBucketAgg }, + { name: BUCKET_TYPES.DATE_RANGE, fn: getDateRangeBucketAgg }, + { name: BUCKET_TYPES.IP_RANGE, fn: getIpRangeBucketAgg }, + { name: BUCKET_TYPES.TERMS, fn: getTermsBucketAgg }, + { name: BUCKET_TYPES.FILTER, fn: getFilterBucketAgg }, + { name: BUCKET_TYPES.FILTERS, fn: getFiltersBucketAgg }, + { name: BUCKET_TYPES.SIGNIFICANT_TERMS, fn: getSignificantTermsBucketAgg }, + { name: BUCKET_TYPES.GEOHASH_GRID, fn: getGeoHashBucketAgg }, + { name: BUCKET_TYPES.GEOTILE_GRID, fn: getGeoTitleBucketAgg }, ], }); diff --git a/src/plugins/data/public/search/aggs/agg_types_registry.test.ts b/src/plugins/data/common/search/aggs/agg_types_registry.test.ts similarity index 54% rename from src/plugins/data/public/search/aggs/agg_types_registry.test.ts rename to src/plugins/data/common/search/aggs/agg_types_registry.test.ts index 58d1a07d965e2..df3dddfcd9c6f 100644 --- a/src/plugins/data/public/search/aggs/agg_types_registry.test.ts +++ b/src/plugins/data/common/search/aggs/agg_types_registry.test.ts @@ -17,21 +17,17 @@ * under the License. */ -import { - AggTypesRegistry, - AggTypesRegistrySetup, - AggTypesRegistryStart, -} from './agg_types_registry'; +import { AggTypesRegistry, AggTypesRegistrySetup } from './agg_types_registry'; import { BucketAggType } from './buckets/bucket_agg_type'; import { MetricAggType } from './metrics/metric_agg_type'; -const bucketType = { name: 'terms', type: 'bucket' } as BucketAggType; -const metricType = { name: 'count', type: 'metric' } as MetricAggType; +const bucketType = () => ({ name: 'terms', type: 'buckets' } as BucketAggType); +const metricType = () => ({ name: 'count', type: 'metrics' } as MetricAggType); describe('AggTypesRegistry', () => { let registry: AggTypesRegistry; let setup: AggTypesRegistrySetup; - let start: AggTypesRegistryStart; + let start: ReturnType; beforeEach(() => { registry = new AggTypesRegistry(); @@ -40,49 +36,53 @@ describe('AggTypesRegistry', () => { }); it('registerBucket adds new buckets', () => { - setup.registerBucket(bucketType); - expect(start.getBuckets()).toEqual([bucketType]); + setup.registerBucket('terms', bucketType); + expect(start.getAll().buckets).toEqual([bucketType]); }); it('registerBucket throws error when registering duplicate bucket', () => { expect(() => { - setup.registerBucket(bucketType); - setup.registerBucket(bucketType); + setup.registerBucket('terms', bucketType); + setup.registerBucket('terms', bucketType); }).toThrow(/already been registered with name: terms/); + + const fooBucket = () => ({ name: 'foo', type: 'buckets' } as BucketAggType); + const fooMetric = () => ({ name: 'foo', type: 'metrics' } as MetricAggType); + expect(() => { + setup.registerBucket('foo', fooBucket); + setup.registerMetric('foo', fooMetric); + }).toThrow(/already been registered with name: foo/); }); it('registerMetric adds new metrics', () => { - setup.registerMetric(metricType); - expect(start.getMetrics()).toEqual([metricType]); + setup.registerMetric('count', metricType); + expect(start.getAll().metrics).toEqual([metricType]); }); it('registerMetric throws error when registering duplicate metric', () => { expect(() => { - setup.registerMetric(metricType); - setup.registerMetric(metricType); + setup.registerMetric('count', metricType); + setup.registerMetric('count', metricType); }).toThrow(/already been registered with name: count/); + + const fooBucket = () => ({ name: 'foo', type: 'buckets' } as BucketAggType); + const fooMetric = () => ({ name: 'foo', type: 'metrics' } as MetricAggType); + expect(() => { + setup.registerMetric('foo', fooMetric); + setup.registerBucket('foo', fooBucket); + }).toThrow(/already been registered with name: foo/); }); it('gets either buckets or metrics by id', () => { - setup.registerBucket(bucketType); - setup.registerMetric(metricType); + setup.registerBucket('terms', bucketType); + setup.registerMetric('count', metricType); expect(start.get('terms')).toEqual(bucketType); expect(start.get('count')).toEqual(metricType); }); - it('getBuckets retrieves only buckets', () => { - setup.registerBucket(bucketType); - expect(start.getBuckets()).toEqual([bucketType]); - }); - - it('getMetrics retrieves only metrics', () => { - setup.registerMetric(metricType); - expect(start.getMetrics()).toEqual([metricType]); - }); - it('getAll returns all buckets and metrics', () => { - setup.registerBucket(bucketType); - setup.registerMetric(metricType); + setup.registerBucket('terms', bucketType); + setup.registerMetric('count', metricType); expect(start.getAll()).toEqual({ buckets: [bucketType], metrics: [metricType], diff --git a/src/plugins/data/public/search/aggs/agg_types_registry.ts b/src/plugins/data/common/search/aggs/agg_types_registry.ts similarity index 57% rename from src/plugins/data/public/search/aggs/agg_types_registry.ts rename to src/plugins/data/common/search/aggs/agg_types_registry.ts index 5a0c58120d810..ce22fa840bafa 100644 --- a/src/plugins/data/public/search/aggs/agg_types_registry.ts +++ b/src/plugins/data/common/search/aggs/agg_types_registry.ts @@ -19,9 +19,21 @@ import { BucketAggType } from './buckets/bucket_agg_type'; import { MetricAggType } from './metrics/metric_agg_type'; +import { AggTypesDependencies } from './agg_types'; export type AggTypesRegistrySetup = ReturnType; -export type AggTypesRegistryStart = ReturnType; +/** + * AggsCommonStart returns the _unitialized_ agg type providers, but in our + * real start contract we will need to return the initialized versions. + * So we need to provide the correct typings so they can be overwritten + * on client/server. + * + * @internal + */ +export interface AggTypesRegistryStart { + get: (id: string) => BucketAggType | MetricAggType; + getAll: () => { buckets: Array>; metrics: Array> }; +} export class AggTypesRegistry { private readonly bucketAggs = new Map(); @@ -29,17 +41,27 @@ export class AggTypesRegistry { setup = () => { return { - registerBucket: >(type: T): void => { - const { name } = type; - if (this.bucketAggs.get(name)) { - throw new Error(`Bucket agg has already been registered with name: ${name}`); + registerBucket: < + N extends string, + T extends (deps: AggTypesDependencies) => BucketAggType + >( + name: N, + type: T + ): void => { + if (this.bucketAggs.get(name) || this.metricAggs.get(name)) { + throw new Error(`Agg has already been registered with name: ${name}`); } this.bucketAggs.set(name, type); }, - registerMetric: >(type: T): void => { - const { name } = type; - if (this.metricAggs.get(name)) { - throw new Error(`Metric agg has already been registered with name: ${name}`); + registerMetric: < + N extends string, + T extends (deps: AggTypesDependencies) => MetricAggType + >( + name: N, + type: T + ): void => { + if (this.bucketAggs.get(name) || this.metricAggs.get(name)) { + throw new Error(`Agg has already been registered with name: ${name}`); } this.metricAggs.set(name, type); }, @@ -51,12 +73,6 @@ export class AggTypesRegistry { get: (name: string) => { return this.bucketAggs.get(name) || this.metricAggs.get(name); }, - getBuckets: () => { - return Array.from(this.bucketAggs.values()); - }, - getMetrics: () => { - return Array.from(this.metricAggs.values()); - }, getAll: () => { return { buckets: Array.from(this.bucketAggs.values()), diff --git a/src/plugins/data/common/search/aggs/aggs_service.test.ts b/src/plugins/data/common/search/aggs/aggs_service.test.ts new file mode 100644 index 0000000000000..bcf2101704c80 --- /dev/null +++ b/src/plugins/data/common/search/aggs/aggs_service.test.ts @@ -0,0 +1,217 @@ +/* + * 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 { + AggsCommonService, + AggsCommonSetupDependencies, + AggsCommonStartDependencies, +} from './aggs_service'; +import { AggTypesDependencies, getAggTypes } from './agg_types'; +import { BucketAggType } from './buckets/bucket_agg_type'; +import { MetricAggType } from './metrics/metric_agg_type'; + +describe('Aggs service', () => { + let service: AggsCommonService; + let setupDeps: AggsCommonSetupDependencies; + let startDeps: AggsCommonStartDependencies; + const aggTypesDependencies: AggTypesDependencies = { + calculateBounds: jest.fn(), + getFieldFormatsStart: jest.fn(), + getConfig: jest.fn(), + isDefaultTimezone: () => true, + }; + + beforeEach(() => { + service = new AggsCommonService(); + setupDeps = { + registerFunction: jest.fn(), + }; + startDeps = { + getConfig: jest.fn(), + }; + }); + + describe('setup()', () => { + test('exposes proper contract', () => { + const setup = service.setup(setupDeps); + expect(Object.keys(setup).length).toBe(1); + expect(setup).toHaveProperty('types'); + }); + + test('instantiates a new registry', () => { + const a = new AggsCommonService(); + const b = new AggsCommonService(); + const bSetupDeps = { + registerFunction: jest.fn(), + }; + + const aSetup = a.setup(setupDeps); + aSetup.types.registerBucket( + 'foo', + () => ({ name: 'foo', type: 'buckets' } as BucketAggType) + ); + const aStart = a.start(startDeps); + expect(aStart.types.getAll().buckets.map((t) => t(aggTypesDependencies).name)) + .toMatchInlineSnapshot(` + Array [ + "date_histogram", + "histogram", + "range", + "date_range", + "ip_range", + "terms", + "filter", + "filters", + "significant_terms", + "geohash_grid", + "geotile_grid", + "foo", + ] + `); + expect(aStart.types.getAll().metrics.map((t) => t(aggTypesDependencies).name)) + .toMatchInlineSnapshot(` + Array [ + "count", + "avg", + "sum", + "median", + "min", + "max", + "std_dev", + "cardinality", + "percentiles", + "percentile_ranks", + "top_hits", + "derivative", + "cumulative_sum", + "moving_avg", + "serial_diff", + "avg_bucket", + "sum_bucket", + "min_bucket", + "max_bucket", + "geo_bounds", + "geo_centroid", + ] + `); + + b.setup(bSetupDeps); + const bStart = b.start(startDeps); + expect(bStart.types.getAll().buckets.map((t) => t(aggTypesDependencies).name)) + .toMatchInlineSnapshot(` + Array [ + "date_histogram", + "histogram", + "range", + "date_range", + "ip_range", + "terms", + "filter", + "filters", + "significant_terms", + "geohash_grid", + "geotile_grid", + ] + `); + expect(bStart.types.getAll().metrics.map((t) => t(aggTypesDependencies).name)) + .toMatchInlineSnapshot(` + Array [ + "count", + "avg", + "sum", + "median", + "min", + "max", + "std_dev", + "cardinality", + "percentiles", + "percentile_ranks", + "top_hits", + "derivative", + "cumulative_sum", + "moving_avg", + "serial_diff", + "avg_bucket", + "sum_bucket", + "min_bucket", + "max_bucket", + "geo_bounds", + "geo_centroid", + ] + `); + }); + + test('registers default agg types', () => { + service.setup(setupDeps); + const start = service.start(startDeps); + + const aggTypes = getAggTypes(); + expect(start.types.getAll().buckets.length).toBe(aggTypes.buckets.length); + expect(start.types.getAll().metrics.length).toBe(aggTypes.metrics.length); + }); + + test('merges default agg types with types registered during setup', () => { + const setup = service.setup(setupDeps); + setup.types.registerBucket( + 'foo', + () => ({ name: 'foo', type: 'buckets' } as BucketAggType) + ); + setup.types.registerMetric( + 'bar', + () => ({ name: 'bar', type: 'metrics' } as MetricAggType) + ); + const start = service.start(startDeps); + + const aggTypes = getAggTypes(); + expect(start.types.getAll().buckets.length).toBe(aggTypes.buckets.length + 1); + expect(start.types.getAll().buckets.some((t) => t(aggTypesDependencies).name === 'foo')).toBe( + true + ); + expect(start.types.getAll().metrics.length).toBe(aggTypes.metrics.length + 1); + expect(start.types.getAll().metrics.some((t) => t(aggTypesDependencies).name === 'bar')).toBe( + true + ); + }); + + test('registers all agg type expression functions', () => { + service.setup(setupDeps); + const aggTypes = getAggTypes(); + expect(setupDeps.registerFunction).toHaveBeenCalledTimes( + aggTypes.buckets.length + aggTypes.metrics.length + ); + }); + }); + + describe('start()', () => { + test('exposes proper contract', () => { + const start = service.start(startDeps); + expect(Object.keys(start).length).toBe(3); + expect(start).toHaveProperty('calculateAutoTimeExpression'); + expect(start).toHaveProperty('createAggConfigs'); + expect(start).toHaveProperty('types'); + }); + + test('types registry returns uninitialized type providers', () => { + service.setup(setupDeps); + const start = service.start(startDeps); + expect(typeof start.types.get('terms')).toBe('function'); + expect(start.types.get('terms')(aggTypesDependencies).name).toBe('terms'); + }); + }); +}); diff --git a/src/plugins/data/common/search/aggs/aggs_service.ts b/src/plugins/data/common/search/aggs/aggs_service.ts new file mode 100644 index 0000000000000..59c54fcce6838 --- /dev/null +++ b/src/plugins/data/common/search/aggs/aggs_service.ts @@ -0,0 +1,92 @@ +/* + * 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 { ExpressionsServiceSetup } from 'src/plugins/expressions/common'; +import { UI_SETTINGS } from '../../../common'; +import { + AggConfigs, + AggTypesRegistry, + getAggTypes, + getAggTypesFunctions, + getCalculateAutoTimeExpression, +} from './'; +import { AggsCommonSetup, AggsCommonStart } from './types'; + +/** @internal */ +export const aggsRequiredUiSettings = [ + 'dateFormat', + 'dateFormat:scaled', + 'dateFormat:tz', + UI_SETTINGS.HISTOGRAM_BAR_TARGET, + UI_SETTINGS.HISTOGRAM_MAX_BARS, + UI_SETTINGS.SEARCH_QUERY_LANGUAGE, + UI_SETTINGS.QUERY_ALLOW_LEADING_WILDCARDS, + UI_SETTINGS.QUERY_STRING_OPTIONS, + UI_SETTINGS.COURIER_IGNORE_FILTER_IF_FIELD_NOT_IN_INDEX, +]; + +/** @internal */ +export interface AggsCommonSetupDependencies { + registerFunction: ExpressionsServiceSetup['registerFunction']; +} + +/** @internal */ +export interface AggsCommonStartDependencies { + getConfig: (key: string) => T; +} + +/** + * The aggs service provides a means of modeling and manipulating the various + * Elasticsearch aggregations supported by Kibana, providing the ability to + * output the correct DSL when you are ready to send your request to ES. + */ +export class AggsCommonService { + private readonly aggTypesRegistry = new AggTypesRegistry(); + + public setup({ registerFunction }: AggsCommonSetupDependencies): AggsCommonSetup { + const aggTypesSetup = this.aggTypesRegistry.setup(); + + // register each agg type + const aggTypes = getAggTypes(); + aggTypes.buckets.forEach(({ name, fn }) => aggTypesSetup.registerBucket(name, fn)); + aggTypes.metrics.forEach(({ name, fn }) => aggTypesSetup.registerMetric(name, fn)); + + // register expression functions for each agg type + const aggFunctions = getAggTypesFunctions(); + aggFunctions.forEach((fn) => registerFunction(fn)); + + return { + types: aggTypesSetup, + }; + } + + public start({ getConfig }: AggsCommonStartDependencies): AggsCommonStart { + const aggTypesStart = this.aggTypesRegistry.start(); + + return { + calculateAutoTimeExpression: getCalculateAutoTimeExpression(getConfig), + createAggConfigs: (indexPattern, configStates = [], schemas) => { + return new AggConfigs(indexPattern, configStates, { + typesRegistry: aggTypesStart, + }); + }, + types: aggTypesStart, + }; + } +} diff --git a/src/plugins/data/public/search/aggs/buckets/_interval_options.ts b/src/plugins/data/common/search/aggs/buckets/_interval_options.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/_interval_options.ts rename to src/plugins/data/common/search/aggs/buckets/_interval_options.ts diff --git a/src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.test.ts b/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.test.ts rename to src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.test.ts diff --git a/src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.ts b/src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/_terms_other_bucket_helper.ts rename to src/plugins/data/common/search/aggs/buckets/_terms_other_bucket_helper.ts diff --git a/src/plugins/data/public/search/aggs/buckets/bucket_agg_type.ts b/src/plugins/data/common/search/aggs/buckets/bucket_agg_type.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/bucket_agg_type.ts rename to src/plugins/data/common/search/aggs/buckets/bucket_agg_type.ts diff --git a/src/plugins/data/public/search/aggs/buckets/bucket_agg_types.ts b/src/plugins/data/common/search/aggs/buckets/bucket_agg_types.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/bucket_agg_types.ts rename to src/plugins/data/common/search/aggs/buckets/bucket_agg_types.ts diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts b/src/plugins/data/common/search/aggs/buckets/create_filter/date_histogram.test.ts similarity index 87% rename from src/plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts rename to src/plugins/data/common/search/aggs/buckets/create_filter/date_histogram.test.ts index 24a17b60566cc..143d549836900 100644 --- a/src/plugins/data/public/search/aggs/buckets/create_filter/date_histogram.test.ts +++ b/src/plugins/data/common/search/aggs/buckets/create_filter/date_histogram.test.ts @@ -22,32 +22,17 @@ import { createFilterDateHistogram } from './date_histogram'; import { intervalOptions } from '../_interval_options'; import { AggConfigs } from '../../agg_configs'; import { mockAggTypesRegistry } from '../../test_helpers'; -import { - getDateHistogramBucketAgg, - DateHistogramBucketAggDependencies, - IBucketDateHistogramAggConfig, -} from '../date_histogram'; +import { IBucketDateHistogramAggConfig } from '../date_histogram'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { RangeFilter } from '../../../../../common'; -import { coreMock } from '../../../../../../../core/public/mocks'; describe('AggConfig Filters', () => { describe('date_histogram', () => { - let aggTypesDependencies: DateHistogramBucketAggDependencies; let agg: IBucketDateHistogramAggConfig; let filter: RangeFilter; let bucketStart: any; let field: any; - beforeEach(() => { - const { uiSettings } = coreMock.createSetup(); - - aggTypesDependencies = { - calculateBounds: jest.fn(), - uiSettings, - }; - }); - const init = (interval: string = 'auto', duration: any = moment.duration(15, 'minutes')) => { field = { name: 'date', @@ -71,7 +56,7 @@ describe('AggConfig Filters', () => { }, ], { - typesRegistry: mockAggTypesRegistry([getDateHistogramBucketAgg(aggTypesDependencies)]), + typesRegistry: mockAggTypesRegistry(), } ); const bucketKey = 1422579600000; diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/date_histogram.ts b/src/plugins/data/common/search/aggs/buckets/create_filter/date_histogram.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/create_filter/date_histogram.ts rename to src/plugins/data/common/search/aggs/buckets/create_filter/date_histogram.ts diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts b/src/plugins/data/common/search/aggs/buckets/create_filter/date_range.test.ts similarity index 78% rename from src/plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts rename to src/plugins/data/common/search/aggs/buckets/create_filter/date_range.test.ts index c272c037c5927..8def27f1d8ee5 100644 --- a/src/plugins/data/public/search/aggs/buckets/create_filter/date_range.test.ts +++ b/src/plugins/data/common/search/aggs/buckets/create_filter/date_range.test.ts @@ -18,31 +18,18 @@ */ import moment from 'moment'; -import { getDateRangeBucketAgg, DateRangeBucketAggDependencies } from '../date_range'; import { createFilterDateRange } from './date_range'; -import { FieldFormatsGetConfigFn } from '../../../../../common'; -import { DateFormat } from '../../../../field_formats'; import { AggConfigs } from '../../agg_configs'; import { mockAggTypesRegistry } from '../../test_helpers'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../bucket_agg_type'; -import { coreMock } from '../../../../../../../core/public/mocks'; describe('AggConfig Filters', () => { describe('Date range', () => { - let aggTypesDependencies: DateRangeBucketAggDependencies; - - beforeEach(() => { - const { uiSettings } = coreMock.createSetup(); - - aggTypesDependencies = { uiSettings }; - }); - - const getConfig = (() => {}) as FieldFormatsGetConfigFn; const getAggConfigs = () => { const field = { name: '@timestamp', - format: new DateFormat({}, getConfig), + format: {}, }; const indexPattern = { @@ -66,7 +53,7 @@ describe('AggConfig Filters', () => { }, ], { - typesRegistry: mockAggTypesRegistry([getDateRangeBucketAgg(aggTypesDependencies)]), + typesRegistry: mockAggTypesRegistry(), } ); }; diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/date_range.ts b/src/plugins/data/common/search/aggs/buckets/create_filter/date_range.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/create_filter/date_range.ts rename to src/plugins/data/common/search/aggs/buckets/create_filter/date_range.ts diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts b/src/plugins/data/common/search/aggs/buckets/create_filter/filters.test.ts similarity index 83% rename from src/plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts rename to src/plugins/data/common/search/aggs/buckets/create_filter/filters.test.ts index ff66d80c6d8d0..aec99bd00af55 100644 --- a/src/plugins/data/public/search/aggs/buckets/create_filter/filters.test.ts +++ b/src/plugins/data/common/search/aggs/buckets/create_filter/filters.test.ts @@ -17,23 +17,13 @@ * under the License. */ -import { getFiltersBucketAgg, FiltersBucketAggDependencies } from '../filters'; import { createFilterFilters } from './filters'; import { AggConfigs } from '../../agg_configs'; import { mockAggTypesRegistry } from '../../test_helpers'; import { IBucketAggConfig } from '../bucket_agg_type'; -import { coreMock } from '../../../../../../../core/public/mocks'; describe('AggConfig Filters', () => { describe('filters', () => { - let aggTypesDependencies: FiltersBucketAggDependencies; - - beforeEach(() => { - const { uiSettings } = coreMock.createSetup(); - - aggTypesDependencies = { uiSettings }; - }); - const getAggConfigs = () => { const field = { name: 'bytes', @@ -63,7 +53,7 @@ describe('AggConfig Filters', () => { }, ], { - typesRegistry: mockAggTypesRegistry([getFiltersBucketAgg(aggTypesDependencies)]), + typesRegistry: mockAggTypesRegistry(), } ); }; diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/filters.ts b/src/plugins/data/common/search/aggs/buckets/create_filter/filters.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/create_filter/filters.ts rename to src/plugins/data/common/search/aggs/buckets/create_filter/filters.ts diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts b/src/plugins/data/common/search/aggs/buckets/create_filter/histogram.test.ts similarity index 77% rename from src/plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts rename to src/plugins/data/common/search/aggs/buckets/create_filter/histogram.test.ts index 3f9f5dd5672f0..b57d530ef40e8 100644 --- a/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.test.ts +++ b/src/plugins/data/common/search/aggs/buckets/create_filter/histogram.test.ts @@ -17,25 +17,14 @@ * under the License. */ -import { createFilterHistogram } from './histogram'; +import { BytesFormat, FieldFormatsGetConfigFn } from '../../../../../common/field_formats'; import { AggConfigs } from '../../agg_configs'; -import { mockAggTypesRegistry } from '../../test_helpers'; +import { mockAggTypesRegistry, mockGetFieldFormatsStart } from '../../test_helpers'; import { BUCKET_TYPES } from '../bucket_agg_types'; import { IBucketAggConfig } from '../bucket_agg_type'; -import { BytesFormat, FieldFormatsGetConfigFn } from '../../../../../common'; -import { GetInternalStartServicesFn, InternalStartServices } from '../../../../types'; -import { FieldFormatsStart } from '../../../../field_formats'; -import { fieldFormatsServiceMock } from '../../../../field_formats/mocks'; +import { createFilterHistogram } from './histogram'; describe('AggConfig Filters', () => { - let getInternalStartServices: GetInternalStartServicesFn; - let fieldFormats: FieldFormatsStart; - - beforeEach(() => { - fieldFormats = fieldFormatsServiceMock.createStartContract(); - getInternalStartServices = () => (({ fieldFormats } as unknown) as InternalStartServices); - }); - describe('histogram', () => { const getConfig = (() => {}) as FieldFormatsGetConfigFn; const getAggConfigs = () => { @@ -72,12 +61,12 @@ describe('AggConfig Filters', () => { test('should return an range filter for histogram', () => { const aggConfigs = getAggConfigs(); - const filter = createFilterHistogram(getInternalStartServices)( + const filter = createFilterHistogram(mockGetFieldFormatsStart)( aggConfigs.aggs[0] as IBucketAggConfig, '2048' ); - expect(fieldFormats.deserialize).toHaveBeenCalledTimes(1); + expect(mockGetFieldFormatsStart().deserialize).toHaveBeenCalledTimes(1); expect(filter).toHaveProperty('meta'); expect(filter.meta).toHaveProperty('index', '1234'); expect(filter).toHaveProperty('range'); diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.ts b/src/plugins/data/common/search/aggs/buckets/create_filter/histogram.ts similarity index 80% rename from src/plugins/data/public/search/aggs/buckets/create_filter/histogram.ts rename to src/plugins/data/common/search/aggs/buckets/create_filter/histogram.ts index f3626bc9130ad..4684b1640cd82 100644 --- a/src/plugins/data/public/search/aggs/buckets/create_filter/histogram.ts +++ b/src/plugins/data/common/search/aggs/buckets/create_filter/histogram.ts @@ -17,14 +17,16 @@ * under the License. */ -import { IBucketAggConfig } from '../bucket_agg_type'; import { buildRangeFilter, RangeFilterParams } from '../../../../../common'; -import { GetInternalStartServicesFn } from '../../../../types'; +import { AggTypesDependencies } from '../../agg_types'; +import { IBucketAggConfig } from '../bucket_agg_type'; /** @internal */ -export const createFilterHistogram = (getInternalStartServices: GetInternalStartServicesFn) => { +export const createFilterHistogram = ( + getFieldFormatsStart: AggTypesDependencies['getFieldFormatsStart'] +) => { return (aggConfig: IBucketAggConfig, key: string) => { - const { fieldFormats } = getInternalStartServices(); + const { deserialize } = getFieldFormatsStart(); const value = parseInt(key, 10); const params: RangeFilterParams = { gte: value, lt: value + aggConfig.params.interval }; @@ -32,7 +34,7 @@ export const createFilterHistogram = (getInternalStartServices: GetInternalStart aggConfig.params.field, params, aggConfig.getIndexPattern(), - fieldFormats.deserialize(aggConfig.toSerializedFieldFormat()).convert(key) + deserialize(aggConfig.toSerializedFieldFormat()).convert(key) ); }; }; diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts b/src/plugins/data/common/search/aggs/buckets/create_filter/ip_range.test.ts similarity index 96% rename from src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts rename to src/plugins/data/common/search/aggs/buckets/create_filter/ip_range.test.ts index 852685a505afd..9f823001aac8c 100644 --- a/src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.test.ts +++ b/src/plugins/data/common/search/aggs/buckets/create_filter/ip_range.test.ts @@ -17,7 +17,6 @@ * under the License. */ -import { getIpRangeBucketAgg } from '../ip_range'; import { createFilterIpRange } from './ip_range'; import { AggConfigs, CreateAggConfigParams } from '../../agg_configs'; import { mockAggTypesRegistry } from '../../test_helpers'; @@ -27,7 +26,7 @@ import { IBucketAggConfig } from '../bucket_agg_type'; describe('AggConfig Filters', () => { describe('IP range', () => { - const typesRegistry = mockAggTypesRegistry([getIpRangeBucketAgg()]); + const typesRegistry = mockAggTypesRegistry(); const getAggConfigs = (aggs: CreateAggConfigParams[]) => { const field = { name: 'ip', diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts b/src/plugins/data/common/search/aggs/buckets/create_filter/ip_range.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/create_filter/ip_range.ts rename to src/plugins/data/common/search/aggs/buckets/create_filter/ip_range.ts diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/range.test.ts b/src/plugins/data/common/search/aggs/buckets/create_filter/range.test.ts similarity index 73% rename from src/plugins/data/public/search/aggs/buckets/create_filter/range.test.ts rename to src/plugins/data/common/search/aggs/buckets/create_filter/range.test.ts index faffad3beb8c1..30af970f55aa9 100644 --- a/src/plugins/data/public/search/aggs/buckets/create_filter/range.test.ts +++ b/src/plugins/data/common/search/aggs/buckets/create_filter/range.test.ts @@ -17,31 +17,15 @@ * under the License. */ -import { getRangeBucketAgg } from '../range'; -import { createFilterRange } from './range'; -import { BytesFormat, FieldFormatsGetConfigFn } from '../../../../../common'; +import { BytesFormat, FieldFormatsGetConfigFn } from '../../../../../common/field_formats'; import { AggConfigs } from '../../agg_configs'; -import { mockAggTypesRegistry } from '../../test_helpers'; -import { BUCKET_TYPES } from '../bucket_agg_types'; +import { mockAggTypesRegistry, mockGetFieldFormatsStart } from '../../test_helpers'; import { IBucketAggConfig } from '../bucket_agg_type'; -import { FieldFormatsStart } from '../../../../field_formats'; -import { fieldFormatsServiceMock } from '../../../../field_formats/mocks'; -import { GetInternalStartServicesFn, InternalStartServices } from '../../../../types'; +import { BUCKET_TYPES } from '../bucket_agg_types'; +import { createFilterRange } from './range'; describe('AggConfig Filters', () => { describe('range', () => { - let getInternalStartServices: GetInternalStartServicesFn; - let fieldFormats: FieldFormatsStart; - - beforeEach(() => { - fieldFormats = fieldFormatsServiceMock.createStartContract(); - - getInternalStartServices = () => - (({ - fieldFormats, - } as unknown) as InternalStartServices); - }); - const getConfig = (() => {}) as FieldFormatsGetConfigFn; const getAggConfigs = () => { const field = { @@ -72,14 +56,14 @@ describe('AggConfig Filters', () => { }, ], { - typesRegistry: mockAggTypesRegistry([getRangeBucketAgg({ getInternalStartServices })]), + typesRegistry: mockAggTypesRegistry(), } ); }; test('should return a range filter for range agg', () => { const aggConfigs = getAggConfigs(); - const filter = createFilterRange(getInternalStartServices)( + const filter = createFilterRange(mockGetFieldFormatsStart)( aggConfigs.aggs[0] as IBucketAggConfig, { gte: 1024, @@ -87,7 +71,7 @@ describe('AggConfig Filters', () => { } ); - expect(fieldFormats.deserialize).toHaveBeenCalledTimes(1); + expect(mockGetFieldFormatsStart().deserialize).toHaveBeenCalledTimes(1); expect(filter).toHaveProperty('range'); expect(filter).toHaveProperty('meta'); expect(filter.meta).toHaveProperty('index', '1234'); diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/range.ts b/src/plugins/data/common/search/aggs/buckets/create_filter/range.ts similarity index 78% rename from src/plugins/data/public/search/aggs/buckets/create_filter/range.ts rename to src/plugins/data/common/search/aggs/buckets/create_filter/range.ts index f9db2973af136..8dea33a450c5d 100644 --- a/src/plugins/data/public/search/aggs/buckets/create_filter/range.ts +++ b/src/plugins/data/common/search/aggs/buckets/create_filter/range.ts @@ -17,19 +17,21 @@ * under the License. */ -import { IBucketAggConfig } from '../bucket_agg_type'; import { buildRangeFilter } from '../../../../../common'; -import { GetInternalStartServicesFn } from '../../../../types'; +import { AggTypesDependencies } from '../../agg_types'; +import { IBucketAggConfig } from '../bucket_agg_type'; /** @internal */ -export const createFilterRange = (getInternalStartServices: GetInternalStartServicesFn) => { +export const createFilterRange = ( + getFieldFormatsStart: AggTypesDependencies['getFieldFormatsStart'] +) => { return (aggConfig: IBucketAggConfig, params: any) => { - const { fieldFormats } = getInternalStartServices(); + const { deserialize } = getFieldFormatsStart(); return buildRangeFilter( aggConfig.params.field, params, aggConfig.getIndexPattern(), - fieldFormats.deserialize(aggConfig.toSerializedFieldFormat()).convert(params) + deserialize(aggConfig.toSerializedFieldFormat()).convert(params) ); }; }; diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts b/src/plugins/data/common/search/aggs/buckets/create_filter/terms.test.ts similarity index 97% rename from src/plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts rename to src/plugins/data/common/search/aggs/buckets/create_filter/terms.test.ts index 1c165f0d29ab6..c3c661296e1cf 100644 --- a/src/plugins/data/public/search/aggs/buckets/create_filter/terms.test.ts +++ b/src/plugins/data/common/search/aggs/buckets/create_filter/terms.test.ts @@ -17,7 +17,6 @@ * under the License. */ -import { getTermsBucketAgg } from '../terms'; import { createFilterTerms } from './terms'; import { AggConfigs, CreateAggConfigParams } from '../../agg_configs'; import { mockAggTypesRegistry } from '../../test_helpers'; @@ -43,7 +42,7 @@ describe('AggConfig Filters', () => { }; return new AggConfigs(indexPattern, aggs, { - typesRegistry: mockAggTypesRegistry([getTermsBucketAgg()]), + typesRegistry: mockAggTypesRegistry(), }); }; diff --git a/src/plugins/data/public/search/aggs/buckets/create_filter/terms.ts b/src/plugins/data/common/search/aggs/buckets/create_filter/terms.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/create_filter/terms.ts rename to src/plugins/data/common/search/aggs/buckets/create_filter/terms.ts diff --git a/src/plugins/data/public/search/aggs/buckets/date_histogram.ts b/src/plugins/data/common/search/aggs/buckets/date_histogram.ts similarity index 92% rename from src/plugins/data/public/search/aggs/buckets/date_histogram.ts rename to src/plugins/data/common/search/aggs/buckets/date_histogram.ts index fa1725eccbd28..fdf9c456b3876 100644 --- a/src/plugins/data/public/search/aggs/buckets/date_histogram.ts +++ b/src/plugins/data/common/search/aggs/buckets/date_histogram.ts @@ -20,27 +20,23 @@ import { get, noop, find, every } from 'lodash'; import moment from 'moment-timezone'; import { i18n } from '@kbn/i18n'; -import { IUiSettingsClient } from 'src/core/public'; -import { TimeBuckets } from './lib/time_buckets'; +import { KBN_FIELD_TYPES, TimeRange, TimeRangeBounds, UI_SETTINGS } from '../../../../common'; + +import { intervalOptions } from './_interval_options'; +import { createFilterDateHistogram } from './create_filter/date_histogram'; import { BucketAggType, IBucketAggConfig } from './bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { createFilterDateHistogram } from './create_filter/date_histogram'; -import { intervalOptions } from './_interval_options'; +import { ExtendedBounds } from './lib/extended_bounds'; +import { TimeBuckets } from './lib/time_buckets'; + import { writeParams } from '../agg_params'; import { isMetricAggType } from '../metrics/metric_agg_type'; - -import { - dateHistogramInterval, - KBN_FIELD_TYPES, - TimeRange, - TimeRangeBounds, - UI_SETTINGS, -} from '../../../../common'; import { BaseAggParams } from '../types'; -import { ExtendedBounds } from './lib/extended_bounds'; +import { dateHistogramInterval } from '../utils'; -type CalculateBoundsFn = (timeRange: TimeRange) => TimeRangeBounds; +/** @internal */ +export type CalculateBoundsFn = (timeRange: TimeRange) => TimeRangeBounds; const updateTimeBuckets = ( agg: IBucketDateHistogramAggConfig, @@ -58,7 +54,8 @@ const updateTimeBuckets = ( export interface DateHistogramBucketAggDependencies { calculateBounds: CalculateBoundsFn; - uiSettings: IUiSettingsClient; + isDefaultTimezone: () => boolean; + getConfig: (key: string) => T; } export interface IBucketDateHistogramAggConfig extends IBucketAggConfig { @@ -84,7 +81,8 @@ export interface AggParamsDateHistogram extends BaseAggParams { export const getDateHistogramBucketAgg = ({ calculateBounds, - uiSettings, + isDefaultTimezone, + getConfig, }: DateHistogramBucketAggDependencies) => new BucketAggType({ name: BUCKET_TYPES.DATE_HISTOGRAM, @@ -122,10 +120,10 @@ export const getDateHistogramBucketAgg = ({ if (buckets) return buckets; buckets = new TimeBuckets({ - 'histogram:maxBars': uiSettings.get(UI_SETTINGS.HISTOGRAM_MAX_BARS), - 'histogram:barTarget': uiSettings.get(UI_SETTINGS.HISTOGRAM_BAR_TARGET), - dateFormat: uiSettings.get('dateFormat'), - 'dateFormat:scaled': uiSettings.get('dateFormat:scaled'), + 'histogram:maxBars': getConfig(UI_SETTINGS.HISTOGRAM_MAX_BARS), + 'histogram:barTarget': getConfig(UI_SETTINGS.HISTOGRAM_BAR_TARGET), + dateFormat: getConfig('dateFormat'), + 'dateFormat:scaled': getConfig('dateFormat:scaled'), }); updateTimeBuckets(this, calculateBounds, buckets); @@ -252,10 +250,9 @@ export const getDateHistogramBucketAgg = ({ } if (!tz) { // If the index pattern typeMeta data, didn't had a time zone assigned for the selected field use the configured tz - const isDefaultTimezone = uiSettings.isDefault('dateFormat:tz'); const detectedTimezone = moment.tz.guess(); const tzOffset = moment().format('Z'); - tz = isDefaultTimezone ? detectedTimezone || tzOffset : uiSettings.get('dateFormat:tz'); + tz = isDefaultTimezone() ? detectedTimezone || tzOffset : getConfig('dateFormat:tz'); } output.params.time_zone = tz; }, diff --git a/src/plugins/data/public/search/aggs/buckets/date_histogram_fn.test.ts b/src/plugins/data/common/search/aggs/buckets/date_histogram_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/date_histogram_fn.test.ts rename to src/plugins/data/common/search/aggs/buckets/date_histogram_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/buckets/date_histogram_fn.ts b/src/plugins/data/common/search/aggs/buckets/date_histogram_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/date_histogram_fn.ts rename to src/plugins/data/common/search/aggs/buckets/date_histogram_fn.ts diff --git a/src/plugins/data/public/search/aggs/buckets/date_range.test.ts b/src/plugins/data/common/search/aggs/buckets/date_range.test.ts similarity index 84% rename from src/plugins/data/public/search/aggs/buckets/date_range.test.ts rename to src/plugins/data/common/search/aggs/buckets/date_range.test.ts index 69515dfee87fe..66f8e269cd38d 100644 --- a/src/plugins/data/public/search/aggs/buckets/date_range.test.ts +++ b/src/plugins/data/common/search/aggs/buckets/date_range.test.ts @@ -17,19 +17,20 @@ * under the License. */ -import { coreMock } from '../../../../../../../src/core/public/mocks'; -import { getDateRangeBucketAgg, DateRangeBucketAggDependencies } from './date_range'; import { AggConfigs } from '../agg_configs'; -import { mockAggTypesRegistry } from '../test_helpers'; +import { AggTypesDependencies } from '../agg_types'; +import { mockAggTypesRegistry, mockAggTypesDependencies } from '../test_helpers'; import { BUCKET_TYPES } from './bucket_agg_types'; describe('date_range params', () => { - let aggTypesDependencies: DateRangeBucketAggDependencies; + let aggTypesDependencies: AggTypesDependencies; beforeEach(() => { - const { uiSettings } = coreMock.createSetup(); - - aggTypesDependencies = { uiSettings }; + aggTypesDependencies = { + ...mockAggTypesDependencies, + getConfig: jest.fn(), + isDefaultTimezone: jest.fn().mockReturnValue(false), + }; }); const getAggConfigs = (params: Record = {}, hasIncludeTypeMeta: boolean = true) => { @@ -68,7 +69,7 @@ describe('date_range params', () => { }, ], { - typesRegistry: mockAggTypesRegistry([getDateRangeBucketAgg(aggTypesDependencies)]), + typesRegistry: mockAggTypesRegistry(aggTypesDependencies), } ); }; @@ -108,10 +109,7 @@ describe('date_range params', () => { test('should use the Kibana time_zone if no parameter specified', () => { aggTypesDependencies = { ...aggTypesDependencies, - uiSettings: { - ...aggTypesDependencies.uiSettings, - get: () => 'kibanaTimeZone' as any, - }, + getConfig: () => 'kibanaTimeZone' as any, }; const aggConfigs = getAggConfigs( diff --git a/src/plugins/data/public/search/aggs/buckets/date_range.ts b/src/plugins/data/common/search/aggs/buckets/date_range.ts similarity index 88% rename from src/plugins/data/public/search/aggs/buckets/date_range.ts rename to src/plugins/data/common/search/aggs/buckets/date_range.ts index 8c576023f0239..eda35a77afa5f 100644 --- a/src/plugins/data/public/search/aggs/buckets/date_range.ts +++ b/src/plugins/data/common/search/aggs/buckets/date_range.ts @@ -20,14 +20,13 @@ import { get } from 'lodash'; import moment from 'moment-timezone'; import { i18n } from '@kbn/i18n'; -import { IUiSettingsClient } from 'src/core/public'; import { BUCKET_TYPES } from './bucket_agg_types'; import { BucketAggType, IBucketAggConfig } from './bucket_agg_type'; import { createFilterDateRange } from './create_filter/date_range'; import { DateRangeKey } from './lib/date_range'; -import { KBN_FIELD_TYPES } from '../../../../common'; +import { KBN_FIELD_TYPES } from '../../../../common/kbn_field_types/types'; import { BaseAggParams } from '../types'; const dateRangeTitle = i18n.translate('data.search.aggs.buckets.dateRangeTitle', { @@ -35,7 +34,8 @@ const dateRangeTitle = i18n.translate('data.search.aggs.buckets.dateRangeTitle', }); export interface DateRangeBucketAggDependencies { - uiSettings: IUiSettingsClient; + isDefaultTimezone: () => boolean; + getConfig: (key: string) => T; } export interface AggParamsDateRange extends BaseAggParams { @@ -44,7 +44,10 @@ export interface AggParamsDateRange extends BaseAggParams { time_zone?: string; } -export const getDateRangeBucketAgg = ({ uiSettings }: DateRangeBucketAggDependencies) => +export const getDateRangeBucketAgg = ({ + isDefaultTimezone, + getConfig, +}: DateRangeBucketAggDependencies) => new BucketAggType({ name: BUCKET_TYPES.DATE_RANGE, title: dateRangeTitle, @@ -100,9 +103,8 @@ export const getDateRangeBucketAgg = ({ uiSettings }: DateRangeBucketAggDependen if (!tz) { const detectedTimezone = moment.tz.guess(); const tzOffset = moment().format('Z'); - const isDefaultTimezone = uiSettings.isDefault('dateFormat:tz'); - tz = isDefaultTimezone ? detectedTimezone || tzOffset : uiSettings.get('dateFormat:tz'); + tz = isDefaultTimezone() ? detectedTimezone || tzOffset : getConfig('dateFormat:tz'); } output.params.time_zone = tz; }, diff --git a/src/plugins/data/public/search/aggs/buckets/date_range_fn.test.ts b/src/plugins/data/common/search/aggs/buckets/date_range_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/date_range_fn.test.ts rename to src/plugins/data/common/search/aggs/buckets/date_range_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/buckets/date_range_fn.ts b/src/plugins/data/common/search/aggs/buckets/date_range_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/date_range_fn.ts rename to src/plugins/data/common/search/aggs/buckets/date_range_fn.ts diff --git a/src/plugins/data/public/search/aggs/buckets/filter.ts b/src/plugins/data/common/search/aggs/buckets/filter.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/filter.ts rename to src/plugins/data/common/search/aggs/buckets/filter.ts diff --git a/src/plugins/data/public/search/aggs/buckets/filter_fn.test.ts b/src/plugins/data/common/search/aggs/buckets/filter_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/filter_fn.test.ts rename to src/plugins/data/common/search/aggs/buckets/filter_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/buckets/filter_fn.ts b/src/plugins/data/common/search/aggs/buckets/filter_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/filter_fn.ts rename to src/plugins/data/common/search/aggs/buckets/filter_fn.ts diff --git a/src/plugins/data/public/search/aggs/buckets/filters.test.ts b/src/plugins/data/common/search/aggs/buckets/filters.test.ts similarity index 93% rename from src/plugins/data/public/search/aggs/buckets/filters.test.ts rename to src/plugins/data/common/search/aggs/buckets/filters.test.ts index bcb82b5f99649..f745b4537131a 100644 --- a/src/plugins/data/public/search/aggs/buckets/filters.test.ts +++ b/src/plugins/data/common/search/aggs/buckets/filters.test.ts @@ -18,20 +18,20 @@ */ import { Query } from '../../../../common'; -import { coreMock } from '../../../../../../../src/core/public/mocks'; import { AggConfigs } from '../agg_configs'; -import { mockAggTypesRegistry } from '../test_helpers'; +import { AggTypesDependencies } from '../agg_types'; +import { mockAggTypesRegistry, mockAggTypesDependencies } from '../test_helpers'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { getFiltersBucketAgg, FiltersBucketAggDependencies } from './filters'; describe('Filters Agg', () => { - let aggTypesDependencies: FiltersBucketAggDependencies; + let aggTypesDependencies: AggTypesDependencies; beforeEach(() => { jest.resetAllMocks(); - const { uiSettings } = coreMock.createSetup(); - - aggTypesDependencies = { uiSettings }; + aggTypesDependencies = { + ...mockAggTypesDependencies, + getConfig: jest.fn(), + }; }); describe('order agg editor UI', () => { @@ -61,7 +61,7 @@ describe('Filters Agg', () => { }, ], { - typesRegistry: mockAggTypesRegistry([getFiltersBucketAgg(aggTypesDependencies)]), + typesRegistry: mockAggTypesRegistry(aggTypesDependencies), } ); }; @@ -218,7 +218,7 @@ describe('Filters Agg', () => { }); test('works with leading wildcards if allowed', () => { - aggTypesDependencies.uiSettings.get = (s: any) => + aggTypesDependencies.getConfig = (s: any) => s === 'query:allowLeadingWildcards' ? true : s; const aggConfigs = getAggConfigs({ diff --git a/src/plugins/data/public/search/aggs/buckets/filters.ts b/src/plugins/data/common/search/aggs/buckets/filters.ts similarity index 90% rename from src/plugins/data/public/search/aggs/buckets/filters.ts rename to src/plugins/data/common/search/aggs/buckets/filters.ts index cd4ed721fda77..7310fa08b68e0 100644 --- a/src/plugins/data/public/search/aggs/buckets/filters.ts +++ b/src/plugins/data/common/search/aggs/buckets/filters.ts @@ -19,7 +19,6 @@ import { i18n } from '@kbn/i18n'; import { size, transform, cloneDeep } from 'lodash'; -import { IUiSettingsClient } from 'src/core/public'; import { createFilterFilters } from './create_filter/filters'; import { toAngularJSON } from '../utils'; @@ -41,7 +40,7 @@ interface FilterValue { } export interface FiltersBucketAggDependencies { - uiSettings: IUiSettingsClient; + getConfig: (key: string) => any; } export interface AggParamsFilters extends Omit { @@ -51,7 +50,7 @@ export interface AggParamsFilters extends Omit { }>; } -export const getFiltersBucketAgg = ({ uiSettings }: FiltersBucketAggDependencies) => +export const getFiltersBucketAgg = ({ getConfig }: FiltersBucketAggDependencies) => new BucketAggType({ name: BUCKET_TYPES.FILTERS, title: filtersTitle, @@ -60,9 +59,9 @@ export const getFiltersBucketAgg = ({ uiSettings }: FiltersBucketAggDependencies params: [ { name: 'filters', - default: [ + default: () => [ { - input: { query: '', language: uiSettings.get(UI_SETTINGS.SEARCH_QUERY_LANGUAGE) }, + input: { query: '', language: getConfig(UI_SETTINGS.SEARCH_QUERY_LANGUAGE) }, label: '', }, ], @@ -80,7 +79,7 @@ export const getFiltersBucketAgg = ({ uiSettings }: FiltersBucketAggDependencies return; } - const esQueryConfigs = getEsQueryConfig(uiSettings); + const esQueryConfigs = getEsQueryConfig({ get: getConfig }); const query = buildEsQuery(aggConfig.getIndexPattern(), [input], [], esQueryConfigs); if (!query) { diff --git a/src/plugins/data/public/search/aggs/buckets/filters_fn.test.ts b/src/plugins/data/common/search/aggs/buckets/filters_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/filters_fn.test.ts rename to src/plugins/data/common/search/aggs/buckets/filters_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/buckets/filters_fn.ts b/src/plugins/data/common/search/aggs/buckets/filters_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/filters_fn.ts rename to src/plugins/data/common/search/aggs/buckets/filters_fn.ts diff --git a/src/plugins/data/public/search/aggs/buckets/geo_hash.test.ts b/src/plugins/data/common/search/aggs/buckets/geo_hash.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/geo_hash.test.ts rename to src/plugins/data/common/search/aggs/buckets/geo_hash.test.ts diff --git a/src/plugins/data/public/search/aggs/buckets/geo_hash.ts b/src/plugins/data/common/search/aggs/buckets/geo_hash.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/geo_hash.ts rename to src/plugins/data/common/search/aggs/buckets/geo_hash.ts diff --git a/src/plugins/data/public/search/aggs/buckets/geo_hash_fn.test.ts b/src/plugins/data/common/search/aggs/buckets/geo_hash_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/geo_hash_fn.test.ts rename to src/plugins/data/common/search/aggs/buckets/geo_hash_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/buckets/geo_hash_fn.ts b/src/plugins/data/common/search/aggs/buckets/geo_hash_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/geo_hash_fn.ts rename to src/plugins/data/common/search/aggs/buckets/geo_hash_fn.ts diff --git a/src/plugins/data/public/search/aggs/buckets/geo_tile.ts b/src/plugins/data/common/search/aggs/buckets/geo_tile.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/geo_tile.ts rename to src/plugins/data/common/search/aggs/buckets/geo_tile.ts diff --git a/src/plugins/data/public/search/aggs/buckets/geo_tile_fn.test.ts b/src/plugins/data/common/search/aggs/buckets/geo_tile_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/geo_tile_fn.test.ts rename to src/plugins/data/common/search/aggs/buckets/geo_tile_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/buckets/geo_tile_fn.ts b/src/plugins/data/common/search/aggs/buckets/geo_tile_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/geo_tile_fn.ts rename to src/plugins/data/common/search/aggs/buckets/geo_tile_fn.ts diff --git a/src/plugins/data/public/search/aggs/buckets/histogram.test.ts b/src/plugins/data/common/search/aggs/buckets/histogram.test.ts similarity index 90% rename from src/plugins/data/public/search/aggs/buckets/histogram.test.ts rename to src/plugins/data/common/search/aggs/buckets/histogram.test.ts index 6ac77f207d9ce..3727747984d3e 100644 --- a/src/plugins/data/public/search/aggs/buckets/histogram.test.ts +++ b/src/plugins/data/common/search/aggs/buckets/histogram.test.ts @@ -17,33 +17,18 @@ * under the License. */ -import { coreMock } from '../../../../../../../src/core/public/mocks'; import { AggConfigs } from '../agg_configs'; -import { mockAggTypesRegistry } from '../test_helpers'; +import { mockAggTypesRegistry, mockAggTypesDependencies } from '../test_helpers'; +import { AggTypesDependencies } from '../agg_types'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { - IBucketHistogramAggConfig, - getHistogramBucketAgg, - AutoBounds, - HistogramBucketAggDependencies, -} from './histogram'; +import { IBucketHistogramAggConfig, getHistogramBucketAgg, AutoBounds } from './histogram'; import { BucketAggType } from './bucket_agg_type'; -import { fieldFormatsServiceMock } from '../../../field_formats/mocks'; -import { InternalStartServices } from '../../../types'; describe('Histogram Agg', () => { - let aggTypesDependencies: HistogramBucketAggDependencies; + let aggTypesDependencies: AggTypesDependencies; beforeEach(() => { - const { uiSettings } = coreMock.createSetup(); - - aggTypesDependencies = { - uiSettings, - getInternalStartServices: () => - (({ - fieldFormats: fieldFormatsServiceMock.createStartContract(), - } as unknown) as InternalStartServices), - }; + aggTypesDependencies = { ...mockAggTypesDependencies }; }); const getAggConfigs = (params: Record) => { @@ -72,7 +57,7 @@ describe('Histogram Agg', () => { }, ], { - typesRegistry: mockAggTypesRegistry([getHistogramBucketAgg(aggTypesDependencies)]), + typesRegistry: mockAggTypesRegistry(aggTypesDependencies), } ); }; @@ -167,10 +152,7 @@ describe('Histogram Agg', () => { ) => { aggTypesDependencies = { ...aggTypesDependencies, - uiSettings: { - ...aggTypesDependencies.uiSettings, - get: () => maxBars as any, - }, + getConfig: () => maxBars as any, }; const aggConfigs = getAggConfigs({ diff --git a/src/plugins/data/public/search/aggs/buckets/histogram.ts b/src/plugins/data/common/search/aggs/buckets/histogram.ts similarity index 93% rename from src/plugins/data/public/search/aggs/buckets/histogram.ts rename to src/plugins/data/common/search/aggs/buckets/histogram.ts index 500b6eab75d77..2b263013e55a2 100644 --- a/src/plugins/data/public/search/aggs/buckets/histogram.ts +++ b/src/plugins/data/common/search/aggs/buckets/histogram.ts @@ -19,14 +19,14 @@ import { get } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { IUiSettingsClient } from 'src/core/public'; + +import { KBN_FIELD_TYPES, UI_SETTINGS } from '../../../../common'; +import { AggTypesDependencies } from '../agg_types'; +import { BaseAggParams } from '../types'; import { BucketAggType, IBucketAggConfig } from './bucket_agg_type'; import { createFilterHistogram } from './create_filter/histogram'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { KBN_FIELD_TYPES, UI_SETTINGS } from '../../../../common'; -import { GetInternalStartServicesFn } from '../../../types'; -import { BaseAggParams } from '../types'; import { ExtendedBounds } from './lib/extended_bounds'; export interface AutoBounds { @@ -35,8 +35,8 @@ export interface AutoBounds { } export interface HistogramBucketAggDependencies { - uiSettings: IUiSettingsClient; - getInternalStartServices: GetInternalStartServicesFn; + getConfig: (key: string) => T; + getFieldFormatsStart: AggTypesDependencies['getFieldFormatsStart']; } export interface IBucketHistogramAggConfig extends IBucketAggConfig { @@ -54,8 +54,8 @@ export interface AggParamsHistogram extends BaseAggParams { } export const getHistogramBucketAgg = ({ - uiSettings, - getInternalStartServices, + getConfig, + getFieldFormatsStart, }: HistogramBucketAggDependencies) => new BucketAggType({ name: BUCKET_TYPES.HISTOGRAM, @@ -66,7 +66,7 @@ export const getHistogramBucketAgg = ({ makeLabel(aggConfig) { return aggConfig.getFieldDisplayName(); }, - createFilter: createFilterHistogram(getInternalStartServices), + createFilter: createFilterHistogram(getFieldFormatsStart), decorateAggConfig() { let autoBounds: AutoBounds; @@ -154,8 +154,8 @@ export const getHistogramBucketAgg = ({ const range = autoBounds.max - autoBounds.min; const bars = range / interval; - if (bars > uiSettings.get(UI_SETTINGS.HISTOGRAM_MAX_BARS)) { - const minInterval = range / uiSettings.get(UI_SETTINGS.HISTOGRAM_MAX_BARS); + if (bars > getConfig(UI_SETTINGS.HISTOGRAM_MAX_BARS)) { + const minInterval = range / getConfig(UI_SETTINGS.HISTOGRAM_MAX_BARS); // Round interval by order of magnitude to provide clean intervals // Always round interval up so there will always be less buckets than histogram:maxBars diff --git a/src/plugins/data/public/search/aggs/buckets/histogram_fn.test.ts b/src/plugins/data/common/search/aggs/buckets/histogram_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/histogram_fn.test.ts rename to src/plugins/data/common/search/aggs/buckets/histogram_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/buckets/histogram_fn.ts b/src/plugins/data/common/search/aggs/buckets/histogram_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/histogram_fn.ts rename to src/plugins/data/common/search/aggs/buckets/histogram_fn.ts diff --git a/src/plugins/data/public/search/aggs/buckets/index.ts b/src/plugins/data/common/search/aggs/buckets/index.ts similarity index 97% rename from src/plugins/data/public/search/aggs/buckets/index.ts rename to src/plugins/data/common/search/aggs/buckets/index.ts index 7036cc7785db7..b16242e519872 100644 --- a/src/plugins/data/public/search/aggs/buckets/index.ts +++ b/src/plugins/data/common/search/aggs/buckets/index.ts @@ -18,6 +18,7 @@ */ export * from './_interval_options'; +export * from './bucket_agg_type'; export * from './bucket_agg_types'; export * from './histogram'; export * from './date_histogram'; diff --git a/src/plugins/data/public/search/aggs/buckets/ip_range.ts b/src/plugins/data/common/search/aggs/buckets/ip_range.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/ip_range.ts rename to src/plugins/data/common/search/aggs/buckets/ip_range.ts diff --git a/src/plugins/data/public/search/aggs/buckets/ip_range_fn.test.ts b/src/plugins/data/common/search/aggs/buckets/ip_range_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/ip_range_fn.test.ts rename to src/plugins/data/common/search/aggs/buckets/ip_range_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/buckets/ip_range_fn.ts b/src/plugins/data/common/search/aggs/buckets/ip_range_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/ip_range_fn.ts rename to src/plugins/data/common/search/aggs/buckets/ip_range_fn.ts diff --git a/src/plugins/data/public/search/aggs/buckets/lib/cidr_mask.test.ts b/src/plugins/data/common/search/aggs/buckets/lib/cidr_mask.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/lib/cidr_mask.test.ts rename to src/plugins/data/common/search/aggs/buckets/lib/cidr_mask.test.ts diff --git a/src/plugins/data/public/search/aggs/buckets/lib/cidr_mask.ts b/src/plugins/data/common/search/aggs/buckets/lib/cidr_mask.ts similarity index 97% rename from src/plugins/data/public/search/aggs/buckets/lib/cidr_mask.ts rename to src/plugins/data/common/search/aggs/buckets/lib/cidr_mask.ts index 57a7b378f305f..e4f6ab1e8da3c 100644 --- a/src/plugins/data/public/search/aggs/buckets/lib/cidr_mask.ts +++ b/src/plugins/data/common/search/aggs/buckets/lib/cidr_mask.ts @@ -17,7 +17,7 @@ * under the License. */ -import { Ipv4Address } from '../../../../../common'; +import { Ipv4Address } from '../../utils'; const NUM_BITS = 32; diff --git a/src/plugins/data/public/search/aggs/buckets/lib/date_range.ts b/src/plugins/data/common/search/aggs/buckets/lib/date_range.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/lib/date_range.ts rename to src/plugins/data/common/search/aggs/buckets/lib/date_range.ts diff --git a/src/plugins/data/public/search/aggs/buckets/lib/extended_bounds.ts b/src/plugins/data/common/search/aggs/buckets/lib/extended_bounds.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/lib/extended_bounds.ts rename to src/plugins/data/common/search/aggs/buckets/lib/extended_bounds.ts diff --git a/src/plugins/data/public/search/aggs/buckets/lib/geo_point.ts b/src/plugins/data/common/search/aggs/buckets/lib/geo_point.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/lib/geo_point.ts rename to src/plugins/data/common/search/aggs/buckets/lib/geo_point.ts diff --git a/src/plugins/data/public/search/aggs/buckets/lib/ip_range.ts b/src/plugins/data/common/search/aggs/buckets/lib/ip_range.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/lib/ip_range.ts rename to src/plugins/data/common/search/aggs/buckets/lib/ip_range.ts diff --git a/src/plugins/data/public/search/aggs/buckets/lib/time_buckets/calc_auto_interval.test.ts b/src/plugins/data/common/search/aggs/buckets/lib/time_buckets/calc_auto_interval.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/lib/time_buckets/calc_auto_interval.test.ts rename to src/plugins/data/common/search/aggs/buckets/lib/time_buckets/calc_auto_interval.test.ts diff --git a/src/plugins/data/public/search/aggs/buckets/lib/time_buckets/calc_auto_interval.ts b/src/plugins/data/common/search/aggs/buckets/lib/time_buckets/calc_auto_interval.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/lib/time_buckets/calc_auto_interval.ts rename to src/plugins/data/common/search/aggs/buckets/lib/time_buckets/calc_auto_interval.ts diff --git a/src/plugins/data/public/search/aggs/buckets/lib/time_buckets/calc_es_interval.ts b/src/plugins/data/common/search/aggs/buckets/lib/time_buckets/calc_es_interval.ts similarity index 97% rename from src/plugins/data/public/search/aggs/buckets/lib/time_buckets/calc_es_interval.ts rename to src/plugins/data/common/search/aggs/buckets/lib/time_buckets/calc_es_interval.ts index 3e7d315a0a42a..0ef2c571ca8fa 100644 --- a/src/plugins/data/public/search/aggs/buckets/lib/time_buckets/calc_es_interval.ts +++ b/src/plugins/data/common/search/aggs/buckets/lib/time_buckets/calc_es_interval.ts @@ -20,7 +20,7 @@ import moment from 'moment'; import dateMath, { Unit } from '@elastic/datemath'; -import { parseEsInterval } from '../../../../../../common'; +import { parseEsInterval } from '../../../utils'; const unitsDesc = dateMath.unitsDesc; const largeMax = unitsDesc.indexOf('M'); diff --git a/src/plugins/data/public/search/aggs/buckets/lib/time_buckets/index.ts b/src/plugins/data/common/search/aggs/buckets/lib/time_buckets/index.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/lib/time_buckets/index.ts rename to src/plugins/data/common/search/aggs/buckets/lib/time_buckets/index.ts diff --git a/src/plugins/data/public/search/aggs/buckets/lib/time_buckets/time_buckets.test.ts b/src/plugins/data/common/search/aggs/buckets/lib/time_buckets/time_buckets.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/lib/time_buckets/time_buckets.test.ts rename to src/plugins/data/common/search/aggs/buckets/lib/time_buckets/time_buckets.test.ts diff --git a/src/plugins/data/public/search/aggs/buckets/lib/time_buckets/time_buckets.ts b/src/plugins/data/common/search/aggs/buckets/lib/time_buckets/time_buckets.ts similarity index 99% rename from src/plugins/data/public/search/aggs/buckets/lib/time_buckets/time_buckets.ts rename to src/plugins/data/common/search/aggs/buckets/lib/time_buckets/time_buckets.ts index 017f646258c01..6402a6e83ead9 100644 --- a/src/plugins/data/public/search/aggs/buckets/lib/time_buckets/time_buckets.ts +++ b/src/plugins/data/common/search/aggs/buckets/lib/time_buckets/time_buckets.ts @@ -20,7 +20,7 @@ import { isString, isObject as isObjectLodash, isPlainObject, sortBy } from 'lodash'; import moment, { Moment } from 'moment'; -import { parseInterval } from '../../../../../../common'; +import { parseInterval } from '../../../utils'; import { TimeRangeBounds } from '../../../../../query'; import { calcAutoIntervalLessThan, calcAutoIntervalNear } from './calc_auto_interval'; import { diff --git a/src/plugins/data/public/search/aggs/buckets/migrate_include_exclude_format.ts b/src/plugins/data/common/search/aggs/buckets/migrate_include_exclude_format.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/migrate_include_exclude_format.ts rename to src/plugins/data/common/search/aggs/buckets/migrate_include_exclude_format.ts diff --git a/src/plugins/data/public/search/aggs/buckets/range.test.ts b/src/plugins/data/common/search/aggs/buckets/range.test.ts similarity index 79% rename from src/plugins/data/public/search/aggs/buckets/range.test.ts rename to src/plugins/data/common/search/aggs/buckets/range.test.ts index f7c61a638158c..b23b03db6a9ec 100644 --- a/src/plugins/data/public/search/aggs/buckets/range.test.ts +++ b/src/plugins/data/common/search/aggs/buckets/range.test.ts @@ -17,26 +17,12 @@ * under the License. */ -import { getRangeBucketAgg, RangeBucketAggDependencies } from './range'; import { AggConfigs } from '../agg_configs'; import { mockAggTypesRegistry } from '../test_helpers'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { FieldFormatsGetConfigFn, NumberFormat } from '../../../../common'; -import { fieldFormatsServiceMock } from '../../../field_formats/mocks'; -import { InternalStartServices } from '../../../types'; +import { FieldFormatsGetConfigFn, NumberFormat } from '../../../../common/field_formats'; describe('Range Agg', () => { - let aggTypesDependencies: RangeBucketAggDependencies; - - beforeEach(() => { - aggTypesDependencies = { - getInternalStartServices: () => - (({ - fieldFormats: fieldFormatsServiceMock.createStartContract(), - } as unknown) as InternalStartServices), - }; - }); - const getConfig = (() => {}) as FieldFormatsGetConfigFn; const getAggConfigs = () => { const field = { @@ -74,7 +60,7 @@ describe('Range Agg', () => { }, ], { - typesRegistry: mockAggTypesRegistry([getRangeBucketAgg(aggTypesDependencies)]), + typesRegistry: mockAggTypesRegistry(), } ); }; diff --git a/src/plugins/data/public/search/aggs/buckets/range.ts b/src/plugins/data/common/search/aggs/buckets/range.ts similarity index 90% rename from src/plugins/data/public/search/aggs/buckets/range.ts rename to src/plugins/data/common/search/aggs/buckets/range.ts index 9f54f9fd0704e..91a357b635950 100644 --- a/src/plugins/data/public/search/aggs/buckets/range.ts +++ b/src/plugins/data/common/search/aggs/buckets/range.ts @@ -18,20 +18,22 @@ */ import { i18n } from '@kbn/i18n'; -import { BucketAggType } from './bucket_agg_type'; + import { KBN_FIELD_TYPES } from '../../../../common'; +import { AggTypesDependencies } from '../agg_types'; +import { BaseAggParams } from '../types'; + +import { BucketAggType } from './bucket_agg_type'; import { RangeKey } from './range_key'; import { createFilterRange } from './create_filter/range'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { GetInternalStartServicesFn } from '../../../types'; -import { BaseAggParams } from '../types'; const rangeTitle = i18n.translate('data.search.aggs.buckets.rangeTitle', { defaultMessage: 'Range', }); export interface RangeBucketAggDependencies { - getInternalStartServices: GetInternalStartServicesFn; + getFieldFormatsStart: AggTypesDependencies['getFieldFormatsStart']; } export interface AggParamsRange extends BaseAggParams { @@ -42,13 +44,13 @@ export interface AggParamsRange extends BaseAggParams { }>; } -export const getRangeBucketAgg = ({ getInternalStartServices }: RangeBucketAggDependencies) => { +export const getRangeBucketAgg = ({ getFieldFormatsStart }: RangeBucketAggDependencies) => { const keyCaches = new WeakMap(); return new BucketAggType({ name: BUCKET_TYPES.RANGE, title: rangeTitle, - createFilter: createFilterRange(getInternalStartServices), + createFilter: createFilterRange(getFieldFormatsStart), makeLabel(aggConfig) { return i18n.translate('data.search.aggs.aggTypesLabel', { defaultMessage: '{fieldName} ranges', diff --git a/src/plugins/data/public/search/aggs/buckets/range_fn.test.ts b/src/plugins/data/common/search/aggs/buckets/range_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/range_fn.test.ts rename to src/plugins/data/common/search/aggs/buckets/range_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/buckets/range_fn.ts b/src/plugins/data/common/search/aggs/buckets/range_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/range_fn.ts rename to src/plugins/data/common/search/aggs/buckets/range_fn.ts diff --git a/src/plugins/data/public/search/aggs/buckets/range_key.ts b/src/plugins/data/common/search/aggs/buckets/range_key.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/range_key.ts rename to src/plugins/data/common/search/aggs/buckets/range_key.ts diff --git a/src/plugins/data/public/search/aggs/buckets/significant_terms.test.ts b/src/plugins/data/common/search/aggs/buckets/significant_terms.test.ts similarity index 95% rename from src/plugins/data/public/search/aggs/buckets/significant_terms.test.ts rename to src/plugins/data/common/search/aggs/buckets/significant_terms.test.ts index f13fafc2b17e6..e6c7bbee72a72 100644 --- a/src/plugins/data/public/search/aggs/buckets/significant_terms.test.ts +++ b/src/plugins/data/common/search/aggs/buckets/significant_terms.test.ts @@ -20,7 +20,6 @@ import { AggConfigs, IAggConfigs } from '../agg_configs'; import { mockAggTypesRegistry } from '../test_helpers'; import { BUCKET_TYPES } from './bucket_agg_types'; -import { getSignificantTermsBucketAgg } from './significant_terms'; describe('Significant Terms Agg', () => { describe('order agg editor UI', () => { @@ -51,7 +50,7 @@ describe('Significant Terms Agg', () => { }, ], { - typesRegistry: mockAggTypesRegistry([getSignificantTermsBucketAgg()]), + typesRegistry: mockAggTypesRegistry(), } ); }; diff --git a/src/plugins/data/public/search/aggs/buckets/significant_terms.ts b/src/plugins/data/common/search/aggs/buckets/significant_terms.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/significant_terms.ts rename to src/plugins/data/common/search/aggs/buckets/significant_terms.ts diff --git a/src/plugins/data/public/search/aggs/buckets/significant_terms_fn.test.ts b/src/plugins/data/common/search/aggs/buckets/significant_terms_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/significant_terms_fn.test.ts rename to src/plugins/data/common/search/aggs/buckets/significant_terms_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/buckets/significant_terms_fn.ts b/src/plugins/data/common/search/aggs/buckets/significant_terms_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/significant_terms_fn.ts rename to src/plugins/data/common/search/aggs/buckets/significant_terms_fn.ts diff --git a/src/plugins/data/public/search/aggs/buckets/terms.test.ts b/src/plugins/data/common/search/aggs/buckets/terms.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/terms.test.ts rename to src/plugins/data/common/search/aggs/buckets/terms.test.ts diff --git a/src/plugins/data/public/search/aggs/buckets/terms.ts b/src/plugins/data/common/search/aggs/buckets/terms.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/terms.ts rename to src/plugins/data/common/search/aggs/buckets/terms.ts diff --git a/src/plugins/data/public/search/aggs/buckets/terms_fn.test.ts b/src/plugins/data/common/search/aggs/buckets/terms_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/terms_fn.test.ts rename to src/plugins/data/common/search/aggs/buckets/terms_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/buckets/terms_fn.ts b/src/plugins/data/common/search/aggs/buckets/terms_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/buckets/terms_fn.ts rename to src/plugins/data/common/search/aggs/buckets/terms_fn.ts diff --git a/src/plugins/data/public/search/aggs/index.test.ts b/src/plugins/data/common/search/aggs/index.test.ts similarity index 63% rename from src/plugins/data/public/search/aggs/index.test.ts rename to src/plugins/data/common/search/aggs/index.test.ts index 73068326ca97e..1fdc28d1c7839 100644 --- a/src/plugins/data/public/search/aggs/index.test.ts +++ b/src/plugins/data/common/search/aggs/index.test.ts @@ -17,42 +17,34 @@ * under the License. */ -import { coreMock } from '../../../../../../src/core/public/mocks'; import { getAggTypes } from './index'; +import { mockGetFieldFormatsStart } from './test_helpers'; import { isBucketAggType } from './buckets/bucket_agg_type'; import { isMetricAggType } from './metrics/metric_agg_type'; -import { FieldFormatsStart } from '../../field_formats'; -import { InternalStartServices } from '../../types'; describe('AggTypesComponent', () => { - const coreSetup = coreMock.createSetup(); - const coreStart = coreMock.createSetup(); - - const aggTypes = getAggTypes({ - calculateBounds: jest.fn(), - getInternalStartServices: () => - (({ - notifications: coreStart.notifications, - fieldFormats: {} as FieldFormatsStart, - } as unknown) as InternalStartServices), - uiSettings: coreSetup.uiSettings, - }); - + const aggTypes = getAggTypes(); const { buckets, metrics } = aggTypes; + const aggTypesDependencies = { + calculateBounds: jest.fn(), + getConfig: jest.fn(), + getFieldFormatsStart: mockGetFieldFormatsStart, + isDefaultTimezone: jest.fn().mockReturnValue(true), + }; describe('bucket aggs', () => { test('all extend BucketAggType', () => { - buckets.forEach((bucketAgg) => { - expect(isBucketAggType(bucketAgg)).toBeTruthy(); + buckets.forEach(({ fn }) => { + expect(isBucketAggType(fn(aggTypesDependencies))).toBeTruthy(); }); }); }); describe('metric aggs', () => { test('all extend MetricAggType', () => { - metrics.forEach((metricAgg) => { - expect(isMetricAggType(metricAgg)).toBeTruthy(); + metrics.forEach(({ fn }) => { + expect(isMetricAggType(fn(aggTypesDependencies))).toBeTruthy(); }); }); }); diff --git a/src/plugins/data/common/search/aggs/index.ts b/src/plugins/data/common/search/aggs/index.ts index 7a5b7d509c940..1c4ae27e49530 100644 --- a/src/plugins/data/common/search/aggs/index.ts +++ b/src/plugins/data/common/search/aggs/index.ts @@ -17,5 +17,15 @@ * under the License. */ -export * from './date_interval_utils'; -export * from './ipv4_address'; +export * from './agg_config'; +export * from './agg_configs'; +export * from './agg_groups'; +export * from './agg_type'; +export * from './agg_types'; +export * from './agg_types_registry'; +export * from './aggs_service'; +export * from './buckets'; +export * from './metrics'; +export * from './param_types'; +export * from './types'; +export * from './utils'; diff --git a/src/plugins/data/public/search/aggs/metrics/avg.ts b/src/plugins/data/common/search/aggs/metrics/avg.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/avg.ts rename to src/plugins/data/common/search/aggs/metrics/avg.ts diff --git a/src/plugins/data/public/search/aggs/metrics/avg_fn.test.ts b/src/plugins/data/common/search/aggs/metrics/avg_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/avg_fn.test.ts rename to src/plugins/data/common/search/aggs/metrics/avg_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/avg_fn.ts b/src/plugins/data/common/search/aggs/metrics/avg_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/avg_fn.ts rename to src/plugins/data/common/search/aggs/metrics/avg_fn.ts diff --git a/src/plugins/data/public/search/aggs/metrics/bucket_avg.ts b/src/plugins/data/common/search/aggs/metrics/bucket_avg.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/bucket_avg.ts rename to src/plugins/data/common/search/aggs/metrics/bucket_avg.ts diff --git a/src/plugins/data/public/search/aggs/metrics/bucket_avg_fn.test.ts b/src/plugins/data/common/search/aggs/metrics/bucket_avg_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/bucket_avg_fn.test.ts rename to src/plugins/data/common/search/aggs/metrics/bucket_avg_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/bucket_avg_fn.ts b/src/plugins/data/common/search/aggs/metrics/bucket_avg_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/bucket_avg_fn.ts rename to src/plugins/data/common/search/aggs/metrics/bucket_avg_fn.ts diff --git a/src/plugins/data/public/search/aggs/metrics/bucket_max.ts b/src/plugins/data/common/search/aggs/metrics/bucket_max.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/bucket_max.ts rename to src/plugins/data/common/search/aggs/metrics/bucket_max.ts diff --git a/src/plugins/data/public/search/aggs/metrics/bucket_max_fn.test.ts b/src/plugins/data/common/search/aggs/metrics/bucket_max_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/bucket_max_fn.test.ts rename to src/plugins/data/common/search/aggs/metrics/bucket_max_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/bucket_max_fn.ts b/src/plugins/data/common/search/aggs/metrics/bucket_max_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/bucket_max_fn.ts rename to src/plugins/data/common/search/aggs/metrics/bucket_max_fn.ts diff --git a/src/plugins/data/public/search/aggs/metrics/bucket_min.ts b/src/plugins/data/common/search/aggs/metrics/bucket_min.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/bucket_min.ts rename to src/plugins/data/common/search/aggs/metrics/bucket_min.ts diff --git a/src/plugins/data/public/search/aggs/metrics/bucket_min_fn.test.ts b/src/plugins/data/common/search/aggs/metrics/bucket_min_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/bucket_min_fn.test.ts rename to src/plugins/data/common/search/aggs/metrics/bucket_min_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/bucket_min_fn.ts b/src/plugins/data/common/search/aggs/metrics/bucket_min_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/bucket_min_fn.ts rename to src/plugins/data/common/search/aggs/metrics/bucket_min_fn.ts diff --git a/src/plugins/data/public/search/aggs/metrics/bucket_sum.ts b/src/plugins/data/common/search/aggs/metrics/bucket_sum.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/bucket_sum.ts rename to src/plugins/data/common/search/aggs/metrics/bucket_sum.ts diff --git a/src/plugins/data/public/search/aggs/metrics/bucket_sum_fn.test.ts b/src/plugins/data/common/search/aggs/metrics/bucket_sum_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/bucket_sum_fn.test.ts rename to src/plugins/data/common/search/aggs/metrics/bucket_sum_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/bucket_sum_fn.ts b/src/plugins/data/common/search/aggs/metrics/bucket_sum_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/bucket_sum_fn.ts rename to src/plugins/data/common/search/aggs/metrics/bucket_sum_fn.ts diff --git a/src/plugins/data/public/search/aggs/metrics/cardinality.ts b/src/plugins/data/common/search/aggs/metrics/cardinality.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/cardinality.ts rename to src/plugins/data/common/search/aggs/metrics/cardinality.ts diff --git a/src/plugins/data/public/search/aggs/metrics/cardinality_fn.test.ts b/src/plugins/data/common/search/aggs/metrics/cardinality_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/cardinality_fn.test.ts rename to src/plugins/data/common/search/aggs/metrics/cardinality_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/cardinality_fn.ts b/src/plugins/data/common/search/aggs/metrics/cardinality_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/cardinality_fn.ts rename to src/plugins/data/common/search/aggs/metrics/cardinality_fn.ts diff --git a/src/plugins/data/public/search/aggs/metrics/count.ts b/src/plugins/data/common/search/aggs/metrics/count.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/count.ts rename to src/plugins/data/common/search/aggs/metrics/count.ts diff --git a/src/plugins/data/public/search/aggs/metrics/count_fn.test.ts b/src/plugins/data/common/search/aggs/metrics/count_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/count_fn.test.ts rename to src/plugins/data/common/search/aggs/metrics/count_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/count_fn.ts b/src/plugins/data/common/search/aggs/metrics/count_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/count_fn.ts rename to src/plugins/data/common/search/aggs/metrics/count_fn.ts diff --git a/src/plugins/data/public/search/aggs/metrics/cumulative_sum.ts b/src/plugins/data/common/search/aggs/metrics/cumulative_sum.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/cumulative_sum.ts rename to src/plugins/data/common/search/aggs/metrics/cumulative_sum.ts diff --git a/src/plugins/data/public/search/aggs/metrics/cumulative_sum_fn.test.ts b/src/plugins/data/common/search/aggs/metrics/cumulative_sum_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/cumulative_sum_fn.test.ts rename to src/plugins/data/common/search/aggs/metrics/cumulative_sum_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/cumulative_sum_fn.ts b/src/plugins/data/common/search/aggs/metrics/cumulative_sum_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/cumulative_sum_fn.ts rename to src/plugins/data/common/search/aggs/metrics/cumulative_sum_fn.ts diff --git a/src/plugins/data/public/search/aggs/metrics/derivative.ts b/src/plugins/data/common/search/aggs/metrics/derivative.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/derivative.ts rename to src/plugins/data/common/search/aggs/metrics/derivative.ts diff --git a/src/plugins/data/public/search/aggs/metrics/derivative_fn.test.ts b/src/plugins/data/common/search/aggs/metrics/derivative_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/derivative_fn.test.ts rename to src/plugins/data/common/search/aggs/metrics/derivative_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/derivative_fn.ts b/src/plugins/data/common/search/aggs/metrics/derivative_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/derivative_fn.ts rename to src/plugins/data/common/search/aggs/metrics/derivative_fn.ts diff --git a/src/plugins/data/public/search/aggs/metrics/geo_bounds.ts b/src/plugins/data/common/search/aggs/metrics/geo_bounds.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/geo_bounds.ts rename to src/plugins/data/common/search/aggs/metrics/geo_bounds.ts diff --git a/src/plugins/data/public/search/aggs/metrics/geo_bounds_fn.test.ts b/src/plugins/data/common/search/aggs/metrics/geo_bounds_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/geo_bounds_fn.test.ts rename to src/plugins/data/common/search/aggs/metrics/geo_bounds_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/geo_bounds_fn.ts b/src/plugins/data/common/search/aggs/metrics/geo_bounds_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/geo_bounds_fn.ts rename to src/plugins/data/common/search/aggs/metrics/geo_bounds_fn.ts diff --git a/src/plugins/data/public/search/aggs/metrics/geo_centroid.ts b/src/plugins/data/common/search/aggs/metrics/geo_centroid.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/geo_centroid.ts rename to src/plugins/data/common/search/aggs/metrics/geo_centroid.ts diff --git a/src/plugins/data/public/search/aggs/metrics/geo_centroid_fn.test.ts b/src/plugins/data/common/search/aggs/metrics/geo_centroid_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/geo_centroid_fn.test.ts rename to src/plugins/data/common/search/aggs/metrics/geo_centroid_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/geo_centroid_fn.ts b/src/plugins/data/common/search/aggs/metrics/geo_centroid_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/geo_centroid_fn.ts rename to src/plugins/data/common/search/aggs/metrics/geo_centroid_fn.ts diff --git a/src/plugins/data/public/search/aggs/metrics/index.ts b/src/plugins/data/common/search/aggs/metrics/index.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/index.ts rename to src/plugins/data/common/search/aggs/metrics/index.ts diff --git a/src/plugins/data/public/search/aggs/metrics/lib/get_response_agg_config_class.ts b/src/plugins/data/common/search/aggs/metrics/lib/get_response_agg_config_class.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/lib/get_response_agg_config_class.ts rename to src/plugins/data/common/search/aggs/metrics/lib/get_response_agg_config_class.ts diff --git a/src/plugins/data/public/search/aggs/metrics/lib/make_nested_label.test.ts b/src/plugins/data/common/search/aggs/metrics/lib/make_nested_label.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/lib/make_nested_label.test.ts rename to src/plugins/data/common/search/aggs/metrics/lib/make_nested_label.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/lib/make_nested_label.ts b/src/plugins/data/common/search/aggs/metrics/lib/make_nested_label.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/lib/make_nested_label.ts rename to src/plugins/data/common/search/aggs/metrics/lib/make_nested_label.ts diff --git a/src/plugins/data/public/search/aggs/metrics/lib/nested_agg_helpers.ts b/src/plugins/data/common/search/aggs/metrics/lib/nested_agg_helpers.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/lib/nested_agg_helpers.ts rename to src/plugins/data/common/search/aggs/metrics/lib/nested_agg_helpers.ts diff --git a/src/plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.test.ts b/src/plugins/data/common/search/aggs/metrics/lib/ordinal_suffix.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.test.ts rename to src/plugins/data/common/search/aggs/metrics/lib/ordinal_suffix.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.ts b/src/plugins/data/common/search/aggs/metrics/lib/ordinal_suffix.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/lib/ordinal_suffix.ts rename to src/plugins/data/common/search/aggs/metrics/lib/ordinal_suffix.ts diff --git a/src/plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts b/src/plugins/data/common/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts rename to src/plugins/data/common/search/aggs/metrics/lib/parent_pipeline_agg_helper.ts diff --git a/src/plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_writer.ts b/src/plugins/data/common/search/aggs/metrics/lib/parent_pipeline_agg_writer.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/lib/parent_pipeline_agg_writer.ts rename to src/plugins/data/common/search/aggs/metrics/lib/parent_pipeline_agg_writer.ts diff --git a/src/plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts b/src/plugins/data/common/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts rename to src/plugins/data/common/search/aggs/metrics/lib/sibling_pipeline_agg_helper.ts diff --git a/src/plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_writer.ts b/src/plugins/data/common/search/aggs/metrics/lib/sibling_pipeline_agg_writer.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/lib/sibling_pipeline_agg_writer.ts rename to src/plugins/data/common/search/aggs/metrics/lib/sibling_pipeline_agg_writer.ts diff --git a/src/plugins/data/public/search/aggs/metrics/max.ts b/src/plugins/data/common/search/aggs/metrics/max.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/max.ts rename to src/plugins/data/common/search/aggs/metrics/max.ts diff --git a/src/plugins/data/public/search/aggs/metrics/max_fn.test.ts b/src/plugins/data/common/search/aggs/metrics/max_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/max_fn.test.ts rename to src/plugins/data/common/search/aggs/metrics/max_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/max_fn.ts b/src/plugins/data/common/search/aggs/metrics/max_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/max_fn.ts rename to src/plugins/data/common/search/aggs/metrics/max_fn.ts diff --git a/src/plugins/data/public/search/aggs/metrics/median.test.ts b/src/plugins/data/common/search/aggs/metrics/median.test.ts similarity index 94% rename from src/plugins/data/public/search/aggs/metrics/median.test.ts rename to src/plugins/data/common/search/aggs/metrics/median.test.ts index 22d907330e2a3..f3f2d157ebafc 100644 --- a/src/plugins/data/public/search/aggs/metrics/median.test.ts +++ b/src/plugins/data/common/search/aggs/metrics/median.test.ts @@ -17,7 +17,6 @@ * under the License. */ -import { getMedianMetricAgg } from './median'; import { AggConfigs, IAggConfigs } from '../agg_configs'; import { mockAggTypesRegistry } from '../test_helpers'; import { METRIC_TYPES } from './metric_agg_types'; @@ -26,7 +25,7 @@ describe('AggTypeMetricMedianProvider class', () => { let aggConfigs: IAggConfigs; beforeEach(() => { - const typesRegistry = mockAggTypesRegistry([getMedianMetricAgg()]); + const typesRegistry = mockAggTypesRegistry(); const field = { name: 'bytes', }; diff --git a/src/plugins/data/public/search/aggs/metrics/median.ts b/src/plugins/data/common/search/aggs/metrics/median.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/median.ts rename to src/plugins/data/common/search/aggs/metrics/median.ts diff --git a/src/plugins/data/public/search/aggs/metrics/median_fn.test.ts b/src/plugins/data/common/search/aggs/metrics/median_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/median_fn.test.ts rename to src/plugins/data/common/search/aggs/metrics/median_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/median_fn.ts b/src/plugins/data/common/search/aggs/metrics/median_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/median_fn.ts rename to src/plugins/data/common/search/aggs/metrics/median_fn.ts diff --git a/src/plugins/data/public/search/aggs/metrics/metric_agg_type.ts b/src/plugins/data/common/search/aggs/metrics/metric_agg_type.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/metric_agg_type.ts rename to src/plugins/data/common/search/aggs/metrics/metric_agg_type.ts diff --git a/src/plugins/data/public/search/aggs/metrics/metric_agg_types.ts b/src/plugins/data/common/search/aggs/metrics/metric_agg_types.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/metric_agg_types.ts rename to src/plugins/data/common/search/aggs/metrics/metric_agg_types.ts diff --git a/src/plugins/data/public/search/aggs/metrics/min.ts b/src/plugins/data/common/search/aggs/metrics/min.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/min.ts rename to src/plugins/data/common/search/aggs/metrics/min.ts diff --git a/src/plugins/data/public/search/aggs/metrics/min_fn.test.ts b/src/plugins/data/common/search/aggs/metrics/min_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/min_fn.test.ts rename to src/plugins/data/common/search/aggs/metrics/min_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/min_fn.ts b/src/plugins/data/common/search/aggs/metrics/min_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/min_fn.ts rename to src/plugins/data/common/search/aggs/metrics/min_fn.ts diff --git a/src/plugins/data/public/search/aggs/metrics/moving_avg.ts b/src/plugins/data/common/search/aggs/metrics/moving_avg.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/moving_avg.ts rename to src/plugins/data/common/search/aggs/metrics/moving_avg.ts diff --git a/src/plugins/data/public/search/aggs/metrics/moving_avg_fn.test.ts b/src/plugins/data/common/search/aggs/metrics/moving_avg_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/moving_avg_fn.test.ts rename to src/plugins/data/common/search/aggs/metrics/moving_avg_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/moving_avg_fn.ts b/src/plugins/data/common/search/aggs/metrics/moving_avg_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/moving_avg_fn.ts rename to src/plugins/data/common/search/aggs/metrics/moving_avg_fn.ts diff --git a/src/plugins/data/public/search/aggs/metrics/parent_pipeline.test.ts b/src/plugins/data/common/search/aggs/metrics/parent_pipeline.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/parent_pipeline.test.ts rename to src/plugins/data/common/search/aggs/metrics/parent_pipeline.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts b/src/plugins/data/common/search/aggs/metrics/percentile_ranks.test.ts similarity index 77% rename from src/plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts rename to src/plugins/data/common/search/aggs/metrics/percentile_ranks.test.ts index 348aecc23243a..970daf5b62458 100644 --- a/src/plugins/data/public/search/aggs/metrics/percentile_ranks.test.ts +++ b/src/plugins/data/common/search/aggs/metrics/percentile_ranks.test.ts @@ -23,29 +23,16 @@ import { PercentileRanksMetricAggDependencies, } from './percentile_ranks'; import { AggConfigs, IAggConfigs } from '../agg_configs'; -import { mockAggTypesRegistry } from '../test_helpers'; +import { mockAggTypesRegistry, mockGetFieldFormatsStart } from '../test_helpers'; import { METRIC_TYPES } from './metric_agg_types'; -import { FieldFormatsStart } from '../../../field_formats'; -import { fieldFormatsServiceMock } from '../../../field_formats/mocks'; -import { InternalStartServices } from '../../../types'; describe('AggTypesMetricsPercentileRanksProvider class', function () { let aggConfigs: IAggConfigs; - let fieldFormats: FieldFormatsStart; let aggTypesDependencies: PercentileRanksMetricAggDependencies; beforeEach(() => { - fieldFormats = fieldFormatsServiceMock.createStartContract(); - fieldFormats.getDefaultInstance = (() => ({ - convert: (t?: string) => t, - })) as any; - aggTypesDependencies = { - getInternalStartServices: () => - (({ - fieldFormats, - } as unknown) as InternalStartServices), - }; - const typesRegistry = mockAggTypesRegistry([getPercentileRanksMetricAgg(aggTypesDependencies)]); + aggTypesDependencies = { getFieldFormatsStart: mockGetFieldFormatsStart }; + const typesRegistry = mockAggTypesRegistry(); const field = { name: 'bytes', }; diff --git a/src/plugins/data/public/search/aggs/metrics/percentile_ranks.ts b/src/plugins/data/common/search/aggs/metrics/percentile_ranks.ts similarity index 86% rename from src/plugins/data/public/search/aggs/metrics/percentile_ranks.ts rename to src/plugins/data/common/search/aggs/metrics/percentile_ranks.ts index 3c0be229f1bbd..664cc1ad02ada 100644 --- a/src/plugins/data/public/search/aggs/metrics/percentile_ranks.ts +++ b/src/plugins/data/common/search/aggs/metrics/percentile_ranks.ts @@ -18,13 +18,15 @@ */ import { i18n } from '@kbn/i18n'; + +import { KBN_FIELD_TYPES } from '../../../../common'; +import { AggTypesDependencies } from '../agg_types'; +import { BaseAggParams } from '../types'; + import { MetricAggType } from './metric_agg_type'; import { getResponseAggConfigClass, IResponseAggConfig } from './lib/get_response_agg_config_class'; import { getPercentileValue } from './percentiles_get_value'; import { METRIC_TYPES } from './metric_agg_types'; -import { KBN_FIELD_TYPES } from '../../../../common'; -import { GetInternalStartServicesFn } from '../../../types'; -import { BaseAggParams } from '../types'; export interface AggParamsPercentileRanks extends BaseAggParams { field: string; @@ -35,16 +37,17 @@ export interface AggParamsPercentileRanks extends BaseAggParams { export type IPercentileRanksAggConfig = IResponseAggConfig; export interface PercentileRanksMetricAggDependencies { - getInternalStartServices: GetInternalStartServicesFn; + getFieldFormatsStart: AggTypesDependencies['getFieldFormatsStart']; } -const getValueProps = (getInternalStartServices: GetInternalStartServicesFn) => { +const getValueProps = ( + getFieldFormatsStart: PercentileRanksMetricAggDependencies['getFieldFormatsStart'] +) => { return { makeLabel(this: IPercentileRanksAggConfig) { - const { fieldFormats } = getInternalStartServices(); + const { getDefaultInstance } = getFieldFormatsStart(); const field = this.getField(); - const format = - (field && field.format) || fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.NUMBER); + const format = (field && field.format) || getDefaultInstance(KBN_FIELD_TYPES.NUMBER); const customLabel = this.getParam('customLabel'); const label = customLabel || this.getFieldDisplayName(); @@ -57,7 +60,7 @@ const getValueProps = (getInternalStartServices: GetInternalStartServicesFn) => }; export const getPercentileRanksMetricAgg = ({ - getInternalStartServices, + getFieldFormatsStart, }: PercentileRanksMetricAggDependencies) => { return new MetricAggType({ name: METRIC_TYPES.PERCENTILE_RANKS, @@ -87,10 +90,7 @@ export const getPercentileRanksMetricAgg = ({ }, ], getResponseAggs(agg) { - const ValueAggConfig = getResponseAggConfigClass( - agg, - getValueProps(getInternalStartServices) - ); + const ValueAggConfig = getResponseAggConfigClass(agg, getValueProps(getFieldFormatsStart)); const values = agg.getParam('values'); return values.map((value: any) => new ValueAggConfig(value)); diff --git a/src/plugins/data/public/search/aggs/metrics/percentile_ranks_fn.test.ts b/src/plugins/data/common/search/aggs/metrics/percentile_ranks_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/percentile_ranks_fn.test.ts rename to src/plugins/data/common/search/aggs/metrics/percentile_ranks_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/percentile_ranks_fn.ts b/src/plugins/data/common/search/aggs/metrics/percentile_ranks_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/percentile_ranks_fn.ts rename to src/plugins/data/common/search/aggs/metrics/percentile_ranks_fn.ts diff --git a/src/plugins/data/public/search/aggs/metrics/percentiles.test.ts b/src/plugins/data/common/search/aggs/metrics/percentiles.test.ts similarity index 96% rename from src/plugins/data/public/search/aggs/metrics/percentiles.test.ts rename to src/plugins/data/common/search/aggs/metrics/percentiles.test.ts index a44c0e5075ef9..10e98df5a4eeb 100644 --- a/src/plugins/data/public/search/aggs/metrics/percentiles.test.ts +++ b/src/plugins/data/common/search/aggs/metrics/percentiles.test.ts @@ -26,7 +26,7 @@ describe('AggTypesMetricsPercentilesProvider class', () => { let aggConfigs: IAggConfigs; beforeEach(() => { - const typesRegistry = mockAggTypesRegistry([getPercentilesMetricAgg()]); + const typesRegistry = mockAggTypesRegistry(); const field = { name: 'bytes', }; diff --git a/src/plugins/data/public/search/aggs/metrics/percentiles.ts b/src/plugins/data/common/search/aggs/metrics/percentiles.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/percentiles.ts rename to src/plugins/data/common/search/aggs/metrics/percentiles.ts diff --git a/src/plugins/data/public/search/aggs/metrics/percentiles_fn.test.ts b/src/plugins/data/common/search/aggs/metrics/percentiles_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/percentiles_fn.test.ts rename to src/plugins/data/common/search/aggs/metrics/percentiles_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/percentiles_fn.ts b/src/plugins/data/common/search/aggs/metrics/percentiles_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/percentiles_fn.ts rename to src/plugins/data/common/search/aggs/metrics/percentiles_fn.ts diff --git a/src/plugins/data/public/search/aggs/metrics/percentiles_get_value.ts b/src/plugins/data/common/search/aggs/metrics/percentiles_get_value.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/percentiles_get_value.ts rename to src/plugins/data/common/search/aggs/metrics/percentiles_get_value.ts diff --git a/src/plugins/data/public/search/aggs/metrics/serial_diff.ts b/src/plugins/data/common/search/aggs/metrics/serial_diff.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/serial_diff.ts rename to src/plugins/data/common/search/aggs/metrics/serial_diff.ts diff --git a/src/plugins/data/public/search/aggs/metrics/serial_diff_fn.test.ts b/src/plugins/data/common/search/aggs/metrics/serial_diff_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/serial_diff_fn.test.ts rename to src/plugins/data/common/search/aggs/metrics/serial_diff_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/serial_diff_fn.ts b/src/plugins/data/common/search/aggs/metrics/serial_diff_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/serial_diff_fn.ts rename to src/plugins/data/common/search/aggs/metrics/serial_diff_fn.ts diff --git a/src/plugins/data/public/search/aggs/metrics/sibling_pipeline.test.ts b/src/plugins/data/common/search/aggs/metrics/sibling_pipeline.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/sibling_pipeline.test.ts rename to src/plugins/data/common/search/aggs/metrics/sibling_pipeline.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/std_deviation.test.ts b/src/plugins/data/common/search/aggs/metrics/std_deviation.test.ts similarity index 97% rename from src/plugins/data/public/search/aggs/metrics/std_deviation.test.ts rename to src/plugins/data/common/search/aggs/metrics/std_deviation.test.ts index c3efe95f44a56..f2f30fcde42eb 100644 --- a/src/plugins/data/public/search/aggs/metrics/std_deviation.test.ts +++ b/src/plugins/data/common/search/aggs/metrics/std_deviation.test.ts @@ -23,7 +23,7 @@ import { mockAggTypesRegistry } from '../test_helpers'; import { METRIC_TYPES } from './metric_agg_types'; describe('AggTypeMetricStandardDeviationProvider class', () => { - const typesRegistry = mockAggTypesRegistry([getStdDeviationMetricAgg()]); + const typesRegistry = mockAggTypesRegistry(); const getAggConfigs = (customLabel?: string) => { const field = { name: 'memory', diff --git a/src/plugins/data/public/search/aggs/metrics/std_deviation.ts b/src/plugins/data/common/search/aggs/metrics/std_deviation.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/std_deviation.ts rename to src/plugins/data/common/search/aggs/metrics/std_deviation.ts diff --git a/src/plugins/data/public/search/aggs/metrics/std_deviation_fn.test.ts b/src/plugins/data/common/search/aggs/metrics/std_deviation_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/std_deviation_fn.test.ts rename to src/plugins/data/common/search/aggs/metrics/std_deviation_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/std_deviation_fn.ts b/src/plugins/data/common/search/aggs/metrics/std_deviation_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/std_deviation_fn.ts rename to src/plugins/data/common/search/aggs/metrics/std_deviation_fn.ts diff --git a/src/plugins/data/public/search/aggs/metrics/sum.ts b/src/plugins/data/common/search/aggs/metrics/sum.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/sum.ts rename to src/plugins/data/common/search/aggs/metrics/sum.ts diff --git a/src/plugins/data/public/search/aggs/metrics/sum_fn.test.ts b/src/plugins/data/common/search/aggs/metrics/sum_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/sum_fn.test.ts rename to src/plugins/data/common/search/aggs/metrics/sum_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/sum_fn.ts b/src/plugins/data/common/search/aggs/metrics/sum_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/sum_fn.ts rename to src/plugins/data/common/search/aggs/metrics/sum_fn.ts diff --git a/src/plugins/data/public/search/aggs/metrics/top_hit.test.ts b/src/plugins/data/common/search/aggs/metrics/top_hit.test.ts similarity index 99% rename from src/plugins/data/public/search/aggs/metrics/top_hit.test.ts rename to src/plugins/data/common/search/aggs/metrics/top_hit.test.ts index c2434df3ae53c..c0cbfb33c842b 100644 --- a/src/plugins/data/public/search/aggs/metrics/top_hit.test.ts +++ b/src/plugins/data/common/search/aggs/metrics/top_hit.test.ts @@ -36,7 +36,7 @@ describe('Top hit metric', () => { fieldType = KBN_FIELD_TYPES.NUMBER, size = 1, }: any) => { - const typesRegistry = mockAggTypesRegistry([getTopHitMetricAgg()]); + const typesRegistry = mockAggTypesRegistry(); const field = { name: fieldName, displayName: fieldName, diff --git a/src/plugins/data/public/search/aggs/metrics/top_hit.ts b/src/plugins/data/common/search/aggs/metrics/top_hit.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/top_hit.ts rename to src/plugins/data/common/search/aggs/metrics/top_hit.ts diff --git a/src/plugins/data/public/search/aggs/metrics/top_hit_fn.test.ts b/src/plugins/data/common/search/aggs/metrics/top_hit_fn.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/top_hit_fn.test.ts rename to src/plugins/data/common/search/aggs/metrics/top_hit_fn.test.ts diff --git a/src/plugins/data/public/search/aggs/metrics/top_hit_fn.ts b/src/plugins/data/common/search/aggs/metrics/top_hit_fn.ts similarity index 100% rename from src/plugins/data/public/search/aggs/metrics/top_hit_fn.ts rename to src/plugins/data/common/search/aggs/metrics/top_hit_fn.ts diff --git a/src/plugins/data/public/search/aggs/param_types/agg.ts b/src/plugins/data/common/search/aggs/param_types/agg.ts similarity index 100% rename from src/plugins/data/public/search/aggs/param_types/agg.ts rename to src/plugins/data/common/search/aggs/param_types/agg.ts diff --git a/src/plugins/data/public/search/aggs/param_types/base.ts b/src/plugins/data/common/search/aggs/param_types/base.ts similarity index 96% rename from src/plugins/data/public/search/aggs/param_types/base.ts rename to src/plugins/data/common/search/aggs/param_types/base.ts index 1ba8a75e98cbe..3a12a9a54500f 100644 --- a/src/plugins/data/public/search/aggs/param_types/base.ts +++ b/src/plugins/data/common/search/aggs/param_types/base.ts @@ -17,11 +17,10 @@ * under the License. */ +import { FetchOptions, ISearchSource } from 'src/plugins/data/public'; import { ExpressionAstFunction } from 'src/plugins/expressions/common'; import { IAggConfigs } from '../agg_configs'; import { IAggConfig } from '../agg_config'; -import { FetchOptions } from '../../fetch'; -import { ISearchSource } from '../../search_source'; export class BaseParamType { name: string; diff --git a/src/plugins/data/public/search/aggs/param_types/field.test.ts b/src/plugins/data/common/search/aggs/param_types/field.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/param_types/field.test.ts rename to src/plugins/data/common/search/aggs/param_types/field.test.ts diff --git a/src/plugins/data/public/search/aggs/param_types/field.ts b/src/plugins/data/common/search/aggs/param_types/field.ts similarity index 96% rename from src/plugins/data/public/search/aggs/param_types/field.ts rename to src/plugins/data/common/search/aggs/param_types/field.ts index 7c00bc668a39f..492294bdf4e5f 100644 --- a/src/plugins/data/public/search/aggs/param_types/field.ts +++ b/src/plugins/data/common/search/aggs/param_types/field.ts @@ -22,8 +22,8 @@ import { IAggConfig } from '../agg_config'; import { SavedObjectNotFound } from '../../../../../../plugins/kibana_utils/common'; import { BaseParamType } from './base'; import { propFilter } from '../utils'; -import { isNestedField, KBN_FIELD_TYPES } from '../../../../common'; -import { IndexPatternField } from '../../../index_patterns'; +import { KBN_FIELD_TYPES } from '../../../kbn_field_types/types'; +import { isNestedField, IndexPatternField } from '../../../index_patterns/fields'; const filterByType = propFilter('type'); diff --git a/src/plugins/data/public/search/aggs/param_types/index.ts b/src/plugins/data/common/search/aggs/param_types/index.ts similarity index 100% rename from src/plugins/data/public/search/aggs/param_types/index.ts rename to src/plugins/data/common/search/aggs/param_types/index.ts diff --git a/src/plugins/data/public/search/aggs/param_types/json.test.ts b/src/plugins/data/common/search/aggs/param_types/json.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/param_types/json.test.ts rename to src/plugins/data/common/search/aggs/param_types/json.test.ts diff --git a/src/plugins/data/public/search/aggs/param_types/json.ts b/src/plugins/data/common/search/aggs/param_types/json.ts similarity index 100% rename from src/plugins/data/public/search/aggs/param_types/json.ts rename to src/plugins/data/common/search/aggs/param_types/json.ts diff --git a/src/plugins/data/public/search/aggs/param_types/optioned.test.ts b/src/plugins/data/common/search/aggs/param_types/optioned.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/param_types/optioned.test.ts rename to src/plugins/data/common/search/aggs/param_types/optioned.test.ts diff --git a/src/plugins/data/public/search/aggs/param_types/optioned.ts b/src/plugins/data/common/search/aggs/param_types/optioned.ts similarity index 100% rename from src/plugins/data/public/search/aggs/param_types/optioned.ts rename to src/plugins/data/common/search/aggs/param_types/optioned.ts diff --git a/src/plugins/data/public/search/aggs/param_types/string.test.ts b/src/plugins/data/common/search/aggs/param_types/string.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/param_types/string.test.ts rename to src/plugins/data/common/search/aggs/param_types/string.test.ts diff --git a/src/plugins/data/public/search/aggs/param_types/string.ts b/src/plugins/data/common/search/aggs/param_types/string.ts similarity index 100% rename from src/plugins/data/public/search/aggs/param_types/string.ts rename to src/plugins/data/common/search/aggs/param_types/string.ts diff --git a/src/plugins/data/public/search/aggs/test_helpers/function_wrapper.ts b/src/plugins/data/common/search/aggs/test_helpers/function_wrapper.ts similarity index 100% rename from src/plugins/data/public/search/aggs/test_helpers/function_wrapper.ts rename to src/plugins/data/common/search/aggs/test_helpers/function_wrapper.ts diff --git a/src/plugins/data/public/search/aggs/test_helpers/index.ts b/src/plugins/data/common/search/aggs/test_helpers/index.ts similarity index 86% rename from src/plugins/data/public/search/aggs/test_helpers/index.ts rename to src/plugins/data/common/search/aggs/test_helpers/index.ts index d47317d8b4725..30f315f276741 100644 --- a/src/plugins/data/public/search/aggs/test_helpers/index.ts +++ b/src/plugins/data/common/search/aggs/test_helpers/index.ts @@ -17,5 +17,5 @@ * under the License. */ -export { functionWrapper } from './function_wrapper'; -export { mockAggTypesRegistry } from './mock_agg_types_registry'; +export * from './function_wrapper'; +export * from './mock_agg_types_registry'; diff --git a/src/plugins/data/public/search/aggs/test_helpers/mock_agg_types_registry.ts b/src/plugins/data/common/search/aggs/test_helpers/mock_agg_types_registry.ts similarity index 52% rename from src/plugins/data/public/search/aggs/test_helpers/mock_agg_types_registry.ts rename to src/plugins/data/common/search/aggs/test_helpers/mock_agg_types_registry.ts index 4a0820c349b5f..14631a9d53055 100644 --- a/src/plugins/data/public/search/aggs/test_helpers/mock_agg_types_registry.ts +++ b/src/plugins/data/common/search/aggs/test_helpers/mock_agg_types_registry.ts @@ -17,17 +17,14 @@ * under the License. */ -import { coreMock } from '../../../../../../../src/core/public/mocks'; +import { fieldFormatsMock } from '../../../field_formats/mocks'; + import { AggTypesRegistry, AggTypesRegistryStart } from '../agg_types_registry'; -import { getAggTypes } from '../agg_types'; -import { BucketAggType } from '../buckets/bucket_agg_type'; -import { MetricAggType } from '../metrics/metric_agg_type'; -import { fieldFormatsServiceMock } from '../../../field_formats/mocks'; -import { InternalStartServices } from '../../../types'; +import { AggTypesDependencies, getAggTypes } from '../agg_types'; import { TimeBucketsConfig } from '../buckets/lib/time_buckets/time_buckets'; // Mocked uiSettings shared among aggs unit tests -const mockUiSettings = jest.fn().mockImplementation((key: string) => { +const mockGetConfig = jest.fn().mockImplementation((key: string) => { const config: TimeBucketsConfig = { 'histogram:maxBars': 4, 'histogram:barTarget': 3, @@ -44,6 +41,23 @@ const mockUiSettings = jest.fn().mockImplementation((key: string) => { return config[key] ?? key; }); +/** @internal */ +export function mockGetFieldFormatsStart() { + const { deserialize, getDefaultInstance } = fieldFormatsMock; + return { + deserialize, + getDefaultInstance, + }; +} + +/** @internal */ +export const mockAggTypesDependencies: AggTypesDependencies = { + calculateBounds: jest.fn(), + getFieldFormatsStart: mockGetFieldFormatsStart, + getConfig: mockGetConfig, + isDefaultTimezone: () => true, +}; + /** * Testing utility which creates a new instance of AggTypesRegistry, * registers the provided agg types, and returns AggTypesRegistry.start() @@ -56,36 +70,37 @@ const mockUiSettings = jest.fn().mockImplementation((key: string) => { * * @internal */ -export function mockAggTypesRegistry | MetricAggType>( - types?: T[] -): AggTypesRegistryStart { +export function mockAggTypesRegistry(deps?: AggTypesDependencies): AggTypesRegistryStart { const registry = new AggTypesRegistry(); + const initializedAggTypes = new Map(); const registrySetup = registry.setup(); - if (types) { - types.forEach((type) => { - if (type instanceof BucketAggType) { - registrySetup.registerBucket(type); - } else if (type instanceof MetricAggType) { - registrySetup.registerMetric(type); - } - }); - } else { - const coreSetup = coreMock.createSetup(); - coreSetup.uiSettings.get = mockUiSettings; + const aggTypes = getAggTypes(); + + aggTypes.buckets.forEach(({ name, fn }) => registrySetup.registerBucket(name, fn)); + aggTypes.metrics.forEach(({ name, fn }) => registrySetup.registerMetric(name, fn)); - const aggTypes = getAggTypes({ - calculateBounds: jest.fn(), - getInternalStartServices: () => - (({ - fieldFormats: fieldFormatsServiceMock.createStartContract(), - } as unknown) as InternalStartServices), - uiSettings: coreSetup.uiSettings, - }); + const registryStart = registry.start(); - aggTypes.buckets.forEach((type) => registrySetup.registerBucket(type)); - aggTypes.metrics.forEach((type) => registrySetup.registerMetric(type)); - } + // initialize each agg type and store in memory + registryStart.getAll().buckets.forEach((type) => { + const agg = type(deps ?? mockAggTypesDependencies); + initializedAggTypes.set(agg.name, agg); + }); + registryStart.getAll().metrics.forEach((type) => { + const agg = type(deps ?? mockAggTypesDependencies); + initializedAggTypes.set(agg.name, agg); + }); - return registry.start(); + return { + get: (name: string) => { + return initializedAggTypes.get(name); + }, + getAll: () => { + return { + buckets: Array.from(initializedAggTypes.values()).filter((agg) => agg.type === 'buckets'), + metrics: Array.from(initializedAggTypes.values()).filter((agg) => agg.type === 'metrics'), + }; + }, + }; } diff --git a/src/plugins/data/common/search/aggs/types.ts b/src/plugins/data/common/search/aggs/types.ts new file mode 100644 index 0000000000000..dabd653463d4f --- /dev/null +++ b/src/plugins/data/common/search/aggs/types.ts @@ -0,0 +1,157 @@ +/* + * 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 { Assign } from '@kbn/utility-types'; +import { IndexPattern } from '../../index_patterns/index_patterns/index_pattern'; +import { + AggConfigSerialized, + AggConfigs, + AggParamsRange, + AggParamsIpRange, + AggParamsDateRange, + AggParamsFilter, + AggParamsFilters, + AggParamsSignificantTerms, + AggParamsGeoTile, + AggParamsGeoHash, + AggParamsTerms, + AggParamsAvg, + AggParamsCardinality, + AggParamsGeoBounds, + AggParamsGeoCentroid, + AggParamsMax, + AggParamsMedian, + AggParamsMin, + AggParamsStdDeviation, + AggParamsSum, + AggParamsBucketAvg, + AggParamsBucketMax, + AggParamsBucketMin, + AggParamsBucketSum, + AggParamsCumulativeSum, + AggParamsDerivative, + AggParamsMovingAvg, + AggParamsPercentileRanks, + AggParamsPercentiles, + AggParamsSerialDiff, + AggParamsTopHit, + AggParamsHistogram, + AggParamsDateHistogram, + AggTypesRegistry, + AggTypesRegistrySetup, + AggTypesRegistryStart, + CreateAggConfigParams, + getCalculateAutoTimeExpression, + METRIC_TYPES, + BUCKET_TYPES, +} from './'; + +export { IAggConfig, AggConfigSerialized } from './agg_config'; +export { CreateAggConfigParams, IAggConfigs } from './agg_configs'; +export { IAggType } from './agg_type'; +export { AggParam, AggParamOption } from './agg_params'; +export { IFieldParamType } from './param_types'; +export { IMetricAggType } from './metrics/metric_agg_type'; +export { DateRangeKey } from './buckets/lib/date_range'; +export { IpRangeKey } from './buckets/lib/ip_range'; +export { OptionedValueProp } from './param_types/optioned'; + +/** @internal */ +export interface AggsCommonSetup { + types: AggTypesRegistrySetup; +} + +/** @internal */ +export interface AggsCommonStart { + calculateAutoTimeExpression: ReturnType; + createAggConfigs: ( + indexPattern: IndexPattern, + configStates?: CreateAggConfigParams[], + schemas?: Record + ) => InstanceType; + types: ReturnType; +} + +/** + * AggsStart represents the actual external contract as AggsCommonStart + * is only used internally. The difference is that AggsStart includes the + * typings for the registry with initialized agg types. + * + * @internal + */ +export type AggsStart = Assign; + +/** @internal */ +export interface BaseAggParams { + json?: string; + customLabel?: string; +} + +/** @internal */ +export interface AggExpressionType { + type: 'agg_type'; + value: AggConfigSerialized; +} + +/** @internal */ +export type AggExpressionFunctionArgs< + Name extends keyof AggParamsMapping +> = AggParamsMapping[Name] & Pick; + +/** + * A global list of the param interfaces for each agg type. + * For now this is internal, but eventually we will probably + * want to make it public. + * + * @internal + */ +export interface AggParamsMapping { + [BUCKET_TYPES.RANGE]: AggParamsRange; + [BUCKET_TYPES.IP_RANGE]: AggParamsIpRange; + [BUCKET_TYPES.DATE_RANGE]: AggParamsDateRange; + [BUCKET_TYPES.FILTER]: AggParamsFilter; + [BUCKET_TYPES.FILTERS]: AggParamsFilters; + [BUCKET_TYPES.SIGNIFICANT_TERMS]: AggParamsSignificantTerms; + [BUCKET_TYPES.GEOTILE_GRID]: AggParamsGeoTile; + [BUCKET_TYPES.GEOHASH_GRID]: AggParamsGeoHash; + [BUCKET_TYPES.HISTOGRAM]: AggParamsHistogram; + [BUCKET_TYPES.DATE_HISTOGRAM]: AggParamsDateHistogram; + [BUCKET_TYPES.TERMS]: AggParamsTerms; + [METRIC_TYPES.AVG]: AggParamsAvg; + [METRIC_TYPES.CARDINALITY]: AggParamsCardinality; + [METRIC_TYPES.COUNT]: BaseAggParams; + [METRIC_TYPES.GEO_BOUNDS]: AggParamsGeoBounds; + [METRIC_TYPES.GEO_CENTROID]: AggParamsGeoCentroid; + [METRIC_TYPES.MAX]: AggParamsMax; + [METRIC_TYPES.MEDIAN]: AggParamsMedian; + [METRIC_TYPES.MIN]: AggParamsMin; + [METRIC_TYPES.STD_DEV]: AggParamsStdDeviation; + [METRIC_TYPES.SUM]: AggParamsSum; + [METRIC_TYPES.AVG_BUCKET]: AggParamsBucketAvg; + [METRIC_TYPES.MAX_BUCKET]: AggParamsBucketMax; + [METRIC_TYPES.MIN_BUCKET]: AggParamsBucketMin; + [METRIC_TYPES.SUM_BUCKET]: AggParamsBucketSum; + [METRIC_TYPES.CUMULATIVE_SUM]: AggParamsCumulativeSum; + [METRIC_TYPES.DERIVATIVE]: AggParamsDerivative; + [METRIC_TYPES.MOVING_FN]: AggParamsMovingAvg; + [METRIC_TYPES.PERCENTILE_RANKS]: AggParamsPercentileRanks; + [METRIC_TYPES.PERCENTILES]: AggParamsPercentiles; + [METRIC_TYPES.SERIAL_DIFF]: AggParamsSerialDiff; + [METRIC_TYPES.TOP_HITS]: AggParamsTopHit; +} diff --git a/src/plugins/data/public/search/aggs/utils/calculate_auto_time_expression.ts b/src/plugins/data/common/search/aggs/utils/calculate_auto_time_expression.ts similarity index 71% rename from src/plugins/data/public/search/aggs/utils/calculate_auto_time_expression.ts rename to src/plugins/data/common/search/aggs/utils/calculate_auto_time_expression.ts index 30fcdd9d83a38..622e8101f34ab 100644 --- a/src/plugins/data/public/search/aggs/utils/calculate_auto_time_expression.ts +++ b/src/plugins/data/common/search/aggs/utils/calculate_auto_time_expression.ts @@ -17,11 +17,12 @@ * under the License. */ import moment from 'moment'; -import { IUiSettingsClient } from 'src/core/public'; +import { UI_SETTINGS } from '../../../../common/constants'; +import { TimeRange } from '../../../../common/query'; import { TimeBuckets } from '../buckets/lib/time_buckets'; -import { toAbsoluteDates, TimeRange, UI_SETTINGS } from '../../../../common'; +import { toAbsoluteDates } from './date_interval_utils'; -export function getCalculateAutoTimeExpression(uiSettings: IUiSettingsClient) { +export function getCalculateAutoTimeExpression(getConfig: (key: string) => any) { return function calculateAutoTimeExpression(range: TimeRange) { const dates = toAbsoluteDates(range); if (!dates) { @@ -29,10 +30,10 @@ export function getCalculateAutoTimeExpression(uiSettings: IUiSettingsClient) { } const buckets = new TimeBuckets({ - 'histogram:maxBars': uiSettings.get(UI_SETTINGS.HISTOGRAM_MAX_BARS), - 'histogram:barTarget': uiSettings.get(UI_SETTINGS.HISTOGRAM_BAR_TARGET), - dateFormat: uiSettings.get('dateFormat'), - 'dateFormat:scaled': uiSettings.get('dateFormat:scaled'), + 'histogram:maxBars': getConfig(UI_SETTINGS.HISTOGRAM_MAX_BARS), + 'histogram:barTarget': getConfig(UI_SETTINGS.HISTOGRAM_BAR_TARGET), + dateFormat: getConfig('dateFormat'), + 'dateFormat:scaled': getConfig('dateFormat:scaled'), }); buckets.setInterval('auto'); diff --git a/src/plugins/data/common/search/aggs/date_interval_utils/date_histogram_interval.test.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/date_histogram_interval.test.ts similarity index 100% rename from src/plugins/data/common/search/aggs/date_interval_utils/date_histogram_interval.test.ts rename to src/plugins/data/common/search/aggs/utils/date_interval_utils/date_histogram_interval.test.ts diff --git a/src/plugins/data/common/search/aggs/date_interval_utils/date_histogram_interval.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/date_histogram_interval.ts similarity index 100% rename from src/plugins/data/common/search/aggs/date_interval_utils/date_histogram_interval.ts rename to src/plugins/data/common/search/aggs/utils/date_interval_utils/date_histogram_interval.ts diff --git a/src/plugins/data/common/search/aggs/date_interval_utils/index.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/index.ts similarity index 100% rename from src/plugins/data/common/search/aggs/date_interval_utils/index.ts rename to src/plugins/data/common/search/aggs/utils/date_interval_utils/index.ts diff --git a/src/plugins/data/common/search/aggs/date_interval_utils/invalid_es_calendar_interval_error.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/invalid_es_calendar_interval_error.ts similarity index 100% rename from src/plugins/data/common/search/aggs/date_interval_utils/invalid_es_calendar_interval_error.ts rename to src/plugins/data/common/search/aggs/utils/date_interval_utils/invalid_es_calendar_interval_error.ts diff --git a/src/plugins/data/common/search/aggs/date_interval_utils/invalid_es_interval_format_error.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/invalid_es_interval_format_error.ts similarity index 100% rename from src/plugins/data/common/search/aggs/date_interval_utils/invalid_es_interval_format_error.ts rename to src/plugins/data/common/search/aggs/utils/date_interval_utils/invalid_es_interval_format_error.ts diff --git a/src/plugins/data/common/search/aggs/date_interval_utils/is_valid_es_interval.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/is_valid_es_interval.ts similarity index 100% rename from src/plugins/data/common/search/aggs/date_interval_utils/is_valid_es_interval.ts rename to src/plugins/data/common/search/aggs/utils/date_interval_utils/is_valid_es_interval.ts diff --git a/src/plugins/data/common/search/aggs/date_interval_utils/is_valid_interval.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/is_valid_interval.ts similarity index 100% rename from src/plugins/data/common/search/aggs/date_interval_utils/is_valid_interval.ts rename to src/plugins/data/common/search/aggs/utils/date_interval_utils/is_valid_interval.ts diff --git a/src/plugins/data/common/search/aggs/date_interval_utils/least_common_interval.test.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/least_common_interval.test.ts similarity index 100% rename from src/plugins/data/common/search/aggs/date_interval_utils/least_common_interval.test.ts rename to src/plugins/data/common/search/aggs/utils/date_interval_utils/least_common_interval.test.ts diff --git a/src/plugins/data/common/search/aggs/date_interval_utils/least_common_interval.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/least_common_interval.ts similarity index 100% rename from src/plugins/data/common/search/aggs/date_interval_utils/least_common_interval.ts rename to src/plugins/data/common/search/aggs/utils/date_interval_utils/least_common_interval.ts diff --git a/src/plugins/data/common/search/aggs/date_interval_utils/least_common_multiple.test.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/least_common_multiple.test.ts similarity index 100% rename from src/plugins/data/common/search/aggs/date_interval_utils/least_common_multiple.test.ts rename to src/plugins/data/common/search/aggs/utils/date_interval_utils/least_common_multiple.test.ts diff --git a/src/plugins/data/common/search/aggs/date_interval_utils/least_common_multiple.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/least_common_multiple.ts similarity index 100% rename from src/plugins/data/common/search/aggs/date_interval_utils/least_common_multiple.ts rename to src/plugins/data/common/search/aggs/utils/date_interval_utils/least_common_multiple.ts diff --git a/src/plugins/data/common/search/aggs/date_interval_utils/parse_es_interval.test.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_es_interval.test.ts similarity index 100% rename from src/plugins/data/common/search/aggs/date_interval_utils/parse_es_interval.test.ts rename to src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_es_interval.test.ts diff --git a/src/plugins/data/common/search/aggs/date_interval_utils/parse_es_interval.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_es_interval.ts similarity index 100% rename from src/plugins/data/common/search/aggs/date_interval_utils/parse_es_interval.ts rename to src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_es_interval.ts diff --git a/src/plugins/data/common/search/aggs/date_interval_utils/parse_interval.test.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_interval.test.ts similarity index 100% rename from src/plugins/data/common/search/aggs/date_interval_utils/parse_interval.test.ts rename to src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_interval.test.ts diff --git a/src/plugins/data/common/search/aggs/date_interval_utils/parse_interval.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_interval.ts similarity index 100% rename from src/plugins/data/common/search/aggs/date_interval_utils/parse_interval.ts rename to src/plugins/data/common/search/aggs/utils/date_interval_utils/parse_interval.ts diff --git a/src/plugins/data/common/search/aggs/date_interval_utils/to_absolute_dates.ts b/src/plugins/data/common/search/aggs/utils/date_interval_utils/to_absolute_dates.ts similarity index 95% rename from src/plugins/data/common/search/aggs/date_interval_utils/to_absolute_dates.ts rename to src/plugins/data/common/search/aggs/utils/date_interval_utils/to_absolute_dates.ts index 98d752a72e28a..99809e06df38f 100644 --- a/src/plugins/data/common/search/aggs/date_interval_utils/to_absolute_dates.ts +++ b/src/plugins/data/common/search/aggs/utils/date_interval_utils/to_absolute_dates.ts @@ -18,7 +18,7 @@ */ import dateMath from '@elastic/datemath'; -import { TimeRange } from '../../../../common'; +import { TimeRange } from '../../../../../common'; export function toAbsoluteDates(range: TimeRange) { const fromDate = dateMath.parse(range.from); diff --git a/src/plugins/data/public/search/aggs/utils/get_format_with_aggs.test.ts b/src/plugins/data/common/search/aggs/utils/get_format_with_aggs.test.ts similarity index 95% rename from src/plugins/data/public/search/aggs/utils/get_format_with_aggs.test.ts rename to src/plugins/data/common/search/aggs/utils/get_format_with_aggs.test.ts index 3b440bc50c93b..20d8cfc105e49 100644 --- a/src/plugins/data/public/search/aggs/utils/get_format_with_aggs.test.ts +++ b/src/plugins/data/common/search/aggs/utils/get_format_with_aggs.test.ts @@ -19,9 +19,8 @@ import { identity } from 'lodash'; -import { SerializedFieldFormat } from '../../../../../expressions/common/types'; -import { FieldFormat } from '../../../../common'; -import { IFieldFormat } from '../../../../public'; +import { SerializedFieldFormat } from 'src/plugins/expressions/common/types'; +import { FieldFormat, IFieldFormat } from '../../../../common'; import { getFormatWithAggs } from './get_format_with_aggs'; diff --git a/src/plugins/data/public/search/aggs/utils/get_format_with_aggs.ts b/src/plugins/data/common/search/aggs/utils/get_format_with_aggs.ts similarity index 95% rename from src/plugins/data/public/search/aggs/utils/get_format_with_aggs.ts rename to src/plugins/data/common/search/aggs/utils/get_format_with_aggs.ts index e0db249c7cf86..01369206ab3cf 100644 --- a/src/plugins/data/public/search/aggs/utils/get_format_with_aggs.ts +++ b/src/plugins/data/common/search/aggs/utils/get_format_with_aggs.ts @@ -19,9 +19,12 @@ import { i18n } from '@kbn/i18n'; -import { SerializedFieldFormat } from '../../../../../expressions/common/types'; -import { FieldFormat } from '../../../../common'; -import { FieldFormatsContentType, IFieldFormat } from '../../../../public'; +import { SerializedFieldFormat } from 'src/plugins/expressions/common/types'; +import { + FieldFormat, + FieldFormatsContentType, + IFieldFormat, +} from '../../../../common/field_formats'; import { convertDateRangeToString, DateRangeKey } from '../buckets/lib/date_range'; import { convertIPRangeToString, IpRangeKey } from '../buckets/lib/ip_range'; diff --git a/src/plugins/data/public/search/aggs/utils/get_parsed_value.ts b/src/plugins/data/common/search/aggs/utils/get_parsed_value.ts similarity index 100% rename from src/plugins/data/public/search/aggs/utils/get_parsed_value.ts rename to src/plugins/data/common/search/aggs/utils/get_parsed_value.ts diff --git a/src/plugins/data/public/search/aggs/utils/index.ts b/src/plugins/data/common/search/aggs/utils/index.ts similarity index 93% rename from src/plugins/data/public/search/aggs/utils/index.ts rename to src/plugins/data/common/search/aggs/utils/index.ts index 5a889ee9ead9d..99ce44207d80d 100644 --- a/src/plugins/data/public/search/aggs/utils/index.ts +++ b/src/plugins/data/common/search/aggs/utils/index.ts @@ -18,6 +18,8 @@ */ export * from './calculate_auto_time_expression'; +export * from './date_interval_utils'; export * from './get_format_with_aggs'; +export * from './ipv4_address'; export * from './prop_filter'; export * from './to_angular_json'; diff --git a/src/plugins/data/common/search/aggs/ipv4_address.test.ts b/src/plugins/data/common/search/aggs/utils/ipv4_address.test.ts similarity index 100% rename from src/plugins/data/common/search/aggs/ipv4_address.test.ts rename to src/plugins/data/common/search/aggs/utils/ipv4_address.test.ts diff --git a/src/plugins/data/common/search/aggs/ipv4_address.ts b/src/plugins/data/common/search/aggs/utils/ipv4_address.ts similarity index 100% rename from src/plugins/data/common/search/aggs/ipv4_address.ts rename to src/plugins/data/common/search/aggs/utils/ipv4_address.ts diff --git a/src/plugins/data/public/search/aggs/utils/prop_filter.test.ts b/src/plugins/data/common/search/aggs/utils/prop_filter.test.ts similarity index 100% rename from src/plugins/data/public/search/aggs/utils/prop_filter.test.ts rename to src/plugins/data/common/search/aggs/utils/prop_filter.test.ts diff --git a/src/plugins/data/public/search/aggs/utils/prop_filter.ts b/src/plugins/data/common/search/aggs/utils/prop_filter.ts similarity index 100% rename from src/plugins/data/public/search/aggs/utils/prop_filter.ts rename to src/plugins/data/common/search/aggs/utils/prop_filter.ts diff --git a/src/plugins/data/public/search/aggs/utils/to_angular_json.ts b/src/plugins/data/common/search/aggs/utils/to_angular_json.ts similarity index 100% rename from src/plugins/data/public/search/aggs/utils/to_angular_json.ts rename to src/plugins/data/common/search/aggs/utils/to_angular_json.ts diff --git a/src/plugins/data/common/search/expressions/index.ts b/src/plugins/data/common/search/expressions/index.ts index f1a39a8383629..25839a805d8c5 100644 --- a/src/plugins/data/common/search/expressions/index.ts +++ b/src/plugins/data/common/search/expressions/index.ts @@ -18,3 +18,4 @@ */ export * from './esaggs'; +export * from './utils'; diff --git a/src/plugins/data/public/search/expressions/utils/courier_inspector_stats.ts b/src/plugins/data/common/search/expressions/utils/courier_inspector_stats.ts similarity index 98% rename from src/plugins/data/public/search/expressions/utils/courier_inspector_stats.ts rename to src/plugins/data/common/search/expressions/utils/courier_inspector_stats.ts index c933e8cd3e961..d41f02d2728d5 100644 --- a/src/plugins/data/public/search/expressions/utils/courier_inspector_stats.ts +++ b/src/plugins/data/common/search/expressions/utils/courier_inspector_stats.ts @@ -26,8 +26,8 @@ import { i18n } from '@kbn/i18n'; import { SearchResponse } from 'elasticsearch'; +import { ISearchSource } from 'src/plugins/data/public'; import { RequestStatistics } from 'src/plugins/inspector/common'; -import { ISearchSource } from '../../search_source'; /** @public */ export function getRequestInspectorStats(searchSource: ISearchSource) { diff --git a/src/plugins/data/common/search/expressions/utils/index.ts b/src/plugins/data/common/search/expressions/utils/index.ts new file mode 100644 index 0000000000000..75c1809770c78 --- /dev/null +++ b/src/plugins/data/common/search/expressions/utils/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 * from './courier_inspector_stats'; diff --git a/src/plugins/data/common/search/index.ts b/src/plugins/data/common/search/index.ts index 45daf16d10c6d..557ab64079d16 100644 --- a/src/plugins/data/common/search/index.ts +++ b/src/plugins/data/common/search/index.ts @@ -17,10 +17,13 @@ * under the License. */ -import { ES_SEARCH_STRATEGY } from './es_search'; - -export { IKibanaSearchResponse, IKibanaSearchRequest } from './types'; +export * from './aggs'; +export * from './es_search'; +export * from './expressions'; +export * from './tabify'; +export * from './types'; +import { ES_SEARCH_STRATEGY } from './es_search'; export const DEFAULT_SEARCH_STRATEGY = ES_SEARCH_STRATEGY; export { diff --git a/src/plugins/data/public/search/tabify/buckets.test.ts b/src/plugins/data/common/search/tabify/buckets.test.ts similarity index 100% rename from src/plugins/data/public/search/tabify/buckets.test.ts rename to src/plugins/data/common/search/tabify/buckets.test.ts diff --git a/src/plugins/data/public/search/tabify/buckets.ts b/src/plugins/data/common/search/tabify/buckets.ts similarity index 100% rename from src/plugins/data/public/search/tabify/buckets.ts rename to src/plugins/data/common/search/tabify/buckets.ts diff --git a/src/plugins/data/public/search/tabify/get_columns.test.ts b/src/plugins/data/common/search/tabify/get_columns.test.ts similarity index 100% rename from src/plugins/data/public/search/tabify/get_columns.test.ts rename to src/plugins/data/common/search/tabify/get_columns.test.ts diff --git a/src/plugins/data/public/search/tabify/get_columns.ts b/src/plugins/data/common/search/tabify/get_columns.ts similarity index 100% rename from src/plugins/data/public/search/tabify/get_columns.ts rename to src/plugins/data/common/search/tabify/get_columns.ts diff --git a/src/plugins/data/public/search/tabify/index.ts b/src/plugins/data/common/search/tabify/index.ts similarity index 100% rename from src/plugins/data/public/search/tabify/index.ts rename to src/plugins/data/common/search/tabify/index.ts diff --git a/src/plugins/data/public/search/tabify/response_writer.test.ts b/src/plugins/data/common/search/tabify/response_writer.test.ts similarity index 100% rename from src/plugins/data/public/search/tabify/response_writer.test.ts rename to src/plugins/data/common/search/tabify/response_writer.test.ts diff --git a/src/plugins/data/public/search/tabify/response_writer.ts b/src/plugins/data/common/search/tabify/response_writer.ts similarity index 100% rename from src/plugins/data/public/search/tabify/response_writer.ts rename to src/plugins/data/common/search/tabify/response_writer.ts diff --git a/src/plugins/data/public/search/tabify/tabify.test.ts b/src/plugins/data/common/search/tabify/tabify.test.ts similarity index 98% rename from src/plugins/data/public/search/tabify/tabify.test.ts rename to src/plugins/data/common/search/tabify/tabify.test.ts index 0a1e99c8bb200..6b9d520b11436 100644 --- a/src/plugins/data/public/search/tabify/tabify.test.ts +++ b/src/plugins/data/common/search/tabify/tabify.test.ts @@ -18,7 +18,7 @@ */ import { tabifyAggResponse } from './tabify'; -import { IndexPattern } from '../../index_patterns'; +import { IndexPattern } from '../../index_patterns/index_patterns/index_pattern'; import { AggConfigs, IAggConfig, IAggConfigs } from '../aggs'; import { mockAggTypesRegistry } from '../aggs/test_helpers'; import { metricOnly, threeTermBuckets } from 'fixtures/fake_hierarchical_data'; diff --git a/src/plugins/data/public/search/tabify/tabify.ts b/src/plugins/data/common/search/tabify/tabify.ts similarity index 100% rename from src/plugins/data/public/search/tabify/tabify.ts rename to src/plugins/data/common/search/tabify/tabify.ts diff --git a/src/plugins/data/public/search/tabify/types.ts b/src/plugins/data/common/search/tabify/types.ts similarity index 100% rename from src/plugins/data/public/search/tabify/types.ts rename to src/plugins/data/common/search/tabify/types.ts diff --git a/src/plugins/data/public/field_formats/utils/deserialize.ts b/src/plugins/data/public/field_formats/utils/deserialize.ts index 26baa5fdeb1e4..7595a443bf8f0 100644 --- a/src/plugins/data/public/field_formats/utils/deserialize.ts +++ b/src/plugins/data/public/field_formats/utils/deserialize.ts @@ -23,9 +23,9 @@ import { SerializedFieldFormat } from '../../../../expressions/common/types'; import { FieldFormat } from '../../../common'; import { FormatFactory } from '../../../common/field_formats/utils'; +import { getFormatWithAggs } from '../../../common/search/aggs'; import { DataPublicPluginStart, IFieldFormat } from '../../../public'; import { getUiSettings } from '../../../public/services'; -import { getFormatWithAggs } from '../../search/aggs/utils'; const getConfig = (key: string, defaultOverride?: any): any => getUiSettings().get(key, defaultOverride); diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index f036d5f30a0e2..d35069207ee84 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -294,15 +294,6 @@ import { propFilter, siblingPipelineType, termsAggFilter, - // expressions utils - getRequestInspectorStats, - getResponseInspectorStats, - // tabify - tabifyAggResponse, - tabifyGetColumns, -} from './search'; - -import { dateHistogramInterval, InvalidEsCalendarIntervalError, InvalidEsIntervalFormatError, @@ -312,10 +303,14 @@ import { parseEsInterval, parseInterval, toAbsoluteDates, + // expressions utils + getRequestInspectorStats, + getResponseInspectorStats, + // tabify + tabifyAggResponse, + tabifyGetColumns, } from '../common'; -export { EsaggsExpressionFunctionDefinition, ParsedInterval } from '../common'; - export { // aggs AggGroupLabels, @@ -326,6 +321,7 @@ export { AggParamType, AggConfigOptions, BUCKET_TYPES, + EsaggsExpressionFunctionDefinition, IAggConfig, IAggConfigs, IAggType, @@ -334,35 +330,39 @@ export { METRIC_TYPES, OptionedParamType, OptionedValueProp, + ParsedInterval, + // tabify + TabbedAggColumn, + TabbedAggRow, + TabbedTable, +} from '../common'; + +export { // search ES_SEARCH_STRATEGY, + EsQuerySortValue, + extractSearchSourceReferences, + FetchOptions, getEsPreference, - ISearch, - ISearchOptions, - ISearchGeneric, - IEsSearchResponse, + getSearchParamsFromRequest, IEsSearchRequest, - IKibanaSearchResponse, + IEsSearchResponse, IKibanaSearchRequest, - SearchRequest, - SearchResponse, - SearchError, + IKibanaSearchResponse, + injectSearchSourceReferences, + ISearch, + ISearchGeneric, + ISearchOptions, ISearchSource, parseSearchSourceJSON, - injectSearchSourceReferences, - getSearchParamsFromRequest, - extractSearchSourceReferences, - SearchSourceFields, - EsQuerySortValue, - SortDirection, - FetchOptions, - // tabify - TabbedAggColumn, - TabbedAggRow, - TabbedTable, + RequestTimeoutError, + SearchError, SearchInterceptor, SearchInterceptorDeps, - RequestTimeoutError, + SearchRequest, + SearchResponse, + SearchSourceFields, + SortDirection, } from './search'; // Search namespace diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts index 3fc1e6454829d..78e40cfedd906 100644 --- a/src/plugins/data/public/mocks.ts +++ b/src/plugins/data/public/mocks.ts @@ -79,7 +79,7 @@ const createStartContract = (): Start => { }; export { createSearchSourceMock } from './search/mocks'; -export { getCalculateAutoTimeExpression } from './search/aggs'; +export { getCalculateAutoTimeExpression } from '../common/search/aggs'; export const dataPluginMock = { createSetupContract, diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index e950434b287a7..e6a48794d8b0f 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -33,7 +33,6 @@ import { DataPublicPluginStart, DataSetupDependencies, DataStartDependencies, - InternalStartServices, DataPublicPluginEnhancements, } from './types'; import { AutocompleteService } from './autocomplete'; @@ -120,17 +119,6 @@ export class DataPublicPlugin ): DataPublicPluginSetup { const startServices = createStartServicesGetter(core.getStartServices); - const getInternalStartServices = (): InternalStartServices => { - const { core: coreStart, self } = startServices(); - return { - fieldFormats: self.fieldFormats, - notifications: coreStart.notifications, - uiSettings: coreStart.uiSettings, - searchService: self.search, - injectedMetadata: coreStart.injectedMetadata, - }; - }; - expressions.registerFunction(esaggs); expressions.registerFunction(indexPatternLoad); @@ -158,10 +146,9 @@ export class DataPublicPlugin ); const searchService = this.searchService.setup(core, { - expressions, usageCollection, - getInternalStartServices, packageInfo: this.packageInfo, + registerFunction: expressions.registerFunction, }); return { @@ -210,7 +197,7 @@ export class DataPublicPlugin }); setQueryService(query); - const search = this.searchService.start(core, { indexPatterns }); + const search = this.searchService.start(core, { fieldFormats, indexPatterns }); setSearchService(search); uiActions.addTriggerAction( @@ -247,5 +234,7 @@ export class DataPublicPlugin public stop() { this.autocomplete.clearProviders(); + this.queryService.stop(); + this.searchService.stop(); } } diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index a61334905e9f5..744376403e1a1 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -26,10 +26,12 @@ import { EuiGlobalToastListToast } from '@elastic/eui'; import { ExclusiveUnion } from '@elastic/eui'; import { ExpressionAstFunction } from 'src/plugins/expressions/common'; import { ExpressionsSetup } from 'src/plugins/expressions/public'; +import { FetchOptions as FetchOptions_2 } from 'src/plugins/data/public'; import { History } from 'history'; import { Href } from 'history'; import { IconType } from '@elastic/eui'; import { InjectedIntl } from '@kbn/i18n/react'; +import { ISearchSource as ISearchSource_2 } from 'src/plugins/data/public'; import { IStorageWrapper } from 'src/plugins/kibana_utils/public'; import { IUiSettingsClient } from 'src/core/public'; import { IUiSettingsClient as IUiSettingsClient_3 } from 'kibana/public'; @@ -153,12 +155,12 @@ export interface ApplyGlobalFilterActionContext { timeFieldName?: string; } -// Warning: (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "DateFormat" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "baseFormattersPublic" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const baseFormattersPublic: (import("../../common").FieldFormatInstanceType | typeof DateNanosFormat | typeof DateFormat)[]; +export const baseFormattersPublic: (import("../../common").FieldFormatInstanceType | typeof DateFormat | typeof DateNanosFormat)[]; // Warning: (ae-missing-release-tag) "BUCKET_TYPES" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1653,7 +1655,7 @@ export const search: { intervalOptions: ({ display: string; val: string; - enabled(agg: import("./search/aggs/buckets/bucket_agg_type").IBucketAggConfig): boolean | "" | undefined; + enabled(agg: import("../common").IBucketAggConfig): boolean | "" | undefined; } | { display: string; val: string; @@ -1662,9 +1664,9 @@ export const search: { InvalidEsIntervalFormatError: typeof InvalidEsIntervalFormatError; Ipv4Address: typeof Ipv4Address; isDateHistogramBucketAggConfig: typeof isDateHistogramBucketAggConfig; - isNumberType: (agg: import("./search").AggConfig) => boolean; - isStringType: (agg: import("./search").AggConfig) => boolean; - isType: (...types: string[]) => (agg: import("./search").AggConfig) => boolean; + isNumberType: (agg: import("../common").AggConfig) => boolean; + isStringType: (agg: import("../common").AggConfig) => boolean; + isType: (...types: string[]) => (agg: import("../common").AggConfig) => boolean; isValidEsInterval: typeof isValidEsInterval; isValidInterval: typeof isValidInterval; parentPipelineType: string; diff --git a/src/plugins/data/public/search/aggs/aggs_service.test.ts b/src/plugins/data/public/search/aggs/aggs_service.test.ts new file mode 100644 index 0000000000000..db25dfb300d11 --- /dev/null +++ b/src/plugins/data/public/search/aggs/aggs_service.test.ts @@ -0,0 +1,182 @@ +/* + * 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 { BehaviorSubject, Subscription } from 'rxjs'; + +import { coreMock } from '../../../../../core/public/mocks'; +import { expressionsPluginMock } from '../../../../../plugins/expressions/public/mocks'; +import { BucketAggType, getAggTypes, MetricAggType } from '../../../common'; +import { fieldFormatsServiceMock } from '../../field_formats/mocks'; + +import { + AggsService, + AggsSetupDependencies, + AggsStartDependencies, + createGetConfig, +} from './aggs_service'; + +const { uiSettings } = coreMock.createSetup(); + +describe('AggsService - public', () => { + let service: AggsService; + let setupDeps: AggsSetupDependencies; + let startDeps: AggsStartDependencies; + + beforeEach(() => { + service = new AggsService(); + setupDeps = { + registerFunction: expressionsPluginMock.createSetupContract().registerFunction, + uiSettings, + }; + startDeps = { + fieldFormats: fieldFormatsServiceMock.createStartContract(), + uiSettings, + }; + }); + + describe('setup()', () => { + test('exposes proper contract', () => { + const setup = service.setup(setupDeps); + expect(Object.keys(setup).length).toBe(1); + expect(setup).toHaveProperty('types'); + }); + + test('registers default agg types', () => { + service.setup(setupDeps); + const start = service.start(startDeps); + expect(start.types.getAll().buckets.length).toBe(11); + expect(start.types.getAll().metrics.length).toBe(21); + }); + + test('registers custom agg types', () => { + const setup = service.setup(setupDeps); + setup.types.registerBucket( + 'foo', + () => ({ name: 'foo', type: 'buckets' } as BucketAggType) + ); + setup.types.registerMetric( + 'bar', + () => ({ name: 'bar', type: 'metrics' } as MetricAggType) + ); + + const start = service.start(startDeps); + expect(start.types.getAll().buckets.length).toBe(12); + expect(start.types.getAll().buckets.some(({ name }) => name === 'foo')).toBe(true); + expect(start.types.getAll().metrics.length).toBe(22); + expect(start.types.getAll().metrics.some(({ name }) => name === 'bar')).toBe(true); + }); + }); + + describe('start()', () => { + test('exposes proper contract', () => { + const start = service.start(startDeps); + expect(Object.keys(start).length).toBe(3); + expect(start).toHaveProperty('calculateAutoTimeExpression'); + expect(start).toHaveProperty('createAggConfigs'); + expect(start).toHaveProperty('types'); + }); + + test('types registry returns initialized agg types', () => { + service.setup(setupDeps); + const start = service.start(startDeps); + + expect(start.types.get('terms').name).toBe('terms'); + }); + + test('registers default agg types', () => { + service.setup(setupDeps); + const start = service.start(startDeps); + + const aggTypes = getAggTypes(); + expect(start.types.getAll().buckets.length).toBe(aggTypes.buckets.length); + expect(start.types.getAll().metrics.length).toBe(aggTypes.metrics.length); + }); + + test('merges default agg types with types registered during setup', () => { + const setup = service.setup(setupDeps); + setup.types.registerBucket( + 'foo', + () => ({ name: 'foo', type: 'buckets' } as BucketAggType) + ); + setup.types.registerMetric( + 'bar', + () => ({ name: 'bar', type: 'metrics' } as MetricAggType) + ); + + const start = service.start(startDeps); + + const aggTypes = getAggTypes(); + expect(start.types.getAll().buckets.length).toBe(aggTypes.buckets.length + 1); + expect(start.types.getAll().buckets.some(({ name }) => name === 'foo')).toBe(true); + expect(start.types.getAll().metrics.length).toBe(aggTypes.metrics.length + 1); + expect(start.types.getAll().metrics.some(({ name }) => name === 'bar')).toBe(true); + }); + }); + + describe('createGetConfig()', () => { + let fooSubject$: BehaviorSubject; + let barSubject$: BehaviorSubject; + + beforeEach(() => { + jest.clearAllMocks(); + + fooSubject$ = new BehaviorSubject('fooVal'); + barSubject$ = new BehaviorSubject('barVal'); + + uiSettings.get$.mockImplementation((key: string) => { + const mockSettings: Record = { + foo: () => fooSubject$, + bar: () => barSubject$, + }; + return mockSettings[key] ? mockSettings[key]() : undefined; + }); + }); + + test('returns a function to get the value of the provided setting', () => { + const requiredSettings = ['foo', 'bar']; + const subscriptions: Subscription[] = []; + const getConfig = createGetConfig(uiSettings, requiredSettings, subscriptions); + + expect(getConfig('foo')).toBe('fooVal'); + expect(getConfig('bar')).toBe('barVal'); + }); + + test('does not return values for settings that are not explicitly declared', () => { + const requiredSettings = ['foo', 'bar']; + const subscriptions: Subscription[] = []; + const getConfig = createGetConfig(uiSettings, requiredSettings, subscriptions); + + expect(subscriptions.length).toBe(2); + expect(getConfig('baz')).toBe(undefined); + }); + + test('provides latest value for each setting', () => { + const requiredSettings = ['foo', 'bar']; + const subscriptions: Subscription[] = []; + const getConfig = createGetConfig(uiSettings, requiredSettings, subscriptions); + + expect(getConfig('foo')).toBe('fooVal'); + fooSubject$.next('fooVal2'); + expect(getConfig('foo')).toBe('fooVal2'); + expect(getConfig('foo')).toBe('fooVal2'); + fooSubject$.next('fooVal3'); + expect(getConfig('foo')).toBe('fooVal3'); + }); + }); +}); diff --git a/src/plugins/data/public/search/aggs/aggs_service.ts b/src/plugins/data/public/search/aggs/aggs_service.ts new file mode 100644 index 0000000000000..d535f97fefdf8 --- /dev/null +++ b/src/plugins/data/public/search/aggs/aggs_service.ts @@ -0,0 +1,152 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Subscription } from 'rxjs'; + +import { IUiSettingsClient } from 'src/core/public'; +import { ExpressionsServiceSetup } from 'src/plugins/expressions/common'; +import { + aggsRequiredUiSettings, + AggsCommonStartDependencies, + AggsCommonService, + AggConfigs, + AggTypesDependencies, + calculateBounds, + TimeRange, +} from '../../../common'; +import { FieldFormatsStart } from '../../field_formats'; +import { getForceNow } from '../../query/timefilter/lib/get_force_now'; +import { AggsSetup, AggsStart } from './types'; + +/** + * Aggs needs synchronous access to specific uiSettings. Since settings can change + * without a page refresh, we create a cache that subscribes to changes from + * uiSettings.get$ and keeps everything up-to-date. + * + * @internal + */ +export function createGetConfig( + uiSettings: IUiSettingsClient, + requiredSettings: string[], + subscriptions: Subscription[] +): AggsCommonStartDependencies['getConfig'] { + const settingsCache: Record = {}; + + requiredSettings.forEach((setting) => { + subscriptions.push( + uiSettings.get$(setting).subscribe((value) => { + settingsCache[setting] = value; + }) + ); + }); + + return (key) => settingsCache[key]; +} + +/** @internal */ +export interface AggsSetupDependencies { + registerFunction: ExpressionsServiceSetup['registerFunction']; + uiSettings: IUiSettingsClient; +} + +/** @internal */ +export interface AggsStartDependencies { + fieldFormats: FieldFormatsStart; + uiSettings: IUiSettingsClient; +} + +/** + * The aggs service provides a means of modeling and manipulating the various + * Elasticsearch aggregations supported by Kibana, providing the ability to + * output the correct DSL when you are ready to send your request to ES. + */ +export class AggsService { + private readonly aggsCommonService = new AggsCommonService(); + private readonly initializedAggTypes = new Map(); + private getConfig?: AggsCommonStartDependencies['getConfig']; + private subscriptions: Subscription[] = []; + + /** + * getForceNow uses window.location, so we must have a separate implementation + * of calculateBounds on the client and the server. + */ + private calculateBounds = (timeRange: TimeRange) => + calculateBounds(timeRange, { forceNow: getForceNow() }); + + public setup({ registerFunction, uiSettings }: AggsSetupDependencies): AggsSetup { + this.getConfig = createGetConfig(uiSettings, aggsRequiredUiSettings, this.subscriptions); + + return this.aggsCommonService.setup({ registerFunction }); + } + + public start({ fieldFormats, uiSettings }: AggsStartDependencies): AggsStart { + const { calculateAutoTimeExpression, types } = this.aggsCommonService.start({ + getConfig: this.getConfig!, + }); + + const aggTypesDependencies: AggTypesDependencies = { + calculateBounds: this.calculateBounds, + getConfig: this.getConfig!, + getFieldFormatsStart: () => ({ + deserialize: fieldFormats.deserialize, + getDefaultInstance: fieldFormats.getDefaultInstance, + }), + isDefaultTimezone: () => uiSettings.isDefault('dateFormat:tz'), + }; + + // initialize each agg type and store in memory + types.getAll().buckets.forEach((type) => { + const agg = type(aggTypesDependencies); + this.initializedAggTypes.set(agg.name, agg); + }); + types.getAll().metrics.forEach((type) => { + const agg = type(aggTypesDependencies); + this.initializedAggTypes.set(agg.name, agg); + }); + + const typesRegistry = { + get: (name: string) => { + return this.initializedAggTypes.get(name); + }, + getAll: () => { + return { + buckets: Array.from(this.initializedAggTypes.values()).filter( + (agg) => agg.type === 'buckets' + ), + metrics: Array.from(this.initializedAggTypes.values()).filter( + (agg) => agg.type === 'metrics' + ), + }; + }, + }; + + return { + calculateAutoTimeExpression, + createAggConfigs: (indexPattern, configStates = [], schemas) => { + return new AggConfigs(indexPattern, configStates, { typesRegistry }); + }, + types: typesRegistry, + }; + } + + public stop() { + this.subscriptions.forEach((s) => s.unsubscribe()); + this.subscriptions = []; + } +} diff --git a/src/plugins/data/public/search/aggs/index.ts b/src/plugins/data/public/search/aggs/index.ts index 1139d9c7ff722..77d97c426260c 100644 --- a/src/plugins/data/public/search/aggs/index.ts +++ b/src/plugins/data/public/search/aggs/index.ts @@ -17,14 +17,5 @@ * under the License. */ -export * from './agg_config'; -export * from './agg_configs'; -export * from './agg_groups'; -export * from './agg_type'; -export * from './agg_types'; -export * from './agg_types_registry'; -export * from './buckets'; -export * from './metrics'; -export * from './param_types'; +export * from './aggs_service'; export * from './types'; -export * from './utils'; diff --git a/src/plugins/data/public/search/aggs/mocks.ts b/src/plugins/data/public/search/aggs/mocks.ts index 2cad646067292..ca13343777e63 100644 --- a/src/plugins/data/public/search/aggs/mocks.ts +++ b/src/plugins/data/public/search/aggs/mocks.ts @@ -17,15 +17,17 @@ * under the License. */ -import { coreMock } from '../../../../../../src/core/public/mocks'; import { AggConfigs, AggTypesRegistrySetup, AggTypesRegistryStart, getCalculateAutoTimeExpression, -} from './'; -import { SearchAggsSetup, SearchAggsStart } from './types'; -import { mockAggTypesRegistry } from './test_helpers'; +} from '../../../common'; +import { AggsSetup, AggsStart } from './types'; + +import { mockAggTypesRegistry } from '../../../common/search/aggs/test_helpers'; + +const getConfig = jest.fn(); const aggTypeBaseParamMock = () => ({ name: 'some_param', @@ -53,21 +55,18 @@ export const aggTypesRegistrySetupMock = (): AggTypesRegistrySetup => ({ export const aggTypesRegistryStartMock = (): AggTypesRegistryStart => ({ get: jest.fn().mockImplementation(aggTypeConfigMock), - getBuckets: jest.fn().mockImplementation(() => [aggTypeConfigMock()]), - getMetrics: jest.fn().mockImplementation(() => [aggTypeConfigMock()]), getAll: jest.fn().mockImplementation(() => ({ buckets: [aggTypeConfigMock()], metrics: [aggTypeConfigMock()], })), }); -export const searchAggsSetupMock = (): SearchAggsSetup => ({ - calculateAutoTimeExpression: getCalculateAutoTimeExpression(coreMock.createSetup().uiSettings), +export const searchAggsSetupMock = (): AggsSetup => ({ types: aggTypesRegistrySetupMock(), }); -export const searchAggsStartMock = (): SearchAggsStart => ({ - calculateAutoTimeExpression: getCalculateAutoTimeExpression(coreMock.createStart().uiSettings), +export const searchAggsStartMock = (): AggsStart => ({ + calculateAutoTimeExpression: getCalculateAutoTimeExpression(getConfig), createAggConfigs: jest.fn().mockImplementation((indexPattern, configStates = [], schemas) => { return new AggConfigs(indexPattern, configStates, { typesRegistry: mockAggTypesRegistry(), diff --git a/src/plugins/data/public/search/aggs/types.ts b/src/plugins/data/public/search/aggs/types.ts index a784bfaada4c7..38be541973ce9 100644 --- a/src/plugins/data/public/search/aggs/types.ts +++ b/src/plugins/data/public/search/aggs/types.ts @@ -17,131 +17,7 @@ * under the License. */ -import { IndexPattern } from '../../index_patterns'; -import { - AggConfigSerialized, - AggConfigs, - AggParamsRange, - AggParamsIpRange, - AggParamsDateRange, - AggParamsFilter, - AggParamsFilters, - AggParamsSignificantTerms, - AggParamsGeoTile, - AggParamsGeoHash, - AggParamsTerms, - AggParamsAvg, - AggParamsCardinality, - AggParamsGeoBounds, - AggParamsGeoCentroid, - AggParamsMax, - AggParamsMedian, - AggParamsMin, - AggParamsStdDeviation, - AggParamsSum, - AggParamsBucketAvg, - AggParamsBucketMax, - AggParamsBucketMin, - AggParamsBucketSum, - AggParamsCumulativeSum, - AggParamsDerivative, - AggParamsMovingAvg, - AggParamsPercentileRanks, - AggParamsPercentiles, - AggParamsSerialDiff, - AggParamsTopHit, - AggParamsHistogram, - AggParamsDateHistogram, - AggTypesRegistrySetup, - AggTypesRegistryStart, - CreateAggConfigParams, - getCalculateAutoTimeExpression, - METRIC_TYPES, - BUCKET_TYPES, -} from './'; +import { AggsCommonSetup } from '../../../common'; -export { IAggConfig, AggConfigSerialized } from './agg_config'; -export { CreateAggConfigParams, IAggConfigs } from './agg_configs'; -export { IAggType } from './agg_type'; -export { AggParam, AggParamOption } from './agg_params'; -export { IFieldParamType } from './param_types'; -export { IMetricAggType } from './metrics/metric_agg_type'; -export { DateRangeKey } from './buckets/lib/date_range'; -export { IpRangeKey } from './buckets/lib/ip_range'; -export { OptionedValueProp } from './param_types/optioned'; - -/** @internal */ -export interface SearchAggsSetup { - calculateAutoTimeExpression: ReturnType; - types: AggTypesRegistrySetup; -} - -/** @internal */ -export interface SearchAggsStart { - calculateAutoTimeExpression: ReturnType; - createAggConfigs: ( - indexPattern: IndexPattern, - configStates?: CreateAggConfigParams[], - schemas?: Record - ) => InstanceType; - types: AggTypesRegistryStart; -} - -/** @internal */ -export interface BaseAggParams { - json?: string; - customLabel?: string; -} - -/** @internal */ -export interface AggExpressionType { - type: 'agg_type'; - value: AggConfigSerialized; -} - -/** @internal */ -export type AggExpressionFunctionArgs< - Name extends keyof AggParamsMapping -> = AggParamsMapping[Name] & Pick; - -/** - * A global list of the param interfaces for each agg type. - * For now this is internal, but eventually we will probably - * want to make it public. - * - * @internal - */ -export interface AggParamsMapping { - [BUCKET_TYPES.RANGE]: AggParamsRange; - [BUCKET_TYPES.IP_RANGE]: AggParamsIpRange; - [BUCKET_TYPES.DATE_RANGE]: AggParamsDateRange; - [BUCKET_TYPES.FILTER]: AggParamsFilter; - [BUCKET_TYPES.FILTERS]: AggParamsFilters; - [BUCKET_TYPES.SIGNIFICANT_TERMS]: AggParamsSignificantTerms; - [BUCKET_TYPES.GEOTILE_GRID]: AggParamsGeoTile; - [BUCKET_TYPES.GEOHASH_GRID]: AggParamsGeoHash; - [BUCKET_TYPES.HISTOGRAM]: AggParamsHistogram; - [BUCKET_TYPES.DATE_HISTOGRAM]: AggParamsDateHistogram; - [BUCKET_TYPES.TERMS]: AggParamsTerms; - [METRIC_TYPES.AVG]: AggParamsAvg; - [METRIC_TYPES.CARDINALITY]: AggParamsCardinality; - [METRIC_TYPES.COUNT]: BaseAggParams; - [METRIC_TYPES.GEO_BOUNDS]: AggParamsGeoBounds; - [METRIC_TYPES.GEO_CENTROID]: AggParamsGeoCentroid; - [METRIC_TYPES.MAX]: AggParamsMax; - [METRIC_TYPES.MEDIAN]: AggParamsMedian; - [METRIC_TYPES.MIN]: AggParamsMin; - [METRIC_TYPES.STD_DEV]: AggParamsStdDeviation; - [METRIC_TYPES.SUM]: AggParamsSum; - [METRIC_TYPES.AVG_BUCKET]: AggParamsBucketAvg; - [METRIC_TYPES.MAX_BUCKET]: AggParamsBucketMax; - [METRIC_TYPES.MIN_BUCKET]: AggParamsBucketMin; - [METRIC_TYPES.SUM_BUCKET]: AggParamsBucketSum; - [METRIC_TYPES.CUMULATIVE_SUM]: AggParamsCumulativeSum; - [METRIC_TYPES.DERIVATIVE]: AggParamsDerivative; - [METRIC_TYPES.MOVING_FN]: AggParamsMovingAvg; - [METRIC_TYPES.PERCENTILE_RANKS]: AggParamsPercentileRanks; - [METRIC_TYPES.PERCENTILES]: AggParamsPercentiles; - [METRIC_TYPES.SERIAL_DIFF]: AggParamsSerialDiff; - [METRIC_TYPES.TOP_HITS]: AggParamsTopHit; -} +export type AggsSetup = AggsCommonSetup; +export { AggsStart } from '../../../common'; diff --git a/src/plugins/data/public/search/expressions/build_tabular_inspector_data.ts b/src/plugins/data/public/search/expressions/build_tabular_inspector_data.ts index 75a4464a8e61e..7eff6f25fd828 100644 --- a/src/plugins/data/public/search/expressions/build_tabular_inspector_data.ts +++ b/src/plugins/data/public/search/expressions/build_tabular_inspector_data.ts @@ -19,8 +19,8 @@ import { set } from '@elastic/safer-lodash-set'; import { FormattedData } from '../../../../../plugins/inspector/public'; +import { TabbedTable } from '../../../common'; import { FormatFactory } from '../../../common/field_formats/utils'; -import { TabbedTable } from '../tabify'; import { createFilter } from './create_filter'; /** diff --git a/src/plugins/data/public/search/expressions/create_filter.test.ts b/src/plugins/data/public/search/expressions/create_filter.test.ts index a7fd67983cb92..7968c80628531 100644 --- a/src/plugins/data/public/search/expressions/create_filter.test.ts +++ b/src/plugins/data/public/search/expressions/create_filter.test.ts @@ -17,11 +17,17 @@ * under the License. */ +import { + AggConfigs, + IAggConfig, + TabbedTable, + isRangeFilter, + BytesFormat, + FieldFormatsGetConfigFn, +} from '../../../common'; +import { mockAggTypesRegistry } from '../../../common/search/aggs/test_helpers'; + import { createFilter } from './create_filter'; -import { AggConfigs, IAggConfig } from '../aggs'; -import { TabbedTable } from '../tabify'; -import { isRangeFilter, BytesFormat, FieldFormatsGetConfigFn } from '../../../common'; -import { mockAggTypesRegistry } from '../aggs/test_helpers'; describe('createFilter', () => { let table: TabbedTable; diff --git a/src/plugins/data/public/search/expressions/create_filter.ts b/src/plugins/data/public/search/expressions/create_filter.ts index 94d84380e03df..09200c2e17b31 100644 --- a/src/plugins/data/public/search/expressions/create_filter.ts +++ b/src/plugins/data/public/search/expressions/create_filter.ts @@ -17,9 +17,7 @@ * under the License. */ -import { IAggConfig } from '../aggs'; -import { TabbedTable } from '../tabify'; -import { Filter } from '../../../common'; +import { Filter, IAggConfig, TabbedTable } from '../../../common'; const getOtherBucketFilterTerms = (table: TabbedTable, columnIndex: number, rowIndex: number) => { if (rowIndex === -1) { diff --git a/src/plugins/data/public/search/expressions/esaggs.ts b/src/plugins/data/public/search/expressions/esaggs.ts index 690f6b1df11c3..50fbb114b39fd 100644 --- a/src/plugins/data/public/search/expressions/esaggs.ts +++ b/src/plugins/data/public/search/expressions/esaggs.ts @@ -19,15 +19,11 @@ import { get, hasIn } from 'lodash'; import { i18n } from '@kbn/i18n'; - import { KibanaDatatable, KibanaDatatableColumn } from 'src/plugins/expressions/public'; import { calculateObjectHash } from '../../../../../plugins/kibana_utils/public'; import { PersistedState } from '../../../../../plugins/visualizations/public'; import { Adapters } from '../../../../../plugins/inspector/public'; -import { IAggConfigs } from '../aggs'; -import { ISearchSource } from '../search_source'; -import { tabifyAggResponse } from '../tabify'; import { calculateBounds, EsaggsExpressionFunctionDefinition, @@ -38,6 +34,13 @@ import { Query, TimeRange, } from '../../../common'; +import { + getRequestInspectorStats, + getResponseInspectorStats, + IAggConfigs, + tabifyAggResponse, +} from '../../../common/search'; + import { FilterManager } from '../../query'; import { getFieldFormats, @@ -45,8 +48,9 @@ import { getQueryService, getSearchService, } from '../../services'; +import { ISearchSource } from '../search_source'; import { buildTabularInspectorData } from './build_tabular_inspector_data'; -import { getRequestInspectorStats, getResponseInspectorStats, serializeAggConfig } from './utils'; +import { serializeAggConfig } from './utils'; export interface RequestHandlerParams { searchSource: ISearchSource; diff --git a/src/plugins/data/public/search/expressions/utils/index.ts b/src/plugins/data/public/search/expressions/utils/index.ts index 0fd51f3e158a6..094536fc18437 100644 --- a/src/plugins/data/public/search/expressions/utils/index.ts +++ b/src/plugins/data/public/search/expressions/utils/index.ts @@ -17,5 +17,4 @@ * under the License. */ -export * from './courier_inspector_stats'; export * from './serialize_agg_config'; diff --git a/src/plugins/data/public/search/expressions/utils/serialize_agg_config.ts b/src/plugins/data/public/search/expressions/utils/serialize_agg_config.ts index 78b4935077d10..6ba323b65783f 100644 --- a/src/plugins/data/public/search/expressions/utils/serialize_agg_config.ts +++ b/src/plugins/data/public/search/expressions/utils/serialize_agg_config.ts @@ -18,7 +18,7 @@ */ import { KibanaDatatableColumnMeta } from '../../../../../../plugins/expressions/public'; -import { IAggConfig } from '../../aggs'; +import { IAggConfig } from '../../../../common'; import { IndexPattern } from '../../../index_patterns'; import { getSearchService } from '../../../../public/services'; diff --git a/src/plugins/data/public/search/index.ts b/src/plugins/data/public/search/index.ts index ae028df31e401..32bcd8a279036 100644 --- a/src/plugins/data/public/search/index.ts +++ b/src/plugins/data/public/search/index.ts @@ -17,9 +17,7 @@ * under the License. */ -export * from './aggs'; export * from './expressions'; -export * from './tabify'; export { ISearch, diff --git a/src/plugins/data/public/search/search_service.test.ts b/src/plugins/data/public/search/search_service.test.ts index f0a017847e06a..e6897a16a353a 100644 --- a/src/plugins/data/public/search/search_service.test.ts +++ b/src/plugins/data/public/search/search_service.test.ts @@ -19,9 +19,8 @@ import { coreMock } from '../../../../core/public/mocks'; import { CoreSetup, CoreStart } from '../../../../core/public'; -import { expressionsPluginMock } from '../../../../plugins/expressions/public/mocks'; -import { SearchService } from './search_service'; +import { SearchService, SearchServiceSetupDependencies } from './search_service'; describe('Search service', () => { let searchService: SearchService; @@ -36,11 +35,12 @@ describe('Search service', () => { describe('setup()', () => { it('exposes proper contract', async () => { - const setup = searchService.setup(mockCoreSetup, { + const setup = searchService.setup(mockCoreSetup, ({ packageInfo: { version: '8' }, - expressions: expressionsPluginMock.createSetupContract(), - } as any); + registerFunction: jest.fn(), + } as unknown) as SearchServiceSetupDependencies); expect(setup).toHaveProperty('aggs'); + expect(setup).toHaveProperty('usageCollector'); expect(setup).toHaveProperty('__enhance'); }); }); @@ -50,6 +50,7 @@ describe('Search service', () => { const start = searchService.start(mockCoreStart, { indexPatterns: {}, } as any); + expect(start).toHaveProperty('aggs'); expect(start).toHaveProperty('search'); }); }); diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index 4c94925b66d6e..bd9c1b1253fe2 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -17,80 +17,43 @@ * under the License. */ -import { Plugin, CoreSetup, CoreStart, PackageInfo } from '../../../../core/public'; +import { Plugin, CoreSetup, CoreStart, PackageInfo } from 'src/core/public'; import { ISearchSetup, ISearchStart, SearchEnhancements } from './types'; -import { ExpressionsSetup } from '../../../../plugins/expressions/public'; import { createSearchSource, SearchSource, SearchSourceDependencies } from './search_source'; import { getEsClient, LegacyApiCaller } from './legacy'; -import { getForceNow } from '../query/timefilter/lib/get_force_now'; -import { calculateBounds, TimeRange } from '../../common/query'; - +import { AggsService, AggsSetupDependencies, AggsStartDependencies } from './aggs'; import { IndexPatternsContract } from '../index_patterns/index_patterns'; -import { GetInternalStartServicesFn } from '../types'; import { ISearchInterceptor, SearchInterceptor } from './search_interceptor'; -import { - getAggTypes, - getAggTypesFunctions, - AggTypesRegistry, - AggConfigs, - getCalculateAutoTimeExpression, -} from './aggs'; import { ISearchGeneric } from './types'; import { SearchUsageCollector, createUsageCollector } from './collectors'; import { UsageCollectionSetup } from '../../../usage_collection/public'; -interface SearchServiceSetupDependencies { - expressions: ExpressionsSetup; - usageCollection?: UsageCollectionSetup; - getInternalStartServices: GetInternalStartServicesFn; +/** @internal */ +export interface SearchServiceSetupDependencies { packageInfo: PackageInfo; + registerFunction: AggsSetupDependencies['registerFunction']; + usageCollection?: UsageCollectionSetup; } -interface SearchServiceStartDependencies { +/** @internal */ +export interface SearchServiceStartDependencies { + fieldFormats: AggsStartDependencies['fieldFormats']; indexPatterns: IndexPatternsContract; } export class SearchService implements Plugin { private esClient?: LegacyApiCaller; - private readonly aggTypesRegistry = new AggTypesRegistry(); + private readonly aggsService = new AggsService(); private searchInterceptor!: ISearchInterceptor; private usageCollector?: SearchUsageCollector; - /** - * getForceNow uses window.location, so we must have a separate implementation - * of calculateBounds on the client and the server. - */ - private calculateBounds = (timeRange: TimeRange) => - calculateBounds(timeRange, { forceNow: getForceNow() }); - public setup( core: CoreSetup, - { - expressions, - usageCollection, - packageInfo, - getInternalStartServices, - }: SearchServiceSetupDependencies + { packageInfo, registerFunction, usageCollection }: SearchServiceSetupDependencies ): ISearchSetup { this.usageCollector = createUsageCollector(core, usageCollection); this.esClient = getEsClient(core.injectedMetadata, core.http, packageInfo); - - const aggTypesSetup = this.aggTypesRegistry.setup(); - - // register each agg type - const aggTypes = getAggTypes({ - calculateBounds: this.calculateBounds, - getInternalStartServices, - uiSettings: core.uiSettings, - }); - aggTypes.buckets.forEach((b) => aggTypesSetup.registerBucket(b)); - aggTypes.metrics.forEach((m) => aggTypesSetup.registerMetric(m)); - - // register expression functions for each agg type - const aggFunctions = getAggTypesFunctions(); - aggFunctions.forEach((fn) => expressions.registerFunction(fn)); - /** * A global object that intercepts all searches and provides convenience methods for cancelling * all pending search requests, as well as getting the number of pending search requests. @@ -109,20 +72,21 @@ export class SearchService implements Plugin { ); return { + aggs: this.aggsService.setup({ + registerFunction, + uiSettings: core.uiSettings, + }), usageCollector: this.usageCollector!, __enhance: (enhancements: SearchEnhancements) => { this.searchInterceptor = enhancements.searchInterceptor; }, - aggs: { - calculateAutoTimeExpression: getCalculateAutoTimeExpression(core.uiSettings), - types: aggTypesSetup, - }, }; } - public start(core: CoreStart, dependencies: SearchServiceStartDependencies): ISearchStart { - const aggTypesStart = this.aggTypesRegistry.start(); - + public start( + { application, http, injectedMetadata, notifications, uiSettings }: CoreStart, + { fieldFormats, indexPatterns }: SearchServiceStartDependencies + ): ISearchStart { const search: ISearchGeneric = (request, options) => { return this.searchInterceptor.search(request, options); }; @@ -132,25 +96,17 @@ export class SearchService implements Plugin { }; const searchSourceDependencies: SearchSourceDependencies = { - uiSettings: core.uiSettings, - injectedMetadata: core.injectedMetadata, + uiSettings, + injectedMetadata, search, legacySearch, }; return { - aggs: { - calculateAutoTimeExpression: getCalculateAutoTimeExpression(core.uiSettings), - createAggConfigs: (indexPattern, configStates = [], schemas) => { - return new AggConfigs(indexPattern, configStates, { - typesRegistry: aggTypesStart, - }); - }, - types: aggTypesStart, - }, + aggs: this.aggsService.start({ fieldFormats, uiSettings }), search, searchSource: { - create: createSearchSource(dependencies.indexPatterns, searchSourceDependencies), + create: createSearchSource(indexPatterns, searchSourceDependencies), createEmpty: () => { return new SearchSource({}, searchSourceDependencies); }, @@ -159,5 +115,7 @@ export class SearchService implements Plugin { }; } - public stop() {} + public stop() { + this.aggsService.stop(); + } } diff --git a/src/plugins/data/public/search/types.ts b/src/plugins/data/public/search/types.ts index d85d4c4e5c935..d1a4437943402 100644 --- a/src/plugins/data/public/search/types.ts +++ b/src/plugins/data/public/search/types.ts @@ -19,11 +19,11 @@ import { Observable } from 'rxjs'; import { PackageInfo } from 'kibana/server'; -import { SearchAggsSetup, SearchAggsStart } from './aggs'; import { LegacyApiCaller } from './legacy/es_client'; import { ISearchInterceptor } from './search_interceptor'; import { ISearchSource, SearchSourceFields } from './search_source'; import { SearchUsageCollector } from './collectors'; +import { AggsSetup, AggsSetupDependencies, AggsStartDependencies, AggsStart } from './aggs'; import { IKibanaSearchRequest, IKibanaSearchResponse, @@ -31,9 +31,7 @@ import { IEsSearchResponse, } from '../../common/search'; import { IndexPatternsContract } from '../../common/index_patterns/index_patterns'; -import { ExpressionsSetup } from '../../../expressions/public'; import { UsageCollectionSetup } from '../../../usage_collection/public'; -import { GetInternalStartServicesFn } from '../types'; export interface ISearchOptions { signal?: AbortSignal; @@ -62,7 +60,7 @@ export interface SearchEnhancements { * point. */ export interface ISearchSetup { - aggs: SearchAggsSetup; + aggs: AggsSetup; usageCollector?: SearchUsageCollector; /** * @internal @@ -71,7 +69,7 @@ export interface ISearchSetup { } export interface ISearchStart { - aggs: SearchAggsStart; + aggs: AggsStart; search: ISearchGeneric; searchSource: { create: (fields?: SearchSourceFields) => Promise; @@ -86,13 +84,15 @@ export interface ISearchStart { export { SEARCH_EVENT_TYPE } from './collectors'; +/** @internal */ export interface SearchServiceSetupDependencies { - expressions: ExpressionsSetup; - usageCollection?: UsageCollectionSetup; - getInternalStartServices: GetInternalStartServicesFn; packageInfo: PackageInfo; + registerFunction: AggsSetupDependencies['registerFunction']; + usageCollection?: UsageCollectionSetup; } +/** @internal */ export interface SearchServiceStartDependencies { + fieldFormats: AggsStartDependencies['fieldFormats']; indexPatterns: IndexPatternsContract; } diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts index c39b7d355d495..bffc10642eb47 100644 --- a/src/plugins/data/public/types.ts +++ b/src/plugins/data/public/types.ts @@ -82,15 +82,3 @@ export interface IDataPluginServices extends Partial { storage: IStorageWrapper; data: DataPublicPluginStart; } - -/** @internal **/ -export interface InternalStartServices { - readonly fieldFormats: FieldFormatsStart; - readonly notifications: CoreStart['notifications']; - readonly uiSettings: CoreStart['uiSettings']; - readonly searchService: DataPublicPluginStart['search']; - readonly injectedMetadata: CoreStart['injectedMetadata']; -} - -/** @internal **/ -export type GetInternalStartServicesFn = () => InternalStartServices; diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts index 73ed88850d787..c3b06992dba0e 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -150,6 +150,16 @@ export { */ import { + // aggs + CidrMask, + intervalOptions, + isNumberType, + isStringType, + isType, + parentPipelineType, + propFilter, + siblingPipelineType, + termsAggFilter, dateHistogramInterval, InvalidEsCalendarIntervalError, InvalidEsIntervalFormatError, @@ -159,13 +169,41 @@ import { parseEsInterval, parseInterval, toAbsoluteDates, + // expressions utils + getRequestInspectorStats, + getResponseInspectorStats, + // tabify + tabifyAggResponse, + tabifyGetColumns, } from '../common'; export { + // aggs + AggGroupLabels, + AggGroupName, + AggGroupNames, + AggParam, + AggParamOption, + AggParamType, + AggConfigOptions, + BUCKET_TYPES, EsaggsExpressionFunctionDefinition, + IAggConfig, + IAggConfigs, + IAggType, + IFieldParamType, + IMetricAggType, + METRIC_TYPES, + OptionedParamType, + OptionedValueProp, ParsedInterval, + // search IEsSearchRequest, IEsSearchResponse, + // tabify + TabbedAggColumn, + TabbedAggRow, + TabbedTable, } from '../common'; export { @@ -182,16 +220,29 @@ export { // Search namespace export const search = { aggs: { + CidrMask, dateHistogramInterval, + intervalOptions, InvalidEsCalendarIntervalError, InvalidEsIntervalFormatError, Ipv4Address, + isNumberType, + isStringType, + isType, isValidEsInterval, isValidInterval, + parentPipelineType, parseEsInterval, parseInterval, + propFilter, + siblingPipelineType, + termsAggFilter, toAbsoluteDates, }, + getRequestInspectorStats, + getResponseInspectorStats, + tabifyAggResponse, + tabifyGetColumns, }; /** diff --git a/src/plugins/data/server/plugin.ts b/src/plugins/data/server/plugin.ts index 61d8e566d2d2b..5163bfcb17d40 100644 --- a/src/plugins/data/server/plugin.ts +++ b/src/plugins/data/server/plugin.ts @@ -17,13 +17,8 @@ * under the License. */ -import { - PluginInitializerContext, - CoreSetup, - CoreStart, - Plugin, - Logger, -} from '../../../core/server'; +import { PluginInitializerContext, CoreSetup, CoreStart, Plugin, Logger } from 'src/core/server'; +import { ExpressionsServerSetup } from 'src/plugins/expressions/server'; import { ConfigSchema } from '../config'; import { IndexPatternsService, IndexPatternsServiceStart } from './index_patterns'; import { ISearchSetup, ISearchStart } from './search'; @@ -48,10 +43,21 @@ export interface DataPluginStart { } export interface DataPluginSetupDependencies { + expressions: ExpressionsServerSetup; usageCollection?: UsageCollectionSetup; } -export class DataServerPlugin implements Plugin { +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface DataPluginStartDependencies {} + +export class DataServerPlugin + implements + Plugin< + DataPluginSetup, + DataPluginStart, + DataPluginSetupDependencies, + DataPluginStartDependencies + > { private readonly searchService: SearchService; private readonly scriptsService: ScriptsService; private readonly kqlTelemetryService: KqlTelemetryService; @@ -70,8 +76,8 @@ export class DataServerPlugin implements Plugin, - { usageCollection }: DataPluginSetupDependencies + core: CoreSetup, + { expressions, usageCollection }: DataPluginSetupDependencies ) { this.indexPatterns.setup(core); this.scriptsService.setup(core); @@ -82,7 +88,10 @@ export class DataServerPlugin implements Plugin { + let service: AggsService; + let setupDeps: AggsSetupDependencies; + let startDeps: AggsStartDependencies; + + beforeEach(() => { + service = new AggsService(); + setupDeps = { + registerFunction: expressionsPluginMock.createSetupContract().registerFunction, + }; + startDeps = { + fieldFormats: createFieldFormatsStartMock(), + uiSettings, + }; + }); + + describe('setup()', () => { + test('exposes proper contract', () => { + const setup = service.setup(setupDeps); + expect(Object.keys(setup).length).toBe(1); + expect(setup).toHaveProperty('types'); + }); + }); + + describe('start()', () => { + test('exposes proper contract', async () => { + service.setup(setupDeps); + const start = service.start(startDeps); + + expect(Object.keys(start).length).toBe(1); + expect(start).toHaveProperty('asScopedToClient'); + + const contract = await start.asScopedToClient( + savedObjects.getScopedClient({} as KibanaRequest) + ); + expect(contract).toHaveProperty('calculateAutoTimeExpression'); + expect(contract).toHaveProperty('createAggConfigs'); + expect(contract).toHaveProperty('types'); + }); + + test('types registry returns initialized agg types', async () => { + service.setup(setupDeps); + const start = await service + .start(startDeps) + .asScopedToClient(savedObjects.getScopedClient({} as KibanaRequest)); + + expect(start.types.get('terms').name).toBe('terms'); + }); + + test('registers default agg types', async () => { + service.setup(setupDeps); + const start = await service + .start(startDeps) + .asScopedToClient(savedObjects.getScopedClient({} as KibanaRequest)); + + const aggTypes = getAggTypes(); + expect(start.types.getAll().buckets.length).toBe(aggTypes.buckets.length); + expect(start.types.getAll().metrics.length).toBe(aggTypes.metrics.length); + }); + + test('merges default agg types with types registered during setup', async () => { + const setup = service.setup(setupDeps); + setup.types.registerBucket( + 'foo', + () => ({ name: 'foo', type: 'buckets' } as BucketAggType) + ); + setup.types.registerMetric( + 'bar', + () => ({ name: 'bar', type: 'metrics' } as MetricAggType) + ); + + const start = await service + .start(startDeps) + .asScopedToClient(savedObjects.getScopedClient({} as KibanaRequest)); + + const aggTypes = getAggTypes(); + expect(start.types.getAll().buckets.length).toBe(aggTypes.buckets.length + 1); + expect(start.types.getAll().buckets.some(({ name }) => name === 'foo')).toBe(true); + expect(start.types.getAll().metrics.length).toBe(aggTypes.metrics.length + 1); + expect(start.types.getAll().metrics.some(({ name }) => name === 'bar')).toBe(true); + }); + }); +}); diff --git a/src/plugins/data/server/search/aggs/aggs_service.ts b/src/plugins/data/server/search/aggs/aggs_service.ts new file mode 100644 index 0000000000000..3e5cd8adb44a6 --- /dev/null +++ b/src/plugins/data/server/search/aggs/aggs_service.ts @@ -0,0 +1,122 @@ +/* + * 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 { pick } from 'lodash'; + +import { UiSettingsServiceStart, SavedObjectsClientContract } from 'src/core/server'; +import { ExpressionsServiceSetup } from 'src/plugins/expressions/common'; +import { + AggsCommonService, + AggConfigs, + AggTypesDependencies, + aggsRequiredUiSettings, + calculateBounds, + TimeRange, +} from '../../../common'; +import { FieldFormatsStart } from '../../field_formats'; +import { AggsSetup, AggsStart } from './types'; + +/** @internal */ +export interface AggsSetupDependencies { + registerFunction: ExpressionsServiceSetup['registerFunction']; +} + +/** @internal */ +export interface AggsStartDependencies { + fieldFormats: FieldFormatsStart; + uiSettings: UiSettingsServiceStart; +} + +/** + * The aggs service provides a means of modeling and manipulating the various + * Elasticsearch aggregations supported by Kibana, providing the ability to + * output the correct DSL when you are ready to send your request to ES. + */ +export class AggsService { + private readonly aggsCommonService = new AggsCommonService(); + + /** + * getForceNow uses window.location on the client, so we must have a + * separate implementation of calculateBounds on the server. + */ + private calculateBounds = (timeRange: TimeRange) => calculateBounds(timeRange, {}); + + public setup({ registerFunction }: AggsSetupDependencies): AggsSetup { + return this.aggsCommonService.setup({ registerFunction }); + } + + public start({ fieldFormats, uiSettings }: AggsStartDependencies): AggsStart { + return { + asScopedToClient: async (savedObjectsClient: SavedObjectsClientContract) => { + const uiSettingsClient = uiSettings.asScopedToClient(savedObjectsClient); + const formats = await fieldFormats.fieldFormatServiceFactory(uiSettingsClient); + + // cache ui settings, only including items which are explicitly needed by aggs + const uiSettingsCache = pick(await uiSettingsClient.getAll(), aggsRequiredUiSettings); + const getConfig = (key: string): T => { + return uiSettingsCache[key]; + }; + + const { calculateAutoTimeExpression, types } = this.aggsCommonService.start({ getConfig }); + + const aggTypesDependencies: AggTypesDependencies = { + calculateBounds: this.calculateBounds, + getConfig, + getFieldFormatsStart: () => ({ + deserialize: formats.deserialize, + getDefaultInstance: formats.getDefaultInstance, + }), + /** + * Date histogram and date range need to know whether we are using the + * default timezone, but `isDefault` is not currently offered on the + * server, so we need to manually check for the default value. + */ + isDefaultTimezone: () => getConfig('dateFormat:tz') === 'Browser', + }; + + const typesRegistry = { + get: (name: string) => { + const type = types.get(name); + if (!type) { + return; + } + return type(aggTypesDependencies); + }, + getAll: () => { + return { + // initialize each agg type on the fly + buckets: types.getAll().buckets.map((type) => type(aggTypesDependencies)), + metrics: types.getAll().metrics.map((type) => type(aggTypesDependencies)), + }; + }, + }; + + return { + calculateAutoTimeExpression, + createAggConfigs: (indexPattern, configStates = [], schemas) => { + return new AggConfigs(indexPattern, configStates, { typesRegistry }); + }, + types: typesRegistry, + }; + }, + }; + } + + public stop() {} +} diff --git a/src/plugins/data/server/search/aggs/index.ts b/src/plugins/data/server/search/aggs/index.ts new file mode 100644 index 0000000000000..77d97c426260c --- /dev/null +++ b/src/plugins/data/server/search/aggs/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 * from './aggs_service'; +export * from './types'; diff --git a/src/plugins/data/server/search/aggs/mocks.ts b/src/plugins/data/server/search/aggs/mocks.ts new file mode 100644 index 0000000000000..b50e22fe87b7c --- /dev/null +++ b/src/plugins/data/server/search/aggs/mocks.ts @@ -0,0 +1,81 @@ +/* + * 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 { + AggConfigs, + AggTypesRegistrySetup, + AggTypesRegistryStart, + AggsCommonStart, + getCalculateAutoTimeExpression, +} from '../../../common'; +import { AggsSetup, AggsStart } from './types'; + +import { mockAggTypesRegistry } from '../../../common/search/aggs/test_helpers'; + +const getConfig = jest.fn(); + +const aggTypeBaseParamMock = () => ({ + name: 'some_param', + type: 'some_param_type', + displayName: 'some_agg_type_param', + required: false, + advanced: false, + default: {}, + write: jest.fn(), + serialize: jest.fn().mockImplementation(() => {}), + deserialize: jest.fn().mockImplementation(() => {}), + options: [], +}); + +const aggTypeConfigMock = () => ({ + name: 'some_name', + title: 'some_title', + params: [aggTypeBaseParamMock()], +}); + +export const aggTypesRegistrySetupMock = (): AggTypesRegistrySetup => ({ + registerBucket: jest.fn(), + registerMetric: jest.fn(), +}); + +export const aggTypesRegistryStartMock = (): AggTypesRegistryStart => ({ + get: jest.fn().mockImplementation(aggTypeConfigMock), + getAll: jest.fn().mockImplementation(() => ({ + buckets: [aggTypeConfigMock()], + metrics: [aggTypeConfigMock()], + })), +}); + +export const searchAggsSetupMock = (): AggsSetup => ({ + types: aggTypesRegistrySetupMock(), +}); + +const commonStartMock = (): AggsCommonStart => ({ + calculateAutoTimeExpression: getCalculateAutoTimeExpression(getConfig), + createAggConfigs: jest.fn().mockImplementation((indexPattern, configStates = [], schemas) => { + return new AggConfigs(indexPattern, configStates, { + typesRegistry: mockAggTypesRegistry(), + }); + }), + types: mockAggTypesRegistry(), +}); + +export const searchAggsStartMock = (): AggsStart => ({ + asScopedToClient: jest.fn().mockResolvedValue(commonStartMock()), +}); diff --git a/src/plugins/data/server/search/aggs/types.ts b/src/plugins/data/server/search/aggs/types.ts new file mode 100644 index 0000000000000..1b21d948b25d9 --- /dev/null +++ b/src/plugins/data/server/search/aggs/types.ts @@ -0,0 +1,27 @@ +/* + * 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 { SavedObjectsClientContract } from 'src/core/server'; +import { AggsCommonSetup, AggsStart as Start } from '../../../common'; + +export type AggsSetup = AggsCommonSetup; + +export interface AggsStart { + asScopedToClient: (savedObjectsClient: SavedObjectsClientContract) => Promise; +} diff --git a/src/plugins/data/server/search/index.ts b/src/plugins/data/server/search/index.ts index cea2714671f0b..4a3990621ca39 100644 --- a/src/plugins/data/server/search/index.ts +++ b/src/plugins/data/server/search/index.ts @@ -22,3 +22,5 @@ export { ISearchStrategy, ISearchOptions, ISearchSetup, ISearchStart } from './t export { getDefaultSearchParams, getTotalLoaded } from './es_search'; export { usageProvider, SearchUsage } from './collectors'; + +export * from './aggs'; diff --git a/src/plugins/data/server/search/mocks.ts b/src/plugins/data/server/search/mocks.ts index b210df3c55db9..578a170f468bf 100644 --- a/src/plugins/data/server/search/mocks.ts +++ b/src/plugins/data/server/search/mocks.ts @@ -17,14 +17,19 @@ * under the License. */ -export function createSearchSetupMock() { +import { ISearchSetup, ISearchStart } from './types'; +import { searchAggsSetupMock, searchAggsStartMock } from './aggs/mocks'; + +export function createSearchSetupMock(): jest.Mocked { return { + aggs: searchAggsSetupMock(), registerSearchStrategy: jest.fn(), }; } -export function createSearchStartMock() { +export function createSearchStartMock(): jest.Mocked { return { + aggs: searchAggsStartMock(), getSearchStrategy: jest.fn(), search: jest.fn(), }; diff --git a/src/plugins/data/server/search/search_service.test.ts b/src/plugins/data/server/search/search_service.test.ts index be00b7409fe4a..030f37d0f7c46 100644 --- a/src/plugins/data/server/search/search_service.test.ts +++ b/src/plugins/data/server/search/search_service.test.ts @@ -17,15 +17,18 @@ * under the License. */ +import { CoreSetup, CoreStart } from '../../../../core/server'; import { coreMock } from '../../../../core/server/mocks'; -import { SearchService } from './search_service'; -import { CoreSetup } from '../../../../core/server'; import { DataPluginStart } from '../plugin'; +import { createFieldFormatsStartMock } from '../field_formats/mocks'; + +import { SearchService, SearchServiceSetupDependencies } from './search_service'; describe('Search service', () => { let plugin: SearchService; let mockCoreSetup: MockedKeys>; + let mockCoreStart: MockedKeys; beforeEach(() => { const mockLogger: any = { @@ -33,19 +36,27 @@ describe('Search service', () => { }; plugin = new SearchService(coreMock.createPluginInitializerContext({}), mockLogger); mockCoreSetup = coreMock.createSetup(); + mockCoreStart = coreMock.createStart(); }); describe('setup()', () => { it('exposes proper contract', async () => { - const setup = plugin.setup(mockCoreSetup, {}); + const setup = plugin.setup(mockCoreSetup, ({ + packageInfo: { version: '8' }, + registerFunction: jest.fn(), + } as unknown) as SearchServiceSetupDependencies); + expect(setup).toHaveProperty('aggs'); expect(setup).toHaveProperty('registerSearchStrategy'); }); }); describe('start()', () => { it('exposes proper contract', async () => { - const setup = plugin.start(); - expect(setup).toHaveProperty('getSearchStrategy'); + const start = plugin.start(mockCoreStart, { + fieldFormats: createFieldFormatsStartMock(), + }); + expect(start).toHaveProperty('aggs'); + expect(start).toHaveProperty('getSearchStrategy'); }); }); }); diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index 9dc47369567af..a8b1cdd608a84 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -18,13 +18,18 @@ */ import { + CoreSetup, + CoreStart, + Logger, Plugin, PluginInitializerContext, - CoreSetup, RequestHandlerContext, - Logger, } from '../../../../core/server'; import { ISearchSetup, ISearchStart, ISearchStrategy } from './types'; + +import { AggsService, AggsSetupDependencies } from './aggs'; + +import { FieldFormatsStart } from '../field_formats'; import { registerSearchRoute } from './routes'; import { ES_SEARCH_STRATEGY, esSearchStrategyProvider } from './es_search'; import { DataPluginStart } from '../plugin'; @@ -38,7 +43,19 @@ interface StrategyMap { [name: string]: ISearchStrategy; } +/** @internal */ +export interface SearchServiceSetupDependencies { + registerFunction: AggsSetupDependencies['registerFunction']; + usageCollection?: UsageCollectionSetup; +} + +/** @internal */ +export interface SearchServiceStartDependencies { + fieldFormats: FieldFormatsStart; +} + export class SearchService implements Plugin { + private readonly aggsService = new AggsService(); private searchStrategies: StrategyMap = {}; constructor( @@ -48,7 +65,7 @@ export class SearchService implements Plugin { public setup( core: CoreSetup, - { usageCollection }: { usageCollection?: UsageCollectionSetup } + { registerFunction, usageCollection }: SearchServiceSetupDependencies ): ISearchSetup { const usage = usageCollection ? usageProvider(core) : undefined; @@ -68,7 +85,11 @@ export class SearchService implements Plugin { registerSearchRoute(core); - return { registerSearchStrategy: this.registerSearchStrategy, usage }; + return { + aggs: this.aggsService.setup({ registerFunction }), + registerSearchStrategy: this.registerSearchStrategy, + usage, + }; } private search( @@ -83,8 +104,12 @@ export class SearchService implements Plugin { ); } - public start(): ISearchStart { + public start( + { uiSettings }: CoreStart, + { fieldFormats }: SearchServiceStartDependencies + ): ISearchStart { return { + aggs: this.aggsService.start({ fieldFormats, uiSettings }), getSearchStrategy: this.getSearchStrategy, search: ( context: RequestHandlerContext, @@ -96,7 +121,9 @@ export class SearchService implements Plugin { }; } - public stop() {} + public stop() { + this.aggsService.stop(); + } private registerSearchStrategy = (name: string, strategy: ISearchStrategy) => { this.logger.info(`Register strategy ${name}`); diff --git a/src/plugins/data/server/search/types.ts b/src/plugins/data/server/search/types.ts index 76afd7e8c951c..fe54975d76624 100644 --- a/src/plugins/data/server/search/types.ts +++ b/src/plugins/data/server/search/types.ts @@ -19,6 +19,7 @@ import { RequestHandlerContext } from '../../../../core/server'; import { IKibanaSearchResponse, IKibanaSearchRequest } from '../../common/search'; +import { AggsSetup, AggsStart } from './aggs'; import { SearchUsage } from './collectors/usage'; import { IEsSearchRequest, IEsSearchResponse } from './es_search'; @@ -31,6 +32,7 @@ export interface ISearchOptions { } export interface ISearchSetup { + aggs: AggsSetup; /** * Extension point exposed for other plugins to register their own search * strategies. @@ -44,6 +46,7 @@ export interface ISearchSetup { } export interface ISearchStart { + aggs: AggsStart; /** * Get other registered search strategies. For example, if a new strategy needs to use the * already-registered ES search strategy, it can use this function to accomplish that. diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index 37d569a4bf9fe..9c8a79f27a9db 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -4,7 +4,9 @@ ```ts +import { $Values } from '@kbn/utility-types'; import { ApiResponse } from '@elastic/elasticsearch/lib/Transport'; +import { Assign } from '@kbn/utility-types'; import Boom from 'boom'; import { BulkIndexDocumentsParams } from 'elasticsearch'; import { CatAliasesParams } from 'elasticsearch'; @@ -22,7 +24,6 @@ import { CatTasksParams } from 'elasticsearch'; import { CatThreadPoolParams } from 'elasticsearch'; import { ClearScrollParams } from 'elasticsearch'; import { Client } from 'elasticsearch'; -import { ClientOptions } from '@elastic/elasticsearch'; import { ClusterAllocationExplainParams } from 'elasticsearch'; import { ClusterGetSettingsParams } from 'elasticsearch'; import { ClusterHealthParams } from 'elasticsearch'; @@ -31,19 +32,23 @@ import { ClusterPutSettingsParams } from 'elasticsearch'; import { ClusterRerouteParams } from 'elasticsearch'; import { ClusterStateParams } from 'elasticsearch'; import { ClusterStatsParams } from 'elasticsearch'; -import { ConfigOptions } from 'elasticsearch'; +import { CoreSetup } from 'src/core/server'; import { CoreSetup as CoreSetup_2 } from 'kibana/server'; +import { CoreStart } from 'src/core/server'; import { CountParams } from 'elasticsearch'; import { CreateDocumentParams } from 'elasticsearch'; import { DeleteDocumentByQueryParams } from 'elasticsearch'; import { DeleteDocumentParams } from 'elasticsearch'; import { DeleteScriptParams } from 'elasticsearch'; import { DeleteTemplateParams } from 'elasticsearch'; -import { DetailedPeerCertificate } from 'tls'; import { Duration } from 'moment'; +import { Ensure } from '@kbn/utility-types'; import { ErrorToastOptions } from 'src/core/public/notifications'; import { ExistsParams } from 'elasticsearch'; import { ExplainParams } from 'elasticsearch'; +import { ExpressionAstFunction } from 'src/plugins/expressions/common'; +import { ExpressionsServerSetup } from 'src/plugins/expressions/server'; +import { FetchOptions } from 'src/plugins/data/public'; import { FieldStatsParams } from 'elasticsearch'; import { GenericParams } from 'elasticsearch'; import { GetParams } from 'elasticsearch'; @@ -94,13 +99,15 @@ import { IngestDeletePipelineParams } from 'elasticsearch'; import { IngestGetPipelineParams } from 'elasticsearch'; import { IngestPutPipelineParams } from 'elasticsearch'; import { IngestSimulateParams } from 'elasticsearch'; +import { ISearchSource } from 'src/plugins/data/public'; import { KibanaClient } from '@elastic/elasticsearch/api/kibana'; import { KibanaConfigType as KibanaConfigType_2 } from 'src/core/server/kibana_config'; -import { KibanaRequest as KibanaRequest_2 } from 'kibana/server'; +import { KibanaRequest } from 'kibana/server'; import { LegacyAPICaller as LegacyAPICaller_2 } from 'kibana/server'; import { Logger as Logger_2 } from 'kibana/server'; import { MGetParams } from 'elasticsearch'; import { MGetResponse } from 'elasticsearch'; +import { Moment } from 'moment'; import moment from 'moment'; import { MSearchParams } from 'elasticsearch'; import { MSearchResponse } from 'elasticsearch'; @@ -109,27 +116,26 @@ import { MTermVectorsParams } from 'elasticsearch'; import { NodesHotThreadsParams } from 'elasticsearch'; import { NodesInfoParams } from 'elasticsearch'; import { NodesStatsParams } from 'elasticsearch'; -import { ObjectType } from '@kbn/config-schema'; import { Observable } from 'rxjs'; -import { PeerCertificate } from 'tls'; import { PingParams } from 'elasticsearch'; +import { Plugin as Plugin_2 } from 'src/core/server'; +import { PluginInitializerContext as PluginInitializerContext_2 } from 'src/core/server'; import { PutScriptParams } from 'elasticsearch'; import { PutTemplateParams } from 'elasticsearch'; import { RecursiveReadonly } from '@kbn/utility-types'; import { ReindexParams } from 'elasticsearch'; import { ReindexRethrottleParams } from 'elasticsearch'; import { RenderSearchTemplateParams } from 'elasticsearch'; -import { Request } from 'hapi'; -import { ResponseObject } from 'hapi'; -import { ResponseToolkit } from 'hapi'; -import { SavedObject as SavedObject_2 } from 'src/core/server'; -import { SchemaTypeError } from '@kbn/config-schema'; +import { RequestAdapter } from 'src/plugins/inspector/common'; +import { RequestStatistics } from 'src/plugins/inspector/common'; +import { SavedObject } from 'src/core/server'; +import { SavedObjectsClientContract as SavedObjectsClientContract_2 } from 'src/core/server'; import { ScrollParams } from 'elasticsearch'; import { SearchParams } from 'elasticsearch'; import { SearchResponse } from 'elasticsearch'; import { SearchShardsParams } from 'elasticsearch'; import { SearchTemplateParams } from 'elasticsearch'; -import { ShallowPromise } from '@kbn/utility-types'; +import { SerializedFieldFormat as SerializedFieldFormat_2 } from 'src/plugins/expressions/common'; import { ShardsResponse } from 'elasticsearch'; import { SnapshotCreateParams } from 'elasticsearch'; import { SnapshotCreateRepositoryParams } from 'elasticsearch'; @@ -140,7 +146,6 @@ import { SnapshotGetRepositoryParams } from 'elasticsearch'; import { SnapshotRestoreParams } from 'elasticsearch'; import { SnapshotStatusParams } from 'elasticsearch'; import { SnapshotVerifyRepositoryParams } from 'elasticsearch'; -import { Stream } from 'stream'; import { SuggestParams } from 'elasticsearch'; import { TasksCancelParams } from 'elasticsearch'; import { TasksGetParams } from 'elasticsearch'; @@ -156,7 +161,96 @@ import { Unit } from '@elastic/datemath'; import { UnwrapPromiseOrReturn } from '@kbn/utility-types'; import { UpdateDocumentByQueryParams } from 'elasticsearch'; import { UpdateDocumentParams } from 'elasticsearch'; -import { Url } from 'url'; + +// Warning: (ae-forgotten-export) The symbol "AggConfigSerialized" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "AggConfigOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type AggConfigOptions = Assign; + +// Warning: (ae-missing-release-tag) "AggGroupLabels" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const AggGroupLabels: { + buckets: string; + metrics: string; + none: string; +}; + +// Warning: (ae-missing-release-tag) "AggGroupName" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type AggGroupName = $Values; + +// Warning: (ae-missing-release-tag) "AggGroupNames" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const AggGroupNames: Readonly<{ + Buckets: "buckets"; + Metrics: "metrics"; + None: "none"; +}>; + +// Warning: (ae-forgotten-export) The symbol "BaseParamType" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "AggParam" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type AggParam = BaseParamType; + +// Warning: (ae-missing-release-tag) "AggParamOption" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface AggParamOption { + // (undocumented) + display: string; + // Warning: (ae-forgotten-export) The symbol "AggConfig" needs to be exported by the entry point index.d.ts + // + // (undocumented) + enabled?(agg: AggConfig): boolean; + // (undocumented) + val: string; +} + +// Warning: (ae-missing-release-tag) "AggParamType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export class AggParamType extends BaseParamType { + constructor(config: Record); + // (undocumented) + allowedAggs: string[]; + // (undocumented) + makeAgg: (agg: TAggConfig, state?: AggConfigSerialized) => TAggConfig; +} + +// Warning: (ae-missing-release-tag) "BUCKET_TYPES" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export enum BUCKET_TYPES { + // (undocumented) + DATE_HISTOGRAM = "date_histogram", + // (undocumented) + DATE_RANGE = "date_range", + // (undocumented) + FILTER = "filter", + // (undocumented) + FILTERS = "filters", + // (undocumented) + GEOHASH_GRID = "geohash_grid", + // (undocumented) + GEOTILE_GRID = "geotile_grid", + // (undocumented) + HISTOGRAM = "histogram", + // (undocumented) + IP_RANGE = "ip_range", + // (undocumented) + RANGE = "range", + // (undocumented) + SIGNIFICANT_TERMS = "significant_terms", + // (undocumented) + TERMS = "terms" +} // Warning: (ae-missing-release-tag) "castEsToKbnFieldTypeName" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -369,6 +463,22 @@ export function getTotalLoaded({ total, failed, successful }: ShardsResponse): { loaded: number; }; +// Warning: (ae-missing-release-tag) "IAggConfig" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export type IAggConfig = AggConfig; + +// Warning: (ae-forgotten-export) The symbol "AggConfigs" needs to be exported by the entry point index.d.ts +// +// @internal +export type IAggConfigs = AggConfigs; + +// Warning: (ae-forgotten-export) The symbol "AggType" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "IAggType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type IAggType = AggType; + // Warning: (ae-forgotten-export) The symbol "IKibanaSearchRequest" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "IEsSearchRequest" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -398,6 +508,12 @@ export interface IEsSearchResponse extends IKibanaSearchResponse { // @public (undocumented) export type IFieldFormatsRegistry = PublicMethodsOf; +// Warning: (ae-forgotten-export) The symbol "FieldParamType" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "IFieldParamType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type IFieldParamType = FieldParamType; + // Warning: (ae-missing-release-tag) "IFieldSubType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -479,6 +595,12 @@ export interface IIndexPattern { type?: string; } +// Warning: (ae-forgotten-export) The symbol "MetricAggType" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "IMetricAggType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type IMetricAggType = MetricAggType; + // Warning: (ae-missing-release-tag) "IndexPatternAttributes" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public @deprecated @@ -561,6 +683,10 @@ export interface ISearchOptions { // // @public (undocumented) export interface ISearchSetup { + // Warning: (ae-forgotten-export) The symbol "AggsSetup" needs to be exported by the entry point index.d.ts + // + // (undocumented) + aggs: AggsSetup; registerSearchStrategy: (name: string, strategy: ISearchStrategy) => void; usage?: SearchUsage; } @@ -569,6 +695,10 @@ export interface ISearchSetup { // // @public (undocumented) export interface ISearchStart { + // Warning: (ae-forgotten-export) The symbol "AggsStart" needs to be exported by the entry point index.d.ts + // + // (undocumented) + aggs: AggsStart; getSearchStrategy: (name: string) => ISearchStrategy; // Warning: (ae-forgotten-export) The symbol "RequestHandlerContext" needs to be exported by the entry point index.d.ts // @@ -632,6 +762,77 @@ export interface KueryNode { type: keyof NodeTypes; } +// Warning: (ae-missing-release-tag) "METRIC_TYPES" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export enum METRIC_TYPES { + // (undocumented) + AVG = "avg", + // (undocumented) + AVG_BUCKET = "avg_bucket", + // (undocumented) + CARDINALITY = "cardinality", + // (undocumented) + COUNT = "count", + // (undocumented) + CUMULATIVE_SUM = "cumulative_sum", + // (undocumented) + DERIVATIVE = "derivative", + // (undocumented) + GEO_BOUNDS = "geo_bounds", + // (undocumented) + GEO_CENTROID = "geo_centroid", + // (undocumented) + MAX = "max", + // (undocumented) + MAX_BUCKET = "max_bucket", + // (undocumented) + MEDIAN = "median", + // (undocumented) + MIN = "min", + // (undocumented) + MIN_BUCKET = "min_bucket", + // (undocumented) + MOVING_FN = "moving_avg", + // (undocumented) + PERCENTILE_RANKS = "percentile_ranks", + // (undocumented) + PERCENTILES = "percentiles", + // (undocumented) + SERIAL_DIFF = "serial_diff", + // (undocumented) + STD_DEV = "std_dev", + // (undocumented) + SUM = "sum", + // (undocumented) + SUM_BUCKET = "sum_bucket", + // (undocumented) + TOP_HITS = "top_hits" +} + +// Warning: (ae-missing-release-tag) "OptionedParamType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export class OptionedParamType extends BaseParamType { + constructor(config: Record); + // (undocumented) + options: OptionedValueProp[]; +} + +// Warning: (ae-missing-release-tag) "OptionedValueProp" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface OptionedValueProp { + // (undocumented) + disabled?: boolean; + // (undocumented) + isCompatible: (agg: IAggConfig) => boolean; + // (undocumented) + text: string; + // (undocumented) + value: string; +} + // Warning: (ae-forgotten-export) The symbol "parseEsInterval" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "ParsedInterval" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -643,25 +844,20 @@ export type ParsedInterval = ReturnType; // @public (undocumented) export function parseInterval(interval: string): moment.Duration | null; -// Warning: (ae-forgotten-export) The symbol "Plugin" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "DataPluginSetupDependencies" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "DataPluginStartDependencies" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "DataServerPlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export class Plugin implements Plugin_2 { - // Warning: (ae-forgotten-export) The symbol "PluginInitializerContext" needs to be exported by the entry point index.d.ts - constructor(initializerContext: PluginInitializerContext); - // Warning: (ae-forgotten-export) The symbol "CoreSetup" needs to be exported by the entry point index.d.ts - // Warning: (ae-forgotten-export) The symbol "DataPluginSetupDependencies" needs to be exported by the entry point index.d.ts - // +export class Plugin implements Plugin_2 { + constructor(initializerContext: PluginInitializerContext_2); // (undocumented) - setup(core: CoreSetup, { usageCollection }: DataPluginSetupDependencies): { + setup(core: CoreSetup, { expressions, usageCollection }: DataPluginSetupDependencies): { search: ISearchSetup; fieldFormats: { - register: (customFieldFormat: import("../common").FieldFormatInstanceType) => number; + register: (customFieldFormat: import("../public").FieldFormatInstanceType) => number; }; }; - // Warning: (ae-forgotten-export) The symbol "CoreStart" needs to be exported by the entry point index.d.ts - // // (undocumented) start(core: CoreStart): { search: ISearchStart; @@ -676,6 +872,8 @@ export class Plugin implements Plugin_2 { stop(): void; } +// Warning: (ae-forgotten-export) The symbol "PluginInitializerContext" needs to be exported by the entry point index.d.ts +// // @public export function plugin(initializerContext: PluginInitializerContext): Plugin; @@ -734,16 +932,36 @@ export interface RefreshInterval { // @public (undocumented) export const search: { aggs: { + CidrMask: typeof CidrMask; dateHistogramInterval: typeof dateHistogramInterval; + intervalOptions: ({ + display: string; + val: string; + enabled(agg: import("../common").IBucketAggConfig): boolean | "" | undefined; + } | { + display: string; + val: string; + })[]; InvalidEsCalendarIntervalError: typeof InvalidEsCalendarIntervalError; InvalidEsIntervalFormatError: typeof InvalidEsIntervalFormatError; Ipv4Address: typeof Ipv4Address; + isNumberType: (agg: import("../common").AggConfig) => boolean; + isStringType: (agg: import("../common").AggConfig) => boolean; + isType: (...types: string[]) => (agg: import("../common").AggConfig) => boolean; isValidEsInterval: typeof isValidEsInterval; isValidInterval: typeof isValidInterval; + parentPipelineType: string; parseEsInterval: typeof parseEsInterval; parseInterval: typeof parseInterval; + propFilter: typeof propFilter; + siblingPipelineType: string; + termsAggFilter: string[]; toAbsoluteDates: typeof toAbsoluteDates; }; + getRequestInspectorStats: typeof getRequestInspectorStats; + getResponseInspectorStats: typeof getResponseInspectorStats; + tabifyAggResponse: typeof tabifyAggResponse; + tabifyGetColumns: typeof tabifyGetColumns; }; // Warning: (ae-missing-release-tag) "SearchUsage" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -761,6 +979,27 @@ export interface SearchUsage { // @public (undocumented) export function shouldReadFieldFromDocValues(aggregatable: boolean, esType: string): boolean; +// @public (undocumented) +export interface TabbedAggColumn { + // (undocumented) + aggConfig: IAggConfig; + // (undocumented) + id: string; + // (undocumented) + name: string; +} + +// @public (undocumented) +export type TabbedAggRow = Record; + +// @public (undocumented) +export interface TabbedTable { + // (undocumented) + columns: TabbedAggColumn[]; + // (undocumented) + rows: TabbedAggRow[]; +} + // Warning: (ae-missing-release-tag) "TimeRange" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -836,13 +1075,19 @@ export function usageProvider(core: CoreSetup_2): SearchUsage; // src/plugins/data/server/index.ts:101:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:127:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:127:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:185:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:186:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:187:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:188:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:189:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:190:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:193:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:221:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:221:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:221:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:221:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:223:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:224:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:233:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:234:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:235:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:239:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:240:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:244:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:247:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx index 1a094a36f68e3..ebf8e09e86396 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/date_histogram.test.tsx @@ -10,7 +10,6 @@ import { dateHistogramOperation } from './index'; import { shallow } from 'enzyme'; import { EuiSwitch, EuiSwitchEvent } from '@elastic/eui'; import { IUiSettingsClient, SavedObjectsClientContract, HttpSetup } from 'kibana/public'; -import { coreMock } from 'src/core/public/mocks'; import { IStorageWrapper } from 'src/plugins/kibana_utils/public'; import { UI_SETTINGS } from '../../../../../../../src/plugins/data/public'; import { @@ -21,14 +20,13 @@ import { createMockedIndexPattern } from '../../mocks'; import { IndexPatternPrivateState } from '../../types'; const dataStart = dataPluginMock.createStartContract(); -dataStart.search.aggs.calculateAutoTimeExpression = getCalculateAutoTimeExpression({ - ...coreMock.createStart().uiSettings, - get: (path: string) => { +dataStart.search.aggs.calculateAutoTimeExpression = getCalculateAutoTimeExpression( + (path: string) => { if (path === UI_SETTINGS.HISTOGRAM_MAX_BARS) { return 10; } - }, -} as IUiSettingsClient); + } +); const defaultOptions = { storage: {} as IStorageWrapper, From ee9a8d29b1588e271486c428e423880f41fa8ee9 Mon Sep 17 00:00:00 2001 From: Ahmad Bamieh Date: Thu, 13 Aug 2020 23:44:17 +0300 Subject: [PATCH 28/53] [I18n] verify select icu-message options are in english (#74963) Co-authored-by: Elastic Machine --- src/dev/i18n/index.ts | 1 - src/dev/i18n/integrate_locale_files.test.ts | 1 - src/dev/i18n/integrate_locale_files.ts | 3 +- .../__snapshots__/utils.test.js.snap | 2 +- src/dev/i18n/utils/index.ts | 48 ++++++++++ src/dev/i18n/utils/intl_types.ts | 41 +++++++++ src/dev/i18n/{ => utils}/utils.js | 22 ----- src/dev/i18n/{ => utils}/utils.test.js | 0 src/dev/i18n/utils/verify_icu_message.test.ts | 91 +++++++++++++++++++ src/dev/i18n/utils/verify_icu_message.ts | 74 +++++++++++++++ src/dev/run_i18n_check.ts | 16 ++-- .../translations/translations/ja-JP.json | 1 - 12 files changed, 266 insertions(+), 34 deletions(-) rename src/dev/i18n/{ => utils}/__snapshots__/utils.test.js.snap (95%) create mode 100644 src/dev/i18n/utils/index.ts create mode 100644 src/dev/i18n/utils/intl_types.ts rename src/dev/i18n/{ => utils}/utils.js (95%) rename src/dev/i18n/{ => utils}/utils.test.js (100%) create mode 100644 src/dev/i18n/utils/verify_icu_message.test.ts create mode 100644 src/dev/i18n/utils/verify_icu_message.ts diff --git a/src/dev/i18n/index.ts b/src/dev/i18n/index.ts index cfc03f1c08b3c..68e6ab1646092 100644 --- a/src/dev/i18n/index.ts +++ b/src/dev/i18n/index.ts @@ -21,7 +21,6 @@ export { extractMessagesFromPathToMap } from './extract_default_translations'; // @ts-ignore export { matchEntriesWithExctractors } from './extract_default_translations'; -// @ts-ignore export { arrayify, writeFileAsync, readFileAsync, normalizePath, ErrorReporter } from './utils'; export { serializeToJson, serializeToJson5 } from './serializers'; export { diff --git a/src/dev/i18n/integrate_locale_files.test.ts b/src/dev/i18n/integrate_locale_files.test.ts index 3bd3dc61c044f..24c24682b2874 100644 --- a/src/dev/i18n/integrate_locale_files.test.ts +++ b/src/dev/i18n/integrate_locale_files.test.ts @@ -21,7 +21,6 @@ import { mockMakeDirAsync, mockWriteFileAsync } from './integrate_locale_files.t import path from 'path'; import { integrateLocaleFiles, verifyMessages } from './integrate_locale_files'; -// @ts-expect-error import { normalizePath } from './utils'; const localePath = path.resolve(__dirname, '__fixtures__', 'integrate_locale_files', 'fr.json'); diff --git a/src/dev/i18n/integrate_locale_files.ts b/src/dev/i18n/integrate_locale_files.ts index f9cd6dd1971c7..ed4f7db4376bb 100644 --- a/src/dev/i18n/integrate_locale_files.ts +++ b/src/dev/i18n/integrate_locale_files.ts @@ -32,7 +32,6 @@ import { readFileAsync, writeFileAsync, verifyICUMessage, - // @ts-expect-error } from './utils'; import { I18nConfig } from './config'; @@ -112,7 +111,7 @@ export function verifyMessages( if (defaultMessage) { try { const message = localizedMessagesMap.get(messageId)!; - verifyICUMessage(message); + verifyICUMessage(typeof message === 'string' ? message : message?.text); } catch (err) { if (options.ignoreMalformed) { localizedMessagesMap.delete(messageId); diff --git a/src/dev/i18n/__snapshots__/utils.test.js.snap b/src/dev/i18n/utils/__snapshots__/utils.test.js.snap similarity index 95% rename from src/dev/i18n/__snapshots__/utils.test.js.snap rename to src/dev/i18n/utils/__snapshots__/utils.test.js.snap index b4e15304cca96..147ef5987c1dc 100644 --- a/src/dev/i18n/__snapshots__/utils.test.js.snap +++ b/src/dev/i18n/utils/__snapshots__/utils.test.js.snap @@ -9,7 +9,7 @@ exports[`i18n utils should create verbose parser error message 1`] = ` " `; -exports[`i18n utils should normalizePath 1`] = `"src/dev/i18n"`; +exports[`i18n utils should normalizePath 1`] = `"src/dev/i18n/utils"`; exports[`i18n utils should not escape linebreaks 1`] = ` "Text diff --git a/src/dev/i18n/utils/index.ts b/src/dev/i18n/utils/index.ts new file mode 100644 index 0000000000000..3f81ab2ca66c3 --- /dev/null +++ b/src/dev/i18n/utils/index.ts @@ -0,0 +1,48 @@ +/* + * 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 { + // constants + readFileAsync, + writeFileAsync, + makeDirAsync, + accessAsync, + globAsync, + // functions + normalizePath, + difference, + isPropertyWithKey, + isI18nTranslateFunction, + node, + formatJSString, + formatHTMLString, + traverseNodes, + createParserErrorMessage, + checkValuesProperty, + extractValueReferencesFromMessage, + extractMessageIdFromNode, + extractMessageValueFromNode, + extractDescriptionValueFromNode, + extractValuesKeysFromNode, + arrayify, + // classes + ErrorReporter, // @ts-ignore +} from './utils'; + +export { verifyICUMessage } from './verify_icu_message'; diff --git a/src/dev/i18n/utils/intl_types.ts b/src/dev/i18n/utils/intl_types.ts new file mode 100644 index 0000000000000..adbceaea66540 --- /dev/null +++ b/src/dev/i18n/utils/intl_types.ts @@ -0,0 +1,41 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export interface OptionalFormatPatternNode { + type: 'optionalFormatPattern'; + selector: string; + value: any; +} + +export interface LinePosition { + offset: number; + line: number; + column: number; +} + +export interface LocationNode { + start: LinePosition; + end: LinePosition; +} + +export interface SelectFormatNode { + type: 'selectFormat'; + options: OptionalFormatPatternNode[]; + location: LocationNode; +} diff --git a/src/dev/i18n/utils.js b/src/dev/i18n/utils/utils.js similarity index 95% rename from src/dev/i18n/utils.js rename to src/dev/i18n/utils/utils.js index 11a002fdbf4a8..1d1c3118e0852 100644 --- a/src/dev/i18n/utils.js +++ b/src/dev/i18n/utils/utils.js @@ -208,28 +208,6 @@ export function checkValuesProperty(prefixedValuesKeys, defaultMessage, messageI } } -/** - * Verifies valid ICU message. - * @param message ICU message. - * @param messageId ICU message id - * @returns {undefined} - */ -export function verifyICUMessage(message) { - try { - parser.parse(message); - } catch (error) { - if (error.name === 'SyntaxError') { - const errorWithContext = createParserErrorMessage(message, { - loc: { - line: error.location.start.line, - column: error.location.start.column - 1, - }, - message: error.message, - }); - throw errorWithContext; - } - } -} /** * Extracts value references from the ICU message. * @param message ICU message. diff --git a/src/dev/i18n/utils.test.js b/src/dev/i18n/utils/utils.test.js similarity index 100% rename from src/dev/i18n/utils.test.js rename to src/dev/i18n/utils/utils.test.js diff --git a/src/dev/i18n/utils/verify_icu_message.test.ts b/src/dev/i18n/utils/verify_icu_message.test.ts new file mode 100644 index 0000000000000..0a4510352c429 --- /dev/null +++ b/src/dev/i18n/utils/verify_icu_message.test.ts @@ -0,0 +1,91 @@ +/* + * 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 { verifyICUMessage, checkEnglishOnly } from './verify_icu_message'; + +describe('verifyICUMessage', () => { + it('passes on plain text', () => { + const message = 'plain text here'; + expect(() => verifyICUMessage(message)).not.toThrowError(); + }); + + it('passes on empty string', () => { + const message = ''; + expect(() => verifyICUMessage(message)).not.toThrowError(); + }); + + it('passes on variable icu-syntax', () => { + const message = 'Your regular {foobar}'; + expect(() => verifyICUMessage(message)).not.toThrowError(); + }); + + it('passes on correct plural icu-syntax', () => { + const message = `You have {itemCount, plural, + =0 {no items} + one {1 item} + other {{itemCount} items} + }.`; + + expect(() => verifyICUMessage(message)).not.toThrowError(); + }); + + it('throws on malformed string', () => { + const message = + 'CDATA[extended_bounds設定を使用すると、強制的にヒストグラムアグリゲーションを実行し、特定の最小値に対してバケットの作成を開始し、最大値までバケットを作成し続けます。 ]]>\n\t\t\tKibana-SW - String "data.search.aggs.buckets.dateHistogram.extendedBounds.help" in Json.Root "messages\\strings" '; + + expect(() => verifyICUMessage(message)).toThrowError(); + }); + + it('throws on missing curly brackets', () => { + const message = `A missing {curly`; + + expect(() => verifyICUMessage(message)).toThrowError(); + }); + + it('throws on incorrect plural icu-syntax', () => { + // Notice that small/Medium/Large constants are swapped with the translation strings. + const message = + '{textScale, select, small {小さい} 中くらい {Medium} 大きい {Large} その他の {{textScale}} }'; + + expect(() => verifyICUMessage(message)).toThrowError(); + }); +}); + +describe('checkEnglishOnly', () => { + it('returns true on english only message', () => { + const result = checkEnglishOnly('english'); + + expect(result).toEqual(true); + }); + it('returns true on empty message', () => { + const result = checkEnglishOnly(''); + + expect(result).toEqual(true); + }); + it('returns false on message containing numbers', () => { + const result = checkEnglishOnly('english 123'); + + expect(result).toEqual(false); + }); + it('returns false on message containing non-english alphabets', () => { + const result = checkEnglishOnly('i am 大きい'); + + expect(result).toEqual(false); + }); +}); diff --git a/src/dev/i18n/utils/verify_icu_message.ts b/src/dev/i18n/utils/verify_icu_message.ts new file mode 100644 index 0000000000000..683d91c5c4939 --- /dev/null +++ b/src/dev/i18n/utils/verify_icu_message.ts @@ -0,0 +1,74 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// @ts-ignore +import parser from 'intl-messageformat-parser'; +// @ts-ignore +import { createParserErrorMessage, traverseNodes } from './utils'; +import { SelectFormatNode } from './intl_types'; + +export function checkEnglishOnly(message: string) { + return /^[a-z]*$/i.test(message); +} + +export function verifySelectFormatNode(node: SelectFormatNode) { + if (node.type !== 'selectFormat') { + throw new parser.SyntaxError( + 'Unable to verify select format icu-syntax', + 'selectFormat', + node.type, + node.location + ); + } + + for (const option of node.options) { + if (option.type === 'optionalFormatPattern') { + if (!checkEnglishOnly(option.selector)) { + throw new parser.SyntaxError( + 'selectFormat Selector must be in english', + 'English only selector', + option.selector, + node.location + ); + } + } + } +} + +export function verifyICUMessage(message: string) { + try { + const results = parser.parse(message); + for (const node of results.elements) { + if (node.type === 'argumentElement' && node.format?.type === 'selectFormat') { + verifySelectFormatNode(node.format); + } + } + } catch (error) { + if (error.name === 'SyntaxError') { + const errorWithContext = createParserErrorMessage(message, { + loc: { + line: error.location.start.line, + column: error.location.start.column - 1, + }, + message: error.message, + }); + throw errorWithContext; + } + } +} diff --git a/src/dev/run_i18n_check.ts b/src/dev/run_i18n_check.ts index 70eeedac2b8b6..17f3fd5d1c734 100644 --- a/src/dev/run_i18n_check.ts +++ b/src/dev/run_i18n_check.ts @@ -30,7 +30,8 @@ import { mergeConfigs, } from './i18n/tasks'; -const skipNoTranslations = ({ config }: { config: I18nConfig }) => !config.translations.length; +const skipOnNoTranslations = ({ config }: { config: I18nConfig }) => + !config.translations.length && 'No translations found.'; run( async ({ @@ -40,6 +41,7 @@ run( 'ignore-missing': ignoreMissing, 'ignore-unused': ignoreUnused, 'include-config': includeConfig, + 'ignore-untracked': ignoreUntracked, fix = false, path, }, @@ -50,12 +52,13 @@ run( (ignoreIncompatible !== undefined || ignoreUnused !== undefined || ignoreMalformed !== undefined || - ignoreMissing !== undefined) + ignoreMissing !== undefined || + ignoreUntracked !== undefined) ) { throw createFailError( `${chalk.white.bgRed( ' I18N ERROR ' - )} none of the --ignore-incompatible, --ignore-malformed, --ignore-unused or --ignore-missing is allowed when --fix is set.` + )} none of the --ignore-incompatible, --ignore-malformed, --ignore-unused or --ignore-missing, --ignore-untracked is allowed when --fix is set.` ); } @@ -83,19 +86,20 @@ run( }, { title: 'Checking For Untracked Messages based on .i18nrc.json', - skip: skipNoTranslations, + enabled: (_) => !ignoreUntracked, + skip: skipOnNoTranslations, task: ({ config }) => new Listr(extractUntrackedMessages(srcPaths), { exitOnError: true }), }, { title: 'Validating Default Messages', - skip: skipNoTranslations, + skip: skipOnNoTranslations, task: ({ config }) => new Listr(extractDefaultMessages(config, srcPaths), { exitOnError: true }), }, { title: 'Compatibility Checks', - skip: skipNoTranslations, + skip: skipOnNoTranslations, task: ({ config }) => new Listr( checkCompatibility( diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 81c06cf5c381f..526f2d88574d3 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -4852,7 +4852,6 @@ "xpack.apm.jvmsTable.nonHeapMemoryColumnLabel": "非ヒープ領域の平均", "xpack.apm.jvmsTable.threadCountColumnLabel": "最大スレッド数", "xpack.apm.kueryBar.disabledPlaceholder": "ここでは検索は利用できません", - "xpack.apm.kueryBar.placeholder": "検索 {event, select,\n トランザクション {transactions}\n メトリック: {metric}\n エラー {errors}\n その他 {transactions, errors and metrics}\n } (E.g. {queryExample})", "xpack.apm.license.betaBadge": "ベータ", "xpack.apm.license.betaTooltipMessage": "現在、この機能はベータです。不具合を見つけた場合やご意見がある場合、サポートに問い合わせるか、またはディスカッションフォーラムにご報告ください。", "xpack.apm.license.button": "トライアルを開始", From a8ed1f4b16a0be6879f4b212df0eae6890acba75 Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Thu, 13 Aug 2020 14:33:27 -0700 Subject: [PATCH 29/53] [Reporting] Update more Server Types for TaskManager (#74915) * [Reporting] Update more Server Types for TaskManager * remove some task manager references * more strict * more strict 2 * simplify * fix test * fix test * routing validation unused types cleanup * remove more casting in route handlers * feedback changes * original comment was fine Co-authored-by: Elastic Machine --- x-pack/plugins/reporting/server/core.ts | 8 +- .../server/export_types/csv/create_job.ts | 4 +- .../export_types/csv/execute_job.test.ts | 112 +++---- .../server/export_types/csv/execute_job.ts | 4 +- .../export_types/csv/generate_csv/index.ts | 4 + .../server/export_types/csv/index.ts | 8 +- .../server/export_types/csv/types.d.ts | 6 +- .../csv_from_savedobject/execute_job.ts | 2 +- .../export_types/png/create_job/index.ts | 4 +- .../export_types/png/execute_job/index.ts | 4 +- .../server/export_types/png/index.ts | 8 +- .../server/export_types/png/types.d.ts | 7 +- .../printable_pdf/create_job/index.ts | 6 +- .../printable_pdf/execute_job/index.ts | 4 +- .../export_types/printable_pdf/index.ts | 8 +- .../export_types/printable_pdf/types.d.ts | 6 +- .../reporting/server/lib/create_worker.ts | 6 +- .../reporting/server/lib/enqueue_job.ts | 38 ++- .../server/lib/esqueue/constants/index.js | 4 +- .../reporting/server/lib/esqueue/worker.js | 48 +-- x-pack/plugins/reporting/server/lib/index.ts | 3 +- .../lib/{esqueue/constants => }/statuses.ts | 0 .../reporting/server/lib/store/mapping.ts | 2 +- .../reporting/server/lib/store/report.test.ts | 113 +++++-- .../reporting/server/lib/store/report.ts | 144 +++++++-- .../reporting/server/lib/store/store.test.ts | 304 ++++++++++++++---- .../reporting/server/lib/store/store.ts | 194 +++++++---- x-pack/plugins/reporting/server/plugin.ts | 10 +- .../server/routes/generate_from_jobparams.ts | 15 +- .../generate_from_savedobject_immediate.ts | 10 +- .../server/routes/generation.test.ts | 3 +- .../reporting/server/routes/generation.ts | 10 +- .../server/routes/lib/get_document_payload.ts | 7 +- .../routes/lib/get_job_params_from_request.ts | 16 +- .../reporting/server/routes/types.d.ts | 4 +- .../create_mock_reportingplugin.ts | 19 +- x-pack/plugins/reporting/server/types.ts | 44 +-- 37 files changed, 774 insertions(+), 415 deletions(-) rename x-pack/plugins/reporting/server/lib/{esqueue/constants => }/statuses.ts (100%) diff --git a/x-pack/plugins/reporting/server/core.ts b/x-pack/plugins/reporting/server/core.ts index 95dc7586ad4a6..25594e1c0140b 100644 --- a/x-pack/plugins/reporting/server/core.ts +++ b/x-pack/plugins/reporting/server/core.ts @@ -23,7 +23,6 @@ import { HeadlessChromiumDriverFactory } from './browsers/chromium/driver_factor import { screenshotsObservableFactory } from './lib/screenshots'; import { checkLicense, getExportTypesRegistry } from './lib'; import { ESQueueInstance } from './lib/create_queue'; -import { EnqueueJobFn } from './lib/enqueue_job'; import { ReportingStore } from './lib/store'; export interface ReportingInternalSetup { @@ -36,7 +35,6 @@ export interface ReportingInternalSetup { export interface ReportingInternalStart { browserDriverFactory: HeadlessChromiumDriverFactory; - enqueueJob: EnqueueJobFn; esqueue: ESQueueInstance; store: ReportingStore; savedObjects: SavedObjectsServiceStart; @@ -115,7 +113,7 @@ export class ReportingCore { /* * Gives async access to the startDeps */ - private async getPluginStartDeps() { + public async getPluginStartDeps() { if (this.pluginStartDeps) { return this.pluginStartDeps; } @@ -131,10 +129,6 @@ export class ReportingCore { return (await this.getPluginStartDeps()).esqueue; } - public async getEnqueueJob() { - return (await this.getPluginStartDeps()).enqueueJob; - } - public async getLicenseInfo() { const { licensing } = this.getPluginSetupDeps(); return await licensing.license$ diff --git a/x-pack/plugins/reporting/server/export_types/csv/create_job.ts b/x-pack/plugins/reporting/server/export_types/csv/create_job.ts index 5e8ce923a79e0..252968e386b53 100644 --- a/x-pack/plugins/reporting/server/export_types/csv/create_job.ts +++ b/x-pack/plugins/reporting/server/export_types/csv/create_job.ts @@ -5,10 +5,10 @@ */ import { cryptoFactory } from '../../lib'; -import { ESQueueCreateJobFn, ScheduleTaskFnFactory } from '../../types'; +import { CreateJobFn, ScheduleTaskFnFactory } from '../../types'; import { JobParamsDiscoverCsv } from './types'; -export const scheduleTaskFnFactory: ScheduleTaskFnFactory> = function createJobFactoryFn(reporting) { const config = reporting.getConfig(); diff --git a/x-pack/plugins/reporting/server/export_types/csv/execute_job.test.ts b/x-pack/plugins/reporting/server/export_types/csv/execute_job.test.ts index 75070c06824e2..5eeef0f9906dd 100644 --- a/x-pack/plugins/reporting/server/export_types/csv/execute_job.test.ts +++ b/x-pack/plugins/reporting/server/export_types/csv/execute_job.test.ts @@ -5,7 +5,7 @@ */ import nodeCrypto from '@elastic/node-crypto'; -import { IUiSettingsClient, ElasticsearchServiceSetup } from 'kibana/server'; +import { ElasticsearchServiceSetup, IUiSettingsClient } from 'kibana/server'; // @ts-ignore import Puid from 'puid'; import sinon from 'sinon'; @@ -20,8 +20,8 @@ import { CSV_BOM_CHARS } from '../../../common/constants'; import { LevelLogger } from '../../lib'; import { setFieldFormats } from '../../services'; import { createMockReportingCore } from '../../test_helpers'; -import { ScheduledTaskParamsCSV } from './types'; import { runTaskFnFactory } from './execute_job'; +import { ScheduledTaskParamsCSV } from './types'; const delay = (ms: number) => new Promise((resolve) => setTimeout(() => resolve(), ms)); @@ -125,7 +125,7 @@ describe('CSV Execute Job', function () { describe('basic Elasticsearch call behavior', function () { it('should decrypt encrypted headers and pass to callAsCurrentUser', async function () { - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); await runTask( 'job456', getScheduledTaskParams({ @@ -145,7 +145,7 @@ describe('CSV Execute Job', function () { testBody: true, }; - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const job = getScheduledTaskParams({ headers: encryptedHeaders, fields: [], @@ -172,7 +172,7 @@ describe('CSV Execute Job', function () { _scroll_id: scrollId, }); callAsCurrentUserStub.onSecondCall().resolves(defaultElasticsearchResponse); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); await runTask( 'job456', getScheduledTaskParams({ @@ -190,7 +190,7 @@ describe('CSV Execute Job', function () { }); it('should not execute scroll if there are no hits from the search', async function () { - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); await runTask( 'job456', getScheduledTaskParams({ @@ -224,7 +224,7 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); await runTask( 'job456', getScheduledTaskParams({ @@ -263,7 +263,7 @@ describe('CSV Execute Job', function () { _scroll_id: lastScrollId, }); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); await runTask( 'job456', getScheduledTaskParams({ @@ -295,7 +295,7 @@ describe('CSV Execute Job', function () { _scroll_id: lastScrollId, }); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], @@ -322,7 +322,7 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], @@ -347,7 +347,7 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['=SUM(A1:A2)', 'two'], @@ -373,7 +373,7 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], @@ -399,7 +399,7 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['=SUM(A1:A2)', 'two'], @@ -425,7 +425,7 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], @@ -452,7 +452,7 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], @@ -473,7 +473,7 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], @@ -496,7 +496,7 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], @@ -517,7 +517,7 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], @@ -533,7 +533,7 @@ describe('CSV Execute Job', function () { describe('Elasticsearch call errors', function () { it('should reject Promise if search call errors out', async function () { callAsCurrentUserStub.rejects(new Error()); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: [], @@ -552,7 +552,7 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); callAsCurrentUserStub.onSecondCall().rejects(new Error()); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: [], @@ -573,7 +573,7 @@ describe('CSV Execute Job', function () { _scroll_id: undefined, }); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: [], @@ -592,7 +592,7 @@ describe('CSV Execute Job', function () { _scroll_id: undefined, }); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: [], @@ -618,7 +618,7 @@ describe('CSV Execute Job', function () { _scroll_id: undefined, }); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: [], @@ -644,7 +644,7 @@ describe('CSV Execute Job', function () { _scroll_id: undefined, }); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: [], @@ -678,7 +678,7 @@ describe('CSV Execute Job', function () { }); it('should stop calling Elasticsearch when cancellationToken.cancel is called', async function () { - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); runTask( 'job345', getScheduledTaskParams({ @@ -697,7 +697,7 @@ describe('CSV Execute Job', function () { }); it(`shouldn't call clearScroll if it never got a scrollId`, async function () { - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); runTask( 'job345', getScheduledTaskParams({ @@ -715,7 +715,7 @@ describe('CSV Execute Job', function () { }); it('should call clearScroll if it got a scrollId', async function () { - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); runTask( 'job345', getScheduledTaskParams({ @@ -737,7 +737,7 @@ describe('CSV Execute Job', function () { describe('csv content', function () { it('should write column headers to output, even if there are no results', async function () { - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], @@ -749,7 +749,7 @@ describe('CSV Execute Job', function () { it('should use custom uiSettings csv:separator for header', async function () { mockUiSettingsClient.get.withArgs(CSV_SEPARATOR_SETTING).returns(';'); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], @@ -761,7 +761,7 @@ describe('CSV Execute Job', function () { it('should escape column headers if uiSettings csv:quoteValues is true', async function () { mockUiSettingsClient.get.withArgs(CSV_QUOTE_VALUES_SETTING).returns(true); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one and a half', 'two', 'three-and-four', 'five & six'], @@ -773,7 +773,7 @@ describe('CSV Execute Job', function () { it(`shouldn't escape column headers if uiSettings csv:quoteValues is false`, async function () { mockUiSettingsClient.get.withArgs(CSV_QUOTE_VALUES_SETTING).returns(false); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one and a half', 'two', 'three-and-four', 'five & six'], @@ -784,7 +784,7 @@ describe('CSV Execute Job', function () { }); it('should write column headers to output, when there are results', async function () { - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); callAsCurrentUserStub.onFirstCall().resolves({ hits: { hits: [{ one: '1', two: '2' }], @@ -798,13 +798,14 @@ describe('CSV Execute Job', function () { searchRequest: { index: null, body: null }, }); const { content } = await runTask('job123', jobParams, cancellationToken); - const lines = content.split('\n'); + expect(content).not.toBe(null); + const lines = content!.split('\n'); const headerLine = lines[0]; expect(headerLine).toBe('one,two'); }); it('should use comma separated values of non-nested fields from _source', async function () { - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); callAsCurrentUserStub.onFirstCall().resolves({ hits: { hits: [{ _source: { one: 'foo', two: 'bar' } }], @@ -819,13 +820,14 @@ describe('CSV Execute Job', function () { searchRequest: { index: null, body: null }, }); const { content } = await runTask('job123', jobParams, cancellationToken); - const lines = content.split('\n'); + expect(content).not.toBe(null); + const lines = content!.split('\n'); const valuesLine = lines[1]; expect(valuesLine).toBe('foo,bar'); }); it('should concatenate the hits from multiple responses', async function () { - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); callAsCurrentUserStub.onFirstCall().resolves({ hits: { hits: [{ _source: { one: 'foo', two: 'bar' } }], @@ -846,14 +848,15 @@ describe('CSV Execute Job', function () { searchRequest: { index: null, body: null }, }); const { content } = await runTask('job123', jobParams, cancellationToken); - const lines = content.split('\n'); + expect(content).not.toBe(null); + const lines = content!.split('\n'); expect(lines[1]).toBe('foo,bar'); expect(lines[2]).toBe('baz,qux'); }); it('should use field formatters to format fields', async function () { - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); callAsCurrentUserStub.onFirstCall().resolves({ hits: { hits: [{ _source: { one: 'foo', two: 'bar' } }], @@ -877,7 +880,8 @@ describe('CSV Execute Job', function () { }, }); const { content } = await runTask('job123', jobParams, cancellationToken); - const lines = content.split('\n'); + expect(content).not.toBe(null); + const lines = content!.split('\n'); expect(lines[1]).toBe('FOO,bar'); }); @@ -889,13 +893,13 @@ describe('CSV Execute Job', function () { // tests use these 'simple' characters to make the math easier describe('when only the headers exceed the maxSizeBytes', function () { - let content: string; - let maxSizeReached: boolean; + let content: string | null; + let maxSizeReached: boolean | undefined; beforeEach(async function () { configGetStub.withArgs('csv', 'maxSizeBytes').returns(1); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], @@ -919,13 +923,13 @@ describe('CSV Execute Job', function () { }); describe('when headers are equal to maxSizeBytes', function () { - let content: string; - let maxSizeReached: boolean; + let content: string | null; + let maxSizeReached: boolean | undefined; beforeEach(async function () { configGetStub.withArgs('csv', 'maxSizeBytes').returns(9); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], @@ -949,8 +953,8 @@ describe('CSV Execute Job', function () { }); describe('when the data exceeds the maxSizeBytes', function () { - let content: string; - let maxSizeReached: boolean; + let content: string | null; + let maxSizeReached: boolean | undefined; beforeEach(async function () { configGetStub.withArgs('csv', 'maxSizeBytes').returns(9); @@ -962,7 +966,7 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], @@ -987,8 +991,8 @@ describe('CSV Execute Job', function () { }); describe('when headers and data equal the maxSizeBytes', function () { - let content: string; - let maxSizeReached: boolean; + let content: string | null; + let maxSizeReached: boolean | undefined; beforeEach(async function () { mockReportingCore.getUiSettingsServiceFactory = () => @@ -1002,7 +1006,7 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], @@ -1039,7 +1043,7 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], @@ -1065,7 +1069,7 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], @@ -1091,7 +1095,7 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const runTask = runTaskFnFactory(mockReportingCore, mockLogger); const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], diff --git a/x-pack/plugins/reporting/server/export_types/csv/execute_job.ts b/x-pack/plugins/reporting/server/export_types/csv/execute_job.ts index f0c41a6a49703..802f4a81777c5 100644 --- a/x-pack/plugins/reporting/server/export_types/csv/execute_job.ts +++ b/x-pack/plugins/reporting/server/export_types/csv/execute_job.ts @@ -10,7 +10,7 @@ import Hapi from 'hapi'; import { KibanaRequest } from '../../../../../../src/core/server'; import { CONTENT_TYPE_CSV, CSV_JOB_TYPE } from '../../../common/constants'; import { cryptoFactory, LevelLogger } from '../../lib'; -import { ESQueueWorkerExecuteFn, RunTaskFnFactory } from '../../types'; +import { WorkerExecuteFn, RunTaskFnFactory } from '../../types'; import { ScheduledTaskParamsCSV } from './types'; import { createGenerateCsv } from './generate_csv'; @@ -54,7 +54,7 @@ const getRequest = async (headers: string | undefined, crypto: Crypto, logger: L } as Hapi.Request); }; -export const runTaskFnFactory: RunTaskFnFactory> = function executeJobFactoryFn(reporting, parentLogger) { const config = reporting.getConfig(); diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/index.ts b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/index.ts index 8da27100ac31c..06aa2434afc3f 100644 --- a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/index.ts +++ b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/index.ts @@ -113,6 +113,10 @@ export function createGenerateCsv(logger: LevelLogger) { break; } + if (cancellationToken.isCancelled()) { + break; + } + const flattened = flattenHit(hit); const rows = formatCsvValues(flattened); const rowsHaveFormulas = diff --git a/x-pack/plugins/reporting/server/export_types/csv/index.ts b/x-pack/plugins/reporting/server/export_types/csv/index.ts index dffc874831dc2..4bca42e0661e5 100644 --- a/x-pack/plugins/reporting/server/export_types/csv/index.ts +++ b/x-pack/plugins/reporting/server/export_types/csv/index.ts @@ -13,17 +13,17 @@ import { LICENSE_TYPE_TRIAL, } from '../../../common/constants'; import { CSV_JOB_TYPE as jobType } from '../../../constants'; -import { ESQueueCreateJobFn, ESQueueWorkerExecuteFn, ExportTypeDefinition } from '../../types'; -import { metadata } from './metadata'; +import { CreateJobFn, WorkerExecuteFn, ExportTypeDefinition } from '../../types'; import { scheduleTaskFnFactory } from './create_job'; import { runTaskFnFactory } from './execute_job'; +import { metadata } from './metadata'; import { JobParamsDiscoverCsv, ScheduledTaskParamsCSV } from './types'; export const getExportType = (): ExportTypeDefinition< JobParamsDiscoverCsv, - ESQueueCreateJobFn, + CreateJobFn, ScheduledTaskParamsCSV, - ESQueueWorkerExecuteFn + WorkerExecuteFn > => ({ ...metadata, jobType, diff --git a/x-pack/plugins/reporting/server/export_types/csv/types.d.ts b/x-pack/plugins/reporting/server/export_types/csv/types.d.ts index 9e86a5bb254a3..e0d09d04a3d3a 100644 --- a/x-pack/plugins/reporting/server/export_types/csv/types.d.ts +++ b/x-pack/plugins/reporting/server/export_types/csv/types.d.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ScheduledTaskParams } from '../../types'; +import { CreateJobBaseParams, ScheduledTaskParams } from '../../types'; export type RawValue = string | object | null | undefined; @@ -28,10 +28,8 @@ export interface IndexPatternSavedObject { }; } -export interface JobParamsDiscoverCsv { - browserTimezone: string; +export interface JobParamsDiscoverCsv extends CreateJobBaseParams { indexPatternId: string; - objectType: string; title: string; searchRequest: SearchRequest; fields: string[]; diff --git a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/execute_job.ts b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/execute_job.ts index 0cc9ec16ed71b..ec7e0a21f0498 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/execute_job.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/execute_job.ts @@ -41,7 +41,7 @@ export const runTaskFnFactory: RunTaskFnFactory = function e // jobID is only for "queued" jobs // Use the jobID as a logging tag or "immediate" const { jobParams } = jobPayload; - const jobLogger = logger.clone([jobId === null ? 'immediate' : jobId]); + const jobLogger = logger.clone(['immediate']); const generateCsv = createGenerateCsv(jobLogger); const { panel, visType } = jobParams as JobParamsPanelCsv & { panel: SearchPanel }; diff --git a/x-pack/plugins/reporting/server/export_types/png/create_job/index.ts b/x-pack/plugins/reporting/server/export_types/png/create_job/index.ts index 9227354520b6e..2252177e98085 100644 --- a/x-pack/plugins/reporting/server/export_types/png/create_job/index.ts +++ b/x-pack/plugins/reporting/server/export_types/png/create_job/index.ts @@ -5,11 +5,11 @@ */ import { cryptoFactory } from '../../../lib'; -import { ESQueueCreateJobFn, ScheduleTaskFnFactory } from '../../../types'; +import { CreateJobFn, ScheduleTaskFnFactory } from '../../../types'; import { validateUrls } from '../../common'; import { JobParamsPNG } from '../types'; -export const scheduleTaskFnFactory: ScheduleTaskFnFactory> = function createJobFactoryFn(reporting) { const config = reporting.getConfig(); diff --git a/x-pack/plugins/reporting/server/export_types/png/execute_job/index.ts b/x-pack/plugins/reporting/server/export_types/png/execute_job/index.ts index 9c7134736f4f6..35cd4139df413 100644 --- a/x-pack/plugins/reporting/server/export_types/png/execute_job/index.ts +++ b/x-pack/plugins/reporting/server/export_types/png/execute_job/index.ts @@ -8,7 +8,7 @@ import apm from 'elastic-apm-node'; import * as Rx from 'rxjs'; import { catchError, map, mergeMap, takeUntil } from 'rxjs/operators'; import { PNG_JOB_TYPE } from '../../../../common/constants'; -import { ESQueueWorkerExecuteFn, RunTaskFnFactory, TaskRunResult } from '../../..//types'; +import { WorkerExecuteFn, RunTaskFnFactory, TaskRunResult } from '../../..//types'; import { decryptJobHeaders, getConditionalHeaders, @@ -18,7 +18,7 @@ import { import { generatePngObservableFactory } from '../lib/generate_png'; import { ScheduledTaskParamsPNG } from '../types'; -type QueuedPngExecutorFactory = RunTaskFnFactory>; +type QueuedPngExecutorFactory = RunTaskFnFactory>; export const runTaskFnFactory: QueuedPngExecutorFactory = function executeJobFactoryFn( reporting, diff --git a/x-pack/plugins/reporting/server/export_types/png/index.ts b/x-pack/plugins/reporting/server/export_types/png/index.ts index 25b4dbd60535b..c966dedb6b076 100644 --- a/x-pack/plugins/reporting/server/export_types/png/index.ts +++ b/x-pack/plugins/reporting/server/export_types/png/index.ts @@ -12,17 +12,17 @@ import { LICENSE_TYPE_TRIAL, PNG_JOB_TYPE as jobType, } from '../../../common/constants'; -import { ESQueueCreateJobFn, ESQueueWorkerExecuteFn, ExportTypeDefinition } from '../../types'; -import { metadata } from './metadata'; +import { CreateJobFn, WorkerExecuteFn, ExportTypeDefinition } from '../../types'; import { scheduleTaskFnFactory } from './create_job'; import { runTaskFnFactory } from './execute_job'; +import { metadata } from './metadata'; import { JobParamsPNG, ScheduledTaskParamsPNG } from './types'; export const getExportType = (): ExportTypeDefinition< JobParamsPNG, - ESQueueCreateJobFn, + CreateJobFn, ScheduledTaskParamsPNG, - ESQueueWorkerExecuteFn + WorkerExecuteFn > => ({ ...metadata, jobType, diff --git a/x-pack/plugins/reporting/server/export_types/png/types.d.ts b/x-pack/plugins/reporting/server/export_types/png/types.d.ts index 4c40f55f0f0d6..1ddee8419df30 100644 --- a/x-pack/plugins/reporting/server/export_types/png/types.d.ts +++ b/x-pack/plugins/reporting/server/export_types/png/types.d.ts @@ -4,16 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ScheduledTaskParams } from '../../../server/types'; +import { CreateJobBaseParams, ScheduledTaskParams } from '../../../server/types'; import { LayoutInstance, LayoutParams } from '../../lib/layouts'; // Job params: structure of incoming user request data -export interface JobParamsPNG { - objectType: string; +export interface JobParamsPNG extends CreateJobBaseParams { title: string; relativeUrl: string; - browserTimezone: string; - layout: LayoutInstance; } // Job payload: structure of stored job data provided by create_job diff --git a/x-pack/plugins/reporting/server/export_types/printable_pdf/create_job/index.ts b/x-pack/plugins/reporting/server/export_types/printable_pdf/create_job/index.ts index 4540983129ebc..5de089a13bfa4 100644 --- a/x-pack/plugins/reporting/server/export_types/printable_pdf/create_job/index.ts +++ b/x-pack/plugins/reporting/server/export_types/printable_pdf/create_job/index.ts @@ -4,12 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { validateUrls } from '../../common'; import { cryptoFactory } from '../../../lib'; -import { ESQueueCreateJobFn, ScheduleTaskFnFactory } from '../../../types'; +import { CreateJobFn, ScheduleTaskFnFactory } from '../../../types'; +import { validateUrls } from '../../common'; import { JobParamsPDF } from '../types'; -export const scheduleTaskFnFactory: ScheduleTaskFnFactory> = function createJobFactoryFn(reporting) { const config = reporting.getConfig(); diff --git a/x-pack/plugins/reporting/server/export_types/printable_pdf/execute_job/index.ts b/x-pack/plugins/reporting/server/export_types/printable_pdf/execute_job/index.ts index eb15c0a71ca3f..5ace1c987adb5 100644 --- a/x-pack/plugins/reporting/server/export_types/printable_pdf/execute_job/index.ts +++ b/x-pack/plugins/reporting/server/export_types/printable_pdf/execute_job/index.ts @@ -8,7 +8,7 @@ import apm from 'elastic-apm-node'; import * as Rx from 'rxjs'; import { catchError, map, mergeMap, takeUntil } from 'rxjs/operators'; import { PDF_JOB_TYPE } from '../../../../common/constants'; -import { ESQueueWorkerExecuteFn, RunTaskFnFactory, TaskRunResult } from '../../../types'; +import { WorkerExecuteFn, RunTaskFnFactory, TaskRunResult } from '../../../types'; import { decryptJobHeaders, getConditionalHeaders, @@ -19,7 +19,7 @@ import { import { generatePdfObservableFactory } from '../lib/generate_pdf'; import { ScheduledTaskParamsPDF } from '../types'; -type QueuedPdfExecutorFactory = RunTaskFnFactory>; +type QueuedPdfExecutorFactory = RunTaskFnFactory>; export const runTaskFnFactory: QueuedPdfExecutorFactory = function executeJobFactoryFn( reporting, diff --git a/x-pack/plugins/reporting/server/export_types/printable_pdf/index.ts b/x-pack/plugins/reporting/server/export_types/printable_pdf/index.ts index e5115c243c697..7f21d36c4b72c 100644 --- a/x-pack/plugins/reporting/server/export_types/printable_pdf/index.ts +++ b/x-pack/plugins/reporting/server/export_types/printable_pdf/index.ts @@ -12,17 +12,17 @@ import { LICENSE_TYPE_TRIAL, PDF_JOB_TYPE as jobType, } from '../../../common/constants'; -import { ESQueueCreateJobFn, ESQueueWorkerExecuteFn, ExportTypeDefinition } from '../../types'; -import { metadata } from './metadata'; +import { CreateJobFn, WorkerExecuteFn, ExportTypeDefinition } from '../../types'; import { scheduleTaskFnFactory } from './create_job'; import { runTaskFnFactory } from './execute_job'; +import { metadata } from './metadata'; import { JobParamsPDF, ScheduledTaskParamsPDF } from './types'; export const getExportType = (): ExportTypeDefinition< JobParamsPDF, - ESQueueCreateJobFn, + CreateJobFn, ScheduledTaskParamsPDF, - ESQueueWorkerExecuteFn + WorkerExecuteFn > => ({ ...metadata, jobType, diff --git a/x-pack/plugins/reporting/server/export_types/printable_pdf/types.d.ts b/x-pack/plugins/reporting/server/export_types/printable_pdf/types.d.ts index cba0f41f07536..7830f87780c2e 100644 --- a/x-pack/plugins/reporting/server/export_types/printable_pdf/types.d.ts +++ b/x-pack/plugins/reporting/server/export_types/printable_pdf/types.d.ts @@ -4,15 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ScheduledTaskParams } from '../../../server/types'; +import { CreateJobBaseParams, ScheduledTaskParams } from '../../../server/types'; import { LayoutInstance, LayoutParams } from '../../lib/layouts'; // Job params: structure of incoming user request data, after being parsed from RISON -export interface JobParamsPDF { - objectType: string; // visualization, dashboard, etc. Used for job info & telemetry +export interface JobParamsPDF extends CreateJobBaseParams { title: string; relativeUrls: string[]; - browserTimezone: string; layout: LayoutInstance; } diff --git a/x-pack/plugins/reporting/server/lib/create_worker.ts b/x-pack/plugins/reporting/server/lib/create_worker.ts index 837be1f44a093..5b0f1ddb2f157 100644 --- a/x-pack/plugins/reporting/server/lib/create_worker.ts +++ b/x-pack/plugins/reporting/server/lib/create_worker.ts @@ -8,7 +8,7 @@ import { CancellationToken } from '../../common'; import { PLUGIN_ID } from '../../common/constants'; import { ReportingCore } from '../../server'; import { LevelLogger } from '../../server/lib'; -import { ESQueueWorkerExecuteFn, ExportTypeDefinition, JobSource } from '../../server/types'; +import { ExportTypeDefinition, JobSource, WorkerExecuteFn } from '../../server/types'; import { ESQueueInstance } from './create_queue'; // @ts-ignore untyped dependency import { events as esqueueEvents } from './esqueue'; @@ -22,10 +22,10 @@ export function createWorkerFactory(reporting: ReportingCore, log // Once more document types are added, this will need to be passed in return async function createWorker(queue: ESQueueInstance) { // export type / execute job map - const jobExecutors: Map> = new Map(); + const jobExecutors: Map> = new Map(); for (const exportType of reporting.getExportTypesRegistry().getAll() as Array< - ExportTypeDefinition> + ExportTypeDefinition> >) { const jobExecutor = exportType.runTaskFnFactory(reporting, logger); jobExecutors.set(exportType.jobType, jobExecutor); diff --git a/x-pack/plugins/reporting/server/lib/enqueue_job.ts b/x-pack/plugins/reporting/server/lib/enqueue_job.ts index d1554a03b9389..31960c782b7b9 100644 --- a/x-pack/plugins/reporting/server/lib/enqueue_job.ts +++ b/x-pack/plugins/reporting/server/lib/enqueue_job.ts @@ -5,15 +5,15 @@ */ import { KibanaRequest, RequestHandlerContext } from 'src/core/server'; +import { ReportingCore } from '../'; import { AuthenticatedUser } from '../../../security/server'; -import { ESQueueCreateJobFn } from '../../server/types'; -import { ReportingCore } from '../core'; +import { CreateJobBaseParams, CreateJobFn } from '../types'; import { LevelLogger } from './'; -import { ReportingStore, Report } from './store'; +import { Report } from './store'; export type EnqueueJobFn = ( exportTypeId: string, - jobParams: unknown, + jobParams: CreateJobBaseParams, user: AuthenticatedUser | null, context: RequestHandlerContext, request: KibanaRequest @@ -21,41 +21,39 @@ export type EnqueueJobFn = ( export function enqueueJobFactory( reporting: ReportingCore, - store: ReportingStore, parentLogger: LevelLogger ): EnqueueJobFn { - const config = reporting.getConfig(); - const queueTimeout = config.get('queue', 'timeout'); - const browserType = config.get('capture', 'browser', 'type'); - const maxAttempts = config.get('capture', 'maxAttempts'); const logger = parentLogger.clone(['queue-job']); return async function enqueueJob( exportTypeId: string, - jobParams: unknown, + jobParams: CreateJobBaseParams, user: AuthenticatedUser | null, context: RequestHandlerContext, request: KibanaRequest ) { - type ScheduleTaskFnType = ESQueueCreateJobFn; + type ScheduleTaskFnType = CreateJobFn; - const username = user ? user.username : false; + const username: string | null = user ? user.username : null; const exportType = reporting.getExportTypesRegistry().getById(exportTypeId); if (exportType == null) { throw new Error(`Export type ${exportTypeId} does not exist in the registry!`); } - const scheduleTask = exportType.scheduleTaskFnFactory(reporting, logger) as ScheduleTaskFnType; + const [scheduleTask, { store }] = await Promise.all([ + exportType.scheduleTaskFnFactory(reporting, logger) as ScheduleTaskFnType, + reporting.getPluginStartDeps(), + ]); + + // add encrytped headers const payload = await scheduleTask(jobParams, context, request); - const options = { - timeout: queueTimeout, - created_by: username, - browser_type: browserType, - max_attempts: maxAttempts, - }; + // store the pending report, puts it in the Reporting Management UI table + const report = await store.addReport(exportType.jobType, username, payload); + + logger.info(`Scheduled ${exportType.name} report: ${report._id}`); - return await store.addReport(exportType.jobType, payload, options); + return report; }; } diff --git a/x-pack/plugins/reporting/server/lib/esqueue/constants/index.js b/x-pack/plugins/reporting/server/lib/esqueue/constants/index.js index 5fcff3531851a..7f7383bb8611d 100644 --- a/x-pack/plugins/reporting/server/lib/esqueue/constants/index.js +++ b/x-pack/plugins/reporting/server/lib/esqueue/constants/index.js @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { events } from './events'; -import { statuses } from './statuses'; +import { statuses } from '../../statuses'; import { defaultSettings } from './default_settings'; +import { events } from './events'; export const constants = { ...events, diff --git a/x-pack/plugins/reporting/server/lib/esqueue/worker.js b/x-pack/plugins/reporting/server/lib/esqueue/worker.js index 469bafd694612..0c3a6384f6b9a 100644 --- a/x-pack/plugins/reporting/server/lib/esqueue/worker.js +++ b/x-pack/plugins/reporting/server/lib/esqueue/worker.js @@ -158,26 +158,18 @@ export class Worker extends events.EventEmitter { kibana_name: this.kibanaName, }; - return this.queue.store - .updateReport({ - index: job._index, - id: job._id, - if_seq_no: job._seq_no, - if_primary_term: job._primary_term, - body: { doc }, - }) - .then((response) => { - this.info(`Job marked as claimed: ${getUpdatedDocPath(response)}`); - const updatedJob = { - ...job, - ...response, - }; - updatedJob._source = { - ...job._source, - ...doc, - }; - return updatedJob; - }); + return this.queue.store.setReportClaimed(job, doc).then((response) => { + this.info(`Job marked as claimed: ${getUpdatedDocPath(response)}`); + const updatedJob = { + ...job, + ...response, + }; + updatedJob._source = { + ...job._source, + ...doc, + }; + return updatedJob; + }); } _failJob(job, output = false) { @@ -198,13 +190,7 @@ export class Worker extends events.EventEmitter { }); return this.queue.store - .updateReport({ - index: job._index, - id: job._id, - if_seq_no: job._seq_no, - if_primary_term: job._primary_term, - body: { doc }, - }) + .setReportFailed(job, doc) .then((response) => { this.info(`Job marked as failed: ${getUpdatedDocPath(response)}`); }) @@ -295,13 +281,7 @@ export class Worker extends events.EventEmitter { }; return this.queue.store - .updateReport({ - index: job._index, - id: job._id, - if_seq_no: job._seq_no, - if_primary_term: job._primary_term, - body: { doc }, - }) + .setReportCompleted(job, doc) .then((response) => { const eventOutput = { job: formatJobObject(job), diff --git a/x-pack/plugins/reporting/server/lib/index.ts b/x-pack/plugins/reporting/server/lib/index.ts index e4adb1188e3fc..f3a09cffbb104 100644 --- a/x-pack/plugins/reporting/server/lib/index.ts +++ b/x-pack/plugins/reporting/server/lib/index.ts @@ -8,8 +8,9 @@ export { checkLicense } from './check_license'; export { createQueueFactory } from './create_queue'; export { cryptoFactory } from './crypto'; export { enqueueJobFactory } from './enqueue_job'; -export { getExportTypesRegistry } from './export_types_registry'; +export { ExportTypesRegistry, getExportTypesRegistry } from './export_types_registry'; export { LevelLogger } from './level_logger'; +export { statuses } from './statuses'; export { ReportingStore } from './store'; export { startTrace } from './trace'; export { runValidations } from './validate'; diff --git a/x-pack/plugins/reporting/server/lib/esqueue/constants/statuses.ts b/x-pack/plugins/reporting/server/lib/statuses.ts similarity index 100% rename from x-pack/plugins/reporting/server/lib/esqueue/constants/statuses.ts rename to x-pack/plugins/reporting/server/lib/statuses.ts diff --git a/x-pack/plugins/reporting/server/lib/store/mapping.ts b/x-pack/plugins/reporting/server/lib/store/mapping.ts index a819923e2f105..d08b928cdca4b 100644 --- a/x-pack/plugins/reporting/server/lib/store/mapping.ts +++ b/x-pack/plugins/reporting/server/lib/store/mapping.ts @@ -45,7 +45,7 @@ export const mapping = { priority: { type: 'byte' }, timeout: { type: 'long' }, process_expiration: { type: 'date' }, - created_by: { type: 'keyword' }, + created_by: { type: 'keyword' }, // `null` if security is disabled created_at: { type: 'date' }, started_at: { type: 'date' }, completed_at: { type: 'date' }, diff --git a/x-pack/plugins/reporting/server/lib/store/report.test.ts b/x-pack/plugins/reporting/server/lib/store/report.test.ts index 83444494e61d3..9ac5d1f87c387 100644 --- a/x-pack/plugins/reporting/server/lib/store/report.test.ts +++ b/x-pack/plugins/reporting/server/lib/store/report.test.ts @@ -8,46 +8,59 @@ import { Report } from './report'; describe('Class Report', () => { it('constructs Report instance', () => { - const opts = { - index: '.reporting-test-index-12345', + const report = new Report({ + _index: '.reporting-test-index-12345', jobtype: 'test-report', created_by: 'created_by_test_string', browser_type: 'browser_type_test_string', max_attempts: 50, - payload: { payload_test_field: 1 }, + payload: { headers: 'payload_test_field', objectType: 'testOt' }, timeout: 30000, priority: 1, - }; - const report = new Report(opts); - expect(report.toJSON()).toMatchObject({ - _primary_term: undefined, - _seq_no: undefined, + }); + + expect(report.toEsDocsJSON()).toMatchObject({ + _index: '.reporting-test-index-12345', + _source: { + attempts: 0, + browser_type: 'browser_type_test_string', + completed_at: undefined, + created_at: undefined, + created_by: 'created_by_test_string', + jobtype: 'test-report', + max_attempts: 50, + meta: undefined, + payload: { headers: 'payload_test_field', objectType: 'testOt' }, + priority: 1, + started_at: undefined, + status: 'pending', + timeout: 30000, + }, + }); + expect(report.toApiJSON()).toMatchObject({ browser_type: 'browser_type_test_string', created_by: 'created_by_test_string', jobtype: 'test-report', max_attempts: 50, - payload: { - payload_test_field: 1, - }, + payload: { headers: 'payload_test_field', objectType: 'testOt' }, priority: 1, timeout: 30000, }); - expect(report.id).toBeDefined(); + expect(report._id).toBeDefined(); }); - it('updateWithDoc method syncs takes fields to sync ES metadata', () => { - const opts = { - index: '.reporting-test-index-12345', + it('updateWithEsDoc method syncs fields to sync ES metadata', () => { + const report = new Report({ + _index: '.reporting-test-index-12345', jobtype: 'test-report', created_by: 'created_by_test_string', browser_type: 'browser_type_test_string', max_attempts: 50, - payload: { payload_test_field: 1 }, + payload: { headers: 'payload_test_field', objectType: 'testOt' }, timeout: 30000, priority: 1, - }; - const report = new Report(opts); + }); const metadata = { _index: '.reporting-test-update', @@ -55,23 +68,53 @@ describe('Class Report', () => { _primary_term: 77, _seq_no: 99, }; - report.updateWithDoc(metadata); - - expect(report.toJSON()).toMatchObject({ - index: '.reporting-test-update', - _primary_term: 77, - _seq_no: 99, - browser_type: 'browser_type_test_string', - created_by: 'created_by_test_string', - jobtype: 'test-report', - max_attempts: 50, - payload: { - payload_test_field: 1, - }, - priority: 1, - timeout: 30000, - }); + report.updateWithEsDoc(metadata); - expect(report._id).toBe('12342p9o387549o2345'); + expect(report.toEsDocsJSON()).toMatchInlineSnapshot(` + Object { + "_id": "12342p9o387549o2345", + "_index": ".reporting-test-update", + "_source": Object { + "attempts": 0, + "browser_type": "browser_type_test_string", + "completed_at": undefined, + "created_at": undefined, + "created_by": "created_by_test_string", + "jobtype": "test-report", + "max_attempts": 50, + "meta": undefined, + "payload": Object { + "headers": "payload_test_field", + "objectType": "testOt", + }, + "priority": 1, + "started_at": undefined, + "status": "pending", + "timeout": 30000, + }, + } + `); + expect(report.toApiJSON()).toMatchInlineSnapshot(` + Object { + "attempts": 0, + "browser_type": "browser_type_test_string", + "completed_at": undefined, + "created_at": undefined, + "created_by": "created_by_test_string", + "id": "12342p9o387549o2345", + "index": ".reporting-test-update", + "jobtype": "test-report", + "max_attempts": 50, + "meta": undefined, + "payload": Object { + "headers": "payload_test_field", + "objectType": "testOt", + }, + "priority": 1, + "started_at": undefined, + "status": "pending", + "timeout": 30000, + } + `); }); }); diff --git a/x-pack/plugins/reporting/server/lib/store/report.ts b/x-pack/plugins/reporting/server/lib/store/report.ts index cc9967e64b6eb..5ff71ae7a7182 100644 --- a/x-pack/plugins/reporting/server/lib/store/report.ts +++ b/x-pack/plugins/reporting/server/lib/store/report.ts @@ -6,80 +6,158 @@ // @ts-ignore no module definition import Puid from 'puid'; +import { JobStatuses } from '../../../constants'; +import { LayoutInstance } from '../layouts'; -interface Payload { - id?: string; - index: string; +/* + * The document created by Reporting to store in the .reporting index + */ +interface ReportingDocument { + _id: string; + _index: string; + _seq_no: unknown; + _primary_term: unknown; jobtype: string; - created_by: string | boolean; - payload: unknown; + created_by: string | null; + payload: { + headers: string; // encrypted headers + objectType: string; + layout?: LayoutInstance; + }; + meta: unknown; browser_type: string; - priority: number; max_attempts: number; timeout: number; + + status: string; + attempts: number; + output?: unknown; + started_at?: string; + completed_at?: string; + created_at?: string; + priority?: number; + process_expiration?: string; } +/* + * The document created by Reporting to store as task parameters for Task + * Manager to reference the report in .reporting + */ const puid = new Puid(); -export class Report { - public readonly jobtype: string; - public readonly created_by: string | boolean; - public readonly payload: unknown; - public readonly browser_type: string; - public readonly id: string; +export class Report implements Partial { + public _index?: string; + public _id: string; + public _primary_term?: unknown; // set by ES + public _seq_no: unknown; // set by ES - public readonly priority: number; - // queue stuff, to be removed with Task Manager integration + public readonly jobtype: string; + public readonly created_at?: string; + public readonly created_by?: string | null; + public readonly payload: { + headers: string; // encrypted headers + objectType: string; + layout?: LayoutInstance; + }; + public readonly meta: unknown; public readonly max_attempts: number; - public readonly timeout: number; + public readonly browser_type?: string; - public _index: string; - public _id?: string; // set by ES - public _primary_term?: unknown; // set by ES - public _seq_no: unknown; // set by ES + public readonly status: string; + public readonly attempts: number; + public readonly output?: unknown; + public readonly started_at?: string; + public readonly completed_at?: string; + public readonly process_expiration?: string; + public readonly priority?: number; + public readonly timeout?: number; /* * Create an unsaved report */ - constructor(opts: Payload) { - this.jobtype = opts.jobtype; + constructor(opts: Partial) { + this._id = opts._id != null ? opts._id : puid.generate(); + this._index = opts._index; + this._primary_term = opts._primary_term; + this._seq_no = opts._seq_no; + + this.payload = opts.payload!; + this.jobtype = opts.jobtype!; + this.max_attempts = opts.max_attempts!; + this.attempts = opts.attempts || 0; + + this.process_expiration = opts.process_expiration; + this.timeout = opts.timeout; + + this.created_at = opts.created_at; this.created_by = opts.created_by; - this.payload = opts.payload; + this.meta = opts.meta; this.browser_type = opts.browser_type; this.priority = opts.priority; - this.max_attempts = opts.max_attempts; - this.timeout = opts.timeout; - this.id = puid.generate(); - this._index = opts.index; + this.status = opts.status || JobStatuses.PENDING; + this.output = opts.output || null; } /* * Update the report with "live" storage metadata */ - updateWithDoc(doc: Partial) { - if (doc._index) { - this._index = doc._index; // can not be undefined + updateWithEsDoc(doc: Partial) { + if (doc._index == null || doc._id == null) { + throw new Error(`Report object from ES has missing fields!`); } this._id = doc._id; + this._index = doc._index; this._primary_term = doc._primary_term; this._seq_no = doc._seq_no; } - toJSON() { + /* + * Data structure for writing to Elasticsearch index + */ + toEsDocsJSON() { + return { + _id: this._id, + _index: this._index, + _source: { + jobtype: this.jobtype, + created_at: this.created_at, + created_by: this.created_by, + payload: this.payload, + meta: this.meta, + timeout: this.timeout, + max_attempts: this.max_attempts, + priority: this.priority, + browser_type: this.browser_type, + status: this.status, + attempts: this.attempts, + started_at: this.started_at, + completed_at: this.completed_at, + }, + }; + } + + /* + * Data structure for API responses + */ + toApiJSON() { return { - id: this.id, + id: this._id, index: this._index, - _seq_no: this._seq_no, - _primary_term: this._primary_term, jobtype: this.jobtype, + created_at: this.created_at, created_by: this.created_by, payload: this.payload, + meta: this.meta, timeout: this.timeout, max_attempts: this.max_attempts, priority: this.priority, browser_type: this.browser_type, + status: this.status, + attempts: this.attempts, + started_at: this.started_at, + completed_at: this.completed_at, }; } } diff --git a/x-pack/plugins/reporting/server/lib/store/store.test.ts b/x-pack/plugins/reporting/server/lib/store/store.test.ts index 4868a1dfdd8f3..c66e2dd7742c4 100644 --- a/x-pack/plugins/reporting/server/lib/store/store.test.ts +++ b/x-pack/plugins/reporting/server/lib/store/store.test.ts @@ -5,11 +5,12 @@ */ import sinon from 'sinon'; +import { ElasticsearchServiceSetup } from 'src/core/server'; import { ReportingConfig, ReportingCore } from '../..'; import { createMockReportingCore } from '../../test_helpers'; import { createMockLevelLogger } from '../../test_helpers/create_mock_levellogger'; +import { Report } from './report'; import { ReportingStore } from './store'; -import { ElasticsearchServiceSetup } from 'src/core/server'; const getMockConfig = (mockConfigGet: sinon.SinonStub) => ({ get: mockConfigGet, @@ -31,11 +32,13 @@ describe('ReportingStore', () => { mockConfig = getMockConfig(mockConfigGet); mockCore = await createMockReportingCore(mockConfig); + callClusterStub.reset(); callClusterStub.withArgs('indices.exists').resolves({}); callClusterStub.withArgs('indices.create').resolves({}); - callClusterStub.withArgs('index').resolves({}); + callClusterStub.withArgs('index').resolves({ _id: 'stub-id', _index: 'stub-index' }); callClusterStub.withArgs('indices.refresh').resolves({}); callClusterStub.withArgs('update').resolves({}); + callClusterStub.withArgs('get').resolves({}); mockCore.getElasticsearchService = () => (mockElasticsearch as unknown) as ElasticsearchServiceSetup; @@ -45,25 +48,25 @@ describe('ReportingStore', () => { it('returns Report object', async () => { const store = new ReportingStore(mockCore, mockLogger); const reportType = 'unknowntype'; - const reportPayload = {}; - const reportOptions = { - timeout: 10000, - created_by: 'created_by_string', - browser_type: 'browser_type_string', - max_attempts: 1, + const reportPayload = { + browserTimezone: 'UTC', + headers: 'rp_headers_1', + objectType: 'testOt', }; - await expect( - store.addReport(reportType, reportPayload, reportOptions) - ).resolves.toMatchObject({ + await expect(store.addReport(reportType, 'username1', reportPayload)).resolves.toMatchObject({ _primary_term: undefined, _seq_no: undefined, - browser_type: 'browser_type_string', - created_by: 'created_by_string', + attempts: 0, + browser_type: undefined, + completed_at: undefined, + created_by: 'username1', jobtype: 'unknowntype', - max_attempts: 1, + max_attempts: undefined, payload: {}, priority: 10, - timeout: 10000, + started_at: undefined, + status: 'pending', + timeout: undefined, }); }); @@ -76,35 +79,31 @@ describe('ReportingStore', () => { const store = new ReportingStore(mockCore, mockLogger); const reportType = 'unknowntype'; - const reportPayload = {}; - const reportOptions = { - timeout: 10000, - created_by: 'created_by_string', - browser_type: 'browser_type_string', - max_attempts: 1, + const reportPayload = { + browserTimezone: 'UTC', + headers: 'rp_headers_2', + objectType: 'testOt', }; - expect( - store.addReport(reportType, reportPayload, reportOptions) - ).rejects.toMatchInlineSnapshot(`[Error: Invalid index interval: centurially]`); + expect(store.addReport(reportType, 'user1', reportPayload)).rejects.toMatchInlineSnapshot( + `[Error: Invalid index interval: centurially]` + ); }); it('handles error creating the index', async () => { // setup callClusterStub.withArgs('indices.exists').resolves(false); - callClusterStub.withArgs('indices.create').rejects(new Error('error')); + callClusterStub.withArgs('indices.create').rejects(new Error('horrible error')); const store = new ReportingStore(mockCore, mockLogger); const reportType = 'unknowntype'; - const reportPayload = {}; - const reportOptions = { - timeout: 10000, - created_by: 'created_by_string', - browser_type: 'browser_type_string', - max_attempts: 1, + const reportPayload = { + browserTimezone: 'UTC', + headers: 'rp_headers_3', + objectType: 'testOt', }; await expect( - store.addReport(reportType, reportPayload, reportOptions) - ).rejects.toMatchInlineSnapshot(`[Error: error]`); + store.addReport(reportType, 'user1', reportPayload) + ).rejects.toMatchInlineSnapshot(`[Error: horrible error]`); }); /* Creating the index will fail, if there were multiple jobs staged in @@ -116,20 +115,18 @@ describe('ReportingStore', () => { it('ignores index creation error if the index already exists and continues adding the report', async () => { // setup callClusterStub.withArgs('indices.exists').resolves(false); - callClusterStub.withArgs('indices.create').rejects(new Error('error')); + callClusterStub.withArgs('indices.create').rejects(new Error('devastating error')); const store = new ReportingStore(mockCore, mockLogger); const reportType = 'unknowntype'; - const reportPayload = {}; - const reportOptions = { - timeout: 10000, - created_by: 'created_by_string', - browser_type: 'browser_type_string', - max_attempts: 1, + const reportPayload = { + browserTimezone: 'UTC', + headers: 'rp_headers_4', + objectType: 'testOt', }; await expect( - store.addReport(reportType, reportPayload, reportOptions) - ).rejects.toMatchInlineSnapshot(`[Error: error]`); + store.addReport(reportType, 'user1', reportPayload) + ).rejects.toMatchInlineSnapshot(`[Error: devastating error]`); }); it('skips creating the index if already exists', async () => { @@ -141,26 +138,223 @@ describe('ReportingStore', () => { const store = new ReportingStore(mockCore, mockLogger); const reportType = 'unknowntype'; - const reportPayload = {}; - const reportOptions = { - timeout: 10000, - created_by: 'created_by_string', - browser_type: 'browser_type_string', - max_attempts: 1, + const reportPayload = { + browserTimezone: 'UTC', + headers: 'rp_headers_5', + objectType: 'testOt', }; - await expect( - store.addReport(reportType, reportPayload, reportOptions) - ).resolves.toMatchObject({ + await expect(store.addReport(reportType, 'user1', reportPayload)).resolves.toMatchObject({ + _primary_term: undefined, + _seq_no: undefined, + attempts: 0, + browser_type: undefined, + completed_at: undefined, + created_by: 'user1', + jobtype: 'unknowntype', + max_attempts: undefined, + payload: {}, + priority: 10, + started_at: undefined, + status: 'pending', + timeout: undefined, + }); + }); + + it('allows username string to be `null`', async () => { + // setup + callClusterStub.withArgs('indices.exists').resolves(false); + callClusterStub + .withArgs('indices.create') + .rejects(new Error('resource_already_exists_exception')); // will be triggered but ignored + + const store = new ReportingStore(mockCore, mockLogger); + const reportType = 'unknowntype'; + const reportPayload = { + browserTimezone: 'UTC', + headers: 'rp_test_headers', + objectType: 'testOt', + }; + await expect(store.addReport(reportType, null, reportPayload)).resolves.toMatchObject({ _primary_term: undefined, _seq_no: undefined, - browser_type: 'browser_type_string', - created_by: 'created_by_string', + attempts: 0, + browser_type: undefined, + completed_at: undefined, + created_by: null, jobtype: 'unknowntype', - max_attempts: 1, + max_attempts: undefined, payload: {}, priority: 10, - timeout: 10000, + started_at: undefined, + status: 'pending', + timeout: undefined, }); }); }); + + it('setReportClaimed sets the status of a record to processing', async () => { + const store = new ReportingStore(mockCore, mockLogger); + const report = new Report({ + _id: 'id-of-processing', + _index: '.reporting-test-index-12345', + jobtype: 'test-report', + created_by: 'created_by_test_string', + browser_type: 'browser_type_test_string', + max_attempts: 50, + payload: { + headers: 'rp_test_headers', + objectType: 'testOt', + }, + timeout: 30000, + priority: 1, + }); + + await store.setReportClaimed(report, { testDoc: 'test' } as any); + + const updateCall = callClusterStub.getCalls().find((call) => call.args[0] === 'update'); + expect(updateCall && updateCall.args).toMatchInlineSnapshot(` + Array [ + "update", + Object { + "body": Object { + "doc": Object { + "status": "processing", + "testDoc": "test", + }, + }, + "id": "id-of-processing", + "if_primary_term": undefined, + "if_seq_no": undefined, + "index": ".reporting-test-index-12345", + }, + ] + `); + }); + + it('setReportFailed sets the status of a record to failed', async () => { + const store = new ReportingStore(mockCore, mockLogger); + const report = new Report({ + _id: 'id-of-failure', + _index: '.reporting-test-index-12345', + jobtype: 'test-report', + created_by: 'created_by_test_string', + browser_type: 'browser_type_test_string', + max_attempts: 50, + payload: { + headers: 'rp_test_headers', + objectType: 'testOt', + }, + timeout: 30000, + priority: 1, + }); + + await store.setReportFailed(report, { errors: 'yes' } as any); + + const updateCall = callClusterStub.getCalls().find((call) => call.args[0] === 'update'); + expect(updateCall && updateCall.args).toMatchInlineSnapshot(` + Array [ + "update", + Object { + "body": Object { + "doc": Object { + "errors": "yes", + "status": "failed", + }, + }, + "id": "id-of-failure", + "if_primary_term": undefined, + "if_seq_no": undefined, + "index": ".reporting-test-index-12345", + }, + ] + `); + }); + + it('setReportCompleted sets the status of a record to completed', async () => { + const store = new ReportingStore(mockCore, mockLogger); + const report = new Report({ + _id: 'vastly-great-report-id', + _index: '.reporting-test-index-12345', + jobtype: 'test-report', + created_by: 'created_by_test_string', + browser_type: 'browser_type_test_string', + max_attempts: 50, + payload: { + headers: 'rp_test_headers', + objectType: 'testOt', + }, + timeout: 30000, + priority: 1, + }); + + await store.setReportCompleted(report, { certainly_completed: 'yes' } as any); + + const updateCall = callClusterStub.getCalls().find((call) => call.args[0] === 'update'); + expect(updateCall && updateCall.args).toMatchInlineSnapshot(` + Array [ + "update", + Object { + "body": Object { + "doc": Object { + "certainly_completed": "yes", + "status": "completed", + }, + }, + "id": "vastly-great-report-id", + "if_primary_term": undefined, + "if_seq_no": undefined, + "index": ".reporting-test-index-12345", + }, + ] + `); + }); + + it('setReportCompleted sets the status of a record to completed_with_warnings', async () => { + const store = new ReportingStore(mockCore, mockLogger); + const report = new Report({ + _id: 'vastly-great-report-id', + _index: '.reporting-test-index-12345', + jobtype: 'test-report', + created_by: 'created_by_test_string', + browser_type: 'browser_type_test_string', + max_attempts: 50, + payload: { + headers: 'rp_test_headers', + objectType: 'testOt', + }, + timeout: 30000, + priority: 1, + }); + + await store.setReportCompleted(report, { + certainly_completed: 'pretty_much', + output: { + warnings: [`those pants don't go with that shirt`], + }, + } as any); + + const updateCall = callClusterStub.getCalls().find((call) => call.args[0] === 'update'); + expect(updateCall && updateCall.args).toMatchInlineSnapshot(` + Array [ + "update", + Object { + "body": Object { + "doc": Object { + "certainly_completed": "pretty_much", + "output": Object { + "warnings": Array [ + "those pants don't go with that shirt", + ], + }, + "status": "completed_with_warnings", + }, + }, + "id": "vastly-great-report-id", + "if_primary_term": undefined, + "if_seq_no": undefined, + "index": ".reporting-test-index-12345", + }, + ] + `); + }); }); diff --git a/x-pack/plugins/reporting/server/lib/store/store.ts b/x-pack/plugins/reporting/server/lib/store/store.ts index 0f1ed83b71767..12cff0e973ed6 100644 --- a/x-pack/plugins/reporting/server/lib/store/store.ts +++ b/x-pack/plugins/reporting/server/lib/store/store.ts @@ -5,36 +5,24 @@ */ import { ElasticsearchServiceSetup } from 'src/core/server'; -import { LevelLogger } from '../'; +import { LevelLogger, statuses } from '../'; import { ReportingCore } from '../../'; +import { CreateJobBaseParams, CreateJobBaseParamsEncryptedFields } from '../../types'; import { indexTimestamp } from './index_timestamp'; -import { LayoutInstance } from '../layouts'; import { mapping } from './mapping'; import { Report } from './report'; - -export const statuses = { - JOB_STATUS_PENDING: 'pending', - JOB_STATUS_PROCESSING: 'processing', - JOB_STATUS_COMPLETED: 'completed', - JOB_STATUS_WARNINGS: 'completed_with_warnings', - JOB_STATUS_FAILED: 'failed', - JOB_STATUS_CANCELLED: 'cancelled', -}; - -interface AddReportOpts { +interface JobSettings { timeout: number; - created_by: string | boolean; browser_type: string; max_attempts: number; + priority: number; } -interface UpdateQuery { - index: string; - id: string; - if_seq_no: unknown; - if_primary_term: unknown; - body: { doc: Partial }; -} +const checkReportIsEditable = (report: Report) => { + if (!report._id || !report._index) { + throw new Error(`Report object is not synced with ES!`); + } +}; /* * A class to give an interface to historical reports in the reporting.index @@ -43,9 +31,9 @@ interface UpdateQuery { * - interface for downloading the report */ export class ReportingStore { - public readonly indexPrefix: string; - public readonly indexInterval: string; - + private readonly indexPrefix: string; + private readonly indexInterval: string; + private readonly jobSettings: JobSettings; private client: ElasticsearchServiceSetup['legacy']['client']; private logger: LevelLogger; @@ -56,12 +44,18 @@ export class ReportingStore { this.client = elasticsearch.legacy.client; this.indexPrefix = config.get('index'); this.indexInterval = config.get('queue', 'indexInterval'); + this.jobSettings = { + timeout: config.get('queue', 'timeout'), + browser_type: config.get('capture', 'browser', 'type'), + max_attempts: config.get('capture', 'maxAttempts'), + priority: 10, // unused + }; this.logger = logger; } private async createIndex(indexName: string) { - return this.client + return await this.client .callAsInternalUser('indices.exists', { index: indexName, }) @@ -95,75 +89,157 @@ export class ReportingStore { return; } + this.logger.error(err); throw err; }); }); } - private async saveReport(report: Report) { - const payload = report.payload as { objectType: string; layout: LayoutInstance }; + /* + * Called from addReport, which handles any errors + */ + private async indexReport(report: Report) { + const params = report.payload; + + // Queing is handled by TM. These queueing-based fields for reference in Report Info panel + const infoFields = { + timeout: report.timeout, + process_expiration: new Date(0), // use epoch so the job query works + created_at: new Date(), + attempts: 0, + max_attempts: report.max_attempts, + status: statuses.JOB_STATUS_PENDING, + browser_type: report.browser_type, + }; const indexParams = { index: report._index, - id: report.id, + id: report._id, body: { + ...infoFields, jobtype: report.jobtype, meta: { // We are copying these values out of payload because these fields are indexed and can be aggregated on // for tracking stats, while payload contents are not. - objectType: payload.objectType, - layout: payload.layout ? payload.layout.id : 'none', + objectType: params.objectType, + layout: params.layout ? params.layout.id : 'none', }, payload: report.payload, created_by: report.created_by, - timeout: report.timeout, - process_expiration: new Date(0), // use epoch so the job query works - created_at: new Date(), - attempts: 0, - max_attempts: report.max_attempts, - status: statuses.JOB_STATUS_PENDING, - browser_type: report.browser_type, }, }; - return this.client.callAsInternalUser('index', indexParams); + return await this.client.callAsInternalUser('index', indexParams); } + /* + * Called from addReport, which handles any errors + */ private async refreshIndex(index: string) { - return this.client.callAsInternalUser('indices.refresh', { index }); + return await this.client.callAsInternalUser('indices.refresh', { index }); } - public async addReport(type: string, payload: unknown, options: AddReportOpts): Promise { + public async addReport( + type: string, + username: string | null, + payload: CreateJobBaseParams & CreateJobBaseParamsEncryptedFields + ): Promise { const timestamp = indexTimestamp(this.indexInterval); const index = `${this.indexPrefix}-${timestamp}`; await this.createIndex(index); const report = new Report({ - index, + _index: index, payload, jobtype: type, - created_by: options.created_by, - browser_type: options.browser_type, - max_attempts: options.max_attempts, - timeout: options.timeout, - priority: 10, // unused + created_by: username, + ...this.jobSettings, }); - const doc = await this.saveReport(report); - report.updateWithDoc(doc); + try { + const doc = await this.indexReport(report); + report.updateWithEsDoc(doc); - await this.refreshIndex(index); - this.logger.info(`Successfully queued pending job: ${report._index}/${report.id}`); + await this.refreshIndex(index); + this.logger.debug(`Successfully stored pending job: ${report._index}/${report._id}`); - return report; + return report; + } catch (err) { + this.logger.error(`Error in addReport!`); + this.logger.error(err); + throw err; + } } - public async updateReport(query: UpdateQuery): Promise { - return this.client.callAsInternalUser('update', { - index: query.index, - id: query.id, - if_seq_no: query.if_seq_no, - if_primary_term: query.if_primary_term, - body: { doc: query.body.doc }, - }); + public async setReportClaimed(report: Report, stats: Partial): Promise { + const doc = { + ...stats, + status: statuses.JOB_STATUS_PROCESSING, + }; + + try { + checkReportIsEditable(report); + + return await this.client.callAsInternalUser('update', { + id: report._id, + index: report._index, + if_seq_no: report._seq_no, + if_primary_term: report._primary_term, + body: { doc }, + }); + } catch (err) { + this.logger.error('Error in setting report processing status!'); + this.logger.error(err); + throw err; + } + } + + public async setReportFailed(report: Report, stats: Partial): Promise { + const doc = { + ...stats, + status: statuses.JOB_STATUS_FAILED, + }; + + try { + checkReportIsEditable(report); + + return await this.client.callAsInternalUser('update', { + id: report._id, + index: report._index, + if_seq_no: report._seq_no, + if_primary_term: report._primary_term, + body: { doc }, + }); + } catch (err) { + this.logger.error('Error in setting report failed status!'); + this.logger.error(err); + throw err; + } + } + + public async setReportCompleted(report: Report, stats: Partial): Promise { + try { + const { output } = stats as { output: any }; + const status = + output && output.warnings && output.warnings.length > 0 + ? statuses.JOB_STATUS_WARNINGS + : statuses.JOB_STATUS_COMPLETED; + const doc = { + ...stats, + status, + }; + checkReportIsEditable(report); + + return await this.client.callAsInternalUser('update', { + id: report._id, + index: report._index, + if_seq_no: report._seq_no, + if_primary_term: report._primary_term, + body: { doc }, + }); + } catch (err) { + this.logger.error('Error in setting report complete status!'); + this.logger.error(err); + throw err; + } } } diff --git a/x-pack/plugins/reporting/server/plugin.ts b/x-pack/plugins/reporting/server/plugin.ts index cedc9dc14a237..20e22c2db00e3 100644 --- a/x-pack/plugins/reporting/server/plugin.ts +++ b/x-pack/plugins/reporting/server/plugin.ts @@ -8,13 +8,7 @@ import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'src/core import { ReportingCore } from './'; import { initializeBrowserDriverFactory } from './browsers'; import { buildConfig, ReportingConfigType } from './config'; -import { - createQueueFactory, - enqueueJobFactory, - LevelLogger, - runValidations, - ReportingStore, -} from './lib'; +import { createQueueFactory, LevelLogger, runValidations, ReportingStore } from './lib'; import { registerRoutes } from './routes'; import { setFieldFormats } from './services'; import { ReportingSetup, ReportingSetupDeps, ReportingStart, ReportingStartDeps } from './types'; @@ -94,14 +88,12 @@ export class ReportingPlugin const browserDriverFactory = await initializeBrowserDriverFactory(config, logger); const store = new ReportingStore(reportingCore, logger); const esqueue = await createQueueFactory(reportingCore, store, logger); // starts polling for pending jobs - const enqueueJob = enqueueJobFactory(reportingCore, store, logger); // called from generation routes reportingCore.pluginStart({ browserDriverFactory, savedObjects: core.savedObjects, uiSettings: core.uiSettings, esqueue, - enqueueJob, store, }); diff --git a/x-pack/plugins/reporting/server/routes/generate_from_jobparams.ts b/x-pack/plugins/reporting/server/routes/generate_from_jobparams.ts index 2a12a64d67a35..f4959b56dfea1 100644 --- a/x-pack/plugins/reporting/server/routes/generate_from_jobparams.ts +++ b/x-pack/plugins/reporting/server/routes/generate_from_jobparams.ts @@ -10,6 +10,7 @@ import { authorizedUserPreRoutingFactory } from './lib/authorized_user_pre_routi import { HandlerErrorFunction, HandlerFunction } from './types'; import { ReportingCore } from '../'; import { API_BASE_URL } from '../../common/constants'; +import { CreateJobBaseParams } from '../types'; const BASE_GENERATE = `${API_BASE_URL}/generate`; @@ -44,13 +45,13 @@ export function registerGenerateFromJobParams( }, }, userHandler(async (user, context, req, res) => { - let jobParamsRison: string | null; + let jobParamsRison: null | string = null; if (req.body) { - const { jobParams: jobParamsPayload } = req.body as { jobParams: string }; - jobParamsRison = jobParamsPayload; - } else { - const { jobParams: queryJobParams } = req.query as { jobParams: string }; + const { jobParams: jobParamsPayload } = req.body; + jobParamsRison = jobParamsPayload ? jobParamsPayload : null; + } else if (req.query?.jobParams) { + const { jobParams: queryJobParams } = req.query; if (queryJobParams) { jobParamsRison = queryJobParams; } else { @@ -65,11 +66,11 @@ export function registerGenerateFromJobParams( }); } - const { exportType } = req.params as { exportType: string }; + const { exportType } = req.params; let jobParams; try { - jobParams = rison.decode(jobParamsRison) as object | null; + jobParams = rison.decode(jobParamsRison) as CreateJobBaseParams | null; if (!jobParams) { return res.customError({ statusCode: 400, diff --git a/x-pack/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts b/x-pack/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts index 8250ca462049b..a0a8f25de7fc4 100644 --- a/x-pack/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts +++ b/x-pack/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts @@ -5,16 +5,24 @@ */ import { schema } from '@kbn/config-schema'; +import { KibanaRequest } from 'src/core/server'; import { ReportingCore } from '../'; import { API_BASE_GENERATE_V1 } from '../../common/constants'; import { scheduleTaskFnFactory } from '../export_types/csv_from_savedobject/create_job'; import { runTaskFnFactory } from '../export_types/csv_from_savedobject/execute_job'; +import { JobParamsPostPayloadPanelCsv } from '../export_types/csv_from_savedobject/types'; import { LevelLogger as Logger } from '../lib'; import { TaskRunResult } from '../types'; import { authorizedUserPreRoutingFactory } from './lib/authorized_user_pre_routing'; import { getJobParamsFromRequest } from './lib/get_job_params_from_request'; import { HandlerErrorFunction } from './types'; +export type CsvFromSavedObjectRequest = KibanaRequest< + { savedObjectType: string; savedObjectId: string }, + unknown, + JobParamsPostPayloadPanelCsv +>; + /* * This function registers API Endpoints for immediate Reporting jobs. The API inputs are: * - saved object type and ID @@ -56,7 +64,7 @@ export function registerGenerateCsvFromSavedObjectImmediate( }), }, }, - userHandler(async (user, context, req, res) => { + userHandler(async (user, context, req: CsvFromSavedObjectRequest, res) => { const logger = parentLogger.clone(['savedobject-csv']); const jobParams = getJobParamsFromRequest(req, { isImmediate: true }); const scheduleTaskFn = scheduleTaskFnFactory(reporting, logger); diff --git a/x-pack/plugins/reporting/server/routes/generation.test.ts b/x-pack/plugins/reporting/server/routes/generation.test.ts index 87a696948ad84..cef4da9aabbd4 100644 --- a/x-pack/plugins/reporting/server/routes/generation.test.ts +++ b/x-pack/plugins/reporting/server/routes/generation.test.ts @@ -138,8 +138,7 @@ describe('POST /api/reporting/generate', () => { }); it('returns 500 if job handler throws an error', async () => { - // throw an error from enqueueJob - core.getEnqueueJob = jest.fn().mockRejectedValue('Sorry, this tests says no'); + callClusterStub.withArgs('index').rejects('silly'); registerJobGenerationRoutes(core, mockLogger); diff --git a/x-pack/plugins/reporting/server/routes/generation.ts b/x-pack/plugins/reporting/server/routes/generation.ts index 017e875931ae2..b2115076aada4 100644 --- a/x-pack/plugins/reporting/server/routes/generation.ts +++ b/x-pack/plugins/reporting/server/routes/generation.ts @@ -10,6 +10,7 @@ import { kibanaResponseFactory } from 'src/core/server'; import { ReportingCore } from '../'; import { API_BASE_URL } from '../../common/constants'; import { LevelLogger as Logger } from '../lib'; +import { enqueueJobFactory } from '../lib/enqueue_job'; import { registerGenerateFromJobParams } from './generate_from_jobparams'; import { registerGenerateCsvFromSavedObjectImmediate } from './generate_from_savedobject_immediate'; import { HandlerFunction } from './types'; @@ -43,11 +44,10 @@ export function registerJobGenerationRoutes(reporting: ReportingCore, logger: Lo } try { - const enqueueJob = await reporting.getEnqueueJob(); - const job = await enqueueJob(exportTypeId, jobParams, user, context, req); + const enqueueJob = enqueueJobFactory(reporting, logger); + const report = await enqueueJob(exportTypeId, jobParams, user, context, req); // return the queue's job information - const jobJson = job.toJSON(); const downloadBaseUrl = getDownloadBaseUrl(reporting); return res.ok({ @@ -55,8 +55,8 @@ export function registerJobGenerationRoutes(reporting: ReportingCore, logger: Lo 'content-type': 'application/json', }, body: { - path: `${downloadBaseUrl}/${jobJson.id}`, - job: jobJson, + path: `${downloadBaseUrl}/${report._id}`, + job: report.toApiJSON(), }, }); } catch (err) { diff --git a/x-pack/plugins/reporting/server/routes/lib/get_document_payload.ts b/x-pack/plugins/reporting/server/routes/lib/get_document_payload.ts index d384cbb878a0e..84a98d6d1f1d7 100644 --- a/x-pack/plugins/reporting/server/routes/lib/get_document_payload.ts +++ b/x-pack/plugins/reporting/server/routes/lib/get_document_payload.ts @@ -8,8 +8,7 @@ import contentDisposition from 'content-disposition'; import { get } from 'lodash'; import { CSV_JOB_TYPE } from '../../../common/constants'; -import { statuses } from '../../lib/esqueue/constants/statuses'; -import { ExportTypesRegistry } from '../../lib/export_types_registry'; +import { ExportTypesRegistry, statuses } from '../../lib'; import { ExportTypeDefinition, JobSource, TaskRunResult } from '../../types'; type ExportTypeType = ExportTypeDefinition; @@ -18,11 +17,11 @@ interface ErrorFromPayload { message: string; } -// A camelCase version of TaskRunResult +// interface of the API result interface Payload { statusCode: number; content: string | Buffer | ErrorFromPayload; - contentType: string; + contentType: string | null; headers: Record; } diff --git a/x-pack/plugins/reporting/server/routes/lib/get_job_params_from_request.ts b/x-pack/plugins/reporting/server/routes/lib/get_job_params_from_request.ts index e5c1f38241349..bfa15a4022a4d 100644 --- a/x-pack/plugins/reporting/server/routes/lib/get_job_params_from_request.ts +++ b/x-pack/plugins/reporting/server/routes/lib/get_job_params_from_request.ts @@ -4,21 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import { KibanaRequest } from 'src/core/server'; -import { - JobParamsPanelCsv, - JobParamsPostPayloadPanelCsv, -} from '../../export_types/csv_from_savedobject/types'; +import { JobParamsPanelCsv } from '../../export_types/csv_from_savedobject/types'; +import { CsvFromSavedObjectRequest } from '../generate_from_savedobject_immediate'; export function getJobParamsFromRequest( - request: KibanaRequest, + request: CsvFromSavedObjectRequest, opts: { isImmediate: boolean } ): JobParamsPanelCsv { - const { savedObjectType, savedObjectId } = request.params as { - savedObjectType: string; - savedObjectId: string; - }; - const { timerange, state } = request.body as JobParamsPostPayloadPanelCsv; + const { savedObjectType, savedObjectId } = request.params; + const { timerange, state } = request.body; const post = timerange || state ? { timerange, state } : undefined; diff --git a/x-pack/plugins/reporting/server/routes/types.d.ts b/x-pack/plugins/reporting/server/routes/types.d.ts index 607ce34ab9465..c92c9fb7eef74 100644 --- a/x-pack/plugins/reporting/server/routes/types.d.ts +++ b/x-pack/plugins/reporting/server/routes/types.d.ts @@ -6,12 +6,12 @@ import { KibanaRequest, KibanaResponseFactory, RequestHandlerContext } from 'src/core/server'; import { AuthenticatedUser } from '../../../security/server'; -import { ScheduledTaskParams } from '../types'; +import { CreateJobBaseParams, ScheduledTaskParams } from '../types'; export type HandlerFunction = ( user: AuthenticatedUser | null, exportType: string, - jobParams: object, + jobParams: CreateJobBaseParams, context: RequestHandlerContext, req: KibanaRequest, res: KibanaResponseFactory diff --git a/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts b/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts index 95b06aa39f07e..c508ee6974ca0 100644 --- a/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts +++ b/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts @@ -8,7 +8,6 @@ jest.mock('../routes'); jest.mock('../usage'); jest.mock('../browsers'); jest.mock('../lib/create_queue'); -jest.mock('../lib/enqueue_job'); jest.mock('../lib/validate'); import * as Rx from 'rxjs'; @@ -19,10 +18,9 @@ import { initializeBrowserDriverFactory, } from '../browsers'; import { ReportingInternalSetup, ReportingInternalStart } from '../core'; -import { ReportingStartDeps } from '../types'; import { ReportingStore } from '../lib'; +import { ReportingStartDeps } from '../types'; import { createMockLevelLogger } from './create_mock_levellogger'; -import { Report } from '../lib/store'; (initializeBrowserDriverFactory as jest.Mock< Promise @@ -30,10 +28,13 @@ import { Report } from '../lib/store'; (chromium as any).createDriverFactory.mockImplementation(() => ({})); -const createMockPluginSetup = (setupMock?: any): ReportingInternalSetup => { +const createMockPluginSetup = ( + mockReportingCore: ReportingCore, + setupMock?: any +): ReportingInternalSetup => { return { elasticsearch: setupMock.elasticsearch || { legacy: { client: {} } }, - basePath: setupMock.basePath, + basePath: setupMock.basePath || '/all-about-that-basepath', router: setupMock.router, security: setupMock.security, licensing: { license$: Rx.of({ isAvailable: true, isActive: true, type: 'basic' }) } as any, @@ -48,7 +49,6 @@ const createMockPluginStart = ( const store = new ReportingStore(mockReportingCore, logger); return { browserDriverFactory: startMock.browserDriverFactory, - enqueueJob: startMock.enqueueJob || jest.fn().mockResolvedValue(new Report({} as any)), esqueue: startMock.esqueue, savedObjects: startMock.savedObjects || { getScopedClient: jest.fn() }, uiSettings: startMock.uiSettings || { asScopedToClient: () => ({ get: jest.fn() }) }, @@ -72,15 +72,14 @@ export const createMockReportingCore = async ( setupDepsMock: ReportingInternalSetup | undefined = undefined, startDepsMock: ReportingInternalStart | undefined = undefined ) => { - if (!setupDepsMock) { - setupDepsMock = createMockPluginSetup({}); - } - const mockReportingCore = { getConfig: () => config, getElasticsearchService: () => setupDepsMock?.elasticsearch, } as ReportingCore; + if (!setupDepsMock) { + setupDepsMock = createMockPluginSetup(mockReportingCore, {}); + } if (!startDepsMock) { startDepsMock = createMockPluginStart(mockReportingCore, {}); } diff --git a/x-pack/plugins/reporting/server/types.ts b/x-pack/plugins/reporting/server/types.ts index ff597b53ea0b0..c9649cb6e558b 100644 --- a/x-pack/plugins/reporting/server/types.ts +++ b/x-pack/plugins/reporting/server/types.ts @@ -19,24 +19,12 @@ import { LevelLogger } from './lib'; import { LayoutInstance } from './lib/layouts'; /* - * Routing / API types + * Routing types */ -interface ListQuery { - page: string; - size: string; - ids?: string; // optional field forbids us from extending RequestQuery -} - -interface GenerateQuery { - jobParams: string; -} - -export type ReportingRequestQuery = ListQuery | GenerateQuery; - export interface ReportingRequestPre { management: { - jobTypes: any; + jobTypes: string[]; }; user: string; } @@ -54,12 +42,14 @@ export interface TimeRangeParams { max?: Date | string | number | null; } +// the "raw" data coming from the client, unencrypted export interface JobParamPostPayload { timerange?: TimeRangeParams; } +// the pre-processed, encrypted data ready for storage export interface ScheduledTaskParams { - headers?: string; // serialized encrypted headers + headers: string; // serialized encrypted headers jobParams: JobParamsType; title: string; type: string; @@ -77,10 +67,10 @@ export interface JobSource { } export interface TaskRunResult { - content_type: string; + content_type: string | null; content: string | null; - size: number; csv_contains_formulas?: boolean; + size: number; max_size_reached?: boolean; warnings?: string[]; } @@ -177,17 +167,29 @@ export type ReportingSetup = object; export type CaptureConfig = ReportingConfigType['capture']; export type ScrollConfig = ReportingConfigType['csv']['scroll']; -export type ESQueueCreateJobFn = ( +export interface CreateJobBaseParams { + browserTimezone: string; + layout?: LayoutInstance; // for screenshot type reports + objectType: string; +} + +export interface CreateJobBaseParamsEncryptedFields extends CreateJobBaseParams { + basePath?: string; // for screenshot type reports + headers: string; // encrypted headers +} + +export type CreateJobFn = ( jobParams: JobParamsType, context: RequestHandlerContext, request: KibanaRequest -) => Promise; +) => Promise; -export type ESQueueWorkerExecuteFn = ( +// rename me +export type WorkerExecuteFn = ( jobId: string, job: ScheduledTaskParamsType, cancellationToken: CancellationToken -) => Promise; +) => Promise; export type ScheduleTaskFnFactory = ( reporting: ReportingCore, From 875f7701c37b0737208fd51e70a9c60f74fea8a3 Mon Sep 17 00:00:00 2001 From: Scotty Bollinger Date: Thu, 13 Aug 2020 16:45:16 -0500 Subject: [PATCH 30/53] Add public url to Workplace Search plugin (#74991) --- x-pack/plugins/enterprise_search/public/plugin.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/plugins/enterprise_search/public/plugin.ts b/x-pack/plugins/enterprise_search/public/plugin.ts index 74263fb36a958..42ad7de93b00e 100644 --- a/x-pack/plugins/enterprise_search/public/plugin.ts +++ b/x-pack/plugins/enterprise_search/public/plugin.ts @@ -73,6 +73,8 @@ export class EnterpriseSearchPlugin implements Plugin { const { chrome } = coreStart; chrome.docTitle.change(WORKPLACE_SEARCH_PLUGIN.NAME); + await this.setPublicUrl(config, coreStart.http); + const { renderApp } = await import('./applications'); const { WorkplaceSearch } = await import('./applications/workplace_search'); From 1729091ddfa466ddf447c55ef90ddd8c0a87d9a4 Mon Sep 17 00:00:00 2001 From: Robert Austin Date: Thu, 13 Aug 2020 17:50:10 -0400 Subject: [PATCH 31/53] [Resolver] Stale query string values are removed when resolver's component instance ID changes. (#74979) The app can show more than 1 Resolver at a time. Each instance has a unique ID called the `resolverComponentInstanceID`. When the user interacts with Resolver it will add values to the query string. The query string values will contain the `resolverComponentInstanceID`. This allows each Resolver to keep its state separate. When resolver unmounts it will remove any query string values related to it. If Resolver's `resolverComponentInstanceID` changes it should remove query string values related to the old instance ID. It does not. This PR fixes that. Note: I don't know if it was possible for this bug to actually happen. I can't make it happen, but depending on how Resolver is mounted by its consumers it *could* --- .../test_utilities/simulator/index.tsx | 38 +++++--- .../resolver/view/clickthrough.test.tsx | 10 +-- .../public/resolver/view/panel.test.tsx | 8 +- .../public/resolver/view/query_params.test.ts | 89 +++++++++++++++++++ .../view/resolver_without_providers.tsx | 9 +- .../resolver/view/use_query_string_keys.ts | 21 +++++ .../view/use_resolver_query_params.ts | 64 ++++--------- .../view/use_resolver_query_params_cleaner.ts | 53 +++++++++++ 8 files changed, 220 insertions(+), 72 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/resolver/view/query_params.test.ts create mode 100644 x-pack/plugins/security_solution/public/resolver/view/use_query_string_keys.ts create mode 100644 x-pack/plugins/security_solution/public/resolver/view/use_resolver_query_params_cleaner.ts diff --git a/x-pack/plugins/security_solution/public/resolver/test_utilities/simulator/index.tsx b/x-pack/plugins/security_solution/public/resolver/test_utilities/simulator/index.tsx index 355b53e374092..14cdc26c80f53 100644 --- a/x-pack/plugins/security_solution/public/resolver/test_utilities/simulator/index.tsx +++ b/x-pack/plugins/security_solution/public/resolver/test_utilities/simulator/index.tsx @@ -22,10 +22,6 @@ import { sideEffectSimulatorFactory } from '../../view/side_effect_simulator_fac * Test a Resolver instance using jest, enzyme, and a mock data layer. */ export class Simulator { - /** - * A string that uniquely identifies this Resolver instance among others mounted in the DOM. - */ - private readonly resolverComponentInstanceID: string; /** * The redux store, creating in the constructor using the `dataAccessLayer`. * This code subscribes to state transitions. @@ -69,7 +65,6 @@ export class Simulator { databaseDocumentID?: string; history?: HistoryPackageHistoryInterface; }) { - this.resolverComponentInstanceID = resolverComponentInstanceID; // create the spy middleware (for debugging tests) this.spyMiddleware = spyMiddlewareFactory(); @@ -98,7 +93,7 @@ export class Simulator { // Render Resolver via the `MockResolver` component, using `enzyme`. this.wrapper = mount( ({ // the query string has a key showing that the second child is selected - queryStringSelectedNode: simulator.queryStringValues().selectedNode, + search: simulator.historyLocationSearch, // the second child is rendered in the DOM, and shows up as selected selectedSecondChildNodeCount: simulator.selectedProcessNode(entityIDs.secondChild) .length, @@ -102,7 +103,9 @@ describe('Resolver, when analyzing a tree that has no ancestors and 2 children', })) ).toYieldEqualTo({ // Just the second child should be marked as selected in the query string - queryStringSelectedNode: [entityIDs.secondChild], + search: urlSearch(resolverComponentInstanceID, { + selectedEntityID: entityIDs.secondChild, + }), // The second child is rendered and has `[aria-selected]` selectedSecondChildNodeCount: 1, // The origin child is rendered and doesn't have `[aria-selected]` @@ -175,9 +178,6 @@ describe('Resolver, when analyzing a tree that has two related events for the or simulator.testSubject('resolver:map:node-submenu-item').map((node) => node.text()) ) ).toYieldEqualTo(['2 registry']); - await expect( - simulator.map(() => simulator.testSubject('resolver:map:node-submenu-item').length) - ).toYieldEqualTo(1); }); }); describe('and when the related events button is clicked again', () => { diff --git a/x-pack/plugins/security_solution/public/resolver/view/panel.test.tsx b/x-pack/plugins/security_solution/public/resolver/view/panel.test.tsx index 21b5a30ee9890..037337fb2f868 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/panel.test.tsx +++ b/x-pack/plugins/security_solution/public/resolver/view/panel.test.tsx @@ -152,9 +152,11 @@ describe(`Resolver: when analyzing a tree with no ancestors and two children, an ]); }); it("should have the first node's ID in the query string", async () => { - await expect(simulator().map(() => simulator().queryStringValues())).toYieldEqualTo({ - selectedNode: [entityIDs.origin], - }); + await expect(simulator().map(() => simulator().historyLocationSearch)).toYieldEqualTo( + urlSearch(resolverComponentInstanceID, { + selectedEntityID: entityIDs.origin, + }) + ); }); describe('and when the node list link has been clicked', () => { beforeEach(async () => { diff --git a/x-pack/plugins/security_solution/public/resolver/view/query_params.test.ts b/x-pack/plugins/security_solution/public/resolver/view/query_params.test.ts new file mode 100644 index 0000000000000..26c25cfab2c21 --- /dev/null +++ b/x-pack/plugins/security_solution/public/resolver/view/query_params.test.ts @@ -0,0 +1,89 @@ +/* + * 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 { noAncestorsTwoChildren } from '../data_access_layer/mocks/no_ancestors_two_children'; +import { Simulator } from '../test_utilities/simulator'; +// Extend jest with a custom matcher +import '../test_utilities/extend_jest'; +import { urlSearch } from '../test_utilities/url_search'; + +let simulator: Simulator; +let databaseDocumentID: string; +let entityIDs: { origin: string; firstChild: string; secondChild: string }; + +// the resolver component instance ID, used by the react code to distinguish piece of global state from those used by other resolver instances +const resolverComponentInstanceID = 'oldID'; + +describe('Resolver, when analyzing a tree that has no ancestors and 2 children', () => { + beforeEach(async () => { + // create a mock data access layer + const { metadata: dataAccessLayerMetadata, dataAccessLayer } = noAncestorsTwoChildren(); + + // save a reference to the entity IDs exposed by the mock data layer + entityIDs = dataAccessLayerMetadata.entityIDs; + + // save a reference to the `_id` supported by the mock data layer + databaseDocumentID = dataAccessLayerMetadata.databaseDocumentID; + + // create a resolver simulator, using the data access layer and an arbitrary component instance ID + simulator = new Simulator({ databaseDocumentID, dataAccessLayer, resolverComponentInstanceID }); + }); + + describe("when the second child node's first button has been clicked", () => { + beforeEach(async () => { + const node = await simulator.resolveWrapper(() => + simulator.processNodeElements({ entityID: entityIDs.secondChild }).find('button') + ); + if (node) { + // Click the first button under the second child element. + node.first().simulate('click'); + } + }); + const expectedSearch = urlSearch(resolverComponentInstanceID, { + selectedEntityID: 'secondChild', + }); + it(`should have a url search of ${expectedSearch}`, async () => { + await expect(simulator.map(() => simulator.historyLocationSearch)).toYieldEqualTo( + urlSearch(resolverComponentInstanceID, { selectedEntityID: 'secondChild' }) + ); + }); + describe('when the resolver component gets unmounted', () => { + beforeEach(() => { + simulator.unmount(); + }); + it('should have a history location search of `""`', async () => { + await expect(simulator.map(() => simulator.historyLocationSearch)).toYieldEqualTo(''); + }); + }); + describe('when the resolver component has its component instance ID changed', () => { + const newInstanceID = 'newID'; + beforeEach(() => { + simulator.resolverComponentInstanceID = newInstanceID; + }); + it('should have a history location search of `""`', async () => { + await expect(simulator.map(() => simulator.historyLocationSearch)).toYieldEqualTo(''); + }); + describe("when the user clicks the second child node's button again", () => { + beforeEach(async () => { + const node = await simulator.resolveWrapper(() => + simulator.processNodeElements({ entityID: entityIDs.secondChild }).find('button') + ); + if (node) { + // Click the first button under the second child element. + node.first().simulate('click'); + } + }); + it(`should have a url search of ${urlSearch(newInstanceID, { + selectedEntityID: 'secondChild', + })}`, async () => { + await expect(simulator.map(() => simulator.historyLocationSearch)).toYieldEqualTo( + urlSearch(newInstanceID, { selectedEntityID: 'secondChild' }) + ); + }); + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/resolver/view/resolver_without_providers.tsx b/x-pack/plugins/security_solution/public/resolver/view/resolver_without_providers.tsx index 5f1e5f18e575d..32faeec043f2d 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/resolver_without_providers.tsx +++ b/x-pack/plugins/security_solution/public/resolver/view/resolver_without_providers.tsx @@ -8,9 +8,9 @@ import React, { useContext, useCallback } from 'react'; import { useSelector } from 'react-redux'; -import { useEffectOnce } from 'react-use'; import { EuiLoadingSpinner } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; +import { useResolverQueryParamCleaner } from './use_resolver_query_params_cleaner'; import * as selectors from '../store/selectors'; import { EdgeLine } from './edge_line'; import { GraphControls } from './graph_controls'; @@ -18,7 +18,6 @@ import { ProcessEventDot } from './process_event_dot'; import { useCamera } from './use_camera'; import { SymbolDefinitions, useResolverTheme } from './assets'; import { useStateSyncingActions } from './use_state_syncing_actions'; -import { useResolverQueryParams } from './use_resolver_query_params'; import { StyledMapContainer, StyledPanel, GraphContainer } from './styles'; import { entityIDSafeVersion } from '../../../common/endpoint/models/event'; import { SideEffectContext } from './side_effect_context'; @@ -35,6 +34,7 @@ export const ResolverWithoutProviders = React.memo( { className, databaseDocumentID, resolverComponentInstanceID }: ResolverProps, refToForward ) { + useResolverQueryParamCleaner(); /** * This is responsible for dispatching actions that include any external data. * `databaseDocumentID` @@ -70,11 +70,6 @@ export const ResolverWithoutProviders = React.memo( const hasError = useSelector(selectors.hasError); const activeDescendantId = useSelector(selectors.ariaActiveDescendant); const { colorMap } = useResolverTheme(); - const { cleanUpQueryParams } = useResolverQueryParams(); - - useEffectOnce(() => { - return () => cleanUpQueryParams(); - }); return ( diff --git a/x-pack/plugins/security_solution/public/resolver/view/use_query_string_keys.ts b/x-pack/plugins/security_solution/public/resolver/view/use_query_string_keys.ts new file mode 100644 index 0000000000000..11f1a30db72fc --- /dev/null +++ b/x-pack/plugins/security_solution/public/resolver/view/use_query_string_keys.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 { useSelector } from 'react-redux'; +import * as selectors from '../store/selectors'; + +/** + * Get the query string keys used by this Resolver instance. + */ +export function useQueryStringKeys(): { idKey: string; eventKey: string } { + const resolverComponentInstanceID = useSelector(selectors.resolverComponentInstanceID); + const idKey: string = `resolver-${resolverComponentInstanceID}-id`; + const eventKey: string = `resolver-${resolverComponentInstanceID}-event`; + return { + idKey, + eventKey, + }; +} diff --git a/x-pack/plugins/security_solution/public/resolver/view/use_resolver_query_params.ts b/x-pack/plugins/security_solution/public/resolver/view/use_resolver_query_params.ts index ed514a61d4e06..aa0851916a7b4 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/use_resolver_query_params.ts +++ b/x-pack/plugins/security_solution/public/resolver/view/use_resolver_query_params.ts @@ -5,11 +5,8 @@ */ import { useCallback, useMemo } from 'react'; -// eslint-disable-next-line import/no-nodejs-modules -import querystring from 'querystring'; -import { useSelector } from 'react-redux'; import { useHistory, useLocation } from 'react-router-dom'; -import * as selectors from '../store/selectors'; +import { useQueryStringKeys } from './use_query_string_keys'; import { CrumbInfo } from './panels/panel_content_utilities'; export function useResolverQueryParams() { @@ -19,63 +16,40 @@ export function useResolverQueryParams() { */ const history = useHistory(); const urlSearch = useLocation().search; - const resolverComponentInstanceID = useSelector(selectors.resolverComponentInstanceID); - const uniqueCrumbIdKey: string = `resolver-${resolverComponentInstanceID}-id`; - const uniqueCrumbEventKey: string = `resolver-${resolverComponentInstanceID}-event`; + const { idKey, eventKey } = useQueryStringKeys(); const pushToQueryParams = useCallback( - (newCrumbs: CrumbInfo) => { - // Construct a new set of parameters from the current set (minus empty parameters) - // by assigning the new set of parameters provided in `newCrumbs` - const crumbsToPass = { - ...querystring.parse(urlSearch.slice(1)), - [uniqueCrumbIdKey]: newCrumbs.crumbId, - [uniqueCrumbEventKey]: newCrumbs.crumbEvent, - }; + (queryStringState: CrumbInfo) => { + const urlSearchParams = new URLSearchParams(urlSearch); - // If either was passed in as empty, remove it from the record - if (newCrumbs.crumbId === '') { - delete crumbsToPass[uniqueCrumbIdKey]; + urlSearchParams.set(idKey, queryStringState.crumbId); + urlSearchParams.set(eventKey, queryStringState.crumbEvent); + + // If either was passed in as empty, remove it + if (queryStringState.crumbId === '') { + urlSearchParams.delete(idKey); } - if (newCrumbs.crumbEvent === '') { - delete crumbsToPass[uniqueCrumbEventKey]; + if (queryStringState.crumbEvent === '') { + urlSearchParams.delete(eventKey); } - const relativeURL = { search: querystring.stringify(crumbsToPass) }; + const relativeURL = { search: urlSearchParams.toString() }; // We probably don't want to nuke the user's history with a huge // trail of these, thus `.replace` instead of `.push` return history.replace(relativeURL); }, - [history, urlSearch, uniqueCrumbIdKey, uniqueCrumbEventKey] + [history, urlSearch, idKey, eventKey] ); const queryParams: CrumbInfo = useMemo(() => { - const parsed = querystring.parse(urlSearch.slice(1)); - const crumbEvent = parsed[uniqueCrumbEventKey]; - const crumbId = parsed[uniqueCrumbIdKey]; - function valueForParam(param: string | string[]): string { - if (Array.isArray(param)) { - return param[0] || ''; - } - return param || ''; - } + const urlSearchParams = new URLSearchParams(urlSearch); return { - crumbEvent: valueForParam(crumbEvent), - crumbId: valueForParam(crumbId), + // Use `''` for backwards compatibility with deprecated code. + crumbEvent: urlSearchParams.get(eventKey) ?? '', + crumbId: urlSearchParams.get(idKey) ?? '', }; - }, [urlSearch, uniqueCrumbIdKey, uniqueCrumbEventKey]); - - const cleanUpQueryParams = () => { - const crumbsToPass = { - ...querystring.parse(urlSearch.slice(1)), - }; - delete crumbsToPass[uniqueCrumbIdKey]; - delete crumbsToPass[uniqueCrumbEventKey]; - const relativeURL = { search: querystring.stringify(crumbsToPass) }; - history.replace(relativeURL); - }; + }, [urlSearch, idKey, eventKey]); return { pushToQueryParams, queryParams, - cleanUpQueryParams, }; } diff --git a/x-pack/plugins/security_solution/public/resolver/view/use_resolver_query_params_cleaner.ts b/x-pack/plugins/security_solution/public/resolver/view/use_resolver_query_params_cleaner.ts new file mode 100644 index 0000000000000..a84eb0490aae2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/resolver/view/use_resolver_query_params_cleaner.ts @@ -0,0 +1,53 @@ +/* + * 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 { useRef, useEffect } from 'react'; +import { useLocation, useHistory } from 'react-router-dom'; + +import { useQueryStringKeys } from './use_query_string_keys'; +/** + * Cleanup any query string keys that were added by this Resolver instance. + * This works by having a React effect that just has behavior in the 'cleanup' function. + */ +export function useResolverQueryParamCleaner() { + /** + * Keep a reference to the current search value. This is used in the cleanup function. + * This value of useLocation().search isn't used directly since that would change and + * we only want the cleanup to run on unmount or when the resolverComponentInstanceID + * changes. + */ + const searchRef = useRef(); + searchRef.current = useLocation().search; + + const history = useHistory(); + + const { idKey, eventKey } = useQueryStringKeys(); + + useEffect(() => { + /** + * Keep track of the old query string keys so we can remove them. + */ + const oldIdKey = idKey; + const oldEventKey = eventKey; + /** + * When `idKey` or `eventKey` changes (such as when the `resolverComponentInstanceID` has changed) or when the component unmounts, remove any state from the query string. + */ + return () => { + /** + * This effect must not be invalidated when `search` changes. + */ + const urlSearchParams = new URLSearchParams(searchRef.current); + + /** + * Remove old keys from the url + */ + urlSearchParams.delete(oldIdKey); + urlSearchParams.delete(oldEventKey); + const relativeURL = { search: urlSearchParams.toString() }; + history.replace(relativeURL); + }; + }, [idKey, eventKey, history]); +} From 447854d992883f6dafc27743372701452ce7e8c4 Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Thu, 13 Aug 2020 15:06:59 -0700 Subject: [PATCH 32/53] [Reporting/Functional] unskip pagination test (#74973) * [Reporting/Functional] unskip pagination test * change to js file for flaky test runner * fix ts --- .../__snapshots__/report_listing.test.tsx.snap | 3 --- .../reporting/public/components/report_listing.tsx | 1 - .../reporting_management/{index.ts => index.js} | 4 +--- .../apps/reporting_management/report_listing.ts | 14 ++++++++++---- 4 files changed, 11 insertions(+), 11 deletions(-) rename x-pack/test/functional/apps/reporting_management/{index.ts => index.js} (75%) diff --git a/x-pack/plugins/reporting/public/components/__snapshots__/report_listing.test.tsx.snap b/x-pack/plugins/reporting/public/components/__snapshots__/report_listing.test.tsx.snap index 66c3aea8acc13..ddba7842f1199 100644 --- a/x-pack/plugins/reporting/public/components/__snapshots__/report_listing.test.tsx.snap +++ b/x-pack/plugins/reporting/public/components/__snapshots__/report_listing.test.tsx.snap @@ -30,7 +30,6 @@ Array [ }, ] } - data-test-page={0} data-test-subj="reportJobListing" isSelectable={true} itemId="id" @@ -57,7 +56,6 @@ Array [ >
@@ -368,7 +366,6 @@ Array [ ,
diff --git a/x-pack/plugins/reporting/public/components/report_listing.tsx b/x-pack/plugins/reporting/public/components/report_listing.tsx index 80ef9311fd0e5..afcae93a8db16 100644 --- a/x-pack/plugins/reporting/public/components/report_listing.tsx +++ b/x-pack/plugins/reporting/public/components/report_listing.tsx @@ -513,7 +513,6 @@ class ReportListingUi extends Component { isSelectable={true} onChange={this.onTableChange} data-test-subj="reportJobListing" - data-test-page={this.state.page} /> {this.state.selectedJobs.length > 0 ? this.renderDeleteButton() : null} diff --git a/x-pack/test/functional/apps/reporting_management/index.ts b/x-pack/test/functional/apps/reporting_management/index.js similarity index 75% rename from x-pack/test/functional/apps/reporting_management/index.ts rename to x-pack/test/functional/apps/reporting_management/index.js index 8606c46053ab0..ef92e7d04ef0c 100644 --- a/x-pack/test/functional/apps/reporting_management/index.ts +++ b/x-pack/test/functional/apps/reporting_management/index.js @@ -4,9 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { FtrProviderContext } from '../../ftr_provider_context'; - -export default ({ loadTestFile }: FtrProviderContext) => { +export default ({ loadTestFile }) => { describe('reporting management app', function () { this.tags('ciGroup7'); loadTestFile(require.resolve('./report_listing')); diff --git a/x-pack/test/functional/apps/reporting_management/report_listing.ts b/x-pack/test/functional/apps/reporting_management/report_listing.ts index 476f3e73d0923..ca5fb888e67e1 100644 --- a/x-pack/test/functional/apps/reporting_management/report_listing.ts +++ b/x-pack/test/functional/apps/reporting_management/report_listing.ts @@ -26,7 +26,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const security = getService('security'); const testSubjects = getService('testSubjects'); - const findInstance = getService('find'); const esArchiver = getService('esArchiver'); describe('Listing of Reports', function () { @@ -68,7 +67,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }); - it.skip('Paginates content', async () => { + it('Paginates historical reports', async () => { + // wait for first row of page 1 + await testSubjects.find('checkboxSelectRow-k9a9xlwl0gpe1457b10rraq3'); + const previousButton = await testSubjects.find('pagination-button-previous'); // previous CAN NOT be clicked @@ -90,7 +92,9 @@ pdf\ndashboard\n2020-04-21 @ 07:00 PM\ntest_user\nCompleted at 2020-04-21 @ 07:0 // click page 2 await testSubjects.click('pagination-button-1'); - await findInstance.byCssSelector('[data-test-page="1"]'); + + // wait for first row of page 2 + await testSubjects.find('checkboxSelectRow-k9a9uc4x0gpe1457b16wthc8'); // previous CAN be clicked expect(await previousButton.getAttribute('disabled')).to.be(null); @@ -110,7 +114,9 @@ test_user\nCompleted at 2020-04-21 @ 06:55 PM - Max size reached\nreport2csv\n20 // click page 3 await testSubjects.click('pagination-button-2'); - await findInstance.byCssSelector('[data-test-page="2"]'); + + // wait for first row of page 3 + await testSubjects.find('checkboxSelectRow-k9a9p1840gpe1457b1ghfxw5'); // scan page 3 tableText = await getTableTextFromElement(await testSubjects.find('reportJobListing')); From 24c2e0a4523926eb1d144fec5fc830b7320929a5 Mon Sep 17 00:00:00 2001 From: Josh Dover Date: Thu, 13 Aug 2020 18:15:11 -0600 Subject: [PATCH 33/53] Remove degraded state from ES status service (#75007) --- src/core/server/elasticsearch/status.test.ts | 6 +++--- src/core/server/elasticsearch/status.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/server/elasticsearch/status.test.ts b/src/core/server/elasticsearch/status.test.ts index ef7ca7cd04608..5dfadba4c88b2 100644 --- a/src/core/server/elasticsearch/status.test.ts +++ b/src/core/server/elasticsearch/status.test.ts @@ -65,7 +65,7 @@ describe('calculateStatus', () => { }); }); - it('changes to degraded when isCompatible and warningNodes present', async () => { + it('changes to available with a differemnt message when isCompatible and warningNodes present', async () => { expect( await calculateStatus$( of({ @@ -81,7 +81,7 @@ describe('calculateStatus', () => { .pipe(take(2)) .toPromise() ).toEqual({ - level: ServiceStatusLevels.degraded, + level: ServiceStatusLevels.available, summary: 'Some nodes are a different version', meta: { incompatibleNodes: [], @@ -188,7 +188,7 @@ describe('calculateStatus', () => { "summary": "Incompatible with Elasticsearch", }, Object { - "level": degraded, + "level": available, "meta": Object { "incompatibleNodes": Array [], "warningNodes": Array [ diff --git a/src/core/server/elasticsearch/status.ts b/src/core/server/elasticsearch/status.ts index 1eaa338af1239..1be32d03c60cb 100644 --- a/src/core/server/elasticsearch/status.ts +++ b/src/core/server/elasticsearch/status.ts @@ -55,7 +55,7 @@ export const calculateStatus$ = ( }; } else if (warningNodes.length > 0) { return { - level: ServiceStatusLevels.degraded, + level: ServiceStatusLevels.available, summary: // Message should always be present, but this is a safe fallback message ?? From 1632391f35d847d32245c502d0310849ae7b9322 Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Thu, 13 Aug 2020 18:45:47 -0700 Subject: [PATCH 34/53] [Metrics UI] Remove TSVB dependency from Metrics Explorer APIs (#74804) * [Metrics UI] Remove TSVB dependency from Metrics Explorer APIs * Update x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_title.tsx Co-authored-by: Zacqary Adam Xeper * Update x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/calculate_auto.ts Co-authored-by: Zacqary Adam Xeper * Update x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/calculate_auto.ts Co-authored-by: Zacqary Adam Xeper * Update x-pack/plugins/infra/server/lib/metrics/lib/convert_histogram_buckets_to_timeseries.ts Co-authored-by: Zacqary Adam Xeper * Update x-pack/plugins/infra/server/lib/metrics/lib/convert_histogram_buckets_to_timeseries.ts Co-authored-by: Zacqary Adam Xeper * Update x-pack/plugins/infra/server/routes/metrics_explorer/lib/find_interval_for_metrics.ts Co-authored-by: Zacqary Adam Xeper * Fixing some names, changing some units * Reverting TSVB calculate_auto; fixing names in infra * Fixing translation names * Fixing typo Co-authored-by: Zacqary Adam Xeper Co-authored-by: Zacqary Adam Xeper --- x-pack/plugins/infra/common/constants.ts | 3 + x-pack/plugins/infra/common/http_api/index.ts | 1 + .../infra/common/http_api/metrics_api.ts | 97 +++++++++ .../infra/common/http_api/metrics_explorer.ts | 2 + .../aws_ec2/metrics/snapshot/cpu.ts | 4 +- .../metrics/snapshot/disk_io_read_bytes.ts | 4 +- .../metrics/snapshot/disk_io_write_bytes.ts | 4 +- .../aws_ec2/metrics/snapshot/rx.ts | 4 +- .../aws_ec2/metrics/snapshot/tx.ts | 4 +- .../aws_rds/metrics/snapshot/cpu.ts | 4 +- .../snapshot/rds_active_transactions.ts | 4 +- .../metrics/snapshot/rds_connections.ts | 4 +- .../aws_rds/metrics/snapshot/rds_latency.ts | 4 +- .../metrics/snapshot/rds_queries_executed.ts | 4 +- .../aws_s3/metrics/snapshot/s3_bucket_size.ts | 4 +- .../metrics/snapshot/s3_download_bytes.ts | 4 +- .../metrics/snapshot/s3_number_of_objects.ts | 4 +- .../metrics/snapshot/s3_total_requests.ts | 4 +- .../metrics/snapshot/s3_upload_bytes.ts | 4 +- .../metrics/snapshot/sqs_messages_delayed.ts | 4 +- .../metrics/snapshot/sqs_messages_empty.ts | 4 +- .../metrics/snapshot/sqs_messages_sent.ts | 4 +- .../metrics/snapshot/sqs_messages_visible.ts | 4 +- .../metrics/snapshot/sqs_oldest_message.ts | 4 +- .../container/metrics/snapshot/cpu.ts | 4 +- .../container/metrics/snapshot/memory.ts | 6 +- .../host/metrics/snapshot/cpu.ts | 4 +- .../host/metrics/snapshot/load.ts | 4 +- .../host/metrics/snapshot/log_rate.ts | 4 +- .../host/metrics/snapshot/memory.ts | 4 +- .../infra/common/inventory_models/index.ts | 4 +- .../pod/metrics/snapshot/cpu.ts | 4 +- .../pod/metrics/snapshot/memory.ts | 4 +- .../shared/metrics/snapshot/count.ts | 4 +- .../metrics/snapshot/network_traffic.ts | 4 +- .../network_traffic_with_interfaces.ts | 4 +- .../shared/metrics/snapshot/rate.ts | 4 +- .../infra/common/inventory_models/types.ts | 55 +++-- .../indices_configuration_panel.tsx | 3 +- .../components/chart_title.tsx | 7 +- .../components/helpers/get_metric_id.ts | 3 - .../infra/server/lib/metrics/constants.ts | 16 ++ .../plugins/infra/server/lib/metrics/index.ts | 113 ++++++++++ ...stogram_buckets_to_timeseries.test.ts.snap | 193 ++++++++++++++++++ .../create_aggregations.test.ts.snap | 87 ++++++++ .../create_metrics_aggregations.test.ts.snap | 23 +++ .../calculate_auto.test.ts | 28 +++ .../calculate_bucket_size/calculate_auto.ts | 88 ++++++++ .../calculate_bucket_size.test.ts | 53 +++++ .../lib/calculate_bucket_size/index.ts | 89 ++++++++ .../interval_regex.test.ts | 81 ++++++++ .../calculate_bucket_size/interval_regex.ts | 10 + .../unit_to_seconds.test.ts | 132 ++++++++++++ .../calculate_bucket_size/unit_to_seconds.ts | 68 ++++++ .../calculate_date_histogram_offset.test.ts | 20 ++ .../lib/calculate_date_histogram_offset.ts | 17 ++ ...rt_histogram_buckets_to_timeseries.test.ts | 120 +++++++++++ ...convert_histogram_buckets_to_timeseries.ts | 93 +++++++++ .../metrics/lib/create_aggregations.test.ts | 45 ++++ .../lib/metrics/lib/create_aggregations.ts | 45 ++++ .../lib/create_metrics_aggregations.test.ts | 36 ++++ .../lib/create_metrics_aggregations.ts | 15 ++ .../plugins/infra/server/lib/metrics/types.ts | 72 +++++++ .../create_timerange_with_interval.ts | 6 +- .../server/lib/snapshot/query_helpers.ts | 10 +- .../infra/server/lib/sources/defaults.ts | 11 +- .../server/routes/metrics_explorer/index.ts | 64 ++++-- ...nvert_metric_to_metrics_api_metric.test.ts | 87 ++++++++ .../convert_metric_to_metrics_api_metric.ts | 62 ++++++ ...ert_request_to_metrics_api_options.test.ts | 123 +++++++++++ .../convert_request_to_metrics_api_options.ts | 58 ++++++ .../lib/create_metrics_model.ts | 97 --------- .../lib/find_interval_for_metrics.ts | 52 +++++ .../metrics_explorer/lib/get_groupings.ts | 150 -------------- .../lib/populate_series_with_tsvb_data.ts | 162 --------------- .../lib/query_total_groupings.ts | 59 ++++++ .../metrics_explorer/lib/transform_series.ts | 24 +++ .../translations/translations/ja-JP.json | 2 +- .../translations/translations/zh-CN.json | 2 +- .../apis/metrics_ui/metrics_explorer.ts | 6 +- 80 files changed, 2190 insertions(+), 534 deletions(-) create mode 100644 x-pack/plugins/infra/common/http_api/metrics_api.ts create mode 100644 x-pack/plugins/infra/server/lib/metrics/constants.ts create mode 100644 x-pack/plugins/infra/server/lib/metrics/index.ts create mode 100644 x-pack/plugins/infra/server/lib/metrics/lib/__snapshots__/convert_histogram_buckets_to_timeseries.test.ts.snap create mode 100644 x-pack/plugins/infra/server/lib/metrics/lib/__snapshots__/create_aggregations.test.ts.snap create mode 100644 x-pack/plugins/infra/server/lib/metrics/lib/__snapshots__/create_metrics_aggregations.test.ts.snap create mode 100644 x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/calculate_auto.test.ts create mode 100644 x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/calculate_auto.ts create mode 100644 x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/calculate_bucket_size.test.ts create mode 100644 x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/index.ts create mode 100644 x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/interval_regex.test.ts create mode 100644 x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/interval_regex.ts create mode 100644 x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/unit_to_seconds.test.ts create mode 100644 x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/unit_to_seconds.ts create mode 100644 x-pack/plugins/infra/server/lib/metrics/lib/calculate_date_histogram_offset.test.ts create mode 100644 x-pack/plugins/infra/server/lib/metrics/lib/calculate_date_histogram_offset.ts create mode 100644 x-pack/plugins/infra/server/lib/metrics/lib/convert_histogram_buckets_to_timeseries.test.ts create mode 100644 x-pack/plugins/infra/server/lib/metrics/lib/convert_histogram_buckets_to_timeseries.ts create mode 100644 x-pack/plugins/infra/server/lib/metrics/lib/create_aggregations.test.ts create mode 100644 x-pack/plugins/infra/server/lib/metrics/lib/create_aggregations.ts create mode 100644 x-pack/plugins/infra/server/lib/metrics/lib/create_metrics_aggregations.test.ts create mode 100644 x-pack/plugins/infra/server/lib/metrics/lib/create_metrics_aggregations.ts create mode 100644 x-pack/plugins/infra/server/lib/metrics/types.ts create mode 100644 x-pack/plugins/infra/server/routes/metrics_explorer/lib/convert_metric_to_metrics_api_metric.test.ts create mode 100644 x-pack/plugins/infra/server/routes/metrics_explorer/lib/convert_metric_to_metrics_api_metric.ts create mode 100644 x-pack/plugins/infra/server/routes/metrics_explorer/lib/convert_request_to_metrics_api_options.test.ts create mode 100644 x-pack/plugins/infra/server/routes/metrics_explorer/lib/convert_request_to_metrics_api_options.ts delete mode 100644 x-pack/plugins/infra/server/routes/metrics_explorer/lib/create_metrics_model.ts create mode 100644 x-pack/plugins/infra/server/routes/metrics_explorer/lib/find_interval_for_metrics.ts delete mode 100644 x-pack/plugins/infra/server/routes/metrics_explorer/lib/get_groupings.ts delete mode 100644 x-pack/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts create mode 100644 x-pack/plugins/infra/server/routes/metrics_explorer/lib/query_total_groupings.ts create mode 100644 x-pack/plugins/infra/server/routes/metrics_explorer/lib/transform_series.ts diff --git a/x-pack/plugins/infra/common/constants.ts b/x-pack/plugins/infra/common/constants.ts index 65dcb2e43c6f7..ba8e421cbf32c 100644 --- a/x-pack/plugins/infra/common/constants.ts +++ b/x-pack/plugins/infra/common/constants.ts @@ -5,3 +5,6 @@ */ export const DEFAULT_SOURCE_ID = 'default'; +export const METRICS_INDEX_PATTERN = 'metrics-*,metricbeat-*'; +export const LOGS_INDEX_PATTERN = 'logs-*,filebeat-*,kibana_sample_data_logs*'; +export const TIMESTAMP_FIELD = '@timestamp'; diff --git a/x-pack/plugins/infra/common/http_api/index.ts b/x-pack/plugins/infra/common/http_api/index.ts index 326daa93de33a..9ec8bf5231066 100644 --- a/x-pack/plugins/infra/common/http_api/index.ts +++ b/x-pack/plugins/infra/common/http_api/index.ts @@ -8,3 +8,4 @@ export * from './log_analysis'; export * from './metadata_api'; export * from './log_entries'; export * from './metrics_explorer'; +export * from './metrics_api'; diff --git a/x-pack/plugins/infra/common/http_api/metrics_api.ts b/x-pack/plugins/infra/common/http_api/metrics_api.ts new file mode 100644 index 0000000000000..7436566f039ca --- /dev/null +++ b/x-pack/plugins/infra/common/http_api/metrics_api.ts @@ -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 * as rt from 'io-ts'; +import { MetricsUIAggregationRT } from '../inventory_models/types'; +import { afterKeyObjectRT } from './metrics_explorer'; + +export const MetricsAPITimerangeRT = rt.type({ + field: rt.string, + from: rt.number, + to: rt.number, + interval: rt.string, +}); + +const groupByRT = rt.union([rt.string, rt.null, rt.undefined]); + +export const MetricsAPIMetricRT = rt.type({ + id: rt.string, + aggregations: MetricsUIAggregationRT, +}); + +export const MetricsAPIRequestRT = rt.intersection([ + rt.type({ + timerange: MetricsAPITimerangeRT, + indexPattern: rt.string, + metrics: rt.array(MetricsAPIMetricRT), + }), + rt.partial({ + groupBy: rt.array(groupByRT), + afterKey: rt.union([rt.null, afterKeyObjectRT]), + limit: rt.union([rt.number, rt.null, rt.undefined]), + filters: rt.array(rt.object), + forceInterval: rt.boolean, + dropLastBucket: rt.boolean, + alignDataToEnd: rt.boolean, + }), +]); + +export const MetricsAPIPageInfoRT = rt.type({ + afterKey: rt.union([rt.null, afterKeyObjectRT, rt.undefined]), + interval: rt.number, +}); + +export const MetricsAPIColumnTypeRT = rt.keyof({ + date: null, + number: null, + string: null, +}); + +export const MetricsAPIColumnRT = rt.type({ + name: rt.string, + type: MetricsAPIColumnTypeRT, +}); + +export const MetricsAPIRowRT = rt.intersection([ + rt.type({ + timestamp: rt.number, + }), + rt.record(rt.string, rt.union([rt.string, rt.number, rt.null, rt.undefined])), +]); + +export const MetricsAPISeriesRT = rt.intersection([ + rt.type({ + id: rt.string, + columns: rt.array(MetricsAPIColumnRT), + rows: rt.array(MetricsAPIRowRT), + }), + rt.partial({ + keys: rt.array(rt.string), + }), +]); + +export const MetricsAPIResponseRT = rt.type({ + series: rt.array(MetricsAPISeriesRT), + info: MetricsAPIPageInfoRT, +}); + +export type MetricsAPITimerange = rt.TypeOf; + +export type MetricsAPIColumnType = rt.TypeOf; + +export type MetricsAPIMetric = rt.TypeOf; + +export type MetricsAPIPageInfo = rt.TypeOf; + +export type MetricsAPIColumn = rt.TypeOf; + +export type MetricsAPIRow = rt.TypeOf; + +export type MetricsAPISeries = rt.TypeOf; + +export type MetricsAPIRequest = rt.TypeOf; + +export type MetricsAPIResponse = rt.TypeOf; diff --git a/x-pack/plugins/infra/common/http_api/metrics_explorer.ts b/x-pack/plugins/infra/common/http_api/metrics_explorer.ts index 0f63b8d275e65..c5776e0b0ced1 100644 --- a/x-pack/plugins/infra/common/http_api/metrics_explorer.ts +++ b/x-pack/plugins/infra/common/http_api/metrics_explorer.ts @@ -108,6 +108,8 @@ export const metricsExplorerResponseRT = rt.type({ pageInfo: metricsExplorerPageInfoRT, }); +export type AfterKey = rt.TypeOf; + export type MetricsExplorerAggregation = rt.TypeOf; export type MetricsExplorerColumnType = rt.TypeOf; diff --git a/x-pack/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/cpu.ts b/x-pack/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/cpu.ts index 483d9de784919..ea6db373eda03 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/cpu.ts +++ b/x-pack/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/cpu.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const cpu: SnapshotModel = { +export const cpu: MetricsUIAggregation = { cpu_avg: { avg: { field: 'aws.ec2.cpu.total.pct', diff --git a/x-pack/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/disk_io_read_bytes.ts b/x-pack/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/disk_io_read_bytes.ts index 48e4a9eb59fad..89b131f9c2a8c 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/disk_io_read_bytes.ts +++ b/x-pack/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/disk_io_read_bytes.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const diskIOReadBytes: SnapshotModel = { +export const diskIOReadBytes: MetricsUIAggregation = { diskIOReadBytes: { avg: { field: 'aws.ec2.diskio.read.bytes_per_sec', diff --git a/x-pack/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/disk_io_write_bytes.ts b/x-pack/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/disk_io_write_bytes.ts index deadaa8c4a776..e52380fbddd33 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/disk_io_write_bytes.ts +++ b/x-pack/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/disk_io_write_bytes.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const diskIOWriteBytes: SnapshotModel = { +export const diskIOWriteBytes: MetricsUIAggregation = { diskIOWriteBytes: { avg: { field: 'aws.ec2.diskio.write.bytes_per_sec', diff --git a/x-pack/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/rx.ts b/x-pack/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/rx.ts index 2b857ce9b338a..ddb6770744699 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/rx.ts +++ b/x-pack/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/rx.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const rx: SnapshotModel = { +export const rx: MetricsUIAggregation = { rx: { avg: { field: 'aws.ec2.network.in.bytes_per_sec', diff --git a/x-pack/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/tx.ts b/x-pack/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/tx.ts index 63c9da8ea1888..cf3bb070c8ec8 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/tx.ts +++ b/x-pack/plugins/infra/common/inventory_models/aws_ec2/metrics/snapshot/tx.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const tx: SnapshotModel = { +export const tx: MetricsUIAggregation = { tx: { avg: { field: 'aws.ec2.network.in.bytes_per_sec', diff --git a/x-pack/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/cpu.ts b/x-pack/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/cpu.ts index e277b3b11958b..4825fb26aa677 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/cpu.ts +++ b/x-pack/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/cpu.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const cpu: SnapshotModel = { +export const cpu: MetricsUIAggregation = { cpu_avg: { avg: { field: 'aws.rds.cpu.total.pct', diff --git a/x-pack/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_active_transactions.ts b/x-pack/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_active_transactions.ts index be3dba100ba29..50c89a51a32da 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_active_transactions.ts +++ b/x-pack/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_active_transactions.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const rdsActiveTransactions: SnapshotModel = { +export const rdsActiveTransactions: MetricsUIAggregation = { rdsActiveTransactions: { avg: { field: 'aws.rds.transactions.active', diff --git a/x-pack/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_connections.ts b/x-pack/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_connections.ts index c7855d5548eea..4f8ab3bec324b 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_connections.ts +++ b/x-pack/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_connections.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const rdsConnections: SnapshotModel = { +export const rdsConnections: MetricsUIAggregation = { rdsConnections: { avg: { field: 'aws.rds.database_connections', diff --git a/x-pack/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_latency.ts b/x-pack/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_latency.ts index 2997b54d2f92e..1682cab04cd7a 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_latency.ts +++ b/x-pack/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_latency.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const rdsLatency: SnapshotModel = { +export const rdsLatency: MetricsUIAggregation = { rdsLatency: { avg: { field: 'aws.rds.latency.dml', diff --git a/x-pack/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_queries_executed.ts b/x-pack/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_queries_executed.ts index 18e6538fb1e1e..7672d17f9d048 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_queries_executed.ts +++ b/x-pack/plugins/infra/common/inventory_models/aws_rds/metrics/snapshot/rds_queries_executed.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const rdsQueriesExecuted: SnapshotModel = { +export const rdsQueriesExecuted: MetricsUIAggregation = { rdsQueriesExecuted: { avg: { field: 'aws.rds.queries', diff --git a/x-pack/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_bucket_size.ts b/x-pack/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_bucket_size.ts index a99753a39c97c..b087d63f95863 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_bucket_size.ts +++ b/x-pack/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_bucket_size.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const s3BucketSize: SnapshotModel = { +export const s3BucketSize: MetricsUIAggregation = { s3BucketSize: { max: { field: 'aws.s3_daily_storage.bucket.size.bytes', diff --git a/x-pack/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_download_bytes.ts b/x-pack/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_download_bytes.ts index a0b23dadee37a..393f09b7340ed 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_download_bytes.ts +++ b/x-pack/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_download_bytes.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const s3DownloadBytes: SnapshotModel = { +export const s3DownloadBytes: MetricsUIAggregation = { s3DownloadBytes: { max: { field: 'aws.s3_request.downloaded.bytes', diff --git a/x-pack/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_number_of_objects.ts b/x-pack/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_number_of_objects.ts index 29162a59db47a..4e360c93ae26c 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_number_of_objects.ts +++ b/x-pack/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_number_of_objects.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const s3NumberOfObjects: SnapshotModel = { +export const s3NumberOfObjects: MetricsUIAggregation = { s3NumberOfObjects: { max: { field: 'aws.s3_daily_storage.number_of_objects', diff --git a/x-pack/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_total_requests.ts b/x-pack/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_total_requests.ts index bc57c6eb38234..87fcd27efa1ec 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_total_requests.ts +++ b/x-pack/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_total_requests.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const s3TotalRequests: SnapshotModel = { +export const s3TotalRequests: MetricsUIAggregation = { s3TotalRequests: { max: { field: 'aws.s3_request.requests.total', diff --git a/x-pack/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_upload_bytes.ts b/x-pack/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_upload_bytes.ts index 977d73254c3cd..c5b7f50a39051 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_upload_bytes.ts +++ b/x-pack/plugins/infra/common/inventory_models/aws_s3/metrics/snapshot/s3_upload_bytes.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const s3UploadBytes: SnapshotModel = { +export const s3UploadBytes: MetricsUIAggregation = { s3UploadBytes: { max: { field: 'aws.s3_request.uploaded.bytes', diff --git a/x-pack/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_delayed.ts b/x-pack/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_delayed.ts index 679f86671725e..630c7946e4478 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_delayed.ts +++ b/x-pack/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_delayed.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const sqsMessagesDelayed: SnapshotModel = { +export const sqsMessagesDelayed: MetricsUIAggregation = { sqsMessagesDelayed: { max: { field: 'aws.sqs.messages.delayed', diff --git a/x-pack/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_empty.ts b/x-pack/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_empty.ts index d80a3f3451e1d..15d1cf9b5df81 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_empty.ts +++ b/x-pack/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_empty.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const sqsMessagesEmpty: SnapshotModel = { +export const sqsMessagesEmpty: MetricsUIAggregation = { sqsMessagesEmpty: { max: { field: 'aws.sqs.messages.not_visible', diff --git a/x-pack/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_sent.ts b/x-pack/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_sent.ts index 3d6934bf3da85..fd6ea2ee53ed2 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_sent.ts +++ b/x-pack/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_sent.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const sqsMessagesSent: SnapshotModel = { +export const sqsMessagesSent: MetricsUIAggregation = { sqsMessagesSent: { max: { field: 'aws.sqs.messages.sent', diff --git a/x-pack/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_visible.ts b/x-pack/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_visible.ts index 1a78c50cd7949..26a1084c63e46 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_visible.ts +++ b/x-pack/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_messages_visible.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const sqsMessagesVisible: SnapshotModel = { +export const sqsMessagesVisible: MetricsUIAggregation = { sqsMessagesVisible: { avg: { field: 'aws.sqs.messages.visible', diff --git a/x-pack/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_oldest_message.ts b/x-pack/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_oldest_message.ts index ae780069c8ca1..1314579319264 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_oldest_message.ts +++ b/x-pack/plugins/infra/common/inventory_models/aws_sqs/metrics/snapshot/sqs_oldest_message.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const sqsOldestMessage: SnapshotModel = { +export const sqsOldestMessage: MetricsUIAggregation = { sqsOldestMessage: { max: { field: 'aws.sqs.oldest_message_age.sec', diff --git a/x-pack/plugins/infra/common/inventory_models/container/metrics/snapshot/cpu.ts b/x-pack/plugins/infra/common/inventory_models/container/metrics/snapshot/cpu.ts index a6c25ee260cac..d5a6229ff56f1 100644 --- a/x-pack/plugins/infra/common/inventory_models/container/metrics/snapshot/cpu.ts +++ b/x-pack/plugins/infra/common/inventory_models/container/metrics/snapshot/cpu.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const cpu: SnapshotModel = { +export const cpu: MetricsUIAggregation = { cpu: { avg: { field: 'docker.cpu.total.pct', diff --git a/x-pack/plugins/infra/common/inventory_models/container/metrics/snapshot/memory.ts b/x-pack/plugins/infra/common/inventory_models/container/metrics/snapshot/memory.ts index 30df0ebbaa1d4..693f9569edd77 100644 --- a/x-pack/plugins/infra/common/inventory_models/container/metrics/snapshot/memory.ts +++ b/x-pack/plugins/infra/common/inventory_models/container/metrics/snapshot/memory.ts @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const memory: SnapshotModel = { memory: { avg: { field: 'docker.memory.usage.pct' } } }; +export const memory: MetricsUIAggregation = { + memory: { avg: { field: 'docker.memory.usage.pct' } }, +}; diff --git a/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/cpu.ts b/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/cpu.ts index fa43acb8d6108..047593d65c546 100644 --- a/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/cpu.ts +++ b/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/cpu.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const cpu: SnapshotModel = { +export const cpu: MetricsUIAggregation = { cpu_user: { avg: { field: 'system.cpu.user.pct', diff --git a/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/load.ts b/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/load.ts index 803fb2664ad27..d42ed590f1bd8 100644 --- a/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/load.ts +++ b/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/load.ts @@ -4,6 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const load: SnapshotModel = { load: { avg: { field: 'system.load.5' } } }; +export const load: MetricsUIAggregation = { load: { avg: { field: 'system.load.5' } } }; diff --git a/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/log_rate.ts b/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/log_rate.ts index 658111bd07676..5e516d12eadf8 100644 --- a/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/log_rate.ts +++ b/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/log_rate.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const logRate: SnapshotModel = { +export const logRate: MetricsUIAggregation = { count: { bucket_script: { buckets_path: { count: '_count' }, diff --git a/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/memory.ts b/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/memory.ts index cb08a9eaebb3b..adfe831fa658d 100644 --- a/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/memory.ts +++ b/x-pack/plugins/infra/common/inventory_models/host/metrics/snapshot/memory.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const memory: SnapshotModel = { +export const memory: MetricsUIAggregation = { memory: { avg: { field: 'system.memory.actual.used.pct' } }, }; diff --git a/x-pack/plugins/infra/common/inventory_models/index.ts b/x-pack/plugins/infra/common/inventory_models/index.ts index 1ddf92516c409..84bdb7887b1d1 100644 --- a/x-pack/plugins/infra/common/inventory_models/index.ts +++ b/x-pack/plugins/infra/common/inventory_models/index.ts @@ -51,9 +51,9 @@ const getFieldByType = (type: InventoryItemType, fields: InventoryFields) => { } }; -export const findInventoryFields = (type: InventoryItemType, fields: InventoryFields) => { +export const findInventoryFields = (type: InventoryItemType, fields?: InventoryFields) => { const inventoryModel = findInventoryModel(type); - if (LEGACY_TYPES.includes(type)) { + if (fields && LEGACY_TYPES.includes(type)) { const id = getFieldByType(type, fields) || inventoryModel.fields.id; return { ...inventoryModel.fields, diff --git a/x-pack/plugins/infra/common/inventory_models/pod/metrics/snapshot/cpu.ts b/x-pack/plugins/infra/common/inventory_models/pod/metrics/snapshot/cpu.ts index d5979d455f0bf..18292b9cf326d 100644 --- a/x-pack/plugins/infra/common/inventory_models/pod/metrics/snapshot/cpu.ts +++ b/x-pack/plugins/infra/common/inventory_models/pod/metrics/snapshot/cpu.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const cpu: SnapshotModel = { +export const cpu: MetricsUIAggregation = { cpu_with_limit: { avg: { field: 'kubernetes.pod.cpu.usage.limit.pct', diff --git a/x-pack/plugins/infra/common/inventory_models/pod/metrics/snapshot/memory.ts b/x-pack/plugins/infra/common/inventory_models/pod/metrics/snapshot/memory.ts index 28a71d9b0275a..9b78d625b73d6 100644 --- a/x-pack/plugins/infra/common/inventory_models/pod/metrics/snapshot/memory.ts +++ b/x-pack/plugins/infra/common/inventory_models/pod/metrics/snapshot/memory.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const memory: SnapshotModel = { +export const memory: MetricsUIAggregation = { memory: { avg: { field: 'kubernetes.pod.memory.usage.node.pct' } }, }; diff --git a/x-pack/plugins/infra/common/inventory_models/shared/metrics/snapshot/count.ts b/x-pack/plugins/infra/common/inventory_models/shared/metrics/snapshot/count.ts index ed8398a5d4a77..428d542542c4c 100644 --- a/x-pack/plugins/infra/common/inventory_models/shared/metrics/snapshot/count.ts +++ b/x-pack/plugins/infra/common/inventory_models/shared/metrics/snapshot/count.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const count: SnapshotModel = { +export const count: MetricsUIAggregation = { count: { bucket_script: { buckets_path: { count: '_count' }, diff --git a/x-pack/plugins/infra/common/inventory_models/shared/metrics/snapshot/network_traffic.ts b/x-pack/plugins/infra/common/inventory_models/shared/metrics/snapshot/network_traffic.ts index 37e90a6416ba7..28c866ff44b98 100644 --- a/x-pack/plugins/infra/common/inventory_models/shared/metrics/snapshot/network_traffic.ts +++ b/x-pack/plugins/infra/common/inventory_models/shared/metrics/snapshot/network_traffic.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const networkTraffic = (id: string, field: string): SnapshotModel => { +export const networkTraffic = (id: string, field: string): MetricsUIAggregation => { return { [`${id}_max`]: { max: { field } }, [`${id}_deriv`]: { diff --git a/x-pack/plugins/infra/common/inventory_models/shared/metrics/snapshot/network_traffic_with_interfaces.ts b/x-pack/plugins/infra/common/inventory_models/shared/metrics/snapshot/network_traffic_with_interfaces.ts index 1ba5cf037e708..3ba8f2eafcc27 100644 --- a/x-pack/plugins/infra/common/inventory_models/shared/metrics/snapshot/network_traffic_with_interfaces.ts +++ b/x-pack/plugins/infra/common/inventory_models/shared/metrics/snapshot/network_traffic_with_interfaces.ts @@ -4,13 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; export const networkTrafficWithInterfaces = ( id: string, metricField: string, interfaceField: string -): SnapshotModel => ({ +): MetricsUIAggregation => ({ [`${id}_interfaces`]: { terms: { field: interfaceField }, aggregations: { diff --git a/x-pack/plugins/infra/common/inventory_models/shared/metrics/snapshot/rate.ts b/x-pack/plugins/infra/common/inventory_models/shared/metrics/snapshot/rate.ts index e1c7c7df52628..312d4e8062988 100644 --- a/x-pack/plugins/infra/common/inventory_models/shared/metrics/snapshot/rate.ts +++ b/x-pack/plugins/infra/common/inventory_models/shared/metrics/snapshot/rate.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SnapshotModel } from '../../../types'; +import { MetricsUIAggregation } from '../../../types'; -export const rate = (id: string, field: string): SnapshotModel => { +export const rate = (id: string, field: string): MetricsUIAggregation => { return { [`${id}_max`]: { max: { field } }, [`${id}_deriv`]: { diff --git a/x-pack/plugins/infra/common/inventory_models/types.ts b/x-pack/plugins/infra/common/inventory_models/types.ts index 2c6432c3e5286..570220bbc7aa5 100644 --- a/x-pack/plugins/infra/common/inventory_models/types.ts +++ b/x-pack/plugins/infra/common/inventory_models/types.ts @@ -224,7 +224,7 @@ export type TSVBMetricModelCreator = ( interval: string ) => TSVBMetricModel; -export const SnapshotModelMetricAggRT = rt.record( +export const ESBasicMetricAggRT = rt.record( rt.string, rt.union([ rt.undefined, @@ -234,7 +234,21 @@ export const SnapshotModelMetricAggRT = rt.record( ]) ); -export const SnapshotModelBucketScriptRT = rt.type({ +export const ESPercentileAggRT = rt.type({ + percentiles: rt.type({ + field: rt.string, + percents: rt.array(rt.number), + }), +}); + +export const ESCaridnalityAggRT = rt.type({ + cardinality: rt.partial({ + field: rt.string, + script: rt.string, + }), +}); + +export const ESBucketScriptAggRT = rt.type({ bucket_script: rt.intersection([ rt.type({ buckets_path: rt.record(rt.string, rt.union([rt.undefined, rt.string])), @@ -247,13 +261,13 @@ export const SnapshotModelBucketScriptRT = rt.type({ ]), }); -export const SnapshotModelCumulativeSumRT = rt.type({ +export const ESCumulativeSumAggRT = rt.type({ cumulative_sum: rt.type({ buckets_path: rt.string, }), }); -export const SnapshotModelDerivativeRT = rt.type({ +export const ESDerivativeAggRT = rt.type({ derivative: rt.type({ buckets_path: rt.string, gap_policy: rt.keyof({ skip: null, insert_zeros: null }), @@ -261,7 +275,7 @@ export const SnapshotModelDerivativeRT = rt.type({ }), }); -export const SnapshotModelSumBucketRT = rt.type({ +export const ESSumBucketAggRT = rt.type({ sum_bucket: rt.type({ buckets_path: rt.string, }), @@ -269,32 +283,31 @@ export const SnapshotModelSumBucketRT = rt.type({ interface SnapshotTermsWithAggregation { terms: { field: string }; - aggregations: SnapshotModel; + aggregations: MetricsUIAggregation; } -export const SnapshotTermsWithAggregationRT: rt.Type = rt.recursion( +export const ESTermsWithAggregationRT: rt.Type = rt.recursion( 'SnapshotModelRT', () => rt.type({ terms: rt.type({ field: rt.string }), - aggregations: SnapshotModelRT, + aggregations: MetricsUIAggregationRT, }) ); -export const SnapshotModelAggregationRT = rt.union([ - SnapshotModelMetricAggRT, - SnapshotModelBucketScriptRT, - SnapshotModelCumulativeSumRT, - SnapshotModelDerivativeRT, - SnapshotModelSumBucketRT, - SnapshotTermsWithAggregationRT, +export const ESAggregationRT = rt.union([ + ESBasicMetricAggRT, + ESPercentileAggRT, + ESBucketScriptAggRT, + ESCumulativeSumAggRT, + ESDerivativeAggRT, + ESSumBucketAggRT, + ESTermsWithAggregationRT, + ESCaridnalityAggRT, ]); -export const SnapshotModelRT = rt.record( - rt.string, - rt.union([rt.undefined, SnapshotModelAggregationRT]) -); -export type SnapshotModel = rt.TypeOf; +export const MetricsUIAggregationRT = rt.record(rt.string, ESAggregationRT); +export type MetricsUIAggregation = rt.TypeOf; export const SnapshotMetricTypeRT = rt.keyof({ count: null, @@ -327,7 +340,7 @@ export type SnapshotMetricType = rt.TypeOf; export interface InventoryMetrics { tsvb: { [name: string]: TSVBMetricModelCreator }; - snapshot: { [name: string]: SnapshotModel }; + snapshot: { [name: string]: MetricsUIAggregation }; defaultSnapshot: SnapshotMetricType; /** This is used by the inventory view to calculate the appropriate amount of time for the metrics detail page. Some metris like awsS3 require multiple days where others like host only need an hour.*/ defaultTimeRangeInSeconds: number; diff --git a/x-pack/plugins/infra/public/components/source_configuration/indices_configuration_panel.tsx b/x-pack/plugins/infra/public/components/source_configuration/indices_configuration_panel.tsx index e9817331ace93..d5fafe3ce41a0 100644 --- a/x-pack/plugins/infra/public/components/source_configuration/indices_configuration_panel.tsx +++ b/x-pack/plugins/infra/public/components/source_configuration/indices_configuration_panel.tsx @@ -16,6 +16,7 @@ import { import { FormattedMessage } from '@kbn/i18n/react'; import React from 'react'; +import { METRICS_INDEX_PATTERN } from '../../../common/constants'; import { InputFieldProps } from './input_fields'; interface IndicesConfigurationPanelProps { @@ -63,7 +64,7 @@ export const IndicesConfigurationPanel = ({ id="xpack.infra.sourceConfiguration.metricIndicesRecommendedValue" defaultMessage="The recommended value is {defaultValue}" values={{ - defaultValue: metrics-*,metricbeat-*, + defaultValue: {METRICS_INDEX_PATTERN}, }} /> } diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_title.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_title.tsx index e756c3bc393ce..c40aef5888ad7 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_title.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/chart_title.tsx @@ -6,12 +6,17 @@ import React, { Fragment } from 'react'; import { EuiText, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { MetricsExplorerSeries } from '../../../../../common/http_api'; interface Props { series: MetricsExplorerSeries; } +const ALL_TITLE = i18n.translate('xpack.infra.metricsExplorer.everything', { + defaultMessage: 'Everything', +}); + export const ChartTitle = ({ series }: Props) => { if (series.keys != null) { const { keys } = series; @@ -21,7 +26,7 @@ export const ChartTitle = ({ series }: Props) => { i ? 'subdued' : 'default'}> - {name} + {name === '*' ? ALL_TITLE : name} {keys.length - 1 > i && ( diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/get_metric_id.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/get_metric_id.ts index 35ca2561b0862..17548de9b2e78 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/get_metric_id.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/get_metric_id.ts @@ -7,8 +7,5 @@ import { MetricsExplorerOptionsMetric } from '../../hooks/use_metrics_explorer_options'; export const getMetricId = (metric: MetricsExplorerOptionsMetric, index: string | number) => { - if (['p95', 'p99'].includes(metric.aggregation)) { - return `metric_${index}:percentile_0`; - } return `metric_${index}`; }; diff --git a/x-pack/plugins/infra/server/lib/metrics/constants.ts b/x-pack/plugins/infra/server/lib/metrics/constants.ts new file mode 100644 index 0000000000000..590eaf5605c72 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/constants.ts @@ -0,0 +1,16 @@ +/* + * 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 EMPTY_RESPONSE = { + series: [ + { + id: '*', + keys: ['*'], + columns: [], + rows: [], + }, + ], + info: { total: 0, afterKey: null, interval: 0 }, +}; diff --git a/x-pack/plugins/infra/server/lib/metrics/index.ts b/x-pack/plugins/infra/server/lib/metrics/index.ts new file mode 100644 index 0000000000000..183254a0486a2 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/index.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 { set } from '@elastic/safer-lodash-set'; +import { ThrowReporter } from 'io-ts/lib/ThrowReporter'; +import { MetricsAPIRequest, MetricsAPIResponse, afterKeyObjectRT } from '../../../common/http_api'; +import { + ESSearchClient, + GroupingResponseRT, + MetricsESResponse, + HistogramResponseRT, +} from './types'; +import { EMPTY_RESPONSE } from './constants'; +import { createAggregations } from './lib/create_aggregations'; +import { convertHistogramBucketsToTimeseries } from './lib/convert_histogram_buckets_to_timeseries'; +import { calculateBucketSize } from './lib/calculate_bucket_size'; + +export const query = async ( + search: ESSearchClient, + options: MetricsAPIRequest +): Promise => { + const hasGroupBy = Array.isArray(options.groupBy) && options.groupBy.length > 0; + const filter: Array> = [ + { + range: { + [options.timerange.field]: { + gte: options.timerange.from, + lte: options.timerange.to, + format: 'epoch_millis', + }, + }, + }, + ...(options.groupBy?.map((field) => ({ exists: { field } })) ?? []), + ]; + const params = { + allowNoIndices: true, + ignoreUnavailable: true, + index: options.indexPattern, + body: { + size: 0, + query: { bool: { filter } }, + aggs: { ...createAggregations(options) }, + }, + }; + + if (hasGroupBy) { + if (options.afterKey) { + if (afterKeyObjectRT.is(options.afterKey)) { + set(params, 'body.aggs.groupings.composite.after', options.afterKey); + } else { + set(params, 'body.aggs.groupings.composite.after', { groupBy0: options.afterKey }); + } + } + } + + if (options.filters) { + params.body.query.bool.filter = [...params.body.query.bool.filter, ...options.filters]; + } + + const response = await search<{}, MetricsESResponse>(params); + + if (response.hits.total.value === 0) { + return EMPTY_RESPONSE; + } + + if (!response.aggregations) { + throw new Error('Aggregations should be present.'); + } + + const { bucketSize } = calculateBucketSize(options.timerange); + + if (hasGroupBy && GroupingResponseRT.is(response.aggregations)) { + const { groupings } = response.aggregations; + const { after_key: afterKey } = groupings; + const limit = options.limit || 9; + const returnAfterKey = afterKey && groupings.buckets.length === limit ? true : false; + return { + series: groupings.buckets.map((bucket) => { + const keys = Object.values(bucket.key); + return convertHistogramBucketsToTimeseries(keys, options, bucket.histogram.buckets); + }), + info: { + afterKey: returnAfterKey ? afterKey : null, + interval: bucketSize, + }, + }; + } else if (hasGroupBy) { + ThrowReporter.report(GroupingResponseRT.decode(response.aggregations)); + } + + if (HistogramResponseRT.is(response.aggregations)) { + return { + series: [ + convertHistogramBucketsToTimeseries( + ['*'], + options, + response.aggregations.histogram.buckets + ), + ], + info: { + afterKey: null, + interval: bucketSize, + }, + }; + } else { + ThrowReporter.report(HistogramResponseRT.decode(response.aggregations)); + } + + throw new Error('Elasticsearch responsed with an unrecoginzed format.'); +}; diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/__snapshots__/convert_histogram_buckets_to_timeseries.test.ts.snap b/x-pack/plugins/infra/server/lib/metrics/lib/__snapshots__/convert_histogram_buckets_to_timeseries.test.ts.snap new file mode 100644 index 0000000000000..9f4cd67c07b6b --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/lib/__snapshots__/convert_histogram_buckets_to_timeseries.test.ts.snap @@ -0,0 +1,193 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`convertHistogramBucketsToTimeseies(keys, options, buckets) should drop the last bucket 1`] = ` +Object { + "columns": Array [ + Object { + "name": "timestamp", + "type": "date", + }, + Object { + "name": "metric_0", + "type": "number", + }, + ], + "id": "example-0", + "keys": Array [ + "example-0", + ], + "rows": Array [ + Object { + "metric_0": 1, + "timestamp": 1577836800000, + }, + Object { + "metric_0": 1, + "timestamp": 1577836860000, + }, + Object { + "metric_0": 1, + "timestamp": 1577836920000, + }, + ], +} +`; + +exports[`convertHistogramBucketsToTimeseies(keys, options, buckets) should just work 1`] = ` +Object { + "columns": Array [ + Object { + "name": "timestamp", + "type": "date", + }, + Object { + "name": "metric_0", + "type": "number", + }, + ], + "id": "example-0", + "keys": Array [ + "example-0", + ], + "rows": Array [ + Object { + "metric_0": 1, + "timestamp": 1577836800000, + }, + Object { + "metric_0": 1, + "timestamp": 1577836860000, + }, + Object { + "metric_0": 1, + "timestamp": 1577836920000, + }, + Object { + "metric_0": null, + "timestamp": 1577836920000, + }, + ], +} +`; + +exports[`convertHistogramBucketsToTimeseies(keys, options, buckets) should return empty timeseries for empty metrics 1`] = ` +Object { + "columns": Array [], + "id": "example-0", + "keys": Array [ + "example-0", + ], + "rows": Array [], +} +`; + +exports[`convertHistogramBucketsToTimeseies(keys, options, buckets) should work with keyed percentiles 1`] = ` +Object { + "columns": Array [ + Object { + "name": "timestamp", + "type": "date", + }, + Object { + "name": "metric_0", + "type": "number", + }, + ], + "id": "example-0", + "keys": Array [ + "example-0", + ], + "rows": Array [ + Object { + "metric_0": 4, + "timestamp": 1577836800000, + }, + Object { + "metric_0": 4, + "timestamp": 1577836860000, + }, + Object { + "metric_0": 4, + "timestamp": 1577836920000, + }, + Object { + "metric_0": 4, + "timestamp": 1577836920000, + }, + ], +} +`; + +exports[`convertHistogramBucketsToTimeseies(keys, options, buckets) should work with normalized_values 1`] = ` +Object { + "columns": Array [ + Object { + "name": "timestamp", + "type": "date", + }, + Object { + "name": "metric_0", + "type": "number", + }, + ], + "id": "example-0", + "keys": Array [ + "example-0", + ], + "rows": Array [ + Object { + "metric_0": 2, + "timestamp": 1577836800000, + }, + Object { + "metric_0": 2, + "timestamp": 1577836860000, + }, + Object { + "metric_0": 2, + "timestamp": 1577836920000, + }, + Object { + "metric_0": null, + "timestamp": 1577836920000, + }, + ], +} +`; + +exports[`convertHistogramBucketsToTimeseies(keys, options, buckets) should work with percentiles 1`] = ` +Object { + "columns": Array [ + Object { + "name": "timestamp", + "type": "date", + }, + Object { + "name": "metric_0", + "type": "number", + }, + ], + "id": "example-0", + "keys": Array [ + "example-0", + ], + "rows": Array [ + Object { + "metric_0": 3, + "timestamp": 1577836800000, + }, + Object { + "metric_0": 3, + "timestamp": 1577836860000, + }, + Object { + "metric_0": 3, + "timestamp": 1577836920000, + }, + Object { + "metric_0": 3, + "timestamp": 1577836920000, + }, + ], +} +`; diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/__snapshots__/create_aggregations.test.ts.snap b/x-pack/plugins/infra/server/lib/metrics/lib/__snapshots__/create_aggregations.test.ts.snap new file mode 100644 index 0000000000000..d2d90914eced5 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/lib/__snapshots__/create_aggregations.test.ts.snap @@ -0,0 +1,87 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`createAggregations(options) should return add offset to histogram 1`] = ` +Object { + "histogram": Object { + "aggregations": Object { + "metric_0": Object { + "avg": Object { + "field": "system.cpu.user.pct", + }, + }, + }, + "date_histogram": Object { + "extended_bounds": Object { + "max": 1577838720000, + "min": 1577835120000, + }, + "field": "@timestamp", + "fixed_interval": "1m", + "offset": "-60s", + }, + }, +} +`; + +exports[`createAggregations(options) should return groupings aggregation with groupBy 1`] = ` +Object { + "groupings": Object { + "aggs": Object { + "histogram": Object { + "aggregations": Object { + "metric_0": Object { + "avg": Object { + "field": "system.cpu.user.pct", + }, + }, + }, + "date_histogram": Object { + "extended_bounds": Object { + "max": 1577840400000, + "min": 1577836800000, + }, + "field": "@timestamp", + "fixed_interval": "1m", + "offset": "0s", + }, + }, + }, + "composite": Object { + "size": 20, + "sources": Array [ + Object { + "groupBy0": Object { + "terms": Object { + "field": "host.name", + "order": "asc", + }, + }, + }, + ], + }, + }, +} +`; + +exports[`createAggregations(options) should return just histogram aggregation without groupBy 1`] = ` +Object { + "histogram": Object { + "aggregations": Object { + "metric_0": Object { + "avg": Object { + "field": "system.cpu.user.pct", + }, + }, + }, + "date_histogram": Object { + "extended_bounds": Object { + "max": 1577840400000, + "min": 1577836800000, + }, + "field": "@timestamp", + "fixed_interval": "1m", + "offset": "0s", + }, + }, +} +`; diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/__snapshots__/create_metrics_aggregations.test.ts.snap b/x-pack/plugins/infra/server/lib/metrics/lib/__snapshots__/create_metrics_aggregations.test.ts.snap new file mode 100644 index 0000000000000..bbfe7e9cf0f9f --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/lib/__snapshots__/create_metrics_aggregations.test.ts.snap @@ -0,0 +1,23 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`createMetricsAggregations(options) should just work 1`] = ` +Object { + "metric_0": Object { + "avg": Object { + "field": "system.cpu.user.pct", + }, + }, + "metric_1": Object { + "derivative": Object { + "buckets_path": "metric_1_max", + "gap_policy": "skip", + "unit": "1s", + }, + }, + "metric_1_max": Object { + "max": Object { + "field": "system.network.in.bytes", + }, + }, +} +`; diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/calculate_auto.test.ts b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/calculate_auto.test.ts new file mode 100644 index 0000000000000..a2f8a08afc303 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/calculate_auto.test.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { calculateAuto } from './calculate_auto'; +import moment, { isDuration } from 'moment'; + +describe('calculateAuto.near(bucket, duration)', () => { + it('should calculate the bucket size for 15 minutes', () => { + const bucketSizeDuration = calculateAuto.near(100, moment.duration(15, 'minutes')); + expect(bucketSizeDuration).not.toBeUndefined(); + expect(isDuration(bucketSizeDuration)).toBeTruthy(); + expect(bucketSizeDuration!.asSeconds()).toBe(10); + }); + it('should calculate the bucket size for an hour', () => { + const bucketSizeDuration = calculateAuto.near(100, moment.duration(1, 'hour')); + expect(bucketSizeDuration).not.toBeUndefined(); + expect(isDuration(bucketSizeDuration)).toBeTruthy(); + expect(bucketSizeDuration!.asSeconds()).toBe(30); + }); + it('should calculate the bucket size for a day', () => { + const bucketSizeDuration = calculateAuto.near(100, moment.duration(1, 'day')); + expect(bucketSizeDuration).not.toBeUndefined(); + expect(isDuration(bucketSizeDuration)).toBeTruthy(); + expect(bucketSizeDuration!.asMinutes()).toBe(10); + }); +}); diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/calculate_auto.ts b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/calculate_auto.ts new file mode 100644 index 0000000000000..00f321b25016d --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/calculate_auto.ts @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import moment, { isDuration, Duration } from 'moment'; +import { isNumber } from 'lodash'; +const d = moment.duration; + +const roundingRules = [ + [d(500, 'ms'), d(100, 'ms')], + [d(5, 'second'), d(1, 'second')], + [d(7.5, 'second'), d(5, 'second')], + [d(15, 'second'), d(10, 'second')], + [d(45, 'second'), d(30, 'second')], + [d(3, 'minute'), d(1, 'minute')], + [d(9, 'minute'), d(5, 'minute')], + [d(20, 'minute'), d(10, 'minute')], + [d(45, 'minute'), d(30, 'minute')], + [d(2, 'hour'), d(1, 'hour')], + [d(6, 'hour'), d(3, 'hour')], + [d(24, 'hour'), d(12, 'hour')], + [d(1, 'week'), d(1, 'd')], + [d(3, 'week'), d(1, 'week')], + [d(1, 'year'), d(1, 'month')], + [Infinity, d(1, 'year')], +]; + +const revRoundingRules = [...roundingRules].reverse(); + +type NumberOrDuration = number | Duration; + +type Rule = NumberOrDuration[]; + +type CheckFunction = ( + bound: NumberOrDuration, + interval: Duration, + target: number +) => Duration | undefined; + +function findRule(rules: Rule[], check: CheckFunction, last?: boolean) { + function pickInterval(buckets: number, duration: Duration) { + const target = duration.asMilliseconds() / buckets; + let lastResult = null; + + for (const rule of rules) { + const result = check(rule[0] as Duration, rule[1] as Duration, target); + + if (result == null) { + if (!last) continue; + if (lastResult) return lastResult; + break; + } + + if (!last) return result; + lastResult = result; + } + + // fallback to just a number of milliseconds, ensure ms is >= 1 + const ms = Math.max(Math.floor(target), 1); + return moment.duration(ms, 'ms'); + } + + return (buckets: number, duration: Duration) => { + const interval = pickInterval(buckets, duration); + if (isDuration(interval)) return interval; + }; +} + +export const calculateAuto = { + near: findRule( + revRoundingRules, + function near(bound, interval, target) { + if (isDuration(bound) && bound.asMilliseconds() > target) return interval; + if (isNumber(bound) && bound > target) return interval; + }, + true + ), + + lessThan: findRule(revRoundingRules, function lessThan(_bound, interval, target) { + if (interval.asMilliseconds() < target) return interval; + }), + + atLeast: findRule(revRoundingRules, function atLeast(_bound, interval, target) { + if (interval.asMilliseconds() <= target) return interval; + }), +}; diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/calculate_bucket_size.test.ts b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/calculate_bucket_size.test.ts new file mode 100644 index 0000000000000..bc54593f10cb9 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/calculate_bucket_size.test.ts @@ -0,0 +1,53 @@ +/* + * 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 { calculateBucketSize } from './'; +import moment from 'moment'; + +const timerange = { + from: moment('2017-01-01T00:00:00.000Z').valueOf(), + to: moment('2017-01-01T01:00:00.000Z').valueOf(), + interval: '1m', + field: '@timetsamp', +}; + +describe('calculateBucketSize(timerange, intervalString)', () => { + test('returns auto calculated buckets', () => { + const result = calculateBucketSize({ ...timerange, interval: 'auto' }); + expect(result).toHaveProperty('bucketSize', 30); + expect(result).toHaveProperty('intervalString', '30s'); + }); + + test('returns overridden buckets (1s)', () => { + const result = calculateBucketSize({ ...timerange, interval: '1s' }); + expect(result).toHaveProperty('bucketSize', 1); + expect(result).toHaveProperty('intervalString', '1s'); + }); + + test('returns overridden buckets (10m)', () => { + const result = calculateBucketSize({ ...timerange, interval: '10m' }); + expect(result).toHaveProperty('bucketSize', 600); + expect(result).toHaveProperty('intervalString', '10m'); + }); + + test('returns overridden buckets (1d)', () => { + const result = calculateBucketSize({ ...timerange, interval: '1d' }); + expect(result).toHaveProperty('bucketSize', 86400); + expect(result).toHaveProperty('intervalString', '1d'); + }); + + test('returns overridden buckets (>=2d)', () => { + const result = calculateBucketSize({ ...timerange, interval: '>=2d' }); + expect(result).toHaveProperty('bucketSize', 86400 * 2); + expect(result).toHaveProperty('intervalString', '2d'); + }); + + test('returns overridden buckets (>=10s)', () => { + const result = calculateBucketSize({ ...timerange, interval: '>=10s' }); + expect(result).toHaveProperty('bucketSize', 30); + expect(result).toHaveProperty('intervalString', '30s'); + }); +}); diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/index.ts b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/index.ts new file mode 100644 index 0000000000000..62e4aed6d4049 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/index.ts @@ -0,0 +1,89 @@ +/* + * 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 moment from 'moment'; +import { MetricsAPITimerange } from '../../../../../common/http_api'; +import { calculateAuto } from './calculate_auto'; +import { + getUnitValue, + parseInterval, + convertIntervalToUnit, + ASCENDING_UNIT_ORDER, +} from './unit_to_seconds'; +import { INTERVAL_STRING_RE, GTE_INTERVAL_RE } from './interval_regex'; + +const calculateBucketData = (intervalString: string) => { + const intervalStringMatch = intervalString.match(INTERVAL_STRING_RE); + + if (!intervalStringMatch) { + throw new Error('Unable to parse interval string'); + } + + const parsedInterval = parseInterval(intervalString); + + if (!parsedInterval) { + throw new Error('Unable to parse interval string'); + } + + let bucketSize = Number(intervalStringMatch[1]) * getUnitValue(intervalStringMatch[2]); + + // don't go too small + if (bucketSize < 1) { + bucketSize = 1; + } + + // Check decimal + if (parsedInterval.value && parsedInterval.value % 1 !== 0) { + if (parsedInterval.unit && parsedInterval.unit !== 'ms') { + const { value, unit } = convertIntervalToUnit( + intervalString, + ASCENDING_UNIT_ORDER[ASCENDING_UNIT_ORDER.indexOf(parsedInterval.unit) - 1] + ); + + if (value && unit) { + intervalString = value + unit; + } else { + intervalString = '1ms'; + } + } else { + intervalString = '1ms'; + } + } + + return { + bucketSize, + intervalString, + }; +}; + +const calculateBucketSizeForAutoInterval = (timerange: MetricsAPITimerange): number | undefined => { + const duration = moment.duration(timerange.to - timerange.from, 'ms'); + const bucketSizeDuration = calculateAuto.near(100, duration); + if (bucketSizeDuration) { + return bucketSizeDuration.asSeconds(); + } +}; + +export const calculateBucketSize = (timerange: MetricsAPITimerange) => { + const bucketSize = calculateBucketSizeForAutoInterval(timerange); + let intervalString = `${bucketSize}s`; + + const gteAutoMatch = timerange.interval.match(GTE_INTERVAL_RE); + + if (gteAutoMatch) { + const bucketData = calculateBucketData(gteAutoMatch[1]); + if (bucketSize && bucketData.bucketSize >= bucketSize) { + return bucketData; + } + } + + const matches = timerange.interval.match(INTERVAL_STRING_RE); + if (matches) { + intervalString = timerange.interval; + } + + return calculateBucketData(intervalString); +}; diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/interval_regex.test.ts b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/interval_regex.test.ts new file mode 100644 index 0000000000000..6c2e9f8d62e36 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/interval_regex.test.ts @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { GTE_INTERVAL_RE, INTERVAL_STRING_RE } from './interval_regex'; + +describe('REGEX for Intervals', () => { + describe('GTE_INTERVAL_RE', () => { + test('returns true for">=12h"', () => { + const value = GTE_INTERVAL_RE.test('>=12h'); + + expect(value).toBeTruthy(); + }); + test('returns true for ">=1y"', () => { + const value = GTE_INTERVAL_RE.test('>=12h'); + + expect(value).toBeTruthy(); + }); + test('returns true for ">=25m"', () => { + const value = GTE_INTERVAL_RE.test('>=12h'); + + expect(value).toBeTruthy(); + }); + test('returns false "auto"', () => { + const value = GTE_INTERVAL_RE.test('auto'); + + expect(value).toBeFalsy(); + }); + test('returns false "wrongInput"', () => { + const value = GTE_INTERVAL_RE.test('wrongInput'); + + expect(value).toBeFalsy(); + }); + test('returns false "d"', () => { + const value = GTE_INTERVAL_RE.test('d'); + + expect(value).toBeFalsy(); + }); + + test('returns false "y"', () => { + const value = GTE_INTERVAL_RE.test('y'); + + expect(value).toBeFalsy(); + }); + }); + + describe('INTERVAL_STRING_RE', () => { + test('returns true for "8d"', () => { + const value = INTERVAL_STRING_RE.test('8d'); + + expect(value).toBeTruthy(); + }); + test('returns true for "1y"', () => { + const value = INTERVAL_STRING_RE.test('1y'); + + expect(value).toBeTruthy(); + }); + test('returns true for "6M"', () => { + const value = INTERVAL_STRING_RE.test('6M'); + + expect(value).toBeTruthy(); + }); + test('returns false "auto"', () => { + const value = INTERVAL_STRING_RE.test('auto'); + + expect(value).toBeFalsy(); + }); + test('returns false "wrongInput"', () => { + const value = INTERVAL_STRING_RE.test('wrongInput'); + + expect(value).toBeFalsy(); + }); + test('returns false for">=21h"', () => { + const value = INTERVAL_STRING_RE.test('>=21h'); + + expect(value).toBeFalsy(); + }); + }); +}); diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/interval_regex.ts b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/interval_regex.ts new file mode 100644 index 0000000000000..d86603551fea2 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/interval_regex.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. + */ + +import dateMath from '@elastic/datemath'; + +export const GTE_INTERVAL_RE = new RegExp(`^>=([\\d\\.]+\\s*(${dateMath.units.join('|')}))$`); +export const INTERVAL_STRING_RE = new RegExp(`^([\\d\\.]+)\\s*(${dateMath.units.join('|')})$`); diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/unit_to_seconds.test.ts b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/unit_to_seconds.test.ts new file mode 100644 index 0000000000000..68816f935a4a0 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/unit_to_seconds.test.ts @@ -0,0 +1,132 @@ +/* + * 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 { + getUnitValue, + parseInterval, + convertIntervalToUnit, + getSuitableUnit, +} from './unit_to_seconds'; + +describe('parseInterval()', () => { + test('should parse "1m" interval (positive)', () => + expect(parseInterval('1m')).toEqual({ + value: 1, + unit: 'm', + })); + + test('should parse "134d" interval (positive)', () => + expect(parseInterval('134d')).toEqual({ + value: 134, + unit: 'd', + })); + + test('should parse "0.5d" interval (positive)', () => + expect(parseInterval('0.5d')).toEqual({ + value: 0.5, + unit: 'd', + })); + + test('should parse "30M" interval (positive)', () => + expect(parseInterval('30M')).toEqual({ + value: 30, + unit: 'M', + })); + + test('should not parse "gm" interval (negative)', () => + expect(parseInterval('gm')).toEqual({ + value: undefined, + unit: undefined, + })); + + test('should not parse "-1d" interval (negative)', () => + expect(parseInterval('-1d')).toEqual({ + value: undefined, + unit: undefined, + })); + + test('should not parse "M" interval (negative)', () => + expect(parseInterval('M')).toEqual({ + value: undefined, + unit: undefined, + })); +}); + +describe('convertIntervalToUnit()', () => { + test('should convert "30m" interval to "h" unit (positive)', () => + expect(convertIntervalToUnit('30m', 'h')).toEqual({ + value: 0.5, + unit: 'h', + })); + + test('should convert "0.5h" interval to "m" unit (positive)', () => + expect(convertIntervalToUnit('0.5h', 'm')).toEqual({ + value: 30, + unit: 'm', + })); + + test('should convert "1h" interval to "m" unit (positive)', () => + expect(convertIntervalToUnit('1h', 'm')).toEqual({ + value: 60, + unit: 'm', + })); + + test('should convert "1h" interval to "ms" unit (positive)', () => + expect(convertIntervalToUnit('1h', 'ms')).toEqual({ + value: 3600000, + unit: 'ms', + })); + + test('should not convert "30m" interval to "0" unit (positive)', () => + expect(convertIntervalToUnit('30m', 'o')).toEqual({ + value: undefined, + unit: undefined, + })); + + test('should not convert "m" interval to "s" unit (positive)', () => + expect(convertIntervalToUnit('m', 's')).toEqual({ + value: undefined, + unit: undefined, + })); +}); + +describe('getSuitableUnit()', () => { + test('should return "d" unit for oneDayInSeconds (positive)', () => { + const oneDayInSeconds = getUnitValue('d') * 1; + + expect(getSuitableUnit(oneDayInSeconds)).toBe('d'); + }); + + test('should return "d" unit for twoDaysInSeconds (positive)', () => { + const twoDaysInSeconds = getUnitValue('d') * 2; + + expect(getSuitableUnit(twoDaysInSeconds)).toBe('d'); + }); + + test('should return "w" unit for threeWeeksInSeconds (positive)', () => { + const threeWeeksInSeconds = getUnitValue('w') * 3; + + expect(getSuitableUnit(threeWeeksInSeconds)).toBe('w'); + }); + + test('should return "y" unit for aroundOneYearInSeconds (positive)', () => { + const aroundOneYearInSeconds = getUnitValue('d') * 370; + + expect(getSuitableUnit(aroundOneYearInSeconds)).toBe('y'); + }); + + test('should return "y" unit for twoYearsInSeconds (positive)', () => { + const twoYearsInSeconds = getUnitValue('y') * 2; + + expect(getSuitableUnit(twoYearsInSeconds)).toBe('y'); + }); + + test('should return "undefined" unit for negativeNumber (negative)', () => { + const negativeNumber = -12; + + expect(getSuitableUnit(negativeNumber)).toBeUndefined(); + }); +}); diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/unit_to_seconds.ts b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/unit_to_seconds.ts new file mode 100644 index 0000000000000..7ca4222fe352f --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_bucket_size/unit_to_seconds.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. + */ + +import { sortBy, isNumber } from 'lodash'; +import { INTERVAL_STRING_RE } from './interval_regex'; + +export const ASCENDING_UNIT_ORDER = ['ms', 's', 'm', 'h', 'd', 'w', 'M', 'y']; + +const units: Record = { + ms: 0.001, + s: 1, + m: 60, + h: 3600, + d: 86400, + w: 86400 * 7, + M: 86400 * 30, + y: 86400 * 365, +}; + +const sortedUnits = sortBy(Object.keys(units), (key) => units[key]); + +export const parseInterval = (intervalString: string) => { + let value; + let unit; + + if (intervalString) { + const matches = intervalString.match(INTERVAL_STRING_RE); + + if (matches) { + value = Number(matches[1]); + unit = matches[2]; + } + } + + return { value, unit }; +}; + +export const convertIntervalToUnit = (intervalString: string, newUnit: string) => { + const parsedInterval = parseInterval(intervalString); + let value; + let unit; + + if (parsedInterval.unit && parsedInterval.value && units[newUnit]) { + value = Number( + ((parsedInterval.value * units[parsedInterval.unit]) / units[newUnit]).toFixed(2) + ); + unit = newUnit; + } + + return { value, unit }; +}; + +export const getSuitableUnit = (intervalInSeconds: number) => + sortedUnits.find((key, index, array) => { + const nextUnit = array[index + 1]; + const isValidInput = isNumber(intervalInSeconds) && intervalInSeconds > 0; + const isLastItem = index + 1 === array.length; + + return ( + isValidInput && + ((intervalInSeconds >= units[key] && intervalInSeconds < units[nextUnit]) || isLastItem) + ); + }); + +export const getUnitValue = (unit: string) => units[unit]; diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/calculate_date_histogram_offset.test.ts b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_date_histogram_offset.test.ts new file mode 100644 index 0000000000000..4fa313eea1852 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_date_histogram_offset.test.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 { calculateDateHistogramOffset } from './calculate_date_histogram_offset'; +import moment from 'moment'; + +describe('calculateDateHistogramOffset(timerange)', () => { + it('should just work', () => { + const timerange = { + from: moment('2020-01-01T00:03:32').valueOf(), + to: moment('2020-01-01T01:03:32').valueOf(), + interval: '1m', + field: '@timestamp', + }; + const offset = calculateDateHistogramOffset(timerange); + expect(offset).toBe('-28s'); + }); +}); diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/calculate_date_histogram_offset.ts b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_date_histogram_offset.ts new file mode 100644 index 0000000000000..673747808f5ca --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/lib/calculate_date_histogram_offset.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 { MetricsAPITimerange } from '../../../../common/http_api'; +import { calculateBucketSize } from './calculate_bucket_size'; + +export const calculateDateHistogramOffset = (timerange: MetricsAPITimerange): string => { + const fromInSeconds = Math.floor(timerange.from / 1000); + const { bucketSize } = calculateBucketSize(timerange); + + // negative offset to align buckets with full intervals (e.g. minutes) + const offset = (fromInSeconds % bucketSize) - bucketSize; + return `${offset}s`; +}; diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/convert_histogram_buckets_to_timeseries.test.ts b/x-pack/plugins/infra/server/lib/metrics/lib/convert_histogram_buckets_to_timeseries.test.ts new file mode 100644 index 0000000000000..d9de8ae7e61e5 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/lib/convert_histogram_buckets_to_timeseries.test.ts @@ -0,0 +1,120 @@ +/* + * 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 { MetricsAPIRequest } from '../../../../common/http_api'; +import moment from 'moment'; +import { convertHistogramBucketsToTimeseries } from './convert_histogram_buckets_to_timeseries'; + +const keys = ['example-0']; + +const options: MetricsAPIRequest = { + timerange: { + field: '@timestamp', + from: moment('2020-01-01T00:00:00Z').valueOf(), + to: moment('2020-01-01T01:00:00Z').valueOf(), + interval: '1m', + }, + limit: 9, + indexPattern: 'metrics-*', + metrics: [ + { id: 'metric_0', aggregations: { metric_0: { avg: { field: 'system.cpu.user.pct' } } } }, + ], +}; + +const buckets = [ + { + key: moment('2020-01-01T00:00:00Z').valueOf(), + key_as_string: moment('2020-01-01T00:00:00Z').toISOString(), + doc_count: 1, + metric_0: { value: 1 }, + }, + { + key: moment('2020-01-01T00:00:00Z').add(1, 'minute').valueOf(), + key_as_string: moment('2020-01-01T00:00:00Z').add(1, 'minute').toISOString(), + doc_count: 1, + metric_0: { value: 1 }, + }, + { + key: moment('2020-01-01T00:00:00Z').add(2, 'minute').valueOf(), + key_as_string: moment('2020-01-01T00:00:00Z').add(2, 'minute').toISOString(), + doc_count: 1, + metric_0: { value: 1 }, + }, + { + key: moment('2020-01-01T00:00:00Z').add(2, 'minute').valueOf(), + key_as_string: moment('2020-01-01T00:00:00Z').add(2, 'minute').toISOString(), + doc_count: 1, + metric_0: { value: null }, + }, +]; + +describe('convertHistogramBucketsToTimeseies(keys, options, buckets)', () => { + it('should just work', () => { + expect(convertHistogramBucketsToTimeseries(keys, options, buckets)).toMatchSnapshot(); + }); + it('should drop the last bucket', () => { + expect( + convertHistogramBucketsToTimeseries(keys, { ...options, dropLastBucket: true }, buckets) + ).toMatchSnapshot(); + }); + it('should return empty timeseries for empty metrics', () => { + expect( + convertHistogramBucketsToTimeseries(keys, { ...options, metrics: [] }, buckets) + ).toMatchSnapshot(); + }); + it('should work with normalized_values', () => { + const bucketsWithNormalizedValue = buckets.map((bucket) => { + const value = bucket.metric_0.value; + if (value) { + return { ...bucket, metric_0: { value, normalized_value: value + 1 } }; + } + return bucket; + }); + expect( + convertHistogramBucketsToTimeseries(keys, { ...options }, bucketsWithNormalizedValue) + ).toMatchSnapshot(); + }); + it('should work with percentiles', () => { + const bucketsWithPercentiles = buckets.map((bucket) => { + return { ...bucket, metric_0: { values: { '95.0': 3 } } }; + }); + expect( + convertHistogramBucketsToTimeseries(keys, { ...options }, bucketsWithPercentiles) + ).toMatchSnapshot(); + }); + it('should throw error with multiple percentiles', () => { + const bucketsWithMultiplePercentiles = buckets.map((bucket) => { + return { ...bucket, metric_0: { values: { '95.0': 3, '99.0': 4 } } }; + }); + expect(() => + convertHistogramBucketsToTimeseries(keys, { ...options }, bucketsWithMultiplePercentiles) + ).toThrow(); + }); + it('should work with keyed percentiles', () => { + const bucketsWithKeyedPercentiles = buckets.map((bucket) => { + return { ...bucket, metric_0: { values: [{ key: '99.0', value: 4 }] } }; + }); + expect( + convertHistogramBucketsToTimeseries(keys, { ...options }, bucketsWithKeyedPercentiles) + ).toMatchSnapshot(); + }); + it('should throw error with multiple keyed percentiles', () => { + const bucketsWithMultipleKeyedPercentiles = buckets.map((bucket) => { + return { + ...bucket, + metric_0: { + values: [ + { key: '95.0', value: 3 }, + { key: '99.0', value: 4 }, + ], + }, + }; + }); + expect(() => + convertHistogramBucketsToTimeseries(keys, { ...options }, bucketsWithMultipleKeyedPercentiles) + ).toThrow(); + }); +}); diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/convert_histogram_buckets_to_timeseries.ts b/x-pack/plugins/infra/server/lib/metrics/lib/convert_histogram_buckets_to_timeseries.ts new file mode 100644 index 0000000000000..95e6ece215133 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/lib/convert_histogram_buckets_to_timeseries.ts @@ -0,0 +1,93 @@ +/* + * 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 { get, values, first } from 'lodash'; +import { + MetricsAPIRequest, + MetricsAPISeries, + MetricsAPIColumn, + MetricsAPIRow, +} from '../../../../common/http_api/metrics_api'; +import { + HistogramBucket, + MetricValueType, + BasicMetricValueRT, + NormalizedMetricValueRT, + PercentilesTypeRT, + PercentilesKeyedTypeRT, +} from '../types'; +const BASE_COLUMNS = [{ name: 'timestamp', type: 'date' }] as MetricsAPIColumn[]; + +const getValue = (valueObject: string | number | MetricValueType) => { + if (NormalizedMetricValueRT.is(valueObject)) { + return valueObject.normalized_value || valueObject.value; + } + + if (PercentilesTypeRT.is(valueObject)) { + const percentileValues = values(valueObject.values); + if (percentileValues.length > 1) { + throw new Error( + 'Metrics API only supports a single percentile, multiple percentiles should be sent separately' + ); + } + return first(percentileValues) || null; + } + + if (PercentilesKeyedTypeRT.is(valueObject)) { + if (valueObject.values.length > 1) { + throw new Error( + 'Metrics API only supports a single percentile, multiple percentiles should be sent separately' + ); + } + const percentileValue = first(valueObject.values); + return (percentileValue && percentileValue.value) || null; + } + + if (BasicMetricValueRT.is(valueObject)) { + return valueObject.value; + } + + return null; +}; + +const convertBucketsToRows = ( + options: MetricsAPIRequest, + buckets: HistogramBucket[] +): MetricsAPIRow[] => { + return buckets.map((bucket) => { + const ids = options.metrics.map((metric) => metric.id); + const metrics = ids.reduce((acc, id) => { + const valueObject = get(bucket, [id]); + return { ...acc, [id]: getValue(valueObject) }; + }, {} as Record); + return { timestamp: bucket.key as number, ...metrics }; + }); +}; + +export const convertHistogramBucketsToTimeseries = ( + keys: string[], + options: MetricsAPIRequest, + buckets: HistogramBucket[] +): MetricsAPISeries => { + const id = keys.join(':'); + // If there are no metrics then we just return the empty series + // but still maintain the groupings. + if (options.metrics.length === 0) { + return { id, keys, columns: [], rows: [] }; + } + const columns = options.metrics.map((metric) => ({ + name: metric.id, + type: 'number', + })) as MetricsAPIColumn[]; + const allRows = convertBucketsToRows(options, buckets); + const rows = options.dropLastBucket ? allRows.slice(0, allRows.length - 1) : allRows; + return { + id, + keys, + rows, + columns: [...BASE_COLUMNS, ...columns], + }; +}; diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/create_aggregations.test.ts b/x-pack/plugins/infra/server/lib/metrics/lib/create_aggregations.test.ts new file mode 100644 index 0000000000000..1353351cde8a2 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/lib/create_aggregations.test.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 { createAggregations } from './create_aggregations'; +import moment from 'moment'; +import { MetricsAPIRequest } from '../../../../common/http_api'; + +const options: MetricsAPIRequest = { + timerange: { + field: '@timestamp', + from: moment('2020-01-01T00:00:00Z').valueOf(), + to: moment('2020-01-01T01:00:00Z').valueOf(), + interval: '>=1m', + }, + limit: 20, + indexPattern: 'metrics-*', + metrics: [ + { id: 'metric_0', aggregations: { metric_0: { avg: { field: 'system.cpu.user.pct' } } } }, + ], +}; + +describe('createAggregations(options)', () => { + it('should return groupings aggregation with groupBy', () => { + const optionsWithGroupBy = { ...options, groupBy: ['host.name'] }; + expect(createAggregations(optionsWithGroupBy)).toMatchSnapshot(); + }); + it('should return just histogram aggregation without groupBy', () => { + expect(createAggregations(options)).toMatchSnapshot(); + }); + it('should return add offset to histogram', () => { + const optionsWithAlignDataToEnd = { + ...options, + timerange: { + ...options.timerange, + from: moment('2020-01-01T00:00:00Z').subtract(28, 'minutes').valueOf(), + to: moment('2020-01-01T01:00:00Z').subtract(28, 'minutes').valueOf(), + }, + alignDataToEnd: true, + }; + expect(createAggregations(optionsWithAlignDataToEnd)).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/create_aggregations.ts b/x-pack/plugins/infra/server/lib/metrics/lib/create_aggregations.ts new file mode 100644 index 0000000000000..991e5febfc634 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/lib/create_aggregations.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 { MetricsAPIRequest } from '../../../../common/http_api/metrics_api'; +import { calculateDateHistogramOffset } from './calculate_date_histogram_offset'; +import { createMetricsAggregations } from './create_metrics_aggregations'; +import { calculateBucketSize } from './calculate_bucket_size'; + +export const createAggregations = (options: MetricsAPIRequest) => { + const { intervalString } = calculateBucketSize(options.timerange); + const histogramAggregation = { + histogram: { + date_histogram: { + field: options.timerange.field, + fixed_interval: intervalString, + offset: options.alignDataToEnd ? calculateDateHistogramOffset(options.timerange) : '0s', + extended_bounds: { + min: options.timerange.from, + max: options.timerange.to, + }, + }, + aggregations: createMetricsAggregations(options), + }, + }; + + if (Array.isArray(options.groupBy) && options.groupBy.length) { + const limit = options.limit || 9; + return { + groupings: { + composite: { + size: limit, + sources: options.groupBy.map((field, index) => ({ + [`groupBy${index}`]: { terms: { field, order: 'asc' } }, + })), + }, + aggs: histogramAggregation, + }, + }; + } + + return histogramAggregation; +}; diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/create_metrics_aggregations.test.ts b/x-pack/plugins/infra/server/lib/metrics/lib/create_metrics_aggregations.test.ts new file mode 100644 index 0000000000000..a18b8fd533c7f --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/lib/create_metrics_aggregations.test.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { MetricsAPIRequest } from '../../../../common/http_api'; +import moment from 'moment'; +import { createMetricsAggregations } from './create_metrics_aggregations'; + +const options: MetricsAPIRequest = { + timerange: { + field: '@timestamp', + from: moment('2020-01-01T00:00:00Z').valueOf(), + to: moment('2020-01-01T01:00:00Z').valueOf(), + interval: '>=1m', + }, + limit: 20, + indexPattern: 'metrics-*', + metrics: [ + { id: 'metric_0', aggregations: { metric_0: { avg: { field: 'system.cpu.user.pct' } } } }, + { + id: 'metric_1', + aggregations: { + metric_1_max: { max: { field: 'system.network.in.bytes' } }, + metric_1: { derivative: { buckets_path: 'metric_1_max', gap_policy: 'skip', unit: '1s' } }, + }, + }, + ], +}; + +describe('createMetricsAggregations(options)', () => { + it('should just work', () => { + expect(createMetricsAggregations(options)).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/create_metrics_aggregations.ts b/x-pack/plugins/infra/server/lib/metrics/lib/create_metrics_aggregations.ts new file mode 100644 index 0000000000000..c1400ea407829 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/lib/create_metrics_aggregations.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 { MetricsUIAggregation } from '../../../../common/inventory_models/types'; +import { MetricsAPIRequest } from '../../../../common/http_api/metrics_api'; + +export const createMetricsAggregations = (options: MetricsAPIRequest): MetricsUIAggregation => { + const { metrics } = options; + return metrics.reduce((aggs, metric) => { + return { ...aggs, ...metric.aggregations }; + }, {}); +}; diff --git a/x-pack/plugins/infra/server/lib/metrics/types.ts b/x-pack/plugins/infra/server/lib/metrics/types.ts new file mode 100644 index 0000000000000..d1866470e0cf9 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/metrics/types.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 * as rt from 'io-ts'; +import { InfraDatabaseSearchResponse, CallWithRequestParams } from '../adapters/framework'; + +export type ESSearchClient = ( + options: CallWithRequestParams +) => Promise>; + +const NumberOrNullRT = rt.union([rt.number, rt.null]); + +export const BasicMetricValueRT = rt.type({ value: NumberOrNullRT }); + +export const NormalizedMetricValueRT = rt.intersection([ + BasicMetricValueRT, + rt.type({ normalized_value: NumberOrNullRT }), +]); +export const PercentilesTypeRT = rt.type({ values: rt.record(rt.string, NumberOrNullRT) }); + +export const PercentilesKeyedTypeRT = rt.type({ + values: rt.array(rt.type({ key: rt.string, value: NumberOrNullRT })), +}); + +export const MetricValueTypeRT = rt.union([ + BasicMetricValueRT, + NormalizedMetricValueRT, + PercentilesTypeRT, + PercentilesKeyedTypeRT, +]); +export type MetricValueType = rt.TypeOf; + +export const HistogramBucketRT = rt.record( + rt.string, + rt.union([rt.number, rt.string, MetricValueTypeRT]) +); + +export const HistogramResponseRT = rt.type({ + histogram: rt.type({ + buckets: rt.array(HistogramBucketRT), + }), +}); + +const GroupingBucketRT = rt.intersection([ + rt.type({ + key: rt.record(rt.string, rt.string), + doc_count: rt.number, + }), + HistogramResponseRT, +]); + +export const GroupingResponseRT = rt.type({ + groupings: rt.intersection([ + rt.type({ + buckets: rt.array(GroupingBucketRT), + }), + rt.partial({ + after_key: rt.record(rt.string, rt.string), + }), + ]), +}); + +export type HistogramBucket = rt.TypeOf; + +export type HistogramResponse = rt.TypeOf; + +export type GroupingResponse = rt.TypeOf; + +export type MetricsESResponse = HistogramResponse | GroupingResponse; diff --git a/x-pack/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts b/x-pack/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts index d1a4ed431a2be..719ffdb8fa7c4 100644 --- a/x-pack/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts +++ b/x-pack/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts @@ -8,7 +8,7 @@ import { uniq } from 'lodash'; import { InfraSnapshotRequestOptions } from './types'; import { getMetricsAggregations } from './query_helpers'; import { calculateMetricInterval } from '../../utils/calculate_metric_interval'; -import { SnapshotModel, SnapshotModelMetricAggRT } from '../../../common/inventory_models/types'; +import { MetricsUIAggregation, ESBasicMetricAggRT } from '../../../common/inventory_models/types'; import { getDatasetForField } from '../../routes/metrics_explorer/lib/get_dataset_for_field'; import { InfraTimerangeInput } from '../../../common/http_api/snapshot_api'; import { ESSearchClient } from '.'; @@ -59,12 +59,12 @@ export const createTimeRangeWithInterval = async ( const aggregationsToModules = async ( client: ESSearchClient, - aggregations: SnapshotModel, + aggregations: MetricsUIAggregation, options: InfraSnapshotRequestOptions ): Promise => { const uniqueFields = Object.values(aggregations) .reduce>((fields, agg) => { - if (SnapshotModelMetricAggRT.is(agg)) { + if (ESBasicMetricAggRT.is(agg)) { return uniq(fields.concat(Object.values(agg).map((a) => a?.field))); } return fields; 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 732fa10decc98..ca63043ba868e 100644 --- a/x-pack/plugins/infra/server/lib/snapshot/query_helpers.ts +++ b/x-pack/plugins/infra/server/lib/snapshot/query_helpers.ts @@ -9,8 +9,8 @@ import { findInventoryModel, findInventoryFields } from '../../../common/invento import { InfraSnapshotRequestOptions } from './types'; import { getIntervalInSeconds } from '../../utils/get_interval_in_seconds'; import { - SnapshotModelRT, - SnapshotModel, + MetricsUIAggregation, + MetricsUIAggregationRT, InventoryItemType, } from '../../../common/inventory_models/types'; import { @@ -75,11 +75,13 @@ export const metricToAggregation = ( return inventoryModel.metrics.snapshot?.[metric.type]; }; -export const getMetricsAggregations = (options: InfraSnapshotRequestOptions): SnapshotModel => { +export const getMetricsAggregations = ( + options: InfraSnapshotRequestOptions +): MetricsUIAggregation => { const { metrics } = options; return metrics.reduce((aggs, metric, index) => { const aggregation = metricToAggregation(options.nodeType, metric, index); - if (!SnapshotModelRT.is(aggregation)) { + if (!MetricsUIAggregationRT.is(aggregation)) { throw new Error( i18n.translate('xpack.infra.snapshot.missingSnapshotMetricError', { defaultMessage: 'The aggregation for {metric} for {nodeType} is not available.', diff --git a/x-pack/plugins/infra/server/lib/sources/defaults.ts b/x-pack/plugins/infra/server/lib/sources/defaults.ts index b096bed84fa9a..82b2852099bae 100644 --- a/x-pack/plugins/infra/server/lib/sources/defaults.ts +++ b/x-pack/plugins/infra/server/lib/sources/defaults.ts @@ -4,20 +4,25 @@ * you may not use this file except in compliance with the Elastic License. */ +import { + METRICS_INDEX_PATTERN, + LOGS_INDEX_PATTERN, + TIMESTAMP_FIELD, +} from '../../../common/constants'; import { InfraSourceConfiguration } from '../../../common/http_api/source_api'; export const defaultSourceConfiguration: InfraSourceConfiguration = { name: 'Default', description: '', - metricAlias: 'metrics-*,metricbeat-*', - logAlias: 'logs-*,filebeat-*,kibana_sample_data_logs*', + metricAlias: METRICS_INDEX_PATTERN, + logAlias: LOGS_INDEX_PATTERN, fields: { container: 'container.id', host: 'host.name', message: ['message', '@message'], pod: 'kubernetes.pod.uid', tiebreaker: '_doc', - timestamp: '@timestamp', + timestamp: TIMESTAMP_FIELD, }, inventoryDefaultView: '0', metricsExplorerDefaultView: '0', diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer/index.ts b/x-pack/plugins/infra/server/routes/metrics_explorer/index.ts index c22095a31195a..4b90b52cb51f6 100644 --- a/x-pack/plugins/infra/server/routes/metrics_explorer/index.ts +++ b/x-pack/plugins/infra/server/routes/metrics_explorer/index.ts @@ -10,17 +10,23 @@ import { fold } from 'fp-ts/lib/Either'; import { identity } from 'fp-ts/lib/function'; import { schema } from '@kbn/config-schema'; import { InfraBackendLibs } from '../../lib/infra_types'; -import { getGroupings } from './lib/get_groupings'; -import { populateSeriesWithTSVBData } from './lib/populate_series_with_tsvb_data'; -import { metricsExplorerRequestBodyRT, metricsExplorerResponseRT } from '../../../common/http_api'; +import { + metricsExplorerRequestBodyRT, + metricsExplorerResponseRT, + MetricsExplorerPageInfo, +} from '../../../common/http_api'; import { throwErrors } from '../../../common/runtime_types'; +import { convertRequestToMetricsAPIOptions } from './lib/convert_request_to_metrics_api_options'; +import { createSearchClient } from '../../lib/create_search_client'; +import { findIntervalForMetrics } from './lib/find_interval_for_metrics'; +import { query } from '../../lib/metrics'; +import { queryTotalGroupings } from './lib/query_total_groupings'; +import { transformSeries } from './lib/transform_series'; const escapeHatch = schema.object({}, { unknowns: 'allow' }); export const initMetricExplorerRoute = (libs: InfraBackendLibs) => { const { framework } = libs; - const { callWithRequest } = framework; - framework.registerRoute( { method: 'post', @@ -31,26 +37,48 @@ export const initMetricExplorerRoute = (libs: InfraBackendLibs) => { }, async (requestContext, request, response) => { try { - const payload = pipe( + const options = pipe( metricsExplorerRequestBodyRT.decode(request.body), fold(throwErrors(Boom.badRequest), identity) ); - const search = (searchOptions: object) => - callWithRequest<{}, Aggregation>(requestContext, 'search', searchOptions); + const client = createSearchClient(requestContext, framework); + const interval = await findIntervalForMetrics(client, options); - // First we get the groupings from a composite aggregation - const groupings = await getGroupings(search, payload); + const optionsWithInterval = options.forceInterval + ? options + : { + ...options, + timerange: { + ...options.timerange, + interval: interval ? `>=${interval}s` : options.timerange.interval, + }, + }; + + const metricsApiOptions = convertRequestToMetricsAPIOptions(optionsWithInterval); + const metricsApiResponse = await query(client, metricsApiOptions); + const totalGroupings = await queryTotalGroupings(client, metricsApiOptions); + const hasGroupBy = + Array.isArray(metricsApiOptions.groupBy) && metricsApiOptions.groupBy.length > 0; + + const pageInfo: MetricsExplorerPageInfo = { + total: totalGroupings, + afterKey: null, + }; + + if (metricsApiResponse.info.afterKey) { + pageInfo.afterKey = metricsApiResponse.info.afterKey; + } + + // If we have a groupBy but there are ZERO groupings returned then we need to + // return an empty array. Otherwise we transform the series to match the current schema. + const series = + hasGroupBy && totalGroupings === 0 + ? [] + : metricsApiResponse.series.map(transformSeries(hasGroupBy)); - // Then we take the results and fill in the data from TSVB with the - // user's custom metrics - const seriesWithMetrics = await Promise.all( - groupings.series.map( - populateSeriesWithTSVBData(request, payload, framework, requestContext) - ) - ); return response.ok({ - body: metricsExplorerResponseRT.encode({ ...groupings, series: seriesWithMetrics }), + body: metricsExplorerResponseRT.encode({ series, pageInfo }), }); } catch (error) { return response.internalError({ diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/convert_metric_to_metrics_api_metric.test.ts b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/convert_metric_to_metrics_api_metric.test.ts new file mode 100644 index 0000000000000..67dbaf8e1e877 --- /dev/null +++ b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/convert_metric_to_metrics_api_metric.test.ts @@ -0,0 +1,87 @@ +/* + * 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 { convertMetricToMetricsAPIMetric } from './convert_metric_to_metrics_api_metric'; +import { + MetricsExplorerMetric, + MetricsAPIMetric, + MetricsExplorerAggregation, +} from '../../../../common/http_api'; + +describe('convertMetricToMetricsAPIMetric(metric, index)', () => { + const runTest = (metric: MetricsExplorerMetric, aggregation: MetricsAPIMetric) => + it(`should convert ${metric.aggregation}`, () => { + expect(convertMetricToMetricsAPIMetric(metric, 1)).toEqual(aggregation); + }); + + const runTestForBasic = (aggregation: MetricsExplorerAggregation) => + runTest( + { aggregation, field: 'system.cpu.user.pct' }, + { + id: 'metric_1', + aggregations: { metric_1: { [aggregation]: { field: 'system.cpu.user.pct' } } }, + } + ); + + runTestForBasic('avg'); + runTestForBasic('sum'); + runTestForBasic('max'); + runTestForBasic('min'); + runTestForBasic('cardinality'); + + runTest( + { aggregation: 'rate', field: 'system.network.in.bytes' }, + { + id: 'metric_1', + aggregations: { + metric_1_max: { + max: { + field: 'system.network.in.bytes', + }, + }, + metric_1_deriv: { + derivative: { + buckets_path: 'metric_1_max', + gap_policy: 'skip', + unit: '1s', + }, + }, + metric_1: { + bucket_script: { + buckets_path: { + value: 'metric_1_deriv[normalized_value]', + }, + gap_policy: 'skip', + script: { + lang: 'painless', + source: 'params.value > 0.0 ? params.value : 0.0', + }, + }, + }, + }, + } + ); + + runTest( + { aggregation: 'count' }, + { + id: 'metric_1', + aggregations: { + metric_1: { + bucket_script: { + buckets_path: { + count: '_count', + }, + gap_policy: 'skip', + script: { + lang: 'expression', + source: 'count * 1', + }, + }, + }, + }, + } + ); +}); diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/convert_metric_to_metrics_api_metric.ts b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/convert_metric_to_metrics_api_metric.ts new file mode 100644 index 0000000000000..93948a8b8797e --- /dev/null +++ b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/convert_metric_to_metrics_api_metric.ts @@ -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 { networkTraffic } from '../../../../common/inventory_models/shared/metrics/snapshot/network_traffic'; +import { MetricsAPIMetric, MetricsExplorerMetric } from '../../../../common/http_api'; + +export const convertMetricToMetricsAPIMetric = ( + metric: MetricsExplorerMetric, + index: number +): MetricsAPIMetric => { + const id = `metric_${index}`; + if (metric.aggregation === 'rate' && metric.field) { + return { + id, + aggregations: networkTraffic(id, metric.field), + }; + } + + if (['p95', 'p99'].includes(metric.aggregation) && metric.field) { + const percent = metric.aggregation === 'p95' ? 95 : 99; + return { + id, + aggregations: { + [id]: { + percentiles: { + field: metric.field, + percents: [percent], + }, + }, + }, + }; + } + + if (['max', 'min', 'avg', 'cardinality', 'sum'].includes(metric.aggregation) && metric.field) { + return { + id, + aggregations: { + [id]: { + [metric.aggregation]: { field: metric.field }, + }, + }, + }; + } + + return { + id, + aggregations: { + [id]: { + bucket_script: { + buckets_path: { count: '_count' }, + script: { + source: 'count * 1', + lang: 'expression', + }, + gap_policy: 'skip', + }, + }, + }, + }; +}; diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/convert_request_to_metrics_api_options.test.ts b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/convert_request_to_metrics_api_options.test.ts new file mode 100644 index 0000000000000..4c423aee347e9 --- /dev/null +++ b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/convert_request_to_metrics_api_options.test.ts @@ -0,0 +1,123 @@ +/* + * 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 { MetricsExplorerRequestBody, MetricsAPIRequest } from '../../../../common/http_api'; +import { convertRequestToMetricsAPIOptions } from './convert_request_to_metrics_api_options'; + +const BASE_REQUEST: MetricsExplorerRequestBody = { + timerange: { + field: '@timestamp', + from: new Date('2020-01-01T00:00:00Z').getTime(), + to: new Date('2020-01-01T01:00:00Z').getTime(), + interval: '1m', + }, + limit: 9, + indexPattern: 'metrics-*', + metrics: [{ aggregation: 'avg', field: 'system.cpu.user.pct' }], +}; + +const BASE_METRICS_UI_OPTIONS: MetricsAPIRequest = { + timerange: { + field: '@timestamp', + from: new Date('2020-01-01T00:00:00Z').getTime(), + to: new Date('2020-01-01T01:00:00Z').getTime(), + interval: '1m', + }, + limit: 9, + dropLastBucket: true, + indexPattern: 'metrics-*', + metrics: [ + { id: 'metric_0', aggregations: { metric_0: { avg: { field: 'system.cpu.user.pct' } } } }, + ], +}; + +describe('convertRequestToMetricsAPIOptions', () => { + it('should just work', () => { + expect(convertRequestToMetricsAPIOptions(BASE_REQUEST)).toEqual(BASE_METRICS_UI_OPTIONS); + }); + + it('should work with string afterKeys', () => { + expect(convertRequestToMetricsAPIOptions({ ...BASE_REQUEST, afterKey: 'host.name' })).toEqual({ + ...BASE_METRICS_UI_OPTIONS, + afterKey: { groupBy0: 'host.name' }, + }); + }); + + it('should work with afterKey objects', () => { + const afterKey = { groupBy0: 'host.name', groupBy1: 'cloud.availability_zone' }; + expect( + convertRequestToMetricsAPIOptions({ + ...BASE_REQUEST, + afterKey, + }) + ).toEqual({ + ...BASE_METRICS_UI_OPTIONS, + afterKey, + }); + }); + + it('should work with string group bys', () => { + expect( + convertRequestToMetricsAPIOptions({ + ...BASE_REQUEST, + groupBy: 'host.name', + }) + ).toEqual({ + ...BASE_METRICS_UI_OPTIONS, + groupBy: ['host.name'], + }); + }); + + it('should work with group by arrays', () => { + expect( + convertRequestToMetricsAPIOptions({ + ...BASE_REQUEST, + groupBy: ['host.name', 'cloud.availability_zone'], + }) + ).toEqual({ + ...BASE_METRICS_UI_OPTIONS, + groupBy: ['host.name', 'cloud.availability_zone'], + }); + }); + + it('should work with filterQuery json string', () => { + const filter = { bool: { filter: [{ match: { 'host.name': 'example-01' } }] } }; + expect( + convertRequestToMetricsAPIOptions({ + ...BASE_REQUEST, + filterQuery: JSON.stringify(filter), + }) + ).toEqual({ + ...BASE_METRICS_UI_OPTIONS, + filters: [filter], + }); + }); + + it('should work with filterQuery as Lucene expressions', () => { + const filter = `host.name: 'example-01'`; + expect( + convertRequestToMetricsAPIOptions({ + ...BASE_REQUEST, + filterQuery: filter, + }) + ).toEqual({ + ...BASE_METRICS_UI_OPTIONS, + filters: [{ query_string: { query: filter, analyze_wildcard: true } }], + }); + }); + + it('should work with empty metrics', () => { + expect( + convertRequestToMetricsAPIOptions({ + ...BASE_REQUEST, + metrics: [], + }) + ).toEqual({ + ...BASE_METRICS_UI_OPTIONS, + metrics: [], + }); + }); +}); diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/convert_request_to_metrics_api_options.ts b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/convert_request_to_metrics_api_options.ts new file mode 100644 index 0000000000000..2dd00c4aed59c --- /dev/null +++ b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/convert_request_to_metrics_api_options.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 { isObject, isArray } from 'lodash'; +import { + MetricsAPIRequest, + MetricsExplorerRequestBody, + afterKeyObjectRT, +} from '../../../../common/http_api'; +import { convertMetricToMetricsAPIMetric } from './convert_metric_to_metrics_api_metric'; + +export const convertRequestToMetricsAPIOptions = ( + options: MetricsExplorerRequestBody +): MetricsAPIRequest => { + const metrics = options.metrics.map(convertMetricToMetricsAPIMetric); + const { limit, timerange, indexPattern } = options; + + const metricsApiOptions: MetricsAPIRequest = { + timerange, + indexPattern, + limit, + metrics, + dropLastBucket: true, + }; + + if (options.afterKey) { + metricsApiOptions.afterKey = afterKeyObjectRT.is(options.afterKey) + ? options.afterKey + : { groupBy0: options.afterKey }; + } + + if (options.groupBy) { + metricsApiOptions.groupBy = isArray(options.groupBy) ? options.groupBy : [options.groupBy]; + } + + if (options.filterQuery) { + try { + const filterObject = JSON.parse(options.filterQuery); + if (isObject(filterObject)) { + metricsApiOptions.filters = [filterObject]; + } + } catch (err) { + metricsApiOptions.filters = [ + { + query_string: { + query: options.filterQuery, + analyze_wildcard: true, + }, + }, + ]; + } + } + + return metricsApiOptions; +}; diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/create_metrics_model.ts b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/create_metrics_model.ts deleted file mode 100644 index 3a9abf525a9f0..0000000000000 --- a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/create_metrics_model.ts +++ /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 { MetricsExplorerRequestBody } from '../../../../common/http_api/metrics_explorer'; -import { TSVBMetricModel } from '../../../../common/inventory_models/types'; - -const percentileToVaue = (agg: 'p95' | 'p99') => { - if (agg === 'p95') { - return 95; - } - return 99; -}; - -export const createMetricModel = (options: MetricsExplorerRequestBody): TSVBMetricModel => { - // if dropLastBucket is set use the value otherwise default to true. - const dropLastBucket: boolean = options.dropLastBucket != null ? options.dropLastBucket : true; - return { - id: 'custom', - requires: [], - index_pattern: options.indexPattern, - interval: options.timerange.interval, - time_field: options.timerange.field, - drop_last_bucket: dropLastBucket, - type: 'timeseries', - // Create one series per metric requested. The series.id will be used to identify the metric - // when the responses are processed and combined with the grouping request. - series: options.metrics.map((metric, index) => { - // If the metric is a rate then we need to add TSVB metrics for calculating the derivative - if (metric.aggregation === 'rate') { - const aggType = 'max'; - return { - id: `metric_${index}`, - split_mode: 'everything', - metrics: [ - { - id: `metric_${aggType}_${index}`, - field: metric.field, - type: aggType, - }, - { - id: `metric_deriv_${aggType}_${index}`, - field: `metric_${aggType}_${index}`, - type: 'derivative', - unit: '1s', - }, - { - id: `metric_posonly_deriv_${aggType}_${index}`, - type: 'calculation', - variables: [ - { id: 'var-rate', name: 'rate', field: `metric_deriv_${aggType}_${index}` }, - ], - script: 'params.rate > 0.0 ? params.rate : 0.0', - }, - ], - }; - } - - if (metric.aggregation === 'p95' || metric.aggregation === 'p99') { - return { - id: `metric_${index}`, - split_mode: 'everything', - metrics: [ - { - field: metric.field, - id: `metric_${metric.aggregation}_${index}`, - type: 'percentile', - percentiles: [ - { - id: 'percentile_0', - value: percentileToVaue(metric.aggregation), - }, - ], - }, - ], - }; - } - - // Create a basic TSVB series with a single metric - const aggregation = metric.aggregation || 'avg'; - - return { - id: `metric_${index}`, - split_mode: 'everything', - metrics: [ - { - field: metric.field, - id: `metric_${aggregation}_${index}`, - type: aggregation, - }, - ], - }; - }), - }; -}; diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/find_interval_for_metrics.ts b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/find_interval_for_metrics.ts new file mode 100644 index 0000000000000..876bbb4199441 --- /dev/null +++ b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/find_interval_for_metrics.ts @@ -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 { uniq } from 'lodash'; +import LRU from 'lru-cache'; +import { MetricsExplorerRequestBody } from '../../../../common/http_api'; +import { ESSearchClient } from '../../../lib/snapshot'; +import { getDatasetForField } from './get_dataset_for_field'; +import { calculateMetricInterval } from '../../../utils/calculate_metric_interval'; + +const cache = new LRU({ + max: 100, + maxAge: 15 * 60 * 1000, +}); + +export const findIntervalForMetrics = async ( + client: ESSearchClient, + options: MetricsExplorerRequestBody +) => { + const fields = uniq( + options.metrics.map((metric) => (metric.field ? metric.field : null)).filter((f) => f) + ) as string[]; + + const cacheKey = fields.sort().join(':'); + + if (cache.has(cacheKey)) return cache.get(cacheKey); + + if (fields.length === 0) { + return 60; + } + + const modules = await Promise.all( + fields.map( + async (field) => await getDatasetForField(client, field as string, options.indexPattern) + ) + ); + + const interval = calculateMetricInterval( + client, + { + indexPattern: options.indexPattern, + timestampField: options.timerange.field, + timerange: options.timerange, + }, + modules.filter(Boolean) as string[] + ); + cache.set(cacheKey, interval); + return interval; +}; diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/get_groupings.ts b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/get_groupings.ts deleted file mode 100644 index fdecb5f3d9315..0000000000000 --- a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/get_groupings.ts +++ /dev/null @@ -1,150 +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 { set } from '@elastic/safer-lodash-set'; -import { isObject } from 'lodash'; -import { i18n } from '@kbn/i18n'; -import { InfraDatabaseSearchResponse } from '../../../lib/adapters/framework'; -import { - MetricsExplorerRequestBody, - MetricsExplorerResponse, - afterKeyObjectRT, -} from '../../../../common/http_api/metrics_explorer'; - -interface GroupingAggregation { - groupingsCount: { - value: number; - }; - groupings: { - after_key?: { - [name: string]: string; - }; - buckets: Array<{ key: { [id: string]: string }; doc_count: number }>; - }; -} - -const EMPTY_RESPONSE = { - series: [ - { - id: i18n.translate('xpack.infra.metricsExploer.everything', { defaultMessage: 'Everything' }), - columns: [], - rows: [], - }, - ], - pageInfo: { total: 0, afterKey: null }, -}; - -export const getGroupings = async ( - search: (options: object) => Promise>, - options: MetricsExplorerRequestBody -): Promise => { - if (!options.groupBy) { - return EMPTY_RESPONSE; - } - - if (Array.isArray(options.groupBy) && options.groupBy.length === 0) { - return EMPTY_RESPONSE; - } - - const limit = options.limit || 9; - const groupBy = Array.isArray(options.groupBy) ? options.groupBy : [options.groupBy]; - const filter: Array> = [ - { - range: { - [options.timerange.field]: { - gte: options.timerange.from, - lte: options.timerange.to, - format: 'epoch_millis', - }, - }, - }, - ...groupBy.map((field) => ({ exists: { field } })), - ]; - const params = { - allowNoIndices: true, - ignoreUnavailable: true, - index: options.indexPattern, - body: { - size: 0, - query: { - bool: { - should: [ - ...options.metrics - .filter((m) => m.field) - .map((m) => ({ - exists: { field: m.field }, - })), - ], - filter, - }, - }, - aggs: { - groupingsCount: { - cardinality: { - script: { source: groupBy.map((field) => `doc['${field}'].value`).join('+') }, - }, - }, - groupings: { - composite: { - size: limit, - sources: groupBy.map((field, index) => ({ - [`groupBy${index}`]: { terms: { field, order: 'asc' } }, - })), - }, - }, - }, - }, - }; - - if (params.body.query.bool.should.length !== 0) { - set(params, 'body.query.bool.minimum_should_match', 1); - } - - if (options.afterKey) { - if (afterKeyObjectRT.is(options.afterKey)) { - set(params, 'body.aggs.groupings.composite.after', options.afterKey); - } else { - set(params, 'body.aggs.groupings.composite.after', { groupBy0: options.afterKey }); - } - } - - if (options.filterQuery) { - try { - const filterObject = JSON.parse(options.filterQuery); - if (isObject(filterObject)) { - params.body.query.bool.filter.push(filterObject); - } - } catch (err) { - params.body.query.bool.filter.push({ - query_string: { - query: options.filterQuery, - analyze_wildcard: true, - }, - }); - } - } - - const response = await search(params); - if (response.hits.total.value === 0) { - return { ...EMPTY_RESPONSE, series: [] }; - } - if (!response.aggregations) { - throw new Error('Aggregations should be present.'); - } - const { groupings, groupingsCount } = response.aggregations; - const { after_key: afterKey } = groupings; - return { - series: groupings.buckets.map((bucket) => { - const keys = Object.values(bucket.key); - const id = keys.join(' / '); - return { id, keys, rows: [], columns: [] }; - }), - pageInfo: { - total: groupingsCount.value, - afterKey: afterKey && groupings.buckets.length === limit ? afterKey : null, - }, - }; -}; diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts deleted file mode 100644 index ce4a9c71b74e6..0000000000000 --- a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts +++ /dev/null @@ -1,162 +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 { union, uniq, isArray, isString } from 'lodash'; -import { KibanaRequest, RequestHandlerContext } from 'src/core/server'; -import { KibanaFramework } from '../../../lib/adapters/framework/kibana_framework_adapter'; -import { - MetricsExplorerRow, - MetricsExplorerSeries, - MetricsExplorerRequestBody, - MetricsExplorerColumn, -} from '../../../../common/http_api/metrics_explorer'; -import { createMetricModel } from './create_metrics_model'; -import { JsonObject } from '../../../../common/typed_json'; -import { calculateMetricInterval } from '../../../utils/calculate_metric_interval'; -import { getDatasetForField } from './get_dataset_for_field'; -import { - CallWithRequestParams, - InfraDatabaseSearchResponse, -} from '../../../lib/adapters/framework'; - -export const populateSeriesWithTSVBData = ( - request: KibanaRequest, - options: MetricsExplorerRequestBody, - framework: KibanaFramework, - requestContext: RequestHandlerContext -) => async (series: MetricsExplorerSeries) => { - // IF there are no metrics selected then we should return an empty result. - if (options.metrics.length === 0) { - return { - ...series, - columns: [], - rows: [], - }; - } - - // Set the filter for the group by or match everything - const isGroupBySet = - Array.isArray(options.groupBy) && options.groupBy.length - ? true - : isString(options.groupBy) - ? true - : false; - - const filters: JsonObject[] = isGroupBySet - ? isArray(options.groupBy) - ? options.groupBy - .filter((f) => f) - .map((field, index) => ({ match: { [field as string]: series.keys?.[index] || '' } })) - : [{ match: { [options.groupBy as string]: series.id } }] - : []; - - if (options.filterQuery) { - try { - const filterQuery = JSON.parse(options.filterQuery); - filters.push(filterQuery); - } catch (error) { - filters.push({ - query_string: { - query: options.filterQuery, - analyze_wildcard: true, - }, - }); - } - } - const timerange = { min: options.timerange.from, max: options.timerange.to }; - - const client = ( - opts: CallWithRequestParams - ): Promise> => - framework.callWithRequest(requestContext, 'search', opts); - - // Create the TSVB model based on the request options - const model = createMetricModel(options); - const modules = await Promise.all( - uniq(options.metrics.filter((m) => m.field)).map( - async (m) => await getDatasetForField(client, m.field as string, options.indexPattern) - ) - ); - - const calculatedInterval = await calculateMetricInterval( - client, - { - indexPattern: options.indexPattern, - timestampField: options.timerange.field, - timerange: options.timerange, - }, - modules.filter((m) => m) as string[] - ); - - if (calculatedInterval) { - model.interval = options.forceInterval - ? options.timerange.interval - : `>=${calculatedInterval}s`; - } - - // Get TSVB results using the model, timerange and filters - const tsvbResults = await framework.makeTSVBRequest( - requestContext, - request, - model, - timerange, - filters - ); - - // If there is no data `custom` will not exist. - if (!tsvbResults.custom) { - return { - ...series, - columns: [], - rows: [], - }; - } - - // Setup the dynamic columns and row attributes depending on if the user is doing a group by - // and multiple metrics - const attributeColumns: MetricsExplorerColumn[] = - options.groupBy != null ? [{ name: 'groupBy', type: 'string' }] : []; - const metricColumns: MetricsExplorerColumn[] = options.metrics.map((m, i) => ({ - name: `metric_${i}`, - type: 'number', - })); - const rowAttributes = options.groupBy != null ? { groupBy: series.id } : {}; - - // To support multiple metrics, there are multiple TSVB series which need to be combined - // into one MetricExplorerRow (Canvas row). This is done by collecting all the timestamps - // across each TSVB series. Then for each timestamp we find the values and create a - // MetricsExplorerRow. - const timestamps = tsvbResults.custom.series.reduce( - (currentTimestamps, tsvbSeries) => - union( - currentTimestamps, - tsvbSeries.data.map((row) => row[0]) - ).sort(), - [] as number[] - ); - // Combine the TSVB series for multiple metrics. - const rows = timestamps.map((timestamp) => { - return tsvbResults.custom.series.reduce( - (currentRow, tsvbSeries) => { - const matches = tsvbSeries.data.find((d) => d[0] === timestamp); - if (matches) { - return { ...currentRow, [tsvbSeries.id]: matches[1] }; - } - return currentRow; - }, - { timestamp, ...rowAttributes } as MetricsExplorerRow - ); - }); - return { - ...series, - rows, - columns: [ - { name: 'timestamp', type: 'date' } as MetricsExplorerColumn, - ...metricColumns, - ...attributeColumns, - ], - }; -}; diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/query_total_groupings.ts b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/query_total_groupings.ts new file mode 100644 index 0000000000000..25b956e093d0f --- /dev/null +++ b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/query_total_groupings.ts @@ -0,0 +1,59 @@ +/* + * 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 { isArray } from 'lodash'; +import { MetricsAPIRequest } from '../../../../common/http_api'; +import { ESSearchClient } from '../../../lib/metrics/types'; + +interface GroupingResponse { + count: { + value: number; + }; +} + +export const queryTotalGroupings = async ( + client: ESSearchClient, + options: MetricsAPIRequest +): Promise => { + if (!options.groupBy || (isArray(options.groupBy) && options.groupBy.length === 0)) { + return Promise.resolve(0); + } + + const params = { + allowNoIndices: true, + ignoreUnavailable: true, + index: options.indexPattern, + body: { + size: 0, + query: { + bool: { + filter: [ + { + range: { + [options.timerange.field]: { + gte: options.timerange.from, + lte: options.timerange.to, + format: 'epoch_millis', + }, + }, + }, + ...options.groupBy.map((field) => ({ exists: { field } })), + ], + }, + }, + aggs: { + count: { + cardinality: { + script: options.groupBy.map((field) => `doc['${field}'].value`).join('+'), + }, + }, + }, + }, + }; + + const response = await client<{}, GroupingResponse>(params); + return response.aggregations?.count.value ?? 0; +}; diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/transform_series.ts b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/transform_series.ts new file mode 100644 index 0000000000000..227ce5c36c2dc --- /dev/null +++ b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/transform_series.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { MetricsAPISeries, MetricsExplorerSeries } from '../../../../common/http_api'; + +export const transformSeries = (hasGroupBy: boolean) => ( + series: MetricsAPISeries +): MetricsExplorerSeries => { + const id = series.keys?.join(' / ') ?? series.id; + return { + ...series, + id, + rows: series.rows.map((row) => { + if (hasGroupBy) { + return { ...row, groupBy: id }; + } + return row; + }), + columns: hasGroupBy ? [...series.columns, { name: 'groupBy', type: 'string' }] : series.columns, + }; +}; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 526f2d88574d3..5f52bfe981440 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -8891,7 +8891,7 @@ "xpack.infra.metrics.missingTSVBModelError": "{nodeType}では{metricId}のTSVBモデルが存在しません", "xpack.infra.metrics.pluginTitle": "メトリック", "xpack.infra.metrics.refetchButtonLabel": "新規データを確認", - "xpack.infra.metricsExploer.everything": "すべて", + "xpack.infra.metricsExplorer.everything": "すべて", "xpack.infra.metricsExplorer.actionsLabel.aria": "{grouping} のアクション", "xpack.infra.metricsExplorer.actionsLabel.button": "アクション", "xpack.infra.metricsExplorer.aggregationLabel": "/", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index af5e68b7e44d7..a97de80243ded 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -8894,7 +8894,7 @@ "xpack.infra.metrics.missingTSVBModelError": "{nodeType} 的 {metricId} TSVB 模型不存在", "xpack.infra.metrics.pluginTitle": "指标", "xpack.infra.metrics.refetchButtonLabel": "检查新数据", - "xpack.infra.metricsExploer.everything": "所有内容", + "xpack.infra.metricsExplorer.everything": "所有内容", "xpack.infra.metricsExplorer.actionsLabel.aria": "适用于 {grouping} 的操作", "xpack.infra.metricsExplorer.actionsLabel.button": "操作", "xpack.infra.metricsExplorer.aggregationLabel": "的", diff --git a/x-pack/test/api_integration/apis/metrics_ui/metrics_explorer.ts b/x-pack/test/api_integration/apis/metrics_ui/metrics_explorer.ts index d372496d2d1d9..16809fba8c8df 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/metrics_explorer.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/metrics_explorer.ts @@ -50,7 +50,7 @@ export default function ({ getService }: FtrProviderContext) { const body = decodeOrThrow(metricsExplorerResponseRT)(response.body); expect(body.series).length(1); const firstSeries = first(body.series) as any; - expect(firstSeries).to.have.property('id', 'Everything'); + expect(firstSeries).to.have.property('id', '*'); expect(firstSeries.columns).to.eql([ { name: 'timestamp', type: 'date' }, { name: 'metric_0', type: 'number' }, @@ -90,7 +90,7 @@ export default function ({ getService }: FtrProviderContext) { const body = decodeOrThrow(metricsExplorerResponseRT)(response.body); expect(body.series).length(1); const firstSeries = first(body.series) as any; - expect(firstSeries).to.have.property('id', 'Everything'); + expect(firstSeries).to.have.property('id', '*'); expect(firstSeries.columns).to.eql([ { name: 'timestamp', type: 'date' }, { name: 'metric_0', type: 'number' }, @@ -121,7 +121,7 @@ export default function ({ getService }: FtrProviderContext) { const body = decodeOrThrow(metricsExplorerResponseRT)(response.body); expect(body.series).length(1); const firstSeries = first(body.series) as any; - expect(firstSeries).to.have.property('id', 'Everything'); + expect(firstSeries).to.have.property('id', '*'); expect(firstSeries.columns).to.eql([]); expect(firstSeries.rows).to.have.length(0); }); From 4d6592edc8ad2b82f1a0eec98aeae810b63b1d73 Mon Sep 17 00:00:00 2001 From: Tim Roes Date: Fri, 14 Aug 2020 09:17:43 +0200 Subject: [PATCH 35/53] Revert "attempt excluding a codeowners directory" (#75023) This reverts commit 250a0b17b03f8924462d484c2254a5af7d64f1ff. --- .github/CODEOWNERS | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5a8271302a72b..1f076e3c84001 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -118,7 +118,6 @@ # Operations /src/dev/ @elastic/kibana-operations -!/src/dev/i18n/ @elastic/kibana-operations /src/setup_node_env/ @elastic/kibana-operations /src/optimize/ @elastic/kibana-operations /packages/*eslint*/ @elastic/kibana-operations From 7cf0e49c897512a827de870c3504888b29824499 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Fri, 14 Aug 2020 09:45:02 +0200 Subject: [PATCH 36/53] [Uptime] Singular alert (#74659) Co-authored-by: Elastic Machine --- .../translations/translations/ja-JP.json | 10 - .../translations/translations/zh-CN.json | 10 - .../uptime/common/runtime_types/ping/ping.ts | 6 + x-pack/plugins/uptime/common/translations.ts | 17 + .../__snapshots__/monitor_list.test.tsx.snap | 20 + .../monitor_list_drawer.test.tsx.snap | 5 + .../__tests__/monitor_status.test.ts | 4 +- .../public/lib/alert_types/monitor_status.tsx | 2 +- .../public/lib/alert_types/translations.ts | 13 - .../lib/alerts/__tests__/status_check.test.ts | 819 ++++++++++-------- .../server/lib/alerts/duration_anomaly.ts | 2 +- .../uptime/server/lib/alerts/status_check.ts | 609 +++++-------- .../uptime/server/lib/alerts/translations.ts | 77 ++ .../plugins/uptime/server/lib/alerts/types.ts | 2 +- .../server/lib/alerts/uptime_alert_wrapper.ts | 34 + .../uptime/server/lib/compose/kibana.ts | 14 +- .../get_monitor_availability.test.ts | 192 ++-- .../__tests__/get_monitor_status.test.ts | 148 ++-- .../lib/requests/get_monitor_availability.ts | 15 +- .../server/lib/requests/get_monitor_status.ts | 46 +- .../uptime/server/lib/requests/index.ts | 49 +- .../server/lib/requests/uptime_requests.ts | 57 -- 22 files changed, 1128 insertions(+), 1023 deletions(-) create mode 100644 x-pack/plugins/uptime/server/lib/alerts/uptime_alert_wrapper.ts delete mode 100644 x-pack/plugins/uptime/server/lib/requests/uptime_requests.ts diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 5f52bfe981440..8c92e7359b2f7 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -18868,10 +18868,6 @@ "xpack.uptime.alerts.anomaly.criteriaExpression.description": "監視するとき", "xpack.uptime.alerts.anomaly.scoreExpression.ariaLabel": "異常アラートしきい値の条件を表示する式。", "xpack.uptime.alerts.anomaly.scoreExpression.description": "異常と重要度があります", - "xpack.uptime.alerts.availability.emptyMessage": "可用性しきい値({threshold} %)未満のモニターはありません", - "xpack.uptime.alerts.availability.monitorSummary": "{nameOrId}({url}): {availabilityRatio}%", - "xpack.uptime.alerts.availability.multiItemTitle": "可用性しきい値({threshold} %)未満の上位{monitorCount}個のモニター:\n", - "xpack.uptime.alerts.availability.singleItemTitle": "可用性しきい値({threshold} %)未満のモニター:\n", "xpack.uptime.alerts.durationAnomaly": "アップタイム期間異常", "xpack.uptime.alerts.durationAnomaly.actionVariables.state.anomalyStartTimestamp": "異常の開始のISO8601タイムスタンプ", "xpack.uptime.alerts.durationAnomaly.actionVariables.state.expectedResponseTime": "想定応答時間", @@ -18884,11 +18880,6 @@ "xpack.uptime.alerts.durationAnomaly.actionVariables.state.slowestAnomalyResponse": "単位(ミリ秒、秒)が関連付けられた異常バケット中の最も遅い応答時間。", "xpack.uptime.alerts.durationAnomaly.clientName": "アップタイム期間異常", "xpack.uptime.alerts.durationAnomaly.defaultActionMessage": "{anomalyStartTimestamp}に、{monitor}、url {monitorUrl}で異常({severity}レベル)応答時間が検出されました。異常重要度スコアは{severityScore}です。\n位置情報{observerLocation}から高い応答時間{slowestAnomalyResponse}が検出されました。想定された応答時間は{expectedResponseTime}です。", - "xpack.uptime.alerts.message.emptyTitle": "停止状況監視 ID を受信していません。", - "xpack.uptime.alerts.message.fullListOverflow": "... とその他 {overflowCount} {pluralizedMonitor}", - "xpack.uptime.alerts.message.multipleTitle": "停止状況監視: ", - "xpack.uptime.alerts.message.overflowBody": "... とその他 {overflowCount} 監視", - "xpack.uptime.alerts.message.singularTitle": "停止状況監視: ", "xpack.uptime.alerts.monitorStatus": "稼働状況の監視ステータス", "xpack.uptime.alerts.monitorStatus.actionVariables.context.downMonitorsWithGeo.description": "アラートによって「ダウン」と検知された一部またはすべてのモニターを示す、生成された概要。", "xpack.uptime.alerts.monitorStatus.actionVariables.context.message.description": "現在ダウンしているモニターを要約する生成されたメッセージ。", @@ -18915,7 +18906,6 @@ "xpack.uptime.alerts.monitorStatus.availability.unit.headline": "時間範囲単位を選択します", "xpack.uptime.alerts.monitorStatus.availability.unit.selectable": "この選択を使用して、このアラートの可用性範囲単位を設定", "xpack.uptime.alerts.monitorStatus.clientName": "稼働状況の監視ステータス", - "xpack.uptime.alerts.monitorStatus.defaultActionMessage": "{contextMessage}\n前回トリガー日時:{lastTriggered}\n", "xpack.uptime.alerts.monitorStatus.filterBar.ariaLabel": "監視状態アラートのフィルター基準を許可するインプット", "xpack.uptime.alerts.monitorStatus.filters.anyLocation": "任意の場所", "xpack.uptime.alerts.monitorStatus.filters.anyPort": "任意のポート", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index a97de80243ded..5ab70ff7a9d04 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -18876,10 +18876,6 @@ "xpack.uptime.alerts.anomaly.criteriaExpression.description": "当监测", "xpack.uptime.alerts.anomaly.scoreExpression.ariaLabel": "显示异常告警阈值的条件的表达式。", "xpack.uptime.alerts.anomaly.scoreExpression.description": "具有异常,严重性为", - "xpack.uptime.alerts.availability.emptyMessage": "没有监测低于可用性阈值 ({threshold} %)", - "xpack.uptime.alerts.availability.monitorSummary": "{nameOrId}({url}):{availabilityRatio}%", - "xpack.uptime.alerts.availability.multiItemTitle": "低于可用性阈值 ({threshold} %) 的排名前 {monitorCount} 监测:\n", - "xpack.uptime.alerts.availability.singleItemTitle": "低于可用性阈值 ({threshold} %) 的监测:\n", "xpack.uptime.alerts.durationAnomaly": "Uptime 持续时间异常", "xpack.uptime.alerts.durationAnomaly.actionVariables.state.anomalyStartTimestamp": "异常开始的 ISO8601 时间戳。", "xpack.uptime.alerts.durationAnomaly.actionVariables.state.expectedResponseTime": "预期响应时间", @@ -18892,11 +18888,6 @@ "xpack.uptime.alerts.durationAnomaly.actionVariables.state.slowestAnomalyResponse": "在附加单位(ms、s)的异常存储桶期间最慢的响应时间。", "xpack.uptime.alerts.durationAnomaly.clientName": "Uptime 持续时间异常", "xpack.uptime.alerts.durationAnomaly.defaultActionMessage": "{anomalyStartTimestamp} 在 url {monitorUrl} 的 {monitor} 上检测到异常({severity} 级别)响应时间。异常严重性分数为 {severityScore}。\n从位置 {observerLocation} 检测到高达 {slowestAnomalyResponse} 的响应时间。预期响应时间为 {expectedResponseTime}。", - "xpack.uptime.alerts.message.emptyTitle": "未接收到已关闭监测 ID", - "xpack.uptime.alerts.message.fullListOverflow": "...以及 {overflowCount} 个其他{pluralizedMonitor}", - "xpack.uptime.alerts.message.multipleTitle": "已关闭监测: ", - "xpack.uptime.alerts.message.overflowBody": "... 以及 {overflowCount} 个其他监测", - "xpack.uptime.alerts.message.singularTitle": "已关闭监测: ", "xpack.uptime.alerts.monitorStatus": "运行时间监测状态", "xpack.uptime.alerts.monitorStatus.actionVariables.context.downMonitorsWithGeo.description": "生成的摘要,显示告警已检测为“关闭”的部分或所有监测", "xpack.uptime.alerts.monitorStatus.actionVariables.context.message.description": "生成的消息,汇总当前关闭的监测", @@ -18923,7 +18914,6 @@ "xpack.uptime.alerts.monitorStatus.availability.unit.headline": "选择时间范围单位", "xpack.uptime.alerts.monitorStatus.availability.unit.selectable": "使用此选择来设置此告警的可用性范围单位", "xpack.uptime.alerts.monitorStatus.clientName": "运行时间监测状态", - "xpack.uptime.alerts.monitorStatus.defaultActionMessage": "{contextMessage}\n上次触发时间:{lastTriggered}\n", "xpack.uptime.alerts.monitorStatus.filterBar.ariaLabel": "允许对监测状态告警使用筛选条件的输入", "xpack.uptime.alerts.monitorStatus.filters.anyLocation": "任意位置", "xpack.uptime.alerts.monitorStatus.filters.anyPort": "任意端口", diff --git a/x-pack/plugins/uptime/common/runtime_types/ping/ping.ts b/x-pack/plugins/uptime/common/runtime_types/ping/ping.ts index 0a4d6310927c4..f954f8ba30849 100644 --- a/x-pack/plugins/uptime/common/runtime_types/ping/ping.ts +++ b/x-pack/plugins/uptime/common/runtime_types/ping/ping.ts @@ -214,6 +214,9 @@ export const makePing = (f: { ip?: string; status?: string; duration?: number; + location?: string; + name?: string; + url?: string; }): Ping => { return { docId: f.docId || 'myDocId', @@ -224,7 +227,10 @@ export const makePing = (f: { ip: f.ip || '127.0.0.1', status: f.status || 'up', duration: { us: f.duration || 100000 }, + name: f.name, }, + ...(f.location ? { observer: { geo: { name: f.location } } } : {}), + ...(f.url ? { url: { full: f.url } } : {}), }; }; diff --git a/x-pack/plugins/uptime/common/translations.ts b/x-pack/plugins/uptime/common/translations.ts index 81f46df86f02e..a4a20a1445f57 100644 --- a/x-pack/plugins/uptime/common/translations.ts +++ b/x-pack/plugins/uptime/common/translations.ts @@ -16,3 +16,20 @@ export const VALUE_MUST_BE_GREATER_THAN_ZERO = i18n.translate( export const VALUE_MUST_BE_AN_INTEGER = i18n.translate('xpack.uptime.settings.invalid.nanError', { defaultMessage: 'Value must be an integer.', }); + +export const MonitorStatusTranslations = { + defaultActionMessage: i18n.translate('xpack.uptime.alerts.monitorStatus.defaultActionMessage', { + defaultMessage: + 'Monitor {monitorName} with url {monitorUrl} is {statusMessage} from {observerLocation}. The latest error message is {latestErrorMessage}', + values: { + monitorName: '{{state.monitorName}}', + monitorUrl: '{{{state.monitorUrl}}}', + statusMessage: '{{state.statusMessage}}', + latestErrorMessage: '{{{state.latestErrorMessage}}}', + observerLocation: '{{state.observerLocation}}', + }, + }), + name: i18n.translate('xpack.uptime.alerts.monitorStatus.clientName', { + defaultMessage: 'Uptime monitor status', + }), +}; diff --git a/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap b/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap index 42ac821c10c7a..2ae8454b99893 100644 --- a/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap +++ b/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/__snapshots__/monitor_list.test.tsx.snap @@ -213,6 +213,7 @@ exports[`MonitorList component MonitorListPagination component renders the pagin }, "id": "foo", "ip": "127.0.0.1", + "name": undefined, "status": "up", "type": "icmp", }, @@ -226,6 +227,7 @@ exports[`MonitorList component MonitorListPagination component renders the pagin }, "id": "foo", "ip": "127.0.0.2", + "name": undefined, "status": "up", "type": "icmp", }, @@ -239,6 +241,7 @@ exports[`MonitorList component MonitorListPagination component renders the pagin }, "id": "foo", "ip": "127.0.0.3", + "name": undefined, "status": "down", "type": "icmp", }, @@ -266,6 +269,7 @@ exports[`MonitorList component MonitorListPagination component renders the pagin }, "id": "bar", "ip": "127.0.0.1", + "name": undefined, "status": "down", "type": "icmp", }, @@ -279,6 +283,7 @@ exports[`MonitorList component MonitorListPagination component renders the pagin }, "id": "bar", "ip": "127.0.0.1", + "name": undefined, "status": "down", "type": "icmp", }, @@ -516,6 +521,7 @@ exports[`MonitorList component renders error list 1`] = ` }, "id": "foo", "ip": "127.0.0.1", + "name": undefined, "status": "up", "type": "icmp", }, @@ -529,6 +535,7 @@ exports[`MonitorList component renders error list 1`] = ` }, "id": "foo", "ip": "127.0.0.2", + "name": undefined, "status": "up", "type": "icmp", }, @@ -542,6 +549,7 @@ exports[`MonitorList component renders error list 1`] = ` }, "id": "foo", "ip": "127.0.0.3", + "name": undefined, "status": "down", "type": "icmp", }, @@ -569,6 +577,7 @@ exports[`MonitorList component renders error list 1`] = ` }, "id": "bar", "ip": "127.0.0.1", + "name": undefined, "status": "down", "type": "icmp", }, @@ -582,6 +591,7 @@ exports[`MonitorList component renders error list 1`] = ` }, "id": "bar", "ip": "127.0.0.1", + "name": undefined, "status": "down", "type": "icmp", }, @@ -714,6 +724,7 @@ exports[`MonitorList component renders loading state 1`] = ` }, "id": "foo", "ip": "127.0.0.1", + "name": undefined, "status": "up", "type": "icmp", }, @@ -727,6 +738,7 @@ exports[`MonitorList component renders loading state 1`] = ` }, "id": "foo", "ip": "127.0.0.2", + "name": undefined, "status": "up", "type": "icmp", }, @@ -740,6 +752,7 @@ exports[`MonitorList component renders loading state 1`] = ` }, "id": "foo", "ip": "127.0.0.3", + "name": undefined, "status": "down", "type": "icmp", }, @@ -767,6 +780,7 @@ exports[`MonitorList component renders loading state 1`] = ` }, "id": "bar", "ip": "127.0.0.1", + "name": undefined, "status": "down", "type": "icmp", }, @@ -780,6 +794,7 @@ exports[`MonitorList component renders loading state 1`] = ` }, "id": "bar", "ip": "127.0.0.1", + "name": undefined, "status": "down", "type": "icmp", }, @@ -1611,6 +1626,7 @@ exports[`MonitorList component shallow renders the monitor list 1`] = ` }, "id": "foo", "ip": "127.0.0.1", + "name": undefined, "status": "up", "type": "icmp", }, @@ -1624,6 +1640,7 @@ exports[`MonitorList component shallow renders the monitor list 1`] = ` }, "id": "foo", "ip": "127.0.0.2", + "name": undefined, "status": "up", "type": "icmp", }, @@ -1637,6 +1654,7 @@ exports[`MonitorList component shallow renders the monitor list 1`] = ` }, "id": "foo", "ip": "127.0.0.3", + "name": undefined, "status": "down", "type": "icmp", }, @@ -1664,6 +1682,7 @@ exports[`MonitorList component shallow renders the monitor list 1`] = ` }, "id": "bar", "ip": "127.0.0.1", + "name": undefined, "status": "down", "type": "icmp", }, @@ -1677,6 +1696,7 @@ exports[`MonitorList component shallow renders the monitor list 1`] = ` }, "id": "bar", "ip": "127.0.0.1", + "name": undefined, "status": "down", "type": "icmp", }, diff --git a/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_list_drawer.test.tsx.snap b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_list_drawer.test.tsx.snap index 329fb8bade106..42c885dfaf515 100644 --- a/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_list_drawer.test.tsx.snap +++ b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list_drawer/__tests__/__snapshots__/monitor_list_drawer.test.tsx.snap @@ -113,6 +113,7 @@ exports[`MonitorListDrawer component renders a MonitorListDrawer when there are }, "id": "foo", "ip": "127.0.0.1", + "name": undefined, "status": "up", "type": "icmp", }, @@ -126,6 +127,7 @@ exports[`MonitorListDrawer component renders a MonitorListDrawer when there are }, "id": "foo", "ip": "127.0.0.1", + "name": undefined, "status": "down", "type": "icmp", }, @@ -139,6 +141,7 @@ exports[`MonitorListDrawer component renders a MonitorListDrawer when there are }, "id": "foo", "ip": "127.0.0.2", + "name": undefined, "status": "up", "type": "icmp", }, @@ -152,6 +155,7 @@ exports[`MonitorListDrawer component renders a MonitorListDrawer when there are }, "id": "foo", "ip": "127.0.0.3", + "name": undefined, "status": "down", "type": "icmp", }, @@ -284,6 +288,7 @@ exports[`MonitorListDrawer component renders a MonitorListDrawer when there is o }, "id": "foo", "ip": "127.0.0.1", + "name": undefined, "status": "up", "type": "icmp", }, diff --git a/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts b/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts index e999768d4e55d..6af817c82ad95 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts +++ b/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts @@ -202,9 +202,7 @@ describe('monitor status alert type', () => { ).toMatchInlineSnapshot(` Object { "alertParamsExpression": [Function], - "defaultActionMessage": "{{context.message}} - Last triggered at: {{state.lastTriggeredAt}} - ", + "defaultActionMessage": "Monitor {{state.monitorName}} with url {{{state.monitorUrl}}} is {{state.statusMessage}} from {{state.observerLocation}}. The latest error message is {{{state.latestErrorMessage}}}", "iconClass": "uptimeApp", "id": "xpack.uptime.alerts.monitorStatus", "name": { "certExpirationThreshold": 30, "heartbeatIndices": "heartbeat-8*", }, + "filters": undefined, "locations": Array [], "numTimes": 5, - "shouldCheckStatus": true, "timerange": Object { "from": "now-15m", "to": "now", @@ -114,19 +114,28 @@ describe('status check alert', () => { it('triggers when monitors are down and provides expected state', async () => { toISOStringSpy.mockImplementation(() => 'foo date string'); - const mockGetter = jest.fn(); + const mockGetter: jest.Mock = jest.fn(); + mockGetter.mockReturnValue([ { - monitor_id: 'first', + monitorId: 'first', location: 'harrisburg', count: 234, status: 'down', + monitorInfo: makePing({ + id: 'first', + location: 'harrisburg', + }), }, { - monitor_id: 'first', + monitorId: 'first', location: 'fairbanks', count: 234, status: 'down', + monitorInfo: makePing({ + id: 'first', + location: 'fairbanks', + }), }, ]); const { server, libs, plugins } = bootstrapDependencies({ getMonitorStatus: mockGetter }); @@ -136,7 +145,7 @@ describe('status check alert', () => { // @ts-ignore the executor can return `void`, but ours never does const state: Record = await alert.executor(options); expect(mockGetter).toHaveBeenCalledTimes(1); - expect(alertServices.alertInstanceFactory).toHaveBeenCalledTimes(1); + expect(alertServices.alertInstanceFactory).toHaveBeenCalledTimes(2); expect(mockGetter.mock.calls[0]).toMatchInlineSnapshot(` Array [ Object { @@ -146,9 +155,9 @@ describe('status check alert', () => { "certExpirationThreshold": 30, "heartbeatIndices": "heartbeat-8*", }, + "filters": undefined, "locations": Array [], "numTimes": 5, - "shouldCheckStatus": true, "timerange": Object { "from": "now-15m", "to": "now", @@ -157,7 +166,7 @@ describe('status check alert', () => { ] `); const [{ value: alertInstanceMock }] = alertServices.alertInstanceFactory.mock.results; - expect(alertInstanceMock.replaceState).toHaveBeenCalledTimes(1); + expect(alertInstanceMock.replaceState).toHaveBeenCalledTimes(2); expect(alertInstanceMock.replaceState.mock.calls[0]).toMatchInlineSnapshot(` Array [ Object { @@ -168,30 +177,23 @@ describe('status check alert', () => { "lastCheckedAt": "foo date string", "lastResolvedAt": undefined, "lastTriggeredAt": "foo date string", - "monitors": Array [ - Object { - "count": 234, - "location": "fairbanks", - "monitor_id": "first", - "status": "down", - }, - Object { - "count": 234, - "location": "harrisburg", - "monitor_id": "first", - "status": "down", - }, - ], + "latestErrorMessage": undefined, + "monitorId": "first", + "monitorName": "first", + "monitorType": "myType", + "monitorUrl": undefined, + "observerHostname": undefined, + "observerLocation": "harrisburg", + "statusMessage": "down", }, ] `); - expect(alertInstanceMock.scheduleActions).toHaveBeenCalledTimes(1); + expect(alertInstanceMock.scheduleActions).toHaveBeenCalledTimes(2); expect(alertInstanceMock.scheduleActions.mock.calls[0]).toMatchInlineSnapshot(` Array [ "xpack.uptime.alerts.actionGroups.monitorStatus", Object { - "downMonitorsWithGeo": "first from fairbanks; first from harrisburg; ", - "message": "Down monitor: first", + "message": "Monitor first with url is down from harrisburg. The latest error message is ", }, ] `); @@ -199,19 +201,29 @@ describe('status check alert', () => { it('supports 7.7 alert format', async () => { toISOStringSpy.mockImplementation(() => '7.7 date'); - const mockGetter = jest.fn(); + const mockGetter: jest.Mock = jest.fn(); + mockGetter.mockReturnValue([ { - monitor_id: 'first', + monitorId: 'first', location: 'harrisburg', count: 234, status: 'down', + monitorInfo: makePing({ + id: 'first', + location: 'harrisburg', + }), }, { - monitor_id: 'first', + monitorId: 'first', location: 'fairbanks', count: 234, status: 'down', + + monitorInfo: makePing({ + id: 'first', + location: 'fairbanks', + }), }, ]); const { server, libs, plugins } = bootstrapDependencies({ @@ -227,8 +239,9 @@ describe('status check alert', () => { }); const alertServices: AlertServicesMock = options.services; const state = await alert.executor(options); + const [{ value: alertInstanceMock }] = alertServices.alertInstanceFactory.mock.results; - expect(alertInstanceMock.replaceState).toHaveBeenCalledTimes(1); + expect(alertInstanceMock.replaceState).toHaveBeenCalledTimes(2); expect(alertInstanceMock.replaceState.mock.calls[0]).toMatchInlineSnapshot(` Array [ Object { @@ -239,20 +252,14 @@ describe('status check alert', () => { "lastCheckedAt": "7.7 date", "lastResolvedAt": undefined, "lastTriggeredAt": "7.7 date", - "monitors": Array [ - Object { - "count": 234, - "location": "fairbanks", - "monitor_id": "first", - "status": "down", - }, - Object { - "count": 234, - "location": "harrisburg", - "monitor_id": "first", - "status": "down", - }, - ], + "latestErrorMessage": undefined, + "monitorId": "first", + "monitorName": "first", + "monitorType": "myType", + "monitorUrl": undefined, + "observerHostname": undefined, + "observerLocation": "harrisburg", + "statusMessage": "down", }, ] `); @@ -272,19 +279,28 @@ describe('status check alert', () => { it('supports 7.8 alert format', async () => { expect.assertions(5); toISOStringSpy.mockImplementation(() => 'foo date string'); - const mockGetter = jest.fn(); + const mockGetter: jest.Mock = jest.fn(); mockGetter.mockReturnValue([ { - monitor_id: 'first', + monitorId: 'first', location: 'harrisburg', count: 234, status: 'down', + monitorInfo: makePing({ + id: 'first', + location: 'harrisburg', + }), }, { - monitor_id: 'first', + monitorId: 'first', location: 'fairbanks', count: 234, status: 'down', + + monitorInfo: makePing({ + id: 'first', + location: 'fairbanks', + }), }, ]); const { server, libs, plugins } = bootstrapDependencies({ @@ -317,7 +333,166 @@ describe('status check alert', () => { "certExpirationThreshold": 30, "heartbeatIndices": "heartbeat-8*", }, - "filters": "{\\"bool\\":{\\"filter\\":[{\\"bool\\":{\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"bool\\":{\\"should\\":[{\\"match\\":{\\"url.port\\":12349}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"bool\\":{\\"should\\":[{\\"match\\":{\\"url.port\\":5601}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"match\\":{\\"url.port\\":443}}],\\"minimum_should_match\\":1}}],\\"minimum_should_match\\":1}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"match\\":{\\"observer.geo.name\\":\\"harrisburg\\"}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"match\\":{\\"monitor.type\\":\\"http\\"}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"bool\\":{\\"should\\":[{\\"match\\":{\\"tags\\":\\"unsecured\\"}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"bool\\":{\\"should\\":[{\\"match\\":{\\"tags\\":\\"containers\\"}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"match_phrase\\":{\\"tags\\":\\"org:google\\"}}],\\"minimum_should_match\\":1}}],\\"minimum_should_match\\":1}}],\\"minimum_should_match\\":1}}]}}]}}]}},{\\"bool\\":{\\"should\\":[{\\"exists\\":{\\"field\\":\\"monitor.ip\\"}}],\\"minimum_should_match\\":1}}]}}", + "filters": Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "url.port": 12349, + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "url.port": 5601, + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "url.port": 443, + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "observer.geo.name": "harrisburg", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "monitor.type": "http", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "tags": "unsecured", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "tags": "containers", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match_phrase": Object { + "tags": "org:google", + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "exists": Object { + "field": "monitor.ip", + }, + }, + ], + }, + }, + ], + }, + }, "locations": Array [], "numTimes": 3, "timerange": Object { @@ -327,7 +502,7 @@ describe('status check alert', () => { }, ] `); - expect(alertInstanceMock.replaceState).toHaveBeenCalledTimes(1); + expect(alertInstanceMock.replaceState).toHaveBeenCalledTimes(2); expect(alertInstanceMock.replaceState.mock.calls[0]).toMatchInlineSnapshot(` Array [ Object { @@ -338,20 +513,14 @@ describe('status check alert', () => { "lastCheckedAt": "foo date string", "lastResolvedAt": undefined, "lastTriggeredAt": "foo date string", - "monitors": Array [ - Object { - "count": 234, - "location": "fairbanks", - "monitor_id": "first", - "status": "down", - }, - Object { - "count": 234, - "location": "harrisburg", - "monitor_id": "first", - "status": "down", - }, - ], + "latestErrorMessage": undefined, + "monitorId": "first", + "monitorName": "first", + "monitorType": "myType", + "monitorUrl": undefined, + "observerHostname": undefined, + "observerLocation": "harrisburg", + "statusMessage": "down", }, ] `); @@ -390,6 +559,7 @@ describe('status check alert', () => { search: 'url.full: *', }); await alert.executor(options); + expect(mockGetter).toHaveBeenCalledTimes(1); expect(mockGetter.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -400,7 +570,36 @@ describe('status check alert', () => { "certExpirationThreshold": 30, "heartbeatIndices": "heartbeat-8*", }, - "filters": "{\\"bool\\":{\\"filter\\":[{\\"bool\\":{\\"should\\":[{\\"match\\":{\\"monitor.type\\":\\"http\\"}}],\\"minimum_should_match\\":1}},{\\"bool\\":{\\"should\\":[{\\"exists\\":{\\"field\\":\\"url.full\\"}}],\\"minimum_should_match\\":1}}]}}", + "filters": Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "monitor.type": "http", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "exists": Object { + "field": "url.full", + }, + }, + ], + }, + }, + ], + }, + }, "locations": Array [], "numTimes": 20, "timerange": Object { @@ -415,57 +614,60 @@ describe('status check alert', () => { it('supports availability checks', async () => { expect.assertions(8); toISOStringSpy.mockImplementation(() => 'availability test'); - const mockGetter = jest.fn(); - mockGetter.mockReturnValue([ - { - monitor_id: 'first', - location: 'harrisburg', - count: 234, - status: 'down', - }, - { - monitor_id: 'first', - location: 'fairbanks', - count: 234, - status: 'down', - }, - ]); - const mockAvailability = jest.fn(); + const mockGetter: jest.Mock = jest.fn(); + mockGetter.mockReturnValue([]); + const mockAvailability: jest.Mock = jest.fn(); mockAvailability.mockReturnValue([ { monitorId: 'foo', location: 'harrisburg', - name: 'Foo', - url: 'https://foo.com', up: 2341, down: 17, availabilityRatio: 0.992790500424088, + monitorInfo: makePing({ + id: 'foo', + location: 'harrisburg', + name: 'Foo', + url: 'https://foo.com', + }), }, { monitorId: 'foo', location: 'fairbanks', - name: 'Foo', - url: 'https://foo.com', up: 2343, down: 47, availabilityRatio: 0.980334728033473, + monitorInfo: makePing({ + id: 'foo', + location: 'fairbanks', + name: 'Foo', + url: 'https://foo.com', + }), }, { monitorId: 'unreliable', location: 'fairbanks', - name: 'Unreliable', - url: 'https://unreliable.co', up: 2134, down: 213, availabilityRatio: 0.909245845760545, + monitorInfo: makePing({ + id: 'unreliable', + location: 'fairbanks', + name: 'Unreliable', + url: 'https://unreliable.co', + }), }, { monitorId: 'no-name', location: 'fairbanks', - url: 'https://no-name.co', up: 2134, down: 213, availabilityRatio: 0.909245845760545, + monitorInfo: makePing({ + id: 'no-name', + location: 'fairbanks', + url: 'https://no-name.co', + }), }, ]); const { server, libs, plugins } = bootstrapDependencies({ @@ -487,11 +689,12 @@ describe('status check alert', () => { tags: ['unsecured', 'containers', 'org:google'], }, shouldCheckAvailability: true, + shouldCheckStatus: false, }); const alertServices: AlertServicesMock = options.services; const state = await alert.executor(options); const [{ value: alertInstanceMock }] = alertServices.alertInstanceFactory.mock.results; - expect(alertInstanceMock.replaceState).toHaveBeenCalledTimes(1); + expect(alertInstanceMock.replaceState).toHaveBeenCalledTimes(4); expect(alertInstanceMock.replaceState.mock.calls[0]).toMatchInlineSnapshot(` Array [ Object { @@ -502,22 +705,42 @@ describe('status check alert', () => { "lastCheckedAt": "availability test", "lastResolvedAt": undefined, "lastTriggeredAt": "availability test", - "monitors": Array [], + "latestErrorMessage": undefined, + "monitorId": "foo", + "monitorName": "Foo", + "monitorType": "myType", + "monitorUrl": "https://foo.com", + "observerHostname": undefined, + "observerLocation": "harrisburg", + "statusMessage": "below threshold with 99.28% availability expected is 99.34%", }, ] `); - expect(alertInstanceMock.scheduleActions).toHaveBeenCalledTimes(1); + expect(alertInstanceMock.scheduleActions).toHaveBeenCalledTimes(4); expect(alertInstanceMock.scheduleActions.mock.calls).toMatchInlineSnapshot(` Array [ Array [ "xpack.uptime.alerts.actionGroups.monitorStatus", Object { - "downMonitorsWithGeo": "", - "message": "Top 3 Monitors Below Availability Threshold (99.34 %): - Unreliable(https://unreliable.co): 90.925% - no-name(https://no-name.co): 90.925% - Foo(https://foo.com): 98.033% - ", + "message": "Monitor Foo with url https://foo.com is below threshold with 99.28% availability expected is 99.34% from harrisburg. The latest error message is ", + }, + ], + Array [ + "xpack.uptime.alerts.actionGroups.monitorStatus", + Object { + "message": "Monitor Foo with url https://foo.com is below threshold with 98.03% availability expected is 99.34% from fairbanks. The latest error message is ", + }, + ], + Array [ + "xpack.uptime.alerts.actionGroups.monitorStatus", + Object { + "message": "Monitor Unreliable with url https://unreliable.co is below threshold with 90.92% availability expected is 99.34% from fairbanks. The latest error message is ", + }, + ], + Array [ + "xpack.uptime.alerts.actionGroups.monitorStatus", + Object { + "message": "Monitor no-name with url https://no-name.co is below threshold with 90.92% availability expected is 99.34% from fairbanks. The latest error message is ", }, ], ] @@ -573,7 +796,9 @@ describe('status check alert', () => { }, search: 'ur.port: *', shouldCheckAvailability: true, + shouldCheckStatus: false, }); + await alert.executor(options); expect(mockAvailability).toHaveBeenCalledTimes(1); expect(mockAvailability.mock.calls[0]).toMatchInlineSnapshot(` @@ -613,8 +838,11 @@ describe('status check alert', () => { threshold: '90', }, shouldCheckAvailability: true, + shouldCheckStatus: false, }); + await alert.executor(options); + expect(mockAvailability).toHaveBeenCalledTimes(1); expect(mockAvailability.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -635,116 +863,6 @@ describe('status check alert', () => { }); }); - describe('fullListByIdAndLocation', () => { - it('renders a list of all monitors', () => { - const statuses: GetMonitorStatusResult[] = [ - { - location: 'harrisburg', - monitor_id: 'first', - status: 'down', - count: 34, - }, - { - location: 'fairbanks', - monitor_id: 'second', - status: 'down', - count: 23, - }, - { - location: 'fairbanks', - monitor_id: 'first', - status: 'down', - count: 23, - }, - { - location: 'harrisburg', - monitor_id: 'second', - status: 'down', - count: 34, - }, - ]; - expect(fullListByIdAndLocation(statuses)).toMatchInlineSnapshot( - `"first from fairbanks; first from harrisburg; second from fairbanks; second from harrisburg; "` - ); - }); - - it('renders a list of monitors when greater than limit', () => { - const statuses: GetMonitorStatusResult[] = [ - { - location: 'fairbanks', - monitor_id: 'second', - status: 'down', - count: 23, - }, - { - location: 'fairbanks', - monitor_id: 'first', - status: 'down', - count: 23, - }, - { - location: 'harrisburg', - monitor_id: 'first', - status: 'down', - count: 34, - }, - { - location: 'harrisburg', - monitor_id: 'second', - status: 'down', - count: 34, - }, - ]; - expect(fullListByIdAndLocation(statuses.slice(0, 2), 1)).toMatchInlineSnapshot( - `"first from fairbanks; ...and 1 other monitor/location"` - ); - }); - - it('renders expected list of monitors when limit difference > 1', () => { - const statuses: GetMonitorStatusResult[] = [ - { - location: 'fairbanks', - monitor_id: 'second', - status: 'down', - count: 23, - }, - { - location: 'harrisburg', - monitor_id: 'first', - status: 'down', - count: 34, - }, - { - location: 'harrisburg', - monitor_id: 'second', - status: 'down', - count: 34, - }, - { - location: 'harrisburg', - monitor_id: 'third', - status: 'down', - count: 34, - }, - { - location: 'fairbanks', - monitor_id: 'third', - status: 'down', - count: 23, - }, - { - location: 'fairbanks', - monitor_id: 'first', - status: 'down', - count: 23, - }, - ]; - expect(fullListByIdAndLocation(statuses, 4)).toMatchInlineSnapshot( - `"first from fairbanks; first from harrisburg; second from fairbanks; second from harrisburg; ...and 2 other monitors/locations"` - ); - }); - }); - describe('alert factory', () => { let alert: AlertType; @@ -820,16 +938,26 @@ describe('status check alert', () => { mockGetIndexPattern.mockReturnValue(undefined); it('returns `undefined` for no filters or search', async () => { - expect(await generateFilterDSL(mockGetIndexPattern)).toBeUndefined(); + expect( + await generateFilterDSL( + mockGetIndexPattern, + { 'monitor.type': [], 'observer.geo.name': [], tags: [], 'url.port': [] }, + '' + ) + ).toBeUndefined(); }); it('creates a filter string for filters only', async () => { - const res = await generateFilterDSL(mockGetIndexPattern, { - 'monitor.type': [], - 'observer.geo.name': ['us-east', 'us-west'], - tags: [], - 'url.port': [], - }); + const res = await generateFilterDSL( + mockGetIndexPattern, + { + 'monitor.type': [], + 'observer.geo.name': ['us-east', 'us-west'], + tags: [], + 'url.port': [], + }, + '' + ); expect(res).toMatchInlineSnapshot(` Object { "bool": Object { @@ -866,8 +994,13 @@ describe('status check alert', () => { }); it('creates a filter string for search only', async () => { - expect(await generateFilterDSL(mockGetIndexPattern, undefined, 'monitor.id: "kibana-dev"')) - .toMatchInlineSnapshot(` + expect( + await generateFilterDSL( + mockGetIndexPattern, + { 'monitor.type': [], 'observer.geo.name': [], tags: [], 'url.port': [] }, + 'monitor.id: "kibana-dev"' + ) + ).toMatchInlineSnapshot(` Object { "bool": Object { "minimum_should_match": 1, @@ -987,217 +1120,159 @@ describe('status check alert', () => { }); describe('uniqueMonitorIds', () => { - let items: GetMonitorStatusResult[]; + let downItems: GetMonitorStatusResult[]; + let availItems: GetMonitorAvailabilityResult[]; beforeEach(() => { - items = [ + downItems = [ { - monitor_id: 'first', + monitorId: 'first', location: 'harrisburg', count: 234, status: 'down', + monitorInfo: makePing({}), }, { - monitor_id: 'first', + monitorId: 'first', location: 'fairbanks', count: 312, status: 'down', + monitorInfo: makePing({}), }, { - monitor_id: 'second', + monitorId: 'second', location: 'harrisburg', count: 325, status: 'down', + monitorInfo: makePing({}), }, { - monitor_id: 'second', + monitorId: 'second', location: 'fairbanks', count: 331, status: 'down', + monitorInfo: makePing({}), }, + ]; + + availItems = [ { - monitor_id: 'third', - location: 'harrisburg', - count: 331, - status: 'down', - }, - { - monitor_id: 'third', - location: 'fairbanks', - count: 342, - status: 'down', - }, - { - monitor_id: 'fourth', + monitorId: 'first', location: 'harrisburg', - count: 355, - status: 'down', + monitorInfo: makePing({}), + up: 2134, + down: 213, + availabilityRatio: 0.909245845760545, }, { - monitor_id: 'fourth', + monitorId: 'first', location: 'fairbanks', - count: 342, - status: 'down', + monitorInfo: makePing({}), + up: 2134, + down: 213, + availabilityRatio: 0.909245845760545, }, { - monitor_id: 'fifth', + monitorId: 'second', location: 'harrisburg', - count: 342, - status: 'down', + monitorInfo: makePing({}), + up: 2134, + down: 213, + availabilityRatio: 0.909245845760545, }, { - monitor_id: 'fifth', + monitorId: 'second', location: 'fairbanks', - count: 342, - status: 'down', + monitorInfo: makePing({}), + up: 2134, + down: 213, + availabilityRatio: 0.909245845760545, }, ]; }); it('creates a set of unique IDs from a list of composite unique objects', () => { - expect(uniqueMonitorIds(items)).toEqual( - new Set(['first', 'second', 'third', 'fourth', 'fifth']) - ); - }); - }); - - describe('contextMessage', () => { - let ids: string[]; - beforeEach(() => { - ids = ['first', 'second', 'third', 'fourth', 'fifth']; - }); - - it('creates a message with appropriate number of monitors', () => { - expect(contextMessage(ids, 3, [], '0', false, true)).toMatchInlineSnapshot( - `"Down monitors: first, second, third... and 2 other monitors"` - ); - }); - - it('throws an error if `max` is less than 2', () => { - expect(() => contextMessage(ids, 1, [], '0', false, true)).toThrowErrorMatchingInlineSnapshot( - '"Maximum value must be greater than 2, received 1."' - ); - }); - - it('returns only the ids if length < max', () => { - expect(contextMessage(ids.slice(0, 2), 3, [], '0', false, true)).toMatchInlineSnapshot( - `"Down monitors: first, second"` - ); - }); - - it('returns a default message when no monitors are provided', () => { - expect(contextMessage([], 3, [], '0', false, true)).toMatchInlineSnapshot( - `"No down monitor IDs received"` + expect(getUniqueIdsByLoc(downItems, availItems)).toEqual( + new Set([ + 'firstharrisburg', + 'firstfairbanks', + 'secondharrisburg', + 'secondfairbanks', + ]) ); }); }); - describe('availabilityMessage', () => { - it('creates message for singular item', () => { + describe('statusMessage', () => { + it('creates message for down item', () => { expect( - availabilityMessage( - [ - { - monitorId: 'test-node-service', - location: 'fairbanks', - name: 'Test Node Service', - url: 'http://localhost:12349', - up: 821.0, - down: 2450.0, - availabilityRatio: 0.25099357994497096, - }, - ], - '59' + getStatusMessage( + makePing({ + id: 'test-node-service', + location: 'fairbanks', + name: 'Test Node Service', + url: 'http://localhost:12349', + }) ) - ).toMatchInlineSnapshot(` - "Monitor Below Availability Threshold (59 %): - Test Node Service(http://localhost:12349): 25.099% - " - `); + ).toMatchInlineSnapshot(`"down"`); }); - it('creates message for multiple items', () => { + it('creates message for availability item', () => { expect( - availabilityMessage( - [ - { - monitorId: 'test-node-service', - location: 'fairbanks', + getStatusMessage( + undefined, + { + monitorId: 'test-node-service', + location: 'harrisburg', + up: 3389.0, + down: 2450.0, + availabilityRatio: 0.5804076040417879, + monitorInfo: makePing({ name: 'Test Node Service', url: 'http://localhost:12349', - up: 821.0, - down: 2450.0, - availabilityRatio: 0.25099357994497096, - }, - { - monitorId: 'test-node-service', + id: 'test-node-service', location: 'harrisburg', - name: 'Test Node Service', - url: 'http://localhost:12349', - up: 3389.0, - down: 2450.0, - availabilityRatio: 0.5804076040417879, - }, - ], - '59' + }), + }, + { + threshold: '90', + range: 5, + rangeUnit: 'm', + } ) - ).toMatchInlineSnapshot(` - "Top 2 Monitors Below Availability Threshold (59 %): - Test Node Service(http://localhost:12349): 25.099% - Test Node Service(http://localhost:12349): 58.041% - " - `); + ).toMatchInlineSnapshot(`"below threshold with 58.04% availability expected is 90%"`); }); - it('caps message for multiple items', () => { + it('creates message for down and availability item', () => { expect( - availabilityMessage( - [ - { - monitorId: 'test-node-service', - location: 'fairbanks', + getStatusMessage( + makePing({ + id: 'test-node-service', + location: 'fairbanks', + name: 'Test Node Service', + url: 'http://localhost:12349', + }), + { + monitorId: 'test-node-service', + location: 'harrisburg', + up: 3389.0, + down: 2450.0, + availabilityRatio: 0.5804076040417879, + monitorInfo: makePing({ name: 'Test Node Service', url: 'http://localhost:12349', - up: 821.0, - down: 2450.0, - availabilityRatio: 0.250993579944971, - }, - { - monitorId: 'test-node-service', + id: 'test-node-service', location: 'harrisburg', - name: 'Test Node Service', - url: 'http://localhost:12349', - up: 3389.0, - down: 2450.0, - availabilityRatio: 0.58040760404178, - }, - { - monitorId: 'test-node-service', - location: 'berlin', - name: 'Test Node Service', - url: 'http://localhost:12349', - up: 3645.0, - down: 2982.0, - availabilityRatio: 0.550022634676324, - }, - { - monitorId: 'test-node-service', - location: 'st paul', - name: 'Test Node Service', - url: 'http://localhost:12349', - up: 3601.0, - down: 2681.0, - availabilityRatio: 0.573225087551735, - }, - ], - '59' + }), + }, + { + threshold: '90', + range: 5, + rangeUnit: 'm', + } ) - ).toMatchInlineSnapshot(` - "Top 3 Monitors Below Availability Threshold (59 %): - Test Node Service(http://localhost:12349): 25.099% - Test Node Service(http://localhost:12349): 55.002% - Test Node Service(http://localhost:12349): 57.323% - " - `); + ).toMatchInlineSnapshot( + `"down and also below threshold with 58.04% availability expected is 90%"` + ); }); }); }); diff --git a/x-pack/plugins/uptime/server/lib/alerts/duration_anomaly.ts b/x-pack/plugins/uptime/server/lib/alerts/duration_anomaly.ts index a71913d0eea9a..9ed453d286285 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/duration_anomaly.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/duration_anomaly.ts @@ -12,12 +12,12 @@ import { ACTION_GROUP_DEFINITIONS } from '../../../common/constants/alerts'; import { commonStateTranslations, durationAnomalyTranslations } from './translations'; import { AnomaliesTableRecord } from '../../../../ml/common/types/anomalies'; import { getSeverityType } from '../../../../ml/common/util/anomaly_utils'; -import { getLatestMonitor } from '../requests'; import { savedObjectsAdapter } from '../saved_objects'; import { UptimeCorePlugins } from '../adapters/framework'; import { UptimeAlertTypeFactory } from './types'; import { Ping } from '../../../common/runtime_types/ping'; import { getMLJobId } from '../../../common/lib'; +import { getLatestMonitor } from '../requests/get_latest_monitor'; const { DURATION_ANOMALY } = ACTION_GROUP_DEFINITIONS; diff --git a/x-pack/plugins/uptime/server/lib/alerts/status_check.ts b/x-pack/plugins/uptime/server/lib/alerts/status_check.ts index 8ca2e857a52c9..134472ba0693f 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/status_check.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/status_check.ts @@ -5,225 +5,46 @@ */ import { schema } from '@kbn/config-schema'; -import { isRight } from 'fp-ts/lib/Either'; -import { ThrowReporter } from 'io-ts/lib/ThrowReporter'; import { i18n } from '@kbn/i18n'; -import { AlertExecutorOptions } from '../../../../alerts/server'; +import { ILegacyScopedClusterClient } from 'kibana/server'; +import Mustache from 'mustache'; import { UptimeAlertTypeFactory } from './types'; -import { GetMonitorStatusResult } from '../requests'; import { esKuery, IIndexPattern } from '../../../../../../src/plugins/data/server'; import { JsonObject } from '../../../../../../src/plugins/kibana_utils/common'; import { - StatusCheckParamsType, - StatusCheckParams, StatusCheckFilters, - AtomicStatusCheckParamsType, - MonitorAvailabilityType, DynamicSettings, + Ping, + GetMonitorAvailabilityParams, } from '../../../common/runtime_types'; import { ACTION_GROUP_DEFINITIONS } from '../../../common/constants/alerts'; -import { savedObjectsAdapter } from '../saved_objects'; import { updateState } from './common'; -import { commonStateTranslations } from './translations'; +import { commonMonitorStateI18, commonStateTranslations, DOWN_LABEL } from './translations'; import { stringifyKueries, combineFiltersAndUserSearch } from '../../../common/lib'; import { GetMonitorAvailabilityResult } from '../requests/get_monitor_availability'; import { UMServerLibs } from '../lib'; +import { GetMonitorStatusResult } from '../requests/get_monitor_status'; +import { UNNAMED_LOCATION } from '../../../common/constants'; +import { uptimeAlertWrapper } from './uptime_alert_wrapper'; +import { MonitorStatusTranslations } from '../../../common/translations'; const { MONITOR_STATUS } = ACTION_GROUP_DEFINITIONS; -/** - * Reduce a composite-key array of status results to a set of unique IDs. - * @param items to reduce - */ -export const uniqueMonitorIds = (items: GetMonitorStatusResult[]): Set => - // eslint-disable-next-line @typescript-eslint/naming-convention - items.reduce((acc, { monitor_id }) => { - acc.add(monitor_id); - return acc; - }, new Set()); - -const sortAvailabilityResultByRatioAsc = ( - a: GetMonitorAvailabilityResult, - b: GetMonitorAvailabilityResult -): number => (a.availabilityRatio ?? 100) - (b.availabilityRatio ?? 100); - -/** - * Map an availability result object to a descriptive string. - */ -const mapAvailabilityResultToString = ({ - availabilityRatio, - name, - monitorId, - url, -}: GetMonitorAvailabilityResult) => - i18n.translate('xpack.uptime.alerts.availability.monitorSummary', { - defaultMessage: '{nameOrId}({url}): {availabilityRatio}%', - values: { - nameOrId: name || monitorId, - url, - availabilityRatio: ((availabilityRatio ?? 1.0) * 100).toPrecision(5), - }, - }); - -const reduceAvailabilityStringsToMessage = (threshold: string) => ( - prev: string, - cur: string, - _ind: number, - array: string[] -) => { - let prefix: string = ''; - if (prev !== '') { - prefix = prev; - } else if (array.length > 1) { - prefix = i18n.translate('xpack.uptime.alerts.availability.multiItemTitle', { - defaultMessage: `Top {monitorCount} Monitors Below Availability Threshold ({threshold} %):\n`, - values: { - monitorCount: Math.min(array.length, MESSAGE_AVAILABILITY_MAX), - threshold, - }, - }); - } else { - prefix = i18n.translate('xpack.uptime.alerts.availability.singleItemTitle', { - defaultMessage: `Monitor Below Availability Threshold ({threshold} %):\n`, - values: { threshold }, - }); - } - return prefix + `${cur}\n`; -}; - -const MESSAGE_AVAILABILITY_MAX = 3; - -/** - * Creates a summary message from a list of availability check result objects. - * @param availabilityResult the list of results - * @param threshold the threshold used by the check - */ -export const availabilityMessage = ( - availabilityResult: GetMonitorAvailabilityResult[], - threshold: string, - max: number = MESSAGE_AVAILABILITY_MAX -): string => { - return availabilityResult.length > 0 - ? // if there are results, map each item to a descriptive string, and reduce the list - availabilityResult - .sort(sortAvailabilityResultByRatioAsc) - .slice(0, max) - .map(mapAvailabilityResultToString) - .reduce(reduceAvailabilityStringsToMessage(threshold), '') - : // if there are no results, return an empty list default string - i18n.translate('xpack.uptime.alerts.availability.emptyMessage', { - defaultMessage: `No monitors were below Availability Threshold ({threshold} %)`, - values: { - threshold, - }, - }); -}; - -/** - * Generates a message to include in contexts of alerts. - * @param monitors the list of monitors to include in the message - * @param max the maximum number of items the summary should contain - */ -export const contextMessage = ( - monitorIds: string[], - max: number, - availabilityResult: GetMonitorAvailabilityResult[], - availabilityThreshold: string, - availabilityWasChecked: boolean, - statusWasChecked: boolean -): string => { - const MIN = 2; - if (max < MIN) throw new Error(`Maximum value must be greater than ${MIN}, received ${max}.`); - - // generate the message - let message = ''; - if (statusWasChecked) { - if (monitorIds.length === 1) { - message = i18n.translate('xpack.uptime.alerts.message.singularTitle', { - defaultMessage: 'Down monitor: ', - }); - } else if (monitorIds.length) { - message = i18n.translate('xpack.uptime.alerts.message.multipleTitle', { - defaultMessage: 'Down monitors: ', - }); - } else { - message = i18n.translate('xpack.uptime.alerts.message.emptyTitle', { - defaultMessage: 'No down monitor IDs received', - }); - } - - for (let i = 0; i < monitorIds.length; i++) { - const id = monitorIds[i]; - if (i === max) { - message = - message + - i18n.translate('xpack.uptime.alerts.message.overflowBody', { - defaultMessage: `... and {overflowCount} other monitors`, - values: { - overflowCount: monitorIds.length - i, - }, - }); - break; - } else if (i === 0) { - message = message + id; - } else { - message = message + `, ${id}`; - } - } - } - - if (availabilityWasChecked) { - const availabilityMsg = availabilityMessage(availabilityResult, availabilityThreshold); - return message ? message + '\n' + availabilityMsg : availabilityMsg; - } +const uniqueDownMonitorIds = (items: GetMonitorStatusResult[]): Set => + items.reduce((acc, { monitorId, location }) => acc.add(monitorId + location), new Set()); - return message; -}; +const uniqueAvailMonitorIds = (items: GetMonitorAvailabilityResult[]): Set => + items.reduce((acc, { monitorId, location }) => acc.add(monitorId + location), new Set()); -/** - * Creates an exhaustive list of all the down monitors. - * @param list all the monitors that are down - * @param sizeLimit the max monitors, we shouldn't allow an arbitrarily long string - */ -export const fullListByIdAndLocation = ( - list: GetMonitorStatusResult[], - sizeLimit: number = 1000 +export const getUniqueIdsByLoc = ( + downMonitorsByLocation: GetMonitorStatusResult[], + availabilityResults: GetMonitorAvailabilityResult[] ) => { - return ( - list - // sort by id, then location - .sort((a, b) => { - if (a.monitor_id > b.monitor_id) { - return 1; - } else if (a.monitor_id < b.monitor_id) { - return -1; - } else if (a.location > b.location) { - return 1; - } - return -1; - }) - .slice(0, sizeLimit) - .reduce( - (cur, { monitor_id: id, location }) => - cur + `${id} from ${location ?? 'Unnamed location'}; `, - '' - ) + - (sizeLimit < list.length - ? i18n.translate('xpack.uptime.alerts.message.fullListOverflow', { - defaultMessage: '...and {overflowCount} other {pluralizedMonitor}', - values: { - pluralizedMonitor: - list.length - sizeLimit === 1 ? 'monitor/location' : 'monitors/locations', - overflowCount: list.length - sizeLimit, - }, - }) - : '') - ); -}; + const uniqueDownsIdsByLoc = uniqueDownMonitorIds(downMonitorsByLocation); + const uniqueAvailIdsByLoc = uniqueAvailMonitorIds(availabilityResults); -// Right now the maximum number of monitors shown in the message is hardcoded here. -// we might want to make this a parameter in the future -const DEFAULT_MAX_MESSAGE_ROWS = 3; + return new Set([...uniqueDownsIdsByLoc, ...uniqueAvailIdsByLoc]); +}; export const hasFilters = (filters?: StatusCheckFilters) => { if (!filters) return false; @@ -237,25 +58,18 @@ export const hasFilters = (filters?: StatusCheckFilters) => { export const generateFilterDSL = async ( getIndexPattern: () => Promise, - filters?: StatusCheckFilters, - search?: string + filters: StatusCheckFilters, + search: string ): Promise => { const filtersExist = hasFilters(filters); if (!filtersExist && !search) return undefined; - let filterString: string | undefined; + let filterString = ''; if (filtersExist) { filterString = stringifyKueries(new Map(Object.entries(filters ?? {}))); } - let combinedString: string | undefined; - if (filterString && search) { - combinedString = combineFiltersAndUserSearch(filterString, search); - } else if (filterString) { - combinedString = filterString; - } else if (search) { - combinedString = search; - } + const combinedString = combineFiltersAndUserSearch(filterString, search); return esKuery.toElasticsearchQuery( esKuery.fromKueryExpression(combinedString ?? ''), @@ -266,183 +80,232 @@ export const generateFilterDSL = async ( const formatFilterString = async ( libs: UMServerLibs, dynamicSettings: DynamicSettings, - options: AlertExecutorOptions, - filters?: StatusCheckFilters, - search?: string + callES: ILegacyScopedClusterClient['callAsCurrentUser'], + filters: StatusCheckFilters, + search: string ) => - JSON.stringify( - await generateFilterDSL( - () => - libs.requests.getIndexPattern({ - callES: options.services.callCluster, - dynamicSettings, - }), - filters, - search - ) + await generateFilterDSL( + () => + libs.requests.getIndexPattern({ + callES, + dynamicSettings, + }), + filters, + search ); -export const statusCheckAlertFactory: UptimeAlertTypeFactory = (_server, libs) => ({ - id: 'xpack.uptime.alerts.monitorStatus', - name: i18n.translate('xpack.uptime.alerts.monitorStatus', { - defaultMessage: 'Uptime monitor status', - }), - validate: { - params: schema.object({ - availability: schema.maybe( - schema.object({ - range: schema.number(), - rangeUnit: schema.string(), - threshold: schema.string(), - }) - ), - filters: schema.maybe( - schema.oneOf([ - // deprecated - schema.object({ - 'monitor.type': schema.maybe(schema.arrayOf(schema.string())), - 'observer.geo.name': schema.maybe(schema.arrayOf(schema.string())), - tags: schema.maybe(schema.arrayOf(schema.string())), - 'url.port': schema.maybe(schema.arrayOf(schema.string())), - }), - schema.string(), - ]) - ), - // deprecated - locations: schema.maybe(schema.arrayOf(schema.string())), - numTimes: schema.number(), - search: schema.maybe(schema.string()), - shouldCheckStatus: schema.maybe(schema.boolean()), - shouldCheckAvailability: schema.maybe(schema.boolean()), - timerangeCount: schema.maybe(schema.number()), - timerangeUnit: schema.maybe(schema.string()), - // deprecated - timerange: schema.maybe( - schema.object({ - from: schema.string(), - to: schema.string(), - }) - ), - version: schema.maybe(schema.number()), - }), - }, - defaultActionGroupId: MONITOR_STATUS.id, - actionGroups: [ - { - id: MONITOR_STATUS.id, - name: MONITOR_STATUS.name, - }, - ], - actionVariables: { - context: [ +export const getMonitorSummary = (monitorInfo: Ping) => { + return { + monitorUrl: monitorInfo.url?.full, + monitorId: monitorInfo.monitor?.id, + monitorName: monitorInfo.monitor?.name ?? monitorInfo.monitor?.id, + monitorType: monitorInfo.monitor?.type, + latestErrorMessage: monitorInfo.error?.message, + observerLocation: monitorInfo.observer?.geo?.name ?? UNNAMED_LOCATION, + observerHostname: monitorInfo.agent?.name, + }; +}; + +const generateMessageForOlderVersions = (fields: Record) => { + const messageTemplate = MonitorStatusTranslations.defaultActionMessage; + + // Monitor {{state.monitorName}} with url {{{state.monitorUrl}}} is {{state.statusMessage}} from + // {{state.observerLocation}}. The latest error message is {{{state.latestErrorMessage}}} + + return Mustache.render(messageTemplate, { state: { ...fields } }); +}; + +export const getStatusMessage = ( + downMonInfo?: Ping, + availMonInfo?: GetMonitorAvailabilityResult, + availability?: GetMonitorAvailabilityParams +) => { + let statusMessage = ''; + if (downMonInfo) { + statusMessage = DOWN_LABEL; + } + let availabilityMessage = ''; + + if (availMonInfo) { + availabilityMessage = i18n.translate( + 'xpack.uptime.alerts.monitorStatus.actionVariables.availabilityMessage', { - name: 'message', - description: i18n.translate( - 'xpack.uptime.alerts.monitorStatus.actionVariables.context.message.description', - { - defaultMessage: 'A generated message summarizing the currently down monitors', - } - ), - }, + defaultMessage: + 'below threshold with {availabilityRatio}% availability expected is {expectedAvailability}%', + values: { + availabilityRatio: (availMonInfo.availabilityRatio! * 100).toFixed(2), + expectedAvailability: availability?.threshold, + }, + } + ); + } + if (availMonInfo && downMonInfo) { + return i18n.translate( + 'xpack.uptime.alerts.monitorStatus.actionVariables.downAndAvailabilityMessage', { - name: 'downMonitorsWithGeo', - description: i18n.translate( - 'xpack.uptime.alerts.monitorStatus.actionVariables.context.downMonitorsWithGeo.description', - { - defaultMessage: - 'A generated summary that shows some or all of the monitors detected as "down" by the alert', - } + defaultMessage: '{statusMessage} and also {availabilityMessage}', + values: { + statusMessage, + availabilityMessage, + }, + } + ); + } + return statusMessage + availabilityMessage; +}; + +export const statusCheckAlertFactory: UptimeAlertTypeFactory = (_server, libs) => + uptimeAlertWrapper({ + id: 'xpack.uptime.alerts.monitorStatus', + name: i18n.translate('xpack.uptime.alerts.monitorStatus', { + defaultMessage: 'Uptime monitor status', + }), + validate: { + params: schema.object({ + availability: schema.maybe( + schema.object({ + range: schema.number(), + rangeUnit: schema.string(), + threshold: schema.string(), + }) + ), + filters: schema.maybe( + schema.oneOf([ + // deprecated + schema.object({ + 'monitor.type': schema.maybe(schema.arrayOf(schema.string())), + 'observer.geo.name': schema.maybe(schema.arrayOf(schema.string())), + tags: schema.maybe(schema.arrayOf(schema.string())), + 'url.port': schema.maybe(schema.arrayOf(schema.string())), + }), + schema.string(), + ]) + ), + // deprecated + locations: schema.maybe(schema.arrayOf(schema.string())), + numTimes: schema.number(), + search: schema.maybe(schema.string()), + shouldCheckStatus: schema.boolean(), + shouldCheckAvailability: schema.boolean(), + timerangeCount: schema.maybe(schema.number()), + timerangeUnit: schema.maybe(schema.string()), + // deprecated + timerange: schema.maybe( + schema.object({ + from: schema.string(), + to: schema.string(), + }) ), + version: schema.maybe(schema.number()), + }), + }, + defaultActionGroupId: MONITOR_STATUS.id, + actionGroups: [ + { + id: MONITOR_STATUS.id, + name: MONITOR_STATUS.name, }, ], - state: [...commonStateTranslations], - }, - producer: 'uptime', - async executor(options: AlertExecutorOptions) { - const { params: rawParams } = options; - const dynamicSettings = await savedObjectsAdapter.getUptimeDynamicSettings( - options.services.savedObjectsClient - ); - const atomicDecoded = AtomicStatusCheckParamsType.decode(rawParams); - const availabilityDecoded = MonitorAvailabilityType.decode(rawParams); - const decoded = StatusCheckParamsType.decode(rawParams); - let filterString: string = ''; - let params: StatusCheckParams; - if (isRight(atomicDecoded)) { - const { filters, search, numTimes, timerangeCount, timerangeUnit } = atomicDecoded.right; - const timerange = { from: `now-${String(timerangeCount) + timerangeUnit}`, to: 'now' }; - filterString = await formatFilterString(libs, dynamicSettings, options, filters, search); - params = { - timerange, + actionVariables: { + context: [ + { + name: 'message', + description: i18n.translate( + 'xpack.uptime.alerts.monitorStatus.actionVariables.context.message.description', + { + defaultMessage: 'A generated message summarizing the currently down monitors', + } + ), + }, + { + name: 'downMonitorsWithGeo', + description: i18n.translate( + 'xpack.uptime.alerts.monitorStatus.actionVariables.context.downMonitorsWithGeo.description', + { + defaultMessage: + 'A generated summary that shows some or all of the monitors detected as "down" by the alert', + } + ), + }, + ], + state: [...commonMonitorStateI18, ...commonStateTranslations], + }, + async executor( + { params: rawParams, state, services: { alertInstanceFactory } }, + callES, + dynamicSettings + ) { + const { + filters, + search, numTimes, - locations: [], - filters: filterString, - }; - } else if (isRight(decoded)) { - params = decoded.right; - } else if (!isRight(availabilityDecoded)) { - ThrowReporter.report(decoded); - return { - error: 'Alert param types do not conform to required shape.', + timerangeCount, + timerangeUnit, + availability, + shouldCheckAvailability, + shouldCheckStatus, + timerange: oldVersionTimeRange, + } = rawParams; + + const timerange = oldVersionTimeRange || { + from: `now-${String(timerangeCount) + timerangeUnit}`, + to: 'now', }; - } - let availabilityResults: GetMonitorAvailabilityResult[] = []; - if ( - isRight(availabilityDecoded) && - availabilityDecoded.right.shouldCheckAvailability === true - ) { - const { filters, search } = availabilityDecoded.right; - if (filterString === '' && (filters || search)) { - filterString = await formatFilterString(libs, dynamicSettings, options, filters, search); + const filterString = await formatFilterString(libs, dynamicSettings, callES, filters, search); + + let availabilityResults: GetMonitorAvailabilityResult[] = []; + if (shouldCheckAvailability) { + availabilityResults = await libs.requests.getMonitorAvailability({ + callES, + dynamicSettings, + ...availability, + filters: JSON.stringify(filterString) || undefined, + }); } - availabilityResults = await libs.requests.getMonitorAvailability({ - callES: options.services.callCluster, - dynamicSettings, - ...availabilityDecoded.right.availability, - filters: filterString || undefined, - }); - } + let downMonitorsByLocation: GetMonitorStatusResult[] = []; - /* This is called `monitorsByLocation` but it's really - * monitors by location by status. The query we run to generate this - * filters on the status field, so effectively there should be one and only one - * status represented in the result set. */ - let monitorsByLocation: GetMonitorStatusResult[] = []; - - // old alert versions are missing this field so it must default to true - const verifiedParams = StatusCheckParamsType.decode(params!); - if (isRight(verifiedParams) && (verifiedParams.right?.shouldCheckStatus ?? true)) { - monitorsByLocation = await libs.requests.getMonitorStatus({ - callES: options.services.callCluster, - dynamicSettings, - ...verifiedParams.right, - }); - } + // if oldVersionTimeRange present means it's 7.7 format and + // after that shouldCheckStatus should be explicitly false + if (!(!oldVersionTimeRange && shouldCheckStatus === false)) { + downMonitorsByLocation = await libs.requests.getMonitorStatus({ + callES, + dynamicSettings, + timerange, + numTimes, + locations: [], + filters: filterString, + }); + } - // if no monitors are down for our query, we don't need to trigger an alert - if (monitorsByLocation.length || availabilityResults.length) { - const uniqueIds = uniqueMonitorIds(monitorsByLocation); - const alertInstance = options.services.alertInstanceFactory(MONITOR_STATUS.id); - alertInstance.replaceState({ - ...options.state, - monitors: monitorsByLocation, - ...updateState(options.state, true), - }); - alertInstance.scheduleActions(MONITOR_STATUS.id, { - message: contextMessage( - Array.from(uniqueIds.keys()), - DEFAULT_MAX_MESSAGE_ROWS, - availabilityResults, - isRight(availabilityDecoded) ? availabilityDecoded.right.availability.threshold : '100', - isRight(availabilityDecoded) && availabilityDecoded.right.shouldCheckAvailability, - rawParams?.shouldCheckStatus ?? false - ), - downMonitorsWithGeo: fullListByIdAndLocation(monitorsByLocation), + const mergedIdsByLoc = getUniqueIdsByLoc(downMonitorsByLocation, availabilityResults); + + mergedIdsByLoc.forEach((monIdByLoc) => { + const alertInstance = alertInstanceFactory(MONITOR_STATUS.id + monIdByLoc); + + const availMonInfo = availabilityResults.find( + ({ monitorId, location }) => monitorId + location === monIdByLoc + ); + + const downMonInfo = downMonitorsByLocation.find( + ({ monitorId, location }) => monitorId + location === monIdByLoc + )?.monitorInfo; + + const monitorSummary = getMonitorSummary(downMonInfo || availMonInfo?.monitorInfo!); + const statusMessage = getStatusMessage(downMonInfo!, availMonInfo!, availability); + + alertInstance.replaceState({ + ...updateState(state, true), + ...monitorSummary, + statusMessage, + }); + + alertInstance.scheduleActions(MONITOR_STATUS.id, { + message: generateMessageForOlderVersions({ ...monitorSummary, statusMessage }), + }); }); - } - return updateState(options.state, monitorsByLocation.length > 0); - }, -}); + return updateState(state, downMonitorsByLocation.length > 0); + }, + }); diff --git a/x-pack/plugins/uptime/server/lib/alerts/translations.ts b/x-pack/plugins/uptime/server/lib/alerts/translations.ts index 50eedcd4fa69e..8e5c0e76ad589 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/translations.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/translations.ts @@ -6,6 +6,79 @@ import { i18n } from '@kbn/i18n'; +export const commonMonitorStateI18 = [ + { + name: 'monitorName', + description: i18n.translate('xpack.uptime.alerts.monitorStatus.actionVariables.state.monitor', { + defaultMessage: 'A human friendly rendering of name or ID, preferring name (e.g. My Monitor)', + }), + }, + { + name: 'monitorId', + description: i18n.translate( + 'xpack.uptime.alerts.monitorStatus.actionVariables.state.monitorId', + { + defaultMessage: 'ID of the monitor.', + } + ), + }, + { + name: 'monitorUrl', + description: i18n.translate( + 'xpack.uptime.alerts.monitorStatus.actionVariables.state.monitorUrl', + { + defaultMessage: 'URL of the monitor.', + } + ), + }, + { + name: 'monitorType', + description: i18n.translate( + 'xpack.uptime.alerts.monitorStatus.actionVariables.state.monitorType', + { + defaultMessage: 'Type (e.g. HTTP/TCP) of the monitor.', + } + ), + }, + { + name: 'statusMessage', + description: i18n.translate( + 'xpack.uptime.alerts.monitorStatus.actionVariables.state.statusMessage', + { + defaultMessage: + 'Status message e.g down or is below availability threshold in case of availability check or both.', + } + ), + }, + { + name: 'latestErrorMessage', + description: i18n.translate( + 'xpack.uptime.alerts.monitorStatus.actionVariables.state.lastErrorMessage', + { + defaultMessage: 'Monitor latest error message', + } + ), + }, + { + name: 'observerLocation', + description: i18n.translate( + 'xpack.uptime.alerts.monitorStatus.actionVariables.state.observerLocation', + { + defaultMessage: 'Observer location from which heartbeat check is performed.', + } + ), + }, + { + name: 'observerHostname', + description: i18n.translate( + 'xpack.uptime.alerts.monitorStatus.actionVariables.state.observerHostname', + { + defaultMessage: 'Observer hostname from which heartbeat check is performed.', + } + ), + }, +]; + export const commonStateTranslations = [ { name: 'firstCheckedAt', @@ -238,3 +311,7 @@ export const durationAnomalyTranslations = { }, ], }; + +export const DOWN_LABEL = i18n.translate('xpack.uptime.alerts.monitorStatus.actionVariables.down', { + defaultMessage: 'down', +}); diff --git a/x-pack/plugins/uptime/server/lib/alerts/types.ts b/x-pack/plugins/uptime/server/lib/alerts/types.ts index 172930bc3dd3b..0a80b36046860 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/types.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/types.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { AlertType } from '../../../../alerts/server'; import { UptimeCorePlugins, UptimeCoreSetup } from '../adapters'; import { UMServerLibs } from '../lib'; +import { AlertType } from '../../../../alerts/server'; export type UptimeAlertTypeFactory = ( server: UptimeCoreSetup, diff --git a/x-pack/plugins/uptime/server/lib/alerts/uptime_alert_wrapper.ts b/x-pack/plugins/uptime/server/lib/alerts/uptime_alert_wrapper.ts new file mode 100644 index 0000000000000..5963b371f844f --- /dev/null +++ b/x-pack/plugins/uptime/server/lib/alerts/uptime_alert_wrapper.ts @@ -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 { ILegacyScopedClusterClient } from 'kibana/server'; +import { AlertExecutorOptions, AlertType, State } from '../../../../alerts/server'; +import { savedObjectsAdapter } from '../saved_objects'; +import { DynamicSettings } from '../../../common/runtime_types'; + +export interface UptimeAlertType extends Omit { + executor: ( + options: AlertExecutorOptions, + callES: ILegacyScopedClusterClient['callAsCurrentUser'], + dynamicSettings: DynamicSettings + ) => Promise; +} + +export const uptimeAlertWrapper = (uptimeAlert: UptimeAlertType) => ({ + ...uptimeAlert, + producer: 'uptime', + executor: async (options: AlertExecutorOptions) => { + const { + services: { callCluster: callES }, + } = options; + + const dynamicSettings = await savedObjectsAdapter.getUptimeDynamicSettings( + options.services.savedObjectsClient + ); + + return uptimeAlert.executor(options, callES, dynamicSettings); + }, +}); diff --git a/x-pack/plugins/uptime/server/lib/compose/kibana.ts b/x-pack/plugins/uptime/server/lib/compose/kibana.ts index edda5cb283323..783a77b9e5377 100644 --- a/x-pack/plugins/uptime/server/lib/compose/kibana.ts +++ b/x-pack/plugins/uptime/server/lib/compose/kibana.ts @@ -5,23 +5,17 @@ */ import { UMKibanaBackendFrameworkAdapter } from '../adapters/framework'; -import * as requests from '../requests'; +import { requests } from '../requests'; import { licenseCheck } from '../domains'; -import { UMDomainLibs, UMServerLibs } from '../lib'; +import { UMServerLibs } from '../lib'; import { UptimeCoreSetup } from '../adapters/framework'; export function compose(server: UptimeCoreSetup): UMServerLibs { const framework = new UMKibanaBackendFrameworkAdapter(server); - const domainLibs: UMDomainLibs = { - requests: { - ...requests, - }, - license: licenseCheck, - }; - return { framework, - ...domainLibs, + requests, + license: licenseCheck, }; } diff --git a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_availability.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_availability.test.ts index e014aa985a82d..f0222de02697d 100644 --- a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_availability.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_availability.test.ts @@ -12,16 +12,9 @@ import { } from '../get_monitor_availability'; import { setupMockEsCompositeQuery } from './helper'; import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../common/constants'; -import { GetMonitorAvailabilityParams } from '../../../../common/runtime_types'; +import { GetMonitorAvailabilityParams, makePing, Ping } from '../../../../common/runtime_types'; interface AvailabilityTopHit { - _source: { - monitor: { - name: string; - }; - url: { - full: string; - }; - }; + _source: Ping; } interface AvailabilityDoc { @@ -46,11 +39,10 @@ interface AvailabilityDoc { const genBucketItem = ({ monitorId, location, - name, - url, up, down, availabilityRatio, + monitorInfo, }: GetMonitorAvailabilityResult): AvailabilityDoc => ({ key: { monitorId, @@ -61,14 +53,7 @@ const genBucketItem = ({ hits: { hits: [ { - _source: { - monitor: { - name, - }, - url: { - full: url, - }, - }, + _source: monitorInfo, }, ], }, @@ -148,10 +133,6 @@ describe('monitor availability', () => { }, "fields": Object { "top_hits": Object { - "_source": Array [ - "monitor.name", - "url.full", - ], "size": 1, "sort": Array [ Object { @@ -271,29 +252,26 @@ describe('monitor availability', () => { { monitorId: 'foo', location: 'harrisburg', - name: 'Foo', - url: 'http://foo.com', up: 456, down: 234, availabilityRatio: 0.660869565217391, + monitorInfo: makePing({}), }, { monitorId: 'foo', location: 'faribanks', - name: 'Foo', - url: 'http://foo.com', up: 450, down: 240, availabilityRatio: 0.652173913043478, + monitorInfo: makePing({}), }, { monitorId: 'bar', location: 'fairbanks', - name: 'Bar', - url: 'http://bar.com', up: 468, down: 212, availabilityRatio: 0.688235294117647, + monitorInfo: makePing({}), }, ], }, @@ -327,10 +305,6 @@ describe('monitor availability', () => { }, "fields": Object { "top_hits": Object { - "_source": Array [ - "monitor.name", - "url.full", - ], "size": 1, "sort": Array [ Object { @@ -417,27 +391,63 @@ describe('monitor availability', () => { "down": 234, "location": "harrisburg", "monitorId": "foo", - "name": "Foo", + "monitorInfo": Object { + "docId": "myDocId", + "monitor": Object { + "duration": Object { + "us": 100000, + }, + "id": "myId", + "ip": "127.0.0.1", + "name": undefined, + "status": "up", + "type": "myType", + }, + "timestamp": "2020-07-07T01:14:08Z", + }, "up": 456, - "url": "http://foo.com", }, Object { "availabilityRatio": 0.652173913043478, "down": 240, "location": "faribanks", "monitorId": "foo", - "name": "Foo", + "monitorInfo": Object { + "docId": "myDocId", + "monitor": Object { + "duration": Object { + "us": 100000, + }, + "id": "myId", + "ip": "127.0.0.1", + "name": undefined, + "status": "up", + "type": "myType", + }, + "timestamp": "2020-07-07T01:14:08Z", + }, "up": 450, - "url": "http://foo.com", }, Object { "availabilityRatio": 0.688235294117647, "down": 212, "location": "fairbanks", "monitorId": "bar", - "name": "Bar", + "monitorInfo": Object { + "docId": "myDocId", + "monitor": Object { + "duration": Object { + "us": 100000, + }, + "id": "myId", + "ip": "127.0.0.1", + "name": undefined, + "status": "up", + "type": "myType", + }, + "timestamp": "2020-07-07T01:14:08Z", + }, "up": 468, - "url": "http://bar.com", }, ] `); @@ -459,20 +469,18 @@ describe('monitor availability', () => { { monitorId: 'foo', location: 'harrisburg', - name: 'Foo', - url: 'http://foo.com', up: 243, down: 11, availabilityRatio: 0.956692913385827, + monitorInfo: makePing({}), }, { monitorId: 'foo', location: 'fairbanks', - name: 'Foo', - url: 'http://foo.com', up: 251, down: 13, availabilityRatio: 0.950757575757576, + monitorInfo: makePing({}), }, ], }, @@ -481,20 +489,18 @@ describe('monitor availability', () => { { monitorId: 'baz', location: 'harrisburg', - name: 'Baz', - url: 'http://baz.com', up: 341, down: 3, availabilityRatio: 0.991279069767442, + monitorInfo: makePing({}), }, { monitorId: 'baz', location: 'fairbanks', - name: 'Baz', - url: 'http://baz.com', up: 365, down: 5, availabilityRatio: 0.986486486486486, + monitorInfo: makePing({}), }, ], }, @@ -515,36 +521,84 @@ describe('monitor availability', () => { "down": 11, "location": "harrisburg", "monitorId": "foo", - "name": "Foo", + "monitorInfo": Object { + "docId": "myDocId", + "monitor": Object { + "duration": Object { + "us": 100000, + }, + "id": "myId", + "ip": "127.0.0.1", + "name": undefined, + "status": "up", + "type": "myType", + }, + "timestamp": "2020-07-07T01:14:08Z", + }, "up": 243, - "url": "http://foo.com", }, Object { "availabilityRatio": 0.950757575757576, "down": 13, "location": "fairbanks", "monitorId": "foo", - "name": "Foo", + "monitorInfo": Object { + "docId": "myDocId", + "monitor": Object { + "duration": Object { + "us": 100000, + }, + "id": "myId", + "ip": "127.0.0.1", + "name": undefined, + "status": "up", + "type": "myType", + }, + "timestamp": "2020-07-07T01:14:08Z", + }, "up": 251, - "url": "http://foo.com", }, Object { "availabilityRatio": 0.991279069767442, "down": 3, "location": "harrisburg", "monitorId": "baz", - "name": "Baz", + "monitorInfo": Object { + "docId": "myDocId", + "monitor": Object { + "duration": Object { + "us": 100000, + }, + "id": "myId", + "ip": "127.0.0.1", + "name": undefined, + "status": "up", + "type": "myType", + }, + "timestamp": "2020-07-07T01:14:08Z", + }, "up": 341, - "url": "http://baz.com", }, Object { "availabilityRatio": 0.986486486486486, "down": 5, "location": "fairbanks", "monitorId": "baz", - "name": "Baz", + "monitorInfo": Object { + "docId": "myDocId", + "monitor": Object { + "duration": Object { + "us": 100000, + }, + "id": "myId", + "ip": "127.0.0.1", + "name": undefined, + "status": "up", + "type": "myType", + }, + "timestamp": "2020-07-07T01:14:08Z", + }, "up": 365, - "url": "http://baz.com", }, ] `); @@ -565,10 +619,6 @@ describe('monitor availability', () => { }, "fields": Object { "top_hits": Object { - "_source": Array [ - "monitor.name", - "url.full", - ], "size": 1, "sort": Array [ Object { @@ -663,10 +713,6 @@ describe('monitor availability', () => { }, "fields": Object { "top_hits": Object { - "_source": Array [ - "monitor.name", - "url.full", - ], "size": 1, "sort": Array [ Object { @@ -833,18 +879,30 @@ describe('monitor availability', () => { "down": 2450, "location": "fairbanks", "monitorId": "test-node-service", - "name": "Test Node Service", + "monitorInfo": Object { + "monitor": Object { + "name": "Test Node Service", + }, + "url": Object { + "full": "http://localhost:12349", + }, + }, "up": 821, - "url": "http://localhost:12349", }, Object { "availabilityRatio": 0.5804076040417879, "down": 2450, "location": "harrisburg", "monitorId": "test-node-service", - "name": "Test Node Service", + "monitorInfo": Object { + "monitor": Object { + "name": "Test Node Service", + }, + "url": Object { + "full": "http://localhost:12349", + }, + }, "up": 3389, - "url": "http://localhost:12349", }, ] `); diff --git a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_status.test.ts b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_status.test.ts index f12f1527fb56c..7dba71a8126e2 100644 --- a/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_status.test.ts +++ b/x-pack/plugins/uptime/server/lib/requests/__tests__/get_monitor_status.test.ts @@ -9,14 +9,14 @@ import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../common/constants'; import { setupMockEsCompositeQuery } from './helper'; export interface BucketItemCriteria { - monitor_id: string; + monitorId: string; status: string; location: string; doc_count: number; } interface BucketKey { - monitor_id: string; + monitorId: string; status: string; location: string; } @@ -27,19 +27,17 @@ interface BucketItem { } const genBucketItem = ({ - // eslint-disable-next-line @typescript-eslint/naming-convention - monitor_id, + monitorId, status, location, - // eslint-disable-next-line @typescript-eslint/naming-convention - doc_count, + doc_count: count, }: BucketItemCriteria): BucketItem => ({ key: { - monitor_id, + monitorId, status, location, }, - doc_count, + doc_count: count, }); describe('getMonitorStatus', () => { @@ -48,37 +46,37 @@ describe('getMonitorStatus', () => { [], genBucketItem ); - const exampleFilter = `{ - "bool": { - "should": [ + const exampleFilter = { + bool: { + should: [ { - "bool": { - "should": [ + bool: { + should: [ { - "match_phrase": { - "monitor.id": "apm-dev" - } - } + match_phrase: { + 'monitor.id': 'apm-dev', + }, + }, ], - "minimum_should_match": 1 - } + minimum_should_match: 1, + }, }, { - "bool": { - "should": [ + bool: { + should: [ { - "match_phrase": { - "monitor.id": "auto-http-0X8D6082B94BBE3B8A" - } - } + match_phrase: { + 'monitor.id': 'auto-http-0X8D6082B94BBE3B8A', + }, + }, ], - "minimum_should_match": 1 - } - } + minimum_should_match: 1, + }, + }, ], - "minimum_should_match": 1 - } - }`; + minimum_should_match: 1, + }, + }; await getMonitorStatus({ callES, dynamicSettings: DYNAMIC_SETTINGS_DEFAULTS, @@ -98,11 +96,18 @@ describe('getMonitorStatus', () => { "body": Object { "aggs": Object { "monitors": Object { + "aggs": Object { + "fields": Object { + "top_hits": Object { + "size": 1, + }, + }, + }, "composite": Object { "size": 2000, "sources": Array [ Object { - "monitor_id": Object { + "monitorId": Object { "terms": Object { "field": "monitor.id", }, @@ -203,11 +208,18 @@ describe('getMonitorStatus', () => { "body": Object { "aggs": Object { "monitors": Object { + "aggs": Object { + "fields": Object { + "top_hits": Object { + "size": 1, + }, + }, + }, "composite": Object { "size": 2000, "sources": Array [ Object { - "monitor_id": Object { + "monitorId": Object { "terms": Object { "field": "monitor.id", }, @@ -280,19 +292,19 @@ describe('getMonitorStatus', () => { { bucketCriteria: [ { - monitor_id: 'foo', + monitorId: 'foo', status: 'down', location: 'fairbanks', doc_count: 43, }, { - monitor_id: 'bar', + monitorId: 'bar', status: 'down', location: 'harrisburg', doc_count: 53, }, { - monitor_id: 'foo', + monitorId: 'foo', status: 'down', location: 'harrisburg', doc_count: 44, @@ -324,11 +336,18 @@ describe('getMonitorStatus', () => { "body": Object { "aggs": Object { "monitors": Object { + "aggs": Object { + "fields": Object { + "top_hits": Object { + "size": 1, + }, + }, + }, "composite": Object { "size": 2000, "sources": Array [ Object { - "monitor_id": Object { + "monitorId": Object { "terms": Object { "field": "monitor.id", }, @@ -377,25 +396,29 @@ describe('getMonitorStatus', () => { "index": "heartbeat-8*", } `); + expect(result.length).toBe(3); expect(result).toMatchInlineSnapshot(` Array [ Object { "count": 43, "location": "fairbanks", - "monitor_id": "foo", + "monitorId": "foo", + "monitorInfo": undefined, "status": "down", }, Object { "count": 53, "location": "harrisburg", - "monitor_id": "bar", + "monitorId": "bar", + "monitorInfo": undefined, "status": "down", }, Object { "count": 44, "location": "harrisburg", - "monitor_id": "foo", + "monitorId": "foo", + "monitorInfo": undefined, "status": "down", }, ] @@ -406,25 +429,25 @@ describe('getMonitorStatus', () => { const criteria = [ { after_key: { - monitor_id: 'foo', + monitorId: 'foo', location: 'harrisburg', status: 'down', }, bucketCriteria: [ { - monitor_id: 'foo', + monitorId: 'foo', status: 'down', location: 'fairbanks', doc_count: 43, }, { - monitor_id: 'bar', + monitorId: 'bar', status: 'down', location: 'harrisburg', doc_count: 53, }, { - monitor_id: 'foo', + monitorId: 'foo', status: 'down', location: 'harrisburg', doc_count: 44, @@ -433,25 +456,25 @@ describe('getMonitorStatus', () => { }, { after_key: { - monitor_id: 'bar', + monitorId: 'bar', status: 'down', location: 'fairbanks', }, bucketCriteria: [ { - monitor_id: 'sna', + monitorId: 'sna', status: 'down', location: 'fairbanks', doc_count: 21, }, { - monitor_id: 'fu', + monitorId: 'fu', status: 'down', location: 'fairbanks', doc_count: 21, }, { - monitor_id: 'bar', + monitorId: 'bar', status: 'down', location: 'fairbanks', doc_count: 45, @@ -461,13 +484,13 @@ describe('getMonitorStatus', () => { { bucketCriteria: [ { - monitor_id: 'sna', + monitorId: 'sna', status: 'down', location: 'harrisburg', doc_count: 21, }, { - monitor_id: 'fu', + monitorId: 'fu', status: 'down', location: 'harrisburg', doc_count: 21, @@ -489,54 +512,63 @@ describe('getMonitorStatus', () => { to: 'now-1m', }, }); + expect(result.length).toBe(8); expect(result).toMatchInlineSnapshot(` Array [ Object { "count": 43, "location": "fairbanks", - "monitor_id": "foo", + "monitorId": "foo", + "monitorInfo": undefined, "status": "down", }, Object { "count": 53, "location": "harrisburg", - "monitor_id": "bar", + "monitorId": "bar", + "monitorInfo": undefined, "status": "down", }, Object { "count": 44, "location": "harrisburg", - "monitor_id": "foo", + "monitorId": "foo", + "monitorInfo": undefined, "status": "down", }, Object { "count": 21, "location": "fairbanks", - "monitor_id": "sna", + "monitorId": "sna", + "monitorInfo": undefined, "status": "down", }, Object { "count": 21, "location": "fairbanks", - "monitor_id": "fu", + "monitorId": "fu", + "monitorInfo": undefined, "status": "down", }, Object { "count": 45, "location": "fairbanks", - "monitor_id": "bar", + "monitorId": "bar", + "monitorInfo": undefined, "status": "down", }, Object { "count": 21, "location": "harrisburg", - "monitor_id": "sna", + "monitorId": "sna", + "monitorInfo": undefined, "status": "down", }, Object { "count": 21, "location": "harrisburg", - "monitor_id": "fu", + "monitorId": "fu", + "monitorInfo": undefined, "status": "down", }, ] diff --git a/x-pack/plugins/uptime/server/lib/requests/get_monitor_availability.ts b/x-pack/plugins/uptime/server/lib/requests/get_monitor_availability.ts index 798cefc404e1f..0801fc5769363 100644 --- a/x-pack/plugins/uptime/server/lib/requests/get_monitor_availability.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_monitor_availability.ts @@ -5,7 +5,7 @@ */ import { UMElasticsearchQueryFn } from '../adapters'; -import { GetMonitorAvailabilityParams } from '../../../common/runtime_types'; +import { GetMonitorAvailabilityParams, Ping } from '../../../common/runtime_types'; export interface AvailabilityKey { monitorId: string; @@ -14,20 +14,18 @@ export interface AvailabilityKey { export interface GetMonitorAvailabilityResult { monitorId: string; - location: string; - name: string; - url: string; up: number; down: number; + location: string; availabilityRatio: number | null; + monitorInfo: Ping; } export const formatBuckets = async (buckets: any[]): Promise => // eslint-disable-next-line @typescript-eslint/naming-convention buckets.map(({ key, fields, up_sum, down_sum, ratio }: any) => ({ ...key, - name: fields?.hits?.hits?.[0]?._source?.monitor.name, - url: fields?.hits?.hits?.[0]?._source?.url.full, + monitorInfo: fields?.hits?.hits?.[0]?._source, up: up_sum.value, down: down_sum.value, availabilityRatio: ratio.value, @@ -94,7 +92,6 @@ export const getMonitorAvailability: UMElasticsearchQueryFn< fields: { top_hits: { size: 1, - _source: ['monitor.name', 'url.full'], sort: [ { '@timestamp': { @@ -143,8 +140,8 @@ export const getMonitorAvailability: UMElasticsearchQueryFn< }; if (filters) { - const parsedFilters = JSON.parse(filters); - esParams.body.query.bool = { ...esParams.body.query.bool, ...parsedFilters.bool }; + const parsedFilter = JSON.parse(filters); + esParams.body.query.bool = { ...esParams.body.query.bool, ...parsedFilter.bool }; } if (afterKey) { diff --git a/x-pack/plugins/uptime/server/lib/requests/get_monitor_status.ts b/x-pack/plugins/uptime/server/lib/requests/get_monitor_status.ts index a52bbfc8f2442..0788880994200 100644 --- a/x-pack/plugins/uptime/server/lib/requests/get_monitor_status.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_monitor_status.ts @@ -4,20 +4,23 @@ * you may not use this file except in compliance with the Elastic License. */ +import { JsonObject } from 'src/plugins/kibana_utils/public'; import { UMElasticsearchQueryFn } from '../adapters'; +import { Ping } from '../../../common/runtime_types/ping'; export interface GetMonitorStatusParams { - filters?: string; + filters?: JsonObject; locations: string[]; numTimes: number; timerange: { from: string; to: string }; } export interface GetMonitorStatusResult { - monitor_id: string; + monitorId: string; status: string; location: string; count: number; + monitorInfo: Ping; } interface MonitorStatusKey { @@ -26,15 +29,6 @@ interface MonitorStatusKey { location: string; } -const formatBuckets = async ( - buckets: any[], - numTimes: number -): Promise => { - return buckets - .filter((monitor: any) => monitor?.doc_count > numTimes) - .map(({ key, doc_count: count }: any) => ({ ...key, count })); -}; - const getLocationClause = (locations: string[]) => ({ bool: { should: [ @@ -51,10 +45,10 @@ export const getMonitorStatus: UMElasticsearchQueryFn< GetMonitorStatusParams, GetMonitorStatusResult[] > = async ({ callES, dynamicSettings, filters, locations, numTimes, timerange: { from, to } }) => { - const queryResults: Array> = []; let afterKey: MonitorStatusKey | undefined; const STATUS = 'down'; + let monitors: any = []; do { // today this value is hardcoded. In the future we may support // multiple status types for this alert, and this will become a parameter @@ -87,7 +81,7 @@ export const getMonitorStatus: UMElasticsearchQueryFn< size: 2000, sources: [ { - monitor_id: { + monitorId: { terms: { field: 'monitor.id', }, @@ -110,18 +104,20 @@ export const getMonitorStatus: UMElasticsearchQueryFn< }, ], }, + aggs: { + fields: { + top_hits: { + size: 1, + }, + }, + }, }, }, }, }; - /** - * `filters` are an unparsed JSON string. We parse them and append the bool fields of the query - * to the bool of the parsed filters. - */ - if (filters) { - const parsedFilters = JSON.parse(filters); - esParams.body.query.bool = Object.assign({}, esParams.body.query.bool, parsedFilters.bool); + if (filters?.bool) { + esParams.body.query.bool = Object.assign({}, esParams.body.query.bool, filters.bool); } /** @@ -142,8 +138,14 @@ export const getMonitorStatus: UMElasticsearchQueryFn< const result = await callES('search', esParams); afterKey = result?.aggregations?.monitors?.after_key; - queryResults.push(formatBuckets(result?.aggregations?.monitors?.buckets || [], numTimes)); + monitors = monitors.concat(result?.aggregations?.monitors?.buckets || []); } while (afterKey !== undefined); - return (await Promise.all(queryResults)).reduce((acc, cur) => acc.concat(cur), []); + return monitors + .filter((monitor: any) => monitor?.doc_count > numTimes) + .map(({ key, doc_count: count, fields }: any) => ({ + ...key, + count, + monitorInfo: fields?.hits?.hits?.[0]?._source, + })); }; diff --git a/x-pack/plugins/uptime/server/lib/requests/index.ts b/x-pack/plugins/uptime/server/lib/requests/index.ts index 415b3d2f4b4a1..8fa4561268e8f 100644 --- a/x-pack/plugins/uptime/server/lib/requests/index.ts +++ b/x-pack/plugins/uptime/server/lib/requests/index.ts @@ -4,19 +4,36 @@ * you may not use this file except in compliance with the Elastic License. */ -export { getCerts } from './get_certs'; -export { getFilterBar, GetFilterBarParams } from './get_filter_bar'; -export { getUptimeIndexPattern as getIndexPattern } from './get_index_pattern'; -export { getLatestMonitor, GetLatestMonitorParams } from './get_latest_monitor'; -export { getMonitorAvailability } from './get_monitor_availability'; -export { getMonitorDurationChart, GetMonitorChartsParams } from './get_monitor_duration'; -export { getMonitorDetails, GetMonitorDetailsParams } from './get_monitor_details'; -export { getMonitorLocations, GetMonitorLocationsParams } from './get_monitor_locations'; -export { getMonitorStates, GetMonitorStatesParams } from './get_monitor_states'; -export { getMonitorStatus, GetMonitorStatusParams } from './get_monitor_status'; -export * from './get_monitor_status'; -export { getPings } from './get_pings'; -export { getPingHistogram, GetPingHistogramParams } from './get_ping_histogram'; -export { UptimeRequests } from './uptime_requests'; -export { getSnapshotCount, GetSnapshotCountParams } from './get_snapshot_counts'; -export { getIndexStatus } from './get_index_status'; +import { getCerts } from './get_certs'; +import { getFilterBar } from './get_filter_bar'; +import { getUptimeIndexPattern as getIndexPattern } from './get_index_pattern'; +import { getLatestMonitor } from './get_latest_monitor'; +import { getMonitorAvailability } from './get_monitor_availability'; +import { getMonitorDurationChart } from './get_monitor_duration'; +import { getMonitorDetails } from './get_monitor_details'; +import { getMonitorLocations } from './get_monitor_locations'; +import { getMonitorStates } from './get_monitor_states'; +import { getMonitorStatus } from './get_monitor_status'; +import { getPings } from './get_pings'; +import { getPingHistogram } from './get_ping_histogram'; +import { getSnapshotCount } from './get_snapshot_counts'; +import { getIndexStatus } from './get_index_status'; + +export const requests = { + getCerts, + getFilterBar, + getIndexPattern, + getLatestMonitor, + getMonitorAvailability, + getMonitorDurationChart, + getMonitorDetails, + getMonitorLocations, + getMonitorStates, + getMonitorStatus, + getPings, + getPingHistogram, + getSnapshotCount, + getIndexStatus, +}; + +export type UptimeRequests = typeof requests; diff --git a/x-pack/plugins/uptime/server/lib/requests/uptime_requests.ts b/x-pack/plugins/uptime/server/lib/requests/uptime_requests.ts deleted file mode 100644 index 2a9420a275570..0000000000000 --- a/x-pack/plugins/uptime/server/lib/requests/uptime_requests.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 { UMElasticsearchQueryFn } from '../adapters'; -import { - OverviewFilters, - GetMonitorAvailabilityParams, - MonitorDetails, - MonitorLocations, - Snapshot, - StatesIndexStatus, - HistogramResult, - Ping, - PingsResponse, - GetCertsParams, - GetPingsParams, - CertResult, - MonitorSummariesResult, -} from '../../../common/runtime_types'; -import { MonitorDurationResult } from '../../../common/types'; - -import { - GetFilterBarParams, - GetLatestMonitorParams, - GetMonitorChartsParams, - GetMonitorDetailsParams, - GetMonitorLocationsParams, - GetMonitorStatesParams, - GetPingHistogramParams, - GetMonitorStatusParams, - GetMonitorStatusResult, -} from '.'; -import { GetSnapshotCountParams } from './get_snapshot_counts'; -import { IIndexPattern } from '../../../../../../src/plugins/data/server'; -import { GetMonitorAvailabilityResult } from './get_monitor_availability'; - -type ESQ = UMElasticsearchQueryFn; - -export interface UptimeRequests { - getCerts: ESQ; - getFilterBar: ESQ; - getIndexPattern: ESQ<{}, IIndexPattern | undefined>; - getLatestMonitor: ESQ; - getMonitorAvailability: ESQ; - getMonitorDurationChart: ESQ; - getMonitorDetails: ESQ; - getMonitorLocations: ESQ; - getMonitorStates: ESQ; - getMonitorStatus: ESQ; - getPings: ESQ; - getPingHistogram: ESQ; - getSnapshotCount: ESQ; - getIndexStatus: ESQ<{}, StatesIndexStatus>; -} From bcf8719824bbc47e482582a13c84e12a39706e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Marcondes?= <55978943+cauemarcondes@users.noreply.github.com> Date: Fri, 14 Aug 2020 08:55:39 +0100 Subject: [PATCH 37/53] Adding API test for custom link transaction example (#74238) * Adding api test for custom link transaction example * expecting specific fields * expecting specific fields Co-authored-by: Elastic Machine --- .../basic/tests/settings/custom_link.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/x-pack/test/apm_api_integration/basic/tests/settings/custom_link.ts b/x-pack/test/apm_api_integration/basic/tests/settings/custom_link.ts index 9465708db2fba..2acc6522bf479 100644 --- a/x-pack/test/apm_api_integration/basic/tests/settings/custom_link.ts +++ b/x-pack/test/apm_api_integration/basic/tests/settings/custom_link.ts @@ -12,6 +12,7 @@ export default function customLinksTests({ getService }: FtrProviderContext) { const supertestRead = getService('supertestAsApmReadUser'); const supertestWrite = getService('supertestAsApmWriteUser'); const log = getService('log'); + const esArchiver = getService('esArchiver'); function searchCustomLinks(filters?: any) { const path = URL.format({ @@ -139,5 +140,18 @@ export default function customLinksTests({ getService }: FtrProviderContext) { expect(status).to.equal(200); expect(body).to.eql([]); }); + + describe('transaction', () => { + before(() => esArchiver.load('8.0.0')); + after(() => esArchiver.unload('8.0.0')); + + it('fetches a transaction sample', async () => { + const response = await supertestRead.get( + '/api/apm/settings/custom_links/transaction?service.name=opbeans-java' + ); + expect(response.status).to.be(200); + expect(response.body.service.name).to.eql('opbeans-java'); + }); + }); }); } From 7bd014abb387a4b6d896abf992c96f2ab98fad65 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Fri, 14 Aug 2020 12:07:04 +0200 Subject: [PATCH 38/53] [UiActions] pass trigger into action execution context (#74363) Co-authored-by: Elastic Machine --- .../public/actions/actions.tsx | 9 ++- examples/ui_actions_explorer/public/app.tsx | 6 +- .../lib/actions/apply_filter_action.test.ts | 4 + .../public/lib/panel/embeddable_panel.tsx | 7 +- .../add_panel/add_panel_action.test.tsx | 9 ++- .../add_panel/add_panel_action.ts | 10 ++- .../lib/panel/panel_header/panel_header.tsx | 19 +++-- .../test_samples/actions/say_hello_action.tsx | 4 +- .../public/tests/apply_filter_action.test.ts | 3 +- .../ui_actions/public/actions/action.test.ts | 13 +++- .../ui_actions/public/actions/action.ts | 76 +++++++++++++++---- .../build_eui_context_menu_panels.tsx | 53 ++++++++++--- src/plugins/ui_actions/public/index.ts | 7 +- .../service/ui_actions_execution_service.ts | 17 +++-- .../public/service/ui_actions_service.ts | 11 ++- .../tests/execute_trigger_actions.test.ts | 24 +++++- .../public/triggers/default_trigger.ts | 27 +++++++ .../ui_actions/public/triggers/index.ts | 1 + src/plugins/ui_actions/public/types.ts | 9 ++- .../dashboard_to_url_drilldown/index.tsx | 11 ++- .../panel_actions/get_csv_panel_action.tsx | 7 +- .../public/custom_time_range_action.tsx | 7 +- .../public/drilldowns/drilldown_definition.ts | 11 ++- 23 files changed, 277 insertions(+), 68 deletions(-) create mode 100644 src/plugins/ui_actions/public/triggers/default_trigger.ts diff --git a/examples/ui_actions_explorer/public/actions/actions.tsx b/examples/ui_actions_explorer/public/actions/actions.tsx index 6d83362e998bc..777bcd9c18119 100644 --- a/examples/ui_actions_explorer/public/actions/actions.tsx +++ b/examples/ui_actions_explorer/public/actions/actions.tsx @@ -21,7 +21,11 @@ import { OverlayStart } from 'kibana/public'; import { EuiFieldText, EuiModalBody, EuiButton } from '@elastic/eui'; import { useState } from 'react'; import { toMountPoint } from '../../../../src/plugins/kibana_react/public'; -import { createAction, UiActionsStart } from '../../../../src/plugins/ui_actions/public'; +import { + ActionExecutionContext, + createAction, + UiActionsStart, +} from '../../../../src/plugins/ui_actions/public'; export const USER_TRIGGER = 'USER_TRIGGER'; export const COUNTRY_TRIGGER = 'COUNTRY_TRIGGER'; @@ -37,7 +41,8 @@ export const ACTION_SHOWCASE_PLUGGABILITY = 'ACTION_SHOWCASE_PLUGGABILITY'; export const showcasePluggability = createAction({ type: ACTION_SHOWCASE_PLUGGABILITY, getDisplayName: () => 'This is pluggable! Any plugin can inject their actions here.', - execute: async () => alert("Isn't that cool?!"), + execute: async (context: ActionExecutionContext) => + alert(`Isn't that cool?! Triggered by ${context.trigger?.id} trigger`), }); export interface PhoneContext { diff --git a/examples/ui_actions_explorer/public/app.tsx b/examples/ui_actions_explorer/public/app.tsx index 1b0667962a3c2..d59309f006838 100644 --- a/examples/ui_actions_explorer/public/app.tsx +++ b/examples/ui_actions_explorer/public/app.tsx @@ -97,9 +97,9 @@ const ActionsExplorer = ({ uiActionsApi, openModal }: Props) => { }); uiActionsApi.addTriggerAction(HELLO_WORLD_TRIGGER_ID, dynamicAction); setConfirmationText( - `You've successfully added a new action: ${dynamicAction.getDisplayName( - {} - )}. Refresh the page to reset state. It's up to the user of the system to persist state like this.` + `You've successfully added a new action: ${dynamicAction.getDisplayName({ + trigger: uiActionsApi.getTrigger(HELLO_WORLD_TRIGGER_ID), + })}. Refresh the page to reset state. It's up to the user of the system to persist state like this.` ); }} > diff --git a/src/plugins/embeddable/public/lib/actions/apply_filter_action.test.ts b/src/plugins/embeddable/public/lib/actions/apply_filter_action.test.ts index 636ce3e623c5b..88c1a5917e609 100644 --- a/src/plugins/embeddable/public/lib/actions/apply_filter_action.test.ts +++ b/src/plugins/embeddable/public/lib/actions/apply_filter_action.test.ts @@ -19,6 +19,7 @@ import { createFilterAction } from './apply_filter_action'; import { expectErrorAsync } from '../../tests/helpers'; +import { defaultTrigger } from '../../../../ui_actions/public/triggers'; test('has ACTION_APPLY_FILTER type and id', () => { const action = createFilterAction(); @@ -51,6 +52,7 @@ describe('isCompatible()', () => { }), } as any, filters: [], + trigger: defaultTrigger, }); expect(result).toBe(true); }); @@ -66,6 +68,7 @@ describe('isCompatible()', () => { }), } as any, filters: [], + trigger: defaultTrigger, }); expect(result).toBe(false); }); @@ -119,6 +122,7 @@ describe('execute()', () => { await action.execute({ embeddable, filters: ['FILTER' as any], + trigger: defaultTrigger, }); expect(root.updateInput).toHaveBeenCalledTimes(1); diff --git a/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx b/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx index cb02ffc470e95..d8659680dceb9 100644 --- a/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx +++ b/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx @@ -30,6 +30,7 @@ import { PANEL_BADGE_TRIGGER, PANEL_NOTIFICATION_TRIGGER, EmbeddableContext, + contextMenuTrigger, } from '../triggers'; import { IEmbeddable, EmbeddableOutput, EmbeddableError } from '../embeddables/i_embeddable'; import { ViewMode } from '../types'; @@ -311,7 +312,11 @@ export class EmbeddablePanel extends React.Component { const sortedActions = [...regularActions, ...extraActions].sort(sortByOrderField); return await buildContextMenuForActions({ - actions: sortedActions.map((action) => [action, { embeddable: this.props.embeddable }]), + actions: sortedActions.map((action) => ({ + action, + context: { embeddable: this.props.embeddable }, + trigger: contextMenuTrigger, + })), closeMenu: this.closeMyContextMenuPanel, }); }; diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.test.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.test.tsx index d8def3147e52c..0361939fd07e6 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.test.tsx +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.test.tsx @@ -31,6 +31,7 @@ import { ContactCardEmbeddable } from '../../../../test_samples'; import { esFilters, Filter } from '../../../../../../../../plugins/data/public'; import { EmbeddableStart } from '../../../../../plugin'; import { embeddablePluginMock } from '../../../../../mocks'; +import { defaultTrigger } from '../../../../../../../ui_actions/public/triggers'; const { setup, doStart } = embeddablePluginMock.createInstance(); setup.registerEmbeddableFactory(FILTERABLE_EMBEDDABLE, new FilterableEmbeddableFactory()); @@ -85,7 +86,9 @@ test('Is not compatible when container is in view mode', async () => { () => null ); container.updateInput({ viewMode: ViewMode.VIEW }); - expect(await addPanelAction.isCompatible({ embeddable: container })).toBe(false); + expect( + await addPanelAction.isCompatible({ embeddable: container, trigger: defaultTrigger }) + ).toBe(false); }); test('Is not compatible when embeddable is not a container', async () => { @@ -94,7 +97,7 @@ test('Is not compatible when embeddable is not a container', async () => { test('Is compatible when embeddable is a parent and in edit mode', async () => { container.updateInput({ viewMode: ViewMode.EDIT }); - expect(await action.isCompatible({ embeddable: container })).toBe(true); + expect(await action.isCompatible({ embeddable: container, trigger: defaultTrigger })).toBe(true); }); test('Execute throws an error when called with an embeddable that is not a container', async () => { @@ -108,6 +111,7 @@ test('Execute throws an error when called with an embeddable that is not a conta }, {} as any ), + trigger: defaultTrigger, } as any); } await expect(check()).rejects.toThrow(Error); @@ -116,6 +120,7 @@ test('Execute does not throw an error when called with a compatible container', container.updateInput({ viewMode: ViewMode.EDIT }); await action.execute({ embeddable: container, + trigger: defaultTrigger, }); }); diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.ts b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.ts index f3a483bb4bda4..63575273bbf62 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.ts +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.ts @@ -17,7 +17,7 @@ * under the License. */ import { i18n } from '@kbn/i18n'; -import { Action } from 'src/plugins/ui_actions/public'; +import { Action, ActionExecutionContext } from 'src/plugins/ui_actions/public'; import { NotificationsStart, OverlayStart } from 'src/core/public'; import { EmbeddableStart } from 'src/plugins/embeddable/public/plugin'; import { ViewMode } from '../../../../types'; @@ -52,12 +52,14 @@ export class AddPanelAction implements Action { return 'plusInCircleFilled'; } - public async isCompatible({ embeddable }: ActionContext) { + public async isCompatible(context: ActionExecutionContext) { + const { embeddable } = context; return embeddable.getIsContainer() && embeddable.getInput().viewMode === ViewMode.EDIT; } - public async execute({ embeddable }: ActionContext) { - if (!embeddable.getIsContainer() || !(await this.isCompatible({ embeddable }))) { + public async execute(context: ActionExecutionContext) { + const { embeddable } = context; + if (!embeddable.getIsContainer() || !(await this.isCompatible(context))) { throw new Error('Context is incompatible'); } diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_header.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_header.tsx index 2f086a3fb2c0c..5d7daaa7217ed 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_header.tsx +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_header.tsx @@ -30,7 +30,7 @@ import React from 'react'; import { Action } from 'src/plugins/ui_actions/public'; import { PanelOptionsMenu } from './panel_options_menu'; import { IEmbeddable } from '../../embeddables'; -import { EmbeddableContext } from '../../triggers'; +import { EmbeddableContext, panelBadgeTrigger, panelNotificationTrigger } from '../../triggers'; export interface PanelHeaderProps { title?: string; @@ -49,11 +49,11 @@ function renderBadges(badges: Array>, embeddable: IEmb badge.execute({ embeddable })} - onClickAriaLabel={badge.getDisplayName({ embeddable })} + iconType={badge.getIconType({ embeddable, trigger: panelBadgeTrigger })} + onClick={() => badge.execute({ embeddable, trigger: panelBadgeTrigger })} + onClickAriaLabel={badge.getDisplayName({ embeddable, trigger: panelBadgeTrigger })} > - {badge.getDisplayName({ embeddable })} + {badge.getDisplayName({ embeddable, trigger: panelBadgeTrigger })} )); } @@ -70,14 +70,17 @@ function renderNotifications( data-test-subj={`embeddablePanelNotification-${notification.id}`} key={notification.id} style={{ marginTop: '4px', marginRight: '4px' }} - onClick={() => notification.execute(context)} + onClick={() => notification.execute({ ...context, trigger: panelNotificationTrigger })} > - {notification.getDisplayName(context)} + {notification.getDisplayName({ ...context, trigger: panelNotificationTrigger })} ); if (notification.getDisplayNameTooltip) { - const tooltip = notification.getDisplayNameTooltip(context); + const tooltip = notification.getDisplayNameTooltip({ + ...context, + trigger: panelNotificationTrigger, + }); if (tooltip) { badge = ( diff --git a/src/plugins/embeddable/public/lib/test_samples/actions/say_hello_action.tsx b/src/plugins/embeddable/public/lib/test_samples/actions/say_hello_action.tsx index 0612b838a6ce7..968caf67b1826 100644 --- a/src/plugins/embeddable/public/lib/test_samples/actions/say_hello_action.tsx +++ b/src/plugins/embeddable/public/lib/test_samples/actions/say_hello_action.tsx @@ -17,7 +17,7 @@ * under the License. */ -import { ActionByType, IncompatibleActionError, ActionType } from '../../ui_actions'; +import { IncompatibleActionError, ActionType, ActionDefinitionByType } from '../../ui_actions'; import { EmbeddableInput, Embeddable, EmbeddableOutput, IEmbeddable } from '../../embeddables'; // Casting to ActionType is a hack - in a real situation use @@ -42,7 +42,7 @@ export interface SayHelloActionContext { message?: string; } -export class SayHelloAction implements ActionByType { +export class SayHelloAction implements ActionDefinitionByType { public readonly type = SAY_HELLO_ACTION; public readonly id = SAY_HELLO_ACTION; diff --git a/src/plugins/embeddable/public/tests/apply_filter_action.test.ts b/src/plugins/embeddable/public/tests/apply_filter_action.test.ts index 9d765c9906443..f8c4a4a7e4b72 100644 --- a/src/plugins/embeddable/public/tests/apply_filter_action.test.ts +++ b/src/plugins/embeddable/public/tests/apply_filter_action.test.ts @@ -31,6 +31,7 @@ import { FilterableEmbeddableInput, } from '../lib/test_samples'; import { esFilters } from '../../../data/public'; +import { applyFilterTrigger } from '../../../ui_actions/public'; test('ApplyFilterAction applies the filter to the root of the container tree', async () => { const { doStart, setup } = testPlugin(); @@ -85,7 +86,7 @@ test('ApplyFilterAction applies the filter to the root of the container tree', a query: { match: { extension: { query: 'foo' } } }, }; - await applyFilterAction.execute({ embeddable, filters: [filter] }); + await applyFilterAction.execute({ embeddable, filters: [filter], trigger: applyFilterTrigger }); expect(root.getInput().filters.length).toBe(1); expect(node1.getInput().filters.length).toBe(1); expect(embeddable.getInput().filters.length).toBe(1); diff --git a/src/plugins/ui_actions/public/actions/action.test.ts b/src/plugins/ui_actions/public/actions/action.test.ts index f9d696d3ddb5f..1f76223a0d7c4 100644 --- a/src/plugins/ui_actions/public/actions/action.test.ts +++ b/src/plugins/ui_actions/public/actions/action.test.ts @@ -17,8 +17,9 @@ * under the License. */ -import { createAction } from '../../../ui_actions/public'; +import { ActionExecutionContext, createAction } from '../../../ui_actions/public'; import { ActionType } from '../types'; +import { defaultTrigger } from '../triggers'; const sayHelloAction = createAction({ // Casting to ActionType is a hack - in a real situation use @@ -29,11 +30,17 @@ const sayHelloAction = createAction({ }); test('action is not compatible based on context', async () => { - const isCompatible = await sayHelloAction.isCompatible({ amICompatible: false }); + const isCompatible = await sayHelloAction.isCompatible({ + amICompatible: false, + trigger: defaultTrigger, + } as ActionExecutionContext); expect(isCompatible).toBe(false); }); test('action is compatible based on context', async () => { - const isCompatible = await sayHelloAction.isCompatible({ amICompatible: true }); + const isCompatible = await sayHelloAction.isCompatible({ + amICompatible: true, + trigger: defaultTrigger, + } as ActionExecutionContext); expect(isCompatible).toBe(true); }); diff --git a/src/plugins/ui_actions/public/actions/action.ts b/src/plugins/ui_actions/public/actions/action.ts index bc5f36acb8f0c..8005dadd8f5ef 100644 --- a/src/plugins/ui_actions/public/actions/action.ts +++ b/src/plugins/ui_actions/public/actions/action.ts @@ -18,13 +18,43 @@ */ import { UiComponent } from 'src/plugins/kibana_utils/public'; -import { ActionType, ActionContextMapping } from '../types'; +import { ActionType, ActionContextMapping, BaseContext } from '../types'; import { Presentable } from '../util/presentable'; +import { Trigger } from '../triggers'; export type ActionByType = Action; +export type ActionDefinitionByType = ActionDefinition< + ActionContextMapping[T] +>; -export interface Action - extends Partial> { +/** + * During action execution we can provide additional information, + * for example, trigger, that caused the action execution + */ +export interface ActionExecutionMeta { + /** + * Trigger that executed the action + */ + trigger: Trigger; +} + +/** + * Action methods are executed with Context from trigger + {@link ActionExecutionMeta} + */ +export type ActionExecutionContext = Context & + ActionExecutionMeta; + +/** + * Simplified action context for {@link ActionDefinition} + * When defining action consumer may use either it's own Context + * or an ActionExecutionContext to get access to {@link ActionExecutionMeta} params + */ +export type ActionDefinitionContext = + | Context + | ActionExecutionContext; + +export interface Action + extends Partial>> { /** * Determined the order when there is more than one action matched to a trigger. * Higher numbers are displayed first. @@ -44,44 +74,51 @@ export interface Action /** * Optional EUI icon type that can be displayed along with the title. */ - getIconType(context: Context): string | undefined; + getIconType(context: ActionExecutionContext): string | undefined; /** * Returns a title to be displayed to the user. * @param context */ - getDisplayName(context: Context): string; + getDisplayName(context: ActionExecutionContext): string; /** * `UiComponent` to render when displaying this action as a context menu item. * If not provided, `getDisplayName` will be used instead. */ - MenuItem?: UiComponent<{ context: Context }>; + MenuItem?: UiComponent<{ context: ActionExecutionContext }>; /** * Returns a promise that resolves to true if this action is compatible given the context, * otherwise resolves to false. */ - isCompatible(context: Context): Promise; + isCompatible(context: ActionExecutionContext): Promise; /** * Executes the action. */ - execute(context: Context): Promise; + execute(context: ActionExecutionContext): Promise; + + /** + * This method should return a link if this item can be clicked on. The link + * is used to navigate user if user middle-clicks it or Ctrl + clicks or + * right-clicks and selects "Open in new tab". + */ + getHref?(context: ActionExecutionContext): Promise; /** * Determines if action should be executed automatically, * without first showing up in context menu. * false by default. */ - shouldAutoExecute?(context: Context): Promise; + shouldAutoExecute?(context: ActionExecutionContext): Promise; } /** * A convenience interface used to register an action. */ -export interface ActionDefinition - extends Partial> { +export interface ActionDefinition + extends Partial>> { /** * ID of the action that uniquely identifies this action in the actions registry. */ @@ -92,17 +129,30 @@ export interface ActionDefinition */ readonly type?: ActionType; + /** + * Returns a promise that resolves to true if this item is compatible given + * the context and should be displayed to user, otherwise resolves to false. + */ + isCompatible?(context: ActionDefinitionContext): Promise; + /** * Executes the action. */ - execute(context: Context): Promise; + execute(context: ActionDefinitionContext): Promise; /** * Determines if action should be executed automatically, * without first showing up in context menu. * false by default. */ - shouldAutoExecute?(context: Context): Promise; + shouldAutoExecute?(context: ActionDefinitionContext): Promise; + + /** + * This method should return a link if this item can be clicked on. The link + * is used to navigate user if user middle-clicks it or Ctrl + clicks or + * right-clicks and selects "Open in new tab". + */ + getHref?(context: ActionDefinitionContext): Promise; } export type ActionContext = A extends ActionDefinition ? Context : never; diff --git a/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx b/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx index 7b87a5992a7f5..b44a07273f4a9 100644 --- a/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx +++ b/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx @@ -23,13 +23,22 @@ import _ from 'lodash'; import { i18n } from '@kbn/i18n'; import { uiToReactComponent } from '../../../kibana_react/public'; import { Action } from '../actions'; +import { Trigger } from '../triggers'; import { BaseContext } from '../types'; export const defaultTitle = i18n.translate('uiActions.actionPanel.title', { defaultMessage: 'Options', }); -type ActionWithContext = [Action, Context]; +interface ActionWithContext { + action: Action; + context: Context; + + /** + * Trigger that caused this action + */ + trigger: Trigger; +} /** * Transforms an array of Actions to the shape EuiContextMenuPanel expects. @@ -66,15 +75,19 @@ async function buildEuiContextMenuPanelItems({ closeMenu: () => void; }) { const items: EuiContextMenuPanelItemDescriptor[] = new Array(actions.length); - const promises = actions.map(async ([action, actionContext], index) => { - const isCompatible = await action.isCompatible(actionContext); + const promises = actions.map(async ({ action, context, trigger }, index) => { + const isCompatible = await action.isCompatible({ + ...context, + trigger, + }); if (!isCompatible) { return; } items[index] = await convertPanelActionToContextMenuItem({ action, - actionContext, + actionContext: context, + trigger, closeMenu, }); }); @@ -87,19 +100,30 @@ async function buildEuiContextMenuPanelItems({ async function convertPanelActionToContextMenuItem({ action, actionContext, + trigger, closeMenu, }: { action: Action; actionContext: Context; + trigger: Trigger; closeMenu: () => void; }): Promise { const menuPanelItem: EuiContextMenuPanelItemDescriptor = { name: action.MenuItem ? React.createElement(uiToReactComponent(action.MenuItem), { - context: actionContext, + context: { + ...actionContext, + trigger, + }, }) - : action.getDisplayName(actionContext), - icon: action.getIconType(actionContext), + : action.getDisplayName({ + ...actionContext, + trigger, + }), + icon: action.getIconType({ + ...actionContext, + trigger, + }), panel: _.get(action, 'childContextMenuPanel.id'), 'data-test-subj': `embeddablePanelAction-${action.id}`, }; @@ -114,20 +138,29 @@ async function convertPanelActionToContextMenuItem({ !(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey) // ignore clicks with modifier keys ) { event.preventDefault(); - action.execute(actionContext); + action.execute({ + ...actionContext, + trigger, + }); } else { // let browser handle navigation } } else { // not a link - action.execute(actionContext); + action.execute({ + ...actionContext, + trigger, + }); } closeMenu(); }; if (action.getHref) { - const href = await action.getHref(actionContext); + const href = await action.getHref({ + ...actionContext, + trigger, + }); if (href) { menuPanelItem.href = href; } diff --git a/src/plugins/ui_actions/public/index.ts b/src/plugins/ui_actions/public/index.ts index a9b413fb36542..d76ca124ead2c 100644 --- a/src/plugins/ui_actions/public/index.ts +++ b/src/plugins/ui_actions/public/index.ts @@ -45,4 +45,9 @@ export { applyFilterTrigger, } from './triggers'; export { TriggerContextMapping, TriggerId, ActionContextMapping, ActionType } from './types'; -export { ActionByType } from './actions'; +export { + ActionByType, + ActionDefinitionByType, + ActionExecutionContext, + ActionExecutionMeta, +} from './actions'; diff --git a/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts b/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts index 7393989672e9d..df89c9c2f70e9 100644 --- a/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts +++ b/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts @@ -46,7 +46,7 @@ export class UiActionsExecutionService { context: BaseContext; trigger: Trigger; }): Promise { - const shouldBatch = !(await action.shouldAutoExecute?.(context)) ?? false; + const shouldBatch = !(await action.shouldAutoExecute?.({ ...context, trigger })) ?? false; const task: ExecuteActionTask = { action, context, @@ -59,7 +59,7 @@ export class UiActionsExecutionService { } else { this.pendingTasks.add(task); try { - await action.execute(context); + await action.execute({ ...context, trigger }); this.pendingTasks.delete(task); } catch (e) { this.pendingTasks.delete(task); @@ -96,9 +96,12 @@ export class UiActionsExecutionService { }, 0); } - private async executeSingleTask({ context, action, defer }: ExecuteActionTask) { + private async executeSingleTask({ context, action, defer, trigger }: ExecuteActionTask) { try { - await action.execute(context); + await action.execute({ + ...context, + trigger, + }); defer.resolve(); } catch (e) { defer.reject(e); @@ -107,7 +110,11 @@ export class UiActionsExecutionService { private async executeMultipleActions(tasks: ExecuteActionTask[]) { const panel = await buildContextMenuForActions({ - actions: tasks.map(({ action, context }) => [action, context]), + actions: tasks.map(({ action, context, trigger }) => ({ + action, + context, + trigger, + })), title: tasks[0].trigger.title, // title of context menu is title of trigger which originated the chain closeMenu: () => { tasks.forEach((t) => t.defer.resolve()); 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 08efffbb6b5a8..6028177964fb7 100644 --- a/src/plugins/ui_actions/public/service/ui_actions_service.ts +++ b/src/plugins/ui_actions/public/service/ui_actions_service.ts @@ -142,7 +142,7 @@ export class UiActionsService { triggerId: T, // The action can accept partial or no context, but if it needs context not provided // by this type of trigger, typescript will complain. yay! - action: Action + action: ActionDefinition | Action // TODO: remove `Action` https://github.com/elastic/kibana/issues/74501 ): void => { if (!this.actions.has(action.id)) this.registerAction(action); this.attachAction(triggerId, action.id); @@ -178,7 +178,14 @@ export class UiActionsService { context: TriggerContextMapping[T] ): Promise>> => { const actions = this.getTriggerActions!(triggerId); - const isCompatibles = await Promise.all(actions.map((action) => action.isCompatible(context))); + const isCompatibles = await Promise.all( + actions.map((action) => + action.isCompatible({ + ...context, + trigger: this.getTrigger(triggerId), + }) + ) + ); return actions.reduce( (acc: Array>, action, i) => isCompatibles[i] ? [...acc, action] : acc, diff --git a/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts b/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts index 9af46f25b4fec..81120990001e3 100644 --- a/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts +++ b/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts @@ -82,7 +82,7 @@ test('executes a single action mapped to a trigger', async () => { jest.runAllTimers(); expect(executeFn).toBeCalledTimes(1); - expect(executeFn).toBeCalledWith(context); + expect(executeFn).toBeCalledWith(expect.objectContaining(context)); }); test('throws an error if there are no compatible actions to execute', async () => { @@ -202,3 +202,25 @@ test("doesn't show a context menu for auto executable actions", async () => { expect(openContextMenu).toHaveBeenCalledTimes(0); }); }); + +test('passes trigger into execute', async () => { + const { setup, doStart } = uiActions; + const trigger = { + id: 'MY-TRIGGER' as TriggerId, + title: 'My trigger', + }; + const action = createTestAction<{ foo: string }>('test', () => true); + + setup.registerTrigger(trigger); + setup.addTriggerAction(trigger.id, action); + + const start = doStart(); + + const context = { foo: 'bar' }; + await start.executeTriggerActions('MY-TRIGGER' as TriggerId, context); + jest.runAllTimers(); + expect(executeFn).toBeCalledWith({ + ...context, + trigger, + }); +}); diff --git a/src/plugins/ui_actions/public/triggers/default_trigger.ts b/src/plugins/ui_actions/public/triggers/default_trigger.ts new file mode 100644 index 0000000000000..74be0243bdac5 --- /dev/null +++ b/src/plugins/ui_actions/public/triggers/default_trigger.ts @@ -0,0 +1,27 @@ +/* + * 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 '.'; + +export const DEFAULT_TRIGGER = ''; +export const defaultTrigger: Trigger<''> = { + id: DEFAULT_TRIGGER, + title: 'Unknown', + description: 'Unknown trigger.', +}; diff --git a/src/plugins/ui_actions/public/triggers/index.ts b/src/plugins/ui_actions/public/triggers/index.ts index a5bf9e1822941..dbc54163c5af5 100644 --- a/src/plugins/ui_actions/public/triggers/index.ts +++ b/src/plugins/ui_actions/public/triggers/index.ts @@ -23,3 +23,4 @@ export * from './trigger_internal'; export * from './select_range_trigger'; export * from './value_click_trigger'; export * from './apply_filter_trigger'; +export * from './default_trigger'; diff --git a/src/plugins/ui_actions/public/types.ts b/src/plugins/ui_actions/public/types.ts index 5631441cf9a1b..dcf0bfb14d538 100644 --- a/src/plugins/ui_actions/public/types.ts +++ b/src/plugins/ui_actions/public/types.ts @@ -19,7 +19,12 @@ import { ActionInternal } from './actions/action_internal'; import { TriggerInternal } from './triggers/trigger_internal'; -import { SELECT_RANGE_TRIGGER, VALUE_CLICK_TRIGGER, APPLY_FILTER_TRIGGER } from './triggers'; +import { + SELECT_RANGE_TRIGGER, + VALUE_CLICK_TRIGGER, + APPLY_FILTER_TRIGGER, + DEFAULT_TRIGGER, +} from './triggers'; import type { RangeSelectContext, ValueClickContext } from '../../embeddable/public'; import type { ApplyGlobalFilterActionContext } from '../../data/public'; @@ -27,8 +32,6 @@ export type TriggerRegistry = Map>; export type ActionRegistry = Map; export type TriggerToActionsRegistry = Map; -const DEFAULT_TRIGGER = ''; - export type TriggerId = keyof TriggerContextMapping; export type BaseContext = object; diff --git a/x-pack/examples/ui_actions_enhanced_examples/public/dashboard_to_url_drilldown/index.tsx b/x-pack/examples/ui_actions_enhanced_examples/public/dashboard_to_url_drilldown/index.tsx index 037e017097e53..67599687dd881 100644 --- a/x-pack/examples/ui_actions_enhanced_examples/public/dashboard_to_url_drilldown/index.tsx +++ b/x-pack/examples/ui_actions_enhanced_examples/public/dashboard_to_url_drilldown/index.tsx @@ -10,6 +10,7 @@ import { reactToUiComponent } from '../../../../../src/plugins/kibana_react/publ import { UiActionsEnhancedDrilldownDefinition as Drilldown } from '../../../../plugins/ui_actions_enhanced/public'; import { ChartActionContext } from '../../../../../src/plugins/embeddable/public'; import { CollectConfigProps as CollectConfigPropsBase } from '../../../../../src/plugins/kibana_utils/public'; +import { ActionExecutionContext } from '../../../../../src/plugins/ui_actions/public'; function isValidUrl(url: string) { try { @@ -101,7 +102,15 @@ export class DashboardToUrlDrilldown implements Drilldown return config.url; }; - public readonly execute = async (config: Config, context: ActionContext) => { + public readonly execute = async ( + config: Config, + context: ActionExecutionContext + ) => { + // Just for showcasing: + // we can get trigger a which caused this drilldown execution + // eslint-disable-next-line no-console + console.log(context.trigger?.id); + const url = await this.getHref(config, context); if (config.openInNewTab) { diff --git a/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx b/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx index d0800c7b24fef..30025dce18c0b 100644 --- a/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx +++ b/x-pack/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx @@ -8,7 +8,10 @@ import { i18n } from '@kbn/i18n'; import _ from 'lodash'; import moment from 'moment-timezone'; import { CoreSetup } from 'src/core/public'; -import { Action, IncompatibleActionError } from '../../../../../src/plugins/ui_actions/public'; +import { + UiActionsActionDefinition as ActionDefinition, + IncompatibleActionError, +} from '../../../../../src/plugins/ui_actions/public'; import { LicensingPluginSetup } from '../../../licensing/public'; import { checkLicense } from '../lib/license_check'; @@ -30,7 +33,7 @@ interface ActionContext { embeddable: ISearchEmbeddable; } -export class GetCsvReportPanelAction implements Action { +export class GetCsvReportPanelAction implements ActionDefinition { private isDownloading: boolean; public readonly type = ''; public readonly id = CSV_REPORTING_ACTION; diff --git a/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_action.tsx b/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_action.tsx index 5d9804d2a5c33..259fe5c774c4b 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_action.tsx +++ b/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_action.tsx @@ -7,7 +7,10 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; import { IEmbeddable, Embeddable, EmbeddableInput } from 'src/plugins/embeddable/public'; -import { ActionByType, IncompatibleActionError } from '../../../../src/plugins/ui_actions/public'; +import { + ActionDefinitionByType, + IncompatibleActionError, +} from '../../../../src/plugins/ui_actions/public'; import { TimeRange } from '../../../../src/plugins/data/public'; import { CustomizeTimeRangeModal } from './customize_time_range_modal'; import { OpenModal, CommonlyUsedRange } from './types'; @@ -38,7 +41,7 @@ export interface TimeRangeActionContext { embeddable: Embeddable; } -export class CustomTimeRangeAction implements ActionByType { +export class CustomTimeRangeAction implements ActionDefinitionByType { public readonly type = CUSTOM_TIME_RANGE; private openModal: OpenModal; private dateFormat?: string; diff --git a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/drilldown_definition.ts b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/drilldown_definition.ts index a41ae851e185b..756bdf9e672aa 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/drilldown_definition.ts +++ b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/drilldown_definition.ts @@ -6,6 +6,7 @@ import { ActionFactoryDefinition } from '../dynamic_actions'; import { LicenseType } from '../../../licensing/public'; +import { ActionExecutionContext } from '../../../../../src/plugins/ui_actions/public'; /** * This is a convenience interface to register a drilldown. Drilldown has @@ -93,10 +94,16 @@ export interface DrilldownDefinition< * @param context Object that represents context in which the underlying * `UIAction` of this drilldown is being executed in. */ - execute(config: Config, context: ExecutionContext): void; + execute( + config: Config, + context: ExecutionContext | ActionExecutionContext + ): void; /** * A link where drilldown should navigate on middle click or Ctrl + click. */ - getHref?(config: Config, context: ExecutionContext): Promise; + getHref?( + config: Config, + context: ExecutionContext | ActionExecutionContext + ): Promise; } From 67e28ac8b45df85c18fe71902833a0c5bd36fe2d Mon Sep 17 00:00:00 2001 From: Patrick Mueller Date: Fri, 14 Aug 2020 08:34:26 -0400 Subject: [PATCH 39/53] [EventLog] Populate alert instances view with event log data (#68437) resolves https://github.com/elastic/kibana/issues/57446 Adds a new API (AlertClient and HTTP endpoint) `getAlertStatus()` which returns alert data calculated from the event log. --- x-pack/plugins/alerts/README.md | 18 + x-pack/plugins/alerts/common/alert_status.ts | 31 ++ x-pack/plugins/alerts/common/index.ts | 1 + .../alerts/server/alerts_client.mock.ts | 1 + .../alerts/server/alerts_client.test.ts | 246 +++++++++- x-pack/plugins/alerts/server/alerts_client.ts | 80 ++- .../server/alerts_client_factory.test.ts | 4 + .../alerts/server/alerts_client_factory.ts | 9 +- .../authorization/alerts_authorization.ts | 1 + .../lib/alert_status_from_event_log.test.ts | 464 ++++++++++++++++++ .../server/lib/alert_status_from_event_log.ts | 123 +++++ .../server/lib/iso_or_relative_date.test.ts | 28 ++ .../alerts/server/lib/iso_or_relative_date.ts | 27 + x-pack/plugins/alerts/server/plugin.ts | 9 +- .../server/routes/get_alert_status.test.ts | 105 ++++ .../alerts/server/routes/get_alert_status.ts | 52 ++ x-pack/plugins/alerts/server/routes/index.ts | 1 + .../server/task_runner/task_runner.test.ts | 67 ++- .../alerts/server/task_runner/task_runner.ts | 30 +- .../server/event_log_start_service.test.ts | 8 + x-pack/plugins/event_log/server/index.ts | 3 + x-pack/plugins/event_log/server/mocks.ts | 2 + x-pack/plugins/event_log/server/types.ts | 1 + .../alerting.test.ts | 4 + .../feature_privilege_builder/alerting.ts | 2 +- .../public/application/lib/alert_api.ts | 12 +- .../components/alert_instances.test.tsx | 149 +++--- .../components/alert_instances.tsx | 49 +- .../components/alert_instances_route.test.tsx | 75 +-- .../components/alert_instances_route.tsx | 30 +- .../with_bulk_alert_api_operations.tsx | 11 +- .../triggers_actions_ui/public/types.ts | 12 +- .../plugins/alerts/server/alert_types.ts | 22 +- .../common/lib/get_event_log.ts | 2 +- .../tests/alerting/get_alert_status.ts | 202 ++++++++ .../tests/alerting/index.ts | 1 + .../spaces_only/tests/alerting/event_log.ts | 35 +- .../tests/alerting/get_alert_status.ts | 261 ++++++++++ .../spaces_only/tests/alerting/index.ts | 1 + .../apps/triggers_actions_ui/details.ts | 20 +- .../services/alerting/alerts.ts | 19 +- 41 files changed, 2012 insertions(+), 206 deletions(-) create mode 100644 x-pack/plugins/alerts/common/alert_status.ts create mode 100644 x-pack/plugins/alerts/server/lib/alert_status_from_event_log.test.ts create mode 100644 x-pack/plugins/alerts/server/lib/alert_status_from_event_log.ts create mode 100644 x-pack/plugins/alerts/server/lib/iso_or_relative_date.test.ts create mode 100644 x-pack/plugins/alerts/server/lib/iso_or_relative_date.ts create mode 100644 x-pack/plugins/alerts/server/routes/get_alert_status.test.ts create mode 100644 x-pack/plugins/alerts/server/routes/get_alert_status.ts create mode 100644 x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get_alert_status.ts create mode 100644 x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_alert_status.ts diff --git a/x-pack/plugins/alerts/README.md b/x-pack/plugins/alerts/README.md index 10568abbe3c72..aab05cb0a7cfd 100644 --- a/x-pack/plugins/alerts/README.md +++ b/x-pack/plugins/alerts/README.md @@ -26,6 +26,7 @@ Table of Contents - [`GET /api/alerts/_find`: Find alerts](#get-apialertfind-find-alerts) - [`GET /api/alerts/alert/{id}`: Get alert](#get-apialertid-get-alert) - [`GET /api/alerts/alert/{id}/state`: Get alert state](#get-apialertidstate-get-alert-state) + - [`GET /api/alerts/alert/{id}/status`: Get alert status](#get-apialertidstate-get-alert-status) - [`GET /api/alerts/list_alert_types`: List alert types](#get-apialerttypes-list-alert-types) - [`PUT /api/alerts/alert/{id}`: Update alert](#put-apialertid-update-alert) - [`POST /api/alerts/alert/{id}/_enable`: Enable an alert](#post-apialertidenable-enable-an-alert) @@ -504,6 +505,23 @@ Params: |---|---|---| |id|The id of the alert whose state you're trying to get.|string| +### `GET /api/alerts/alert/{id}/status`: Get alert status + +Similar to the `GET state` call, but collects additional information from +the event log. + +Params: + +|Property|Description|Type| +|---|---|---| +|id|The id of the alert whose status you're trying to get.|string| + +Query: + +|Property|Description|Type| +|---|---|---| +|dateStart|The date to start looking for alert events in the event log. Either an ISO date string, or a duration string indicating time since now.|string| + ### `GET /api/alerts/list_alert_types`: List alert types No parameters. diff --git a/x-pack/plugins/alerts/common/alert_status.ts b/x-pack/plugins/alerts/common/alert_status.ts new file mode 100644 index 0000000000000..517db6d6cb243 --- /dev/null +++ b/x-pack/plugins/alerts/common/alert_status.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. + */ + +type AlertStatusValues = 'OK' | 'Active' | 'Error'; +type AlertInstanceStatusValues = 'OK' | 'Active'; + +export interface AlertStatus { + id: string; + name: string; + tags: string[]; + alertTypeId: string; + consumer: string; + muteAll: boolean; + throttle: string | null; + enabled: boolean; + statusStartDate: string; + statusEndDate: string; + status: AlertStatusValues; + lastRun?: string; + errorMessages: Array<{ date: string; message: string }>; + instances: Record; +} + +export interface AlertInstanceStatus { + status: AlertInstanceStatusValues; + muted: boolean; + activeStartDate?: string; +} diff --git a/x-pack/plugins/alerts/common/index.ts b/x-pack/plugins/alerts/common/index.ts index b839c07a9db89..0922e164a3aa3 100644 --- a/x-pack/plugins/alerts/common/index.ts +++ b/x-pack/plugins/alerts/common/index.ts @@ -9,6 +9,7 @@ export * from './alert_type'; export * from './alert_instance'; export * from './alert_task_instance'; export * from './alert_navigation'; +export * from './alert_status'; export interface ActionGroup { id: string; diff --git a/x-pack/plugins/alerts/server/alerts_client.mock.ts b/x-pack/plugins/alerts/server/alerts_client.mock.ts index be70e441b6fc5..b61139ae72c99 100644 --- a/x-pack/plugins/alerts/server/alerts_client.mock.ts +++ b/x-pack/plugins/alerts/server/alerts_client.mock.ts @@ -25,6 +25,7 @@ const createAlertsClientMock = () => { muteInstance: jest.fn(), unmuteInstance: jest.fn(), listAlertTypes: jest.fn(), + getAlertStatus: jest.fn(), }; return mocked; }; diff --git a/x-pack/plugins/alerts/server/alerts_client.test.ts b/x-pack/plugins/alerts/server/alerts_client.test.ts index c25e040ad09ce..d994269366ae6 100644 --- a/x-pack/plugins/alerts/server/alerts_client.test.ts +++ b/x-pack/plugins/alerts/server/alerts_client.test.ts @@ -11,16 +11,22 @@ import { taskManagerMock } from '../../task_manager/server/task_manager.mock'; import { alertTypeRegistryMock } from './alert_type_registry.mock'; import { alertsAuthorizationMock } from './authorization/alerts_authorization.mock'; import { TaskStatus } from '../../task_manager/server'; -import { IntervalSchedule } from './types'; +import { IntervalSchedule, RawAlert } from './types'; import { resolvable } from './test_utils'; import { encryptedSavedObjectsMock } from '../../encrypted_saved_objects/server/mocks'; import { actionsClientMock, actionsAuthorizationMock } from '../../actions/server/mocks'; import { AlertsAuthorization } from './authorization/alerts_authorization'; import { ActionsAuthorization } from '../../actions/server'; +import { eventLogClientMock } from '../../event_log/server/mocks'; +import { QueryEventsBySavedObjectResult } from '../../event_log/server'; +import { SavedObject } from 'kibana/server'; +import { EventsFactory } from './lib/alert_status_from_event_log.test'; const taskManager = taskManagerMock.start(); const alertTypeRegistry = alertTypeRegistryMock.create(); const unsecuredSavedObjectsClient = savedObjectsClientMock.create(); +const eventLogClient = eventLogClientMock.create(); + const encryptedSavedObjects = encryptedSavedObjectsMock.createClient(); const authorization = alertsAuthorizationMock.create(); const actionsAuthorization = actionsAuthorizationMock.create(); @@ -39,6 +45,7 @@ const alertsClientParams: jest.Mocked = { logger: loggingSystemMock.create().get(), encryptedSavedObjectsClient: encryptedSavedObjects, getActionsClient: jest.fn(), + getEventLogClient: jest.fn(), }; beforeEach(() => { @@ -91,17 +98,33 @@ beforeEach(() => { async executor() {}, producer: 'alerts', })); + alertsClientParams.getEventLogClient.mockResolvedValue(eventLogClient); }); -const mockedDate = new Date('2019-02-12T21:01:22.479Z'); -// eslint-disable-next-line @typescript-eslint/no-explicit-any +const mockedDateString = '2019-02-12T21:01:22.479Z'; +const mockedDate = new Date(mockedDateString); +const DateOriginal = Date; + +// A version of date that responds to `new Date(null|undefined)` and `Date.now()` +// by returning a fixed date, otherwise should be same as Date. +/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ (global as any).Date = class Date { - constructor() { - return mockedDate; + constructor(...args: unknown[]) { + // sometimes the ctor has no args, sometimes has a single `null` arg + if (args[0] == null) { + // @ts-ignore + return mockedDate; + } else { + // @ts-ignore + return new DateOriginal(...args); + } } static now() { return mockedDate.getTime(); } + static parse(string: string) { + return DateOriginal.parse(string); + } }; function getMockData(overwrites: Record = {}): CreateOptions['data'] { @@ -2295,6 +2318,219 @@ describe('getAlertState()', () => { }); }); +const AlertStatusFindEventsResult: QueryEventsBySavedObjectResult = { + page: 1, + per_page: 10000, + total: 0, + data: [], +}; + +const AlertStatusIntervalSeconds = 1; + +const BaseAlertStatusSavedObject: SavedObject = { + id: '1', + type: 'alert', + attributes: { + enabled: true, + name: 'alert-name', + tags: ['tag-1', 'tag-2'], + alertTypeId: '123', + consumer: 'alert-consumer', + schedule: { interval: `${AlertStatusIntervalSeconds}s` }, + actions: [], + params: {}, + createdBy: null, + updatedBy: null, + createdAt: mockedDateString, + apiKey: null, + apiKeyOwner: null, + throttle: null, + muteAll: false, + mutedInstanceIds: [], + }, + references: [], +}; + +function getAlertStatusSavedObject(attributes: Partial = {}): SavedObject { + return { + ...BaseAlertStatusSavedObject, + attributes: { ...BaseAlertStatusSavedObject.attributes, ...attributes }, + }; +} + +describe('getAlertStatus()', () => { + let alertsClient: AlertsClient; + + beforeEach(() => { + alertsClient = new AlertsClient(alertsClientParams); + }); + + test('runs as expected with some event log data', async () => { + const alertSO = getAlertStatusSavedObject({ mutedInstanceIds: ['instance-muted-no-activity'] }); + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(alertSO); + + const eventsFactory = new EventsFactory(mockedDateString); + const events = eventsFactory + .addExecute() + .addNewInstance('instance-currently-active') + .addNewInstance('instance-previously-active') + .addActiveInstance('instance-currently-active') + .addActiveInstance('instance-previously-active') + .advanceTime(10000) + .addExecute() + .addResolvedInstance('instance-previously-active') + .addActiveInstance('instance-currently-active') + .getEvents(); + const eventsResult = { + ...AlertStatusFindEventsResult, + total: events.length, + data: events, + }; + eventLogClient.findEventsBySavedObject.mockResolvedValueOnce(eventsResult); + + const dateStart = new Date(Date.now() - 60 * 1000).toISOString(); + + const result = await alertsClient.getAlertStatus({ id: '1', dateStart }); + expect(result).toMatchInlineSnapshot(` + Object { + "alertTypeId": "123", + "consumer": "alert-consumer", + "enabled": true, + "errorMessages": Array [], + "id": "1", + "instances": Object { + "instance-currently-active": Object { + "activeStartDate": "2019-02-12T21:01:22.479Z", + "muted": false, + "status": "Active", + }, + "instance-muted-no-activity": Object { + "activeStartDate": undefined, + "muted": true, + "status": "OK", + }, + "instance-previously-active": Object { + "activeStartDate": undefined, + "muted": false, + "status": "OK", + }, + }, + "lastRun": "2019-02-12T21:01:32.479Z", + "muteAll": false, + "name": "alert-name", + "status": "Active", + "statusEndDate": "2019-02-12T21:01:22.479Z", + "statusStartDate": "2019-02-12T21:00:22.479Z", + "tags": Array [ + "tag-1", + "tag-2", + ], + "throttle": null, + } + `); + }); + + // Further tests don't check the result of `getAlertStatus()`, as the result + // is just the result from the `alertStatusFromEventLog()`, which itself + // has a complete set of tests. These tests just make sure the data gets + // sent into `getAlertStatus()` as appropriate. + + test('calls saved objects and event log client with default params', async () => { + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertStatusSavedObject()); + eventLogClient.findEventsBySavedObject.mockResolvedValueOnce(AlertStatusFindEventsResult); + + await alertsClient.getAlertStatus({ id: '1' }); + + expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1); + expect(eventLogClient.findEventsBySavedObject).toHaveBeenCalledTimes(1); + expect(eventLogClient.findEventsBySavedObject.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "alert", + "1", + Object { + "end": "2019-02-12T21:01:22.479Z", + "page": 1, + "per_page": 10000, + "sort_order": "desc", + "start": "2019-02-12T21:00:22.479Z", + }, + ] + `); + // calculate the expected start/end date for one test + const { start, end } = eventLogClient.findEventsBySavedObject.mock.calls[0][2]!; + expect(end).toBe(mockedDateString); + + const startMillis = Date.parse(start!); + const endMillis = Date.parse(end!); + const expectedDuration = 60 * AlertStatusIntervalSeconds * 1000; + expect(endMillis - startMillis).toBeGreaterThan(expectedDuration - 2); + expect(endMillis - startMillis).toBeLessThan(expectedDuration + 2); + }); + + test('calls event log client with start date', async () => { + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertStatusSavedObject()); + eventLogClient.findEventsBySavedObject.mockResolvedValueOnce(AlertStatusFindEventsResult); + + const dateStart = new Date(Date.now() - 60 * AlertStatusIntervalSeconds * 1000).toISOString(); + await alertsClient.getAlertStatus({ id: '1', dateStart }); + + expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1); + expect(eventLogClient.findEventsBySavedObject).toHaveBeenCalledTimes(1); + const { start, end } = eventLogClient.findEventsBySavedObject.mock.calls[0][2]!; + + expect({ start, end }).toMatchInlineSnapshot(` + Object { + "end": "2019-02-12T21:01:22.479Z", + "start": "2019-02-12T21:00:22.479Z", + } + `); + }); + + test('calls event log client with relative start date', async () => { + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertStatusSavedObject()); + eventLogClient.findEventsBySavedObject.mockResolvedValueOnce(AlertStatusFindEventsResult); + + const dateStart = '2m'; + await alertsClient.getAlertStatus({ id: '1', dateStart }); + + expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1); + expect(eventLogClient.findEventsBySavedObject).toHaveBeenCalledTimes(1); + const { start, end } = eventLogClient.findEventsBySavedObject.mock.calls[0][2]!; + + expect({ start, end }).toMatchInlineSnapshot(` + Object { + "end": "2019-02-12T21:01:22.479Z", + "start": "2019-02-12T20:59:22.479Z", + } + `); + }); + + test('invalid start date throws an error', async () => { + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertStatusSavedObject()); + eventLogClient.findEventsBySavedObject.mockResolvedValueOnce(AlertStatusFindEventsResult); + + const dateStart = 'ain"t no way this will get parsed as a date'; + expect(alertsClient.getAlertStatus({ id: '1', dateStart })).rejects.toMatchInlineSnapshot( + `[Error: Invalid date for parameter dateStart: "ain"t no way this will get parsed as a date"]` + ); + }); + + test('saved object get throws an error', async () => { + unsecuredSavedObjectsClient.get.mockRejectedValueOnce(new Error('OMG!')); + eventLogClient.findEventsBySavedObject.mockResolvedValueOnce(AlertStatusFindEventsResult); + + expect(alertsClient.getAlertStatus({ id: '1' })).rejects.toMatchInlineSnapshot(`[Error: OMG!]`); + }); + + test('findEvents throws an error', async () => { + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertStatusSavedObject()); + eventLogClient.findEventsBySavedObject.mockRejectedValueOnce(new Error('OMG 2!')); + + // error eaten but logged + await alertsClient.getAlertStatus({ id: '1' }); + }); +}); + describe('find()', () => { const listedTypes = new Set([ { diff --git a/x-pack/plugins/alerts/server/alerts_client.ts b/x-pack/plugins/alerts/server/alerts_client.ts index dd66ccc7a0256..80e021fc5cb6e 100644 --- a/x-pack/plugins/alerts/server/alerts_client.ts +++ b/x-pack/plugins/alerts/server/alerts_client.ts @@ -24,6 +24,7 @@ import { IntervalSchedule, SanitizedAlert, AlertTaskState, + AlertStatus, } from './types'; import { validateAlertTypeParams } from './lib'; import { @@ -41,6 +42,11 @@ import { WriteOperations, ReadOperations, } from './authorization/alerts_authorization'; +import { IEventLogClient } from '../../../plugins/event_log/server'; +import { parseIsoOrRelativeDate } from './lib/iso_or_relative_date'; +import { alertStatusFromEventLog } from './lib/alert_status_from_event_log'; +import { IEvent } from '../../event_log/server'; +import { parseDuration } from '../common/parse_duration'; export interface RegistryAlertTypeWithAuth extends RegistryAlertType { authorizedConsumers: string[]; @@ -67,6 +73,7 @@ export interface ConstructorOptions { createAPIKey: (name: string) => Promise; invalidateAPIKey: (params: InvalidateAPIKeyParams) => Promise; getActionsClient: () => Promise; + getEventLogClient: () => Promise; } export interface MuteOptions extends IndexType { @@ -132,6 +139,11 @@ interface UpdateOptions { }; } +interface GetAlertStatusParams { + id: string; + dateStart?: string; +} + export class AlertsClient { private readonly logger: Logger; private readonly getUserName: () => Promise; @@ -147,6 +159,7 @@ export class AlertsClient { ) => Promise; private readonly getActionsClient: () => Promise; private readonly actionsAuthorization: ActionsAuthorization; + private readonly getEventLogClient: () => Promise; encryptedSavedObjectsClient: EncryptedSavedObjectsClient; constructor({ @@ -163,6 +176,7 @@ export class AlertsClient { encryptedSavedObjectsClient, getActionsClient, actionsAuthorization, + getEventLogClient, }: ConstructorOptions) { this.logger = logger; this.getUserName = getUserName; @@ -177,6 +191,7 @@ export class AlertsClient { this.encryptedSavedObjectsClient = encryptedSavedObjectsClient; this.getActionsClient = getActionsClient; this.actionsAuthorization = actionsAuthorization; + this.getEventLogClient = getEventLogClient; } public async create({ data, options }: CreateOptions): Promise { @@ -269,6 +284,49 @@ export class AlertsClient { } } + public async getAlertStatus({ id, dateStart }: GetAlertStatusParams): Promise { + this.logger.debug(`getAlertStatus(): getting alert ${id}`); + const alert = await this.get({ id }); + await this.authorization.ensureAuthorized( + alert.alertTypeId, + alert.consumer, + ReadOperations.GetAlertStatus + ); + + // default duration of status is 60 * alert interval + const dateNow = new Date(); + const durationMillis = parseDuration(alert.schedule.interval) * 60; + const defaultDateStart = new Date(dateNow.valueOf() - durationMillis); + const parsedDateStart = parseDate(dateStart, 'dateStart', defaultDateStart); + + const eventLogClient = await this.getEventLogClient(); + + this.logger.debug(`getAlertStatus(): search the event log for alert ${id}`); + let events: IEvent[]; + try { + const queryResults = await eventLogClient.findEventsBySavedObject('alert', id, { + page: 1, + per_page: 10000, + start: parsedDateStart.toISOString(), + end: dateNow.toISOString(), + sort_order: 'desc', + }); + events = queryResults.data; + } catch (err) { + this.logger.debug( + `alertsClient.getAlertStatus(): error searching event log for alert ${id}: ${err.message}` + ); + events = []; + } + + return alertStatusFromEventLog({ + alert, + events, + dateStart: parsedDateStart.toISOString(), + dateEnd: dateNow.toISOString(), + }); + } + public async find({ options: { fields, ...options } = {}, }: { options?: FindOptions } = {}): Promise { @@ -283,7 +341,6 @@ export class AlertsClient { ? `${options.filter} and ${authorizationFilter}` : authorizationFilter; } - const { page, per_page: perPage, @@ -886,3 +943,24 @@ export class AlertsClient { return truncate(`Alerting: ${alertTypeId}/${alertName}`, { length: 256 }); } } + +function parseDate(dateString: string | undefined, propertyName: string, defaultValue: Date): Date { + if (dateString === undefined) { + return defaultValue; + } + + const parsedDate = parseIsoOrRelativeDate(dateString); + if (parsedDate === undefined) { + throw Boom.badRequest( + i18n.translate('xpack.alerts.alertsClient.getAlertStatus.invalidDate', { + defaultMessage: 'Invalid date for parameter {field}: "{dateValue}"', + values: { + field: propertyName, + dateValue: dateString, + }, + }) + ); + } + + return parsedDate; +} diff --git a/x-pack/plugins/alerts/server/alerts_client_factory.test.ts b/x-pack/plugins/alerts/server/alerts_client_factory.test.ts index 16b5af499bb90..a5eb371633f1e 100644 --- a/x-pack/plugins/alerts/server/alerts_client_factory.test.ts +++ b/x-pack/plugins/alerts/server/alerts_client_factory.test.ts @@ -22,6 +22,7 @@ import { actionsMock, actionsAuthorizationMock } from '../../actions/server/mock import { featuresPluginMock } from '../../features/server/mocks'; import { AuditLogger } from '../../security/server'; import { ALERTS_FEATURE_ID } from '../common'; +import { eventLogMock } from '../../event_log/server/mocks'; jest.mock('./alerts_client'); jest.mock('./authorization/alerts_authorization'); @@ -42,6 +43,7 @@ const alertsClientFactoryParams: jest.Mocked = { encryptedSavedObjectsClient: encryptedSavedObjectsMock.createClient(), actions: actionsMock.createStart(), features, + eventLog: eventLogMock.createStart(), }; const fakeRequest = ({ headers: {}, @@ -119,6 +121,7 @@ test('creates an alerts client with proper constructor arguments when security i namespace: 'default', getUserName: expect.any(Function), getActionsClient: expect.any(Function), + getEventLogClient: expect.any(Function), createAPIKey: expect.any(Function), invalidateAPIKey: expect.any(Function), encryptedSavedObjectsClient: alertsClientFactoryParams.encryptedSavedObjectsClient, @@ -164,6 +167,7 @@ test('creates an alerts client with proper constructor arguments', async () => { invalidateAPIKey: expect.any(Function), encryptedSavedObjectsClient: alertsClientFactoryParams.encryptedSavedObjectsClient, getActionsClient: expect.any(Function), + getEventLogClient: expect.any(Function), }); }); diff --git a/x-pack/plugins/alerts/server/alerts_client_factory.ts b/x-pack/plugins/alerts/server/alerts_client_factory.ts index 79b0ccaf1f0bc..83202424c9773 100644 --- a/x-pack/plugins/alerts/server/alerts_client_factory.ts +++ b/x-pack/plugins/alerts/server/alerts_client_factory.ts @@ -16,6 +16,7 @@ import { PluginStartContract as FeaturesPluginStart } from '../../features/serve import { AlertsAuthorization } from './authorization/alerts_authorization'; import { AlertsAuthorizationAuditLogger } from './authorization/audit_logger'; import { Space } from '../../spaces/server'; +import { IEventLogClientService } from '../../../plugins/event_log/server'; export interface AlertsClientFactoryOpts { logger: Logger; @@ -28,6 +29,7 @@ export interface AlertsClientFactoryOpts { encryptedSavedObjectsClient: EncryptedSavedObjectsClient; actions: ActionsPluginStartContract; features: FeaturesPluginStart; + eventLog: IEventLogClientService; } export class AlertsClientFactory { @@ -42,6 +44,7 @@ export class AlertsClientFactory { private encryptedSavedObjectsClient!: EncryptedSavedObjectsClient; private actions!: ActionsPluginStartContract; private features!: FeaturesPluginStart; + private eventLog!: IEventLogClientService; public initialize(options: AlertsClientFactoryOpts) { if (this.isInitialized) { @@ -58,10 +61,11 @@ export class AlertsClientFactory { this.encryptedSavedObjectsClient = options.encryptedSavedObjectsClient; this.actions = options.actions; this.features = options.features; + this.eventLog = options.eventLog; } public create(request: KibanaRequest, savedObjects: SavedObjectsServiceStart): AlertsClient { - const { securityPluginSetup, actions, features } = this; + const { securityPluginSetup, actions, eventLog, features } = this; const spaceId = this.getSpaceId(request); const authorization = new AlertsAuthorization({ authorization: securityPluginSetup?.authz, @@ -135,6 +139,9 @@ export class AlertsClientFactory { async getActionsClient() { return actions.getActionsClientWithRequest(request); }, + async getEventLogClient() { + return eventLog.getClient(request); + }, }); } } diff --git a/x-pack/plugins/alerts/server/authorization/alerts_authorization.ts b/x-pack/plugins/alerts/server/authorization/alerts_authorization.ts index 33a9a0bf0396e..b2a214eae9316 100644 --- a/x-pack/plugins/alerts/server/authorization/alerts_authorization.ts +++ b/x-pack/plugins/alerts/server/authorization/alerts_authorization.ts @@ -18,6 +18,7 @@ import { Space } from '../../../spaces/server'; export enum ReadOperations { Get = 'get', GetAlertState = 'getAlertState', + GetAlertStatus = 'getAlertStatus', Find = 'find', } diff --git a/x-pack/plugins/alerts/server/lib/alert_status_from_event_log.test.ts b/x-pack/plugins/alerts/server/lib/alert_status_from_event_log.test.ts new file mode 100644 index 0000000000000..15570d3032f24 --- /dev/null +++ b/x-pack/plugins/alerts/server/lib/alert_status_from_event_log.test.ts @@ -0,0 +1,464 @@ +/* + * 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 { SanitizedAlert, AlertStatus } from '../types'; +import { IValidatedEvent } from '../../../event_log/server'; +import { EVENT_LOG_ACTIONS, EVENT_LOG_PROVIDER } from '../plugin'; +import { alertStatusFromEventLog } from './alert_status_from_event_log'; + +const ONE_HOUR_IN_MILLIS = 60 * 60 * 1000; +const dateStart = '2020-06-18T00:00:00.000Z'; +const dateEnd = dateString(dateStart, ONE_HOUR_IN_MILLIS); + +describe('alertStatusFromEventLog', () => { + test('no events and muted ids', async () => { + const alert = createAlert({}); + const events: IValidatedEvent[] = []; + const status: AlertStatus = alertStatusFromEventLog({ alert, events, dateStart, dateEnd }); + + expect(status).toMatchInlineSnapshot(` + Object { + "alertTypeId": "123", + "consumer": "alert-consumer", + "enabled": false, + "errorMessages": Array [], + "id": "alert-123", + "instances": Object {}, + "lastRun": undefined, + "muteAll": false, + "name": "alert-name", + "status": "OK", + "statusEndDate": "2020-06-18T01:00:00.000Z", + "statusStartDate": "2020-06-18T00:00:00.000Z", + "tags": Array [], + "throttle": null, + } + `); + }); + + test('different alert properties', async () => { + const alert = createAlert({ + id: 'alert-456', + alertTypeId: '456', + schedule: { interval: '100s' }, + enabled: true, + name: 'alert-name-2', + tags: ['tag-1', 'tag-2'], + consumer: 'alert-consumer-2', + throttle: '1h', + muteAll: true, + }); + const events: IValidatedEvent[] = []; + const status: AlertStatus = alertStatusFromEventLog({ + alert, + events, + dateStart: dateString(dateEnd, ONE_HOUR_IN_MILLIS), + dateEnd: dateString(dateEnd, ONE_HOUR_IN_MILLIS * 2), + }); + + expect(status).toMatchInlineSnapshot(` + Object { + "alertTypeId": "456", + "consumer": "alert-consumer-2", + "enabled": true, + "errorMessages": Array [], + "id": "alert-456", + "instances": Object {}, + "lastRun": undefined, + "muteAll": true, + "name": "alert-name-2", + "status": "OK", + "statusEndDate": "2020-06-18T03:00:00.000Z", + "statusStartDate": "2020-06-18T02:00:00.000Z", + "tags": Array [ + "tag-1", + "tag-2", + ], + "throttle": "1h", + } + `); + }); + + test('two muted instances', async () => { + const alert = createAlert({ + mutedInstanceIds: ['instance-1', 'instance-2'], + }); + const events: IValidatedEvent[] = []; + const alertStatus: AlertStatus = alertStatusFromEventLog({ alert, events, dateStart, dateEnd }); + + const { lastRun, status, instances } = alertStatus; + expect({ lastRun, status, instances }).toMatchInlineSnapshot(` + Object { + "instances": Object { + "instance-1": Object { + "activeStartDate": undefined, + "muted": true, + "status": "OK", + }, + "instance-2": Object { + "activeStartDate": undefined, + "muted": true, + "status": "OK", + }, + }, + "lastRun": undefined, + "status": "OK", + } + `); + }); + + test('active alert but no instances', async () => { + const alert = createAlert({}); + const eventsFactory = new EventsFactory(); + const events = eventsFactory.addExecute().advanceTime(10000).addExecute().getEvents(); + + const alertStatus: AlertStatus = alertStatusFromEventLog({ alert, events, dateStart, dateEnd }); + + const { lastRun, status, instances } = alertStatus; + expect({ lastRun, status, instances }).toMatchInlineSnapshot(` + Object { + "instances": Object {}, + "lastRun": "2020-06-18T00:00:10.000Z", + "status": "OK", + } + `); + }); + + test('active alert with no instances but has errors', async () => { + const alert = createAlert({}); + const eventsFactory = new EventsFactory(); + const events = eventsFactory + .addExecute('oof!') + .advanceTime(10000) + .addExecute('rut roh!') + .getEvents(); + + const alertStatus: AlertStatus = alertStatusFromEventLog({ alert, events, dateStart, dateEnd }); + + const { lastRun, status, errorMessages, instances } = alertStatus; + expect({ lastRun, status, errorMessages, instances }).toMatchInlineSnapshot(` + Object { + "errorMessages": Array [ + Object { + "date": "2020-06-18T00:00:00.000Z", + "message": "oof!", + }, + Object { + "date": "2020-06-18T00:00:10.000Z", + "message": "rut roh!", + }, + ], + "instances": Object {}, + "lastRun": "2020-06-18T00:00:10.000Z", + "status": "Error", + } + `); + }); + + test('alert with currently inactive instance', async () => { + const alert = createAlert({}); + const eventsFactory = new EventsFactory(); + const events = eventsFactory + .addExecute() + .addNewInstance('instance-1') + .addActiveInstance('instance-1') + .advanceTime(10000) + .addExecute() + .addResolvedInstance('instance-1') + .getEvents(); + + const alertStatus: AlertStatus = alertStatusFromEventLog({ alert, events, dateStart, dateEnd }); + + const { lastRun, status, instances } = alertStatus; + expect({ lastRun, status, instances }).toMatchInlineSnapshot(` + Object { + "instances": Object { + "instance-1": Object { + "activeStartDate": undefined, + "muted": false, + "status": "OK", + }, + }, + "lastRun": "2020-06-18T00:00:10.000Z", + "status": "OK", + } + `); + }); + + test('alert with currently inactive instance, no new-instance', async () => { + const alert = createAlert({}); + const eventsFactory = new EventsFactory(); + const events = eventsFactory + .addExecute() + .addActiveInstance('instance-1') + .advanceTime(10000) + .addExecute() + .addResolvedInstance('instance-1') + .getEvents(); + + const alertStatus: AlertStatus = alertStatusFromEventLog({ alert, events, dateStart, dateEnd }); + + const { lastRun, status, instances } = alertStatus; + expect({ lastRun, status, instances }).toMatchInlineSnapshot(` + Object { + "instances": Object { + "instance-1": Object { + "activeStartDate": undefined, + "muted": false, + "status": "OK", + }, + }, + "lastRun": "2020-06-18T00:00:10.000Z", + "status": "OK", + } + `); + }); + + test('alert with currently active instance', async () => { + const alert = createAlert({}); + const eventsFactory = new EventsFactory(); + const events = eventsFactory + .addExecute() + .addNewInstance('instance-1') + .addActiveInstance('instance-1') + .advanceTime(10000) + .addExecute() + .addActiveInstance('instance-1') + .getEvents(); + + const alertStatus: AlertStatus = alertStatusFromEventLog({ alert, events, dateStart, dateEnd }); + + const { lastRun, status, instances } = alertStatus; + expect({ lastRun, status, instances }).toMatchInlineSnapshot(` + Object { + "instances": Object { + "instance-1": Object { + "activeStartDate": "2020-06-18T00:00:00.000Z", + "muted": false, + "status": "Active", + }, + }, + "lastRun": "2020-06-18T00:00:10.000Z", + "status": "Active", + } + `); + }); + + test('alert with currently active instance, no new-instance', async () => { + const alert = createAlert({}); + const eventsFactory = new EventsFactory(); + const events = eventsFactory + .addExecute() + .addActiveInstance('instance-1') + .advanceTime(10000) + .addExecute() + .addActiveInstance('instance-1') + .getEvents(); + + const alertStatus: AlertStatus = alertStatusFromEventLog({ alert, events, dateStart, dateEnd }); + + const { lastRun, status, instances } = alertStatus; + expect({ lastRun, status, instances }).toMatchInlineSnapshot(` + Object { + "instances": Object { + "instance-1": Object { + "activeStartDate": undefined, + "muted": false, + "status": "Active", + }, + }, + "lastRun": "2020-06-18T00:00:10.000Z", + "status": "Active", + } + `); + }); + + test('alert with active and inactive muted alerts', async () => { + const alert = createAlert({ mutedInstanceIds: ['instance-1', 'instance-2'] }); + const eventsFactory = new EventsFactory(); + const events = eventsFactory + .addExecute() + .addNewInstance('instance-1') + .addActiveInstance('instance-1') + .addNewInstance('instance-2') + .addActiveInstance('instance-2') + .advanceTime(10000) + .addExecute() + .addActiveInstance('instance-1') + .addResolvedInstance('instance-2') + .getEvents(); + + const alertStatus: AlertStatus = alertStatusFromEventLog({ alert, events, dateStart, dateEnd }); + + const { lastRun, status, instances } = alertStatus; + expect({ lastRun, status, instances }).toMatchInlineSnapshot(` + Object { + "instances": Object { + "instance-1": Object { + "activeStartDate": "2020-06-18T00:00:00.000Z", + "muted": true, + "status": "Active", + }, + "instance-2": Object { + "activeStartDate": undefined, + "muted": true, + "status": "OK", + }, + }, + "lastRun": "2020-06-18T00:00:10.000Z", + "status": "Active", + } + `); + }); + + test('alert with active and inactive alerts over many executes', async () => { + const alert = createAlert({}); + const eventsFactory = new EventsFactory(); + const events = eventsFactory + .addExecute() + .addNewInstance('instance-1') + .addActiveInstance('instance-1') + .addNewInstance('instance-2') + .addActiveInstance('instance-2') + .advanceTime(10000) + .addExecute() + .addActiveInstance('instance-1') + .addResolvedInstance('instance-2') + .advanceTime(10000) + .addExecute() + .addActiveInstance('instance-1') + .advanceTime(10000) + .addExecute() + .addActiveInstance('instance-1') + .getEvents(); + + const alertStatus: AlertStatus = alertStatusFromEventLog({ alert, events, dateStart, dateEnd }); + + const { lastRun, status, instances } = alertStatus; + expect({ lastRun, status, instances }).toMatchInlineSnapshot(` + Object { + "instances": Object { + "instance-1": Object { + "activeStartDate": "2020-06-18T00:00:00.000Z", + "muted": false, + "status": "Active", + }, + "instance-2": Object { + "activeStartDate": undefined, + "muted": false, + "status": "OK", + }, + }, + "lastRun": "2020-06-18T00:00:30.000Z", + "status": "Active", + } + `); + }); +}); + +function dateString(isoBaseDate: string, offsetMillis = 0): string { + return new Date(Date.parse(isoBaseDate) + offsetMillis).toISOString(); +} + +export class EventsFactory { + private events: IValidatedEvent[] = []; + + constructor(private date: string = dateStart) {} + + getEvents(): IValidatedEvent[] { + // ES normally returns events sorted newest to oldest, so we need to sort + // that way also + const events = this.events.slice(); + events.sort((a, b) => -a!['@timestamp']!.localeCompare(b!['@timestamp']!)); + return events; + } + + getTime(): string { + return this.date; + } + + advanceTime(millis: number): EventsFactory { + this.date = dateString(this.date, millis); + return this; + } + + addExecute(errorMessage?: string): EventsFactory { + let event: IValidatedEvent = { + '@timestamp': this.date, + event: { + provider: EVENT_LOG_PROVIDER, + action: EVENT_LOG_ACTIONS.execute, + }, + }; + + if (errorMessage) { + event = { ...event, error: { message: errorMessage } }; + } + + this.events.push(event); + return this; + } + + addActiveInstance(instanceId: string): EventsFactory { + this.events.push({ + '@timestamp': this.date, + event: { + provider: EVENT_LOG_PROVIDER, + action: EVENT_LOG_ACTIONS.activeInstance, + }, + kibana: { alerting: { instance_id: instanceId } }, + }); + return this; + } + + addNewInstance(instanceId: string): EventsFactory { + this.events.push({ + '@timestamp': this.date, + event: { + provider: EVENT_LOG_PROVIDER, + action: EVENT_LOG_ACTIONS.newInstance, + }, + kibana: { alerting: { instance_id: instanceId } }, + }); + return this; + } + + addResolvedInstance(instanceId: string): EventsFactory { + this.events.push({ + '@timestamp': this.date, + event: { + provider: EVENT_LOG_PROVIDER, + action: EVENT_LOG_ACTIONS.resolvedInstance, + }, + kibana: { alerting: { instance_id: instanceId } }, + }); + return this; + } +} + +function createAlert(overrides: Partial): SanitizedAlert { + return { ...BaseAlert, ...overrides }; +} + +const BaseAlert: SanitizedAlert = { + id: 'alert-123', + alertTypeId: '123', + schedule: { interval: '10s' }, + enabled: false, + name: 'alert-name', + tags: [], + consumer: 'alert-consumer', + throttle: null, + muteAll: false, + mutedInstanceIds: [], + params: { bar: true }, + actions: [], + createdBy: null, + updatedBy: null, + createdAt: new Date(), + updatedAt: new Date(), + apiKeyOwner: null, +}; diff --git a/x-pack/plugins/alerts/server/lib/alert_status_from_event_log.ts b/x-pack/plugins/alerts/server/lib/alert_status_from_event_log.ts new file mode 100644 index 0000000000000..606bd44c6990c --- /dev/null +++ b/x-pack/plugins/alerts/server/lib/alert_status_from_event_log.ts @@ -0,0 +1,123 @@ +/* + * 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 { SanitizedAlert, AlertStatus, AlertInstanceStatus } from '../types'; +import { IEvent } from '../../../event_log/server'; +import { EVENT_LOG_ACTIONS, EVENT_LOG_PROVIDER } from '../plugin'; + +export interface AlertStatusFromEventLogParams { + alert: SanitizedAlert; + events: IEvent[]; + dateStart: string; + dateEnd: string; +} + +export function alertStatusFromEventLog(params: AlertStatusFromEventLogParams): AlertStatus { + // initialize the result + const { alert, events, dateStart, dateEnd } = params; + const alertStatus: AlertStatus = { + id: alert.id, + name: alert.name, + tags: alert.tags, + alertTypeId: alert.alertTypeId, + consumer: alert.consumer, + statusStartDate: dateStart, + statusEndDate: dateEnd, + status: 'OK', + muteAll: alert.muteAll, + throttle: alert.throttle, + enabled: alert.enabled, + lastRun: undefined, + errorMessages: [], + instances: {}, + }; + + const instances = new Map(); + + // loop through the events + // should be sorted newest to oldest, we want oldest to newest, so reverse + for (const event of events.reverse()) { + const timeStamp = event?.['@timestamp']; + if (timeStamp === undefined) continue; + + const provider = event?.event?.provider; + if (provider !== EVENT_LOG_PROVIDER) continue; + + const action = event?.event?.action; + if (action === undefined) continue; + + if (action === EVENT_LOG_ACTIONS.execute) { + alertStatus.lastRun = timeStamp; + + const errorMessage = event?.error?.message; + if (errorMessage !== undefined) { + alertStatus.status = 'Error'; + alertStatus.errorMessages.push({ + date: timeStamp, + message: errorMessage, + }); + } else { + alertStatus.status = 'OK'; + } + + continue; + } + + const instanceId = event?.kibana?.alerting?.instance_id; + if (instanceId === undefined) continue; + + const status = getAlertInstanceStatus(instances, instanceId); + switch (action) { + case EVENT_LOG_ACTIONS.newInstance: + status.activeStartDate = timeStamp; + // intentionally no break here + case EVENT_LOG_ACTIONS.activeInstance: + status.status = 'Active'; + break; + case EVENT_LOG_ACTIONS.resolvedInstance: + status.status = 'OK'; + status.activeStartDate = undefined; + } + } + + // set the muted status of instances + for (const instanceId of alert.mutedInstanceIds) { + getAlertInstanceStatus(instances, instanceId).muted = true; + } + + // convert the instances map to object form + const instanceIds = Array.from(instances.keys()).sort(); + for (const instanceId of instanceIds) { + alertStatus.instances[instanceId] = instances.get(instanceId)!; + } + + // set the overall alert status to Active if appropriate + if (alertStatus.status !== 'Error') { + if (Array.from(instances.values()).some((instance) => instance.status === 'Active')) { + alertStatus.status = 'Active'; + } + } + + alertStatus.errorMessages.sort((a, b) => a.date.localeCompare(b.date)); + + return alertStatus; +} + +// return an instance status object, creating and adding to the map if needed +function getAlertInstanceStatus( + instances: Map, + instanceId: string +): AlertInstanceStatus { + if (instances.has(instanceId)) return instances.get(instanceId)!; + + const status: AlertInstanceStatus = { + status: 'OK', + muted: false, + activeStartDate: undefined, + }; + instances.set(instanceId, status); + return status; +} diff --git a/x-pack/plugins/alerts/server/lib/iso_or_relative_date.test.ts b/x-pack/plugins/alerts/server/lib/iso_or_relative_date.test.ts new file mode 100644 index 0000000000000..91272c1cca3b5 --- /dev/null +++ b/x-pack/plugins/alerts/server/lib/iso_or_relative_date.test.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { parseIsoOrRelativeDate } from './iso_or_relative_date'; + +describe('parseIsoOrRelativeDate', () => { + test('handles ISO dates', () => { + const date = new Date(); + const parsedDate = parseIsoOrRelativeDate(date.toISOString()); + expect(parsedDate?.valueOf()).toBe(date.valueOf()); + }); + + test('handles relative dates', () => { + const hoursDiff = 1; + const date = new Date(Date.now() - hoursDiff * 60 * 60 * 1000); + const parsedDate = parseIsoOrRelativeDate(`${hoursDiff}h`); + const diff = Math.abs(parsedDate!.valueOf() - date.valueOf()); + expect(diff).toBeLessThan(1000); + }); + + test('returns undefined for invalid date strings', () => { + const parsedDate = parseIsoOrRelativeDate('this shall not pass'); + expect(parsedDate).toBeUndefined(); + }); +}); diff --git a/x-pack/plugins/alerts/server/lib/iso_or_relative_date.ts b/x-pack/plugins/alerts/server/lib/iso_or_relative_date.ts new file mode 100644 index 0000000000000..77c4eefa04439 --- /dev/null +++ b/x-pack/plugins/alerts/server/lib/iso_or_relative_date.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { parseDuration } from '../../common/parse_duration'; + +/** + * Parse an ISO date or NNx duration string as a Date + * + * @param dateString an ISO date or NNx "duration" string representing now-duration + * @returns a Date or undefined if the dateString was not valid + */ +export function parseIsoOrRelativeDate(dateString: string): Date | undefined { + const epochMillis = Date.parse(dateString); + if (!isNaN(epochMillis)) return new Date(epochMillis); + + let millis: number; + try { + millis = parseDuration(dateString); + } catch (err) { + return; + } + + return new Date(Date.now() - millis); +} diff --git a/x-pack/plugins/alerts/server/plugin.ts b/x-pack/plugins/alerts/server/plugin.ts index 5d69887bd5bf0..d5843bd531d84 100644 --- a/x-pack/plugins/alerts/server/plugin.ts +++ b/x-pack/plugins/alerts/server/plugin.ts @@ -38,6 +38,7 @@ import { findAlertRoute, getAlertRoute, getAlertStateRoute, + getAlertStatusRoute, listAlertTypesRoute, updateAlertRoute, enableAlertRoute, @@ -57,16 +58,17 @@ import { import { Services } from './types'; import { registerAlertsUsageCollector } from './usage'; import { initializeAlertingTelemetry, scheduleAlertingTelemetry } from './usage/task'; -import { IEventLogger, IEventLogService } from '../../event_log/server'; +import { IEventLogger, IEventLogService, IEventLogClientService } from '../../event_log/server'; import { PluginStartContract as FeaturesPluginStart } from '../../features/server'; import { setupSavedObjects } from './saved_objects'; -const EVENT_LOG_PROVIDER = 'alerting'; +export const EVENT_LOG_PROVIDER = 'alerting'; export const EVENT_LOG_ACTIONS = { execute: 'execute', executeAction: 'execute-action', newInstance: 'new-instance', resolvedInstance: 'resolved-instance', + activeInstance: 'active-instance', }; export interface PluginSetupContract { @@ -92,6 +94,7 @@ export interface AlertingPluginsStart { taskManager: TaskManagerStartContract; encryptedSavedObjects: EncryptedSavedObjectsPluginStart; features: FeaturesPluginStart; + eventLog: IEventLogClientService; } export class AlertingPlugin { @@ -189,6 +192,7 @@ export class AlertingPlugin { findAlertRoute(router, this.licenseState); getAlertRoute(router, this.licenseState); getAlertStateRoute(router, this.licenseState); + getAlertStatusRoute(router, this.licenseState); listAlertTypesRoute(router, this.licenseState); updateAlertRoute(router, this.licenseState); enableAlertRoute(router, this.licenseState); @@ -235,6 +239,7 @@ export class AlertingPlugin { }, actions: plugins.actions, features: plugins.features, + eventLog: plugins.eventLog, }); const getAlertsClientWithRequest = (request: KibanaRequest) => { diff --git a/x-pack/plugins/alerts/server/routes/get_alert_status.test.ts b/x-pack/plugins/alerts/server/routes/get_alert_status.test.ts new file mode 100644 index 0000000000000..1b4cb1941018b --- /dev/null +++ b/x-pack/plugins/alerts/server/routes/get_alert_status.test.ts @@ -0,0 +1,105 @@ +/* + * 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 { getAlertStatusRoute } from './get_alert_status'; +import { httpServiceMock } from 'src/core/server/mocks'; +import { mockLicenseState } from '../lib/license_state.mock'; +import { mockHandlerArguments } from './_mock_handler_arguments'; +import { SavedObjectsErrorHelpers } from 'src/core/server'; +import { alertsClientMock } from '../alerts_client.mock'; +import { AlertStatus } from '../types'; + +const alertsClient = alertsClientMock.create(); +jest.mock('../lib/license_api_access.ts', () => ({ + verifyApiAccess: jest.fn(), +})); + +beforeEach(() => { + jest.resetAllMocks(); +}); + +describe('getAlertStatusRoute', () => { + const dateString = new Date().toISOString(); + const mockedAlertStatus: AlertStatus = { + id: '', + name: '', + tags: [], + alertTypeId: '', + consumer: '', + muteAll: false, + throttle: null, + enabled: false, + statusStartDate: dateString, + statusEndDate: dateString, + status: 'OK', + errorMessages: [], + instances: {}, + }; + + it('gets alert status', async () => { + const licenseState = mockLicenseState(); + const router = httpServiceMock.createRouter(); + + getAlertStatusRoute(router, licenseState); + + const [config, handler] = router.get.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/api/alerts/alert/{id}/status"`); + + alertsClient.getAlertStatus.mockResolvedValueOnce(mockedAlertStatus); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { + id: '1', + }, + query: {}, + }, + ['ok'] + ); + + await handler(context, req, res); + + expect(alertsClient.getAlertStatus).toHaveBeenCalledTimes(1); + expect(alertsClient.getAlertStatus.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "dateStart": undefined, + "id": "1", + }, + ] + `); + + expect(res.ok).toHaveBeenCalled(); + }); + + it('returns NOT-FOUND when alert is not found', async () => { + const licenseState = mockLicenseState(); + const router = httpServiceMock.createRouter(); + + getAlertStatusRoute(router, licenseState); + + const [, handler] = router.get.mock.calls[0]; + + alertsClient.getAlertStatus = jest + .fn() + .mockResolvedValueOnce(SavedObjectsErrorHelpers.createGenericNotFoundError('alert', '1')); + + const [context, req, res] = mockHandlerArguments( + { alertsClient }, + { + params: { + id: '1', + }, + query: {}, + }, + ['notFound'] + ); + + expect(await handler(context, req, res)).toEqual(undefined); + }); +}); diff --git a/x-pack/plugins/alerts/server/routes/get_alert_status.ts b/x-pack/plugins/alerts/server/routes/get_alert_status.ts new file mode 100644 index 0000000000000..eab18c50189f4 --- /dev/null +++ b/x-pack/plugins/alerts/server/routes/get_alert_status.ts @@ -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 { schema, TypeOf } from '@kbn/config-schema'; +import { + IRouter, + RequestHandlerContext, + KibanaRequest, + IKibanaResponse, + KibanaResponseFactory, +} from 'kibana/server'; +import { LicenseState } from '../lib/license_state'; +import { verifyApiAccess } from '../lib/license_api_access'; +import { BASE_ALERT_API_PATH } from '../../common'; + +const paramSchema = schema.object({ + id: schema.string(), +}); + +const querySchema = schema.object({ + dateStart: schema.maybe(schema.string()), +}); + +export const getAlertStatusRoute = (router: IRouter, licenseState: LicenseState) => { + router.get( + { + path: `${BASE_ALERT_API_PATH}/alert/{id}/status`, + validate: { + params: paramSchema, + query: querySchema, + }, + }, + router.handleLegacyErrors(async function ( + context: RequestHandlerContext, + req: KibanaRequest, TypeOf, unknown>, + res: KibanaResponseFactory + ): Promise { + verifyApiAccess(licenseState); + if (!context.alerting) { + return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); + } + const alertsClient = context.alerting.getAlertsClient(); + const { id } = req.params; + const { dateStart } = req.query; + const status = await alertsClient.getAlertStatus({ id, dateStart }); + return res.ok({ body: status }); + }) + ); +}; diff --git a/x-pack/plugins/alerts/server/routes/index.ts b/x-pack/plugins/alerts/server/routes/index.ts index f833a29c67bb9..4c6b1eb8e9b58 100644 --- a/x-pack/plugins/alerts/server/routes/index.ts +++ b/x-pack/plugins/alerts/server/routes/index.ts @@ -9,6 +9,7 @@ export { deleteAlertRoute } from './delete'; export { findAlertRoute } from './find'; export { getAlertRoute } from './get'; export { getAlertStateRoute } from './get_alert_state'; +export { getAlertStatusRoute } from './get_alert_status'; export { listAlertTypesRoute } from './list_alert_types'; export { updateAlertRoute } from './update'; export { enableAlertRoute } from './enable'; diff --git a/x-pack/plugins/alerts/server/task_runner/task_runner.test.ts b/x-pack/plugins/alerts/server/task_runner/task_runner.test.ts index 4abe58de5a904..58b1fa4a123e1 100644 --- a/x-pack/plugins/alerts/server/task_runner/task_runner.test.ts +++ b/x-pack/plugins/alerts/server/task_runner/task_runner.test.ts @@ -224,7 +224,7 @@ describe('Task Runner', () => { `); const eventLogger = taskRunnerFactoryInitializerParams.eventLogger; - expect(eventLogger.logEvent).toHaveBeenCalledTimes(3); + expect(eventLogger.logEvent).toHaveBeenCalledTimes(4); expect(eventLogger.logEvent).toHaveBeenCalledWith({ event: { action: 'execute', @@ -261,6 +261,25 @@ describe('Task Runner', () => { }, message: "test:1: 'alert-name' created new instance: '1'", }); + expect(eventLogger.logEvent).toHaveBeenCalledWith({ + event: { + action: 'active-instance', + }, + kibana: { + alerting: { + instance_id: '1', + }, + saved_objects: [ + { + id: '1', + namespace: undefined, + rel: 'primary', + type: 'alert', + }, + ], + }, + message: "test:1: 'alert-name' active instance: '1'", + }); expect(eventLogger.logEvent).toHaveBeenCalledWith({ event: { action: 'execute-action', @@ -345,7 +364,7 @@ describe('Task Runner', () => { `); const eventLogger = taskRunnerFactoryInitializerParams.eventLogger; - expect(eventLogger.logEvent).toHaveBeenCalledTimes(3); + expect(eventLogger.logEvent).toHaveBeenCalledTimes(4); expect(eventLogger.logEvent.mock.calls).toMatchInlineSnapshot(` Array [ Array [ @@ -388,6 +407,27 @@ describe('Task Runner', () => { "message": "test:1: 'alert-name' created new instance: '1'", }, ], + Array [ + Object { + "event": Object { + "action": "active-instance", + }, + "kibana": Object { + "alerting": Object { + "instance_id": "1", + }, + "saved_objects": Array [ + Object { + "id": "1", + "namespace": undefined, + "rel": "primary", + "type": "alert", + }, + ], + }, + "message": "test:1: 'alert-name' active instance: '1'", + }, + ], Array [ Object { "event": Object { @@ -465,7 +505,7 @@ describe('Task Runner', () => { `); const eventLogger = taskRunnerFactoryInitializerParams.eventLogger; - expect(eventLogger.logEvent).toHaveBeenCalledTimes(2); + expect(eventLogger.logEvent).toHaveBeenCalledTimes(3); expect(eventLogger.logEvent.mock.calls).toMatchInlineSnapshot(` Array [ Array [ @@ -508,6 +548,27 @@ describe('Task Runner', () => { "message": "test:1: 'alert-name' resolved instance: '2'", }, ], + Array [ + Object { + "event": Object { + "action": "active-instance", + }, + "kibana": Object { + "alerting": Object { + "instance_id": "1", + }, + "saved_objects": Array [ + Object { + "id": "1", + "namespace": undefined, + "rel": "primary", + "type": "alert", + }, + ], + }, + "message": "test:1: 'alert-name' active instance: '1'", + }, + ], ] `); }); diff --git a/x-pack/plugins/alerts/server/task_runner/task_runner.ts b/x-pack/plugins/alerts/server/task_runner/task_runner.ts index 04fea58f250a3..4c16d23b485b5 100644 --- a/x-pack/plugins/alerts/server/task_runner/task_runner.ts +++ b/x-pack/plugins/alerts/server/task_runner/task_runner.ts @@ -355,41 +355,53 @@ interface GenerateNewAndResolvedInstanceEventsParams { } function generateNewAndResolvedInstanceEvents(params: GenerateNewAndResolvedInstanceEventsParams) { - const { currentAlertInstanceIds, originalAlertInstanceIds } = params; + const { + eventLogger, + alertId, + namespace, + currentAlertInstanceIds, + originalAlertInstanceIds, + } = params; + const newIds = without(currentAlertInstanceIds, ...originalAlertInstanceIds); const resolvedIds = without(originalAlertInstanceIds, ...currentAlertInstanceIds); + for (const id of resolvedIds) { + const message = `${params.alertLabel} resolved instance: '${id}'`; + logInstanceEvent(id, EVENT_LOG_ACTIONS.resolvedInstance, message); + } + for (const id of newIds) { const message = `${params.alertLabel} created new instance: '${id}'`; logInstanceEvent(id, EVENT_LOG_ACTIONS.newInstance, message); } - for (const id of resolvedIds) { - const message = `${params.alertLabel} resolved instance: '${id}'`; - logInstanceEvent(id, EVENT_LOG_ACTIONS.resolvedInstance, message); + for (const id of currentAlertInstanceIds) { + const message = `${params.alertLabel} active instance: '${id}'`; + logInstanceEvent(id, EVENT_LOG_ACTIONS.activeInstance, message); } - function logInstanceEvent(id: string, action: string, message: string) { + function logInstanceEvent(instanceId: string, action: string, message: string) { const event: IEvent = { event: { action, }, kibana: { alerting: { - instance_id: id, + instance_id: instanceId, }, saved_objects: [ { rel: SAVED_OBJECT_REL_PRIMARY, type: 'alert', - id: params.alertId, - namespace: params.namespace, + id: alertId, + namespace, }, ], }, message, }; - params.eventLogger.logEvent(event); + eventLogger.logEvent(event); } } diff --git a/x-pack/plugins/event_log/server/event_log_start_service.test.ts b/x-pack/plugins/event_log/server/event_log_start_service.test.ts index cbdc168a8ffde..0a5b169e87d4d 100644 --- a/x-pack/plugins/event_log/server/event_log_start_service.test.ts +++ b/x-pack/plugins/event_log/server/event_log_start_service.test.ts @@ -28,6 +28,14 @@ describe('EventLogClientService', () => { eventLogStartService.getClient(request); + const savedObjectGetter = savedObjectProviderRegistry.getProvidersClient(request); + expect(jest.requireMock('./event_log_client').EventLogClient).toHaveBeenCalledWith({ + esContext, + request, + savedObjectGetter, + spacesService: undefined, + }); + expect(savedObjectProviderRegistry.getProvidersClient).toHaveBeenCalledWith(request); }); }); diff --git a/x-pack/plugins/event_log/server/index.ts b/x-pack/plugins/event_log/server/index.ts index 25b1b95831b8a..7169aa6ff9baa 100644 --- a/x-pack/plugins/event_log/server/index.ts +++ b/x-pack/plugins/event_log/server/index.ts @@ -14,7 +14,10 @@ export { IEventLogClientService, IEvent, IValidatedEvent, + IEventLogClient, + QueryEventsBySavedObjectResult, SAVED_OBJECT_REL_PRIMARY, } from './types'; + export const config = { schema: ConfigSchema }; export const plugin = (context: PluginInitializerContext) => new Plugin(context); diff --git a/x-pack/plugins/event_log/server/mocks.ts b/x-pack/plugins/event_log/server/mocks.ts index 2f632a52d2f36..39ec9c42522dc 100644 --- a/x-pack/plugins/event_log/server/mocks.ts +++ b/x-pack/plugins/event_log/server/mocks.ts @@ -7,6 +7,8 @@ import { eventLogServiceMock } from './event_log_service.mock'; import { eventLogStartServiceMock } from './event_log_start_service.mock'; +export { eventLogClientMock } from './event_log_client.mock'; + export { eventLogServiceMock, eventLogStartServiceMock }; export { eventLoggerMock } from './event_logger.mock'; diff --git a/x-pack/plugins/event_log/server/types.ts b/x-pack/plugins/event_log/server/types.ts index cda9579220623..66030ee3910dc 100644 --- a/x-pack/plugins/event_log/server/types.ts +++ b/x-pack/plugins/event_log/server/types.ts @@ -12,6 +12,7 @@ export { IEvent, IValidatedEvent, EventSchema, ECS_VERSION } from '../generated/ import { IEvent } from '../generated/schemas'; import { FindOptionsType } from './event_log_client'; import { QueryEventsBySavedObjectResult } from './es/cluster_client_adapter'; +export { QueryEventsBySavedObjectResult } from './es/cluster_client_adapter'; import { SavedObjectProvider } from './saved_object_provider_registry'; export const SAVED_OBJECT_REL_PRIMARY = 'primary'; diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts index 99d69602db137..636082656f1a4 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts @@ -74,6 +74,7 @@ describe(`feature_privilege_builder`, () => { Array [ "alerting:1.0.0-zeta1:alert-type/my-feature/get", "alerting:1.0.0-zeta1:alert-type/my-feature/getAlertState", + "alerting:1.0.0-zeta1:alert-type/my-feature/getAlertStatus", "alerting:1.0.0-zeta1:alert-type/my-feature/find", ] `); @@ -110,6 +111,7 @@ describe(`feature_privilege_builder`, () => { Array [ "alerting:1.0.0-zeta1:alert-type/my-feature/get", "alerting:1.0.0-zeta1:alert-type/my-feature/getAlertState", + "alerting:1.0.0-zeta1:alert-type/my-feature/getAlertStatus", "alerting:1.0.0-zeta1:alert-type/my-feature/find", "alerting:1.0.0-zeta1:alert-type/my-feature/create", "alerting:1.0.0-zeta1:alert-type/my-feature/delete", @@ -156,6 +158,7 @@ describe(`feature_privilege_builder`, () => { Array [ "alerting:1.0.0-zeta1:alert-type/my-feature/get", "alerting:1.0.0-zeta1:alert-type/my-feature/getAlertState", + "alerting:1.0.0-zeta1:alert-type/my-feature/getAlertStatus", "alerting:1.0.0-zeta1:alert-type/my-feature/find", "alerting:1.0.0-zeta1:alert-type/my-feature/create", "alerting:1.0.0-zeta1:alert-type/my-feature/delete", @@ -169,6 +172,7 @@ describe(`feature_privilege_builder`, () => { "alerting:1.0.0-zeta1:alert-type/my-feature/unmuteInstance", "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/get", "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/getAlertState", + "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/getAlertStatus", "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/find", ] `); diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts index 42dd7794ba184..540b9e5c1e56e 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts @@ -8,7 +8,7 @@ import { uniq } from 'lodash'; import { Feature, FeatureKibanaPrivileges } from '../../../../../features/server'; import { BaseFeaturePrivilegeBuilder } from './feature_privilege_builder'; -const readOperations: string[] = ['get', 'getAlertState', 'find']; +const readOperations: string[] = ['get', 'getAlertState', 'getAlertStatus', 'find']; const writeOperations: string[] = [ 'create', 'delete', diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts index 35fdc3974a296..7dde344d06fb5 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts @@ -11,7 +11,7 @@ import { fold } from 'fp-ts/lib/Either'; import { pick } from 'lodash'; import { alertStateSchema, AlertingFrameworkHealth } from '../../../../alerts/common'; import { BASE_ALERT_API_PATH } from '../constants'; -import { Alert, AlertType, AlertWithoutId, AlertTaskState } from '../../types'; +import { Alert, AlertType, AlertWithoutId, AlertTaskState, AlertStatus } from '../../types'; export async function loadAlertTypes({ http }: { http: HttpSetup }): Promise { return await http.get(`${BASE_ALERT_API_PATH}/list_alert_types`); @@ -48,6 +48,16 @@ export async function loadAlertState({ }); } +export async function loadAlertStatus({ + http, + alertId, +}: { + http: HttpSetup; + alertId: string; +}): Promise { + return await http.get(`${BASE_ALERT_API_PATH}/alert/${alertId}/status`); +} + export async function loadAlerts({ http, page, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances.test.tsx index dd2ee48b7a620..ff9b518a9f5b1 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances.test.tsx @@ -7,7 +7,7 @@ import * as React from 'react'; import uuid from 'uuid'; import { shallow } from 'enzyme'; import { AlertInstances, AlertInstanceListItem, alertInstanceToListItem } from './alert_instances'; -import { Alert, AlertTaskState, RawAlertInstance } from '../../../../types'; +import { Alert, AlertStatus, AlertInstanceStatus } from '../../../../types'; import { EuiBasicTable } from '@elastic/eui'; const fakeNow = new Date('2020-02-09T23:15:41.941Z'); @@ -34,26 +34,37 @@ jest.mock('../../../app_context', () => { describe('alert_instances', () => { it('render a list of alert instances', () => { const alert = mockAlert(); + const alertStatus = mockAlertStatus({ + instances: { + first_instance: { + status: 'OK', + muted: false, + }, + second_instance: { + status: 'OK', + muted: false, + }, + }, + }); - const alertState = mockAlertState(); const instances: AlertInstanceListItem[] = [ alertInstanceToListItem( fakeNow.getTime(), alert, 'first_instance', - alertState.alertInstances!.first_instance + alertStatus.instances.first_instance ), alertInstanceToListItem( fakeNow.getTime(), alert, 'second_instance', - alertState.alertInstances!.second_instance + alertStatus.instances.second_instance ), ]; expect( shallow( - + ) .find(EuiBasicTable) .prop('items') @@ -62,7 +73,7 @@ describe('alert_instances', () => { it('render a hidden field with duration epoch', () => { const alert = mockAlert(); - const alertState = mockAlertState(); + const alertStatus = mockAlertStatus(); expect( shallow( @@ -71,7 +82,7 @@ describe('alert_instances', () => { {...mockAPIs} alert={alert} readOnly={false} - alertState={alertState} + alertStatus={alertStatus} /> ) .find('[name="alertInstancesDurationEpoch"]') @@ -81,17 +92,15 @@ describe('alert_instances', () => { it('render all active alert instances', () => { const alert = mockAlert(); - const instances = { + const instances: Record = { ['us-central']: { - state: {}, - meta: { - lastScheduledActions: { - group: 'warning', - date: fake2MinutesAgo, - }, - }, + status: 'OK', + muted: false, + }, + ['us-east']: { + status: 'OK', + muted: false, }, - ['us-east']: {}, }; expect( shallow( @@ -99,8 +108,8 @@ describe('alert_instances', () => { {...mockAPIs} alert={alert} readOnly={false} - alertState={mockAlertState({ - alertInstances: instances, + alertStatus={mockAlertStatus({ + instances, })} /> ) @@ -116,6 +125,8 @@ describe('alert_instances', () => { const alert = mockAlert({ mutedInstanceIds: ['us-west', 'us-east'], }); + const instanceUsWest: AlertInstanceStatus = { status: 'OK', muted: false }; + const instanceUsEast: AlertInstanceStatus = { status: 'OK', muted: false }; expect( shallow( @@ -123,16 +134,25 @@ describe('alert_instances', () => { {...mockAPIs} alert={alert} readOnly={false} - alertState={mockAlertState({ - alertInstances: {}, + alertStatus={mockAlertStatus({ + instances: { + 'us-west': { + status: 'OK', + muted: false, + }, + 'us-east': { + status: 'OK', + muted: false, + }, + }, })} /> ) .find(EuiBasicTable) .prop('items') ).toEqual([ - alertInstanceToListItem(fakeNow.getTime(), alert, 'us-west'), - alertInstanceToListItem(fakeNow.getTime(), alert, 'us-east'), + alertInstanceToListItem(fakeNow.getTime(), alert, 'us-west', instanceUsWest), + alertInstanceToListItem(fakeNow.getTime(), alert, 'us-east', instanceUsEast), ]); }); }); @@ -141,13 +161,10 @@ describe('alertInstanceToListItem', () => { it('handles active instances', () => { const alert = mockAlert(); const start = fake2MinutesAgo; - const instance: RawAlertInstance = { - meta: { - lastScheduledActions: { - date: start, - group: 'default', - }, - }, + const instance: AlertInstanceStatus = { + status: 'Active', + muted: false, + activeStartDate: fake2MinutesAgo.toISOString(), }; expect(alertInstanceToListItem(fakeNow.getTime(), alert, 'id', instance)).toEqual({ @@ -164,13 +181,10 @@ describe('alertInstanceToListItem', () => { mutedInstanceIds: ['id'], }); const start = fake2MinutesAgo; - const instance: RawAlertInstance = { - meta: { - lastScheduledActions: { - date: start, - group: 'default', - }, - }, + const instance: AlertInstanceStatus = { + status: 'Active', + muted: true, + activeStartDate: fake2MinutesAgo.toISOString(), }; expect(alertInstanceToListItem(fakeNow.getTime(), alert, 'id', instance)).toEqual({ @@ -182,23 +196,11 @@ describe('alertInstanceToListItem', () => { }); }); - it('handles active instances with no meta', () => { + it('handles active instances with start date', () => { const alert = mockAlert(); - const instance: RawAlertInstance = {}; - - expect(alertInstanceToListItem(fakeNow.getTime(), alert, 'id', instance)).toEqual({ - instance: 'id', - status: { label: 'Active', healthColor: 'primary' }, - start: undefined, - duration: 0, - isMuted: false, - }); - }); - - it('handles active instances with no lastScheduledActions', () => { - const alert = mockAlert(); - const instance: RawAlertInstance = { - meta: {}, + const instance: AlertInstanceStatus = { + status: 'Active', + muted: false, }; expect(alertInstanceToListItem(fakeNow.getTime(), alert, 'id', instance)).toEqual({ @@ -214,9 +216,13 @@ describe('alertInstanceToListItem', () => { const alert = mockAlert({ mutedInstanceIds: ['id'], }); - expect(alertInstanceToListItem(fakeNow.getTime(), alert, 'id')).toEqual({ + const instance: AlertInstanceStatus = { + status: 'OK', + muted: true, + }; + expect(alertInstanceToListItem(fakeNow.getTime(), alert, 'id', instance)).toEqual({ instance: 'id', - status: { label: 'Inactive', healthColor: 'subdued' }, + status: { label: 'OK', healthColor: 'subdued' }, start: undefined, duration: 0, isMuted: true, @@ -247,23 +253,26 @@ function mockAlert(overloads: Partial = {}): Alert { }; } -function mockAlertState(overloads: Partial = {}): AlertTaskState { - return { - alertTypeState: { - some: 'value', - }, - alertInstances: { - first_instance: { - state: {}, - meta: { - lastScheduledActions: { - group: 'first_group', - date: new Date(), - }, - }, +function mockAlertStatus(overloads: Partial = {}): AlertStatus { + const status: AlertStatus = { + id: 'alert-id', + name: 'alert-name', + tags: ['tag-1', 'tag-2'], + alertTypeId: 'alert-type-id', + consumer: 'alert-consumer', + status: 'OK', + muteAll: false, + throttle: '', + enabled: true, + errorMessages: [], + statusStartDate: fake2MinutesAgo.toISOString(), + statusEndDate: fakeNow.toISOString(), + instances: { + foo: { + status: 'OK', + muted: false, }, - second_instance: {}, }, - ...overloads, }; + return { ...status, ...overloads }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances.tsx index e239188659178..77a3b454a1820 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances.tsx @@ -10,8 +10,8 @@ import { i18n } from '@kbn/i18n'; import { EuiBasicTable, EuiHealth, EuiSpacer, EuiSwitch } from '@elastic/eui'; // @ts-ignore import { RIGHT_ALIGNMENT, CENTER_ALIGNMENT } from '@elastic/eui/lib/services'; -import { padStart, difference, chunk } from 'lodash'; -import { Alert, AlertTaskState, RawAlertInstance, Pagination } from '../../../../types'; +import { padStart, chunk } from 'lodash'; +import { Alert, AlertStatus, AlertInstanceStatus, Pagination } from '../../../../types'; import { ComponentOpts as AlertApis, withBulkAlertOperations, @@ -21,7 +21,7 @@ import { DEFAULT_SEARCH_PAGE_SIZE } from '../../../constants'; type AlertInstancesProps = { alert: Alert; readOnly: boolean; - alertState: AlertTaskState; + alertStatus: AlertStatus; requestRefresh: () => Promise; durationEpoch?: number; } & Pick; @@ -113,7 +113,7 @@ function durationAsString(duration: Duration): string { export function AlertInstances({ alert, readOnly, - alertState: { alertInstances = {} }, + alertStatus, muteAlertInstance, unmuteAlertInstance, requestRefresh, @@ -124,15 +124,10 @@ export function AlertInstances({ size: DEFAULT_SEARCH_PAGE_SIZE, }); - const mergedAlertInstances = [ - ...Object.entries(alertInstances).map(([instanceId, instance]) => - alertInstanceToListItem(durationEpoch, alert, instanceId, instance) - ), - ...difference(alert.mutedInstanceIds, Object.keys(alertInstances)).map((instanceId) => - alertInstanceToListItem(durationEpoch, alert, instanceId) - ), - ]; - const pageOfAlertInstances = getPage(mergedAlertInstances, pagination); + const alertInstances = Object.entries(alertStatus.instances).map(([instanceId, instance]) => + alertInstanceToListItem(durationEpoch, alert, instanceId, instance) + ); + const pageOfAlertInstances = getPage(alertInstances, pagination); const onMuteAction = async (instance: AlertInstanceListItem) => { await (instance.isMuted @@ -155,7 +150,7 @@ export function AlertInstances({ pagination={{ pageIndex: pagination.index, pageSize: pagination.size, - totalItemCount: mergedAlertInstances.length, + totalItemCount: alertInstances.length, }} onChange={({ page: changedPage }: { page: Pagination }) => { setPagination(changedPage); @@ -197,29 +192,27 @@ const ACTIVE_LABEL = i18n.translate( const INACTIVE_LABEL = i18n.translate( 'xpack.triggersActionsUI.sections.alertDetails.alertInstancesList.status.inactive', - { defaultMessage: 'Inactive' } + { defaultMessage: 'OK' } ); -const durationSince = (durationEpoch: number, startTime?: number) => - startTime ? durationEpoch - startTime : 0; - export function alertInstanceToListItem( durationEpoch: number, alert: Alert, instanceId: string, - instance?: RawAlertInstance + instance: AlertInstanceStatus ): AlertInstanceListItem { - const isMuted = alert.mutedInstanceIds.findIndex((muted) => muted === instanceId) >= 0; + const isMuted = !!instance?.muted; + const status = + instance?.status === 'Active' + ? { label: ACTIVE_LABEL, healthColor: 'primary' } + : { label: INACTIVE_LABEL, healthColor: 'subdued' }; + const start = instance?.activeStartDate ? new Date(instance.activeStartDate) : undefined; + const duration = start ? durationEpoch - start.valueOf() : 0; return { instance: instanceId, - status: instance - ? { label: ACTIVE_LABEL, healthColor: 'primary' } - : { label: INACTIVE_LABEL, healthColor: 'subdued' }, - start: instance?.meta?.lastScheduledActions?.date, - duration: durationSince( - durationEpoch, - instance?.meta?.lastScheduledActions?.date?.getTime() ?? 0 - ), + status, + start, + duration, isMuted, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.test.tsx index 975856beba556..61af8f5478521 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.test.tsx @@ -7,17 +7,20 @@ import * as React from 'react'; import uuid from 'uuid'; import { shallow } from 'enzyme'; import { ToastsApi } from 'kibana/public'; -import { AlertInstancesRoute, getAlertState } from './alert_instances_route'; -import { Alert } from '../../../../types'; +import { AlertInstancesRoute, getAlertStatus } from './alert_instances_route'; +import { Alert, AlertStatus } from '../../../../types'; import { EuiLoadingSpinner } from '@elastic/eui'; +const fakeNow = new Date('2020-02-09T23:15:41.941Z'); +const fake2MinutesAgo = new Date('2020-02-09T23:13:41.941Z'); + jest.mock('../../../app_context', () => { const toastNotifications = jest.fn(); return { useAppDependencies: jest.fn(() => ({ toastNotifications })), }; }); -describe('alert_state_route', () => { +describe('alert_status_route', () => { it('render a loader while fetching data', () => { const alert = mockAlert(); @@ -34,25 +37,25 @@ describe('getAlertState useEffect handler', () => { jest.clearAllMocks(); }); - it('fetches alert state', async () => { + it('fetches alert status', async () => { const alert = mockAlert(); - const alertState = mockAlertState(); - const { loadAlertState } = mockApis(); - const { setAlertState } = mockStateSetter(); + const alertStatus = mockAlertStatus(); + const { loadAlertStatus } = mockApis(); + const { setAlertStatus } = mockStateSetter(); - loadAlertState.mockImplementationOnce(async () => alertState); + loadAlertStatus.mockImplementationOnce(async () => alertStatus); const toastNotifications = ({ addDanger: jest.fn(), } as unknown) as ToastsApi; - await getAlertState(alert.id, loadAlertState, setAlertState, toastNotifications); + await getAlertStatus(alert.id, loadAlertStatus, setAlertStatus, toastNotifications); - expect(loadAlertState).toHaveBeenCalledWith(alert.id); - expect(setAlertState).toHaveBeenCalledWith(alertState); + expect(loadAlertStatus).toHaveBeenCalledWith(alert.id); + expect(setAlertStatus).toHaveBeenCalledWith(alertStatus); }); - it('displays an error if the alert state isnt found', async () => { + it('displays an error if the alert status isnt found', async () => { const actionType = { id: '.server-log', name: 'Server log', @@ -69,34 +72,34 @@ describe('getAlertState useEffect handler', () => { ], }); - const { loadAlertState } = mockApis(); - const { setAlertState } = mockStateSetter(); + const { loadAlertStatus } = mockApis(); + const { setAlertStatus } = mockStateSetter(); - loadAlertState.mockImplementation(async () => { + loadAlertStatus.mockImplementation(async () => { throw new Error('OMG'); }); const toastNotifications = ({ addDanger: jest.fn(), } as unknown) as ToastsApi; - await getAlertState(alert.id, loadAlertState, setAlertState, toastNotifications); + await getAlertStatus(alert.id, loadAlertStatus, setAlertStatus, toastNotifications); expect(toastNotifications.addDanger).toHaveBeenCalledTimes(1); expect(toastNotifications.addDanger).toHaveBeenCalledWith({ - title: 'Unable to load alert state: OMG', + title: 'Unable to load alert status: OMG', }); }); }); function mockApis() { return { - loadAlertState: jest.fn(), + loadAlertStatus: jest.fn(), requestRefresh: jest.fn(), }; } function mockStateSetter() { return { - setAlertState: jest.fn(), + setAlertStatus: jest.fn(), }; } @@ -123,22 +126,26 @@ function mockAlert(overloads: Partial = {}): Alert { }; } -function mockAlertState(overloads: Partial = {}): any { - return { - alertTypeState: { - some: 'value', - }, - alertInstances: { - first_instance: { - state: {}, - meta: { - lastScheduledActions: { - group: 'first_group', - date: new Date(), - }, - }, +function mockAlertStatus(overloads: Partial = {}): any { + const status: AlertStatus = { + id: 'alert-id', + name: 'alert-name', + tags: ['tag-1', 'tag-2'], + alertTypeId: 'alert-type-id', + consumer: 'alert-consumer', + status: 'OK', + muteAll: false, + throttle: null, + enabled: true, + errorMessages: [], + statusStartDate: fake2MinutesAgo.toISOString(), + statusEndDate: fakeNow.toISOString(), + instances: { + foo: { + status: 'OK', + muted: false, }, - second_instance: {}, }, }; + return status; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.tsx index d8a7d18eb87a9..3afec45bcad64 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.tsx @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; import { ToastsApi } from 'kibana/public'; import React, { useState, useEffect } from 'react'; import { EuiLoadingSpinner } from '@elastic/eui'; -import { Alert, AlertTaskState } from '../../../../types'; +import { Alert, AlertStatus } from '../../../../types'; import { useAppDependencies } from '../../../app_context'; import { ComponentOpts as AlertApis, @@ -16,33 +16,33 @@ import { } from '../../common/components/with_bulk_alert_api_operations'; import { AlertInstancesWithApi as AlertInstances } from './alert_instances'; -type WithAlertStateProps = { +type WithAlertStatusProps = { alert: Alert; readOnly: boolean; requestRefresh: () => Promise; -} & Pick; +} & Pick; -export const AlertInstancesRoute: React.FunctionComponent = ({ +export const AlertInstancesRoute: React.FunctionComponent = ({ alert, readOnly, requestRefresh, - loadAlertState, + loadAlertStatus: loadAlertStatus, }) => { const { toastNotifications } = useAppDependencies(); - const [alertState, setAlertState] = useState(null); + const [alertStatus, setAlertStatus] = useState(null); useEffect(() => { - getAlertState(alert.id, loadAlertState, setAlertState, toastNotifications); + getAlertStatus(alert.id, loadAlertStatus, setAlertStatus, toastNotifications); // eslint-disable-next-line react-hooks/exhaustive-deps }, [alert]); - return alertState ? ( + return alertStatus ? ( ) : (
= ); }; -export async function getAlertState( +export async function getAlertStatus( alertId: string, - loadAlertState: AlertApis['loadAlertState'], - setAlertState: React.Dispatch>, + loadAlertStatus: AlertApis['loadAlertStatus'], + setAlertStatus: React.Dispatch>, toastNotifications: Pick ) { try { - const loadedState = await loadAlertState(alertId); - setAlertState(loadedState); + const loadedStatus = await loadAlertStatus(alertId); + setAlertStatus(loadedStatus); } catch (e) { toastNotifications.addDanger({ title: i18n.translate( 'xpack.triggersActionsUI.sections.alertDetails.unableToLoadAlertStateMessage', { - defaultMessage: 'Unable to load alert state: {message}', + defaultMessage: 'Unable to load alert status: {message}', values: { message: e.message, }, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.tsx index 0c6f71120cc2e..fd8b35a96bdf0 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.tsx @@ -6,7 +6,13 @@ import React from 'react'; -import { Alert, AlertType, AlertTaskState, AlertingFrameworkHealth } from '../../../../types'; +import { + Alert, + AlertType, + AlertTaskState, + AlertStatus, + AlertingFrameworkHealth, +} from '../../../../types'; import { useAppDependencies } from '../../../app_context'; import { deleteAlerts, @@ -22,6 +28,7 @@ import { unmuteAlertInstance, loadAlert, loadAlertState, + loadAlertStatus, loadAlertTypes, health, } from '../../../lib/alert_api'; @@ -51,6 +58,7 @@ export interface ComponentOpts { }>; loadAlert: (id: Alert['id']) => Promise; loadAlertState: (id: Alert['id']) => Promise; + loadAlertStatus: (id: Alert['id']) => Promise; loadAlertTypes: () => Promise; getHealth: () => Promise; } @@ -119,6 +127,7 @@ export function withBulkAlertOperations( deleteAlert={async (alert: Alert) => deleteAlerts({ http, ids: [alert.id] })} loadAlert={async (alertId: Alert['id']) => loadAlert({ http, alertId })} loadAlertState={async (alertId: Alert['id']) => loadAlertState({ http, alertId })} + loadAlertStatus={async (alertId: Alert['id']) => loadAlertStatus({ http, alertId })} loadAlertTypes={async () => loadAlertTypes({ http })} getHealth={async () => health({ http })} /> diff --git a/x-pack/plugins/triggers_actions_ui/public/types.ts b/x-pack/plugins/triggers_actions_ui/public/types.ts index a42a9f56a751f..0c0d99eed4e7b 100644 --- a/x-pack/plugins/triggers_actions_ui/public/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/types.ts @@ -12,10 +12,20 @@ import { SanitizedAlert as Alert, AlertAction, AlertTaskState, + AlertStatus, + AlertInstanceStatus, RawAlertInstance, AlertingFrameworkHealth, } from '../../alerts/common'; -export { Alert, AlertAction, AlertTaskState, RawAlertInstance, AlertingFrameworkHealth }; +export { + Alert, + AlertAction, + AlertTaskState, + AlertStatus, + AlertInstanceStatus, + RawAlertInstance, + AlertingFrameworkHealth, +}; export { ActionType }; export type ActionTypeIndex = Record; diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts index 269a9d3a504a2..40b2c33a702aa 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts @@ -310,23 +310,31 @@ export function defineAlertTypes( defaultActionGroupId: 'default', async executor(alertExecutorOptions: AlertExecutorOptions) { const { services, state, params } = alertExecutorOptions; - const pattern = params.pattern; - if (!Array.isArray(pattern)) throw new Error('pattern is not an array'); - if (pattern.length === 0) throw new Error('pattern is empty'); + const pattern = params.pattern as Record; + if (typeof pattern !== 'object') throw new Error('pattern is not an object'); + let maxPatternLength = 0; + for (const [instanceId, instancePattern] of Object.entries(pattern)) { + if (!Array.isArray(instancePattern)) { + throw new Error(`pattern for instance ${instanceId} is not an array`); + } + maxPatternLength = Math.max(maxPatternLength, instancePattern.length); + } // get the pattern index, return if past it const patternIndex = state.patternIndex ?? 0; - if (patternIndex > pattern.length) { + if (patternIndex >= maxPatternLength) { return { patternIndex }; } // fire if pattern says to - if (pattern[patternIndex]) { - services.alertInstanceFactory('instance').scheduleActions('default'); + for (const [instanceId, instancePattern] of Object.entries(pattern)) { + if (instancePattern[patternIndex]) { + services.alertInstanceFactory(instanceId).scheduleActions('default'); + } } return { - patternIndex: (patternIndex + 1) % pattern.length, + patternIndex: patternIndex + 1, }; }, }; diff --git a/x-pack/test/alerting_api_integration/common/lib/get_event_log.ts b/x-pack/test/alerting_api_integration/common/lib/get_event_log.ts index 99f51ff244546..aebcd854514b2 100644 --- a/x-pack/test/alerting_api_integration/common/lib/get_event_log.ts +++ b/x-pack/test/alerting_api_integration/common/lib/get_event_log.ts @@ -25,7 +25,7 @@ export async function getEventLog(params: GetEventLogParams): Promise { + const objectRemover = new ObjectRemover(supertest); + + afterEach(() => objectRemover.removeAll()); + + for (const scenario of UserAtSpaceScenarios) { + const { user, space } = scenario; + describe(scenario.id, () => { + it('should handle getAlertStatus alert request appropriately', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData()) + .expect(200); + objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + + const response = await supertestWithoutAuth + .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}/status`) + .auth(user.username, user.password); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + expect(response.statusCode).to.eql(403); + expect(response.body).to.eql({ + error: 'Forbidden', + message: getConsumerUnauthorizedErrorMessage('get', 'test.noop', 'alertsFixture'), + statusCode: 403, + }); + break; + case 'global_read at space1': + case 'superuser at space1': + case 'space_1_all at space1': + case 'space_1_all_alerts_none_actions at space1': + case 'space_1_all_with_restricted_fixture at space1': + expect(response.statusCode).to.eql(200); + const { id, statusStartDate, statusEndDate } = response.body; + expect(id).to.equal(createdAlert.id); + expect(Date.parse(statusStartDate)).to.be.lessThan(Date.parse(statusEndDate)); + + const stableBody = omit(response.body, [ + 'id', + 'statusStartDate', + 'statusEndDate', + 'lastRun', + ]); + expect(stableBody).to.eql({ + name: 'abc', + tags: ['foo'], + alertTypeId: 'test.noop', + consumer: 'alertsFixture', + status: 'OK', + muteAll: false, + throttle: '1m', + enabled: true, + errorMessages: [], + instances: {}, + }); + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); + + it('should handle getAlertStatus alert request appropriately when unauthorized', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .set('kbn-xsrf', 'foo') + .send( + getTestAlertData({ + alertTypeId: 'test.unrestricted-noop', + consumer: 'alertsFixture', + }) + ) + .expect(200); + objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + + const response = await supertestWithoutAuth + .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}/status`) + .auth(user.username, user.password); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + expect(response.statusCode).to.eql(403); + expect(response.body).to.eql({ + error: 'Forbidden', + message: getConsumerUnauthorizedErrorMessage( + 'get', + 'test.unrestricted-noop', + 'alertsFixture' + ), + statusCode: 403, + }); + break; + case 'space_1_all at space1': + case 'space_1_all_alerts_none_actions at space1': + expect(response.statusCode).to.eql(403); + expect(response.body).to.eql({ + error: 'Forbidden', + message: getProducerUnauthorizedErrorMessage( + 'get', + 'test.unrestricted-noop', + 'alertsRestrictedFixture' + ), + statusCode: 403, + }); + break; + case 'global_read at space1': + case 'superuser at space1': + case 'space_1_all_with_restricted_fixture at space1': + expect(response.statusCode).to.eql(200); + expect(response.body).to.key('id', 'instances', 'errorMessages'); + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); + + it(`shouldn't getAlertStatus for an alert from another space`, async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData()) + .expect(200); + objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); + + const response = await supertestWithoutAuth + .get(`${getUrlPrefix('other')}/api/alerts/alert/${createdAlert.id}/status`) + .auth(user.username, user.password); + + expect(response.statusCode).to.eql(404); + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + case 'space_1_all at space1': + case 'space_1_all_alerts_none_actions at space1': + case 'space_1_all_with_restricted_fixture at space1': + case 'global_read at space1': + case 'superuser at space1': + expect(response.body).to.eql({ + statusCode: 404, + error: 'Not Found', + message: `Saved object [alert/${createdAlert.id}] not found`, + }); + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); + + it(`should handle getAlertStatus request appropriately when alert doesn't exist`, async () => { + const response = await supertestWithoutAuth + .get(`${getUrlPrefix(space.id)}/api/alerts/alert/1/status`) + .auth(user.username, user.password); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + case 'global_read at space1': + case 'superuser at space1': + case 'space_1_all at space1': + case 'space_1_all_alerts_none_actions at space1': + case 'space_1_all_with_restricted_fixture at space1': + expect(response.statusCode).to.eql(404); + expect(response.body).to.eql({ + statusCode: 404, + error: 'Not Found', + message: 'Saved object [alert/1] not found', + }); + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); + }); + } + }); +} diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts index 4cd5f0805121c..45fa075a65978 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts @@ -16,6 +16,7 @@ export default function alertingTests({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./enable')); loadTestFile(require.resolve('./get')); loadTestFile(require.resolve('./get_alert_state')); + loadTestFile(require.resolve('./get_alert_status')); loadTestFile(require.resolve('./list_alert_types')); loadTestFile(require.resolve('./mute_all')); loadTestFile(require.resolve('./mute_instance')); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/event_log.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/event_log.ts index 79d25d8d10436..a5dff437283ae 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/event_log.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/event_log.ts @@ -35,7 +35,9 @@ export default function eventLogTests({ getService }: FtrProviderContext) { .expect(200); // pattern of when the alert should fire - const pattern = [false, true, true]; + const pattern = { + instance: [false, true, true], + }; const response = await supertest .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) @@ -70,7 +72,13 @@ export default function eventLogTests({ getService }: FtrProviderContext) { type: 'alert', id: alertId, provider: 'alerting', - actions: ['execute', 'execute-action', 'new-instance', 'resolved-instance'], + actions: [ + 'execute', + 'execute-action', + 'new-instance', + 'active-instance', + 'resolved-instance', + ], }); }); @@ -120,24 +128,27 @@ export default function eventLogTests({ getService }: FtrProviderContext) { }); break; case 'new-instance': - validateEvent(event, { - spaceId: Spaces.space1.id, - savedObjects: [{ type: 'alert', id: alertId, rel: 'primary' }], - message: `test.patternFiring:${alertId}: 'abc' created new instance: 'instance'`, - }); + validateInstanceEvent(event, `created new instance: 'instance'`); break; case 'resolved-instance': - validateEvent(event, { - spaceId: Spaces.space1.id, - savedObjects: [{ type: 'alert', id: alertId, rel: 'primary' }], - message: `test.patternFiring:${alertId}: 'abc' resolved instance: 'instance'`, - }); + validateInstanceEvent(event, `resolved instance: 'instance'`); + break; + case 'active-instance': + validateInstanceEvent(event, `active instance: 'instance'`); break; // this will get triggered as we add new event actions default: throw new Error(`unexpected event action "${event?.event?.action}"`); } } + + function validateInstanceEvent(event: IValidatedEvent, subMessage: string) { + validateEvent(event, { + spaceId: Spaces.space1.id, + savedObjects: [{ type: 'alert', id: alertId, rel: 'primary' }], + message: `test.patternFiring:${alertId}: 'abc' ${subMessage}`, + }); + } }); it('should generate events for execution errors', async () => { diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_alert_status.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_alert_status.ts new file mode 100644 index 0000000000000..341313ce55c60 --- /dev/null +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_alert_status.ts @@ -0,0 +1,261 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { omit } from 'lodash'; + +import { Spaces } from '../../scenarios'; +import { + getUrlPrefix, + ObjectRemover, + getTestAlertData, + AlertUtils, + getEventLog, +} from '../../../common/lib'; +import { FtrProviderContext } from '../../../common/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function createGetAlertStatusTests({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const retry = getService('retry'); + const alertUtils = new AlertUtils({ space: Spaces.space1, supertestWithoutAuth }); + + describe('getAlertStatus', () => { + const objectRemover = new ObjectRemover(supertest); + + afterEach(() => objectRemover.removeAll()); + + it(`handles non-existant alert`, async () => { + await supertest + .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/1/status`) + .expect(404, { + statusCode: 404, + error: 'Not Found', + message: 'Saved object [alert/1] not found', + }); + }); + + it('handles no-op alert', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData()) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + + await waitForEvents(createdAlert.id, ['execute']); + const response = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/status` + ); + + expect(response.status).to.eql(200); + + const { statusStartDate, statusEndDate } = response.body; + expect(Date.parse(statusStartDate)).to.be.lessThan(Date.parse(statusEndDate)); + + const stableBody = omit(response.body, ['statusStartDate', 'statusEndDate', 'lastRun']); + expect(stableBody).to.eql({ + id: createdAlert.id, + name: 'abc', + tags: ['foo'], + alertTypeId: 'test.noop', + consumer: 'alertsFixture', + status: 'OK', + muteAll: false, + throttle: '1m', + enabled: true, + errorMessages: [], + instances: {}, + }); + }); + + it('handles no-op alert without waiting for execution event', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData()) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + + const response = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/status` + ); + + expect(response.status).to.eql(200); + + const { statusStartDate, statusEndDate } = response.body; + expect(Date.parse(statusStartDate)).to.be.lessThan(Date.parse(statusEndDate)); + + const stableBody = omit(response.body, ['statusStartDate', 'statusEndDate', 'lastRun']); + expect(stableBody).to.eql({ + id: createdAlert.id, + name: 'abc', + tags: ['foo'], + alertTypeId: 'test.noop', + consumer: 'alertsFixture', + status: 'OK', + muteAll: false, + throttle: '1m', + enabled: true, + errorMessages: [], + instances: {}, + }); + }); + + it('handles dateStart parameter', async () => { + const dateStart = '2020-08-08T08:08:08.008Z'; + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData()) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + + await waitForEvents(createdAlert.id, ['execute']); + const response = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${ + createdAlert.id + }/status?dateStart=${dateStart}` + ); + expect(response.status).to.eql(200); + const { statusStartDate, statusEndDate } = response.body; + expect(Date.parse(statusStartDate)).to.be.lessThan(Date.parse(statusEndDate)); + expect(statusStartDate).to.be(dateStart); + }); + + it('handles invalid dateStart parameter', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData()) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + + await waitForEvents(createdAlert.id, ['execute']); + const dateStart = 'X0X0-08-08T08:08:08.008Z'; + const response = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${ + createdAlert.id + }/status?dateStart=${dateStart}` + ); + expect(response.status).to.eql(400); + expect(response.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: 'Invalid date for parameter dateStart: "X0X0-08-08T08:08:08.008Z"', + }); + }); + + it('handles muted instances', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData()) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + + await alertUtils.muteInstance(createdAlert.id, '1'); + await waitForEvents(createdAlert.id, ['execute']); + const response = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/status` + ); + + expect(response.status).to.eql(200); + expect(response.body.instances).to.eql({ + '1': { + status: 'OK', + muted: true, + }, + }); + }); + + it('handles alert errors', async () => { + const dateNow = Date.now(); + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData({ alertTypeId: 'test.throw' })) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + + await waitForEvents(createdAlert.id, ['execute']); + const response = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/status` + ); + const { errorMessages } = response.body; + expect(errorMessages.length).to.be.greaterThan(0); + const errorMessage = errorMessages[0]; + expect(Date.parse(errorMessage.date)).to.be.greaterThan(dateNow); + expect(errorMessage.message).to.be('this alert is intended to fail'); + }); + + it('handles multi-instance status', async () => { + // pattern of when the alert should fire + const pattern = { + instanceA: [true, true, true, true], + instanceB: [true, true, false, false], + instanceC: [true, true, true, true], + }; + + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert`) + .set('kbn-xsrf', 'foo') + .send( + getTestAlertData({ + alertTypeId: 'test.patternFiring', + params: { pattern }, + schedule: { interval: '1s' }, + }) + ) + .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); + + await alertUtils.muteInstance(createdAlert.id, 'instanceC'); + await alertUtils.muteInstance(createdAlert.id, 'instanceD'); + await waitForEvents(createdAlert.id, ['new-instance', 'resolved-instance']); + const response = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/status` + ); + + const actualInstances = response.body.instances; + const expectedInstances = { + instanceA: { + status: 'Active', + muted: false, + activeStartDate: actualInstances.instanceA.activeStartDate, + }, + instanceB: { + status: 'OK', + muted: false, + }, + instanceC: { + status: 'Active', + muted: true, + activeStartDate: actualInstances.instanceC.activeStartDate, + }, + instanceD: { + status: 'OK', + muted: true, + }, + }; + expect(actualInstances).to.eql(expectedInstances); + }); + }); + + async function waitForEvents(id: string, actions: string[]) { + await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: Spaces.space1.id, + type: 'alert', + id, + provider: 'alerting', + actions, + }); + }); + } +} diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts index a23f0fa835313..b927b563eb54a 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts @@ -16,6 +16,7 @@ export default function alertingTests({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./find')); loadTestFile(require.resolve('./get')); loadTestFile(require.resolve('./get_alert_state')); + loadTestFile(require.resolve('./get_alert_status')); loadTestFile(require.resolve('./list_alert_types')); loadTestFile(require.resolve('./event_log')); loadTestFile(require.resolve('./mute_all')); diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts index d86d272c1da8c..1579d041c9f58 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts @@ -361,7 +361,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // await first run to complete so we have an initial state await retry.try(async () => { - const { alertInstances } = await alerting.alerts.getAlertState(alert.id); + const { instances: alertInstances } = await alerting.alerts.getAlertStatus(alert.id); expect(Object.keys(alertInstances).length).to.eql(instances.length); }); }); @@ -373,15 +373,11 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Verify content await testSubjects.existOrFail('alertInstancesList'); - const { alertInstances } = await alerting.alerts.getAlertState(alert.id); + const status = await alerting.alerts.getAlertStatus(alert.id); const dateOnAllInstancesFromApiResponse = mapValues( - alertInstances, - ({ - meta: { - lastScheduledActions: { date }, - }, - }) => date + status.instances, + (instance) => instance.activeStartDate ); log.debug( @@ -471,7 +467,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ).to.eql([ { instance: 'eu-east', - status: 'Inactive', + status: 'OK', start: '', duration: '', }, @@ -574,7 +570,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // await first run to complete so we have an initial state await retry.try(async () => { - const { alertInstances } = await alerting.alerts.getAlertState(alert.id); + const { instances: alertInstances } = await alerting.alerts.getAlertStatus(alert.id); expect(Object.keys(alertInstances).length).to.eql(instances.length); }); @@ -595,7 +591,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Verify content await testSubjects.existOrFail('alertInstancesList'); - const { alertInstances } = await alerting.alerts.getAlertState(alert.id); + const { instances: alertInstances } = await alerting.alerts.getAlertStatus(alert.id); const items = await pageObjects.alertDetailsUI.getAlertInstancesList(); expect(items.length).to.eql(PAGE_SIZE); @@ -608,7 +604,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Verify content await testSubjects.existOrFail('alertInstancesList'); - const { alertInstances } = await alerting.alerts.getAlertState(alert.id); + const { instances: alertInstances } = await alerting.alerts.getAlertStatus(alert.id); await pageObjects.alertDetailsUI.clickPaginationNextPage(); diff --git a/x-pack/test/functional_with_es_ssl/services/alerting/alerts.ts b/x-pack/test/functional_with_es_ssl/services/alerting/alerts.ts index 23a4529139c53..c6fbdecf77f16 100644 --- a/x-pack/test/functional_with_es_ssl/services/alerting/alerts.ts +++ b/x-pack/test/functional_with_es_ssl/services/alerting/alerts.ts @@ -8,6 +8,21 @@ import axios, { AxiosInstance } from 'axios'; import util from 'util'; import { ToolingLog } from '@kbn/dev-utils'; +export interface AlertStatus { + status: string; + muted: boolean; + enabled: boolean; + lastRun?: string; + errorMessage?: string; + instances: Record; +} + +export interface AlertInstanceStatus { + status: string; + muted: boolean; + activeStartDate?: string; +} + export class Alerts { private log: ToolingLog; private axios: AxiosInstance; @@ -141,10 +156,10 @@ export class Alerts { this.log.debug(`deleted alert ${alert.id}`); } - public async getAlertState(id: string) { + public async getAlertStatus(id: string): Promise { this.log.debug(`getting alert ${id} state`); - const { data } = await this.axios.get(`/api/alerts/alert/${id}/state`); + const { data } = await this.axios.get(`/api/alerts/alert/${id}/status`); return data; } From f6f59ec261d55e77d48b766cc0d3d64033b522d7 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Fri, 14 Aug 2020 15:46:55 +0300 Subject: [PATCH 40/53] Drilldowns for TSVB / Vega / Timelion (#74848) * Drilldowns for TSVB / Vega Closes: #60611 * fix PR comment * fix PR comments * add support for Timelion * rename vis.API.events.brush -> vis.API.events.applyFilter --- .../public/components/chart.tsx | 2 + .../public/components/panel.tsx | 22 ++++++++--- .../public/components/timelion_vis.tsx | 1 + .../public/timelion_vis_type.tsx | 5 +++ .../application/components/vis_editor.js | 2 +- ...r.test.js => create_brush_handler.test.ts} | 37 ++++++++++--------- ...ush_handler.js => create_brush_handler.ts} | 25 +++++++++---- .../public/metrics_type.ts | 4 ++ src/plugins/vis_type_vega/public/vega_type.ts | 4 ++ .../public/vega_view/vega_base_view.js | 21 ++++++++++- .../public/vega_visualization.js | 1 + .../public/vega_visualization.test.js | 5 +++ .../public/embeddable/events.ts | 8 +++- .../public/embeddable/visualize_embeddable.ts | 21 ++++++++--- .../visualizations/public/expressions/vis.ts | 5 +++ src/plugins/visualizations/public/index.ts | 1 + 16 files changed, 124 insertions(+), 40 deletions(-) rename src/plugins/vis_type_timeseries/public/application/lib/{create_brush_handler.test.js => create_brush_handler.test.ts} (58%) rename src/plugins/vis_type_timeseries/public/application/lib/{create_brush_handler.js => create_brush_handler.ts} (68%) diff --git a/src/plugins/vis_type_timelion/public/components/chart.tsx b/src/plugins/vis_type_timelion/public/components/chart.tsx index a8b03bdbc8b7e..15a376d4e9638 100644 --- a/src/plugins/vis_type_timelion/public/components/chart.tsx +++ b/src/plugins/vis_type_timelion/public/components/chart.tsx @@ -21,8 +21,10 @@ import React from 'react'; import { Sheet } from '../helpers/timelion_request_handler'; import { Panel } from './panel'; +import { ExprVisAPIEvents } from '../../../visualizations/public'; interface ChartComponentProp { + applyFilter: ExprVisAPIEvents['applyFilter']; interval: string; renderComplete(): void; seriesList: Sheet; diff --git a/src/plugins/vis_type_timelion/public/components/panel.tsx b/src/plugins/vis_type_timelion/public/components/panel.tsx index f4f1cd84613be..9c30a6b75d6db 100644 --- a/src/plugins/vis_type_timelion/public/components/panel.tsx +++ b/src/plugins/vis_type_timelion/public/components/panel.tsx @@ -33,10 +33,12 @@ import { colors, Axis, } from '../helpers/panel_utils'; + import { Series, Sheet } from '../helpers/timelion_request_handler'; import { tickFormatters } from '../helpers/tick_formatters'; import { generateTicksProvider } from '../helpers/tick_generator'; import { TimelionVisDependencies } from '../plugin'; +import { ExprVisAPIEvents } from '../../../visualizations/public'; interface CrosshairPlot extends jquery.flot.plot { setCrosshair: (pos: Position) => void; @@ -44,6 +46,7 @@ interface CrosshairPlot extends jquery.flot.plot { } interface PanelProps { + applyFilter: ExprVisAPIEvents['applyFilter']; interval: string; seriesList: Sheet; renderComplete(): void; @@ -72,7 +75,7 @@ const DEBOUNCE_DELAY = 50; // ensure legend is the same height with or without a caption so legend items do not move around const emptyCaption = '
'; -function Panel({ interval, seriesList, renderComplete }: PanelProps) { +function Panel({ interval, seriesList, renderComplete, applyFilter }: PanelProps) { const kibana = useKibana(); const [chart, setChart] = useState(() => cloneDeep(seriesList.list)); const [canvasElem, setCanvasElem] = useState(); @@ -346,12 +349,21 @@ function Panel({ interval, seriesList, renderComplete }: PanelProps) { const plotSelectedHandler = useCallback( (event: JQuery.TriggeredEvent, ranges: Ranges) => { - kibana.services.timefilter.setTime({ - from: moment(ranges.xaxis.from), - to: moment(ranges.xaxis.to), + applyFilter({ + timeFieldName: '*', + filters: [ + { + range: { + '*': { + gte: ranges.xaxis.from, + lte: ranges.xaxis.to, + }, + }, + }, + ], }); }, - [kibana.services.timefilter] + [applyFilter] ); useEffect(() => { diff --git a/src/plugins/vis_type_timelion/public/components/timelion_vis.tsx b/src/plugins/vis_type_timelion/public/components/timelion_vis.tsx index 4bb07fe74ee82..aa594c749b600 100644 --- a/src/plugins/vis_type_timelion/public/components/timelion_vis.tsx +++ b/src/plugins/vis_type_timelion/public/components/timelion_vis.tsx @@ -38,6 +38,7 @@ function TimelionVisComponent(props: TimelionVisComponentProp) { return (
{ + return [VIS_EVENT_TO_TRIGGER.applyFilter]; + }, options: { showIndexSelection: false, showQueryBar: false, diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_editor.js b/src/plugins/vis_type_timeseries/public/application/components/vis_editor.js index 300e70f3ae0c0..50585869862ee 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/vis_editor.js +++ b/src/plugins/vis_type_timeseries/public/application/components/vis_editor.js @@ -50,7 +50,7 @@ export class VisEditor extends Component { visFields: props.visFields, extractedIndexPatterns: [''], }; - this.onBrush = createBrushHandler(getDataStart().query.timefilter.timefilter); + this.onBrush = createBrushHandler((data) => props.vis.API.events.applyFilter(data)); this.visDataSubject = new Rx.BehaviorSubject(this.props.visData); this.visData$ = this.visDataSubject.asObservable().pipe(share()); diff --git a/src/plugins/vis_type_timeseries/public/application/lib/create_brush_handler.test.js b/src/plugins/vis_type_timeseries/public/application/lib/create_brush_handler.test.ts similarity index 58% rename from src/plugins/vis_type_timeseries/public/application/lib/create_brush_handler.test.js rename to src/plugins/vis_type_timeseries/public/application/lib/create_brush_handler.test.ts index 6ae01a384e7ca..a9568b5be9d3f 100644 --- a/src/plugins/vis_type_timeseries/public/application/lib/create_brush_handler.test.js +++ b/src/plugins/vis_type_timeseries/public/application/lib/create_brush_handler.test.ts @@ -18,28 +18,31 @@ */ import { createBrushHandler } from './create_brush_handler'; -import moment from 'moment'; +import { ExprVisAPIEvents } from '../../../../visualizations/public'; describe('brushHandler', () => { - let mockTimefilter; - let onBrush; + let onBrush: ReturnType; + let applyFilter: ExprVisAPIEvents['applyFilter']; beforeEach(() => { - mockTimefilter = { - time: {}, - setTime: function (time) { - this.time = time; - }, - }; - onBrush = createBrushHandler(mockTimefilter); + applyFilter = jest.fn(); + + onBrush = createBrushHandler(applyFilter); }); - it('returns brushHandler() that updates timefilter', () => { - const from = '2017-01-01T00:00:00Z'; - const to = '2017-01-01T00:10:00Z'; - onBrush(from, to); - expect(mockTimefilter.time.from).toEqual(moment(from).toISOString()); - expect(mockTimefilter.time.to).toEqual(moment(to).toISOString()); - expect(mockTimefilter.time.mode).toEqual('absolute'); + test('returns brushHandler() should updates timefilter through vis.API.events.applyFilter', () => { + const gte = '2017-01-01T00:00:00Z'; + const lte = '2017-01-01T00:10:00Z'; + + onBrush(gte, lte); + + expect(applyFilter).toHaveBeenCalledWith({ + timeFieldName: '*', + filters: [ + { + range: { '*': { gte: '2017-01-01T00:00:00Z', lte: '2017-01-01T00:10:00Z' } }, + }, + ], + }); }); }); diff --git a/src/plugins/vis_type_timeseries/public/application/lib/create_brush_handler.js b/src/plugins/vis_type_timeseries/public/application/lib/create_brush_handler.ts similarity index 68% rename from src/plugins/vis_type_timeseries/public/application/lib/create_brush_handler.js rename to src/plugins/vis_type_timeseries/public/application/lib/create_brush_handler.ts index 452e85c6405fe..38002c7552952 100644 --- a/src/plugins/vis_type_timeseries/public/application/lib/create_brush_handler.js +++ b/src/plugins/vis_type_timeseries/public/application/lib/create_brush_handler.ts @@ -17,14 +17,23 @@ * under the License. */ -import moment from 'moment'; +import { ExprVisAPIEvents } from '../../../../visualizations/public'; -const TIME_MODE = 'absolute'; - -export const createBrushHandler = (timefilter) => (from, to) => { - timefilter.setTime({ - from: moment(from).toISOString(), - to: moment(to).toISOString(), - mode: TIME_MODE, +export const createBrushHandler = (applyFilter: ExprVisAPIEvents['applyFilter']) => ( + gte: string, + lte: string +) => { + return applyFilter({ + timeFieldName: '*', + filters: [ + { + range: { + '*': { + gte, + lte, + }, + }, + }, + ], }); }; diff --git a/src/plugins/vis_type_timeseries/public/metrics_type.ts b/src/plugins/vis_type_timeseries/public/metrics_type.ts index 44b0334a37871..d6621870fef67 100644 --- a/src/plugins/vis_type_timeseries/public/metrics_type.ts +++ b/src/plugins/vis_type_timeseries/public/metrics_type.ts @@ -25,6 +25,7 @@ import { EditorController } from './application'; // @ts-ignore import { PANEL_TYPES } from '../common/panel_types'; import { VisEditor } from './application/components/vis_editor_lazy'; +import { VIS_EVENT_TO_TRIGGER } from '../../visualizations/public'; export const metricsVisDefinition = { name: 'metrics', @@ -78,6 +79,9 @@ export const metricsVisDefinition = { showIndexSelection: false, }, requestHandler: metricsRequestHandler, + getSupportedTriggers: () => { + return [VIS_EVENT_TO_TRIGGER.applyFilter]; + }, inspectorAdapters: {}, responseHandler: 'none', }; diff --git a/src/plugins/vis_type_vega/public/vega_type.ts b/src/plugins/vis_type_vega/public/vega_type.ts index d69eb3cfba282..f49816017b684 100644 --- a/src/plugins/vis_type_vega/public/vega_type.ts +++ b/src/plugins/vis_type_vega/public/vega_type.ts @@ -27,6 +27,7 @@ import { createVegaRequestHandler } from './vega_request_handler'; import { createVegaVisualization } from './vega_visualization'; import { getDefaultSpec } from './default_spec'; import { createInspectorAdapters } from './vega_inspector'; +import { VIS_EVENT_TO_TRIGGER } from '../../visualizations/public'; export const createVegaTypeDefinition = (dependencies: VegaVisualizationDependencies) => { const requestHandler = createVegaRequestHandler(dependencies); @@ -54,6 +55,9 @@ export const createVegaTypeDefinition = (dependencies: VegaVisualizationDependen showQueryBar: true, showFilterBar: true, }, + getSupportedTriggers: () => { + return [VIS_EVENT_TO_TRIGGER.applyFilter]; + }, stage: 'experimental', inspectorAdapters: createInspectorAdapters, }; diff --git a/src/plugins/vis_type_vega/public/vega_view/vega_base_view.js b/src/plugins/vis_type_vega/public/vega_view/vega_base_view.js index 4596b47364494..a2a973d232de0 100644 --- a/src/plugins/vis_type_vega/public/vega_view/vega_base_view.js +++ b/src/plugins/vis_type_vega/public/vega_view/vega_base_view.js @@ -63,6 +63,7 @@ export class VegaBaseView { this._parser = opts.vegaParser; this._serviceSettings = opts.serviceSettings; this._filterManager = opts.filterManager; + this._applyFilter = opts.applyFilter; this._timefilter = opts.timefilter; this._findIndex = opts.findIndex; this._view = null; @@ -263,7 +264,8 @@ export class VegaBaseView { async addFilterHandler(query, index) { const indexId = await this._findIndex(index); const filter = esFilters.buildQueryFilter(query, indexId); - this._filterManager.addFilters(filter); + + this._applyFilter({ filters: [filter] }); } /** @@ -298,7 +300,22 @@ export class VegaBaseView { * @param {number|string|Date} end */ setTimeFilterHandler(start, end) { - this._timefilter.setTime(VegaBaseView._parseTimeRange(start, end)); + const { from, to, mode } = VegaBaseView._parseTimeRange(start, end); + + this._applyFilter({ + timeFieldName: '*', + filters: [ + { + range: { + '*': { + mode, + gte: from, + lte: to, + }, + }, + }, + ], + }); } /** diff --git a/src/plugins/vis_type_vega/public/vega_visualization.js b/src/plugins/vis_type_vega/public/vega_visualization.js index 1fcb89f04457d..d6db0f9ea239f 100644 --- a/src/plugins/vis_type_vega/public/vega_visualization.js +++ b/src/plugins/vis_type_vega/public/vega_visualization.js @@ -106,6 +106,7 @@ export const createVegaVisualization = ({ serviceSettings }) => const { timefilter } = this.dataPlugin.query.timefilter; const vegaViewParams = { parentEl: this._el, + applyFilter: this._vis.API.events.applyFilter, vegaParser, serviceSettings, filterManager, diff --git a/src/plugins/vis_type_vega/public/vega_visualization.test.js b/src/plugins/vis_type_vega/public/vega_visualization.test.js index 3e318fa22c195..0912edf9503a6 100644 --- a/src/plugins/vis_type_vega/public/vega_visualization.test.js +++ b/src/plugins/vis_type_vega/public/vega_visualization.test.js @@ -105,6 +105,11 @@ describe('VegaVisualizations', () => { vis = { type: vegaVisType, + API: { + events: { + applyFilter: jest.fn(), + }, + }, }; }); diff --git a/src/plugins/visualizations/public/embeddable/events.ts b/src/plugins/visualizations/public/embeddable/events.ts index 0957895a21403..52cac59fbffaa 100644 --- a/src/plugins/visualizations/public/embeddable/events.ts +++ b/src/plugins/visualizations/public/embeddable/events.ts @@ -17,14 +17,20 @@ * under the License. */ -import { SELECT_RANGE_TRIGGER, VALUE_CLICK_TRIGGER } from '../../../../plugins/ui_actions/public'; +import { + APPLY_FILTER_TRIGGER, + SELECT_RANGE_TRIGGER, + VALUE_CLICK_TRIGGER, +} from '../../../../plugins/ui_actions/public'; export interface VisEventToTrigger { + ['applyFilter']: typeof APPLY_FILTER_TRIGGER; ['brush']: typeof SELECT_RANGE_TRIGGER; ['filter']: typeof VALUE_CLICK_TRIGGER; } export const VIS_EVENT_TO_TRIGGER: VisEventToTrigger = { + applyFilter: APPLY_FILTER_TRIGGER, brush: SELECT_RANGE_TRIGGER, filter: VALUE_CLICK_TRIGGER, }; diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts index cc24c0509fbc1..80e577930fa8d 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts @@ -310,12 +310,21 @@ export class VisualizeEmbeddable extends Embeddable void; brush: (data: any) => void; + applyFilter: (data: any) => void; } export interface ExprVisAPI { @@ -83,6 +84,10 @@ export class ExprVis extends EventEmitter { if (!this.eventsSubject) return; this.eventsSubject.next({ name: 'brush', data }); }, + applyFilter: (data: any) => { + if (!this.eventsSubject) return; + this.eventsSubject.next({ name: 'applyFilter', data }); + }, }, }; } diff --git a/src/plugins/visualizations/public/index.ts b/src/plugins/visualizations/public/index.ts index 2ac53c2c81acc..49cfbe76aa9d0 100644 --- a/src/plugins/visualizations/public/index.ts +++ b/src/plugins/visualizations/public/index.ts @@ -51,5 +51,6 @@ export { VisSavedObject, VisResponseValue, } from './types'; +export { ExprVisAPIEvents } from './expressions/vis'; export { VisualizationListItem } from './vis_types/vis_type_alias_registry'; export { VISUALIZE_ENABLE_LABS_SETTING } from '../common/constants'; From 187a13075b5fe03a165be68faa9c31516ab74a28 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Fri, 14 Aug 2020 07:15:16 -0600 Subject: [PATCH 41/53] [file upload] lazy load to reduce page load size (#74967) * [file upload] lazy load to reduce page load size * tslint --- .../public/get_file_upload_component.ts | 38 +++++++++++++++++++ x-pack/plugins/file_upload/public/index.ts | 2 + x-pack/plugins/file_upload/public/plugin.ts | 6 +-- .../layers/file_upload_wizard/wizard.tsx | 19 +++++++++- .../plugins/maps/public/kibana_services.d.ts | 4 +- x-pack/plugins/maps/public/kibana_services.js | 4 +- 6 files changed, 64 insertions(+), 9 deletions(-) create mode 100644 x-pack/plugins/file_upload/public/get_file_upload_component.ts diff --git a/x-pack/plugins/file_upload/public/get_file_upload_component.ts b/x-pack/plugins/file_upload/public/get_file_upload_component.ts new file mode 100644 index 0000000000000..7232c4126e297 --- /dev/null +++ b/x-pack/plugins/file_upload/public/get_file_upload_component.ts @@ -0,0 +1,38 @@ +/* + * 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 { FeatureCollection } from 'geojson'; + +export interface FileUploadComponentProps { + appName: string; + isIndexingTriggered: boolean; + onFileUpload: (geojsonFile: FeatureCollection, name: string) => void; + onFileRemove: () => void; + onIndexReady: (indexReady: boolean) => void; + transformDetails: string; + onIndexingComplete: (indexResponses: { + indexDataResp: unknown; + indexPatternResp: unknown; + }) => void; +} + +let lazyLoadPromise: Promise>; + +export async function getFileUploadComponent(): Promise< + React.ComponentType +> { + if (typeof lazyLoadPromise !== 'undefined') { + return lazyLoadPromise; + } + + lazyLoadPromise = new Promise(async (resolve) => { + // @ts-expect-error + const { JsonUploadAndParse } = await import('./components/json_upload_and_parse'); + resolve(JsonUploadAndParse); + }); + return lazyLoadPromise; +} diff --git a/x-pack/plugins/file_upload/public/index.ts b/x-pack/plugins/file_upload/public/index.ts index 205ceae37d6a1..1e39fb4dc8596 100644 --- a/x-pack/plugins/file_upload/public/index.ts +++ b/x-pack/plugins/file_upload/public/index.ts @@ -9,3 +9,5 @@ import { FileUploadPlugin } from './plugin'; export function plugin() { return new FileUploadPlugin(); } + +export { FileUploadComponentProps } from './get_file_upload_component'; diff --git a/x-pack/plugins/file_upload/public/plugin.ts b/x-pack/plugins/file_upload/public/plugin.ts index 338c61ad141c6..ff74be659aeca 100644 --- a/x-pack/plugins/file_upload/public/plugin.ts +++ b/x-pack/plugins/file_upload/public/plugin.ts @@ -4,10 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -// @ts-ignore import { CoreSetup, CoreStart, Plugin } from 'kibana/server'; -// @ts-ignore -import { JsonUploadAndParse } from './components/json_upload_and_parse'; +import { getFileUploadComponent } from './get_file_upload_component'; // @ts-ignore import { setupInitServicesAndConstants, startInitServicesAndConstants } from './kibana_services'; import { IDataPluginServices } from '../../../../src/plugins/data/public'; @@ -35,7 +33,7 @@ export class FileUploadPlugin implements Plugin | null; } export class ClientFileCreateSourceEditor extends Component { private _isMounted: boolean = false; - state = { + state: State = { indexingStage: null, + fileUploadComponent: null, }; componentDidMount() { this._isMounted = true; + this._loadFileUploadComponent(); } componentWillUnmount() { @@ -59,6 +63,13 @@ export class ClientFileCreateSourceEditor extends Component { if (!this._isMounted) { return; @@ -145,7 +156,11 @@ export class ClientFileCreateSourceEditor extends Component >; export function getIndexPatternSelectComponent(): any; export function getHttp(): any; export function getTimeFilter(): any; diff --git a/x-pack/plugins/maps/public/kibana_services.js b/x-pack/plugins/maps/public/kibana_services.js index 9b035a87a3b37..64aa0e07ffafb 100644 --- a/x-pack/plugins/maps/public/kibana_services.js +++ b/x-pack/plugins/maps/public/kibana_services.js @@ -33,8 +33,8 @@ export const getInspector = () => { let fileUploadPlugin; export const setFileUpload = (fileUpload) => (fileUploadPlugin = fileUpload); -export const getFileUploadComponent = () => { - return fileUploadPlugin.JsonUploadAndParse; +export const getFileUploadComponent = async () => { + return await fileUploadPlugin.getFileUploadComponent(); }; let uiSettings; From 8aa8b04cee7eceac3fb87ff19d5ab2c12a9c2a26 Mon Sep 17 00:00:00 2001 From: Kevin Logan <56395104+kevinlog@users.noreply.github.com> Date: Fri, 14 Aug 2020 10:06:51 -0400 Subject: [PATCH 42/53] [SECURITY_SOLUTION] Retry on ingest setup (#75000) --- x-pack/test/common/services/ingest_manager.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/x-pack/test/common/services/ingest_manager.ts b/x-pack/test/common/services/ingest_manager.ts index 96b1b97a68dc9..2fcfaa014b2e1 100644 --- a/x-pack/test/common/services/ingest_manager.ts +++ b/x-pack/test/common/services/ingest_manager.ts @@ -8,15 +8,18 @@ import { fleetSetupRouteService } from '../../../plugins/ingest_manager/common'; export function IngestManagerProvider({ getService }: FtrProviderContext) { const supertest = getService('supertest'); + const retry = getService('retry'); return { async setup() { const headers = { accept: 'application/json', 'kbn-xsrf': 'some-xsrf-token' }; - await supertest - .post(fleetSetupRouteService.postFleetSetupPath()) - .set(headers) - .send({ forceRecreate: true }) - .expect(200); + await retry.try(async () => { + await supertest + .post(fleetSetupRouteService.postFleetSetupPath()) + .set(headers) + .send({ forceRecreate: true }) + .expect(200); + }); }, }; } From ec5112b9cc6dcdb37242407925d6c0f2a10ffe50 Mon Sep 17 00:00:00 2001 From: Wylie Conlon Date: Fri, 14 Aug 2020 10:54:43 -0400 Subject: [PATCH 43/53] [Lens] Fix table sorting bug (#74902) * [Lens] Fix table sorting bug * Fix types --- .../visualization.test.tsx | 25 +++++++++++++++++++ .../datatable_visualization/visualization.tsx | 8 ++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/lens/public/datatable_visualization/visualization.test.tsx b/x-pack/plugins/lens/public/datatable_visualization/visualization.test.tsx index e18190b6c2d69..0b6584277ffa7 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/visualization.test.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/visualization.test.tsx @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ +import { Ast } from '@kbn/interpreter/common'; +import { buildExpression } from '../../../../../src/plugins/expressions/public'; import { createMockDatasource } from '../editor_frame_service/mocks'; import { DatatableVisualizationState, datatableVisualization } from './visualization'; import { Operation, DataType, FramePublicAPI, TableSuggestionColumn } from '../types'; @@ -324,4 +326,27 @@ describe('Datatable Visualization', () => { }); }); }); + + describe('#toExpression', () => { + it('reorders the rendered colums based on the order from the datasource', () => { + const datasource = createMockDatasource('test'); + const layer = { layerId: 'a', columns: ['b', 'c'] }; + const frame = mockFrame(); + frame.datasourceLayers = { a: datasource.publicAPIMock }; + datasource.publicAPIMock.getTableSpec.mockReturnValue([{ columnId: 'c' }, { columnId: 'b' }]); + datasource.publicAPIMock.getOperationForColumnId.mockReturnValue({ + dataType: 'string', + isBucketed: true, + label: 'label', + }); + + const expression = datatableVisualization.toExpression({ layers: [layer] }, frame) as Ast; + const tableArgs = buildExpression(expression).findFunction('lens_datatable_columns'); + + expect(tableArgs).toHaveLength(1); + expect(tableArgs[0].arguments).toEqual({ + columnIds: ['c', 'b'], + }); + }); + }); }); diff --git a/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx b/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx index e4b371143594a..659f8ea12bcb0 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/visualization.tsx @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { Ast } from '@kbn/interpreter/common'; import { i18n } from '@kbn/i18n'; import { SuggestionRequest, Visualization, VisualizationSuggestion, Operation } from '../types'; import chartTableSVG from '../assets/chart_datatable.svg'; @@ -185,10 +186,13 @@ export const datatableVisualization: Visualization< }; }, - toExpression(state, frame) { + toExpression(state, frame): Ast { const layer = state.layers[0]; const datasource = frame.datasourceLayers[layer.layerId]; - const operations = layer.columns + const originalOrder = datasource.getTableSpec().map(({ columnId }) => columnId); + // When we add a column it could be empty, and therefore have no order + const sortedColumns = Array.from(new Set(originalOrder.concat(layer.columns))); + const operations = sortedColumns .map((columnId) => ({ columnId, operation: datasource.getOperationForColumnId(columnId) })) .filter((o): o is { columnId: string; operation: Operation } => !!o.operation); From 458bf9fb0db04a7648f9466520a6bdae2004e2b3 Mon Sep 17 00:00:00 2001 From: Stratoula Kalafateli Date: Fri, 14 Aug 2020 17:57:08 +0300 Subject: [PATCH 44/53] Fix bug on TopN weird behavior with zero values (#74942) --- .../public/application/visualizations/views/top_n.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/vis_type_timeseries/public/application/visualizations/views/top_n.js b/src/plugins/vis_type_timeseries/public/application/visualizations/views/top_n.js index b595979130d3a..3aae1bd64d953 100644 --- a/src/plugins/vis_type_timeseries/public/application/visualizations/views/top_n.js +++ b/src/plugins/vis_type_timeseries/public/application/visualizations/views/top_n.js @@ -110,7 +110,9 @@ export class TopN extends Component { const isPositiveValue = lastValue >= 0; const intervalLength = TopN.calcDomain(renderMode, min, max); - const width = 100 * (Math.abs(lastValue) / intervalLength); + // if both are 0, the division returns NaN causing unexpected behavior. + // For this it defaults to 0 + const width = 100 * (Math.abs(lastValue) / intervalLength) || 0; const styles = reactcss( { From 344e1de7e1a0962c4e4c1ebf2ed81fccebf84b15 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Fri, 14 Aug 2020 17:14:03 +0200 Subject: [PATCH 45/53] [Upgrade Assistant] Fix potentially long URI (#74485) * _cluster/state/metadata/* and added a comment to function * add another comment regarding why we are asking for * * update jest test * refactor and clean up use of cluster status to get index state Co-authored-by: Elastic Machine --- .../common/get_index_state.test.ts | 41 +++++++++++++ .../common/get_index_state.ts | 24 ++++++++ ...get_index_state_from_cluster_state.test.ts | 53 ----------------- .../get_index_state_from_cluster_state.ts | 28 --------- .../plugins/upgrade_assistant/common/types.ts | 50 +++++----------- .../server/lib/es_indices_state_check.ts | 21 ++++--- .../server/lib/es_migration_apis.test.ts | 28 ++++----- .../server/lib/es_migration_apis.ts | 2 +- .../server/lib/reindexing/reindex_service.ts | 6 +- .../upgrade_assistant/index.js | 1 - .../upgrade_assistant/reindexing.js | 16 ++--- .../upgrade_assistant/status.ts | 58 ------------------- 12 files changed, 108 insertions(+), 220 deletions(-) create mode 100644 x-pack/plugins/upgrade_assistant/common/get_index_state.test.ts create mode 100644 x-pack/plugins/upgrade_assistant/common/get_index_state.ts delete mode 100644 x-pack/plugins/upgrade_assistant/common/get_index_state_from_cluster_state.test.ts delete mode 100644 x-pack/plugins/upgrade_assistant/common/get_index_state_from_cluster_state.ts delete mode 100644 x-pack/test/upgrade_assistant_integration/upgrade_assistant/status.ts diff --git a/x-pack/plugins/upgrade_assistant/common/get_index_state.test.ts b/x-pack/plugins/upgrade_assistant/common/get_index_state.test.ts new file mode 100644 index 0000000000000..43c20add0bb3c --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/common/get_index_state.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 { getIndexState } from './get_index_state'; +import { ResolveIndexResponseFromES } from './types'; + +describe('getIndexState', () => { + const indexName1 = 'indexName'; + const indexName2 = 'indexName2'; + const response: ResolveIndexResponseFromES = { + indices: [ + { + name: indexName2, + aliases: ['.security'], + attributes: ['open'], + }, + { + name: indexName1, + attributes: ['closed'], + }, + ], + aliases: [ + { + name: '.security', + indices: ['.security-7'], + }, + ], + data_streams: [], + }; + + it('correctly extracts state', () => { + expect(getIndexState(indexName1, response)).toBe('closed'); + expect(getIndexState(indexName2, response)).toBe('open'); + }); + + it('throws if the index name cannot be found', () => { + expect(() => getIndexState('nonExistent', response)).toThrow('not found'); + }); +}); diff --git a/x-pack/plugins/upgrade_assistant/common/get_index_state.ts b/x-pack/plugins/upgrade_assistant/common/get_index_state.ts new file mode 100644 index 0000000000000..24d044f324d07 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/common/get_index_state.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ResolveIndexResponseFromES } from './types'; + +/** + * Throws if the index name is not found in the resolved indices response + * + * @param indexName Assume this is an index name, not an alias + * @param resolvedResponse The response from _resolve/index/ + */ +export const getIndexState = ( + indexName: string, + resolvedResponse: ResolveIndexResponseFromES +): 'open' | 'closed' => { + const index = resolvedResponse.indices.find((i) => i.name === indexName); + if (index) { + return index.attributes.includes('closed') ? 'closed' : 'open'; + } + throw new Error(`${indexName} not found!`); +}; diff --git a/x-pack/plugins/upgrade_assistant/common/get_index_state_from_cluster_state.test.ts b/x-pack/plugins/upgrade_assistant/common/get_index_state_from_cluster_state.test.ts deleted file mode 100644 index 1098594a68f8a..0000000000000 --- a/x-pack/plugins/upgrade_assistant/common/get_index_state_from_cluster_state.test.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 { getIndexStateFromClusterState } from './get_index_state_from_cluster_state'; -import { ClusterStateAPIResponse } from './types'; - -describe('getIndexStateFromClusterState', () => { - const indexName = 'indexName'; - const clusterState: ClusterStateAPIResponse = { - metadata: { - indices: {}, - cluster_coordination: {} as any, - cluster_uuid: 'test', - templates: {} as any, - }, - cluster_name: 'test', - cluster_uuid: 'test', - }; - - afterEach(() => { - clusterState.metadata.indices = {}; - }); - - it('correctly extracts state from cluster state', () => { - clusterState.metadata.indices[indexName] = { state: 'open' } as any; - clusterState.metadata.indices.aTotallyDifferentIndex = { state: 'close' } as any; - expect(getIndexStateFromClusterState(indexName, clusterState)).toBe('open'); - }); - - it('correctly extracts state from aliased index in cluster state', () => { - clusterState.metadata.indices.aTotallyDifferentName = { - state: 'close', - aliases: [indexName, 'test'], - } as any; - clusterState.metadata.indices.aTotallyDifferentName1 = { - state: 'open', - aliases: ['another', 'test'], - } as any; - - expect(getIndexStateFromClusterState(indexName, clusterState)).toBe('close'); - }); - - it('throws if the index name cannot be found in the cluster state', () => { - expect(() => getIndexStateFromClusterState(indexName, clusterState)).toThrow('not found'); - clusterState.metadata.indices.aTotallyDifferentName1 = { - state: 'open', - aliases: ['another', 'test'], - } as any; - expect(() => getIndexStateFromClusterState(indexName, clusterState)).toThrow('not found'); - }); -}); diff --git a/x-pack/plugins/upgrade_assistant/common/get_index_state_from_cluster_state.ts b/x-pack/plugins/upgrade_assistant/common/get_index_state_from_cluster_state.ts deleted file mode 100644 index f302940424ee3..0000000000000 --- a/x-pack/plugins/upgrade_assistant/common/get_index_state_from_cluster_state.ts +++ /dev/null @@ -1,28 +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 { ClusterStateAPIResponse } from './types'; - -const checkAllAliases = ( - indexName: string, - clusterState: ClusterStateAPIResponse -): 'open' | 'close' => { - for (const index of Object.values(clusterState.metadata.indices)) { - if (index.aliases?.some((alias) => alias === indexName)) { - return index.state; - } - } - - throw new Error(`${indexName} not found in cluster state!`); -}; - -export const getIndexStateFromClusterState = ( - indexName: string, - clusterState: ClusterStateAPIResponse -): 'open' | 'close' => - clusterState.metadata.indices[indexName] - ? clusterState.metadata.indices[indexName].state - : checkAllAliases(indexName, clusterState); diff --git a/x-pack/plugins/upgrade_assistant/common/types.ts b/x-pack/plugins/upgrade_assistant/common/types.ts index 6c1b24b677754..a29c37c9a988c 100644 --- a/x-pack/plugins/upgrade_assistant/common/types.ts +++ b/x-pack/plugins/upgrade_assistant/common/types.ts @@ -184,41 +184,17 @@ export interface UpgradeAssistantStatus { indices: EnrichedDeprecationInfo[]; } -export interface ClusterStateIndexAPIResponse { - state: 'open' | 'close'; - settings: { - index: { - verified_before_close: string; - search: { - throttled: string; - }; - number_of_shards: string; - provided_name: string; - frozen: string; - creation_date: string; - number_of_replicas: string; - uuid: string; - version: { - created: string; - }; - }; - }; - mappings: any; - aliases: string[]; -} - -export interface ClusterStateAPIResponse { - cluster_name: string; - cluster_uuid: string; - metadata: { - cluster_uuid: string; - cluster_coordination: { - term: number; - last_committed_config: string[]; - last_accepted_config: string[]; - voting_config_exclusions: []; - }; - templates: any; - indices: { [indexName: string]: ClusterStateIndexAPIResponse }; - }; +export interface ResolveIndexResponseFromES { + indices: Array<{ + name: string; + // per https://github.com/elastic/elasticsearch/pull/57626 + attributes: Array<'open' | 'closed' | 'hidden' | 'frozen'>; + aliases?: string[]; + data_stream?: string; + }>; + aliases: Array<{ + name: string; + indices: string[]; + }>; + data_streams: Array<{ name: string; backing_indices: string[]; timestamp_field: string }>; } diff --git a/x-pack/plugins/upgrade_assistant/server/lib/es_indices_state_check.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_indices_state_check.ts index cec89bbe2745e..bce48b152700f 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/es_indices_state_check.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_indices_state_check.ts @@ -5,28 +5,27 @@ */ import { LegacyAPICaller } from 'kibana/server'; -import { getIndexStateFromClusterState } from '../../common/get_index_state_from_cluster_state'; -import { ClusterStateAPIResponse } from '../../common/types'; +import { getIndexState } from '../../common/get_index_state'; +import { ResolveIndexResponseFromES } from '../../common/types'; -type StatusCheckResult = Record; +type StatusCheckResult = Record; export const esIndicesStateCheck = async ( callAsUser: LegacyAPICaller, indices: string[] ): Promise => { - // According to https://www.elastic.co/guide/en/elasticsearch/reference/7.6/cluster-state.html - // The response from this call is considered internal and subject to change. We have an API - // integration test for asserting that the current ES version still returns what we expect. - // This lives in x-pack/test/upgrade_assistant_integration - const clusterState: ClusterStateAPIResponse = await callAsUser('cluster.state', { - index: indices, - metric: 'metadata', + const response: ResolveIndexResponseFromES = await callAsUser('transport.request', { + method: 'GET', + path: `/_resolve/index/*`, + query: { + expand_wildcards: 'all', + }, }); const result: StatusCheckResult = {}; indices.forEach((index) => { - result[index] = getIndexStateFromClusterState(index, clusterState); + result[index] = getIndexState(index, response); }); return result; diff --git a/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.test.ts index 2a4fa5cd48ded..6e524a98afdc6 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.test.ts @@ -6,33 +6,25 @@ import _ from 'lodash'; import { elasticsearchServiceMock } from 'src/core/server/mocks'; -import { getUpgradeAssistantStatus } from './es_migration_apis'; - import { DeprecationAPIResponse } from 'src/legacy/core_plugins/elasticsearch'; + +import { getUpgradeAssistantStatus } from './es_migration_apis'; import fakeDeprecations from './__fixtures__/fake_deprecations.json'; +const fakeIndexNames = Object.keys(fakeDeprecations.index_settings); + describe('getUpgradeAssistantStatus', () => { + const resolvedIndices = { + indices: fakeIndexNames.map((f) => ({ name: f, attributes: ['open'] })), + }; let deprecationsResponse: DeprecationAPIResponse; const dataClient = elasticsearchServiceMock.createLegacyScopedClusterClient(); - (dataClient.callAsCurrentUser as jest.Mock).mockImplementation(async (api, { path, index }) => { + (dataClient.callAsCurrentUser as jest.Mock).mockImplementation(async (api, { path }) => { if (path === '/_migration/deprecations') { return deprecationsResponse; - } else if (api === 'cluster.state') { - return { - metadata: { - indices: { - ...index.reduce((acc: any, i: any) => { - return { - ...acc, - [i]: { - state: 'open', - }, - }; - }, {}), - }, - }, - }; + } else if (path === '/_resolve/index/*') { + return resolvedIndices; } else if (api === 'indices.getMapping') { return {}; } else { diff --git a/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts index 98175e2ae791e..abbeb8a89e12a 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_migration_apis.ts @@ -34,7 +34,7 @@ export async function getUpgradeAssistantStatus( indices.forEach((indexData) => { indexData.blockerForReindexing = - indexStates[indexData.index!] === 'close' ? 'index-closed' : undefined; + indexStates[indexData.index!] === 'closed' ? 'index-closed' : undefined; }); } diff --git a/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.ts b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.ts index a23ddc0d60329..e784f42867d57 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/reindexing/reindex_service.ts @@ -346,8 +346,8 @@ export const reindexServiceFactory = ( // Where possible, derive reindex options at the last moment before reindexing // to prevent them from becoming stale as they wait in the queue. const indicesState = await esIndicesStateCheck(callAsUser, [indexName]); - const openAndClose = indicesState[indexName] === 'close'; - if (indicesState[indexName] === 'close') { + const shouldOpenAndClose = indicesState[indexName] === 'closed'; + if (shouldOpenAndClose) { log.debug(`Detected closed index ${indexName}, opening...`); await callAsUser('indices.open', { index: indexName }); } @@ -369,7 +369,7 @@ export const reindexServiceFactory = ( ...(reindexOptions ?? {}), // Indicate to downstream states whether we opened a closed index that should be // closed again. - openAndClose, + openAndClose: shouldOpenAndClose, }, }); }; diff --git a/x-pack/test/upgrade_assistant_integration/upgrade_assistant/index.js b/x-pack/test/upgrade_assistant_integration/upgrade_assistant/index.js index 638f31dc211b5..1b7406b37022a 100644 --- a/x-pack/test/upgrade_assistant_integration/upgrade_assistant/index.js +++ b/x-pack/test/upgrade_assistant_integration/upgrade_assistant/index.js @@ -9,6 +9,5 @@ export default function ({ loadTestFile }) { this.tags('ciGroup7'); loadTestFile(require.resolve('./reindexing')); - loadTestFile(require.resolve('./status')); }); } 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 1131089130d36..10074f68bb59e 100644 --- a/x-pack/test/upgrade_assistant_integration/upgrade_assistant/reindexing.js +++ b/x-pack/test/upgrade_assistant_integration/upgrade_assistant/reindexing.js @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import { ReindexStatus, REINDEX_OP_TYPE } from '../../../plugins/upgrade_assistant/common/types'; import { generateNewIndexName } from '../../../plugins/upgrade_assistant/server/lib/reindexing/index_settings'; -import { getIndexStateFromClusterState } from '../../../plugins/upgrade_assistant/common/get_index_state_from_cluster_state'; +import { getIndexState } from '../../../plugins/upgrade_assistant/common/get_index_state'; export default function ({ getService }) { const supertest = getService('supertest'); @@ -190,7 +190,7 @@ export default function ({ getService }) { expect(result.body.enqueued.length).to.equal(3); expect(result.body.errors.length).to.equal(0); - const [{ newIndexName: newTest1Name }] = result.body.enqueued; + const [{ newIndexName: nameOfIndexThatShouldBeClosed }] = result.body.enqueued; await assertQueueState(test1, 3); await waitForReindexToComplete(test1); @@ -204,16 +204,12 @@ export default function ({ getService }) { await assertQueueState(undefined, 0); // Check that the closed index is still closed after reindexing - const clusterStateResponse = await es.cluster.state({ - index: newTest1Name, - metric: 'metadata', + const resolvedIndices = await es.transport.request({ + path: `_resolve/index/${nameOfIndexThatShouldBeClosed}`, }); - const test1ReindexedState = getIndexStateFromClusterState( - newTest1Name, - clusterStateResponse - ); - expect(test1ReindexedState).to.be('close'); + const test1ReindexedState = getIndexState(nameOfIndexThatShouldBeClosed, resolvedIndices); + expect(test1ReindexedState).to.be('closed'); } finally { await cleanupReindex(test1); await cleanupReindex(test2); diff --git a/x-pack/test/upgrade_assistant_integration/upgrade_assistant/status.ts b/x-pack/test/upgrade_assistant_integration/upgrade_assistant/status.ts deleted file mode 100644 index d13b9836f25a1..0000000000000 --- a/x-pack/test/upgrade_assistant_integration/upgrade_assistant/status.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 expect from '@kbn/expect'; -import { FtrProviderContext } from '../../api_integration/ftr_provider_context'; -import { ClusterStateAPIResponse } from '../../../plugins/upgrade_assistant/common/types'; -import { getIndexStateFromClusterState } from '../../../plugins/upgrade_assistant/common/get_index_state_from_cluster_state'; - -// eslint-disable-next-line import/no-default-export -export default function ({ getService }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const es = getService('es'); - - describe('status and _cluster/state contract', () => { - beforeEach(async () => { - await es.indices.open({ index: '7.0-data' }); - }); - - afterEach(async () => { - await es.indices.open({ index: '7.0-data' }); - }); - - // According to https://www.elastic.co/guide/en/elasticsearch/reference/7.6/cluster-state.html - // The response from this call is considered internal and subject to change. We check that - // the contract has not changed in this integration test. - it('the _cluster/state endpoint is still what we expect', async () => { - await esArchiver.load('upgrade_assistant/reindex'); - await es.indices.close({ index: '7.0-data' }); - const result = await es.cluster.state({ - index: '7.0-data', - metric: 'metadata', - }); - - try { - if (getIndexStateFromClusterState('7.0-data', result.body) === 'close') { - return; - } - } catch (e) { - expect().fail( - `Can no longer access index open/closed state. Please update Upgrade Assistant checkup. (${e.message})` - ); - return; - } - expect().fail( - `The response contract for _cluster/state metadata has changed. Please update Upgrade Assistant checkup. Received ${JSON.stringify( - result, - null, - 2 - )}. - -Expected body.metadata.indices['7.0-data'].state to be "close".` - ); - }); - }); -} From f1ad1f1b7bd11ebf8b25d3ea95e615b92a205547 Mon Sep 17 00:00:00 2001 From: Quynh Nguyen <43350163+qn895@users.noreply.github.com> Date: Fri, 14 Aug 2020 10:34:08 -0500 Subject: [PATCH 46/53] [ML] Add new storeInHashQuery and replaceUrlQuery (#74955) Co-authored-by: Elastic Machine --- .../public/state_management/url/format.ts | 17 +++++++++++++++ .../url/kbn_url_storage.test.ts | 21 +++++++++++++++++++ .../state_management/url/kbn_url_storage.ts | 10 ++++++--- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/plugins/kibana_utils/public/state_management/url/format.ts b/src/plugins/kibana_utils/public/state_management/url/format.ts index 2912b665ff014..4497e509bc86b 100644 --- a/src/plugins/kibana_utils/public/state_management/url/format.ts +++ b/src/plugins/kibana_utils/public/state_management/url/format.ts @@ -22,6 +22,23 @@ import { stringify, ParsedQuery } from 'query-string'; import { parseUrl, parseUrlHash } from './parse'; import { url as urlUtils } from '../../../common'; +export function replaceUrlQuery( + rawUrl: string, + queryReplacer: (query: ParsedQuery) => ParsedQuery +) { + const url = parseUrl(rawUrl); + const newQuery = queryReplacer(url.query || {}); + const searchQueryString = stringify(urlUtils.encodeQuery(newQuery), { + sort: false, + encode: false, + }); + if (!url.search && !searchQueryString) return rawUrl; // nothing to change. return original url + return formatUrl({ + ...url, + search: searchQueryString, + }); +} + export function replaceUrlHashQuery( rawUrl: string, queryReplacer: (query: ParsedQuery) => ParsedQuery diff --git a/src/plugins/kibana_utils/public/state_management/url/kbn_url_storage.test.ts b/src/plugins/kibana_utils/public/state_management/url/kbn_url_storage.test.ts index a8c3aab2202d1..3d25134cd178d 100644 --- a/src/plugins/kibana_utils/public/state_management/url/kbn_url_storage.test.ts +++ b/src/plugins/kibana_utils/public/state_management/url/kbn_url_storage.test.ts @@ -78,6 +78,27 @@ describe('kbn_url_storage', () => { const retrievedState2 = getStateFromKbnUrl('_s', newUrl); expect(retrievedState2).toEqual(state2); }); + + it('should set query to url with storeInHashQuery: false', () => { + let newUrl = setStateToKbnUrl( + '_a', + { tab: 'other' }, + { useHash: false, storeInHashQuery: false }, + 'http://localhost:5601/oxf/app/kibana/yourApp' + ); + expect(newUrl).toMatchInlineSnapshot( + `"http://localhost:5601/oxf/app/kibana/yourApp?_a=(tab:other)"` + ); + newUrl = setStateToKbnUrl( + '_b', + { f: 'test', i: '', l: '' }, + { useHash: false, storeInHashQuery: false }, + newUrl + ); + expect(newUrl).toMatchInlineSnapshot( + `"http://localhost:5601/oxf/app/kibana/yourApp?_a=(tab:other)&_b=(f:test,i:'',l:'')"` + ); + }); }); describe('urlControls', () => { diff --git a/src/plugins/kibana_utils/public/state_management/url/kbn_url_storage.ts b/src/plugins/kibana_utils/public/state_management/url/kbn_url_storage.ts index fefd5f668c6b3..a3b220f911504 100644 --- a/src/plugins/kibana_utils/public/state_management/url/kbn_url_storage.ts +++ b/src/plugins/kibana_utils/public/state_management/url/kbn_url_storage.ts @@ -22,7 +22,7 @@ import { stringify } from 'query-string'; import { createBrowserHistory, History } from 'history'; import { decodeState, encodeState } from '../state_encoder'; import { getCurrentUrl, parseUrl, parseUrlHash } from './parse'; -import { replaceUrlHashQuery } from './format'; +import { replaceUrlHashQuery, replaceUrlQuery } from './format'; import { url as urlUtils } from '../../../common'; /** @@ -84,10 +84,14 @@ export function getStateFromKbnUrl( export function setStateToKbnUrl( key: string, state: State, - { useHash = false }: { useHash: boolean } = { useHash: false }, + { useHash = false, storeInHashQuery = true }: { useHash: boolean; storeInHashQuery?: boolean } = { + useHash: false, + storeInHashQuery: true, + }, rawUrl = window.location.href ): string { - return replaceUrlHashQuery(rawUrl, (query) => { + const replacer = storeInHashQuery ? replaceUrlHashQuery : replaceUrlQuery; + return replacer(rawUrl, (query) => { const encoded = encodeState(state, useHash); return { ...query, From bbee1f92b0879e8e4ed50a34e74edde7fe83e0c2 Mon Sep 17 00:00:00 2001 From: Greg Thompson Date: Fri, 14 Aug 2020 10:31:15 -0600 Subject: [PATCH 47/53] Upgrade EUI to v27.4.0 (#74004) * eui to 27.1.0 * eui to 27.2.0 * buttoniconside type * euiselectable type * update onScroll callback and polyfill size references * findTestSubject ts * buttoncontent and collapsiblenav src snapshot updates * update prop retrieval * xpack snapshots * jest updates * type fixes * more snapshots * virtual list changes * more virtualization changes * merge * fix functional tests * data-test-subj for indexPatter-switcher * storyshots * eui to 27.3.1 * Fix unit tests * Fix broken unit test * Updated snapshots * Fixed types * search for value in euiselectable before selection * select the correct element * mock virtualized dep * ts fix * reinstate storyshot * ts fix Co-authored-by: Chandler Prall Co-authored-by: Elastic Machine --- package.json | 2 +- packages/kbn-ui-shared-deps/package.json | 2 +- .../collapsible_nav.test.tsx.snap | 9557 ++++++++++------- .../header/__snapshots__/header.test.tsx.snap | 1724 ++- .../__snapshots__/modal_service.test.tsx.snap | 4 +- .../components/field/field.test.tsx | 1 - .../components/form/form.test.tsx | 1 - .../components/search/search.test.tsx | 1 - .../dashboard_empty_screen.test.tsx.snap | 65 +- .../dashboard_empty_screen.test.tsx | 1 - .../viewport/dashboard_viewport.test.tsx | 1 - .../tests/dashboard_container.test.tsx | 1 - .../shard_failure_open_modal_button.test.tsx | 1 - .../components/action_bar/action_bar.test.tsx | 1 - .../pager/tool_bar_pager_buttons.test.tsx | 1 - .../table_header/table_header.test.tsx | 1 - .../context_error_message.test.tsx | 1 - .../application/components/doc/doc.test.tsx | 1 - .../components/doc_viewer/doc_viewer.test.tsx | 1 - .../hits_counter/hits_counter.test.tsx | 1 - .../loading_spinner/loading_spinner.test.tsx | 1 - .../sidebar/discover_field.test.tsx | 1 - .../sidebar/discover_field_search.test.tsx | 1 - .../sidebar/discover_index_pattern.test.tsx | 4 +- .../sidebar/discover_sidebar.test.tsx | 1 - .../skip_bottom_button.test.tsx | 2 - .../components/table/table.test.tsx | 1 - .../timechart_header.test.tsx | 1 - .../lib/embeddables/embeddable_root.test.tsx | 1 - .../lib/panel/embeddable_panel.test.tsx | 1 - .../add_panel/add_panel_flyout.test.tsx | 3 +- .../customize_panel_action.test.ts | 2 - .../tests/customize_panel_modal.test.tsx | 1 - .../saved_objects_installer.test.js.snap | 78 +- .../header/__snapshots__/header.test.tsx.snap | 2 +- .../empty_state/empty_state.test.tsx | 1 - .../components/editor/controls_tab.test.tsx | 1 - .../editor/list_control_editor.test.tsx | 1 - .../editor/range_control_editor.test.tsx | 1 - .../components/vis/input_control_vis.test.tsx | 1 - .../inspector_panel.test.tsx.snap | 63 +- .../public/top_nav_menu/top_nav_menu_data.tsx | 4 +- .../__snapshots__/header.test.tsx.snap | 165 +- .../objects_table/components/table.test.tsx | 1 - .../components/color_picker.test.tsx | 1 - .../legend/__snapshots__/legend.test.tsx.snap | 2 +- .../__snapshots__/new_vis_modal.test.tsx.snap | 4284 +++++--- .../apps/dashboard/dashboard_filter_bar.js | 2 +- .../input_control_vis/chained_controls.js | 2 +- .../input_control_vis/dynamic_options.js | 8 +- test/functional/page_objects/discover_page.ts | 1 + .../plugins/kbn_tp_run_pipeline/package.json | 2 +- .../kbn_sample_panel_action/package.json | 2 +- .../kbn_tp_custom_visualizations/package.json | 2 +- x-pack/package.json | 2 +- .../__test__/__snapshots__/List.test.tsx.snap | 18 +- .../ServiceOverview.test.tsx.snap | 5 +- .../TransactionActionMenu.test.tsx.snap | 12 +- .../time_filter.stories.storyshot | 40 +- .../asset_manager.stories.storyshot | 16 +- .../custom_element_modal.stories.storyshot | 44 +- .../element_card.stories.storyshot | 8 +- .../keyboard_shortcuts_doc.stories.storyshot | 5 + .../element_grid.stories.storyshot | 6 +- .../saved_elements_modal.stories.storyshot | 29 +- .../text_style_picker.stories.storyshot | 60 +- .../__snapshots__/toolbar.stories.storyshot | 19 +- .../delete_var.stories.storyshot | 7 +- .../__snapshots__/edit_var.stories.storyshot | 34 +- .../__snapshots__/edit_menu.stories.storyshot | 12 +- .../element_menu.stories.storyshot | 5 +- .../__snapshots__/pdf_panel.stories.storyshot | 7 +- .../share_menu.stories.storyshot | 2 +- .../__snapshots__/view_menu.stories.storyshot | 8 +- .../workpad_templates.stories.storyshot | 22 +- .../__snapshots__/shareable.test.tsx.snap | 10 +- .../__snapshots__/canvas.stories.storyshot | 6 +- .../__tests__/__snapshots__/app.test.tsx.snap | 2 +- .../__snapshots__/footer.stories.storyshot | 4 +- .../page_controls.stories.storyshot | 6 +- .../autoplay_settings.stories.storyshot | 6 +- .../__snapshots__/settings.test.tsx.snap | 2 +- .../__snapshots__/policy_table.test.js.snap | 5 +- .../layerpanel.test.tsx | 23 +- .../__snapshots__/add_license.test.js.snap | 4 +- .../request_trial_extension.test.js.snap | 8 +- .../revert_to_basic.test.js.snap | 6 +- .../__snapshots__/start_trial.test.js.snap | 8 +- .../upload_license.test.tsx.snap | 1399 ++- .../pipeline_list/pipelines_table.test.js | 2 +- .../upgrade_failure.test.js.snap | 195 +- .../entity_control/entity_control.tsx | 3 +- .../__snapshots__/no_data.test.js.snap | 8 +- .../collection_enabled.test.js.snap | 48 +- .../collection_interval.test.js.snap | 116 +- .../__snapshots__/reason_found.test.js.snap | 2 +- .../__snapshots__/summary_status.test.js.snap | 10 - .../remote_cluster_form.test.js.snap | 113 +- .../report_info_button.test.tsx.snap | 1272 ++- .../job_create/navigation/navigation.js | 2 +- .../overwritten_session_page.test.tsx.snap | 54 +- .../role_combo_box/role_combo_box.test.tsx | 37 +- .../cypress/tasks/create_new_case.ts | 2 +- .../__snapshots__/index.test.tsx.snap | 6 + .../note_card_body.test.tsx.snap | 6 + .../open_timeline_modal/index.test.tsx | 11 +- .../components/timeline/body/index.test.tsx | 2 +- .../timeline/selectable_timeline/index.tsx | 56 +- .../client_integration/policy_add.test.ts | 10 + .../public/custom_time_range_action.test.ts | 1 - .../public/custom_time_range_badge.test.ts | 1 - .../fingerprint_col.test.tsx.snap | 4 +- .../uptime_date_picker.test.tsx.snap | 12 +- .../__snapshots__/license_info.test.tsx.snap | 2 +- .../__snapshots__/ml_flyout.test.tsx.snap | 16 +- .../ml_integerations.test.tsx.snap | 7 +- .../__snapshots__/ml_job_link.test.tsx.snap | 2 +- .../__snapshots__/ml_manage_job.test.tsx.snap | 7 +- .../location_status_tags.test.tsx.snap | 6 +- .../location_missing.test.tsx.snap | 5 +- .../__snapshots__/empty_state.test.tsx.snap | 285 +- .../filter_popover.test.tsx.snap | 7 +- .../__tests__/filter_popover.test.tsx | 13 +- .../filter_status_button.test.tsx.snap | 4 +- .../__snapshots__/monitor_list.test.tsx.snap | 19 +- .../__snapshots__/status_filter.test.tsx.snap | 12 +- .../__snapshots__/page_header.test.tsx.snap | 41 +- .../threshold_watch_edit.tsx | 2 +- .../functional/apps/maps/add_layer_panel.js | 5 +- .../functional/page_objects/graph_page.ts | 3 + yarn.lock | 137 +- 131 files changed, 12036 insertions(+), 8372 deletions(-) diff --git a/package.json b/package.json index df35e5901159b..c79c2a2f3e33a 100644 --- a/package.json +++ b/package.json @@ -124,7 +124,7 @@ "@elastic/datemath": "5.0.3", "@elastic/elasticsearch": "7.9.0-rc.2", "@elastic/ems-client": "7.9.3", - "@elastic/eui": "26.3.1", + "@elastic/eui": "27.4.0", "@elastic/filesaver": "1.1.2", "@elastic/good": "8.1.1-kibana2", "@elastic/numeral": "^2.5.0", diff --git a/packages/kbn-ui-shared-deps/package.json b/packages/kbn-ui-shared-deps/package.json index ae14777e8b44a..a37281cb2263f 100644 --- a/packages/kbn-ui-shared-deps/package.json +++ b/packages/kbn-ui-shared-deps/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@elastic/charts": "19.8.1", - "@elastic/eui": "26.3.1", + "@elastic/eui": "27.4.0", "@elastic/numeral": "^2.5.0", "@kbn/i18n": "1.0.0", "@kbn/monaco": "1.0.0", diff --git a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap index 9ecbc055e3320..72d62730fa698 100644 --- a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap +++ b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap @@ -378,7 +378,9 @@ exports[`CollapsibleNav renders links grouped by category 1`] = `
-
-
- -

@@ -715,41 +637,26 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` class="euiCollapsibleNavGroup__children" >
  • - - discover - - -
  • -
  • - - visualize + recent 1
  • @@ -757,16 +664,18 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` class="euiListGroupItem euiListGroupItem--small euiListGroupItem--subdued euiListGroupItem-isClickable" > - dashboard + recent 2 @@ -776,665 +685,678 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` +
    - -
    -
    -
    -
    + + +
    +
    +
    - + + visualize + + + +
  • + + + dashboard + + +
  • +
+ - -
- +
+
+
+
-

- Security -

+
  • + + + metrics + + +
  • +
  • + + + logs + + +
  • +
    - - +
    +
    -
    -
    + +
    +
    +
    - + + siem + + + + +
    - -
    - -
    -
    -
    -
    + + +
    +
    +
    - + + monitoring + + + + +
    -
    -
    - + + canvas + + + + +
    - -
    -
      -
    • - -
    • -
    -
    + + + +
    + - - - - - } - onActivation={[Function]} - onDeactivation={[Function]} - persistentFocus={false} - > - - + + } + onActivation={[Function]} + onDeactivation={[Function]} + persistentFocus={false} + returnFocus={[Function]} + shards={Array []} + sideCar={ + Object { + "assignMedium": [Function], + "assignSyncMedium": [Function], + "options": Object { + "async": true, + "ssr": false, + }, + "read": [Function], + "useMedium": [Function], + } + } + > + -
    - + + Custom link + + + + +
    - -
    -
    +
    - +
    + + Home + + + + +
    -
    -
    - -
    -
    -
    -
    + + +
    + -
    -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
      -
    • - - - discover - - -
    • - visualize + recent 1
    • @@ -1442,16 +1364,18 @@ exports[`CollapsibleNav renders links grouped by category 1`] = ` class="euiListGroupItem euiListGroupItem--small euiListGroupItem--subdued euiListGroupItem-isClickable" > - dashboard + recent 2 @@ -1461,2983 +1385,3573 @@ exports[`CollapsibleNav renders links grouped by category 1`] = `
    +
    - -
    -
    -
    -
    + + +
    +
    +
    - + + visualize + + + +
  • + + + dashboard + + +
  • + +
    -
    -
    - +
    +
    +
    +
    -

    - Security -

    +
  • + + + metrics + + +
  • +
  • + + + logs + + +
  • +
    - - +
    +
    -
    -
    + +
    +
    +
    - + + siem + + + + +
    -
    -
    - -
    -
    -
    -
    + + +
    +
    +
    - + + monitoring + + + + +
    -
    -
    - + + canvas + + + + +
    -
    -
    -
      -
    • - -
    • -
    +
    + + Dock navigation + + + + +
    -
    - - -
    - } - onActivation={[Function]} - onDeactivation={[Function]} - persistentFocus={false} - /> - - - - - - -
    -
    - -
    - -
    + - - - -
    -
    - - -
    - - - - -

    - Recently viewed -

    -
    -
    - - } - className="euiCollapsibleNavGroup euiCollapsibleNavGroup--light euiCollapsibleNavGroup--withHeading" - data-test-subj="collapsibleNavGroup-recentlyViewed" - id="mockId" - initialIsOpen={true} - onToggle={[Function]} - paddingSize="none" - > -
    -
    -
    +
    +
    +
    - -
    +
      - -

      - Recently viewed -

      -
      -
    -
    +
    + + Home + + + + +
    - - - -
    -
    - -
    +
    - -
    + + +
    +
    +
    +
    +
    -
  • - - + + recent 1 + + +
  • +
  • + - recent 2 - - -
  • - - - + + recent 2 + + + + +
    +
    +
    - - - - -
    -
    - -
    -
    - -
    - - - - - - - -

    - Kibana -

    -
    -
    - - } - className="euiCollapsibleNavGroup euiCollapsibleNavGroup--withHeading" - data-test-subj="collapsibleNavGroup-kibana" - id="mockId" - initialIsOpen={true} - onToggle={[Function]} - paddingSize="none" - > -
    -
    - -
    -
    - -
    + + +
    -
    - + +
    - -
    - - - - - - - - - - -

    - Observability -

    -
    -
    - - } - className="euiCollapsibleNavGroup euiCollapsibleNavGroup--withHeading" - data-test-subj="collapsibleNavGroup-observability" - id="mockId" - initialIsOpen={true} - onToggle={[Function]} - paddingSize="none" - > -
    -
    - -
    -
    - -
    + + +
    -
    - +
    - - + +
    +
    - - - -
    -
    - - - - - - - -

    - Security -

    -
    -
    - - } - className="euiCollapsibleNavGroup euiCollapsibleNavGroup--withHeading" - data-test-subj="collapsibleNavGroup-security" - id="mockId" - initialIsOpen={true} - onToggle={[Function]} - paddingSize="none" - > -
    -
    - -
    -
    - -
    + + +
    -
    - +
    - - + +
    +
    - - - -
    -
    - - - - -

    - Management -

    -
    -
    - - } - className="euiCollapsibleNavGroup euiCollapsibleNavGroup--withHeading" - data-test-subj="collapsibleNavGroup-management" - id="mockId" - initialIsOpen={true} - onToggle={[Function]} - paddingSize="none" - > -
    -
    - -
    -
    - -
    + + +
    -
    - +
    - - + +
    +
    - - - -
    -
    - -
    -
    - - - -
    -
    -
    - - -
    -
    - -
      - -
      + canvas + + + +
    +
    +
    +
    +
    +
      +
    • + , - } - } - color="subdued" - data-test-subj="collapsible-nav-lock" - iconType="lockOpen" - label="Dock navigation" - onClick={[Function]} - size="xs" + +
    • +
    +
    +
    + + + + + } + onActivation={[Function]} + onDeactivation={[Function]} + persistentFocus={false} + returnFocus={[Function]} + shards={Array []} + > + + - -
    - -
    - - - - - -`; - -exports[`CollapsibleNav renders the default nav 1`] = ` - - - -`; - -exports[`CollapsibleNav renders the default nav 2`] = ` - - - - - - - -
    - -
    -
    -
    - - - -
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
      +
    • + +
    • +
    +
    +
    +
    + + +
    + } + onActivation={[Function]} + onDeactivation={[Function]} + persistentFocus={false} + returnFocus={[Function]} + shards={Array []} + /> + + + +
    - -
    +
    + +
    +
    + + + +
    +
    +
    +
    + + +
    +
    +
    + +
    +
    + + + +
    +
    +
    +
    +
    + + + + +

    + Recently viewed +

    +
    +
    + + } + className="euiCollapsibleNavGroup euiCollapsibleNavGroup--light euiCollapsibleNavGroup--withHeading" + data-test-subj="collapsibleNavGroup-recentlyViewed" + id="mockId" + initialIsOpen={true} + onToggle={[Function]} + paddingSize="none" + > +
    +
    + +
    +
    + +
    +
    +
    + + + +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    + +
    - - - -
    -
    -
    -
    - - - - - -

    - Recently viewed -

    -
    -
    - - } - className="euiCollapsibleNavGroup euiCollapsibleNavGroup--light euiCollapsibleNavGroup--withHeading" - data-test-subj="collapsibleNavGroup-recentlyViewed" - id="mockId" - initialIsOpen={true} - onToggle={[Function]} - paddingSize="none" - > -
    -
    -
    +
    + +
    +
    +
    + + + +
    +
    +
    +
    +
    +
    +
    +
    + - + + + + + +

    + Observability +

    +
    +
    + + } + className="euiCollapsibleNavGroup euiCollapsibleNavGroup--withHeading" + data-test-subj="collapsibleNavGroup-observability" + id="mockId" + initialIsOpen={true} + onToggle={[Function]} + paddingSize="none" >
    - - - +
    + +
    +
    + +
    +
    +
    + + + +
    +
    +
    +
    +
    +
    + +
    + - + + + + + +

    + Security +

    +
    +
    +
    + } + className="euiCollapsibleNavGroup euiCollapsibleNavGroup--withHeading" + data-test-subj="collapsibleNavGroup-security" + id="mockId" + initialIsOpen={true} + onToggle={[Function]} + paddingSize="none" >
    - -
    + +
    +
    + +
    +
    +
    + + + +
    +
    +
    +
    +
    +
    + +
    + + +

    - Recently viewed + Management

    -
    -
    - - - - - -
    - -
    -
    + + } + className="euiCollapsibleNavGroup euiCollapsibleNavGroup--withHeading" + data-test-subj="collapsibleNavGroup-management" + id="mockId" + initialIsOpen={true} + onToggle={[Function]} + paddingSize="none" >
    - -
    - + +
    + + + + +
    + +
    + +

    + Management +

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

    - No recently viewed items -

    +
    + + + +
    - -
    - +
    + +
    -
    -
    -
    -
    - - - - -
    -
    - -
    - - -
    -
    + + - -
      - -
      - - Dock navigation - - , - } - } - color="subdued" - data-test-subj="collapsible-nav-lock" - iconType="lockOpen" - label="Dock navigation" - onClick={[Function]} - size="xs" + -
    • -
    • + +
    +
    +
    +
    +
    + + +
    +
    + +
      + +
      + + Dock navigation + + , + } + } + color="subdued" + data-test-subj="collapsible-nav-lock" + iconType="lockOpen" + label="Dock navigation" + onClick={[Function]} + size="xs" > - Dock navigation - - - - -
    -
    -
    +
  • + +
  • + + + +
    +
    + + - - - -
    - - - - - - - -
    + + +
    + + + + close + + + + + + + + +
    + +
    + + - + > + + + + + + + + + +
    @@ -4446,7 +4960,242 @@ exports[`CollapsibleNav renders the default nav 2`] = ` `; -exports[`CollapsibleNav renders the default nav 3`] = ` +exports[`CollapsibleNav renders the default nav 1`] = ` + + + +`; + +exports[`CollapsibleNav renders the default nav 2`] = ` @@ -4682,12 +5431,16 @@ exports[`CollapsibleNav renders the default nav 3`] = ` event="keydown" handler={[Function]} /> + - -
    -
    -
    - +
    +
    +
    -
    -
    + -
    - -
    -
    -
    -
    -
    -
    -
    -

    - No recently viewed items -

    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    + + + } + className="euiCollapsibleNavGroup euiCollapsibleNavGroup--light euiCollapsibleNavGroup--withHeading" + data-test-subj="collapsibleNavGroup-recentlyViewed" id="mockId" + initialIsOpen={true} + onToggle={[Function]} + paddingSize="none" >
    -
      -
    • - -
    • -
    -
    -
    -
    - - -
    - } - onActivation={[Function]} - onDeactivation={[Function]} - persistentFocus={false} - > - - -
    + + +
    + + + + close + + + + + + + + +
    + +
    - -
    + - -
    - - - - , + } + } + color="subdued" + data-test-subj="collapsible-nav-lock" + iconType="lock" + label="Undock navigation" + onClick={[Function]} + size="xs" + > +
  • + +
  • + + + +
    +
    + + + + + + - - close - - - - - - - - -
    - + + + +
    + + + + close + + + + + + + + +
    + +
    + + +
    diff --git a/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap index ce56b19f82cd0..a1920154d9f71 100644 --- a/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap +++ b/src/core/public/chrome/ui/header/__snapshots__/header.test.tsx.snap @@ -9016,953 +9016,264 @@ exports[`Header renders 3`] = ` onTouchEnd={[Function]} onTouchStart={[Function]} > - -
    -
    -
    - - -
    + lockProps={ + Object { + "allowPinchZoom": undefined, + "enabled": false, + "inert": undefined, + "shards": undefined, + "sideCar": [Function], + } } - onActivation={[Function]} - onDeactivation={[Function]} + noFocusGuards={false} persistentFocus={false} + returnFocus={true} + sideCar={[Function]} > - - -
    +
    - -
    + + +
    +
    +
    - - - -
    -
    - -
    - - - - - -

    - Recently viewed -

    -
    -
    - - } - className="euiCollapsibleNavGroup euiCollapsibleNavGroup--light euiCollapsibleNavGroup--withHeading" - data-test-subj="collapsibleNavGroup-recentlyViewed" - id="mockId" - initialIsOpen={true} - onToggle={[Function]} - paddingSize="none" - > -
    -
    - -
    -
    - -
    -
    -
    -
    -
    -
    -
    -
    - -
    -
    - -
    - -
    +
    + + -
    + + +

    + Recently viewed +

    +
    +
    + + } + className="euiCollapsibleNavGroup euiCollapsibleNavGroup--light euiCollapsibleNavGroup--withHeading" + data-test-subj="collapsibleNavGroup-recentlyViewed" + id="mockId" + initialIsOpen={true} + onToggle={[Function]} + paddingSize="none" > - -
      - -
    • + +
      + + + - -
    • -
      -
    -
    -
    -
    - - - +
    + +

    + Recently viewed +

    +
    +
    +
    + + + + + +
    + +
    +
    +
    + + + +
    +
    +
    +
    +
    + + + + +
    +
    +
    -
    - -
      - -
      - - Undock navigation - - , - } - } - color="subdued" - data-test-subj="collapsible-nav-lock" - iconType="lock" - label="Undock navigation" - onClick={[Function]} - size="xs" + -
    • - +
    • + +
    +
    +
    +
    + + + +
    +
    + +
      + +
      + + Undock navigation + + , + } + } + color="subdued" + data-test-subj="collapsible-nav-lock" + iconType="lock" + label="Undock navigation" + onClick={[Function]} + size="xs" > - Undock navigation - - - - -
    -
    -
    +
  • + +
  • + + + +
    + +
    +
    - - - -
    - - - - - - - -
    - + + + +
    + + + + close + + + + + + + + +
    + +
    + + +
    diff --git a/src/core/public/overlays/modal/__snapshots__/modal_service.test.tsx.snap b/src/core/public/overlays/modal/__snapshots__/modal_service.test.tsx.snap index b17e7d0fec773..fb00ddc38c6dc 100644 --- a/src/core/public/overlays/modal/__snapshots__/modal_service.test.tsx.snap +++ b/src/core/public/overlays/modal/__snapshots__/modal_service.test.tsx.snap @@ -31,7 +31,7 @@ Array [ ] `; -exports[`ModalService openConfirm() renders a mountpoint confirm message 2`] = `"
    Modal content
    "`; +exports[`ModalService openConfirm() renders a mountpoint confirm message 2`] = `"
    Modal content
    "`; exports[`ModalService openConfirm() renders a string confirm message 1`] = ` Array [ @@ -53,7 +53,7 @@ Array [ ] `; -exports[`ModalService openConfirm() renders a string confirm message 2`] = `"

    Some message

    "`; +exports[`ModalService openConfirm() renders a string confirm message 2`] = `"

    Some message

    "`; exports[`ModalService openConfirm() with a currently active confirm replaces the current confirm with the new one 1`] = ` Array [ 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 72992c190e8ae..5b33b0e0ea120 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 @@ -25,7 +25,6 @@ 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, getEditableValue } from './field'; 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 0e942665b23a9..e42432d0bc319 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 @@ -21,7 +21,6 @@ import React from 'react'; 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'; diff --git a/src/plugins/advanced_settings/public/management_app/components/search/search.test.tsx b/src/plugins/advanced_settings/public/management_app/components/search/search.test.tsx index 0e3fbb3cf97fa..01f54cce60319 100644 --- a/src/plugins/advanced_settings/public/management_app/components/search/search.test.tsx +++ b/src/plugins/advanced_settings/public/management_app/components/search/search.test.tsx @@ -20,7 +20,6 @@ import React from 'react'; import { shallowWithI18nProvider, mountWithI18nProvider } from 'test_utils/enzyme_helpers'; -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; import { Query } from '@elastic/eui'; diff --git a/src/plugins/dashboard/public/application/__snapshots__/dashboard_empty_screen.test.tsx.snap b/src/plugins/dashboard/public/application/__snapshots__/dashboard_empty_screen.test.tsx.snap index 698c124d2d805..201c6e83a4a44 100644 --- a/src/plugins/dashboard/public/application/__snapshots__/dashboard_empty_screen.test.tsx.snap +++ b/src/plugins/dashboard/public/application/__snapshots__/dashboard_empty_screen.test.tsx.snap @@ -671,35 +671,54 @@ exports[`DashboardEmptyScreen renders correctly with visualize paragraph 1`] = ` iconType="plusInCircle" size="s" > - + + +
    + + + Create new + + + + +

    diff --git a/src/plugins/dashboard/public/application/dashboard_empty_screen.test.tsx b/src/plugins/dashboard/public/application/dashboard_empty_screen.test.tsx index 933475d354cfa..0a49e524d3350 100644 --- a/src/plugins/dashboard/public/application/dashboard_empty_screen.test.tsx +++ b/src/plugins/dashboard/public/application/dashboard_empty_screen.test.tsx @@ -19,7 +19,6 @@ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { DashboardEmptyScreen, DashboardEmptyScreenProps } from './dashboard_empty_screen'; -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; import { coreMock } from '../../../../core/public/mocks'; diff --git a/src/plugins/dashboard/public/application/embeddable/viewport/dashboard_viewport.test.tsx b/src/plugins/dashboard/public/application/embeddable/viewport/dashboard_viewport.test.tsx index 1e07c610b0ef2..60395bce678c2 100644 --- a/src/plugins/dashboard/public/application/embeddable/viewport/dashboard_viewport.test.tsx +++ b/src/plugins/dashboard/public/application/embeddable/viewport/dashboard_viewport.test.tsx @@ -17,7 +17,6 @@ * under the License. */ -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; import React from 'react'; import { skip } from 'rxjs/operators'; diff --git a/src/plugins/dashboard/public/application/tests/dashboard_container.test.tsx b/src/plugins/dashboard/public/application/tests/dashboard_container.test.tsx index 6eb85faeea014..24075e0a634ba 100644 --- a/src/plugins/dashboard/public/application/tests/dashboard_container.test.tsx +++ b/src/plugins/dashboard/public/application/tests/dashboard_container.test.tsx @@ -17,7 +17,6 @@ * under the License. */ -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; import React from 'react'; import { mount } from 'enzyme'; diff --git a/src/plugins/data/public/ui/shard_failure_modal/shard_failure_open_modal_button.test.tsx b/src/plugins/data/public/ui/shard_failure_modal/shard_failure_open_modal_button.test.tsx index 18b1237895f79..aee8d1f4eac4d 100644 --- a/src/plugins/data/public/ui/shard_failure_modal/shard_failure_open_modal_button.test.tsx +++ b/src/plugins/data/public/ui/shard_failure_modal/shard_failure_open_modal_button.test.tsx @@ -22,7 +22,6 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { ShardFailureOpenModalButton } from './shard_failure_open_modal_button'; import { shardFailureRequest } from './__mocks__/shard_failure_request'; import { shardFailureResponse } from './__mocks__/shard_failure_response'; -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; describe('ShardFailureOpenModalButton', () => { diff --git a/src/plugins/discover/public/application/angular/context/components/action_bar/action_bar.test.tsx b/src/plugins/discover/public/application/angular/context/components/action_bar/action_bar.test.tsx index 8976f8ea3c107..ab7adba193d87 100644 --- a/src/plugins/discover/public/application/angular/context/components/action_bar/action_bar.test.tsx +++ b/src/plugins/discover/public/application/angular/context/components/action_bar/action_bar.test.tsx @@ -20,7 +20,6 @@ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { ActionBar, ActionBarProps } from './action_bar'; -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; import { MAX_CONTEXT_SIZE, MIN_CONTEXT_SIZE } from '../../query_parameters/constants'; diff --git a/src/plugins/discover/public/application/angular/doc_table/components/pager/tool_bar_pager_buttons.test.tsx b/src/plugins/discover/public/application/angular/doc_table/components/pager/tool_bar_pager_buttons.test.tsx index 524161c77cbf8..2cd829d89f78e 100644 --- a/src/plugins/discover/public/application/angular/doc_table/components/pager/tool_bar_pager_buttons.test.tsx +++ b/src/plugins/discover/public/application/angular/doc_table/components/pager/tool_bar_pager_buttons.test.tsx @@ -20,7 +20,6 @@ import React from 'react'; import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers'; import { ToolBarPagerButtons } from './tool_bar_pager_buttons'; -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; test('it renders ToolBarPagerButtons', () => { diff --git a/src/plugins/discover/public/application/angular/doc_table/components/table_header/table_header.test.tsx b/src/plugins/discover/public/application/angular/doc_table/components/table_header/table_header.test.tsx index b201bea26503e..224e249a274cd 100644 --- a/src/plugins/discover/public/application/angular/doc_table/components/table_header/table_header.test.tsx +++ b/src/plugins/discover/public/application/angular/doc_table/components/table_header/table_header.test.tsx @@ -20,7 +20,6 @@ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { TableHeader } from './table_header'; -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; import { SortOrder } from './helpers'; import { IndexPattern, IFieldType } from '../../../../../kibana_services'; diff --git a/src/plugins/discover/public/application/components/context_error_message/context_error_message.test.tsx b/src/plugins/discover/public/application/components/context_error_message/context_error_message.test.tsx index 1c9439bc34e58..1cc8247957512 100644 --- a/src/plugins/discover/public/application/components/context_error_message/context_error_message.test.tsx +++ b/src/plugins/discover/public/application/components/context_error_message/context_error_message.test.tsx @@ -22,7 +22,6 @@ import { ReactWrapper } from 'enzyme'; import { ContextErrorMessage } from './context_error_message'; // @ts-ignore import { FAILURE_REASONS, LOADING_STATUS } from '../../angular/context/query'; -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; describe('loading spinner', function () { diff --git a/src/plugins/discover/public/application/components/doc/doc.test.tsx b/src/plugins/discover/public/application/components/doc/doc.test.tsx index 0bc621714c70f..c9fa551f61aca 100644 --- a/src/plugins/discover/public/application/components/doc/doc.test.tsx +++ b/src/plugins/discover/public/application/components/doc/doc.test.tsx @@ -20,7 +20,6 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { ReactWrapper } from 'enzyme'; -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; import { Doc, DocProps } from './doc'; diff --git a/src/plugins/discover/public/application/components/doc_viewer/doc_viewer.test.tsx b/src/plugins/discover/public/application/components/doc_viewer/doc_viewer.test.tsx index 3710ce72533db..9115915690324 100644 --- a/src/plugins/discover/public/application/components/doc_viewer/doc_viewer.test.tsx +++ b/src/plugins/discover/public/application/components/doc_viewer/doc_viewer.test.tsx @@ -19,7 +19,6 @@ import React from 'react'; import { mount, shallow } from 'enzyme'; import { DocViewer } from './doc_viewer'; -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; import { getDocViewsRegistry } from '../../../kibana_services'; import { DocViewRenderProps } from '../../doc_views/doc_views_types'; diff --git a/src/plugins/discover/public/application/components/hits_counter/hits_counter.test.tsx b/src/plugins/discover/public/application/components/hits_counter/hits_counter.test.tsx index 84ad19dbddcbf..c2eb4f08cf549 100644 --- a/src/plugins/discover/public/application/components/hits_counter/hits_counter.test.tsx +++ b/src/plugins/discover/public/application/components/hits_counter/hits_counter.test.tsx @@ -20,7 +20,6 @@ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { ReactWrapper } from 'enzyme'; import { HitsCounter, HitsCounterProps } from './hits_counter'; -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; describe('hits counter', function () { diff --git a/src/plugins/discover/public/application/components/loading_spinner/loading_spinner.test.tsx b/src/plugins/discover/public/application/components/loading_spinner/loading_spinner.test.tsx index 3321ac764a05b..e996da5fe0e3c 100644 --- a/src/plugins/discover/public/application/components/loading_spinner/loading_spinner.test.tsx +++ b/src/plugins/discover/public/application/components/loading_spinner/loading_spinner.test.tsx @@ -20,7 +20,6 @@ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { ReactWrapper } from 'enzyme'; import { LoadingSpinner } from './loading_spinner'; -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; describe('loading spinner', function () { diff --git a/src/plugins/discover/public/application/components/sidebar/discover_field.test.tsx b/src/plugins/discover/public/application/components/sidebar/discover_field.test.tsx index 3f12a8c0fa769..e1abbfd7657d0 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_field.test.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_field.test.tsx @@ -18,7 +18,6 @@ */ import React from 'react'; -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; // @ts-ignore import StubIndexPattern from 'test_utils/stub_index_pattern'; diff --git a/src/plugins/discover/public/application/components/sidebar/discover_field_search.test.tsx b/src/plugins/discover/public/application/components/sidebar/discover_field_search.test.tsx index 654df5bfa9ee9..625d6833406eb 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_field_search.test.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_field_search.test.tsx @@ -19,7 +19,6 @@ import React, { EventHandler, MouseEvent as ReactMouseEvent } from 'react'; import { act } from 'react-dom/test-utils'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; import { DiscoverFieldSearch, Props } from './discover_field_search'; import { EuiButtonGroupProps, EuiPopover } from '@elastic/eui'; diff --git a/src/plugins/discover/public/application/components/sidebar/discover_index_pattern.test.tsx b/src/plugins/discover/public/application/components/sidebar/discover_index_pattern.test.tsx index 24e6f5993a0a5..a1b231c2d4479 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_index_pattern.test.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_index_pattern.test.tsx @@ -24,7 +24,7 @@ import { ShallowWrapper } from 'enzyme'; import { ChangeIndexPattern } from './change_indexpattern'; import { SavedObject } from 'kibana/server'; import { DiscoverIndexPattern } from './discover_index_pattern'; -import { EuiSelectable, EuiSelectableList } from '@elastic/eui'; +import { EuiSelectable } from '@elastic/eui'; import { IIndexPattern } from 'src/plugins/data/public'; const indexPattern = { @@ -57,7 +57,7 @@ function getIndexPatternPickerList(instance: ShallowWrapper) { } function getIndexPatternPickerOptions(instance: ShallowWrapper) { - return getIndexPatternPickerList(instance).dive().find(EuiSelectableList).prop('options'); + return getIndexPatternPickerList(instance).prop('options'); } function selectIndexPatternPickerOption(instance: ShallowWrapper, selectedLabel: string) { diff --git a/src/plugins/discover/public/application/components/sidebar/discover_sidebar.test.tsx b/src/plugins/discover/public/application/components/sidebar/discover_sidebar.test.tsx index 90ade60d2073d..9572f35641d69 100644 --- a/src/plugins/discover/public/application/components/sidebar/discover_sidebar.test.tsx +++ b/src/plugins/discover/public/application/components/sidebar/discover_sidebar.test.tsx @@ -19,7 +19,6 @@ import _ from 'lodash'; import { ReactWrapper } from 'enzyme'; -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; // @ts-ignore import StubIndexPattern from 'test_utils/stub_index_pattern'; diff --git a/src/plugins/discover/public/application/components/skip_bottom_button/skip_bottom_button.test.tsx b/src/plugins/discover/public/application/components/skip_bottom_button/skip_bottom_button.test.tsx index bf417f9f1890b..fdb0ff973dcf0 100644 --- a/src/plugins/discover/public/application/components/skip_bottom_button/skip_bottom_button.test.tsx +++ b/src/plugins/discover/public/application/components/skip_bottom_button/skip_bottom_button.test.tsx @@ -20,8 +20,6 @@ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { ReactWrapper } from 'enzyme'; import { SkipBottomButton, SkipBottomButtonProps } from './skip_bottom_button'; -// @ts-ignore -import { findTestSubject } from '@elastic/eui/lib/test'; describe('Skip to Bottom Button', function () { let props: SkipBottomButtonProps; diff --git a/src/plugins/discover/public/application/components/table/table.test.tsx b/src/plugins/discover/public/application/components/table/table.test.tsx index 29659b3969365..5b840a25d8beb 100644 --- a/src/plugins/discover/public/application/components/table/table.test.tsx +++ b/src/plugins/discover/public/application/components/table/table.test.tsx @@ -18,7 +18,6 @@ */ import React from 'react'; import { mount } from 'enzyme'; -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; import { DocViewTable } from './table'; import { indexPatterns, IndexPattern } from '../../../../../data/public'; diff --git a/src/plugins/discover/public/application/components/timechart_header/timechart_header.test.tsx b/src/plugins/discover/public/application/components/timechart_header/timechart_header.test.tsx index 964f94ca9d9b2..a4c10e749d868 100644 --- a/src/plugins/discover/public/application/components/timechart_header/timechart_header.test.tsx +++ b/src/plugins/discover/public/application/components/timechart_header/timechart_header.test.tsx @@ -21,7 +21,6 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { ReactWrapper } from 'enzyme'; import { TimechartHeader, TimechartHeaderProps } from './timechart_header'; import { EuiIconTip } from '@elastic/eui'; -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; describe('timechart header', function () { diff --git a/src/plugins/embeddable/public/lib/embeddables/embeddable_root.test.tsx b/src/plugins/embeddable/public/lib/embeddables/embeddable_root.test.tsx index 131069909dd2a..cb900884fde97 100644 --- a/src/plugins/embeddable/public/lib/embeddables/embeddable_root.test.tsx +++ b/src/plugins/embeddable/public/lib/embeddables/embeddable_root.test.tsx @@ -20,7 +20,6 @@ import React from 'react'; import { HelloWorldEmbeddable } from '../../../../../../examples/embeddable_examples/public'; import { EmbeddableRoot } from './embeddable_root'; import { mount } from 'enzyme'; -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; test('EmbeddableRoot renders an embeddable', async () => { diff --git a/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx b/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx index 341a51d7348b2..fcf79c1d6b211 100644 --- a/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx +++ b/src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx @@ -21,7 +21,6 @@ import React from 'react'; import { mount } from 'enzyme'; import { nextTick } from 'test_utils/enzyme_helpers'; -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; import { I18nProvider } from '@kbn/i18n/react'; import { CONTEXT_MENU_TRIGGER } from '../triggers'; diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.test.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.test.tsx index 34a176400dbb9..95aee3d9cb335 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.test.tsx +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_flyout.test.tsx @@ -30,7 +30,6 @@ import { ContainerInput } from '../../../../containers'; import { mountWithIntl as mount } from 'test_utils/enzyme_helpers'; import { ReactWrapper } from 'enzyme'; import { coreMock } from '../../../../../../../../core/public/mocks'; -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; import { embeddablePluginMock } from '../../../../../mocks'; @@ -125,7 +124,7 @@ test('selecting embeddable in "Create new ..." list calls createNewEmbeddable()' notifications={core.notifications} SavedObjectFinder={(props) => } /> - ) as ReactWrapper; + ) as ReactWrapper; const spy = jest.fn(); component.instance().createNewEmbeddable = spy; diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/customize_title/customize_panel_action.test.ts b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/customize_title/customize_panel_action.test.ts index 6fddcbc84faf7..dbfa55a4e0f13 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/customize_title/customize_panel_action.test.ts +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_actions/customize_title/customize_panel_action.test.ts @@ -18,8 +18,6 @@ */ import { Container, isErrorEmbeddable } from '../../../..'; -// @ts-ignore -import { findTestSubject } from '@elastic/eui/lib/test'; import { nextTick } from 'test_utils/enzyme_helpers'; import { CustomizePanelTitleAction } from './customize_panel_action'; import { diff --git a/src/plugins/embeddable/public/tests/customize_panel_modal.test.tsx b/src/plugins/embeddable/public/tests/customize_panel_modal.test.tsx index e094afe528498..d12a55dd827e6 100644 --- a/src/plugins/embeddable/public/tests/customize_panel_modal.test.tsx +++ b/src/plugins/embeddable/public/tests/customize_panel_modal.test.tsx @@ -17,7 +17,6 @@ * under the License. */ -// @ts-ignore import { findTestSubject } from '@elastic/eui/lib/test'; import * as React from 'react'; import { Container, isErrorEmbeddable } from '../lib'; diff --git a/src/plugins/home/public/application/components/tutorial/__snapshots__/saved_objects_installer.test.js.snap b/src/plugins/home/public/application/components/tutorial/__snapshots__/saved_objects_installer.test.js.snap index 1e7b3d5c6284c..9a9e055d54d2f 100644 --- a/src/plugins/home/public/application/components/tutorial/__snapshots__/saved_objects_installer.test.js.snap +++ b/src/plugins/home/public/application/components/tutorial/__snapshots__/saved_objects_installer.test.js.snap @@ -245,22 +245,41 @@ exports[`bulkCreate should display error message when bulkCreate request fails 1 isLoading={false} onClick={[Function]} > - + + + Load Kibana objects + + +
    + +
    @@ -565,22 +584,41 @@ exports[`bulkCreate should display success message when bulkCreate is successful isLoading={false} onClick={[Function]} > - + + + Load Kibana objects + + + + + diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/components/header/__snapshots__/header.test.tsx.snap b/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/components/header/__snapshots__/header.test.tsx.snap index 6261ea2c90793..5218ebd1b4ad4 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/components/header/__snapshots__/header.test.tsx.snap +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/components/header/__snapshots__/header.test.tsx.snap @@ -33,7 +33,7 @@ exports[`Header should render normally 1`] = ` type="button" > diff --git a/src/plugins/navigation/public/top_nav_menu/top_nav_menu_data.tsx b/src/plugins/navigation/public/top_nav_menu/top_nav_menu_data.tsx index a1653c5289255..992a2fcf0c89d 100644 --- a/src/plugins/navigation/public/top_nav_menu/top_nav_menu_data.tsx +++ b/src/plugins/navigation/public/top_nav_menu/top_nav_menu_data.tsx @@ -17,7 +17,7 @@ * under the License. */ -import { ButtonIconSide } from '@elastic/eui'; +import { EuiButtonProps } from '@elastic/eui'; export type TopNavMenuAction = (anchorElement: HTMLElement) => void; @@ -32,7 +32,7 @@ export interface TopNavMenuData { tooltip?: string | (() => string | undefined); emphasize?: boolean; iconType?: string; - iconSide?: ButtonIconSide; + iconSide?: EuiButtonProps['iconSide']; } export interface RegisteredTopNavMenuData extends TopNavMenuData { diff --git a/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/header.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/header.test.tsx.snap index d56776c2be9d7..f5c2d3efd56f7 100644 --- a/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/header.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/object_view/components/__snapshots__/header.test.tsx.snap @@ -58,45 +58,63 @@ exports[`Intro component renders correctly 1`] = ` iconType="eye" size="s" > - - -
    My Canvas Workpad
    " `; exports[`Canvas Shareable Workpad API Placed successfully with height specified 1`] = `"
    "`; @@ -21,7 +21,7 @@ exports[`Canvas Shareable Workpad API Placed successfully with height specified
    markdown mock
    markdown mock
    My Canvas Workpad
    " +
    markdown mock
    My Canvas Workpad
    " `; exports[`Canvas Shareable Workpad API Placed successfully with page specified 1`] = `"
    "`; @@ -33,7 +33,7 @@ exports[`Canvas Shareable Workpad API Placed successfully with page specified 2`
    markdown mock
    markdown mock
    My Canvas Workpad
    " +
    markdown mock
    My Canvas Workpad
    " `; exports[`Canvas Shareable Workpad API Placed successfully with width and height specified 1`] = `"
    "`; @@ -45,7 +45,7 @@ exports[`Canvas Shareable Workpad API Placed successfully with width and height
    markdown mock
    markdown mock
    My Canvas Workpad
    " +
    markdown mock
    My Canvas Workpad
    " `; exports[`Canvas Shareable Workpad API Placed successfully with width specified 1`] = `"
    "`; @@ -57,5 +57,5 @@ exports[`Canvas Shareable Workpad API Placed successfully with width specified 2
    markdown mock
    markdown mock
    My Canvas Workpad
    " +
    markdown mock
    My Canvas Workpad
    " `; diff --git a/x-pack/plugins/canvas/shareable_runtime/components/__stories__/__snapshots__/canvas.stories.storyshot b/x-pack/plugins/canvas/shareable_runtime/components/__stories__/__snapshots__/canvas.stories.storyshot index 81e75ff5ee0d9..e0970b57ed971 100644 --- a/x-pack/plugins/canvas/shareable_runtime/components/__stories__/__snapshots__/canvas.stories.storyshot +++ b/x-pack/plugins/canvas/shareable_runtime/components/__stories__/__snapshots__/canvas.stories.storyshot @@ -1398,7 +1398,7 @@ exports[`Storyshots shareables/Canvas component 1`] = ` type="button" > App renders properly 1`] = `
    markdown mock
    markdown mock
    My Canvas Workpad
    " +
    markdown mock
    My Canvas Workpad
    " `; diff --git a/x-pack/plugins/canvas/shareable_runtime/components/footer/__stories__/__snapshots__/footer.stories.storyshot b/x-pack/plugins/canvas/shareable_runtime/components/footer/__stories__/__snapshots__/footer.stories.storyshot index 6ff39b723a49a..2d3a9c460272c 100644 --- a/x-pack/plugins/canvas/shareable_runtime/components/footer/__stories__/__snapshots__/footer.stories.storyshot +++ b/x-pack/plugins/canvas/shareable_runtime/components/footer/__stories__/__snapshots__/footer.stories.storyshot @@ -1351,7 +1351,7 @@ exports[`Storyshots shareables/Footer contextual: austin 1`] = ` type="button" > can navigate Autoplay Settings 2`] = ` type="submit" > - - -
    + +
    + + - + > + + + + + + + + + + @@ -1076,21 +1469,31 @@ exports[`UploadLicense should display a modal when license requires acknowledgem onClick={[Function]} rel="noreferrer" > - - - Cancel - + + Cancel + + - +
    @@ -1107,28 +1510,48 @@ exports[`UploadLicense should display a modal when license requires acknowledgem isLoading={false} onClick={[Function]} > - + + + Upload + + + + + +
    @@ -1734,21 +2157,31 @@ exports[`UploadLicense should display an error when ES says license is expired 1 onClick={[Function]} rel="noreferrer" > - - - Cancel - + + Cancel + + -
    + @@ -1765,28 +2198,48 @@ exports[`UploadLicense should display an error when ES says license is expired 1 isLoading={false} onClick={[Function]} > - + + + Upload + + +
    + + + @@ -2392,21 +2845,31 @@ exports[`UploadLicense should display an error when ES says license is invalid 1 onClick={[Function]} rel="noreferrer" > - - - Cancel - + + Cancel + + -
    + @@ -2423,28 +2886,48 @@ exports[`UploadLicense should display an error when ES says license is invalid 1 isLoading={false} onClick={[Function]} > - + + + Upload + + +
    + + + @@ -3050,21 +3533,31 @@ exports[`UploadLicense should display an error when submitting invalid JSON 1`] onClick={[Function]} rel="noreferrer" > - - - Cancel - + + Cancel + + -
    + @@ -3081,28 +3574,48 @@ exports[`UploadLicense should display an error when submitting invalid JSON 1`] isLoading={false} onClick={[Function]} > - + + + Upload + + +
    + + + @@ -3708,21 +4221,31 @@ exports[`UploadLicense should display error when ES returns error 1`] = ` onClick={[Function]} rel="noreferrer" > - - - Cancel - + + Cancel + + -
    + @@ -3739,28 +4262,48 @@ exports[`UploadLicense should display error when ES returns error 1`] = ` isLoading={false} onClick={[Function]} > - + + + Upload + + +
    + + + diff --git a/x-pack/plugins/logstash/public/application/components/pipeline_list/pipelines_table.test.js b/x-pack/plugins/logstash/public/application/components/pipeline_list/pipelines_table.test.js index 2c25ae69ae722..6c2f0d02801c4 100644 --- a/x-pack/plugins/logstash/public/application/components/pipeline_list/pipelines_table.test.js +++ b/x-pack/plugins/logstash/public/application/components/pipeline_list/pipelines_table.test.js @@ -45,7 +45,7 @@ describe('PipelinesTable component', () => { it('calls clone when cloned button clicked', () => { props.pipelines = [{ id: 'testPipeline', isCentrallyManaged: true }]; const wrapper = mountWithIntl(); - wrapper.find('[iconType="copy"]').simulate('click'); + wrapper.find('[iconType="copy"]').first().simulate('click'); expect(clonePipeline).toHaveBeenCalled(); }); diff --git a/x-pack/plugins/logstash/public/application/components/upgrade_failure/__snapshots__/upgrade_failure.test.js.snap b/x-pack/plugins/logstash/public/application/components/upgrade_failure/__snapshots__/upgrade_failure.test.js.snap index 5f54513c427dd..d0f1bed8e8e9e 100644 --- a/x-pack/plugins/logstash/public/application/components/upgrade_failure/__snapshots__/upgrade_failure.test.js.snap +++ b/x-pack/plugins/logstash/public/application/components/upgrade_failure/__snapshots__/upgrade_failure.test.js.snap @@ -265,21 +265,38 @@ exports[`UpgradeFailure component passes expected text for new pipeline 1`] = ` fill={true} onClick={[MockFunction]} > - + + + Try again + + + + + @@ -298,21 +315,31 @@ exports[`UpgradeFailure component passes expected text for new pipeline 1`] = ` onClick={[MockFunction]} type="button" > - - - Go back - + + Go back + + -
    + @@ -594,21 +621,38 @@ exports[`UpgradeFailure component passes expected text for not manual upgrade 1` fill={true} onClick={[MockFunction]} > - + + + Upgrade + + + + + @@ -627,21 +671,31 @@ exports[`UpgradeFailure component passes expected text for not manual upgrade 1` onClick={[MockFunction]} type="button" > - - - Go back - + + Go back + + -
    + @@ -923,21 +977,38 @@ exports[`UpgradeFailure component passes expected text for not new pipeline 1`] fill={true} onClick={[MockFunction]} > - + + + Try again + + + + + @@ -956,21 +1027,31 @@ exports[`UpgradeFailure component passes expected text for not new pipeline 1`] onClick={[MockFunction]} type="button" > - - - Go back - + + Go back + + -
    + diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/components/entity_control/entity_control.tsx b/x-pack/plugins/ml/public/application/timeseriesexplorer/components/entity_control/entity_control.tsx index c144525699d81..93bb62fa1fc58 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/components/entity_control/entity_control.tsx +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/components/entity_control/entity_control.tsx @@ -16,7 +16,6 @@ import { EuiFormRow, EuiToolTip, } from '@elastic/eui'; -import { EuiSelectableOption } from '@elastic/eui/src/components/selectable/selectable_option'; export interface Entity { fieldName: string; @@ -113,7 +112,7 @@ export class EntityControl extends Component { + renderOption = (option: EuiComboBoxOptionOption) => { const { label } = option; return label === EMPTY_FIELD_VALUE_LABEL ? {label} : label; }; diff --git a/x-pack/plugins/monitoring/public/components/no_data/__tests__/__snapshots__/no_data.test.js.snap b/x-pack/plugins/monitoring/public/components/no_data/__tests__/__snapshots__/no_data.test.js.snap index 72f6e2b01c129..c06f71e79e766 100644 --- a/x-pack/plugins/monitoring/public/components/no_data/__tests__/__snapshots__/no_data.test.js.snap +++ b/x-pack/plugins/monitoring/public/components/no_data/__tests__/__snapshots__/no_data.test.js.snap @@ -52,7 +52,7 @@ exports[`NoData should show a default message if reason is unknown 1`] = ` type="button" > - + + + Turn on monitoring + + + + + + diff --git a/x-pack/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/__snapshots__/collection_interval.test.js.snap b/x-pack/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/__snapshots__/collection_interval.test.js.snap index 49cbe092e0e20..782be3a073016 100644 --- a/x-pack/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/__snapshots__/collection_interval.test.js.snap +++ b/x-pack/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/__snapshots__/collection_interval.test.js.snap @@ -430,37 +430,59 @@ exports[`ExplainCollectionInterval collection interval setting updates should sh onClick={[Function]} type="button" > - + + + + + + Turn on monitoring + + + + + + @@ -728,28 +750,48 @@ exports[`ExplainCollectionInterval should explain about xpack.monitoring.collect onClick={[Function]} type="button" > - + + + Turn on monitoring + + + + + + diff --git a/x-pack/plugins/monitoring/public/components/no_data/reasons/__tests__/__snapshots__/reason_found.test.js.snap b/x-pack/plugins/monitoring/public/components/no_data/reasons/__tests__/__snapshots__/reason_found.test.js.snap index 898be82b139d1..e7b88e23c5f68 100644 --- a/x-pack/plugins/monitoring/public/components/no_data/reasons/__tests__/__snapshots__/reason_found.test.js.snap +++ b/x-pack/plugins/monitoring/public/components/no_data/reasons/__tests__/__snapshots__/reason_found.test.js.snap @@ -61,7 +61,7 @@ Array [ type="button" >  Yellow

    -

    - Status [object Object] -

     Green

    -

    - Status [object Object] -

    - + +
    + + + + Save + + + + + +
    @@ -1326,21 +1348,31 @@ exports[`RemoteClusterForm proxy mode renders correct connection settings when u onClick={[Function]} type="button" > - - - Show request - + + Show request + + - +
    @@ -1743,11 +1775,10 @@ Array [ type="button" > - -
    +
    + + - + > + + + + + + + + + +
    @@ -449,7 +717,9 @@ Array [
    @@ -844,27 +897,44 @@ exports[`EmptyState component doesn't render child components when count is fals color="primary" href="/app/uptime#/settings" > - - - - - Update index pattern settings - - - - + + + Update index pattern settings + + +
    + + + @@ -1256,27 +1326,45 @@ exports[`EmptyState component notifies when index does not exist 1`] = ` fill={true} href="/app/home#/tutorial/uptimeMonitors" > - - - - - View setup instructions - - - - + + + View setup instructions + + +
    + + + @@ -1288,27 +1376,44 @@ exports[`EmptyState component notifies when index does not exist 1`] = ` color="primary" href="/app/uptime#/settings" > - - - - - Update index pattern settings - - - - + + + Update index pattern settings + + +
    + + + diff --git a/x-pack/plugins/uptime/public/components/overview/filter_group/__tests__/__snapshots__/filter_popover.test.tsx.snap b/x-pack/plugins/uptime/public/components/overview/filter_group/__tests__/__snapshots__/filter_popover.test.tsx.snap index 2677fd828c957..63ba8bcf9d26a 100644 --- a/x-pack/plugins/uptime/public/components/overview/filter_group/__tests__/__snapshots__/filter_popover.test.tsx.snap +++ b/x-pack/plugins/uptime/public/components/overview/filter_group/__tests__/__snapshots__/filter_popover.test.tsx.snap @@ -94,15 +94,14 @@ exports[`FilterPopover component returns selected items on popover close 1`] = ` class="euiPopover__anchor" >