From 4a3f2ac0932f7ebb688a1601247a6a8a002e3971 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 9 Oct 2019 13:43:51 -0400 Subject: [PATCH 001/297] WIP --- x-pack/legacy/plugins/alerting_ui/index.ts | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 x-pack/legacy/plugins/alerting_ui/index.ts diff --git a/x-pack/legacy/plugins/alerting_ui/index.ts b/x-pack/legacy/plugins/alerting_ui/index.ts new file mode 100644 index 00000000000000..9314b3b43ca7d8 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/index.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Legacy } from 'kibana'; +import { Root } from 'joi'; + +export function alertingUI(kibana: any) { + return new kibana.Plugin({ + id: 'alerting_ui', + configPrefix: 'xpack.alerting_ui', + require: ['kibana', 'actions'], + isEnabled(config: Legacy.KibanaConfig) { + return ( + config.get('xpack.alerting_ui.enabled') === true && + config.get('xpack.actions.enabled') === true + ); + }, + config(Joi: Root) { + return Joi.object() + .keys({ + enabled: Joi.boolean().default(false), + }) + .default(); + }, + }); +} From 9cd4e5a575819c4048a1c62171f0470b056ccb45 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 9 Oct 2019 13:51:02 -0400 Subject: [PATCH 002/297] Move files over to new plugin --- .../es_ui_shared/public/request/index.ts | 9 + .../es_ui_shared/public/request/request_np.ts | 165 ++++++++++++++++++ x-pack/legacy/plugins/alerting_ui/index.ts | 7 + .../plugins/alerting_ui/np_ready/kibana.json | 7 + .../np_ready/public/application/app.tsx | 55 ++++++ .../components/page_error/form_errors.tsx | 31 ++++ .../components/page_error/index.ts | 7 + .../components/page_error/page_error.tsx | 35 ++++ .../page_error/page_error_forbidden.tsx | 27 +++ .../page_error/page_error_not_exist.tsx | 36 ++++ .../public/application/constants/index.ts | 8 + .../application/context/app_context.tsx | 8 + .../np_ready/public/application/index.tsx | 20 +++ .../np_ready/public/application/lib/api.ts | 94 ++++++++++ .../public/application/lib/flat_map.ts | 19 ++ .../public/application/lib/navigation.ts | 15 ++ .../public/application/lib/result_type.ts | 55 ++++++ .../actions_list/components/actions_list.tsx | 149 ++++++++++++++++ .../alerting_ui/np_ready/public/index.scss | 4 + .../alerting_ui/np_ready/public/index.ts | 15 ++ .../alerting_ui/np_ready/public/legacy.ts | 12 ++ .../alerting_ui/np_ready/public/plugin.ts | 108 ++++++++++++ .../alerting_ui/public/hacks/register.ts | 25 +++ .../plugins/alerting_ui/public/index.html | 3 + .../plugins/alerting_ui/public/index.ts | 7 + .../alerting_ui/public/shared_imports.ts | 13 ++ .../legacy/plugins/alerting_ui/public/shim.ts | 18 ++ 27 files changed, 952 insertions(+) create mode 100644 src/plugins/es_ui_shared/public/request/request_np.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/kibana.json create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/form_errors.tsx create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/index.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error.tsx create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/app_context.tsx create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/index.tsx create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/flat_map.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/navigation.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/result_type.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/index.scss create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/index.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/legacy.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/public/hacks/register.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/public/index.html create mode 100644 x-pack/legacy/plugins/alerting_ui/public/index.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/public/shared_imports.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/public/shim.ts diff --git a/src/plugins/es_ui_shared/public/request/index.ts b/src/plugins/es_ui_shared/public/request/index.ts index f942a9cc3932bb..fbee6b4d848c40 100644 --- a/src/plugins/es_ui_shared/public/request/index.ts +++ b/src/plugins/es_ui_shared/public/request/index.ts @@ -25,3 +25,12 @@ export { sendRequest, useRequest, } from './request'; + +export { + SendRequestConfigNp, + SendRequestResponseNp, + UseRequestConfigNp, + UseRequestResponseNp, + sendRequestNp, + useRequestNp, +} from './request_np'; diff --git a/src/plugins/es_ui_shared/public/request/request_np.ts b/src/plugins/es_ui_shared/public/request/request_np.ts new file mode 100644 index 00000000000000..cfaa6ac102292f --- /dev/null +++ b/src/plugins/es_ui_shared/public/request/request_np.ts @@ -0,0 +1,165 @@ +/* + * 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 { useEffect, useState, useRef } from 'react'; +import { HttpServiceBase } from 'kibana/public'; + +export interface SendRequestConfigNp { + path: string; + method: 'get' | 'post' | 'put' | 'delete' | 'patch'; + body?: any; +} + +export interface SendRequestResponseNp { + data: any; + error: Error | null; +} + +export interface UseRequestConfigNp extends SendRequestConfigNp { + pollIntervalMs?: number; + initialData?: any; + deserializer?: (data: any) => any; +} + +export interface UseRequestResponseNp { + isInitialRequest: boolean; + isLoading: boolean; + error: null | unknown; + data: any; + sendRequestNp: (...args: any[]) => Promise; +} + +export const sendRequestNp = async ( + http: HttpServiceBase, + { path, method, body }: SendRequestConfigNp +): Promise => { + try { + const response = await (http as any)[method](path, body); + if (typeof response === 'undefined') { + throw new Error(response); + } + + return { data: response, error: null }; + } catch (e) { + return { + data: null, + error: e.response ? e.response : e, + }; + } +}; + +export const useRequestNp = ( + http: HttpServiceBase, + { + path, + method, + body, + pollIntervalMs, + initialData, + deserializer = (data: any): any => data, + }: UseRequestConfigNp +): UseRequestResponseNp => { + // Main states for tracking request status and data + const [error, setError] = useState(null); + const [isLoading, setIsLoading] = useState(true); + const [data, setData] = useState(initialData); + + // Consumers can use isInitialRequest to implement a polling UX. + const [isInitialRequest, setIsInitialRequest] = useState(true); + const pollInterval = useRef(null); + const pollIntervalId = useRef(null); + + // We always want to use the most recently-set interval in scheduleRequest. + pollInterval.current = pollIntervalMs; + + // Tied to every render and bound to each request. + let isOutdatedRequest = false; + + const scheduleRequest = () => { + // Clear current interval + if (pollIntervalId.current) { + clearTimeout(pollIntervalId.current); + } + + // Set new interval + if (pollInterval.current) { + pollIntervalId.current = setTimeout(_sendRequest, pollInterval.current); + } + }; + + const _sendRequest = async () => { + // We don't clear error or data, so it's up to the consumer to decide whether to display the + // "old" error/data or loading state when a new request is in-flight. + setIsLoading(true); + + const requestBody = { + path, + method, + body, + }; + + const response = await sendRequestNp(http, requestBody); + const { data: serializedResponseData, error: responseError } = response; + const responseData = deserializer(serializedResponseData); + + // If an outdated request has resolved, DON'T update state, but DO allow the processData handler + // to execute side effects like update telemetry. + if (isOutdatedRequest) { + return { data: null, error: null }; + } + + setError(responseError); + setData(responseData); + setIsLoading(false); + setIsInitialRequest(false); + + // If we're on an interval, we need to schedule the next request. This also allows us to reset + // the interval if the user has manually requested the data, to avoid doubled-up requests. + scheduleRequest(); + + return { data: serializedResponseData, error: responseError }; + }; + + useEffect(() => { + _sendRequest(); + // To be functionally correct we'd send a new request if the method, path, or body changes. + // But it doesn't seem likely that the method will change and body is likely to be a new + // object even if its shape hasn't changed, so for now we're just watching the path. + }, [path]); + + useEffect(() => { + scheduleRequest(); + + // Clean up intervals and inflight requests and corresponding state changes + return () => { + isOutdatedRequest = true; + if (pollIntervalId.current) { + clearTimeout(pollIntervalId.current); + } + }; + }, [pollIntervalMs]); + + return { + isInitialRequest, + isLoading, + error, + data, + sendRequestNp: _sendRequest, // Gives the user the ability to manually request data + }; +}; diff --git a/x-pack/legacy/plugins/alerting_ui/index.ts b/x-pack/legacy/plugins/alerting_ui/index.ts index 9314b3b43ca7d8..2767789b390e05 100644 --- a/x-pack/legacy/plugins/alerting_ui/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/index.ts @@ -6,11 +6,13 @@ import { Legacy } from 'kibana'; import { Root } from 'joi'; +import { resolve } from 'path'; export function alertingUI(kibana: any) { return new kibana.Plugin({ id: 'alerting_ui', configPrefix: 'xpack.alerting_ui', + publicDir: resolve(__dirname, 'public'), require: ['kibana', 'actions'], isEnabled(config: Legacy.KibanaConfig) { return ( @@ -25,5 +27,10 @@ export function alertingUI(kibana: any) { }) .default(); }, + uiExports: { + // styleSheetPaths: resolve(__dirname, 'public/np_ready/public/index.scss'), + hacks: ['plugins/alerting_ui/hacks/register'], + managementSections: ['plugins/alerting_ui'], + }, }); } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/kibana.json b/x-pack/legacy/plugins/alerting_ui/np_ready/kibana.json new file mode 100644 index 00000000000000..c1ac1ce5d8afd6 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/kibana.json @@ -0,0 +1,7 @@ +{ + "id": "xpackActions", + "version": "kibana", + "server": false, + "ui": true + } + \ No newline at end of file diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx new file mode 100644 index 00000000000000..3d8b61adefe2f4 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.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, { Component } from 'react'; +import { some } from 'fp-ts/lib/Option'; +import PropTypes from 'prop-types'; +import { HashRouter, Switch, Route, Redirect } from 'react-router-dom'; + +import { ActionsList } from './sections/actions_list/components/actions_list'; +import { registerRouter } from './lib/navigation'; +import { BASE_PATH } from './constants'; + +class ShareRouter extends Component { + static contextTypes = { + router: PropTypes.shape({ + history: PropTypes.shape({ + push: PropTypes.func.isRequired, + createHref: PropTypes.func.isRequired, + }).isRequired, + }).isRequired, + }; + constructor(props: any, context?: any) { + super(props, context); + this.registerRouter(); + } + + registerRouter() { + // Share the router with the app without requiring React or context. + const { router } = this.context; + registerRouter(router); + } + + render() { + return this.props.children; + } +} + +export const App = (api: any) => { + return ( + + + + + + ); +}; + +export const AppWithoutRouter = ({ api }: any) => ( + + } /> + + +); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/form_errors.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/form_errors.tsx new file mode 100644 index 00000000000000..0a35d6cb5d1046 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/form_errors.tsx @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { EuiFormRow } from '@elastic/eui'; +import React, { Children, cloneElement, Fragment, ReactElement } from 'react'; +export const ErrableFormRow = ({ + errorKey, + isShowingErrors, + errors, + children, + ...rest +}: { + errorKey: string; + isShowingErrors: boolean; + errors: { [key: string]: string[] }; + children: ReactElement; + [key: string]: any; +}) => { + return ( + 0} + error={errors[errorKey]} + {...rest} + > + {Children.map(children, child => cloneElement(child))} + + ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/index.ts new file mode 100644 index 00000000000000..6f1ea7d16facb7 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { PageError } from './page_error'; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error.tsx new file mode 100644 index 00000000000000..822e828e59de84 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error.tsx @@ -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 React from 'react'; + +import { PageErrorNotExist } from './page_error_not_exist'; +import { PageErrorForbidden } from './page_error_forbidden'; + +export function getPageErrorCode(errorOrErrors: any) { + const errors = Array.isArray(errorOrErrors) ? errorOrErrors : [errorOrErrors]; + const firstError = errors.find((error: any) => { + if (error) { + return [403, 404].includes(error.status); + } + return false; + }); + + if (firstError) { + return firstError.status; + } +} + +export function PageError({ errorCode, id }: { errorCode?: any; id?: any }) { + switch (errorCode) { + case 404: + return ; + + case 403: + default: + return ; + } +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx new file mode 100644 index 00000000000000..5309d710835d28 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx @@ -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 React from 'react'; + +import { EuiEmptyPrompt } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; + +export function PageErrorForbidden() { + return ( + + + + } + /> + ); +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx new file mode 100644 index 00000000000000..91b2f4ee4643f2 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; + +import { EuiEmptyPrompt } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; + +export function PageErrorNotExist({ id }: { id: any }) { + return ( + + + + } + body={ +

+ +

+ } + /> + ); +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts new file mode 100644 index 00000000000000..22cb65d31c3d0a --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export const BASE_PATH = '/management/elasticsearch/actions/'; +export const BASE_API_PATH = '../api/action'; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/app_context.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/app_context.tsx new file mode 100644 index 00000000000000..2cf59d001dd538 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/app_context.tsx @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +export const ActionsContext = React.createContext({} as any); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/index.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/index.tsx new file mode 100644 index 00000000000000..09a5ce55e8a521 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/index.tsx @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { render } from 'react-dom'; +import { I18nContext } from 'ui/i18n'; +import { HttpServiceBase } from 'kibana/public'; +import { App } from './app'; + +export const renderReact = async (element: any, http: HttpServiceBase) => { + render( + + + , + element + ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts new file mode 100644 index 00000000000000..b844dfcc1e1345 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -0,0 +1,94 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { Option, fromNullable } from 'fp-ts/lib/Option'; +import { HttpServiceBase } from 'kibana/public'; +import { useRequestNp } from '../../../../public/shared_imports'; +import { BASE_API_PATH } from '../constants'; + +import { ActionType } from '../../../../server/types'; +import { Result, asOk, asErr } from './result_type'; + +export interface RequestData { + isLoading: boolean; + data: Option; + sendRequest?: any; +} + +export interface RequestStatus { + isLoading: boolean; + error?: E; + data?: T; + sendRequest?: any; +} + +export interface LoadActionTypesResponse { + data: ActionTypesResponse[]; +} + +export interface LoadActionTypesError { + status: number; +} +export type LoadActionTypesErrorResponse = LoadActionTypesError | LoadActionTypesError[]; + +export function hasReceivedAErrorCode( + errorOrErrors: any +): errorOrErrors is LoadActionTypesErrorResponse { + const errors = Array.isArray(errorOrErrors) ? errorOrErrors : [errorOrErrors]; + const firstError = errors.find((error: any) => { + if (error) { + return [403, 404].includes(error.status); + } + + return false; + }); + + if (firstError) { + return true; + } + return false; +} + +function wrapInResult(status: any): Result, E> { + return hasReceivedAErrorCode(status.error) + ? asErr(status.error) + : asOk({ + ...status, + data: fromNullable(status.data), + }); +} + +export interface ActionTypesResponse extends ActionType { + id: string; + name: string; +} +export interface LoadActionTypese { + page: number; + perPage: number; + total: number; + data: ActionTypesResponse[]; +} + +export interface ActionTypesApi { + loadActionTypes: ( + pollIntervalMs: number + ) => Result, LoadActionTypesErrorResponse>; +} + +export function loadActionTypes( + http: HttpServiceBase, + pollIntervalMs?: number +): Result, LoadActionTypesErrorResponse> { + return wrapInResult( + useRequestNp(http, { + path: `${BASE_API_PATH}/types`, + method: 'get', + pollIntervalMs, + deserializer: (response: { data?: any[]; error?: any }) => { + return response; + }, + }) + ); +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/flat_map.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/flat_map.ts new file mode 100644 index 00000000000000..cdbb134dd85f5e --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/flat_map.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Option, map, flatten } from 'fp-ts/lib/Option'; +import { pipe } from 'fp-ts/lib/pipeable'; + +type mapperToFlatten = (val: A) => Option; +export function flatMap(fn: mapperToFlatten) { + return function(optional: Option): Option { + return pipe( + optional, + map(fn), + flatten + ); + }; +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/navigation.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/navigation.ts new file mode 100644 index 00000000000000..f0fbb3802fea71 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/navigation.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 { BASE_PATH } from '../constants'; + +let router: any; +export const registerRouter = (aRouter: any) => { + router = aRouter; +}; + +export const goToActionTypesList = () => { + router.history.push({ pathname: `${BASE_PATH}actionTypes` }); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/result_type.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/result_type.ts new file mode 100644 index 00000000000000..59317a36ff3445 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/result_type.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +// eslint-disable-next-line @typescript-eslint/prefer-interface +export type Ok = { + tag: 'ok'; + value: T; +}; +// eslint-disable-next-line @typescript-eslint/prefer-interface +export type Err = { + tag: 'err'; + error: E; +}; +export type Result = Ok | Err; + +export function asOk(value: T): Ok { + return { + tag: 'ok', + value, + }; +} + +export function asErr(error: T): Err { + return { + tag: 'err', + error, + }; +} + +export function isOk(result: Result): result is Ok { + return result.tag === 'ok'; +} + +export function isErr(result: Result): result is Err { + return !isOk(result); +} + +export function mapResult( + result: Result, + mapOk: (value: T) => R, + mapErr: (err: E) => R +) { + return isOk(result) ? mapOk(result.value) : mapErr(result.error); +} + +export async function promiseResult(future: Promise): Promise> { + try { + return asOk(await future); + } catch (e) { + return asErr(e); + } +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx new file mode 100644 index 00000000000000..5a9f0dad367502 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -0,0 +1,149 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under 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 { Option, option, some, getOrElse } from 'fp-ts/lib/Option'; +import { pipe } from 'fp-ts/lib/pipeable'; +import { EuiText, EuiPageContent, EuiEmptyPrompt, EuiInMemoryTable, EuiSpacer } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { flatMap } from '../../../lib/flat_map'; +import { mapResult } from '../../../lib/result_type'; +import { PageError } from '../../../components/page_error'; +import { + loadActionTypes, + RequestData, + LoadActionTypesResponse, + LoadActionTypesErrorResponse, + ActionTypesResponse, +} from '../../../lib/api'; +import { ActionsContext } from '../../../context/app_context'; + +const map = option.map; + +interface ActionsListProps { + api: any; +} + +export const ActionsList = ({ api }: ActionsListProps) => { + const actionTypesTableColumns = [ + { + field: 'id', + name: i18n.translate('xpack.actions.sections.actionTypesList.actionTypesTable.idHeader', { + defaultMessage: 'Id', + }), + sortable: true, + truncateText: true, + }, + { + field: 'name', + name: i18n.translate( + 'xpack.actions.sections.actionTypesList.actionTypesTable.actionTypeHeader', + { + defaultMessage: 'Action Type', + } + ), + sortable: true, + truncateText: true, + }, + ]; + + const ActionTypesTable = ({ actionTypes }: { actionTypes: ActionTypesResponse[] }) => { + return ( + + } + rowProps={() => ({ + 'data-test-subj': 'row', + })} + cellProps={() => ({ + 'data-test-subj': 'cell', + })} + data-test-subj="actionTypesTable" + /> + ); + }; + + const ActionTypesLoadingIndicator = () => ( + + ); + + return pipe( + api, + flatMap((actionTypesApi: any) => + mapResult< + RequestData, + LoadActionTypesErrorResponse, + Option + >( + loadActionTypes(actionTypesApi.api.http), + ({ isLoading: isActionTypesLoading, data: actionTypes }) => + isActionTypesLoading + ? some() + : map(actionTypes, (data: any) => ( + + + + + )), + error => + some( + + + + ) + ) + ), + getOrElse(() => ) + ); +}; + +export const NoActionTypes = () => { + const emptyPromptBody = ( + +

No Action Types

+
+ ); + + return ( + + + + + } + body={emptyPromptBody} + data-test-subj="emptyPrompt" + /> + + ); +}; + +export const ContentWrapper = ({ children }: { children: React.ReactNode }) => { + return ( + + + {children} + + ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/index.scss b/x-pack/legacy/plugins/alerting_ui/np_ready/public/index.scss new file mode 100644 index 00000000000000..bd0a70a19d8b58 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/index.scss @@ -0,0 +1,4 @@ +// Import the EUI global scope so we can use EUI constants +@import 'src/legacy/ui/public/styles/_styling_constants'; + +// Actions plugin styles diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/index.ts new file mode 100644 index 00000000000000..525f5e6df388e8 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/index.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 { PluginInitializerContext } from 'src/core/public'; +import { ActionsPlugin } from './plugin'; + +export function plugin(ctx: PluginInitializerContext) { + return new ActionsPlugin(ctx); +} + +export { ActionsPlugin as Plugin }; +export * from './plugin'; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/legacy.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/legacy.ts new file mode 100644 index 00000000000000..210f60fa64c71f --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/legacy.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 { npStart } from 'ui/new_platform'; +import { createShim } from '../../public/shim'; +import { plugin } from '.'; + +const pluginInstance = plugin({} as any); +const { pluginsStart } = createShim(); +pluginInstance.start(npStart.core, pluginsStart); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts new file mode 100644 index 00000000000000..5f989039351572 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts @@ -0,0 +1,108 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { unmountComponentAtNode } from 'react-dom'; +import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'src/core/public'; +import { i18n } from '@kbn/i18n'; +import routes from 'ui/routes'; + +import template from '../../public/index.html'; +import { renderReact } from './application'; +import { BASE_PATH } from './application/constants'; + +export type Setup = void; +export type Start = void; + +export class ActionsPlugin implements Plugin { + constructor(initializerContext: PluginInitializerContext) {} + + public setup(coreSetup: CoreSetup): Setup { + // TODO: management doesn't exposed in core yet + /* + The code below would be replacing for current: + uiExports: { + managementSections: ['myplugin/management'], + } + */ + // Registering a new app to a new section + /* const mySection = coreSetup.management.sections.register({ + id: 'my-section', + title: 'My Main Section', // display name + order: 10, + euiIconType: 'iconName', + }); + mySection.registerApp({ + id: 'my-management-app', + title: 'My Management App', // display name + order: 20, + async mount(context, params) { + const { renderApp } = await import('./my-section'); + return renderApp(context, params); + } + }); + + // Registering a new app to an existing section + const kibanaSection = management.sections.get('kibana'); + kibanaSection.registerApp({ id: 'my-kibana-management-app', ... }); + */ + } + + public start(coreStart: CoreStart, pluginsStart: any) { + const { + management: { getSection }, + } = pluginsStart; + + const esSection = getSection('elasticsearch'); + esSection.register('actions', { + display: i18n.translate( + 'xpack.actions.sections.actionsList.managementSection.actionsDisplayName', + { + defaultMessage: 'Alert Actions', + } + ), + order: 7, + url: `#${BASE_PATH}/`, + }); + + routes.when('/management/elasticsearch/actions/:param1?/:param2?/:param3?/:param4?', { + template, + controller: (() => { + let elReactRoot: HTMLElement | undefined | null; + return ($injector: any, $scope: any) => { + const $route = $injector.get('$route'); + // clean up previously rendered React app if one exists + // this happens because of React Router redirects + if (elReactRoot) { + unmountComponentAtNode(elReactRoot); + } + $scope.$$postDigest(() => { + elReactRoot = document.getElementById('actionsRoot'); + renderReact(elReactRoot, coreStart.http); + const lastRoute = $route.current; + + const deregister = $scope.$on('$locationChangeSuccess', () => { + const currentRoute = $route.current; + if (lastRoute.$$route.template === currentRoute.$$route.template) { + $route.current = lastRoute; + } + }); + + $scope.$on('$destroy', () => { + if (deregister) { + deregister(); + } + if (elReactRoot) { + unmountComponentAtNode(elReactRoot); + } + }); + }); + }; + })(), + }); + } + + public stop() {} +} diff --git a/x-pack/legacy/plugins/alerting_ui/public/hacks/register.ts b/x-pack/legacy/plugins/alerting_ui/public/hacks/register.ts new file mode 100644 index 00000000000000..1271b5423d0a98 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/public/hacks/register.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { + FeatureCatalogueRegistryProvider, + FeatureCatalogueCategory, +} from 'ui/registry/feature_catalogue'; +import { i18n } from '@kbn/i18n'; + +FeatureCatalogueRegistryProvider.register(() => { + return { + id: 'actions', + title: 'Actions', // This is a product name so we don't translate it. + description: i18n.translate('xpack.actions.ActionsDescription', { + defaultMessage: 'Data by creating, managing, and monitoring actions.', + }), + icon: 'actionsApp', + path: '/app/kibana#/management/elasticsearch/actions', + showOnHomePage: true, + category: FeatureCatalogueCategory.ADMIN, + }; +}); diff --git a/x-pack/legacy/plugins/alerting_ui/public/index.html b/x-pack/legacy/plugins/alerting_ui/public/index.html new file mode 100644 index 00000000000000..a3dec86a48e192 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/public/index.html @@ -0,0 +1,3 @@ + +
+
diff --git a/x-pack/legacy/plugins/alerting_ui/public/index.ts b/x-pack/legacy/plugins/alerting_ui/public/index.ts new file mode 100644 index 00000000000000..573578bfb1275a --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/public/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import '../np_ready/public/legacy'; diff --git a/x-pack/legacy/plugins/alerting_ui/public/shared_imports.ts b/x-pack/legacy/plugins/alerting_ui/public/shared_imports.ts new file mode 100644 index 00000000000000..0d3f9c8b32ba58 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/public/shared_imports.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under 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 { + SendRequestConfigNp, + SendRequestResponseNp, + UseRequestConfigNp, + sendRequestNp, + useRequestNp, +} from '../../../../../src/plugins/es_ui_shared/public/request'; diff --git a/x-pack/legacy/plugins/alerting_ui/public/shim.ts b/x-pack/legacy/plugins/alerting_ui/public/shim.ts new file mode 100644 index 00000000000000..92f234d336b55c --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/public/shim.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { management, MANAGEMENT_BREADCRUMB } from 'ui/management'; + +export function createShim() { + return { + pluginsStart: { + management: { + getSection: management.getSection.bind(management), + breadcrumb: MANAGEMENT_BREADCRUMB, + }, + }, + }; +} From 73ece0a792bc0ef188cb7cf94c4fabed87d31c85 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 9 Oct 2019 14:01:10 -0400 Subject: [PATCH 003/297] Register plugin --- x-pack/.i18nrc.json | 1 + x-pack/index.js | 2 ++ 2 files changed, 3 insertions(+) diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index db8e618ff11340..0bc5df105e8f5e 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -4,6 +4,7 @@ "xpack.actions": "legacy/plugins/actions", "xpack.advancedUiActions": "plugins/advanced_ui_actions", "xpack.alerting": "legacy/plugins/alerting", + "xpack.alertingUI": "legacy/plugins/alerting_ui", "xpack.apm": "legacy/plugins/apm", "xpack.beatsManagement": "legacy/plugins/beats_management", "xpack.canvas": "legacy/plugins/canvas", diff --git a/x-pack/index.js b/x-pack/index.js index 10f969a21b68be..bde68c6c0ea947 100644 --- a/x-pack/index.js +++ b/x-pack/index.js @@ -44,6 +44,7 @@ import { snapshotRestore } from './legacy/plugins/snapshot_restore'; import { actions } from './legacy/plugins/actions'; import { alerting } from './legacy/plugins/alerting'; import { lens } from './legacy/plugins/lens'; +import { alertingUI } from './legacy/plugins/alerting_ui'; module.exports = function (kibana) { return [ @@ -87,5 +88,6 @@ module.exports = function (kibana) { snapshotRestore(kibana), actions(kibana), alerting(kibana), + alertingUI(kibana), ]; }; From 3c3e6bc0e25acd87f47797bf81ecfe4183bec729 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 9 Oct 2019 14:58:39 -0400 Subject: [PATCH 004/297] Rename kibana.json and translation keys --- x-pack/legacy/plugins/alerting_ui/np_ready/kibana.json | 3 +-- .../components/page_error/page_error_forbidden.tsx | 2 +- .../components/page_error/page_error_not_exist.tsx | 4 ++-- .../sections/actions_list/components/actions_list.tsx | 10 +++++----- .../plugins/alerting_ui/np_ready/public/plugin.ts | 2 +- .../plugins/alerting_ui/public/hacks/register.ts | 2 +- 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/kibana.json b/x-pack/legacy/plugins/alerting_ui/np_ready/kibana.json index c1ac1ce5d8afd6..faf30ef4d4e91e 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/kibana.json +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/kibana.json @@ -1,7 +1,6 @@ { - "id": "xpackActions", + "id": "xpackAlertingUI", "version": "kibana", "server": false, "ui": true } - \ No newline at end of file diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx index 5309d710835d28..eac701d03ce760 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx @@ -17,7 +17,7 @@ export function PageErrorForbidden() { title={

diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx index 91b2f4ee4643f2..b1c243af8e04c7 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx @@ -17,7 +17,7 @@ export function PageErrorNotExist({ id }: { id: any }) { title={

@@ -25,7 +25,7 @@ export function PageErrorNotExist({ id }: { id: any }) { body={

diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 5a9f0dad367502..a33fac996ff4ea 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -32,7 +32,7 @@ export const ActionsList = ({ api }: ActionsListProps) => { const actionTypesTableColumns = [ { field: 'id', - name: i18n.translate('xpack.actions.sections.actionTypesList.actionTypesTable.idHeader', { + name: i18n.translate('xpack.alertingUI.sections.actionTypesList.actionTypesTable.idHeader', { defaultMessage: 'Id', }), sortable: true, @@ -41,7 +41,7 @@ export const ActionsList = ({ api }: ActionsListProps) => { { field: 'name', name: i18n.translate( - 'xpack.actions.sections.actionTypesList.actionTypesTable.actionTypeHeader', + 'xpack.alertingUI.sections.actionTypesList.actionTypesTable.actionTypeHeader', { defaultMessage: 'Action Type', } @@ -61,7 +61,7 @@ export const ActionsList = ({ api }: ActionsListProps) => { isSelectable={true} message={ } @@ -78,7 +78,7 @@ export const ActionsList = ({ api }: ActionsListProps) => { const ActionTypesLoadingIndicator = () => ( ); @@ -127,7 +127,7 @@ export const NoActionTypes = () => { title={

diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts index 5f989039351572..a80e93116d6ce0 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts @@ -58,7 +58,7 @@ export class ActionsPlugin implements Plugin { const esSection = getSection('elasticsearch'); esSection.register('actions', { display: i18n.translate( - 'xpack.actions.sections.actionsList.managementSection.actionsDisplayName', + 'xpack.alertingUI.sections.actionsList.managementSection.actionsDisplayName', { defaultMessage: 'Alert Actions', } diff --git a/x-pack/legacy/plugins/alerting_ui/public/hacks/register.ts b/x-pack/legacy/plugins/alerting_ui/public/hacks/register.ts index 1271b5423d0a98..f98356e50b6b77 100644 --- a/x-pack/legacy/plugins/alerting_ui/public/hacks/register.ts +++ b/x-pack/legacy/plugins/alerting_ui/public/hacks/register.ts @@ -14,7 +14,7 @@ FeatureCatalogueRegistryProvider.register(() => { return { id: 'actions', title: 'Actions', // This is a product name so we don't translate it. - description: i18n.translate('xpack.actions.ActionsDescription', { + description: i18n.translate('xpack.alertingUI.ActionsDescription', { defaultMessage: 'Data by creating, managing, and monitoring actions.', }), icon: 'actionsApp', From 579145ae028cecc75c4512f04d2356e64bbe3d13 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 9 Oct 2019 15:01:53 -0400 Subject: [PATCH 005/297] Fix failing type check --- .../plugins/alerting_ui/np_ready/public/application/lib/api.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index b844dfcc1e1345..fcc7e7f4d66294 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -8,7 +8,7 @@ import { HttpServiceBase } from 'kibana/public'; import { useRequestNp } from '../../../../public/shared_imports'; import { BASE_API_PATH } from '../constants'; -import { ActionType } from '../../../../server/types'; +import { ActionType } from '../../../../../actions/server/types'; import { Result, asOk, asErr } from './result_type'; export interface RequestData { From 5b7ef4b6406660efe98a6210abd5803ab2836ad6 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 9 Oct 2019 15:19:39 -0400 Subject: [PATCH 006/297] Move alerting into kibana management section --- .../public/application/constants/index.ts | 2 +- .../plugins/alerting_ui/np_ready/public/plugin.ts | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts index 22cb65d31c3d0a..9886bdcbf157e6 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts @@ -4,5 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export const BASE_PATH = '/management/elasticsearch/actions/'; +export const BASE_PATH = '/management/kibana/alerting/'; export const BASE_API_PATH = '../api/action'; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts index a80e93116d6ce0..83d75b7d05d2d7 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts @@ -55,19 +55,16 @@ export class ActionsPlugin implements Plugin { management: { getSection }, } = pluginsStart; - const esSection = getSection('elasticsearch'); - esSection.register('actions', { - display: i18n.translate( - 'xpack.alertingUI.sections.actionsList.managementSection.actionsDisplayName', - { - defaultMessage: 'Alert Actions', - } - ), + const kbnSection = getSection('kibana'); + kbnSection.register('alerting', { + display: i18n.translate('xpack.alertingUI.managementSection.displayName', { + defaultMessage: 'Alerting', + }), order: 7, url: `#${BASE_PATH}/`, }); - routes.when('/management/elasticsearch/actions/:param1?/:param2?/:param3?/:param4?', { + routes.when('/management/kibana/alerting/:param1?/:param2?/:param3?/:param4?', { template, controller: (() => { let elReactRoot: HTMLElement | undefined | null; From ac28c98452f0fdc7885ead5248645bb128639507 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 9 Oct 2019 15:47:14 -0400 Subject: [PATCH 007/297] Fix app references within /public --- .../plugins/alerting_ui/public/hacks/register.ts | 12 ++++++------ x-pack/legacy/plugins/alerting_ui/public/index.html | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/public/hacks/register.ts b/x-pack/legacy/plugins/alerting_ui/public/hacks/register.ts index f98356e50b6b77..bf8cb6c5cc7dd4 100644 --- a/x-pack/legacy/plugins/alerting_ui/public/hacks/register.ts +++ b/x-pack/legacy/plugins/alerting_ui/public/hacks/register.ts @@ -12,13 +12,13 @@ import { i18n } from '@kbn/i18n'; FeatureCatalogueRegistryProvider.register(() => { return { - id: 'actions', - title: 'Actions', // This is a product name so we don't translate it. - description: i18n.translate('xpack.alertingUI.ActionsDescription', { - defaultMessage: 'Data by creating, managing, and monitoring actions.', + id: 'alerting', + title: 'Alerting', // This is a product name so we don't translate it. + description: i18n.translate('xpack.alertingUI.AlertingDescription', { + defaultMessage: 'Data by creating, managing, and monitoring alerts.', }), - icon: 'actionsApp', - path: '/app/kibana#/management/elasticsearch/actions', + icon: 'alertingApp', + path: '/app/kibana#/management/kibana/alerting', showOnHomePage: true, category: FeatureCatalogueCategory.ADMIN, }; diff --git a/x-pack/legacy/plugins/alerting_ui/public/index.html b/x-pack/legacy/plugins/alerting_ui/public/index.html index a3dec86a48e192..83385ce118ceb7 100644 --- a/x-pack/legacy/plugins/alerting_ui/public/index.html +++ b/x-pack/legacy/plugins/alerting_ui/public/index.html @@ -1,3 +1,3 @@ - +
From fb28e9aeb220f24df8a09ad1f8b6084ace508971 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 9 Oct 2019 17:37:35 -0700 Subject: [PATCH 008/297] [Alerts] Create UI for alerting tabs navigation #47754 --- .../np_ready/public/application/app.tsx | 26 ++-- .../public/application/constants/index.ts | 25 +++- .../np_ready/public/application/home.tsx | 112 ++++++++++++++++++ .../np_ready/public/application/index.tsx | 61 ++++++++-- .../np_ready/public/application/lib/api.ts | 39 ++---- .../public/application/lib/breadcrumb.ts | 95 +++++++++++++++ .../public/application/lib/doc_title.ts | 24 ++++ .../public/application/lib/flat_map.ts | 19 --- .../public/application/lib/result_type.ts | 55 --------- .../public/application/lib/text/index.ts | 7 ++ .../public/application/lib/text/text.ts | 34 ++++++ .../actions_list/components/actions_list.tsx | 85 ++++++------- .../alerts_list/components/alerts_list.tsx | 39 ++++++ .../alerting_ui/np_ready/public/plugin.ts | 65 ++++++---- .../plugins/alerting_ui/public/index.html | 2 +- .../legacy/plugins/alerting_ui/public/shim.ts | 14 +++ 16 files changed, 509 insertions(+), 193 deletions(-) create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/doc_title.ts delete mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/flat_map.ts delete mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/result_type.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/text/index.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/text/text.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx index 3d8b61adefe2f4..99d4a3fe5d3b12 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx @@ -4,13 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ import React, { Component } from 'react'; -import { some } from 'fp-ts/lib/Option'; import PropTypes from 'prop-types'; -import { HashRouter, Switch, Route, Redirect } from 'react-router-dom'; - -import { ActionsList } from './sections/actions_list/components/actions_list'; +import { Switch, Route, Redirect } from 'react-router-dom'; import { registerRouter } from './lib/navigation'; -import { BASE_PATH } from './constants'; +import { BASE_PATH, Section } from './constants'; +import { AlertsUIHome } from './home'; class ShareRouter extends Component { static contextTypes = { @@ -38,18 +36,20 @@ class ShareRouter extends Component { } export const App = (api: any) => { + const sections: Section[] = ['alerts', 'actions', 'notifications', 'activity_logs']; + + const sectionsRegex = sections.join('|'); + return ( - - - - - + + + ); }; -export const AppWithoutRouter = ({ api }: any) => ( +export const AppWithoutRouter = ({ sectionsRegex }: any) => ( - } /> - + + ); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts index 9886bdcbf157e6..3fee275735f920 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts @@ -4,5 +4,28 @@ * you may not use this file except in compliance with the Elastic License. */ -export const BASE_PATH = '/management/kibana/alerting/'; +export const BASE_PATH = '/management/kibana/alerting'; export const BASE_API_PATH = '../api/action'; + +export const DEFAULT_SECTION: Section = 'alerts'; +export type Section = 'actions' | 'alerts' | 'activity_logs' | 'notifications'; + +export function linkToHome() { + return `#${BASE_PATH}`; +} + +export function linkToAlerts() { + return `#${BASE_PATH}/alerts`; +} + +export function linkToActions() { + return `#${BASE_PATH}/actions`; +} + +export function linkToActivityLogs() { + return `#${BASE_PATH}/activity_logs`; +} + +export function linkToNotifications() { + return `#${BASE_PATH}/notifications`; +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx new file mode 100644 index 00000000000000..0065f9569be2dd --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx @@ -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 React, { useEffect } from 'react'; +import { Route, RouteComponentProps, Switch } from 'react-router-dom'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiPageBody, EuiPageContent, EuiSpacer, EuiTab, EuiTabs } from '@elastic/eui'; +import { BASE_PATH, Section } from '../../../np_ready/public/application/constants'; +import { useAppDependencies } from './index'; +import { breadcrumbService } from './lib/breadcrumb'; +import { docTitleService } from './lib/doc_title'; + +import { ActionsList } from './sections/actions_list/components/actions_list'; +import { AlertsList } from './sections/alerts_list/components/alerts_list'; + +interface MatchParams { + section: Section; +} + +export const AlertsUIHome: React.FunctionComponent> = ({ + match: { + params: { section }, + }, + history, +}) => { + const { + core: { chrome }, + } = useAppDependencies(); + + const notificationsUiEnabled = chrome.getIsVisible$(); + + const tabs: Array<{ + id: Section; + name: React.ReactNode; + }> = [ + { + id: 'alerts', + name: ( + + ), + }, + { + id: 'actions', + name: ( + + ), + }, + { + id: 'activity_logs', + name: ( + + ), + }, + ]; + + // Just example of Enable/Disable some UI tabs + if (notificationsUiEnabled) { + tabs.splice(2, 0, { + id: 'notifications', + name: ( + + ), + }); + } + + const onSectionChange = (newSection: Section) => { + history.push(`${BASE_PATH}/${newSection}`); + }; + + // Set breadcrumb and page title + useEffect(() => { + breadcrumbService.setBreadcrumbs(section || 'home'); + docTitleService.setTitle(section || 'home'); + }, [section]); + + return ( + + + + {tabs.map(tab => ( + onSectionChange(tab.id)} + isSelected={tab.id === section} + key={tab.id} + data-test-subj="tab" + > + {tab.name} + + ))} + + + + + + + + + + + + + ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/index.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/index.tsx index 09a5ce55e8a521..74d021d574d7bd 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/index.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/index.tsx @@ -4,17 +4,62 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { createContext, useContext, ReactNode } from 'react'; +import { HashRouter } from 'react-router-dom'; import { render } from 'react-dom'; -import { I18nContext } from 'ui/i18n'; -import { HttpServiceBase } from 'kibana/public'; +import { CoreStart } from 'src/core/public'; import { App } from './app'; -export const renderReact = async (element: any, http: HttpServiceBase) => { - render( +import { AppDependencies, AppPlugins } from '../../../public/shim'; + +export { BASE_PATH as CLIENT_BASE_PATH } from './constants'; + +/** + * App dependencies + */ +let DependenciesContext: React.Context; + +export const setAppDependencies = (deps: AppDependencies) => { + DependenciesContext = createContext(deps); + return DependenciesContext.Provider; +}; + +export const useAppDependencies = () => { + if (!DependenciesContext) { + throw new Error(`The app dependencies Context hasn't been set. + Use the "setAppDependencies()" method when bootstrapping the app.`); + } + return useContext(DependenciesContext); +}; + +const getAppProviders = (deps: AppDependencies) => { + const { + i18n: { Context: I18nContext }, + } = deps.core; + + // Create App dependencies context and get its provider + const AppDependenciesProvider = setAppDependencies(deps); + + return ({ children }: { children: ReactNode }) => ( - - , - element + + {children} + + + ); +}; + +export const renderReact = async ( + elem: HTMLElement | null, + core: CoreStart, + plugins: AppPlugins +) => { + const Providers = getAppProviders({ core, plugins }); + + render( + + + , + elem ); }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index fcc7e7f4d66294..58d71941070686 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -3,13 +3,12 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Option, fromNullable } from 'fp-ts/lib/Option'; +import { Option } from 'fp-ts/lib/Option'; import { HttpServiceBase } from 'kibana/public'; import { useRequestNp } from '../../../../public/shared_imports'; import { BASE_API_PATH } from '../constants'; import { ActionType } from '../../../../../actions/server/types'; -import { Result, asOk, asErr } from './result_type'; export interface RequestData { isLoading: boolean; @@ -51,15 +50,6 @@ export function hasReceivedAErrorCode( return false; } -function wrapInResult(status: any): Result, E> { - return hasReceivedAErrorCode(status.error) - ? asErr(status.error) - : asOk({ - ...status, - data: fromNullable(status.data), - }); -} - export interface ActionTypesResponse extends ActionType { id: string; name: string; @@ -72,23 +62,16 @@ export interface LoadActionTypese { } export interface ActionTypesApi { - loadActionTypes: ( - pollIntervalMs: number - ) => Result, LoadActionTypesErrorResponse>; + loadActionTypes: (pollIntervalMs: number) => RequestData; } -export function loadActionTypes( - http: HttpServiceBase, - pollIntervalMs?: number -): Result, LoadActionTypesErrorResponse> { - return wrapInResult( - useRequestNp(http, { - path: `${BASE_API_PATH}/types`, - method: 'get', - pollIntervalMs, - deserializer: (response: { data?: any[]; error?: any }) => { - return response; - }, - }) - ); +export function loadActionTypes(http: HttpServiceBase, pollIntervalMs?: number) { + return useRequestNp(http, { + path: `${BASE_API_PATH}/types`, + method: 'get', + pollIntervalMs, + deserializer: (response: { data?: any[]; error?: any }) => { + return response; + }, + }); } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts new file mode 100644 index 00000000000000..1c1f77ca583919 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.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 { textService } from './text'; +import { + linkToHome, + linkToAlerts, + linkToActions, + linkToNotifications, + linkToActivityLogs, +} from '../constants'; + +class BreadcrumbService { + private chrome: any; + private breadcrumbs: { + [key: string]: Array<{ + text: string; + href?: string; + }>; + } = { + management: [], + home: [], + alerts: [], + actions: [], + notifications: [], + activity_logs: [], + }; + + public init(chrome: any, managementBreadcrumb: any): void { + this.chrome = chrome; + this.breadcrumbs.management = [managementBreadcrumb]; + + // Home and sections + this.breadcrumbs.home = [ + ...this.breadcrumbs.management, + { + text: textService.breadcrumbs.home, + href: linkToHome(), + }, + ]; + this.breadcrumbs.alerts = [ + ...this.breadcrumbs.alerts, + { + text: textService.breadcrumbs.alerts, + href: linkToAlerts(), + }, + ]; + this.breadcrumbs.actions = [ + ...this.breadcrumbs.actions, + { + text: textService.breadcrumbs.actions, + href: linkToActions(), + }, + ]; + this.breadcrumbs.activity_logs = [ + ...this.breadcrumbs.home, + { + text: textService.breadcrumbs.activity_logs, + href: linkToActivityLogs(), + }, + ]; + this.breadcrumbs.notifications = [ + ...this.breadcrumbs.home, + { + text: textService.breadcrumbs.notifications, + href: linkToNotifications(), + }, + ]; + } + + public setBreadcrumbs(type: string): void { + const newBreadcrumbs = this.breadcrumbs[type] + ? [...this.breadcrumbs[type]] + : [...this.breadcrumbs.home]; + + // Pop off last breadcrumb + const lastBreadcrumb = newBreadcrumbs.pop() as { + text: string; + href?: string; + }; + + // Put last breadcrumb back without href + newBreadcrumbs.push({ + ...lastBreadcrumb, + href: undefined, + }); + + this.chrome.setBreadcrumbs(newBreadcrumbs); + } +} + +export const breadcrumbService = new BreadcrumbService(); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/doc_title.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/doc_title.ts new file mode 100644 index 00000000000000..d5082699d5e9a0 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/doc_title.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 { textService } from './text'; + +class DocTitleService { + private changeDocTitle: any = () => {}; + + public init(changeDocTitle: any): void { + this.changeDocTitle = changeDocTitle; + } + + public setTitle(page?: string): void { + if (!page || page === 'home') { + this.changeDocTitle(`${textService.breadcrumbs.home}`); + } else if (textService.breadcrumbs[page]) { + this.changeDocTitle(`${textService.breadcrumbs[page]} - ${textService.breadcrumbs.home}`); + } + } +} + +export const docTitleService = new DocTitleService(); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/flat_map.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/flat_map.ts deleted file mode 100644 index cdbb134dd85f5e..00000000000000 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/flat_map.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { Option, map, flatten } from 'fp-ts/lib/Option'; -import { pipe } from 'fp-ts/lib/pipeable'; - -type mapperToFlatten = (val: A) => Option; -export function flatMap(fn: mapperToFlatten) { - return function(optional: Option
): Option { - return pipe( - optional, - map(fn), - flatten - ); - }; -} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/result_type.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/result_type.ts deleted file mode 100644 index 59317a36ff3445..00000000000000 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/result_type.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -// eslint-disable-next-line @typescript-eslint/prefer-interface -export type Ok = { - tag: 'ok'; - value: T; -}; -// eslint-disable-next-line @typescript-eslint/prefer-interface -export type Err = { - tag: 'err'; - error: E; -}; -export type Result = Ok | Err; - -export function asOk(value: T): Ok { - return { - tag: 'ok', - value, - }; -} - -export function asErr(error: T): Err { - return { - tag: 'err', - error, - }; -} - -export function isOk(result: Result): result is Ok { - return result.tag === 'ok'; -} - -export function isErr(result: Result): result is Err { - return !isOk(result); -} - -export function mapResult( - result: Result, - mapOk: (value: T) => R, - mapErr: (err: E) => R -) { - return isOk(result) ? mapOk(result.value) : mapErr(result.error); -} - -export async function promiseResult(future: Promise): Promise> { - try { - return asOk(await future); - } catch (e) { - return asErr(e); - } -} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/text/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/text/index.ts new file mode 100644 index 00000000000000..3bed86f69937ac --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/text/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { textService } from './text'; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/text/text.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/text/text.ts new file mode 100644 index 00000000000000..28baa9be29238c --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/text/text.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. + */ + +class TextService { + public breadcrumbs: { [key: string]: string } = {}; + public i18n: any; + + public init(i18n: any): void { + this.i18n = i18n; + + this.breadcrumbs = { + home: i18n.translate('xpack.alertingUI.home.breadcrumbTitle', { + defaultMessage: 'Alerting UI', + }), + alerts: i18n.translate('xpack.alertingUI.alerts.breadcrumbTitle', { + defaultMessage: 'Alerts', + }), + actions: i18n.translate('xpack.alertingUI.actions.breadcrumbTitle', { + defaultMessage: 'Actions', + }), + notifications: i18n.translate('xpack.alertingUI.notifications.breadcrumbTitle', { + defaultMessage: 'Notifications', + }), + activity_logs: i18n.translate('xpack.alertingUI.activity_logs.breadcrumbTitle', { + defaultMessage: 'Activity logs', + }), + }; + } +} + +export const textService = new TextService(); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index a33fac996ff4ea..4181ff9f73bfa7 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -4,31 +4,32 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; -import { Option, option, some, getOrElse } from 'fp-ts/lib/Option'; -import { pipe } from 'fp-ts/lib/pipeable'; +import React, { Fragment } from 'react'; +import { RouteComponentProps } from 'react-router-dom'; import { EuiText, EuiPageContent, EuiEmptyPrompt, EuiInMemoryTable, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { flatMap } from '../../../lib/flat_map'; -import { mapResult } from '../../../lib/result_type'; import { PageError } from '../../../components/page_error'; -import { - loadActionTypes, - RequestData, - LoadActionTypesResponse, - LoadActionTypesErrorResponse, - ActionTypesResponse, -} from '../../../lib/api'; +import { loadActionTypes, ActionTypesResponse } from '../../../lib/api'; import { ActionsContext } from '../../../context/app_context'; - -const map = option.map; +import { useAppDependencies } from '../../../index'; interface ActionsListProps { api: any; } -export const ActionsList = ({ api }: ActionsListProps) => { +export const ActionsList: React.FunctionComponent> = ({ + match: { + params: { api }, + }, + history, +}) => { + const { + core: { http }, + } = useAppDependencies(); + + const { error, isLoading, data } = loadActionTypes(http); + const actionTypesTableColumns = [ { field: 'id', @@ -83,33 +84,33 @@ export const ActionsList = ({ api }: ActionsListProps) => { /> ); - return pipe( - api, - flatMap((actionTypesApi: any) => - mapResult< - RequestData, - LoadActionTypesErrorResponse, - Option - >( - loadActionTypes(actionTypesApi.api.http), - ({ isLoading: isActionTypesLoading, data: actionTypes }) => - isActionTypesLoading - ? some() - : map(actionTypes, (data: any) => ( - - - - - )), - error => - some( - - - - ) - ) - ), - getOrElse(() => ) + let content; + + if (isLoading) { + content = ActionTypesLoadingIndicator(); + } else if (error) { + content = ( + + + + ); + } else if (data.length === 0) { + content = NoActionTypes(); + } else { + content = ( + + + + ); + } + + return ( +
+ + + {content} + +
); }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx new file mode 100644 index 00000000000000..b5ae01ed108c83 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { EuiPageContent, EuiEmptyPrompt } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { RouteComponentProps } from 'react-router-dom'; + +interface AlertsListProps { + api: any; +} + +export const AlertsList: React.FunctionComponent> = ({ + match: { + params: { api }, + }, + history, +}) => { + return ( + + + + + } + body={'emptyPromptBody'} + data-test-subj="emptyPrompt" + /> + + ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts index 83d75b7d05d2d7..f6a8e78c7cb4df 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts @@ -12,10 +12,14 @@ import routes from 'ui/routes'; import template from '../../public/index.html'; import { renderReact } from './application'; import { BASE_PATH } from './application/constants'; +import { breadcrumbService } from './application/lib/breadcrumb'; +import { textService } from './application/lib/text'; export type Setup = void; export type Start = void; +const REACT_ROOT_ID = 'alertingRoot'; + export class ActionsPlugin implements Plugin { constructor(initializerContext: PluginInitializerContext) {} @@ -61,41 +65,50 @@ export class ActionsPlugin implements Plugin { defaultMessage: 'Alerting', }), order: 7, - url: `#${BASE_PATH}/`, + url: `#${BASE_PATH}`, }); - routes.when('/management/kibana/alerting/:param1?/:param2?/:param3?/:param4?', { + textService.init(i18n); + breadcrumbService.init(coreStart.chrome, pluginsStart.management.breadcrumb); + + const unmountReactApp = (): void => { + const elem = document.getElementById(REACT_ROOT_ID); + if (elem) { + unmountComponentAtNode(elem); + } + }; + + routes.when(`${BASE_PATH}/:section?/:subsection?/:view?/:id?`, { template, controller: (() => { - let elReactRoot: HTMLElement | undefined | null; - return ($injector: any, $scope: any) => { - const $route = $injector.get('$route'); - // clean up previously rendered React app if one exists - // this happens because of React Router redirects - if (elReactRoot) { - unmountComponentAtNode(elReactRoot); - } - $scope.$$postDigest(() => { - elReactRoot = document.getElementById('actionsRoot'); - renderReact(elReactRoot, coreStart.http); - const lastRoute = $route.current; - - const deregister = $scope.$on('$locationChangeSuccess', () => { - const currentRoute = $route.current; - if (lastRoute.$$route.template === currentRoute.$$route.template) { - $route.current = lastRoute; - } - }); + return ($route: any, $scope: any) => { + const appRoute = $route.current; + const stopListeningForLocationChange = $scope.$on('$locationChangeSuccess', () => { + const currentRoute = $route.current; + const isNavigationInApp = currentRoute.$$route.template === appRoute.$$route.template; + + // When we navigate within SR, prevent Angular from re-matching the route and rebuild the app + if (isNavigationInApp) { + $route.current = appRoute; + } else { + // Any clean up when user leaves SR + } $scope.$on('$destroy', () => { - if (deregister) { - deregister(); - } - if (elReactRoot) { - unmountComponentAtNode(elReactRoot); + if (stopListeningForLocationChange) { + stopListeningForLocationChange(); } + unmountReactApp(); }); }); + + $scope.$$postDigest(() => { + unmountReactApp(); + const elReactRoot = document.getElementById(REACT_ROOT_ID); + if (elReactRoot) { + renderReact(elReactRoot, coreStart, pluginsStart); + } + }); }; })(), }); diff --git a/x-pack/legacy/plugins/alerting_ui/public/index.html b/x-pack/legacy/plugins/alerting_ui/public/index.html index 83385ce118ceb7..1fa034c65347b4 100644 --- a/x-pack/legacy/plugins/alerting_ui/public/index.html +++ b/x-pack/legacy/plugins/alerting_ui/public/index.html @@ -1,3 +1,3 @@ -
+
diff --git a/x-pack/legacy/plugins/alerting_ui/public/shim.ts b/x-pack/legacy/plugins/alerting_ui/public/shim.ts index 92f234d336b55c..97cb48b0789b0a 100644 --- a/x-pack/legacy/plugins/alerting_ui/public/shim.ts +++ b/x-pack/legacy/plugins/alerting_ui/public/shim.ts @@ -5,6 +5,20 @@ */ import { management, MANAGEMENT_BREADCRUMB } from 'ui/management'; +import { CoreStart } from 'kibana/public'; + +export interface AppPlugins { + management: { + sections: typeof management; + getSection(): any; + breadcrumb: any; + }; +} + +export interface AppDependencies { + core: CoreStart; + plugins: AppPlugins; +} export function createShim() { return { From 3b3aadf5bd89fc448e3f26906819c5a3244079e9 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 10 Oct 2019 08:46:53 -0400 Subject: [PATCH 009/297] Change actions list to pull from actions API --- .../plugins/actions/server/actions_client.ts | 2 +- x-pack/legacy/plugins/actions/server/index.ts | 2 +- .../public/application/constants/index.ts | 2 +- .../np_ready/public/application/lib/api.ts | 23 +++++++- .../actions_list/components/actions_list.tsx | 57 ++++++++++--------- 5 files changed, 53 insertions(+), 33 deletions(-) diff --git a/x-pack/legacy/plugins/actions/server/actions_client.ts b/x-pack/legacy/plugins/actions/server/actions_client.ts index 823cb55abaf5e7..4daed0b8a2adec 100644 --- a/x-pack/legacy/plugins/actions/server/actions_client.ts +++ b/x-pack/legacy/plugins/actions/server/actions_client.ts @@ -15,7 +15,7 @@ interface ActionUpdate extends SavedObjectAttributes { secrets: SavedObjectAttributes; } -interface Action extends ActionUpdate { +export interface Action extends ActionUpdate { actionTypeId: string; } diff --git a/x-pack/legacy/plugins/actions/server/index.ts b/x-pack/legacy/plugins/actions/server/index.ts index faafb0db330cd3..71532c32704fde 100644 --- a/x-pack/legacy/plugins/actions/server/index.ts +++ b/x-pack/legacy/plugins/actions/server/index.ts @@ -6,5 +6,5 @@ export { init } from './init'; export { ActionsPlugin, ActionTypeExecutorOptions, ActionType } from './types'; -export { ActionsClient } from './actions_client'; +export { Action, ActionsClient } from './actions_client'; export { PluginSetupContract, PluginStartContract } from './plugin'; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts index 3fee275735f920..60d3d26bab4e4f 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts @@ -5,7 +5,7 @@ */ export const BASE_PATH = '/management/kibana/alerting'; -export const BASE_API_PATH = '../api/action'; +export const BASE_ACTION_API_PATH = '../api/action'; export const DEFAULT_SECTION: Section = 'alerts'; export type Section = 'actions' | 'alerts' | 'activity_logs' | 'notifications'; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index 58d71941070686..e4c30ffaad37ea 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -6,9 +6,9 @@ import { Option } from 'fp-ts/lib/Option'; import { HttpServiceBase } from 'kibana/public'; import { useRequestNp } from '../../../../public/shared_imports'; -import { BASE_API_PATH } from '../constants'; +import { BASE_ACTION_API_PATH } from '../constants'; -import { ActionType } from '../../../../../actions/server/types'; +import { ActionType, Action } from '../../../../../actions/server'; export interface RequestData { isLoading: boolean; @@ -67,7 +67,7 @@ export interface ActionTypesApi { export function loadActionTypes(http: HttpServiceBase, pollIntervalMs?: number) { return useRequestNp(http, { - path: `${BASE_API_PATH}/types`, + path: `${BASE_ACTION_API_PATH}/types`, method: 'get', pollIntervalMs, deserializer: (response: { data?: any[]; error?: any }) => { @@ -75,3 +75,20 @@ export function loadActionTypes(http: HttpServiceBase, pollIntervalMs?: number) }, }); } + +export interface ActionsResponse extends Action { + id: string; + description: string; + actionTypeId: string; +} + +export function loadActions(http: HttpServiceBase, pollIntervalMs?: number) { + return useRequestNp(http, { + path: `${BASE_ACTION_API_PATH}/_find`, + method: 'get', + pollIntervalMs, + deserializer(response: { data?: any[]; error?: any }) { + return response; + }, + }); +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 4181ff9f73bfa7..a76994f674b855 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -10,7 +10,7 @@ import { EuiText, EuiPageContent, EuiEmptyPrompt, EuiInMemoryTable, EuiSpacer } import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { PageError } from '../../../components/page_error'; -import { loadActionTypes, ActionTypesResponse } from '../../../lib/api'; +import { loadActions, ActionsResponse } from '../../../lib/api'; import { ActionsContext } from '../../../context/app_context'; import { useAppDependencies } from '../../../index'; @@ -28,21 +28,24 @@ export const ActionsList: React.FunctionComponent { + const ActionsTable = ({ actions }: { actions: ActionsResponse[] }) => { return ( } rowProps={() => ({ @@ -72,40 +75,40 @@ export const ActionsList: React.FunctionComponent ({ 'data-test-subj': 'cell', })} - data-test-subj="actionTypesTable" + data-test-subj="actionsTable" /> ); }; - const ActionTypesLoadingIndicator = () => ( + const ActionsLoadingIndicator = () => ( ); let content; if (isLoading) { - content = ActionTypesLoadingIndicator(); + content = ActionsLoadingIndicator(); } else if (error) { content = ( ); - } else if (data.length === 0) { - content = NoActionTypes(); + } else if (result.data.length === 0) { + content = NoActions(); } else { content = ( - + ); } return ( -
+
{content} @@ -114,10 +117,10 @@ export const ActionsList: React.FunctionComponent { +export const NoActions = () => { const emptyPromptBody = ( -

No Action Types

+

No Actions

); @@ -128,8 +131,8 @@ export const NoActionTypes = () => { title={

} From c3d16f213271a0e788683f9db7ac9dfeff3706c6 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 10 Oct 2019 10:53:23 -0400 Subject: [PATCH 010/297] Switch to EuiBasicTable --- .../actions_list/components/actions_list.tsx | 91 +++++-------------- 1 file changed, 24 insertions(+), 67 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index a76994f674b855..db5e8875f94e9b 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -6,11 +6,10 @@ import React, { Fragment } from 'react'; import { RouteComponentProps } from 'react-router-dom'; -import { EuiText, EuiPageContent, EuiEmptyPrompt, EuiInMemoryTable, EuiSpacer } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiPageContent, EuiBasicTable, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { PageError } from '../../../components/page_error'; -import { loadActions, ActionsResponse } from '../../../lib/api'; +import { loadActions } from '../../../lib/api'; import { ActionsContext } from '../../../context/app_context'; import { useAppDependencies } from '../../../index'; @@ -53,56 +52,40 @@ export const ActionsList: React.FunctionComponent { - return ( - - } - rowProps={() => ({ - 'data-test-subj': 'row', - })} - cellProps={() => ({ - 'data-test-subj': 'cell', - })} - data-test-subj="actionsTable" - /> - ); - }; - - const ActionsLoadingIndicator = () => ( - - ); - let content; - if (isLoading) { - content = ActionsLoadingIndicator(); - } else if (error) { + if (error) { content = ( ); - } else if (result.data.length === 0) { - content = NoActions(); } else { content = ( - + ({ + 'data-test-subj': 'row', + })} + cellProps={() => ({ + 'data-test-subj': 'cell', + })} + data-test-subj="actionsTable" + /> ); } @@ -117,32 +100,6 @@ export const ActionsList: React.FunctionComponent { - const emptyPromptBody = ( - -

No Actions

-
- ); - - return ( - - - - - } - body={emptyPromptBody} - data-test-subj="emptyPrompt" - /> - - ); -}; - export const ContentWrapper = ({ children }: { children: React.ReactNode }) => { return ( From bf8179e6bd0728d10965ecda5e572fa8566497fa Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 10 Oct 2019 12:13:02 -0700 Subject: [PATCH 011/297] Moved management section registration to Plugin setup --- .../alerting_ui/np_ready/public/legacy.ts | 5 +-- .../alerting_ui/np_ready/public/plugin.ts | 33 +++---------------- .../legacy/plugins/alerting_ui/public/shim.ts | 6 +++- 3 files changed, 13 insertions(+), 31 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/legacy.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/legacy.ts index 210f60fa64c71f..0afd9b35dc7a49 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/legacy.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/legacy.ts @@ -3,10 +3,11 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { npStart } from 'ui/new_platform'; +import { npStart, npSetup } from 'ui/new_platform'; import { createShim } from '../../public/shim'; import { plugin } from '.'; const pluginInstance = plugin({} as any); -const { pluginsStart } = createShim(); +const { pluginsSetup, pluginsStart } = createShim(); +pluginInstance.setup(npSetup.core, pluginsSetup); pluginInstance.start(npStart.core, pluginsStart); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts index f6a8e78c7cb4df..a4f78dca8daf8a 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts @@ -20,44 +20,19 @@ export type Start = void; const REACT_ROOT_ID = 'alertingRoot'; -export class ActionsPlugin implements Plugin { +export class ActionsPlugin implements Plugin { constructor(initializerContext: PluginInitializerContext) {} - public setup(coreSetup: CoreSetup): Setup { - // TODO: management doesn't exposed in core yet + public setup(coreSetup: CoreSetup, pluginsSetup: any): Setup { /* The code below would be replacing for current: uiExports: { managementSections: ['myplugin/management'], } */ - // Registering a new app to a new section - /* const mySection = coreSetup.management.sections.register({ - id: 'my-section', - title: 'My Main Section', // display name - order: 10, - euiIconType: 'iconName', - }); - mySection.registerApp({ - id: 'my-management-app', - title: 'My Management App', // display name - order: 20, - async mount(context, params) { - const { renderApp } = await import('./my-section'); - return renderApp(context, params); - } - }); - - // Registering a new app to an existing section - const kibanaSection = management.sections.get('kibana'); - kibanaSection.registerApp({ id: 'my-kibana-management-app', ... }); - */ - } - - public start(coreStart: CoreStart, pluginsStart: any) { const { management: { getSection }, - } = pluginsStart; + } = pluginsSetup; const kbnSection = getSection('kibana'); kbnSection.register('alerting', { @@ -67,7 +42,9 @@ export class ActionsPlugin implements Plugin { order: 7, url: `#${BASE_PATH}`, }); + } + public start(coreStart: CoreStart, pluginsStart: any) { textService.init(i18n); breadcrumbService.init(coreStart.chrome, pluginsStart.management.breadcrumb); diff --git a/x-pack/legacy/plugins/alerting_ui/public/shim.ts b/x-pack/legacy/plugins/alerting_ui/public/shim.ts index 97cb48b0789b0a..ec12afd337e0dd 100644 --- a/x-pack/legacy/plugins/alerting_ui/public/shim.ts +++ b/x-pack/legacy/plugins/alerting_ui/public/shim.ts @@ -22,9 +22,13 @@ export interface AppDependencies { export function createShim() { return { - pluginsStart: { + pluginsSetup: { management: { getSection: management.getSection.bind(management), + }, + }, + pluginsStart: { + management: { breadcrumb: MANAGEMENT_BREADCRUMB, }, }, From 05a63f34de9d90f1832f64e6637122eaec789010 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 11 Oct 2019 07:54:10 -0400 Subject: [PATCH 012/297] Start work on sorting --- x-pack/legacy/plugins/actions/server/actions_client.ts | 1 + x-pack/legacy/plugins/actions/server/routes/find.ts | 3 +++ x-pack/legacy/plugins/alerting/server/alerts_client.ts | 1 + x-pack/legacy/plugins/alerting/server/routes/find.ts | 3 +++ .../sections/actions_list/components/actions_list.tsx | 9 ++++++++- 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/actions/server/actions_client.ts b/x-pack/legacy/plugins/actions/server/actions_client.ts index 4daed0b8a2adec..15cfdce12a7ac8 100644 --- a/x-pack/legacy/plugins/actions/server/actions_client.ts +++ b/x-pack/legacy/plugins/actions/server/actions_client.ts @@ -31,6 +31,7 @@ interface FindOptions { defaultSearchOperator?: 'AND' | 'OR'; searchFields?: string[]; sortField?: string; + sortOrder?: string; hasReference?: { type: string; id: string; diff --git a/x-pack/legacy/plugins/actions/server/routes/find.ts b/x-pack/legacy/plugins/actions/server/routes/find.ts index e521ba174f2879..e0bbade2c26c25 100644 --- a/x-pack/legacy/plugins/actions/server/routes/find.ts +++ b/x-pack/legacy/plugins/actions/server/routes/find.ts @@ -17,6 +17,7 @@ interface FindRequest extends WithoutQueryAndParams { default_search_operator: 'AND' | 'OR'; search_fields?: string[]; sort_field?: string; + sort_order?: string; has_reference?: { type: string; id: string; @@ -50,6 +51,7 @@ export const findActionRoute = { .items(Joi.string()) .single(), sort_field: Joi.string(), + sort_order: Joi.string(), has_reference: Joi.object() .keys({ type: Joi.string().required(), @@ -77,6 +79,7 @@ export const findActionRoute = { defaultSearchOperator: query.default_search_operator, searchFields: query.search_fields, sortField: query.sort_field, + sortOrder: query.sort_order, hasReference: query.has_reference, fields: query.fields, filter: query.filter, diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.ts index 39d0277ff53b3c..0be2bc4f323914 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.ts @@ -40,6 +40,7 @@ interface FindOptions { defaultSearchOperator?: 'AND' | 'OR'; searchFields?: string[]; sortField?: string; + sortOrder?: string; hasReference?: { type: string; id: string; diff --git a/x-pack/legacy/plugins/alerting/server/routes/find.ts b/x-pack/legacy/plugins/alerting/server/routes/find.ts index 75cf93b18398ff..954ae9fc623aaa 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/find.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/find.ts @@ -17,6 +17,7 @@ interface FindRequest extends WithoutQueryAndParams { default_search_operator: 'AND' | 'OR'; search_fields?: string[]; sort_field?: string; + sort_order?: string; has_reference?: { type: string; id: string; @@ -50,6 +51,7 @@ export const findAlertRoute = { .items(Joi.string()) .single(), sort_field: Joi.string(), + sort_order: Joi.string(), has_reference: Joi.object() .keys({ type: Joi.string().required(), @@ -77,6 +79,7 @@ export const findAlertRoute = { defaultSearchOperator: query.default_search_operator, searchFields: query.search_fields, sortField: query.sort_field, + sortOrder: query.sort_order, hasReference: query.has_reference, fields: query.fields, filter: query.filter, diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index db5e8875f94e9b..0a765c237dbe94 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment } from 'react'; +import React, { Fragment, useState } from 'react'; import { RouteComponentProps } from 'react-router-dom'; import { EuiPageContent, EuiBasicTable, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -27,6 +27,8 @@ export const ActionsList: React.FunctionComponent { + setSortField(sort.field); + setSortDirection(sort.direction); + }} /> ); From d5988ac09ed8d406ec6ed75786b4b7e21376f7ea Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 11 Oct 2019 08:28:26 -0400 Subject: [PATCH 013/297] Add sorting support --- .../np_ready/public/application/lib/api.ts | 12 ++++----- .../actions_list/components/actions_list.tsx | 26 +++++++++++++++---- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index e4c30ffaad37ea..e17973b445fb59 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -82,13 +82,11 @@ export interface ActionsResponse extends Action { actionTypeId: string; } -export function loadActions(http: HttpServiceBase, pollIntervalMs?: number) { - return useRequestNp(http, { - path: `${BASE_ACTION_API_PATH}/_find`, - method: 'get', - pollIntervalMs, - deserializer(response: { data?: any[]; error?: any }) { - return response; +export async function loadActions(http: HttpServiceBase, sortField: string, sortOrder: string) { + return http.get(`${BASE_ACTION_API_PATH}/_find`, { + query: { + sort_field: sortField, + sort_order: sortOrder, }, }); } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 0a765c237dbe94..37955756a752f2 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, useState } from 'react'; +import React, { Fragment, useState, useEffect } from 'react'; import { RouteComponentProps } from 'react-router-dom'; import { EuiPageContent, EuiBasicTable, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -27,9 +27,25 @@ export const ActionsList: React.FunctionComponent([]); + + useEffect(() => { + (async () => { + setIsLoading(true); + try { + const response = await loadActions(http, sortField, sortDirection); + setData(response.data); + } catch (e) { + setError(e); + } finally { + setIsLoading(false); + } + })(); + }, [sortField, sortDirection]); const actionsTableColumns = [ { @@ -40,7 +56,7 @@ export const ActionsList: React.FunctionComponent ({ From 211b39de2ce0071d5b863acc2cfcb3a2704262c3 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 11 Oct 2019 08:44:37 -0400 Subject: [PATCH 014/297] Add pagination --- .../np_ready/public/application/lib/api.ts | 14 +++++-- .../actions_list/components/actions_list.tsx | 37 +++++++++++++++---- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index e17973b445fb59..707a43d09de23a 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -76,17 +76,25 @@ export function loadActionTypes(http: HttpServiceBase, pollIntervalMs?: number) }); } +export interface LoadActionsOpts { + http: HttpServiceBase; + sort: { field: string; direction: 'asc' | 'desc' }; + page: { index: number; size: number }; +} + export interface ActionsResponse extends Action { id: string; description: string; actionTypeId: string; } -export async function loadActions(http: HttpServiceBase, sortField: string, sortOrder: string) { +export async function loadActions({ http, sort, page }: LoadActionsOpts) { return http.get(`${BASE_ACTION_API_PATH}/_find`, { query: { - sort_field: sortField, - sort_order: sortOrder, + sort_field: sort.field, + sort_order: sort.direction, + page: page.index + 1, + per_page: page.size, }, }); } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 37955756a752f2..4aabccf9d22d52 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -16,6 +16,14 @@ import { useAppDependencies } from '../../../index'; interface ActionsListProps { api: any; } +interface Sorting { + field: string; + direction: 'asc' | 'desc'; +} +interface Pagination { + index: number; + size: number; +} export const ActionsList: React.FunctionComponent> = ({ match: { @@ -27,25 +35,27 @@ export const ActionsList: React.FunctionComponent([]); + const [totalItemCount, setTotalItemCount] = useState(0); + const [page, setPage] = useState({ index: 0, size: 10 }); + const [sort, setSort] = useState({ field: 'actionTypeId', direction: 'asc' }); useEffect(() => { (async () => { setIsLoading(true); try { - const response = await loadActions(http, sortField, sortDirection); + const response = await loadActions({ http, sort, page }); setData(response.data); + setTotalItemCount(response.total); } catch (e) { setError(e); } finally { setIsLoading(false); } })(); - }, [sortField, sortDirection]); + }, [sort, page]); const actionsTableColumns = [ { @@ -103,10 +113,21 @@ export const ActionsList: React.FunctionComponent { - setSortField(sort.field); - setSortDirection(sort.direction); + sorting={{ sort }} + pagination={{ + pageIndex: page.index, + pageSize: page.size, + totalItemCount, + }} + onChange={({ + sort: changedSort, + page: changedPage, + }: { + sort: Sorting; + page: Pagination; + }) => { + setPage(changedPage); + setSort(changedSort); }} /> From ecdc17a60b6985dbf98ddc1242b90a767e1c04ad Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 11 Oct 2019 08:55:36 -0400 Subject: [PATCH 015/297] More types --- .../np_ready/public/application/lib/api.ts | 24 ++++++++++++++----- .../actions_list/components/actions_list.tsx | 17 ++++++------- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index 707a43d09de23a..f3704920a18a91 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -8,7 +8,7 @@ import { HttpServiceBase } from 'kibana/public'; import { useRequestNp } from '../../../../public/shared_imports'; import { BASE_ACTION_API_PATH } from '../constants'; -import { ActionType, Action } from '../../../../../actions/server'; +import { ActionType } from '../../../../../actions/server'; export interface RequestData { isLoading: boolean; @@ -76,19 +76,31 @@ export function loadActionTypes(http: HttpServiceBase, pollIntervalMs?: number) }); } +export interface Action { + id: string; + actionTypeId: string; + description: string; + config: Record; +} + export interface LoadActionsOpts { http: HttpServiceBase; sort: { field: string; direction: 'asc' | 'desc' }; page: { index: number; size: number }; } -export interface ActionsResponse extends Action { - id: string; - description: string; - actionTypeId: string; +export interface LoadActionsResponse { + page: number; + perPage: number; + total: number; + data: Action[]; } -export async function loadActions({ http, sort, page }: LoadActionsOpts) { +export async function loadActions({ + http, + sort, + page, +}: LoadActionsOpts): Promise { return http.get(`${BASE_ACTION_API_PATH}/_find`, { query: { sort_field: sort.field, diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 4aabccf9d22d52..6ab56aeba471d3 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -9,7 +9,7 @@ import { RouteComponentProps } from 'react-router-dom'; import { EuiPageContent, EuiBasicTable, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { PageError } from '../../../components/page_error'; -import { loadActions } from '../../../lib/api'; +import { loadActions, Action } from '../../../lib/api'; import { ActionsContext } from '../../../context/app_context'; import { useAppDependencies } from '../../../index'; @@ -35,22 +35,23 @@ export const ActionsList: React.FunctionComponent([]); - const [totalItemCount, setTotalItemCount] = useState(0); + const [data, setData] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [errorCode, setErrorCode] = useState(null); + const [totalItemCount, setTotalItemCount] = useState(0); const [page, setPage] = useState({ index: 0, size: 10 }); const [sort, setSort] = useState({ field: 'actionTypeId', direction: 'asc' }); useEffect(() => { (async () => { setIsLoading(true); + setErrorCode(null); try { const response = await loadActions({ http, sort, page }); setData(response.data); setTotalItemCount(response.total); } catch (e) { - setError(e); + setErrorCode(e.response.status); } finally { setIsLoading(false); } @@ -92,10 +93,10 @@ export const ActionsList: React.FunctionComponent - + ); } else { From 6821358db585735642e3c180be4ccd66b88e4830 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 11 Oct 2019 08:58:03 -0400 Subject: [PATCH 016/297] Cleanup api.ts --- .../np_ready/public/application/lib/api.ts | 70 ------------------- 1 file changed, 70 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index f3704920a18a91..dafa24e5ad4e2b 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -3,79 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Option } from 'fp-ts/lib/Option'; import { HttpServiceBase } from 'kibana/public'; -import { useRequestNp } from '../../../../public/shared_imports'; import { BASE_ACTION_API_PATH } from '../constants'; -import { ActionType } from '../../../../../actions/server'; - -export interface RequestData { - isLoading: boolean; - data: Option; - sendRequest?: any; -} - -export interface RequestStatus { - isLoading: boolean; - error?: E; - data?: T; - sendRequest?: any; -} - -export interface LoadActionTypesResponse { - data: ActionTypesResponse[]; -} - -export interface LoadActionTypesError { - status: number; -} -export type LoadActionTypesErrorResponse = LoadActionTypesError | LoadActionTypesError[]; - -export function hasReceivedAErrorCode( - errorOrErrors: any -): errorOrErrors is LoadActionTypesErrorResponse { - const errors = Array.isArray(errorOrErrors) ? errorOrErrors : [errorOrErrors]; - const firstError = errors.find((error: any) => { - if (error) { - return [403, 404].includes(error.status); - } - - return false; - }); - - if (firstError) { - return true; - } - return false; -} - -export interface ActionTypesResponse extends ActionType { - id: string; - name: string; -} -export interface LoadActionTypese { - page: number; - perPage: number; - total: number; - data: ActionTypesResponse[]; -} - -export interface ActionTypesApi { - loadActionTypes: (pollIntervalMs: number) => RequestData; -} - -export function loadActionTypes(http: HttpServiceBase, pollIntervalMs?: number) { - return useRequestNp(http, { - path: `${BASE_ACTION_API_PATH}/types`, - method: 'get', - pollIntervalMs, - deserializer: (response: { data?: any[]; error?: any }) => { - return response; - }, - }); -} - export interface Action { id: string; actionTypeId: string; From 4eb77ab2af1ce260c68e3d713dc717f5d7799d48 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 11 Oct 2019 09:13:04 -0400 Subject: [PATCH 017/297] Dislpay action type instead of actionTypeId --- .../server/builtin_action_types/email.ts | 4 ++- .../server/builtin_action_types/es_index.ts | 4 ++- .../server/builtin_action_types/pagerduty.ts | 4 ++- .../server/builtin_action_types/server_log.ts | 4 ++- .../server/builtin_action_types/slack.ts | 4 ++- .../server/builtin_action_types/webhook.ts | 4 ++- .../np_ready/public/application/lib/api.ts | 17 ++++++++++ .../actions_list/components/actions_list.tsx | 34 ++++++++++++++----- 8 files changed, 61 insertions(+), 14 deletions(-) diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/email.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/email.ts index c68d9acd8b174a..ace5443e778c08 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/email.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/email.ts @@ -102,7 +102,9 @@ function validateParams(paramsObject: any): string | void { export function getActionType({ logger }: { logger: Logger }): ActionType { return { id: '.email', - name: 'email', + name: i18n.translate('xpack.actions.builtin.email.name', { + defaultMessage: 'Email', + }), validate: { config: ConfigSchema, secrets: SecretsSchema, diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/es_index.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/es_index.ts index 1d5fe9271ad11e..9bed5b50e0d5a8 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/es_index.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/es_index.ts @@ -38,7 +38,9 @@ const ParamsSchema = schema.object({ export function getActionType({ logger }: { logger: Logger }): ActionType { return { id: '.index', - name: 'index', + name: i18n.translate('xpack.actions.builtin.esIndex.name', { + defaultMessage: 'Index', + }), validate: { config: ConfigSchema, params: ParamsSchema, diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/pagerduty.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/pagerduty.ts index ec45e298d39022..7f6eb57794b242 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/pagerduty.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/pagerduty.ts @@ -89,7 +89,9 @@ function validateParams(paramsObject: any): string | void { export function getActionType({ logger }: { logger: Logger }): ActionType { return { id: '.pagerduty', - name: 'pagerduty', + name: i18n.translate('xpack.actions.builtin.pagerduty.name', { + defaultMessage: 'PagerDuty', + }), validate: { config: ConfigSchema, secrets: SecretsSchema, diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.ts index f17430b734c66b..f7fd30d1d3f0ae 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.ts @@ -31,7 +31,9 @@ const ParamsSchema = schema.object({ export function getActionType({ logger }: { logger: Logger }): ActionType { return { id: '.server-log', - name: 'server-log', + name: i18n.translate('xpack.actions.builtin.serverLog.name', { + defaultMessage: 'Server Log', + }), validate: { params: ParamsSchema, }, diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/slack.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/slack.ts index 8ec569a69ff235..5e3021c37fac45 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/slack.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/slack.ts @@ -42,7 +42,9 @@ export function getActionType( ): ActionType { return { id: '.slack', - name: 'slack', + name: i18n.translate('xpack.actions.builtin.slack.name', { + defaultMessage: 'Slack', + }), validate: { secrets: SecretsSchema, params: ParamsSchema, diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/webhook.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/webhook.ts index b91fd86b0b6824..fcaf3471ff5637 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/webhook.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/webhook.ts @@ -56,7 +56,9 @@ export function getActionType({ }): ActionType { return { id: '.webhook', - name: 'webhook', + name: i18n.translate('xpack.actions.builtin.webhook.name', { + defaultMessage: 'Webhook', + }), validate: { config: schema.object(configSchemaProps, { validate: curry(valdiateActionTypeConfig)(configurationUtilities), diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index dafa24e5ad4e2b..79da03200340ed 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -6,6 +6,11 @@ import { HttpServiceBase } from 'kibana/public'; import { BASE_ACTION_API_PATH } from '../constants'; +export interface ActionType { + id: string; + name: string; +} + export interface Action { id: string; actionTypeId: string; @@ -13,6 +18,18 @@ export interface Action { config: Record; } +export interface LoadActionTypesOpts { + http: HttpServiceBase; +} + +export type LoadActionTypesResponse = ActionType[]; + +export async function loadActionTypes({ + http, +}: LoadActionTypesOpts): Promise { + return http.get(`${BASE_ACTION_API_PATH}/types`); +} + export interface LoadActionsOpts { http: HttpServiceBase; sort: { field: string; direction: 'asc' | 'desc' }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 6ab56aeba471d3..bffbfb23a6d413 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -9,7 +9,7 @@ import { RouteComponentProps } from 'react-router-dom'; import { EuiPageContent, EuiBasicTable, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { PageError } from '../../../components/page_error'; -import { loadActions, Action } from '../../../lib/api'; +import { Action, ActionType, loadActions, loadActionTypes } from '../../../lib/api'; import { ActionsContext } from '../../../context/app_context'; import { useAppDependencies } from '../../../index'; @@ -24,6 +24,9 @@ interface Pagination { index: number; size: number; } +interface Data extends Action { + actionType: ActionType['name']; +} export const ActionsList: React.FunctionComponent> = ({ match: { @@ -35,7 +38,7 @@ export const ActionsList: React.FunctionComponent([]); + const [data, setData] = useState([]); const [isLoading, setIsLoading] = useState(false); const [errorCode, setErrorCode] = useState(null); const [totalItemCount, setTotalItemCount] = useState(0); @@ -47,9 +50,24 @@ export const ActionsList: React.FunctionComponent = {}; + for (const actionType of actionTypesResponse) { + actionTypesById[actionType.id] = actionType; + } + const updatedData = actionsResponse.data.map( + (action: Action): Data => ({ + ...action, + actionType: actionTypesById[action.actionTypeId] + ? actionTypesById[action.actionTypeId].name + : action.actionTypeId, + }) + ); + setData(updatedData); + setTotalItemCount(actionsResponse.total); } catch (e) { setErrorCode(e.response.status); } finally { @@ -71,14 +89,14 @@ export const ActionsList: React.FunctionComponent Date: Fri, 11 Oct 2019 09:19:54 -0400 Subject: [PATCH 018/297] More cleanup --- .../es_ui_shared/public/request/index.ts | 9 - .../es_ui_shared/public/request/request_np.ts | 165 ------------------ .../public/application/lib/navigation.ts | 4 +- .../alerting_ui/public/shared_imports.ts | 13 -- 4 files changed, 2 insertions(+), 189 deletions(-) delete mode 100644 src/plugins/es_ui_shared/public/request/request_np.ts delete mode 100644 x-pack/legacy/plugins/alerting_ui/public/shared_imports.ts diff --git a/src/plugins/es_ui_shared/public/request/index.ts b/src/plugins/es_ui_shared/public/request/index.ts index fbee6b4d848c40..f942a9cc3932bb 100644 --- a/src/plugins/es_ui_shared/public/request/index.ts +++ b/src/plugins/es_ui_shared/public/request/index.ts @@ -25,12 +25,3 @@ export { sendRequest, useRequest, } from './request'; - -export { - SendRequestConfigNp, - SendRequestResponseNp, - UseRequestConfigNp, - UseRequestResponseNp, - sendRequestNp, - useRequestNp, -} from './request_np'; diff --git a/src/plugins/es_ui_shared/public/request/request_np.ts b/src/plugins/es_ui_shared/public/request/request_np.ts deleted file mode 100644 index cfaa6ac102292f..00000000000000 --- a/src/plugins/es_ui_shared/public/request/request_np.ts +++ /dev/null @@ -1,165 +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 { useEffect, useState, useRef } from 'react'; -import { HttpServiceBase } from 'kibana/public'; - -export interface SendRequestConfigNp { - path: string; - method: 'get' | 'post' | 'put' | 'delete' | 'patch'; - body?: any; -} - -export interface SendRequestResponseNp { - data: any; - error: Error | null; -} - -export interface UseRequestConfigNp extends SendRequestConfigNp { - pollIntervalMs?: number; - initialData?: any; - deserializer?: (data: any) => any; -} - -export interface UseRequestResponseNp { - isInitialRequest: boolean; - isLoading: boolean; - error: null | unknown; - data: any; - sendRequestNp: (...args: any[]) => Promise; -} - -export const sendRequestNp = async ( - http: HttpServiceBase, - { path, method, body }: SendRequestConfigNp -): Promise => { - try { - const response = await (http as any)[method](path, body); - if (typeof response === 'undefined') { - throw new Error(response); - } - - return { data: response, error: null }; - } catch (e) { - return { - data: null, - error: e.response ? e.response : e, - }; - } -}; - -export const useRequestNp = ( - http: HttpServiceBase, - { - path, - method, - body, - pollIntervalMs, - initialData, - deserializer = (data: any): any => data, - }: UseRequestConfigNp -): UseRequestResponseNp => { - // Main states for tracking request status and data - const [error, setError] = useState(null); - const [isLoading, setIsLoading] = useState(true); - const [data, setData] = useState(initialData); - - // Consumers can use isInitialRequest to implement a polling UX. - const [isInitialRequest, setIsInitialRequest] = useState(true); - const pollInterval = useRef(null); - const pollIntervalId = useRef(null); - - // We always want to use the most recently-set interval in scheduleRequest. - pollInterval.current = pollIntervalMs; - - // Tied to every render and bound to each request. - let isOutdatedRequest = false; - - const scheduleRequest = () => { - // Clear current interval - if (pollIntervalId.current) { - clearTimeout(pollIntervalId.current); - } - - // Set new interval - if (pollInterval.current) { - pollIntervalId.current = setTimeout(_sendRequest, pollInterval.current); - } - }; - - const _sendRequest = async () => { - // We don't clear error or data, so it's up to the consumer to decide whether to display the - // "old" error/data or loading state when a new request is in-flight. - setIsLoading(true); - - const requestBody = { - path, - method, - body, - }; - - const response = await sendRequestNp(http, requestBody); - const { data: serializedResponseData, error: responseError } = response; - const responseData = deserializer(serializedResponseData); - - // If an outdated request has resolved, DON'T update state, but DO allow the processData handler - // to execute side effects like update telemetry. - if (isOutdatedRequest) { - return { data: null, error: null }; - } - - setError(responseError); - setData(responseData); - setIsLoading(false); - setIsInitialRequest(false); - - // If we're on an interval, we need to schedule the next request. This also allows us to reset - // the interval if the user has manually requested the data, to avoid doubled-up requests. - scheduleRequest(); - - return { data: serializedResponseData, error: responseError }; - }; - - useEffect(() => { - _sendRequest(); - // To be functionally correct we'd send a new request if the method, path, or body changes. - // But it doesn't seem likely that the method will change and body is likely to be a new - // object even if its shape hasn't changed, so for now we're just watching the path. - }, [path]); - - useEffect(() => { - scheduleRequest(); - - // Clean up intervals and inflight requests and corresponding state changes - return () => { - isOutdatedRequest = true; - if (pollIntervalId.current) { - clearTimeout(pollIntervalId.current); - } - }; - }, [pollIntervalMs]); - - return { - isInitialRequest, - isLoading, - error, - data, - sendRequestNp: _sendRequest, // Gives the user the ability to manually request data - }; -}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/navigation.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/navigation.ts index f0fbb3802fea71..db9360e60f8cf7 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/navigation.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/navigation.ts @@ -10,6 +10,6 @@ export const registerRouter = (aRouter: any) => { router = aRouter; }; -export const goToActionTypesList = () => { - router.history.push({ pathname: `${BASE_PATH}actionTypes` }); +export const goToActionsList = () => { + router.history.push({ pathname: `${BASE_PATH}actions` }); }; diff --git a/x-pack/legacy/plugins/alerting_ui/public/shared_imports.ts b/x-pack/legacy/plugins/alerting_ui/public/shared_imports.ts deleted file mode 100644 index 0d3f9c8b32ba58..00000000000000 --- a/x-pack/legacy/plugins/alerting_ui/public/shared_imports.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -export { - SendRequestConfigNp, - SendRequestResponseNp, - UseRequestConfigNp, - sendRequestNp, - useRequestNp, -} from '../../../../../src/plugins/es_ui_shared/public/request'; From 2c00fc922f9466ecfd0e4093b48dfa8a25b45382 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 11 Oct 2019 09:52:00 -0400 Subject: [PATCH 019/297] Avoid loading action types on every load of actions, though this flickers in the UI the action type column (from id to name) --- .../actions_list/components/actions_list.tsx | 39 ++++++++++++++----- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index bffbfb23a6d413..86c23592f92eb9 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -27,6 +27,7 @@ interface Pagination { interface Data extends Action { actionType: ActionType['name']; } +type ActionTypeIndex = Record; export const ActionsList: React.FunctionComponent> = ({ match: { @@ -38,6 +39,7 @@ export const ActionsList: React.FunctionComponent({}); const [data, setData] = useState([]); const [isLoading, setIsLoading] = useState(false); const [errorCode, setErrorCode] = useState(null); @@ -45,24 +47,41 @@ export const ActionsList: React.FunctionComponent({ index: 0, size: 10 }); const [sort, setSort] = useState({ field: 'actionTypeId', direction: 'asc' }); + useEffect(() => { + (async () => { + const actionTypes = await loadActionTypes({ http }); + const index: ActionTypeIndex = {}; + for (const actionType of actionTypes) { + index[actionType.id] = actionType; + } + setActionTypesIndex(index); + })(); + }); + + useEffect(() => { + const updatedData: Data[] = []; + for (const action of data) { + updatedData.push({ + ...action, + actionType: actionTypesIndex[action.actionTypeId] + ? actionTypesIndex[action.actionTypeId].name + : action.actionTypeId, + }); + } + setData(updatedData); + }, [actionTypesIndex]); + useEffect(() => { (async () => { setIsLoading(true); setErrorCode(null); try { - const [actionsResponse, actionTypesResponse] = await Promise.all([ - loadActions({ http, sort, page }), - loadActionTypes({ http }), - ]); - const actionTypesById: Record = {}; - for (const actionType of actionTypesResponse) { - actionTypesById[actionType.id] = actionType; - } + const actionsResponse = await loadActions({ http, sort, page }); const updatedData = actionsResponse.data.map( (action: Action): Data => ({ ...action, - actionType: actionTypesById[action.actionTypeId] - ? actionTypesById[action.actionTypeId].name + actionType: actionTypesIndex[action.actionTypeId] + ? actionTypesIndex[action.actionTypeId].name : action.actionTypeId, }) ); From e7af8237d0c7527eb06b8aa1f148a57e370d4600 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 11 Oct 2019 11:20:40 -0700 Subject: [PATCH 020/297] Fixed infinite loop useEffect execution for loadActionTypes --- .../sections/actions_list/components/actions_list.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 86c23592f92eb9..27ffeb5a385d46 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -56,7 +56,7 @@ export const ActionsList: React.FunctionComponent { const updatedData: Data[] = []; From fa1e776a9070afae7520742f51047cb72f8d9441 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 11 Oct 2019 12:18:16 -0700 Subject: [PATCH 021/297] Implemented Add Action dropdown button with exposed types options retrieved from server action types list --- .../actions_list/components/actions_list.tsx | 23 ++- .../components/create_menu_popover.tsx | 162 ++++++++++++++++++ 2 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 27ffeb5a385d46..0d397003ea18d7 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -6,12 +6,20 @@ import React, { Fragment, useState, useEffect } from 'react'; import { RouteComponentProps } from 'react-router-dom'; -import { EuiPageContent, EuiBasicTable, EuiSpacer } from '@elastic/eui'; +import { + EuiPageContent, + EuiBasicTable, + EuiSpacer, + EuiFlexGroup, + EuiFlexItem, + EuiFieldSearch, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { PageError } from '../../../components/page_error'; import { Action, ActionType, loadActions, loadActionTypes } from '../../../lib/api'; import { ActionsContext } from '../../../context/app_context'; import { useAppDependencies } from '../../../index'; +import { AlertingActionsDropdown } from './create_menu_popover'; interface ActionsListProps { api: any; @@ -139,6 +147,19 @@ export const ActionsList: React.FunctionComponent + + + + + + + + + = ({ actionTypes }) => { + const { addAction } = useContext(ActionsContext); + + const [isPopoverOpen, setIsPopOverOpen] = useState(false); + + const actionTypesSettings = (val: string) => { + let res; + switch (val) { + case '.email': + res = { + iconClass: 'email', + selectMessage: i18n.translate( + 'xpack.alertingUI.sections.actions.emailAction.selectMessageText', + { + defaultMessage: 'Send an email from your server.', + } + ), + simulatePrompt: i18n.translate( + 'xpack.alertingUI.sections.actions.emailAction.simulateButtonLabel', + { + defaultMessage: 'Send test email', + } + ), + }; + break; + case '.slack': + res = { + iconClass: 'logoSlack', + selectMessage: i18n.translate( + 'xpack.alertingUI.sections.actions.slackAction.selectMessageText', + { + defaultMessage: 'Send a message to a Slack user or channel.', + } + ), + simulatePrompt: i18n.translate( + 'xpack.alertingUI.sections.actions.slackAction.simulateButtonLabel', + { + defaultMessage: 'Send a sample message', + } + ), + }; + break; + case '.server-log': + res = { + iconClass: 'loggingApp', + selectMessage: i18n.translate( + 'xpack.alertingUI.sections.actions.serverLogAction.selectMessageText', + { + defaultMessage: 'Add an item to the logs.', + } + ), + simulatePrompt: i18n.translate( + 'xpack.alertingUI.sections.actions.serverLogAction.simulateButtonLabel', + { + defaultMessage: 'Log a sample message', + } + ), + }; + break; + default: + res = { typeName: '', iconClass: 'apps', selectMessage: '' }; + } + return res; + }; + + const actions = Object.entries(!actionTypes ? [] : actionTypes).map( + ([actionType, { id, name }]: any) => { + const actionSettings = actionTypesSettings(id); + const typeName = name; + const iconClass = actionSettings.iconClass; + const selectMessage = !actionSettings.selectMessage ? name : actionSettings.selectMessage; + return { + name, + typeName, + iconClass, + selectMessage, + }; + } + ); + + const button = ( + setIsPopOverOpen(!isPopoverOpen)} + > + + + ); + + return ( + setIsPopOverOpen(false)} + panelPaddingSize="none" + anchorPosition="downLeft" + > + { + const isActionDisabled = false; + const description = action.selectMessage; + return ( + { + addAction({ type: action.name, defaults: { isNew: true } }); + setIsPopOverOpen(false); + }} + > + + + + + + {action.typeName} + + +

{description}

+
+
+
+
+ ); + })} + /> +
+ ); +}; From 9ef1cf4c42928fad7fdb9451e5eac0e3a15901cc Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 14 Oct 2019 20:32:21 -0700 Subject: [PATCH 022/297] Created action forms for build-in action types for adding new Action --- .../components/page_error/index.ts | 2 + .../components/page_error/section_error.tsx | 45 ++++ .../constants/action_types_settings.ts | 109 ++++++++ .../sections/action_add/action_add.tsx | 204 +++++++++++++++ .../action_fields/email_action_fields.tsx | 109 ++++++++ .../action_add/action_fields/index.ts | 12 + .../action_fields/index_action_fields.tsx | 53 ++++ .../action_fields/logging_action_fields.tsx | 53 ++++ .../action_fields/pagerduty_action_fields.tsx | 61 +++++ .../action_fields/slack_action_fields.tsx | 71 ++++++ .../action_fields/webhook_action_fields.tsx | 238 ++++++++++++++++++ .../application/sections/action_add/index.ts | 7 + .../actions_list/components/actions_list.tsx | 35 ++- .../components/create_menu_popover.tsx | 71 +----- 14 files changed, 1000 insertions(+), 70 deletions(-) create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/section_error.tsx create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_types_settings.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/email_action_fields.tsx create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index_action_fields.tsx create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/logging_action_fields.tsx create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/pagerduty_action_fields.tsx create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/slack_action_fields.tsx create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/index.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/index.ts index 6f1ea7d16facb7..c9ed4d3f1d77e7 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/index.ts @@ -5,3 +5,5 @@ */ export { PageError } from './page_error'; +export { SectionError } from './section_error'; +export { ErrableFormRow } from './form_errors'; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/section_error.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/section_error.tsx new file mode 100644 index 00000000000000..8951b95b750781 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/section_error.tsx @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { EuiCallOut, EuiSpacer } from '@elastic/eui'; +import React, { Fragment } from 'react'; + +export interface Error { + data: { + error: string; + cause?: string[]; + message?: string; + }; +} + +interface Props { + title: React.ReactNode; + error: Error; +} + +export const SectionError: React.FunctionComponent = ({ title, error, ...rest }) => { + const { + error: errorString, + cause, // wrapEsError() on the server adds a "cause" array + message, + } = error.data; + + return ( + +
{message || errorString}
+ {cause && ( + + +
    + {cause.map((causeMsg, i) => ( +
  • {causeMsg}
  • + ))} +
+
+ )} +
+ ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_types_settings.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_types_settings.ts new file mode 100644 index 00000000000000..1a3743cbf41942 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_types_settings.ts @@ -0,0 +1,109 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { i18n } from '@kbn/i18n'; + +export const BUILDIN_ACTION_TYPES: { [key: string]: string } = { + EMAIL: '.email', + WEBHOOK: '.webhook', + INDEX: '.index', + LOGGING: '.server-log', + SLACK: '.slack', + PAGERDUTY: '.pagerduty', + CUSTOM: '.custom', +}; + +export const actionTypesSettings = (val: string) => { + let res; + switch (val) { + case '.email': + res = { + iconClass: 'email', + selectMessage: i18n.translate( + 'xpack.alertingUI.sections.actions.emailAction.selectMessageText', + { + defaultMessage: 'Send an email from your server.', + } + ), + simulatePrompt: i18n.translate( + 'xpack.alertingUI.sections.actions.emailAction.simulateButtonLabel', + { + defaultMessage: 'Send test email', + } + ), + }; + break; + case '.slack': + res = { + iconClass: 'logoSlack', + selectMessage: i18n.translate( + 'xpack.alertingUI.sections.actions.slackAction.selectMessageText', + { + defaultMessage: 'Send a message to a Slack user or channel.', + } + ), + simulatePrompt: i18n.translate( + 'xpack.alertingUI.sections.actions.slackAction.simulateButtonLabel', + { + defaultMessage: 'Send a sample message', + } + ), + }; + break; + case '.server-log': + res = { + iconClass: 'loggingApp', + selectMessage: i18n.translate( + 'xpack.alertingUI.sections.actions.serverLogAction.selectMessageText', + { + defaultMessage: 'Add an item to the logs.', + } + ), + simulatePrompt: i18n.translate( + 'xpack.alertingUI.sections.actions.serverLogAction.simulateButtonLabel', + { + defaultMessage: 'Log a sample message', + } + ), + }; + break; + case '.index': + res = { + iconClass: 'indexOpen', + selectMessage: i18n.translate('xpack.watcher.models.indexAction.selectMessageText', { + defaultMessage: 'Index data into Elasticsearch.', + }), + simulatePrompt: i18n.translate('xpack.watcher.models.indexAction.simulateButtonLabel', { + defaultMessage: 'Index data', + }), + }; + break; + case '.pagerduty': + res = { + iconClass: 'apps', + selectMessage: i18n.translate('xpack.watcher.models.pagerDutyAction.selectMessageText', { + defaultMessage: 'Create an event in PagerDuty.', + }), + simulatePrompt: i18n.translate('xpack.watcher.models.pagerDutyAction.simulateButtonLabel', { + defaultMessage: 'Send a PagerDuty event', + }), + }; + break; + case '.webhook': + res = { + iconClass: 'logoWebhook', + selectMessage: i18n.translate('xpack.watcher.models.webhookAction.selectMessageText', { + defaultMessage: 'Send a request to a web service.', + }), + simulatePrompt: i18n.translate('xpack.watcher.models.webhookAction.simulateButtonLabel', { + defaultMessage: 'Send request', + }), + }; + break; + default: + res = { typeName: '', iconClass: 'apps', selectMessage: '' }; + } + return res; +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx new file mode 100644 index 00000000000000..5500919cdbcc4b --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx @@ -0,0 +1,204 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React, { Fragment, useContext, useState, useCallback } from 'react'; + +import { + EuiButton, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiTitle, + EuiForm, + EuiCallOut, + EuiLink, + EuiText, + EuiSpacer, + EuiButtonEmpty, + EuiFlyoutFooter, + EuiFlyoutBody, + EuiFlyoutHeader, + EuiFlyout, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { Action, ActionType } from '../../lib/api'; +import { ActionsContext } from '../../context/app_context'; +import { + WebhookActionFields, + LoggingActionFields, + IndexActionFields, + SlackActionFields, + EmailActionFields, + PagerDutyActionFields, +} from './action_fields'; +import { SectionError } from '../../../application/components/page_error'; +import { actionTypesSettings, BUILDIN_ACTION_TYPES } from '../../constants/action_types_settings'; + +const actionFieldsComponentMap = { + [BUILDIN_ACTION_TYPES.LOGGING]: LoggingActionFields, + [BUILDIN_ACTION_TYPES.SLACK]: SlackActionFields, + [BUILDIN_ACTION_TYPES.EMAIL]: EmailActionFields, + [BUILDIN_ACTION_TYPES.INDEX]: IndexActionFields, + [BUILDIN_ACTION_TYPES.WEBHOOK]: WebhookActionFields, + [BUILDIN_ACTION_TYPES.PAGERDUTY]: PagerDutyActionFields, +}; + +interface Props { + actionType: ActionType | null; +} + +export const ActionAdd = ({ actionType }: Props) => { + const { flyoutVisible, setFlyoutVisibility } = useContext(ActionsContext); + const closeFlyout = useCallback(() => setFlyoutVisibility(false), []); + const [isExecuting, setIsExecuting] = useState<{ [key: string]: boolean }>({}); + const [executeResultsError, setExecuteResultsError] = useState(null); + const [isSaving, setIsSaving] = useState(false); + const [serverError, setServerError] = useState<{ + data: { nessage: string; error: string }; + } | null>(null); + + if (!flyoutVisible) { + return null; + } + if (!actionType) return null; + const FieldsComponent = actionFieldsComponentMap[actionType.id]; + const actionSettings = actionTypesSettings(actionType.id); + const hasErrors = false; // !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); + const action = { actionTypeId: actionType.id, config: {} } as Action; + + return ( + + + + + + + + +

+ +

+
+
+
+
+ + {executeResultsError && executeResultsError[action.id] && ( + + + } + error={executeResultsError[action.id]} + /> + + + )} + + + {actionType.id === null ? ( + + + +

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

+
+
+ +
+ ) : null} +
+
+
+ + + + setFlyoutVisibility(false)}> + {i18n.translate('xpack.alertingUI.sections.actionAdd.cancelButtonLabel', { + defaultMessage: 'Cancel', + })} + + + + { + setIsExecuting({ [action.id]: true }); + setExecuteResultsError(null); + setIsExecuting({ [action.id]: false }); + }} + > + {i18n.translate('xpack.alertingUI.sections.actionAdd.testButtonLabel', { + defaultMessage: 'Test', + })} + + + + { + setIsSaving(true); + const savedAction = await onActionSave(action); + if (savedAction && savedAction.error) { + setIsSaving(false); + return setServerError(savedAction.error); + } + }} + > + + + + + +
+ ); +}; + +export async function onActionSave(action: Action): Promise { + return []; +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/email_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/email_action_fields.tsx new file mode 100644 index 00000000000000..09821a04a2c6c4 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/email_action_fields.tsx @@ -0,0 +1,109 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React, { Fragment } from 'react'; + +import { EuiComboBox, EuiFieldText, EuiFormRow, EuiTextArea } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { ErrableFormRow } from '../../../components/page_error'; +import { Action } from '../../../lib/api'; + +interface Props { + action: Action; + errors: { [key: string]: string[] }; + hasErrors: boolean; +} + +export const EmailActionFields: React.FunctionComponent = ({ + action, + errors, + hasErrors, +}) => { + const { to, subject, body }: any = action.config; + const toOptions = to ? to.map((label: any) => ({ label })) : []; + + return ( + + + { + const newOptions = [...toOptions, { label: searchValue }]; + // editAction({ key: 'to', value: newOptions.map(newOption => newOption.label) }); + }} + onChange={(selectedOptions: Array<{ label: string }>) => { + /* editAction({ + key: 'to', + value: selectedOptions.map(selectedOption => selectedOption.label), + }); */ + }} + onBlur={() => { + if (!to) { + /* editAction({ + key: 'to', + value: [], + }); */ + } + }} + /> + + + + { + // editAction({ key: 'subject', value: e.target.value }); + }} + /> + + + + { + // editAction({ key: 'body', value: e.target.value }); + }} + /> + + + ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index.ts new file mode 100644 index 00000000000000..1934fbe3b3b02d --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index.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. + */ + +export { EmailActionFields } from './email_action_fields'; +export { IndexActionFields } from './index_action_fields'; +export { LoggingActionFields } from './logging_action_fields'; +export { PagerDutyActionFields } from './pagerduty_action_fields'; +export { SlackActionFields } from './slack_action_fields'; +export { WebhookActionFields } from './webhook_action_fields'; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index_action_fields.tsx new file mode 100644 index 00000000000000..3278685720860f --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index_action_fields.tsx @@ -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 React from 'react'; +import { EuiFieldText } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { ErrableFormRow } from '../../../components/page_error'; +import { Action } from '../../../lib/api'; + +interface Props { + action: Action; + // editAction: (changedProperty: { key: string; value: string }) => void; + errors: { [key: string]: string[] }; + hasErrors: boolean; +} + +export const IndexActionFields: React.FunctionComponent = ({ + action, + // editAction, + errors, + hasErrors, +}) => { + const { index }: any = action.config; + return ( + + ) => { + // editAction({ key: 'index', value: e.target.value }); + }} + onBlur={() => { + if (!index) { + // editAction({ key: 'index', value: '' }); + } + }} + /> + + ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/logging_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/logging_action_fields.tsx new file mode 100644 index 00000000000000..66186eeaa69efa --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/logging_action_fields.tsx @@ -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 React from 'react'; +import { EuiFieldText } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { ErrableFormRow } from '../../../components/page_error'; +import { Action } from '../../../lib/api'; + +interface Props { + action: Action; + // editAction: (changedProperty: { key: string; value: string }) => void; + errors: { [key: string]: string[] }; + hasErrors: boolean; +} + +export const LoggingActionFields: React.FunctionComponent = ({ + action, + // editAction, + errors, + hasErrors, +}) => { + const { text }: any = action.config; + return ( + + ) => { + // editAction({ key: 'text', value: e.target.value }); + }} + onBlur={() => { + if (!text) { + // editAction({ key: 'text', value: '' }); + } + }} + /> + + ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/pagerduty_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/pagerduty_action_fields.tsx new file mode 100644 index 00000000000000..4fd3f2807adec8 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/pagerduty_action_fields.tsx @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React, { Fragment } from 'react'; +import { EuiFieldText } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { ErrableFormRow } from '../../../components/page_error'; +import { Action } from '../../../lib/api'; + +interface Props { + action: Action; + // editAction: (changedProperty: { key: string; value: string }) => void; + errors: { [key: string]: string[] }; + hasErrors: boolean; + children: React.ReactNode; +} + +export const PagerDutyActionFields: React.FunctionComponent = ({ + errors, + hasErrors, + action, + // editAction, + children, +}) => { + const { description } = action; + return ( + + {children} + + ) => { + // editAction({ key: 'description', value: e.target.value }); + }} + onBlur={() => { + if (!description) { + // editAction({ key: 'description', value: '' }); + } + }} + /> + + + ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/slack_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/slack_action_fields.tsx new file mode 100644 index 00000000000000..95053cb4abb1d8 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/slack_action_fields.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React, { Fragment } from 'react'; +import { EuiComboBox, EuiTextArea, EuiFormRow } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { Action } from '../../../lib/api'; + +interface Props { + action: Action; + children: React.ReactNode; +} + +export const SlackActionFields: React.FunctionComponent = ({ action, children }) => { + const { text, to }: any = action.config; + const toOptions = to ? to.map((label: any) => ({ label })) : []; + + return ( + + {children} + + { + const newOptions = [...toOptions, { label: searchValue }]; + // editAction({ key: 'to', value: newOptions.map(newOption => newOption.label) }); + }} + onChange={(selectedOptions: Array<{ label: string }>) => { + /* editAction({ + key: 'to', + value: selectedOptions.map(selectedOption => selectedOption.label), + }); */ + }} + /> + + + + { + // editAction({ key: 'text', value: e.target.value }); + }} + /> + + + ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx new file mode 100644 index 00000000000000..a13f2adebf7b16 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx @@ -0,0 +1,238 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React, { Fragment, useEffect } from 'react'; + +import { + EuiCodeEditor, + EuiFieldNumber, + EuiFieldPassword, + EuiFieldText, + EuiFormRow, + EuiSelect, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { ErrableFormRow } from '../../../components/page_error'; +import { Action } from '../../../lib/api'; + +interface Props { + action: Action; + // editAction: (changedProperty: { key: string; value: any }) => void; + errors: { [key: string]: string[] }; + hasErrors: boolean; +} + +const HTTP_VERBS = ['head', 'get', 'post', 'put', 'delete']; + +export const WebhookActionFields: React.FunctionComponent = ({ + action, + // editAction, + errors, + hasErrors, +}) => { + const { method, host, port, path, body, username, password }: any = action.config; + + // useEffect(() => { + // editAction({ key: 'contentType', value: 'application/json' }); // set content-type for threshold watch to json by default + // }, []); + + return ( + + + + + ({ text: verb.toUpperCase(), value: verb }))} + onChange={e => { + // editAction({ key: 'method', value: e.target.value }); + }} + /> + + + + + + { + // editAction({ key: 'host', value: e.target.value }); + }} + onBlur={() => { + if (!host) { + // editAction({ key: 'host', value: '' }); + } + }} + /> + + + + + + { + // editAction({ key: 'port', value: parseInt(e.target.value, 10) }); + }} + onBlur={() => { + if (!port) { + // editAction({ key: 'port', value: '' }); + } + }} + /> + + + + + + { + // editAction({ key: 'path', value: e.target.value }); + }} + /> + + + + + + + + { + // editAction({ key: 'username', value: e.target.value }); + }} + /> + + + + + + { + // editAction({ key: 'password', value: e.target.value }); + }} + /> + + + + + + + + { + // editAction({ key: 'body', value: json }); + }} + /> + + + ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/index.ts new file mode 100644 index 00000000000000..31241220a0b483 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { ActionAdd } from './action_add'; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 0d397003ea18d7..5f18491e42e1d5 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -20,6 +20,7 @@ import { Action, ActionType, loadActions, loadActionTypes } from '../../../lib/a import { ActionsContext } from '../../../context/app_context'; import { useAppDependencies } from '../../../index'; import { AlertingActionsDropdown } from './create_menu_popover'; +import { ActionAdd } from '../../action_add'; interface ActionsListProps { api: any; @@ -54,13 +55,15 @@ export const ActionsList: React.FunctionComponent(0); const [page, setPage] = useState({ index: 0, size: 10 }); const [sort, setSort] = useState({ field: 'actionTypeId', direction: 'asc' }); + const [flyoutVisible, setFlyoutVisibility] = useState(false); + const [actionType, setActionTypeId] = useState(null); useEffect(() => { (async () => { const actionTypes = await loadActionTypes({ http }); const index: ActionTypeIndex = {}; - for (const actionType of actionTypes) { - index[actionType.id] = actionType; + for (const actionTypeItem of actionTypes) { + index[actionTypeItem.id] = actionTypeItem; } setActionTypesIndex(index); })(); @@ -136,6 +139,11 @@ export const ActionsList: React.FunctionComponent - + {content} +
); }; -export const ContentWrapper = ({ children }: { children: React.ReactNode }) => { +export const ContentWrapper = ({ + flyoutVisible, + setFlyoutVisibility, + createAction, + children, +}: { + flyoutVisible: boolean; + setFlyoutVisibility: React.Dispatch>; + createAction: (actionType: ActionType) => void; + children: React.ReactNode; +}) => { return ( - {children} + + {children} + ); }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx index e7fa67424b4f70..68150646eaad15 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx @@ -15,79 +15,19 @@ import { EuiContextMenuPanel, EuiContextMenuItem, } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { ActionsContext } from '../../../context/app_context'; +import { actionTypesSettings } from '../../../constants/action_types_settings'; interface Props { actionTypes: any; } export const AlertingActionsDropdown: React.FunctionComponent = ({ actionTypes }) => { - const { addAction } = useContext(ActionsContext); + const { createAction } = useContext(ActionsContext); const [isPopoverOpen, setIsPopOverOpen] = useState(false); - const actionTypesSettings = (val: string) => { - let res; - switch (val) { - case '.email': - res = { - iconClass: 'email', - selectMessage: i18n.translate( - 'xpack.alertingUI.sections.actions.emailAction.selectMessageText', - { - defaultMessage: 'Send an email from your server.', - } - ), - simulatePrompt: i18n.translate( - 'xpack.alertingUI.sections.actions.emailAction.simulateButtonLabel', - { - defaultMessage: 'Send test email', - } - ), - }; - break; - case '.slack': - res = { - iconClass: 'logoSlack', - selectMessage: i18n.translate( - 'xpack.alertingUI.sections.actions.slackAction.selectMessageText', - { - defaultMessage: 'Send a message to a Slack user or channel.', - } - ), - simulatePrompt: i18n.translate( - 'xpack.alertingUI.sections.actions.slackAction.simulateButtonLabel', - { - defaultMessage: 'Send a sample message', - } - ), - }; - break; - case '.server-log': - res = { - iconClass: 'loggingApp', - selectMessage: i18n.translate( - 'xpack.alertingUI.sections.actions.serverLogAction.selectMessageText', - { - defaultMessage: 'Add an item to the logs.', - } - ), - simulatePrompt: i18n.translate( - 'xpack.alertingUI.sections.actions.serverLogAction.simulateButtonLabel', - { - defaultMessage: 'Log a sample message', - } - ), - }; - break; - default: - res = { typeName: '', iconClass: 'apps', selectMessage: '' }; - } - return res; - }; - const actions = Object.entries(!actionTypes ? [] : actionTypes).map( ([actionType, { id, name }]: any) => { const actionSettings = actionTypesSettings(id); @@ -95,6 +35,7 @@ export const AlertingActionsDropdown: React.FunctionComponent = ({ action const iconClass = actionSettings.iconClass; const selectMessage = !actionSettings.selectMessage ? name : actionSettings.selectMessage; return { + id, name, typeName, iconClass, @@ -105,7 +46,7 @@ export const AlertingActionsDropdown: React.FunctionComponent = ({ action const button = ( = ({ action return ( setIsPopOverOpen(false)} @@ -137,8 +78,8 @@ export const AlertingActionsDropdown: React.FunctionComponent = ({ action disabled={isActionDisabled} data-test-subj={`${action.name}ActionButton`} onClick={() => { - addAction({ type: action.name, defaults: { isNew: true } }); setIsPopOverOpen(false); + createAction(action); }} > From 39ad16bbc73d2d7a723a03fce8d687be3bd04024 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 15 Oct 2019 08:48:30 -0400 Subject: [PATCH 023/297] Remove duplicated code --- .../actions_list/components/actions_list.tsx | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 0d397003ea18d7..3c934aa66b7e27 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -37,6 +37,20 @@ interface Data extends Action { } type ActionTypeIndex = Record; +function setActionTypeAttributeToActions( + actionTypesIndex: ActionTypeIndex, + actions: Action[] +): Data[] { + return actions.map(action => { + return { + ...action, + actionType: actionTypesIndex[action.actionTypeId] + ? actionTypesIndex[action.actionTypeId].name + : action.actionTypeId, + }; + }); +} + export const ActionsList: React.FunctionComponent> = ({ match: { params: { api }, @@ -67,16 +81,7 @@ export const ActionsList: React.FunctionComponent { - const updatedData: Data[] = []; - for (const action of data) { - updatedData.push({ - ...action, - actionType: actionTypesIndex[action.actionTypeId] - ? actionTypesIndex[action.actionTypeId].name - : action.actionTypeId, - }); - } - setData(updatedData); + setData(setActionTypeAttributeToActions(actionTypesIndex, data)); }, [actionTypesIndex]); useEffect(() => { @@ -85,15 +90,7 @@ export const ActionsList: React.FunctionComponent ({ - ...action, - actionType: actionTypesIndex[action.actionTypeId] - ? actionTypesIndex[action.actionTypeId].name - : action.actionTypeId, - }) - ); - setData(updatedData); + setData(setActionTypeAttributeToActions(actionTypesIndex, data)); setTotalItemCount(actionsResponse.total); } catch (e) { setErrorCode(e.response.status); From 979f06b315ffd814e637e2da7340aabba67fc96e Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 15 Oct 2019 09:09:40 -0400 Subject: [PATCH 024/297] Add searching --- .../np_ready/public/application/lib/api.ts | 4 ++++ .../actions_list/components/actions_list.tsx | 12 ++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index 79da03200340ed..a09cf46f8bbac2 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -34,6 +34,7 @@ export interface LoadActionsOpts { http: HttpServiceBase; sort: { field: string; direction: 'asc' | 'desc' }; page: { index: number; size: number }; + searchText?: string; } export interface LoadActionsResponse { @@ -47,6 +48,7 @@ export async function loadActions({ http, sort, page, + searchText, }: LoadActionsOpts): Promise { return http.get(`${BASE_ACTION_API_PATH}/_find`, { query: { @@ -54,6 +56,8 @@ export async function loadActions({ sort_order: sort.direction, page: page.index + 1, per_page: page.size, + search_fields: searchText ? 'description' : undefined, + search: searchText, }, }); } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 3c934aa66b7e27..5fa6c5f7340d69 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -68,6 +68,7 @@ export const ActionsList: React.FunctionComponent(0); const [page, setPage] = useState({ index: 0, size: 10 }); const [sort, setSort] = useState({ field: 'actionTypeId', direction: 'asc' }); + const [searchText, setSearchText] = useState(undefined); useEffect(() => { (async () => { @@ -89,7 +90,7 @@ export const ActionsList: React.FunctionComponent setSearchText(updatedSearchText)} /> From 461bede81f3dd3db83dd604fad74d0d6e797e90a Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 15 Oct 2019 09:15:39 -0400 Subject: [PATCH 025/297] Remove content wrapper within wrapper --- .../sections/actions_list/components/actions_list.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 5fa6c5f7340d69..a239557f164066 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -161,6 +161,8 @@ export const ActionsList: React.FunctionComponent + + { return ( - + {children} - + ); }; From 72cc5f2ffc58a599ff8c04d983b967d615c76660 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 15 Oct 2019 11:50:16 -0400 Subject: [PATCH 026/297] Use EuiSearchBar --- .../actions_list/components/actions_list.tsx | 30 +++++-------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index a239557f164066..3e3b7bee2a13df 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -6,14 +6,7 @@ import React, { Fragment, useState, useEffect } from 'react'; import { RouteComponentProps } from 'react-router-dom'; -import { - EuiPageContent, - EuiBasicTable, - EuiSpacer, - EuiFlexGroup, - EuiFlexItem, - EuiFieldSearch, -} from '@elastic/eui'; +import { EuiPageContent, EuiBasicTable, EuiSpacer, EuiSearchBar } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { PageError } from '../../../components/page_error'; import { Action, ActionType, loadActions, loadActionTypes } from '../../../lib/api'; @@ -145,21 +138,12 @@ export const ActionsList: React.FunctionComponent - - - setSearchText(updatedSearchText)} - /> - - - - - + setSearchText(query.text)} + toolsRight={[ + , + ]} + > From 4eb13e2b7adeb7fcfd0336f41e91c78e7d6d8efc Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 15 Oct 2019 11:58:48 -0400 Subject: [PATCH 027/297] Fix bug not rendering data --- .../sections/actions_list/components/actions_list.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 3e3b7bee2a13df..0ee24f7f37261a 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -84,7 +84,7 @@ export const ActionsList: React.FunctionComponent Date: Tue, 15 Oct 2019 13:18:53 -0400 Subject: [PATCH 028/297] Add delete support --- .../legacy/plugins/actions/server/plugin.ts | 4 +- .../np_ready/public/application/lib/api.ts | 9 +++ .../actions_list/components/actions_list.tsx | 73 +++++++++++++++---- 3 files changed, 68 insertions(+), 18 deletions(-) diff --git a/x-pack/legacy/plugins/actions/server/plugin.ts b/x-pack/legacy/plugins/actions/server/plugin.ts index 618c1d120c37ae..273d37e37125e4 100644 --- a/x-pack/legacy/plugins/actions/server/plugin.ts +++ b/x-pack/legacy/plugins/actions/server/plugin.ts @@ -74,7 +74,7 @@ export class Plugin { all: ['action', 'action_task_params'], read: [], }, - ui: [], + ui: ['save', 'show', 'delete'], api: ['actions-read', 'actions-all'], }, read: { @@ -82,7 +82,7 @@ export class Plugin { all: ['action_task_params'], read: ['action'], }, - ui: [], + ui: ['show'], api: ['actions-read'], }, }, diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index a09cf46f8bbac2..e174bc71da3d85 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -61,3 +61,12 @@ export async function loadActions({ }, }); } + +export interface DeleteActionsOpts { + ids: string[]; + http: HttpServiceBase; +} + +export async function deleteActions({ ids, http }: DeleteActionsOpts): Promise { + await Promise.all(ids.map(id => http.delete(`${BASE_ACTION_API_PATH}/${id}`))); +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 0ee24f7f37261a..40b4c15729804a 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -6,10 +6,12 @@ import React, { Fragment, useState, useEffect } from 'react'; import { RouteComponentProps } from 'react-router-dom'; -import { EuiPageContent, EuiBasicTable, EuiSpacer, EuiSearchBar } from '@elastic/eui'; +import { EuiPageContent, EuiBasicTable, EuiSpacer, EuiSearchBar, EuiButton } from '@elastic/eui'; +import { capabilities } from 'ui/capabilities'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { PageError } from '../../../components/page_error'; -import { Action, ActionType, loadActions, loadActionTypes } from '../../../lib/api'; +import { Action, ActionType, deleteActions, loadActions, loadActionTypes } from '../../../lib/api'; import { ActionsContext } from '../../../context/app_context'; import { useAppDependencies } from '../../../index'; import { AlertingActionsDropdown } from './create_menu_popover'; @@ -44,6 +46,8 @@ function setActionTypeAttributeToActions( }); } +const canDelete = capabilities.get().actions.delete; + export const ActionsList: React.FunctionComponent> = ({ match: { params: { api }, @@ -56,6 +60,7 @@ export const ActionsList: React.FunctionComponent({}); const [data, setData] = useState([]); + const [selectedItems, setSelectedItems] = useState([]); const [isLoading, setIsLoading] = useState(false); const [errorCode, setErrorCode] = useState(null); const [totalItemCount, setTotalItemCount] = useState(0); @@ -63,6 +68,20 @@ export const ActionsList: React.FunctionComponent({ field: 'actionTypeId', direction: 'asc' }); const [searchText, setSearchText] = useState(undefined); + async function loadTable() { + setIsLoading(true); + setErrorCode(null); + try { + const actionsResponse = await loadActions({ http, sort, page, searchText }); + setData(setActionTypeAttributeToActions(actionTypesIndex, actionsResponse.data)); + setTotalItemCount(actionsResponse.total); + } catch (e) { + setErrorCode(e.response.status); + } finally { + setIsLoading(false); + } + } + useEffect(() => { (async () => { const actionTypes = await loadActionTypes({ http }); @@ -79,19 +98,7 @@ export const ActionsList: React.FunctionComponent { - (async () => { - setIsLoading(true); - setErrorCode(null); - try { - const actionsResponse = await loadActions({ http, sort, page, searchText }); - setData(setActionTypeAttributeToActions(actionTypesIndex, actionsResponse.data)); - setTotalItemCount(actionsResponse.total); - } catch (e) { - setErrorCode(e.response.status); - } finally { - setIsLoading(false); - } - })(); + loadTable(); }, [sort, page, searchText]); const actionsTableColumns = [ @@ -127,6 +134,12 @@ export const ActionsList: React.FunctionComponent { + setIsLoading(true); + await deleteActions({ http, ids: selectedItems.map(item => item.id) }); + await loadTable(); + }; + let content; if (errorCode) { @@ -141,7 +154,30 @@ export const ActionsList: React.FunctionComponent setSearchText(query.text)} toolsRight={[ - , + + + , + , ]} > @@ -175,6 +211,11 @@ export const ActionsList: React.FunctionComponent ); From 3234084ec0a422a5882ab6880d5c1d148bb05d99 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 15 Oct 2019 16:59:24 -0400 Subject: [PATCH 029/297] Wait for action types to load before displaying data --- .../actions_list/components/actions_list.tsx | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 40b4c15729804a..1442d2bdcd4561 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -32,20 +32,6 @@ interface Data extends Action { } type ActionTypeIndex = Record; -function setActionTypeAttributeToActions( - actionTypesIndex: ActionTypeIndex, - actions: Action[] -): Data[] { - return actions.map(action => { - return { - ...action, - actionType: actionTypesIndex[action.actionTypeId] - ? actionTypesIndex[action.actionTypeId].name - : action.actionTypeId, - }; - }); -} - const canDelete = capabilities.get().actions.delete; export const ActionsList: React.FunctionComponent> = ({ @@ -58,7 +44,8 @@ export const ActionsList: React.FunctionComponent({}); + const [actionTypesIndex, setActionTypesIndex] = useState(undefined); + const [actions, setActions] = useState([]); const [data, setData] = useState([]); const [selectedItems, setSelectedItems] = useState([]); const [isLoading, setIsLoading] = useState(false); @@ -68,12 +55,12 @@ export const ActionsList: React.FunctionComponent({ field: 'actionTypeId', direction: 'asc' }); const [searchText, setSearchText] = useState(undefined); - async function loadTable() { + async function loadActionsTable() { setIsLoading(true); setErrorCode(null); try { const actionsResponse = await loadActions({ http, sort, page, searchText }); - setData(setActionTypeAttributeToActions(actionTypesIndex, actionsResponse.data)); + setActions(actionsResponse.data); setTotalItemCount(actionsResponse.total); } catch (e) { setErrorCode(e.response.status); @@ -82,6 +69,10 @@ export const ActionsList: React.FunctionComponent { + loadActionsTable(); + }, [sort, page, searchText]); + useEffect(() => { (async () => { const actionTypes = await loadActionTypes({ http }); @@ -94,12 +85,20 @@ export const ActionsList: React.FunctionComponent { - setData(setActionTypeAttributeToActions(actionTypesIndex, data)); - }, [actionTypesIndex]); - - useEffect(() => { - loadTable(); - }, [sort, page, searchText]); + // Avoid flickering after action types load + if (typeof actionTypesIndex === 'undefined') { + return; + } + const updatedData = actions.map(action => { + return { + ...action, + actionType: actionTypesIndex[action.actionTypeId] + ? actionTypesIndex[action.actionTypeId].name + : action.actionTypeId, + }; + }); + setData(updatedData); + }, [actions, actionTypesIndex]); const actionsTableColumns = [ { From 4cb768a308284866ad108dca4b074b39fd71bdb5 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 15 Oct 2019 17:00:10 -0400 Subject: [PATCH 030/297] Change comment --- .../sections/actions_list/components/actions_list.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 1442d2bdcd4561..257e049298a48d 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -85,7 +85,7 @@ export const ActionsList: React.FunctionComponent { - // Avoid flickering after action types load + // Avoid flickering before action types load if (typeof actionTypesIndex === 'undefined') { return; } From 9ecae3ccada80a01af944fc70503c1bd16c53f7e Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 16 Oct 2019 08:49:31 -0400 Subject: [PATCH 031/297] Handle loading boolean for action types and actions --- .../actions_list/components/actions_list.tsx | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 257e049298a48d..dab2588fc36a2f 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -48,7 +48,8 @@ export const ActionsList: React.FunctionComponent([]); const [data, setData] = useState([]); const [selectedItems, setSelectedItems] = useState([]); - const [isLoading, setIsLoading] = useState(false); + const [isLoadingActionTypes, setIsLoadingActionTypes] = useState(false); + const [isLoadingActions, setIsLoadingActions] = useState(false); const [errorCode, setErrorCode] = useState(null); const [totalItemCount, setTotalItemCount] = useState(0); const [page, setPage] = useState({ index: 0, size: 10 }); @@ -56,7 +57,7 @@ export const ActionsList: React.FunctionComponent(undefined); async function loadActionsTable() { - setIsLoading(true); + setIsLoadingActions(true); setErrorCode(null); try { const actionsResponse = await loadActions({ http, sort, page, searchText }); @@ -65,7 +66,7 @@ export const ActionsList: React.FunctionComponent { (async () => { - const actionTypes = await loadActionTypes({ http }); - const index: ActionTypeIndex = {}; - for (const actionType of actionTypes) { - index[actionType.id] = actionType; + try { + setIsLoadingActionTypes(true); + const actionTypes = await loadActionTypes({ http }); + const index: ActionTypeIndex = {}; + for (const actionType of actionTypes) { + index[actionType.id] = actionType; + } + setActionTypesIndex(index); + } catch (e) { + setErrorCode(e.response.status); + } finally { + setIsLoadingActionTypes(false); } - setActionTypesIndex(index); })(); }, []); @@ -134,9 +142,8 @@ export const ActionsList: React.FunctionComponent { - setIsLoading(true); await deleteActions({ http, ids: selectedItems.map(item => item.id) }); - await loadTable(); + await loadActionsTable(); }; let content; @@ -183,7 +190,7 @@ export const ActionsList: React.FunctionComponent Date: Wed, 16 Oct 2019 08:52:14 -0400 Subject: [PATCH 032/297] Add loading indicator when deleting actions --- .../sections/actions_list/components/actions_list.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index dab2588fc36a2f..26a610e505abc9 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -50,6 +50,7 @@ export const ActionsList: React.FunctionComponent([]); const [isLoadingActionTypes, setIsLoadingActionTypes] = useState(false); const [isLoadingActions, setIsLoadingActions] = useState(false); + const [isDeletingActions, setIsDeletingActions] = useState(false); const [errorCode, setErrorCode] = useState(null); const [totalItemCount, setTotalItemCount] = useState(0); const [page, setPage] = useState({ index: 0, size: 10 }); @@ -142,8 +143,10 @@ export const ActionsList: React.FunctionComponent { + setIsDeletingActions(true); await deleteActions({ http, ids: selectedItems.map(item => item.id) }); await loadActionsTable(); + setIsDeletingActions(false); }; let content; @@ -190,7 +193,7 @@ export const ActionsList: React.FunctionComponent Date: Wed, 16 Oct 2019 09:03:07 -0400 Subject: [PATCH 033/297] Add type filter --- .../actions_list/components/actions_list.tsx | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 26a610e505abc9..081f2d857e84f2 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -161,7 +161,22 @@ export const ActionsList: React.FunctionComponent setSearchText(query.text)} + onChange={({ queryText }: { queryText: string }) => setSearchText(queryText)} + filters={[ + { + type: 'field_value_selection', + field: 'type', + name: i18n.translate( + 'xpack.alertingUI.sections.actionsList.actionsListTable.typeFilterName', + { defaultMessage: 'Type' } + ), + multiSelect: 'or', + options: Object.values(actionTypesIndex || {}).map(actionType => ({ + value: actionType.id, + name: actionType.name, + })), + }, + ]} toolsRight={[ Date: Wed, 16 Oct 2019 09:17:49 -0400 Subject: [PATCH 034/297] Remove sorting support, for now --- .../np_ready/public/application/lib/api.ts | 4 ---- .../actions_list/components/actions_list.tsx | 19 +++---------------- 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index e174bc71da3d85..ba9572a50771b4 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -32,7 +32,6 @@ export async function loadActionTypes({ export interface LoadActionsOpts { http: HttpServiceBase; - sort: { field: string; direction: 'asc' | 'desc' }; page: { index: number; size: number }; searchText?: string; } @@ -46,14 +45,11 @@ export interface LoadActionsResponse { export async function loadActions({ http, - sort, page, searchText, }: LoadActionsOpts): Promise { return http.get(`${BASE_ACTION_API_PATH}/_find`, { query: { - sort_field: sort.field, - sort_order: sort.direction, page: page.index + 1, per_page: page.size, search_fields: searchText ? 'description' : undefined, diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 081f2d857e84f2..247716ab7482ef 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -19,10 +19,6 @@ import { AlertingActionsDropdown } from './create_menu_popover'; interface ActionsListProps { api: any; } -interface Sorting { - field: string; - direction: 'asc' | 'desc'; -} interface Pagination { index: number; size: number; @@ -54,14 +50,13 @@ export const ActionsList: React.FunctionComponent(null); const [totalItemCount, setTotalItemCount] = useState(0); const [page, setPage] = useState({ index: 0, size: 10 }); - const [sort, setSort] = useState({ field: 'actionTypeId', direction: 'asc' }); const [searchText, setSearchText] = useState(undefined); async function loadActionsTable() { setIsLoadingActions(true); setErrorCode(null); try { - const actionsResponse = await loadActions({ http, sort, page, searchText }); + const actionsResponse = await loadActions({ http, page, searchText }); setActions(actionsResponse.data); setTotalItemCount(actionsResponse.total); } catch (e) { @@ -73,7 +68,7 @@ export const ActionsList: React.FunctionComponent { loadActionsTable(); - }, [sort, page, searchText]); + }, [page, searchText]); useEffect(() => { (async () => { @@ -219,21 +214,13 @@ export const ActionsList: React.FunctionComponent { + onChange={({ page: changedPage }: { page: Pagination }) => { setPage(changedPage); - setSort(changedSort); }} selection={{ onSelectionChange(updatedSelectedItemsList: Data[]) { From 509e8d0adadbf4735d330314af9b291d7b5569c3 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 16 Oct 2019 09:22:18 -0400 Subject: [PATCH 035/297] Cleanup --- .../actions_list/components/actions_list.tsx | 71 +++++++++---------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 247716ab7482ef..0043c0792db42e 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -16,6 +16,7 @@ import { ActionsContext } from '../../../context/app_context'; import { useAppDependencies } from '../../../index'; import { AlertingActionsDropdown } from './create_menu_popover'; +type ActionTypeIndex = Record; interface ActionsListProps { api: any; } @@ -26,9 +27,40 @@ interface Pagination { interface Data extends Action { actionType: ActionType['name']; } -type ActionTypeIndex = Record; const canDelete = capabilities.get().actions.delete; +const actionsTableColumns = [ + { + field: 'description', + name: i18n.translate( + 'xpack.alertingUI.sections.actionsList.actionsListTable.descriptionHeader', + { + defaultMessage: 'Description', + } + ), + sortable: false, + truncateText: true, + }, + { + field: 'actionType', + name: i18n.translate( + 'xpack.alertingUI.sections.actionsList.actionsListTable.actionTypeHeader', + { + defaultMessage: 'Action Type', + } + ), + sortable: false, + truncateText: true, + }, + { + field: 'config', + name: i18n.translate('xpack.alertingUI.sections.actionsList.actionsListTable.configHeader', { + defaultMessage: 'Config', + }), + sortable: false, + truncateText: false, + }, +]; export const ActionsList: React.FunctionComponent> = ({ match: { @@ -104,45 +136,12 @@ export const ActionsList: React.FunctionComponent { + async function deleteSelectedItems() { setIsDeletingActions(true); await deleteActions({ http, ids: selectedItems.map(item => item.id) }); await loadActionsTable(); setIsDeletingActions(false); - }; + } let content; From efa9d5f2b6da8da336925d2810bad662af7ae836 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 16 Oct 2019 10:26:17 -0400 Subject: [PATCH 036/297] Remove remaining sort related code --- x-pack/legacy/plugins/actions/server/actions_client.ts | 3 +-- x-pack/legacy/plugins/actions/server/index.ts | 2 +- x-pack/legacy/plugins/actions/server/routes/find.ts | 3 --- x-pack/legacy/plugins/alerting/server/alerts_client.ts | 1 - x-pack/legacy/plugins/alerting/server/routes/find.ts | 3 --- 5 files changed, 2 insertions(+), 10 deletions(-) diff --git a/x-pack/legacy/plugins/actions/server/actions_client.ts b/x-pack/legacy/plugins/actions/server/actions_client.ts index 15cfdce12a7ac8..823cb55abaf5e7 100644 --- a/x-pack/legacy/plugins/actions/server/actions_client.ts +++ b/x-pack/legacy/plugins/actions/server/actions_client.ts @@ -15,7 +15,7 @@ interface ActionUpdate extends SavedObjectAttributes { secrets: SavedObjectAttributes; } -export interface Action extends ActionUpdate { +interface Action extends ActionUpdate { actionTypeId: string; } @@ -31,7 +31,6 @@ interface FindOptions { defaultSearchOperator?: 'AND' | 'OR'; searchFields?: string[]; sortField?: string; - sortOrder?: string; hasReference?: { type: string; id: string; diff --git a/x-pack/legacy/plugins/actions/server/index.ts b/x-pack/legacy/plugins/actions/server/index.ts index 71532c32704fde..faafb0db330cd3 100644 --- a/x-pack/legacy/plugins/actions/server/index.ts +++ b/x-pack/legacy/plugins/actions/server/index.ts @@ -6,5 +6,5 @@ export { init } from './init'; export { ActionsPlugin, ActionTypeExecutorOptions, ActionType } from './types'; -export { Action, ActionsClient } from './actions_client'; +export { ActionsClient } from './actions_client'; export { PluginSetupContract, PluginStartContract } from './plugin'; diff --git a/x-pack/legacy/plugins/actions/server/routes/find.ts b/x-pack/legacy/plugins/actions/server/routes/find.ts index e0bbade2c26c25..e521ba174f2879 100644 --- a/x-pack/legacy/plugins/actions/server/routes/find.ts +++ b/x-pack/legacy/plugins/actions/server/routes/find.ts @@ -17,7 +17,6 @@ interface FindRequest extends WithoutQueryAndParams { default_search_operator: 'AND' | 'OR'; search_fields?: string[]; sort_field?: string; - sort_order?: string; has_reference?: { type: string; id: string; @@ -51,7 +50,6 @@ export const findActionRoute = { .items(Joi.string()) .single(), sort_field: Joi.string(), - sort_order: Joi.string(), has_reference: Joi.object() .keys({ type: Joi.string().required(), @@ -79,7 +77,6 @@ export const findActionRoute = { defaultSearchOperator: query.default_search_operator, searchFields: query.search_fields, sortField: query.sort_field, - sortOrder: query.sort_order, hasReference: query.has_reference, fields: query.fields, filter: query.filter, diff --git a/x-pack/legacy/plugins/alerting/server/alerts_client.ts b/x-pack/legacy/plugins/alerting/server/alerts_client.ts index 0be2bc4f323914..39d0277ff53b3c 100644 --- a/x-pack/legacy/plugins/alerting/server/alerts_client.ts +++ b/x-pack/legacy/plugins/alerting/server/alerts_client.ts @@ -40,7 +40,6 @@ interface FindOptions { defaultSearchOperator?: 'AND' | 'OR'; searchFields?: string[]; sortField?: string; - sortOrder?: string; hasReference?: { type: string; id: string; diff --git a/x-pack/legacy/plugins/alerting/server/routes/find.ts b/x-pack/legacy/plugins/alerting/server/routes/find.ts index 954ae9fc623aaa..75cf93b18398ff 100644 --- a/x-pack/legacy/plugins/alerting/server/routes/find.ts +++ b/x-pack/legacy/plugins/alerting/server/routes/find.ts @@ -17,7 +17,6 @@ interface FindRequest extends WithoutQueryAndParams { default_search_operator: 'AND' | 'OR'; search_fields?: string[]; sort_field?: string; - sort_order?: string; has_reference?: { type: string; id: string; @@ -51,7 +50,6 @@ export const findAlertRoute = { .items(Joi.string()) .single(), sort_field: Joi.string(), - sort_order: Joi.string(), has_reference: Joi.object() .keys({ type: Joi.string().required(), @@ -79,7 +77,6 @@ export const findAlertRoute = { defaultSearchOperator: query.default_search_operator, searchFields: query.search_fields, sortField: query.sort_field, - sortOrder: query.sort_order, hasReference: query.has_reference, fields: query.fields, filter: query.filter, From 216b463d45ed43b32f26f7a39db2561d617efd8f Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 16 Oct 2019 11:06:01 -0400 Subject: [PATCH 037/297] Cleanup pt1 --- x-pack/legacy/plugins/alerting_ui/index.ts | 1 - .../plugins/alerting_ui/np_ready/kibana.json | 2 +- .../np_ready/public/application/app.tsx | 6 +-- .../public/application/constants/index.ts | 16 +------- .../np_ready/public/application/home.tsx | 36 ----------------- .../public/application/lib/breadcrumb.ts | 32 +-------------- .../public/application/lib/text/text.ts | 9 ----- .../alerts_list/components/alerts_list.tsx | 39 ------------------- .../alerting_ui/np_ready/public/index.scss | 4 -- .../alerting_ui/np_ready/public/plugin.ts | 10 ++--- .../alerting_ui/public/hacks/register.ts | 2 +- 11 files changed, 13 insertions(+), 144 deletions(-) delete mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx delete mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/index.scss diff --git a/x-pack/legacy/plugins/alerting_ui/index.ts b/x-pack/legacy/plugins/alerting_ui/index.ts index 2767789b390e05..3bf4c22b4ba6fe 100644 --- a/x-pack/legacy/plugins/alerting_ui/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/index.ts @@ -28,7 +28,6 @@ export function alertingUI(kibana: any) { .default(); }, uiExports: { - // styleSheetPaths: resolve(__dirname, 'public/np_ready/public/index.scss'), hacks: ['plugins/alerting_ui/hacks/register'], managementSections: ['plugins/alerting_ui'], }, diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/kibana.json b/x-pack/legacy/plugins/alerting_ui/np_ready/kibana.json index faf30ef4d4e91e..db2848601f6980 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/kibana.json +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/kibana.json @@ -1,5 +1,5 @@ { - "id": "xpackAlertingUI", + "id": "alertingUI", "version": "kibana", "server": false, "ui": true diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx index 99d4a3fe5d3b12..97c5064a26f5e8 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx @@ -7,7 +7,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { Switch, Route, Redirect } from 'react-router-dom'; import { registerRouter } from './lib/navigation'; -import { BASE_PATH, Section } from './constants'; +import { BASE_PATH, Section, DEFAULT_SECTION } from './constants'; import { AlertsUIHome } from './home'; class ShareRouter extends Component { @@ -36,7 +36,7 @@ class ShareRouter extends Component { } export const App = (api: any) => { - const sections: Section[] = ['alerts', 'actions', 'notifications', 'activity_logs']; + const sections: Section[] = ['actions']; const sectionsRegex = sections.join('|'); @@ -50,6 +50,6 @@ export const App = (api: any) => { export const AppWithoutRouter = ({ sectionsRegex }: any) => ( - + ); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts index 60d3d26bab4e4f..f16c921e07888c 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts @@ -7,25 +7,13 @@ export const BASE_PATH = '/management/kibana/alerting'; export const BASE_ACTION_API_PATH = '../api/action'; -export const DEFAULT_SECTION: Section = 'alerts'; -export type Section = 'actions' | 'alerts' | 'activity_logs' | 'notifications'; +export const DEFAULT_SECTION: Section = 'actions'; +export type Section = 'actions'; export function linkToHome() { return `#${BASE_PATH}`; } -export function linkToAlerts() { - return `#${BASE_PATH}/alerts`; -} - export function linkToActions() { return `#${BASE_PATH}/actions`; } - -export function linkToActivityLogs() { - return `#${BASE_PATH}/activity_logs`; -} - -export function linkToNotifications() { - return `#${BASE_PATH}/notifications`; -} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx index 0065f9569be2dd..71d03208fdce9d 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx @@ -9,12 +9,10 @@ import { Route, RouteComponentProps, Switch } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiPageBody, EuiPageContent, EuiSpacer, EuiTab, EuiTabs } from '@elastic/eui'; import { BASE_PATH, Section } from '../../../np_ready/public/application/constants'; -import { useAppDependencies } from './index'; import { breadcrumbService } from './lib/breadcrumb'; import { docTitleService } from './lib/doc_title'; import { ActionsList } from './sections/actions_list/components/actions_list'; -import { AlertsList } from './sections/alerts_list/components/alerts_list'; interface MatchParams { section: Section; @@ -26,22 +24,10 @@ export const AlertsUIHome: React.FunctionComponent { - const { - core: { chrome }, - } = useAppDependencies(); - - const notificationsUiEnabled = chrome.getIsVisible$(); - const tabs: Array<{ id: Section; name: React.ReactNode; }> = [ - { - id: 'alerts', - name: ( - - ), - }, { id: 'actions', name: ( @@ -51,27 +37,8 @@ export const AlertsUIHome: React.FunctionComponent ), }, - { - id: 'activity_logs', - name: ( - - ), - }, ]; - // Just example of Enable/Disable some UI tabs - if (notificationsUiEnabled) { - tabs.splice(2, 0, { - id: 'notifications', - name: ( - - ), - }); - } - const onSectionChange = (newSection: Section) => { history.push(`${BASE_PATH}/${newSection}`); }; @@ -102,9 +69,6 @@ export const AlertsUIHome: React.FunctionComponent - - - diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts index 1c1f77ca583919..b09292bd13121c 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts @@ -5,13 +5,7 @@ */ import { textService } from './text'; -import { - linkToHome, - linkToAlerts, - linkToActions, - linkToNotifications, - linkToActivityLogs, -} from '../constants'; +import { linkToHome, linkToActions } from '../constants'; class BreadcrumbService { private chrome: any; @@ -23,10 +17,7 @@ class BreadcrumbService { } = { management: [], home: [], - alerts: [], actions: [], - notifications: [], - activity_logs: [], }; public init(chrome: any, managementBreadcrumb: any): void { @@ -41,13 +32,6 @@ class BreadcrumbService { href: linkToHome(), }, ]; - this.breadcrumbs.alerts = [ - ...this.breadcrumbs.alerts, - { - text: textService.breadcrumbs.alerts, - href: linkToAlerts(), - }, - ]; this.breadcrumbs.actions = [ ...this.breadcrumbs.actions, { @@ -55,20 +39,6 @@ class BreadcrumbService { href: linkToActions(), }, ]; - this.breadcrumbs.activity_logs = [ - ...this.breadcrumbs.home, - { - text: textService.breadcrumbs.activity_logs, - href: linkToActivityLogs(), - }, - ]; - this.breadcrumbs.notifications = [ - ...this.breadcrumbs.home, - { - text: textService.breadcrumbs.notifications, - href: linkToNotifications(), - }, - ]; } public setBreadcrumbs(type: string): void { diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/text/text.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/text/text.ts index 28baa9be29238c..76a39a327a4f23 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/text/text.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/text/text.ts @@ -15,18 +15,9 @@ class TextService { home: i18n.translate('xpack.alertingUI.home.breadcrumbTitle', { defaultMessage: 'Alerting UI', }), - alerts: i18n.translate('xpack.alertingUI.alerts.breadcrumbTitle', { - defaultMessage: 'Alerts', - }), actions: i18n.translate('xpack.alertingUI.actions.breadcrumbTitle', { defaultMessage: 'Actions', }), - notifications: i18n.translate('xpack.alertingUI.notifications.breadcrumbTitle', { - defaultMessage: 'Notifications', - }), - activity_logs: i18n.translate('xpack.alertingUI.activity_logs.breadcrumbTitle', { - defaultMessage: 'Activity logs', - }), }; } } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx deleted file mode 100644 index b5ae01ed108c83..00000000000000 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import { EuiPageContent, EuiEmptyPrompt } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { RouteComponentProps } from 'react-router-dom'; - -interface AlertsListProps { - api: any; -} - -export const AlertsList: React.FunctionComponent> = ({ - match: { - params: { api }, - }, - history, -}) => { - return ( - - - - - } - body={'emptyPromptBody'} - data-test-subj="emptyPrompt" - /> - - ); -}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/index.scss b/x-pack/legacy/plugins/alerting_ui/np_ready/public/index.scss deleted file mode 100644 index bd0a70a19d8b58..00000000000000 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/index.scss +++ /dev/null @@ -1,4 +0,0 @@ -// Import the EUI global scope so we can use EUI constants -@import 'src/legacy/ui/public/styles/_styling_constants'; - -// Actions plugin styles diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts index a4f78dca8daf8a..7945d0a39c97fb 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts @@ -23,7 +23,7 @@ const REACT_ROOT_ID = 'alertingRoot'; export class ActionsPlugin implements Plugin { constructor(initializerContext: PluginInitializerContext) {} - public setup(coreSetup: CoreSetup, pluginsSetup: any): Setup { + public setup(core: CoreSetup, plugins: any): Setup { /* The code below would be replacing for current: uiExports: { @@ -32,7 +32,7 @@ export class ActionsPlugin implements Plugin { */ const { management: { getSection }, - } = pluginsSetup; + } = plugins; const kbnSection = getSection('kibana'); kbnSection.register('alerting', { @@ -44,9 +44,9 @@ export class ActionsPlugin implements Plugin { }); } - public start(coreStart: CoreStart, pluginsStart: any) { + public start(core: CoreStart, plugins: any) { textService.init(i18n); - breadcrumbService.init(coreStart.chrome, pluginsStart.management.breadcrumb); + breadcrumbService.init(core.chrome, plugins.management.breadcrumb); const unmountReactApp = (): void => { const elem = document.getElementById(REACT_ROOT_ID); @@ -83,7 +83,7 @@ export class ActionsPlugin implements Plugin { unmountReactApp(); const elReactRoot = document.getElementById(REACT_ROOT_ID); if (elReactRoot) { - renderReact(elReactRoot, coreStart, pluginsStart); + renderReact(elReactRoot, core, plugins); } }); }; diff --git a/x-pack/legacy/plugins/alerting_ui/public/hacks/register.ts b/x-pack/legacy/plugins/alerting_ui/public/hacks/register.ts index bf8cb6c5cc7dd4..71143525a840bb 100644 --- a/x-pack/legacy/plugins/alerting_ui/public/hacks/register.ts +++ b/x-pack/legacy/plugins/alerting_ui/public/hacks/register.ts @@ -4,11 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ +import { i18n } from '@kbn/i18n'; import { FeatureCatalogueRegistryProvider, FeatureCatalogueCategory, } from 'ui/registry/feature_catalogue'; -import { i18n } from '@kbn/i18n'; FeatureCatalogueRegistryProvider.register(() => { return { From 26ad779b26e20f1491971d3b4af39bcc0b720033 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 16 Oct 2019 13:04:08 -0400 Subject: [PATCH 038/297] Ability to delete actions individually --- .../actions_list/components/actions_list.tsx | 93 ++++++++++++------- 1 file changed, 59 insertions(+), 34 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 0043c0792db42e..a4139c9e270fb8 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -29,38 +29,6 @@ interface Data extends Action { } const canDelete = capabilities.get().actions.delete; -const actionsTableColumns = [ - { - field: 'description', - name: i18n.translate( - 'xpack.alertingUI.sections.actionsList.actionsListTable.descriptionHeader', - { - defaultMessage: 'Description', - } - ), - sortable: false, - truncateText: true, - }, - { - field: 'actionType', - name: i18n.translate( - 'xpack.alertingUI.sections.actionsList.actionsListTable.actionTypeHeader', - { - defaultMessage: 'Action Type', - } - ), - sortable: false, - truncateText: true, - }, - { - field: 'config', - name: i18n.translate('xpack.alertingUI.sections.actionsList.actionsListTable.configHeader', { - defaultMessage: 'Config', - }), - sortable: false, - truncateText: false, - }, -]; export const ActionsList: React.FunctionComponent> = ({ match: { @@ -136,13 +104,70 @@ export const ActionsList: React.FunctionComponent item.id) }); + await deleteActions({ http, ids: items.map(item => item.id) }); await loadActionsTable(); setIsDeletingActions(false); } + async function deleteSelectedItems() { + await deleteItems(selectedItems); + } + + const actionsTableColumns = [ + { + field: 'description', + name: i18n.translate( + 'xpack.alertingUI.sections.actionsList.actionsListTable.descriptionHeader', + { + defaultMessage: 'Description', + } + ), + sortable: false, + truncateText: true, + }, + { + field: 'actionType', + name: i18n.translate( + 'xpack.alertingUI.sections.actionsList.actionsListTable.actionTypeHeader', + { + defaultMessage: 'Action Type', + } + ), + sortable: false, + truncateText: true, + }, + { + field: 'config', + name: i18n.translate('xpack.alertingUI.sections.actionsList.actionsListTable.configHeader', { + defaultMessage: 'Config', + }), + sortable: false, + truncateText: false, + }, + { + name: i18n.translate('xpack.alertingUI.sections.actionsList.actionsListTable.actionsHeader', { + defaultMessage: 'Actions', + }), + actions: [ + { + name: i18n.translate( + 'xpack.alertingUI.sections.actionsList.actionsListTable.deleteActionName', + { defaultMessage: 'Delete' } + ), + description: i18n.translate( + 'xpack.alertingUI.sections.actionsList.actionsListTable.deleteActionDescription', + { defaultMessage: 'Delete' } + ), + type: 'icon', + icon: 'trash', + onClick: (item: Data) => deleteItems([item]), + }, + ], + }, + ]; + let content; if (errorCode) { From 02583625759924584143220304e0c05439c974ca Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 16 Oct 2019 13:47:47 -0400 Subject: [PATCH 039/297] Cleanup actions list --- .../actions_list/components/actions_list.tsx | 68 +++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index a4139c9e270fb8..9d58054842864b 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -52,20 +52,6 @@ export const ActionsList: React.FunctionComponent({ index: 0, size: 10 }); const [searchText, setSearchText] = useState(undefined); - async function loadActionsTable() { - setIsLoadingActions(true); - setErrorCode(null); - try { - const actionsResponse = await loadActions({ http, page, searchText }); - setActions(actionsResponse.data); - setTotalItemCount(actionsResponse.total); - } catch (e) { - setErrorCode(e.response.status); - } finally { - setIsLoadingActions(false); - } - } - useEffect(() => { loadActionsTable(); }, [page, searchText]); @@ -104,6 +90,20 @@ export const ActionsList: React.FunctionComponent item.id) }); @@ -119,7 +119,7 @@ export const ActionsList: React.FunctionComponent ({ value: actionType.id, @@ -206,14 +207,13 @@ export const ActionsList: React.FunctionComponent , From 3fc2c577c0e906e3adf214923a4778cbf65f373f Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 16 Oct 2019 14:41:47 -0400 Subject: [PATCH 040/297] Fix breadcrumb --- .../alerting_ui/np_ready/public/application/lib/breadcrumb.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts index b09292bd13121c..d71a5e434e33dd 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts @@ -33,7 +33,7 @@ class BreadcrumbService { }, ]; this.breadcrumbs.actions = [ - ...this.breadcrumbs.actions, + ...this.breadcrumbs.home, { text: textService.breadcrumbs.actions, href: linkToActions(), From 140e644b1ed93605d6e07537b774aa4c5a08aec2 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 16 Oct 2019 14:43:14 -0400 Subject: [PATCH 041/297] Remove required props from actions list --- .../sections/actions_list/components/actions_list.tsx | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 9d58054842864b..683f7d2ab59918 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -5,7 +5,6 @@ */ import React, { Fragment, useState, useEffect } from 'react'; -import { RouteComponentProps } from 'react-router-dom'; import { EuiPageContent, EuiBasicTable, EuiSpacer, EuiSearchBar, EuiButton } from '@elastic/eui'; import { capabilities } from 'ui/capabilities'; import { i18n } from '@kbn/i18n'; @@ -17,9 +16,6 @@ import { useAppDependencies } from '../../../index'; import { AlertingActionsDropdown } from './create_menu_popover'; type ActionTypeIndex = Record; -interface ActionsListProps { - api: any; -} interface Pagination { index: number; size: number; @@ -30,12 +26,7 @@ interface Data extends Action { const canDelete = capabilities.get().actions.delete; -export const ActionsList: React.FunctionComponent> = ({ - match: { - params: { api }, - }, - history, -}) => { +export const ActionsList: React.FunctionComponent = () => { const { core: { http }, } = useAppDependencies(); From c2b33014ced00b5c726585071d562332a54ba874 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 16 Oct 2019 14:50:46 -0400 Subject: [PATCH 042/297] Remove navigation.ts --- .../np_ready/public/application/app.tsx | 8 -------- .../np_ready/public/application/lib/navigation.ts | 15 --------------- 2 files changed, 23 deletions(-) delete mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/navigation.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx index 97c5064a26f5e8..ca49d3edab6701 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx @@ -6,7 +6,6 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { Switch, Route, Redirect } from 'react-router-dom'; -import { registerRouter } from './lib/navigation'; import { BASE_PATH, Section, DEFAULT_SECTION } from './constants'; import { AlertsUIHome } from './home'; @@ -21,13 +20,6 @@ class ShareRouter extends Component { }; constructor(props: any, context?: any) { super(props, context); - this.registerRouter(); - } - - registerRouter() { - // Share the router with the app without requiring React or context. - const { router } = this.context; - registerRouter(router); } render() { diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/navigation.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/navigation.ts deleted file mode 100644 index db9360e60f8cf7..00000000000000 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/navigation.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import { BASE_PATH } from '../constants'; - -let router: any; -export const registerRouter = (aRouter: any) => { - router = aRouter; -}; - -export const goToActionsList = () => { - router.history.push({ pathname: `${BASE_PATH}actions` }); -}; From 108222e8445f9d929b51eceead59685598e29a3a Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 16 Oct 2019 17:41:04 -0700 Subject: [PATCH 043/297] Added POST action to the server with proper server response validation, fixed action.config fields mapping --- .../components/page_error/section_error.tsx | 4 +- .../np_ready/public/application/lib/api.ts | 16 +- .../public/application/models/action.ts | 37 ++++ .../sections/action_add/action_add.tsx | 201 +++++++++++++----- .../action_fields/email_action_fields.tsx | 64 ++---- .../action_fields/index_action_fields.tsx | 10 +- .../action_fields/logging_action_fields.tsx | 10 +- .../action_fields/pagerduty_action_fields.tsx | 10 +- .../action_fields/slack_action_fields.tsx | 16 +- .../action_fields/webhook_action_fields.tsx | 28 +-- .../actions_list/components/actions_list.tsx | 14 +- .../components/create_menu_popover.tsx | 12 +- 12 files changed, 283 insertions(+), 139 deletions(-) create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/models/action.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/section_error.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/section_error.tsx index 8951b95b750781..c13f792e719883 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/section_error.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/section_error.tsx @@ -8,7 +8,7 @@ import { EuiCallOut, EuiSpacer } from '@elastic/eui'; import React, { Fragment } from 'react'; export interface Error { - data: { + body: { error: string; cause?: string[]; message?: string; @@ -25,7 +25,7 @@ export const SectionError: React.FunctionComponent = ({ title, error, ... error: errorString, cause, // wrapEsError() on the server adds a "cause" array message, - } = error.data; + } = error.body; return ( diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index 79da03200340ed..72c30c2866200b 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -12,10 +12,11 @@ export interface ActionType { } export interface Action { + secrets: Record; id: string; actionTypeId: string; description: string; - config: Record; + config: Record; } export interface LoadActionTypesOpts { @@ -57,3 +58,16 @@ export async function loadActions({ }, }); } + +export async function saveAction({ + http, + action, +}: { + http: HttpServiceBase; + action: Action; +}): Promise { + action.secrets = {}; + return http.post(`${BASE_ACTION_API_PATH}`, { + body: JSON.stringify(action), + }); +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/models/action.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/models/action.ts new file mode 100644 index 00000000000000..1d3e412c13a954 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/models/action.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { get } from 'lodash'; +import { i18n } from '@kbn/i18n'; + +export class ActionModel { + id: string; + actionTypeId: string; + description: string; + config: Record; + + constructor(props = {}) { + this.id = get(props, 'id'); + this.actionTypeId = get(props, 'actionTypeId'); + this.description = get(props, 'description'); + this.config = get(props, 'config', {}); + } + + validate() { + const validationResult = { errors: {} }; + const errors = { + description: new Array(), + }; + validationResult.errors = errors; + if (!this.description) { + errors.description.push( + i18n.translate('xpack.watcher.sections.watchEdit.threshold.error.requiredNameText', { + defaultMessage: 'Description is required.', + }) + ); + } + return validationResult; + } +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx index 5500919cdbcc4b..f865a26715ad46 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx @@ -3,8 +3,10 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, useContext, useState, useCallback } from 'react'; - +import React, { Fragment, useContext, useState, useCallback, useReducer, useEffect } from 'react'; +import { isEqual } from 'lodash'; +import { HttpServiceBase } from 'kibana/public'; +import { toastNotifications } from 'ui/notify'; import { EuiButton, EuiFlexGroup, @@ -21,10 +23,11 @@ import { EuiFlyoutBody, EuiFlyoutHeader, EuiFlyout, + EuiFieldText, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { Action, ActionType } from '../../lib/api'; +import { Action, ActionType, saveAction } from '../../lib/api'; import { ActionsContext } from '../../context/app_context'; import { WebhookActionFields, @@ -34,8 +37,10 @@ import { EmailActionFields, PagerDutyActionFields, } from './action_fields'; -import { SectionError } from '../../../application/components/page_error'; +import { SectionError, ErrableFormRow } from '../../../application/components/page_error'; import { actionTypesSettings, BUILDIN_ACTION_TYPES } from '../../constants/action_types_settings'; +import { useAppDependencies } from '../..'; +import { ActionModel } from '../../models/action'; const actionFieldsComponentMap = { [BUILDIN_ACTION_TYPES.LOGGING]: LoggingActionFields, @@ -47,30 +52,96 @@ const actionFieldsComponentMap = { }; interface Props { - actionType: ActionType | null; + actionType: ActionType; } +const actionReducer = (state: any, actionItem: any) => { + const { command, payload } = actionItem; + const { action } = state; + + switch (command) { + case 'setAction': + return { + ...state, + action: payload, + }; + case 'setProperty': { + const { property, value } = payload; + if (isEqual(action[property], value)) { + return state; + } else { + return { + ...state, + action: new ActionModel({ + ...action, + [property]: value, + }), + }; + } + } + case 'setConfigProperty': { + const { property, value } = payload; + if (isEqual(action.config[property], value)) { + return state; + } else { + return { + ...state, + action: new ActionModel({ + ...action, + config: { + ...action.config, + [property]: value, + }, + }), + }; + } + } + } +}; + export const ActionAdd = ({ actionType }: Props) => { + const { + core: { http }, + } = useAppDependencies(); const { flyoutVisible, setFlyoutVisibility } = useContext(ActionsContext); + // hooks + const [{ action }, dispatch] = useReducer(actionReducer, { + action: new ActionModel({ actionTypeId: actionType.id }), + }); + + const setActionProperty = (property: string, value: any) => { + dispatch({ command: 'setProperty', payload: { property, value } }); + }; + + const setActionConfigProperty = (property: string, value: any) => { + dispatch({ command: 'setConfigProperty', payload: { property, value } }); + }; + + const getAction = () => { + dispatch({ command: 'setAction', payload: new ActionModel({ actionTypeId: actionType.id }) }); + }; + + useEffect(() => { + getAction(); + }, [flyoutVisible]); + const closeFlyout = useCallback(() => setFlyoutVisibility(false), []); - const [isExecuting, setIsExecuting] = useState<{ [key: string]: boolean }>({}); - const [executeResultsError, setExecuteResultsError] = useState(null); const [isSaving, setIsSaving] = useState(false); const [serverError, setServerError] = useState<{ - data: { nessage: string; error: string }; + body: { message: string; error: string }; } | null>(null); if (!flyoutVisible) { return null; } - if (!actionType) return null; + const FieldsComponent = actionFieldsComponentMap[actionType.id]; const actionSettings = actionTypesSettings(actionType.id); - const hasErrors = false; // !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); - const action = { actionTypeId: actionType.id, config: {} } as Action; + const { errors } = action.validate(); + const hasErrors = !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); return ( - + @@ -81,7 +152,7 @@ export const ActionAdd = ({ actionType }: Props) => {

@@ -89,22 +160,53 @@ export const ActionAdd = ({ actionType }: Props) => {
- {executeResultsError && executeResultsError[action.id] && ( - - - } - error={executeResultsError[action.id]} - /> - - - )} - + {serverError && ( + + + } + error={serverError} + /> + + + )} + + } + errorKey="description" + isShowingErrors={hasErrors && action.description !== undefined} + errors={errors} + > + { + setActionProperty('description', e.target.value); + }} + onBlur={() => { + if (!action.description) { + setActionProperty('description', ''); + } + }} + /> + + {actionType.id === null ? ( { })} - - { - setIsExecuting({ [action.id]: true }); - setExecuteResultsError(null); - setIsExecuting({ [action.id]: false }); - }} - > - {i18n.translate('xpack.alertingUI.sections.actionAdd.testButtonLabel', { - defaultMessage: 'Test', - })} - - - + { isLoading={isSaving} onClick={async () => { setIsSaving(true); - const savedAction = await onActionSave(action); + const savedAction = await onActionSave(http, action); + setIsSaving(false); if (savedAction && savedAction.error) { - setIsSaving(false); return setServerError(savedAction.error); } + setFlyoutVisibility(false); }} > { ); }; -export async function onActionSave(action: Action): Promise { - return []; +export async function onActionSave(http: HttpServiceBase, action: Action): Promise { + try { + const newAction = await saveAction({ http, action }); + toastNotifications.addSuccess( + i18n.translate('xpack.alertingUI.sections.actionAdd.saveSuccessNotificationText', { + defaultMessage: "Saved '{actionName}'", + values: { + actionName: newAction.description, + }, + }) + ); + return newAction; + } catch (error) { + return { + error, + }; + } } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/email_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/email_action_fields.tsx index 09821a04a2c6c4..b3edf71f4789a5 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/email_action_fields.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/email_action_fields.tsx @@ -4,66 +4,46 @@ * you may not use this file except in compliance with the Elastic License. */ import React, { Fragment } from 'react'; - -import { EuiComboBox, EuiFieldText, EuiFormRow, EuiTextArea } from '@elastic/eui'; +import { EuiFieldText, EuiFormRow, EuiTextArea } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ErrableFormRow } from '../../../components/page_error'; import { Action } from '../../../lib/api'; interface Props { action: Action; + editActionConfig: (property: string, value: any) => void; errors: { [key: string]: string[] }; hasErrors: boolean; } export const EmailActionFields: React.FunctionComponent = ({ action, + editActionConfig, errors, hasErrors, }) => { - const { to, subject, body }: any = action.config; - const toOptions = to ? to.map((label: any) => ({ label })) : []; + const { from, host, port }: any = action.config; return ( - - { - const newOptions = [...toOptions, { label: searchValue }]; - // editAction({ key: 'to', value: newOptions.map(newOption => newOption.label) }); - }} - onChange={(selectedOptions: Array<{ label: string }>) => { - /* editAction({ - key: 'to', - value: selectedOptions.map(selectedOption => selectedOption.label), - }); */ - }} - onBlur={() => { - if (!to) { - /* editAction({ - key: 'to', - value: [], - }); */ - } + name="from" + data-test-subj="emailFromInput" + value={from || ''} + onChange={e => { + editActionConfig('from', e.target.value); }} /> - + = ({ fullWidth name="subject" data-test-subj="emailSubjectInput" - value={subject || ''} + value={host || ''} onChange={e => { - // editAction({ key: 'subject', value: e.target.value }); + editActionConfig('subject', e.target.value); }} /> @@ -88,19 +68,19 @@ export const EmailActionFields: React.FunctionComponent = ({ { - // editAction({ key: 'body', value: e.target.value }); + editActionConfig('message', e.target.value); }} /> diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index_action_fields.tsx index 3278685720860f..b8819a2fb4e8d1 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index_action_fields.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index_action_fields.tsx @@ -11,14 +11,14 @@ import { Action } from '../../../lib/api'; interface Props { action: Action; - // editAction: (changedProperty: { key: string; value: string }) => void; + editActionConfig: (property: string, value: any) => void; errors: { [key: string]: string[] }; hasErrors: boolean; } export const IndexActionFields: React.FunctionComponent = ({ action, - // editAction, + editActionConfig, errors, hasErrors, }) => { @@ -38,13 +38,13 @@ export const IndexActionFields: React.FunctionComponent = ({ fullWidth name="index" data-test-subj="indexInput" - value={index || ''} + value={index} onChange={(e: React.ChangeEvent) => { - // editAction({ key: 'index', value: e.target.value }); + editActionConfig('index', e.target.value); }} onBlur={() => { if (!index) { - // editAction({ key: 'index', value: '' }); + editActionConfig('index', ''); } }} /> diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/logging_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/logging_action_fields.tsx index 66186eeaa69efa..421322af8f4fe8 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/logging_action_fields.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/logging_action_fields.tsx @@ -11,18 +11,18 @@ import { Action } from '../../../lib/api'; interface Props { action: Action; - // editAction: (changedProperty: { key: string; value: string }) => void; + editActionConfig: (property: string, value: any) => void; errors: { [key: string]: string[] }; hasErrors: boolean; } export const LoggingActionFields: React.FunctionComponent = ({ action, - // editAction, + editActionConfig, errors, hasErrors, }) => { - const { text }: any = action.config; + const { text } = action.config; return ( = ({ value={text || ''} data-test-subj="loggingTextInput" onChange={(e: React.ChangeEvent) => { - // editAction({ key: 'text', value: e.target.value }); + editActionConfig('text', e.target.value); }} onBlur={() => { if (!text) { - // editAction({ key: 'text', value: '' }); + editActionConfig('text', ''); } }} /> diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/pagerduty_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/pagerduty_action_fields.tsx index 4fd3f2807adec8..41d3754e6ca03e 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/pagerduty_action_fields.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/pagerduty_action_fields.tsx @@ -11,7 +11,7 @@ import { Action } from '../../../lib/api'; interface Props { action: Action; - // editAction: (changedProperty: { key: string; value: string }) => void; + editActionConfig: (property: string, value: any) => void; errors: { [key: string]: string[] }; hasErrors: boolean; children: React.ReactNode; @@ -21,10 +21,10 @@ export const PagerDutyActionFields: React.FunctionComponent = ({ errors, hasErrors, action, - // editAction, + editActionConfig, children, }) => { - const { description } = action; + const { description } = action.config; return ( {children} @@ -47,11 +47,11 @@ export const PagerDutyActionFields: React.FunctionComponent = ({ value={description || ''} data-test-subj="pagerdutyDescriptionInput" onChange={(e: React.ChangeEvent) => { - // editAction({ key: 'description', value: e.target.value }); + editActionConfig('description', e.target.value); }} onBlur={() => { if (!description) { - // editAction({ key: 'description', value: '' }); + editActionConfig('description', ''); } }} /> diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/slack_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/slack_action_fields.tsx index 95053cb4abb1d8..ec492387b8061a 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/slack_action_fields.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/slack_action_fields.tsx @@ -10,10 +10,15 @@ import { Action } from '../../../lib/api'; interface Props { action: Action; + editActionConfig: (property: string, value: any) => void; children: React.ReactNode; } -export const SlackActionFields: React.FunctionComponent = ({ action, children }) => { +export const SlackActionFields: React.FunctionComponent = ({ + action, + editActionConfig, + children, +}) => { const { text, to }: any = action.config; const toOptions = to ? to.map((label: any) => ({ label })) : []; @@ -36,13 +41,10 @@ export const SlackActionFields: React.FunctionComponent = ({ action, chil data-test-subj="slackRecipientComboBox" onCreateOption={(searchValue: string) => { const newOptions = [...toOptions, { label: searchValue }]; - // editAction({ key: 'to', value: newOptions.map(newOption => newOption.label) }); + editActionConfig('to', newOptions.map(newOption => newOption.label)); }} onChange={(selectedOptions: Array<{ label: string }>) => { - /* editAction({ - key: 'to', - value: selectedOptions.map(selectedOption => selectedOption.label), - }); */ + editActionConfig('to', selectedOptions.map(selectedOption => selectedOption.label)); }} /> @@ -62,7 +64,7 @@ export const SlackActionFields: React.FunctionComponent = ({ action, chil value={text} data-test-subj="slackMessageTextarea" onChange={e => { - // editAction({ key: 'text', value: e.target.value }); + editActionConfig('text', e.target.value); }} /> diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx index a13f2adebf7b16..46c49db93790d0 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx @@ -22,7 +22,7 @@ import { Action } from '../../../lib/api'; interface Props { action: Action; - // editAction: (changedProperty: { key: string; value: any }) => void; + editActionConfig: (property: string, value: any) => void; errors: { [key: string]: string[] }; hasErrors: boolean; } @@ -31,15 +31,15 @@ const HTTP_VERBS = ['head', 'get', 'post', 'put', 'delete']; export const WebhookActionFields: React.FunctionComponent = ({ action, - // editAction, + editActionConfig, errors, hasErrors, }) => { const { method, host, port, path, body, username, password }: any = action.config; - // useEffect(() => { - // editAction({ key: 'contentType', value: 'application/json' }); // set content-type for threshold watch to json by default - // }, []); + useEffect(() => { + editActionConfig('contentType', 'application/json'); // set content-type for threshold watch to json by default + }, []); return ( @@ -59,7 +59,7 @@ export const WebhookActionFields: React.FunctionComponent = ({ data-test-subj="webhookMethodSelect" options={HTTP_VERBS.map(verb => ({ text: verb.toUpperCase(), value: verb }))} onChange={e => { - // editAction({ key: 'method', value: e.target.value }); + editActionConfig('method', e.target.value); }} /> @@ -85,11 +85,11 @@ export const WebhookActionFields: React.FunctionComponent = ({ value={host || ''} data-test-subj="webhookHostInput" onChange={e => { - // editAction({ key: 'host', value: e.target.value }); + editActionConfig('host', e.target.value); }} onBlur={() => { if (!host) { - // editAction({ key: 'host', value: '' }); + editActionConfig('host', ''); } }} /> @@ -117,11 +117,11 @@ export const WebhookActionFields: React.FunctionComponent = ({ value={port || ''} data-test-subj="webhookPortInput" onChange={e => { - // editAction({ key: 'port', value: parseInt(e.target.value, 10) }); + editActionConfig('port', parseInt(e.target.value, 10)); }} onBlur={() => { if (!port) { - // editAction({ key: 'port', value: '' }); + editActionConfig('port', ''); } }} /> @@ -145,7 +145,7 @@ export const WebhookActionFields: React.FunctionComponent = ({ value={path || ''} data-test-subj="webhookPathInput" onChange={e => { - // editAction({ key: 'path', value: e.target.value }); + editActionConfig('path', e.target.value); }} /> @@ -171,7 +171,7 @@ export const WebhookActionFields: React.FunctionComponent = ({ value={username || ''} data-test-subj="webhookUsernameInput" onChange={e => { - // editAction({ key: 'username', value: e.target.value }); + editActionConfig('username', e.target.value); }} /> @@ -195,7 +195,7 @@ export const WebhookActionFields: React.FunctionComponent = ({ value={password || ''} data-test-subj="webhookPasswordInput" onChange={e => { - // editAction({ key: 'password', value: e.target.value }); + editActionConfig('password', e.target.value); }} /> @@ -229,7 +229,7 @@ export const WebhookActionFields: React.FunctionComponent = ({ )} value={body || ''} onChange={(json: string) => { - // editAction({ key: 'body', value: json }); + editActionConfig('body', json); }} /> diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 5f18491e42e1d5..f90685a083185a 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -164,7 +164,10 @@ export const ActionsList: React.FunctionComponent - + @@ -201,6 +204,11 @@ export const ActionsList: React.FunctionComponent; + } + return (
{content} - + {flyout}
); @@ -230,7 +238,7 @@ export const ContentWrapper = ({ return ( - + {children} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx index 68150646eaad15..8fafc80404bf08 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx @@ -16,16 +16,18 @@ import { EuiContextMenuItem, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { ActionsContext } from '../../../context/app_context'; import { actionTypesSettings } from '../../../constants/action_types_settings'; +import { ActionType } from '../../../lib/api'; interface Props { - actionTypes: any; + actionTypes: Record; + createAction: (actionTypeItem: ActionType) => void; } -export const AlertingActionsDropdown: React.FunctionComponent = ({ actionTypes }) => { - const { createAction } = useContext(ActionsContext); - +export const AlertingActionsDropdown: React.FunctionComponent = ({ + actionTypes, + createAction, +}) => { const [isPopoverOpen, setIsPopOverOpen] = useState(false); const actions = Object.entries(!actionTypes ? [] : actionTypes).map( From ab7f26150fbdc35e0c4e25801ffc04e9f1fc1729 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 16 Oct 2019 22:32:47 -0700 Subject: [PATCH 044/297] Refactored and cleanup buildin Action adding forms, added validation --- .../constants/action_types_settings.ts | 139 ++++++++++++- .../np_ready/public/application/lib/api.ts | 1 - .../public/application/models/action.ts | 2 + .../sections/action_add/action_add.tsx | 25 ++- .../action_fields/email_action_fields.tsx | 184 +++++++++++++----- .../action_fields/index_action_fields.tsx | 15 +- .../action_fields/logging_action_fields.tsx | 34 +--- .../action_fields/pagerduty_action_fields.tsx | 58 ++++-- .../action_fields/slack_action_fields.tsx | 68 +++---- .../action_fields/webhook_action_fields.tsx | 175 +++-------------- 10 files changed, 407 insertions(+), 294 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_types_settings.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_types_settings.ts index 1a3743cbf41942..c14bb93dbf43fe 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_types_settings.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_types_settings.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import { i18n } from '@kbn/i18n'; +import { Action } from '../lib/api'; export const BUILDIN_ACTION_TYPES: { [key: string]: string } = { EMAIL: '.email', @@ -15,7 +16,14 @@ export const BUILDIN_ACTION_TYPES: { [key: string]: string } = { CUSTOM: '.custom', }; -export const actionTypesSettings = (val: string) => { +interface ActionTypeSettings { + iconClass: string; + selectMessage: string; + simulatePrompt: string; + validate: any; +} + +export const actionTypesSettings = (val: string): ActionTypeSettings => { let res; switch (val) { case '.email': @@ -33,6 +41,53 @@ export const actionTypesSettings = (val: string) => { defaultMessage: 'Send test email', } ), + validate: (action: Action): any => { + const validationResult = { errors: {} }; + const errors = { + from: new Array(), + port: new Array(), + host: new Array(), + user: new Array(), + password: new Array(), + }; + validationResult.errors = errors; + if (!action.config.from) { + errors.from.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredFromText', { + defaultMessage: 'From is required.', + }) + ); + } + if (!action.config.port) { + errors.port.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredPortText', { + defaultMessage: 'Port is required.', + }) + ); + } + if (!action.config.host) { + errors.host.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHostText', { + defaultMessage: 'Host is required.', + }) + ); + } + if (!action.secrets.user) { + errors.user.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHostText', { + defaultMessage: 'User is required.', + }) + ); + } + if (!action.secrets.password) { + errors.password.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHostText', { + defaultMessage: 'Password is required.', + }) + ); + } + return validationResult; + }, }; break; case '.slack': @@ -50,6 +105,21 @@ export const actionTypesSettings = (val: string) => { defaultMessage: 'Send a sample message', } ), + validate: (action: Action): any => { + const validationResult = { errors: {} }; + const errors = { + webhookUrl: new Array(), + }; + validationResult.errors = errors; + if (!action.secrets.webhookUrl) { + errors.webhookUrl.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredWebhookUrlText', { + defaultMessage: 'WebhookUrl is required.', + }) + ); + } + return validationResult; + }, }; break; case '.server-log': @@ -67,6 +137,9 @@ export const actionTypesSettings = (val: string) => { defaultMessage: 'Log a sample message', } ), + validate: (action: Action): any => { + return { errors: {} }; + }, }; break; case '.index': @@ -78,6 +151,9 @@ export const actionTypesSettings = (val: string) => { simulatePrompt: i18n.translate('xpack.watcher.models.indexAction.simulateButtonLabel', { defaultMessage: 'Index data', }), + validate: (action: Action): any => { + return { errors: {} }; + }, }; break; case '.pagerduty': @@ -89,6 +165,29 @@ export const actionTypesSettings = (val: string) => { simulatePrompt: i18n.translate('xpack.watcher.models.pagerDutyAction.simulateButtonLabel', { defaultMessage: 'Send a PagerDuty event', }), + validate: (action: Action): any => { + const validationResult = { errors: {} }; + const errors = { + routingKey: new Array(), + apiUrl: new Array(), + }; + validationResult.errors = errors; + if (!action.secrets.routingKey) { + errors.routingKey.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredRoutingKeyText', { + defaultMessage: 'RoutingKey is required.', + }) + ); + } + if (!action.config.apiUrl) { + errors.apiUrl.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredApiUrlText', { + defaultMessage: 'ApiUrl is required.', + }) + ); + } + return validationResult; + }, }; break; case '.webhook': @@ -100,10 +199,46 @@ export const actionTypesSettings = (val: string) => { simulatePrompt: i18n.translate('xpack.watcher.models.webhookAction.simulateButtonLabel', { defaultMessage: 'Send request', }), + validate: (action: Action): any => { + const validationResult = { errors: {} }; + const errors = { + description: new Array(), + }; + validationResult.errors = errors; + if (!action.config.url) { + errors.description.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredUrlText', { + defaultMessage: 'Url is required.', + }) + ); + } + if (!action.config.method) { + errors.description.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredMethodText', { + defaultMessage: 'Method is required.', + }) + ); + } + if (!action.config.headers) { + errors.description.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHeadersText', { + defaultMessage: 'Headers is required.', + }) + ); + } + return validationResult; + }, }; break; default: - res = { typeName: '', iconClass: 'apps', selectMessage: '' }; + res = { + iconClass: 'apps', + simulatePrompt: '', + selectMessage: '', + validate: (action: Action): any => { + return { errors: {} }; + }, + }; } return res; }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index d13eba1e3e8ff7..caebb14d53c2af 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -66,7 +66,6 @@ export async function saveAction({ http: HttpServiceBase; action: Action; }): Promise { - action.secrets = {}; return http.post(`${BASE_ACTION_API_PATH}`, { body: JSON.stringify(action), }); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/models/action.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/models/action.ts index 1d3e412c13a954..fe845674202e2f 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/models/action.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/models/action.ts @@ -11,12 +11,14 @@ export class ActionModel { actionTypeId: string; description: string; config: Record; + secrets: Record; constructor(props = {}) { this.id = get(props, 'id'); this.actionTypeId = get(props, 'actionTypeId'); this.description = get(props, 'description'); this.config = get(props, 'config', {}); + this.secrets = get(props, 'secrets', {}); } validate() { diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx index f865a26715ad46..3589a4e70438bf 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx @@ -96,6 +96,23 @@ const actionReducer = (state: any, actionItem: any) => { }; } } + case 'setSecretsProperty': { + const { property, value } = payload; + if (isEqual(action.secrets[property], value)) { + return state; + } else { + return { + ...state, + action: new ActionModel({ + ...action, + secrets: { + ...action.secrets, + [property]: value, + }, + }), + }; + } + } } }; @@ -117,12 +134,17 @@ export const ActionAdd = ({ actionType }: Props) => { dispatch({ command: 'setConfigProperty', payload: { property, value } }); }; + const setActionSecretsProperty = (property: string, value: any) => { + dispatch({ command: 'setSecretsProperty', payload: { property, value } }); + }; + const getAction = () => { dispatch({ command: 'setAction', payload: new ActionModel({ actionTypeId: actionType.id }) }); }; useEffect(() => { getAction(); + setServerError(null); }, [flyoutVisible]); const closeFlyout = useCallback(() => setFlyoutVisibility(false), []); @@ -137,7 +159,7 @@ export const ActionAdd = ({ actionType }: Props) => { const FieldsComponent = actionFieldsComponentMap[actionType.id]; const actionSettings = actionTypesSettings(actionType.id); - const { errors } = action.validate(); + const errors = { ...actionSettings.validate(action).errors, ...action.validate().errors }; const hasErrors = !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); return ( @@ -205,6 +227,7 @@ export const ActionAdd = ({ actionType }: Props) => { action={action} errors={errors} editActionConfig={setActionConfigProperty} + editActionSecrets={setActionSecretsProperty} hasErrors={hasErrors} > {actionType.id === null ? ( diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/email_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/email_action_fields.tsx index b3edf71f4789a5..7012e55198640e 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/email_action_fields.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/email_action_fields.tsx @@ -4,13 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ import React, { Fragment } from 'react'; -import { EuiFieldText, EuiFormRow, EuiTextArea } from '@elastic/eui'; +import { EuiFieldText, EuiFlexItem, EuiFlexGroup, EuiFieldNumber } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { Action } from '../../../lib/api'; +import { ErrableFormRow } from '../../../components/page_error'; interface Props { action: Action; editActionConfig: (property: string, value: any) => void; + editActionSecrets: (property: string, value: any) => void; errors: { [key: string]: string[] }; hasErrors: boolean; } @@ -18,72 +20,156 @@ interface Props { export const EmailActionFields: React.FunctionComponent = ({ action, editActionConfig, + editActionSecrets, errors, hasErrors, }) => { const { from, host, port }: any = action.config; + const { user, password }: any = action.secrets; return ( - { editActionConfig('from', e.target.value); }} - /> - - - - { - editActionConfig('subject', e.target.value); - }} - /> - - - - { - editActionConfig('message', e.target.value); + onBlur={() => { + if (!from) { + editActionConfig('from', ''); + } }} /> - + + + + + { + editActionConfig('host', e.target.value); + }} + onBlur={() => { + if (!host) { + editActionConfig('host', ''); + } + }} + /> + + + + + { + editActionConfig('port', parseInt(e.target.value, 10)); + }} + onBlur={() => { + if (!port) { + editActionConfig('port', ''); + } + }} + /> + + + + + + + { + editActionSecrets('user', e.target.value); + }} + onBlur={() => { + if (!user) { + editActionSecrets('user', ''); + } + }} + /> + + + + + { + editActionSecrets('password', e.target.value); + }} + onBlur={() => { + if (!password) { + editActionSecrets('password', ''); + } + }} + /> + + + ); }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index_action_fields.tsx index b8819a2fb4e8d1..938055c46ea4b6 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index_action_fields.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index_action_fields.tsx @@ -4,9 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ import React from 'react'; -import { EuiFieldText } from '@elastic/eui'; +import { EuiFieldText, EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ErrableFormRow } from '../../../components/page_error'; import { Action } from '../../../lib/api'; interface Props { @@ -24,14 +23,10 @@ export const IndexActionFields: React.FunctionComponent = ({ }) => { const { index }: any = action.config; return ( - = ({ } }} /> - + ); }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/logging_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/logging_action_fields.tsx index 421322af8f4fe8..d476b658ed1b43 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/logging_action_fields.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/logging_action_fields.tsx @@ -3,10 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; -import { EuiFieldText } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { ErrableFormRow } from '../../../components/page_error'; +import React, { Fragment } from 'react'; import { Action } from '../../../lib/api'; interface Props { @@ -22,32 +19,5 @@ export const LoggingActionFields: React.FunctionComponent = ({ errors, hasErrors, }) => { - const { text } = action.config; - return ( - - ) => { - editActionConfig('text', e.target.value); - }} - onBlur={() => { - if (!text) { - editActionConfig('text', ''); - } - }} - /> - - ); + return ; }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/pagerduty_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/pagerduty_action_fields.tsx index 41d3754e6ca03e..afd3829b0df43d 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/pagerduty_action_fields.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/pagerduty_action_fields.tsx @@ -12,9 +12,9 @@ import { Action } from '../../../lib/api'; interface Props { action: Action; editActionConfig: (property: string, value: any) => void; + editActionSecrets: (property: string, value: any) => void; errors: { [key: string]: string[] }; hasErrors: boolean; - children: React.ReactNode; } export const PagerDutyActionFields: React.FunctionComponent = ({ @@ -22,36 +22,64 @@ export const PagerDutyActionFields: React.FunctionComponent = ({ hasErrors, action, editActionConfig, - children, + editActionSecrets, }) => { - const { description } = action.config; + const { apiUrl } = action.config; + const { routingKey } = action.secrets; return ( - {children} ) => { - editActionConfig('description', e.target.value); + editActionConfig('apiUrl', e.target.value); }} onBlur={() => { - if (!description) { - editActionConfig('description', ''); + if (!apiUrl) { + editActionConfig('apiUrl', ''); + } + }} + /> + + + ) => { + editActionSecrets('routingKey', e.target.value); + }} + onBlur={() => { + if (!routingKey) { + editActionSecrets('routingKey', ''); } }} /> diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/slack_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/slack_action_fields.tsx index ec492387b8061a..1636d2752b0d81 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/slack_action_fields.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/slack_action_fields.tsx @@ -4,70 +4,56 @@ * you may not use this file except in compliance with the Elastic License. */ import React, { Fragment } from 'react'; -import { EuiComboBox, EuiTextArea, EuiFormRow } from '@elastic/eui'; +import { EuiFieldText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { Action } from '../../../lib/api'; +import { ErrableFormRow } from '../../../components/page_error'; interface Props { action: Action; - editActionConfig: (property: string, value: any) => void; - children: React.ReactNode; + editActionSecrets: (property: string, value: any) => void; + errors: { [key: string]: string[] }; + hasErrors: boolean; } export const SlackActionFields: React.FunctionComponent = ({ action, - editActionConfig, - children, + editActionSecrets, + errors, + hasErrors, }) => { - const { text, to }: any = action.config; - const toOptions = to ? to.map((label: any) => ({ label })) : []; + const { webhookUrl }: any = action.secrets; return ( - {children} - - { - const newOptions = [...toOptions, { label: searchValue }]; - editActionConfig('to', newOptions.map(newOption => newOption.label)); - }} - onChange={(selectedOptions: Array<{ label: string }>) => { - editActionConfig('to', selectedOptions.map(selectedOption => selectedOption.label)); - }} - /> - - - - { - editActionConfig('text', e.target.value); + editActionSecrets('webhookUrl', e.target.value); + }} + onBlur={() => { + if (!webhookUrl) { + editActionSecrets('webhookUrl', ''); + } }} /> - + ); }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx index 46c49db93790d0..0affd269980798 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx @@ -14,7 +14,6 @@ import { EuiSelect, EuiFlexGroup, EuiFlexItem, - EuiSpacer, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ErrableFormRow } from '../../../components/page_error'; @@ -23,23 +22,22 @@ import { Action } from '../../../lib/api'; interface Props { action: Action; editActionConfig: (property: string, value: any) => void; + editActionSecrets: (property: string, value: any) => void; errors: { [key: string]: string[] }; hasErrors: boolean; } -const HTTP_VERBS = ['head', 'get', 'post', 'put', 'delete']; +const HTTP_VERBS = ['post', 'put']; export const WebhookActionFields: React.FunctionComponent = ({ action, editActionConfig, + editActionSecrets, errors, hasErrors, }) => { - const { method, host, port, path, body, username, password }: any = action.config; - - useEffect(() => { - editActionConfig('contentType', 'application/json'); // set content-type for threshold watch to json by default - }, []); + const { user, password }: any = action.secrets; + const { method, url, headers }: any = action.config; return ( @@ -55,7 +53,7 @@ export const WebhookActionFields: React.FunctionComponent = ({ > ({ text: verb.toUpperCase(), value: verb }))} onChange={e => { @@ -64,175 +62,66 @@ export const WebhookActionFields: React.FunctionComponent = ({ />
- + + { - editActionConfig('host', e.target.value); + editActionSecrets('user', e.target.value); }} onBlur={() => { - if (!host) { - editActionConfig('host', ''); + if (!user) { + editActionSecrets('user', ''); } }} /> - - { - editActionConfig('port', parseInt(e.target.value, 10)); - }} - onBlur={() => { - if (!port) { - editActionConfig('port', ''); - } - }} - /> - - - - - { - editActionConfig('path', e.target.value); - }} - /> - - - - - - - - { - editActionConfig('username', e.target.value); - }} - /> - - - - - - { - editActionConfig('password', e.target.value); + editActionSecrets('password', e.target.value); + }} + onBlur={() => { + if (!password) { + editActionSecrets('password', ''); + } }} /> - - - - - { - editActionConfig('body', json); - }} - /> -
); }; From 428479cb1bfae9b053dc02aafd7b7863fe42501a Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 16 Oct 2019 22:42:05 -0700 Subject: [PATCH 045/297] Added refresh of actions list on action saved handler --- .../application/sections/action_add/action_add.tsx | 4 +++- .../sections/actions_list/components/actions_list.tsx | 10 ++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx index 3589a4e70438bf..6c27a0688d7e5a 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx @@ -53,6 +53,7 @@ const actionFieldsComponentMap = { interface Props { actionType: ActionType; + refreshList: () => void; } const actionReducer = (state: any, actionItem: any) => { @@ -116,7 +117,7 @@ const actionReducer = (state: any, actionItem: any) => { } }; -export const ActionAdd = ({ actionType }: Props) => { +export const ActionAdd = ({ actionType, refreshList }: Props) => { const { core: { http }, } = useAppDependencies(); @@ -294,6 +295,7 @@ export const ActionAdd = ({ actionType }: Props) => { return setServerError(savedAction.error); } setFlyoutVisibility(false); + refreshList(); }} > { let flyout = null; if (actionType) { - flyout = ; + flyout = ; } return (
- + {content} {flyout} @@ -279,12 +275,10 @@ export const ActionsList: React.FunctionComponent = () => { export const ContentWrapper = ({ flyoutVisible, setFlyoutVisibility, - createAction, children, }: { flyoutVisible: boolean; setFlyoutVisibility: React.Dispatch>; - createAction: (actionType: ActionType) => void; children: React.ReactNode; }) => { return ( From 906db1449b1fb3d05617e85bad3d83c88e6363d0 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 17 Oct 2019 09:39:36 -0400 Subject: [PATCH 046/297] Disable delete icon when no access --- .../actions_list/components/actions_list.tsx | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 683f7d2ab59918..17231626048288 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -145,14 +145,20 @@ export const ActionsList: React.FunctionComponent = () => { ), actions: [ { + enabled: () => canDelete, name: i18n.translate( 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.actions.deleteActionName', { defaultMessage: 'Delete' } ), - description: i18n.translate( - 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.actions.deleteActionDescription', - { defaultMessage: 'Delete this action' } - ), + description: canDelete + ? i18n.translate( + 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.actions.deleteActionDescription', + { defaultMessage: 'Delete this action' } + ) + : i18n.translate( + 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.actions.deleteActionDisabledDescription', + { defaultMessage: 'Unable to delete actions' } + ), type: 'icon', icon: 'trash', onClick: (item: Data) => deleteItems([item]), @@ -198,9 +204,10 @@ export const ActionsList: React.FunctionComponent = () => { title={ canDelete ? undefined - : i18n.translate('xpack.alertingUI.sections.actionsList.buttons.deleteTitle', { - defaultMessage: 'Unable to delete saved objects', - }) + : i18n.translate( + 'xpack.alertingUI.sections.actionsList.buttons.deleteDisabledTitle', + { defaultMessage: 'Unable to delete actions' } + ) } > Date: Thu, 17 Oct 2019 10:40:24 -0400 Subject: [PATCH 047/297] Fix failing jest tests --- .../plugins/actions/server/builtin_action_types/email.test.ts | 2 +- .../actions/server/builtin_action_types/es_index.test.ts | 2 +- .../actions/server/builtin_action_types/pagerduty.test.ts | 2 +- .../actions/server/builtin_action_types/server_log.test.ts | 2 +- .../plugins/actions/server/builtin_action_types/slack.test.ts | 2 +- .../plugins/actions/server/builtin_action_types/webhook.test.ts | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/email.test.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/email.test.ts index 4e2ef29dd740ff..407e93b3957613 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/email.test.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/email.test.ts @@ -40,7 +40,7 @@ beforeEach(() => { describe('actionTypeRegistry.get() works', () => { test('action type static data is as expected', () => { expect(actionType.id).toEqual(ACTION_TYPE_ID); - expect(actionType.name).toEqual('email'); + expect(actionType.name).toEqual('Email'); }); }); diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/es_index.test.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/es_index.test.ts index 57a107968ba70b..48b4e78b68748c 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/es_index.test.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/es_index.test.ts @@ -37,7 +37,7 @@ beforeEach(() => { describe('actionTypeRegistry.get() works', () => { test('action type static data is as expected', () => { expect(actionType.id).toEqual(ACTION_TYPE_ID); - expect(actionType.name).toEqual('index'); + expect(actionType.name).toEqual('Index'); }); }); diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/pagerduty.test.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/pagerduty.test.ts index a9f3ea757e33b5..18965573849007 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/pagerduty.test.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/pagerduty.test.ts @@ -33,7 +33,7 @@ beforeAll(() => { describe('get()', () => { test('should return correct action type', () => { expect(actionType.id).toEqual(ACTION_TYPE_ID); - expect(actionType.name).toEqual('pagerduty'); + expect(actionType.name).toEqual('PagerDuty'); }); }); diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.test.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.test.ts index e3feec6d1bc670..fddfcd2cb2cd8a 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.test.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.test.ts @@ -25,7 +25,7 @@ beforeAll(() => { describe('get()', () => { test('returns action type', () => { expect(actionType.id).toEqual(ACTION_TYPE_ID); - expect(actionType.name).toEqual('server-log'); + expect(actionType.name).toEqual('Server Log'); }); }); diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/slack.test.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/slack.test.ts index 681f508b1d2145..cd9976628d9592 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/slack.test.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/slack.test.ts @@ -58,7 +58,7 @@ describe('action is registered', () => { test('returns action type', () => { const returnedActionType = actionTypeRegistry.get(ACTION_TYPE_ID); expect(returnedActionType.id).toEqual(ACTION_TYPE_ID); - expect(returnedActionType.name).toEqual('slack'); + expect(returnedActionType.name).toEqual('Slack'); }); }); diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/webhook.test.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/webhook.test.ts index 2d492eb451e801..9883d3ec1c1403 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/webhook.test.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/webhook.test.ts @@ -31,7 +31,7 @@ beforeAll(() => { describe('actionType', () => { test('exposes the action as `webhook` on its Id and Name', () => { expect(actionType.id).toEqual('.webhook'); - expect(actionType.name).toEqual('webhook'); + expect(actionType.name).toEqual('Webhook'); }); }); From 0d91b8f9493424c9b098bc5c2a0762014e1c7abd Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 17 Oct 2019 10:41:07 -0400 Subject: [PATCH 048/297] Fix failing type check --- .../sections/actions_list/components/actions_list.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 17231626048288..327a8dfb800146 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -5,6 +5,7 @@ */ import React, { Fragment, useState, useEffect } from 'react'; +// @ts-ignore: EuiSearchBar not defined in TypeScript yet import { EuiPageContent, EuiBasicTable, EuiSpacer, EuiSearchBar, EuiButton } from '@elastic/eui'; import { capabilities } from 'ui/capabilities'; import { i18n } from '@kbn/i18n'; From bbb769002c3e9dd9971103c0b0d17bf24c869f45 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 17 Oct 2019 08:36:03 -0700 Subject: [PATCH 049/297] Did small fields refactoring for webhook and email forms fields --- .../constants/action_types_settings.ts | 24 ++++-- .../sections/action_add/action_add.tsx | 3 + .../action_fields/email_action_fields.tsx | 10 ++- .../action_fields/webhook_action_fields.tsx | 81 ++++++++++++++----- 4 files changed, 90 insertions(+), 28 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_types_settings.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_types_settings.ts index c14bb93dbf43fe..a334cd5fa3f365 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_types_settings.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_types_settings.ts @@ -202,27 +202,37 @@ export const actionTypesSettings = (val: string): ActionTypeSettings => { validate: (action: Action): any => { const validationResult = { errors: {} }; const errors = { - description: new Array(), + url: new Array(), + method: new Array(), + user: new Array(), + password: new Array(), }; validationResult.errors = errors; if (!action.config.url) { - errors.description.push( + errors.url.push( i18n.translate('xpack.alertingUI.sections.addAction.error.requiredUrlText', { defaultMessage: 'Url is required.', }) ); } if (!action.config.method) { - errors.description.push( + errors.method.push( i18n.translate('xpack.alertingUI.sections.addAction.error.requiredMethodText', { defaultMessage: 'Method is required.', }) ); } - if (!action.config.headers) { - errors.description.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHeadersText', { - defaultMessage: 'Headers is required.', + if (!action.secrets.user) { + errors.user.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHostText', { + defaultMessage: 'User is required.', + }) + ); + } + if (!action.secrets.password) { + errors.password.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHostText', { + defaultMessage: 'Password is required.', }) ); } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx index 6c27a0688d7e5a..cb66809f70f32d 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx @@ -200,6 +200,7 @@ export const ActionAdd = ({ actionType, refreshList }: Props) => { )} { errors={errors} > { }} /> + = ({ } )} > - = ({ return ( - + = ({ /> + + + { + editActionConfig('url', e.target.value); + }} + onBlur={() => { + if (!url) { + editActionConfig('url', ''); + } + }} + /> + + @@ -79,7 +105,7 @@ export const WebhookActionFields: React.FunctionComponent = ({ fullWidth name="user" value={user || ''} - data-test-subj="emailUserInput" + data-test-subj="webhookUserInput" onChange={e => { editActionSecrets('user', e.target.value); }} @@ -93,23 +119,20 @@ export const WebhookActionFields: React.FunctionComponent = ({ - { editActionSecrets('password', e.target.value); }} @@ -122,6 +145,26 @@ export const WebhookActionFields: React.FunctionComponent = ({ + + + + + { + editActionSecrets('headers', e.target.value); + }} + /> + ); }; From b80d51248b9dc60d6a8b5fd0121211d3c862c3b9 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 17 Oct 2019 12:22:37 -0400 Subject: [PATCH 050/297] Attempt to shim capabilities --- .../sections/actions_list/components/actions_list.tsx | 5 ++--- x-pack/legacy/plugins/alerting_ui/public/shim.ts | 5 +++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 327a8dfb800146..4024a1e3da989c 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -7,7 +7,6 @@ import React, { Fragment, useState, useEffect } from 'react'; // @ts-ignore: EuiSearchBar not defined in TypeScript yet import { EuiPageContent, EuiBasicTable, EuiSpacer, EuiSearchBar, EuiButton } from '@elastic/eui'; -import { capabilities } from 'ui/capabilities'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { PageError } from '../../../components/page_error'; @@ -25,12 +24,12 @@ interface Data extends Action { actionType: ActionType['name']; } -const canDelete = capabilities.get().actions.delete; - export const ActionsList: React.FunctionComponent = () => { const { core: { http }, + plugins: { capabilities }, } = useAppDependencies(); + const canDelete = capabilities.get().actions.delete; const [actionTypesIndex, setActionTypesIndex] = useState(undefined); const [actions, setActions] = useState([]); diff --git a/x-pack/legacy/plugins/alerting_ui/public/shim.ts b/x-pack/legacy/plugins/alerting_ui/public/shim.ts index ec12afd337e0dd..611a41fce641de 100644 --- a/x-pack/legacy/plugins/alerting_ui/public/shim.ts +++ b/x-pack/legacy/plugins/alerting_ui/public/shim.ts @@ -5,6 +5,7 @@ */ import { management, MANAGEMENT_BREADCRUMB } from 'ui/management'; +import { capabilities } from 'ui/capabilities'; import { CoreStart } from 'kibana/public'; export interface AppPlugins { @@ -13,6 +14,9 @@ export interface AppPlugins { getSection(): any; breadcrumb: any; }; + capabilities: { + get: () => any; + }; } export interface AppDependencies { @@ -28,6 +32,7 @@ export function createShim() { }, }, pluginsStart: { + capabilities, management: { breadcrumb: MANAGEMENT_BREADCRUMB, }, From 2afdbc0136e89e03d0bdfc983cf1165ed83177e0 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 17 Oct 2019 10:11:59 -0700 Subject: [PATCH 051/297] Moved action reducers to separate file --- .../sections/action_add/action_add.tsx | 68 ++----------- .../action_fields/webhook_action_fields.tsx | 18 ++-- .../sections/action_add/action_reducer.ts | 98 +++++++++++++++++++ 3 files changed, 114 insertions(+), 70 deletions(-) create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_reducer.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx index cb66809f70f32d..7879928dcdb051 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ import React, { Fragment, useContext, useState, useCallback, useReducer, useEffect } from 'react'; -import { isEqual } from 'lodash'; import { HttpServiceBase } from 'kibana/public'; import { toastNotifications } from 'ui/notify'; import { @@ -41,6 +40,7 @@ import { SectionError, ErrableFormRow } from '../../../application/components/pa import { actionTypesSettings, BUILDIN_ACTION_TYPES } from '../../constants/action_types_settings'; import { useAppDependencies } from '../..'; import { ActionModel } from '../../models/action'; +import { actionReducer } from './action_reducer'; const actionFieldsComponentMap = { [BUILDIN_ACTION_TYPES.LOGGING]: LoggingActionFields, @@ -56,67 +56,6 @@ interface Props { refreshList: () => void; } -const actionReducer = (state: any, actionItem: any) => { - const { command, payload } = actionItem; - const { action } = state; - - switch (command) { - case 'setAction': - return { - ...state, - action: payload, - }; - case 'setProperty': { - const { property, value } = payload; - if (isEqual(action[property], value)) { - return state; - } else { - return { - ...state, - action: new ActionModel({ - ...action, - [property]: value, - }), - }; - } - } - case 'setConfigProperty': { - const { property, value } = payload; - if (isEqual(action.config[property], value)) { - return state; - } else { - return { - ...state, - action: new ActionModel({ - ...action, - config: { - ...action.config, - [property]: value, - }, - }), - }; - } - } - case 'setSecretsProperty': { - const { property, value } = payload; - if (isEqual(action.secrets[property], value)) { - return state; - } else { - return { - ...state, - action: new ActionModel({ - ...action, - secrets: { - ...action.secrets, - [property]: value, - }, - }), - }; - } - } - } -}; - export const ActionAdd = ({ actionType, refreshList }: Props) => { const { core: { http }, @@ -135,6 +74,10 @@ export const ActionAdd = ({ actionType, refreshList }: Props) => { dispatch({ command: 'setConfigProperty', payload: { property, value } }); }; + const editActionJSONConfig = (property: string, value: any) => { + dispatch({ command: 'setConfigJSONProperty', payload: { property, value } }); + }; + const setActionSecretsProperty = (property: string, value: any) => { dispatch({ command: 'setSecretsProperty', payload: { property, value } }); }; @@ -232,6 +175,7 @@ export const ActionAdd = ({ actionType, refreshList }: Props) => { errors={errors} editActionConfig={setActionConfigProperty} editActionSecrets={setActionSecretsProperty} + editActionJSONConfig={editActionJSONConfig} hasErrors={hasErrors} > {actionType.id === null ? ( diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx index dc3e7204f6253e..4da69de9480532 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx @@ -3,11 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, useEffect } from 'react'; +import React, { Fragment } from 'react'; import { - EuiCodeEditor, - EuiFieldNumber, EuiFieldPassword, EuiFieldText, EuiFormRow, @@ -15,7 +13,8 @@ import { EuiFlexGroup, EuiFlexItem, EuiSpacer, - EuiBasicTable, + EuiCodeEditor, + EuiTextArea, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ErrableFormRow } from '../../../components/page_error'; @@ -24,6 +23,7 @@ import { Action } from '../../../lib/api'; interface Props { action: Action; editActionConfig: (property: string, value: any) => void; + editActionJSONConfig: (property: string, value: any) => void; editActionSecrets: (property: string, value: any) => void; errors: { [key: string]: string[] }; hasErrors: boolean; @@ -34,12 +34,14 @@ const HTTP_VERBS = ['post', 'put']; export const WebhookActionFields: React.FunctionComponent = ({ action, editActionConfig, + editActionJSONConfig, editActionSecrets, errors, hasErrors, }) => { const { user, password }: any = action.secrets; const { method, url, headers }: any = action.config; + editActionConfig('method', 'post'); // set method to POST by default return ( @@ -155,13 +157,13 @@ export const WebhookActionFields: React.FunctionComponent = ({ })} fullWidth > - { - editActionSecrets('headers', e.target.value); + editActionJSONConfig('headers', e.target.value); }} /> diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_reducer.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_reducer.ts new file mode 100644 index 00000000000000..fd158bc94a66e6 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_reducer.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 { isEqual } from 'lodash'; +import { ActionModel } from '../../models/action'; + +export const actionReducer = (state: any, actionItem: any) => { + const { command, payload } = actionItem; + const { action } = state; + + switch (command) { + case 'setAction': + return { + ...state, + action: payload, + }; + case 'setProperty': { + const { property, value } = payload; + if (isEqual(action[property], value)) { + return state; + } else { + return { + ...state, + action: new ActionModel({ + ...action, + [property]: value, + }), + }; + } + } + case 'setConfigProperty': { + const { property, value } = payload; + if (isEqual(action.config[property], value)) { + return state; + } else { + return { + ...state, + action: new ActionModel({ + ...action, + config: { + ...action.config, + [property]: value, + }, + }), + }; + } + } + case 'setConfigJSONProperty': { + const { property, value } = payload; + if (isEqual(action.config[property], value)) { + return state; + } else { + try { + return { + ...state, + action: new ActionModel({ + ...action, + config: { + ...action.config, + [property]: JSON.parse(value), + }, + }), + }; + } catch { + return { + ...state, + action: new ActionModel({ + ...action, + config: { + ...action.config, + [property]: value, + }, + }), + }; + } + } + } + case 'setSecretsProperty': { + const { property, value } = payload; + if (isEqual(action.secrets[property], value)) { + return state; + } else { + return { + ...state, + action: new ActionModel({ + ...action, + secrets: { + ...action.secrets, + [property]: value, + }, + }), + }; + } + } + } +}; From 7c063af06d6b345d616272d89aad7c23895fcc3f Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 17 Oct 2019 21:10:58 -0700 Subject: [PATCH 052/297] Implemented form control for action Webhook headers adding --- .../sections/action_add/action_add.tsx | 5 - .../action_fields/webhook_action_fields.tsx | 144 +++++++++++++++--- .../sections/action_add/action_reducer.ts | 30 ---- 3 files changed, 123 insertions(+), 56 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx index 7879928dcdb051..5ea78f079cbe24 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx @@ -74,10 +74,6 @@ export const ActionAdd = ({ actionType, refreshList }: Props) => { dispatch({ command: 'setConfigProperty', payload: { property, value } }); }; - const editActionJSONConfig = (property: string, value: any) => { - dispatch({ command: 'setConfigJSONProperty', payload: { property, value } }); - }; - const setActionSecretsProperty = (property: string, value: any) => { dispatch({ command: 'setSecretsProperty', payload: { property, value } }); }; @@ -175,7 +171,6 @@ export const ActionAdd = ({ actionType, refreshList }: Props) => { errors={errors} editActionConfig={setActionConfigProperty} editActionSecrets={setActionSecretsProperty} - editActionJSONConfig={editActionJSONConfig} hasErrors={hasErrors} > {actionType.id === null ? ( diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx index 4da69de9480532..67dcd88d6a6ffa 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment } from 'react'; +import React, { Fragment, useState } from 'react'; import { EuiFieldPassword, @@ -13,8 +13,9 @@ import { EuiFlexGroup, EuiFlexItem, EuiSpacer, - EuiCodeEditor, - EuiTextArea, + EuiButton, + EuiButtonIcon, + EuiText, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ErrableFormRow } from '../../../components/page_error'; @@ -23,7 +24,6 @@ import { Action } from '../../../lib/api'; interface Props { action: Action; editActionConfig: (property: string, value: any) => void; - editActionJSONConfig: (property: string, value: any) => void; editActionSecrets: (property: string, value: any) => void; errors: { [key: string]: string[] }; hasErrors: boolean; @@ -34,15 +34,60 @@ const HTTP_VERBS = ['post', 'put']; export const WebhookActionFields: React.FunctionComponent = ({ action, editActionConfig, - editActionJSONConfig, editActionSecrets, errors, hasErrors, }) => { + const [headerKey, setHeaderKey] = useState(''); + const [headerValue, setHeaderValue] = useState(''); + const { user, password }: any = action.secrets; const { method, url, headers }: any = action.config; + editActionConfig('method', 'post'); // set method to POST by default + const headerErrors = { + keyHeader: new Array(), + valueHeader: new Array(), + }; + if (!headerKey && headerValue) { + headerErrors.keyHeader.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHeaderKeyText', { + defaultMessage: 'Header Key is required.', + }) + ); + } + if (headerKey && !headerValue) { + headerErrors.valueHeader.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHeaderValueText', { + defaultMessage: 'Header Value is required.', + }) + ); + } + const hasHeaderErrors = headerErrors.keyHeader.length > 0 || headerErrors.valueHeader.length > 0; + + function addHeader() { + if (headers && !!Object.keys(headers).find(key => key === headerKey)) { + return; + } + const updatedHeaders = headers + ? { ...headers, [headerKey]: headerValue } + : { [headerKey]: headerValue }; + editActionConfig('headers', updatedHeaders); + setHeaderKey(''); + setHeaderValue(''); + } + + function removeHeader(objKey: string) { + const updatedHeaders = Object.keys(headers) + .filter(key => key !== objKey) + .reduce((obj: any, key: string) => { + obj[key] = headers[key]; + return obj; + }, {}); + editActionConfig('headers', updatedHeaders); + } + return ( @@ -150,23 +195,80 @@ export const WebhookActionFields: React.FunctionComponent = ({ - + + + { + setHeaderKey(e.target.value); + }} + /> + + + + + { + setHeaderValue(e.target.value); + }} + /> + + + + + addHeader()} > - { - editActionJSONConfig('headers', e.target.value); - }} - /> - + {i18n.translate('xpack.alertingUI.sections.webhookHeaders.AddHeaderButton', { + defaultMessage: 'Add header', + })} + + + + {Object.keys(headers || {}).map((key: string) => { + return ( + + + {key}: + + + {headers[key]} + + + removeHeader(key)} /> + + + ); + })} + ); }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_reducer.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_reducer.ts index fd158bc94a66e6..d9783beb156053 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_reducer.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_reducer.ts @@ -47,36 +47,6 @@ export const actionReducer = (state: any, actionItem: any) => { }; } } - case 'setConfigJSONProperty': { - const { property, value } = payload; - if (isEqual(action.config[property], value)) { - return state; - } else { - try { - return { - ...state, - action: new ActionModel({ - ...action, - config: { - ...action.config, - [property]: JSON.parse(value), - }, - }), - }; - } catch { - return { - ...state, - action: new ActionModel({ - ...action, - config: { - ...action.config, - [property]: value, - }, - }), - }; - } - } - } case 'setSecretsProperty': { const { property, value } = payload; if (isEqual(action.secrets[property], value)) { From dc8b13a21c72fed34b1a768445bacb7a59aaa2fa Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 18 Oct 2019 08:59:53 -0400 Subject: [PATCH 053/297] Use proper TypeScript types for AppPlugins --- x-pack/legacy/plugins/alerting_ui/public/shim.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/public/shim.ts b/x-pack/legacy/plugins/alerting_ui/public/shim.ts index 611a41fce641de..3621be8ba01760 100644 --- a/x-pack/legacy/plugins/alerting_ui/public/shim.ts +++ b/x-pack/legacy/plugins/alerting_ui/public/shim.ts @@ -10,13 +10,9 @@ import { CoreStart } from 'kibana/public'; export interface AppPlugins { management: { - sections: typeof management; - getSection(): any; - breadcrumb: any; - }; - capabilities: { - get: () => any; + breadcrumb: typeof MANAGEMENT_BREADCRUMB; }; + capabilities: typeof capabilities; } export interface AppDependencies { From 4318d9a8c3b5fcd743628b65ce56a8ea362513fb Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 18 Oct 2019 09:07:42 -0400 Subject: [PATCH 054/297] Remove text service --- .../public/application/lib/breadcrumb.ts | 10 +++++--- .../public/application/lib/doc_title.ts | 18 +++++++++---- .../public/application/lib/text/index.ts | 7 ------ .../public/application/lib/text/text.ts | 25 ------------------- .../alerting_ui/np_ready/public/plugin.ts | 2 -- 5 files changed, 20 insertions(+), 42 deletions(-) delete mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/text/index.ts delete mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/text/text.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts index d71a5e434e33dd..c93085ef1fca32 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { textService } from './text'; +import { i18n } from '@kbn/i18n'; import { linkToHome, linkToActions } from '../constants'; class BreadcrumbService { @@ -28,14 +28,18 @@ class BreadcrumbService { this.breadcrumbs.home = [ ...this.breadcrumbs.management, { - text: textService.breadcrumbs.home, + text: i18n.translate('xpack.alertingUI.home.breadcrumbTitle', { + defaultMessage: 'Alerting UI', + }), href: linkToHome(), }, ]; this.breadcrumbs.actions = [ ...this.breadcrumbs.home, { - text: textService.breadcrumbs.actions, + text: i18n.translate('xpack.alertingUI.actions.breadcrumbTitle', { + defaultMessage: 'Actions', + }), href: linkToActions(), }, ]; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/doc_title.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/doc_title.ts index d5082699d5e9a0..8cb8a3189432e4 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/doc_title.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/doc_title.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { textService } from './text'; +import { i18n } from '@kbn/i18n'; class DocTitleService { private changeDocTitle: any = () => {}; @@ -13,11 +13,19 @@ class DocTitleService { } public setTitle(page?: string): void { - if (!page || page === 'home') { - this.changeDocTitle(`${textService.breadcrumbs.home}`); - } else if (textService.breadcrumbs[page]) { - this.changeDocTitle(`${textService.breadcrumbs[page]} - ${textService.breadcrumbs.home}`); + let updatedTitle = i18n.translate('xpack.alertingUI.home.breadcrumbTitle', { + defaultMessage: 'Alerting UI', + }); + + switch (page) { + case 'actions': + updatedTitle = i18n.translate('xpack.alertingUI.actions.breadcrumbTitle', { + defaultMessage: 'Actions', + }); + break; } + + this.changeDocTitle(updatedTitle); } } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/text/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/text/index.ts deleted file mode 100644 index 3bed86f69937ac..00000000000000 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/text/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -export { textService } from './text'; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/text/text.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/text/text.ts deleted file mode 100644 index 76a39a327a4f23..00000000000000 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/text/text.ts +++ /dev/null @@ -1,25 +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. - */ - -class TextService { - public breadcrumbs: { [key: string]: string } = {}; - public i18n: any; - - public init(i18n: any): void { - this.i18n = i18n; - - this.breadcrumbs = { - home: i18n.translate('xpack.alertingUI.home.breadcrumbTitle', { - defaultMessage: 'Alerting UI', - }), - actions: i18n.translate('xpack.alertingUI.actions.breadcrumbTitle', { - defaultMessage: 'Actions', - }), - }; - } -} - -export const textService = new TextService(); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts index 7945d0a39c97fb..959ba88a7985b0 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts @@ -13,7 +13,6 @@ import template from '../../public/index.html'; import { renderReact } from './application'; import { BASE_PATH } from './application/constants'; import { breadcrumbService } from './application/lib/breadcrumb'; -import { textService } from './application/lib/text'; export type Setup = void; export type Start = void; @@ -45,7 +44,6 @@ export class ActionsPlugin implements Plugin { } public start(core: CoreStart, plugins: any) { - textService.init(i18n); breadcrumbService.init(core.chrome, plugins.management.breadcrumb); const unmountReactApp = (): void => { From 697339e1246863ff67f8a01b9e2ebb71aa7d322d Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 18 Oct 2019 09:09:32 -0400 Subject: [PATCH 055/297] Remove functions from constants file --- .../np_ready/public/application/constants/index.ts | 9 ++------- .../np_ready/public/application/lib/breadcrumb.ts | 4 ++-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts index f16c921e07888c..1714e02c0bedc6 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts @@ -10,10 +10,5 @@ export const BASE_ACTION_API_PATH = '../api/action'; export const DEFAULT_SECTION: Section = 'actions'; export type Section = 'actions'; -export function linkToHome() { - return `#${BASE_PATH}`; -} - -export function linkToActions() { - return `#${BASE_PATH}/actions`; -} +export const linkToHome = `#${BASE_PATH}`; +export const linkToActions = `#${BASE_PATH}/actions`; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts index c93085ef1fca32..4016fd44d795d8 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts @@ -31,7 +31,7 @@ class BreadcrumbService { text: i18n.translate('xpack.alertingUI.home.breadcrumbTitle', { defaultMessage: 'Alerting UI', }), - href: linkToHome(), + href: linkToHome, }, ]; this.breadcrumbs.actions = [ @@ -40,7 +40,7 @@ class BreadcrumbService { text: i18n.translate('xpack.alertingUI.actions.breadcrumbTitle', { defaultMessage: 'Actions', }), - href: linkToActions(), + href: linkToActions, }, ]; } From 1d271ba558a229d3644ac9bfac443f5b925fbef1 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 18 Oct 2019 09:27:30 -0400 Subject: [PATCH 056/297] Single source for routes --- .../np_ready/public/application/constants/index.ts | 4 ++-- .../alerting_ui/np_ready/public/application/home.tsx | 4 ++-- .../np_ready/public/application/lib/breadcrumb.ts | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts index 1714e02c0bedc6..7c92d0b79686d6 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts @@ -10,5 +10,5 @@ export const BASE_ACTION_API_PATH = '../api/action'; export const DEFAULT_SECTION: Section = 'actions'; export type Section = 'actions'; -export const linkToHome = `#${BASE_PATH}`; -export const linkToActions = `#${BASE_PATH}/actions`; +export const routeToHome = `${BASE_PATH}`; +export const routeToActions = `${BASE_PATH}/actions`; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx index 71d03208fdce9d..a11004466dd629 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx @@ -8,7 +8,7 @@ import React, { useEffect } from 'react'; import { Route, RouteComponentProps, Switch } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiPageBody, EuiPageContent, EuiSpacer, EuiTab, EuiTabs } from '@elastic/eui'; -import { BASE_PATH, Section } from '../../../np_ready/public/application/constants'; +import { BASE_PATH, Section, routeToActions } from '../../../np_ready/public/application/constants'; import { breadcrumbService } from './lib/breadcrumb'; import { docTitleService } from './lib/doc_title'; @@ -68,7 +68,7 @@ export const AlertsUIHome: React.FunctionComponent - + diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts index 4016fd44d795d8..df06fdace62a4b 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts @@ -5,7 +5,7 @@ */ import { i18n } from '@kbn/i18n'; -import { linkToHome, linkToActions } from '../constants'; +import { routeToHome, routeToActions } from '../constants'; class BreadcrumbService { private chrome: any; @@ -31,7 +31,7 @@ class BreadcrumbService { text: i18n.translate('xpack.alertingUI.home.breadcrumbTitle', { defaultMessage: 'Alerting UI', }), - href: linkToHome, + href: `#${routeToHome}`, }, ]; this.breadcrumbs.actions = [ @@ -40,7 +40,7 @@ class BreadcrumbService { text: i18n.translate('xpack.alertingUI.actions.breadcrumbTitle', { defaultMessage: 'Actions', }), - href: linkToActions, + href: `#${routeToActions}`, }, ]; } From 6a3417f6ca56b4c928a9c559f8f7ffa93ddb9211 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 18 Oct 2019 09:47:37 -0400 Subject: [PATCH 057/297] Use toast notifications --- .../actions_list/components/actions_list.tsx | 42 +++++++------------ .../legacy/plugins/alerting_ui/public/shim.ts | 3 ++ 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 4024a1e3da989c..10884531404547 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -9,7 +9,6 @@ import React, { Fragment, useState, useEffect } from 'react'; import { EuiPageContent, EuiBasicTable, EuiSpacer, EuiSearchBar, EuiButton } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { PageError } from '../../../components/page_error'; import { Action, ActionType, deleteActions, loadActions, loadActionTypes } from '../../../lib/api'; import { ActionsContext } from '../../../context/app_context'; import { useAppDependencies } from '../../../index'; @@ -27,7 +26,7 @@ interface Data extends Action { export const ActionsList: React.FunctionComponent = () => { const { core: { http }, - plugins: { capabilities }, + plugins: { capabilities, toastNotifications }, } = useAppDependencies(); const canDelete = capabilities.get().actions.delete; @@ -38,7 +37,6 @@ export const ActionsList: React.FunctionComponent = () => { const [isLoadingActionTypes, setIsLoadingActionTypes] = useState(false); const [isLoadingActions, setIsLoadingActions] = useState(false); const [isDeletingActions, setIsDeletingActions] = useState(false); - const [errorCode, setErrorCode] = useState(null); const [totalItemCount, setTotalItemCount] = useState(0); const [page, setPage] = useState({ index: 0, size: 10 }); const [searchText, setSearchText] = useState(undefined); @@ -58,7 +56,12 @@ export const ActionsList: React.FunctionComponent = () => { } setActionTypesIndex(index); } catch (e) { - setErrorCode(e.response.status); + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.alertingUI.sections.actionsList.unableToLoadActionTypesMessage', + { defaultMessage: 'Unable to load action types' } + ), + }); } finally { setIsLoadingActionTypes(false); } @@ -83,13 +86,16 @@ export const ActionsList: React.FunctionComponent = () => { async function loadActionsTable() { setIsLoadingActions(true); - setErrorCode(null); try { const actionsResponse = await loadActions({ http, page, searchText }); setActions(actionsResponse.data); setTotalItemCount(actionsResponse.total); } catch (e) { - setErrorCode(e.response.status); + toastNotifications.addDanger({ + title: i18n.translate('xpack.alertingUI.sections.actionsList.unableToLoadActionsMessage', { + defaultMessage: 'Unable to load actions', + }), + }); } finally { setIsLoadingActions(false); } @@ -167,17 +173,10 @@ export const ActionsList: React.FunctionComponent = () => { }, ]; - let content; - - if (errorCode) { - content = ( - - - - ); - } else { - content = ( - + return ( +
+ + setSearchText(queryText)} filters={[ @@ -250,15 +249,6 @@ export const ActionsList: React.FunctionComponent = () => { }, }} /> - - ); - } - - return ( -
- - - {content}
); diff --git a/x-pack/legacy/plugins/alerting_ui/public/shim.ts b/x-pack/legacy/plugins/alerting_ui/public/shim.ts index 3621be8ba01760..acbece454e4b3a 100644 --- a/x-pack/legacy/plugins/alerting_ui/public/shim.ts +++ b/x-pack/legacy/plugins/alerting_ui/public/shim.ts @@ -7,12 +7,14 @@ import { management, MANAGEMENT_BREADCRUMB } from 'ui/management'; import { capabilities } from 'ui/capabilities'; import { CoreStart } from 'kibana/public'; +import { toastNotifications } from 'ui/notify'; export interface AppPlugins { management: { breadcrumb: typeof MANAGEMENT_BREADCRUMB; }; capabilities: typeof capabilities; + toastNotifications: typeof toastNotifications; } export interface AppDependencies { @@ -29,6 +31,7 @@ export function createShim() { }, pluginsStart: { capabilities, + toastNotifications, management: { breadcrumb: MANAGEMENT_BREADCRUMB, }, From 36c280d0aaf480e90592abadf239e6fcb1af3ce3 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 18 Oct 2019 10:12:26 -0400 Subject: [PATCH 058/297] Don't render management tab when no access, remove routes, remove sub tabs --- .../np_ready/public/application/home.tsx | 18 ++++++++---- .../alerting_ui/np_ready/public/plugin.ts | 28 +++++++++++++------ .../legacy/plugins/alerting_ui/public/shim.ts | 1 + 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx index a11004466dd629..9c4b59bb29a942 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx @@ -11,6 +11,7 @@ import { EuiPageBody, EuiPageContent, EuiSpacer, EuiTab, EuiTabs } from '@elasti import { BASE_PATH, Section, routeToActions } from '../../../np_ready/public/application/constants'; import { breadcrumbService } from './lib/breadcrumb'; import { docTitleService } from './lib/doc_title'; +import { useAppDependencies } from './index'; import { ActionsList } from './sections/actions_list/components/actions_list'; @@ -24,11 +25,18 @@ export const AlertsUIHome: React.FunctionComponent { + const { + plugins: { capabilities }, + } = useAppDependencies(); + + const canShowActions = capabilities.get().actions.show; const tabs: Array<{ id: Section; name: React.ReactNode; - }> = [ - { + }> = []; + + if (canShowActions) { + tabs.push({ id: 'actions', name: ( ), - }, - ]; + }); + } const onSectionChange = (newSection: Section) => { history.push(`${BASE_PATH}/${newSection}`); @@ -68,7 +76,7 @@ export const AlertsUIHome: React.FunctionComponent - + {canShowActions && } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts index 959ba88a7985b0..8a16a473a75e55 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts @@ -30,20 +30,32 @@ export class ActionsPlugin implements Plugin { } */ const { + capabilities, management: { getSection }, } = plugins; - const kbnSection = getSection('kibana'); - kbnSection.register('alerting', { - display: i18n.translate('xpack.alertingUI.managementSection.displayName', { - defaultMessage: 'Alerting', - }), - order: 7, - url: `#${BASE_PATH}`, - }); + const canShowActions = capabilities.get().actions.show; + if (canShowActions) { + const kbnSection = getSection('kibana'); + kbnSection.register('alerting', { + display: i18n.translate('xpack.alertingUI.managementSection.displayName', { + defaultMessage: 'Alerting', + }), + order: 7, + url: `#${BASE_PATH}`, + }); + } } public start(core: CoreStart, plugins: any) { + const { capabilities } = plugins; + const canShowActions = capabilities.get().actions.show; + + // Don't register routes when user doesn't have access to the application + if (!canShowActions) { + return; + } + breadcrumbService.init(core.chrome, plugins.management.breadcrumb); const unmountReactApp = (): void => { diff --git a/x-pack/legacy/plugins/alerting_ui/public/shim.ts b/x-pack/legacy/plugins/alerting_ui/public/shim.ts index acbece454e4b3a..0b4e34f0298b8e 100644 --- a/x-pack/legacy/plugins/alerting_ui/public/shim.ts +++ b/x-pack/legacy/plugins/alerting_ui/public/shim.ts @@ -25,6 +25,7 @@ export interface AppDependencies { export function createShim() { return { pluginsSetup: { + capabilities, management: { getSection: management.getSection.bind(management), }, From 3cc37841a4b08ef7653ca75f5098177f9a52256f Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 18 Oct 2019 10:17:06 -0400 Subject: [PATCH 059/297] Fix doc title stuff --- x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts | 2 ++ x-pack/legacy/plugins/alerting_ui/public/shim.ts | 3 +++ 2 files changed, 5 insertions(+) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts index 8a16a473a75e55..eebf20592bfb0d 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts @@ -13,6 +13,7 @@ import template from '../../public/index.html'; import { renderReact } from './application'; import { BASE_PATH } from './application/constants'; import { breadcrumbService } from './application/lib/breadcrumb'; +import { docTitleService } from './application/lib/doc_title'; export type Setup = void; export type Start = void; @@ -56,6 +57,7 @@ export class ActionsPlugin implements Plugin { return; } + docTitleService.init(plugins.docTitle.change); breadcrumbService.init(core.chrome, plugins.management.breadcrumb); const unmountReactApp = (): void => { diff --git a/x-pack/legacy/plugins/alerting_ui/public/shim.ts b/x-pack/legacy/plugins/alerting_ui/public/shim.ts index 0b4e34f0298b8e..610623784ad03d 100644 --- a/x-pack/legacy/plugins/alerting_ui/public/shim.ts +++ b/x-pack/legacy/plugins/alerting_ui/public/shim.ts @@ -8,6 +8,7 @@ import { management, MANAGEMENT_BREADCRUMB } from 'ui/management'; import { capabilities } from 'ui/capabilities'; import { CoreStart } from 'kibana/public'; import { toastNotifications } from 'ui/notify'; +import { docTitle } from 'ui/doc_title/doc_title'; export interface AppPlugins { management: { @@ -15,6 +16,7 @@ export interface AppPlugins { }; capabilities: typeof capabilities; toastNotifications: typeof toastNotifications; + docTitle: typeof docTitle; } export interface AppDependencies { @@ -31,6 +33,7 @@ export function createShim() { }, }, pluginsStart: { + docTitle, capabilities, toastNotifications, management: { From bd486e0767f352b8d0697399133df3aadd3b37e3 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 18 Oct 2019 10:37:31 -0400 Subject: [PATCH 060/297] Fix import path --- .../plugins/alerting_ui/np_ready/public/application/home.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx index 9c4b59bb29a942..ef05a0fb358e42 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx @@ -8,7 +8,7 @@ import React, { useEffect } from 'react'; import { Route, RouteComponentProps, Switch } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiPageBody, EuiPageContent, EuiSpacer, EuiTab, EuiTabs } from '@elastic/eui'; -import { BASE_PATH, Section, routeToActions } from '../../../np_ready/public/application/constants'; +import { BASE_PATH, Section, routeToActions } from './constants'; import { breadcrumbService } from './lib/breadcrumb'; import { docTitleService } from './lib/doc_title'; import { useAppDependencies } from './index'; From f31d052706bf5134dd48da647ea6ab6bc963eb97 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 18 Oct 2019 10:40:01 -0400 Subject: [PATCH 061/297] Sort action types alphabetically --- .../actions_list/components/actions_list.tsx | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 10884531404547..1ab024bc8e8557 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -187,10 +187,16 @@ export const ActionsList: React.FunctionComponent = () => { defaultMessage: 'Type', }), multiSelect: 'or', - options: Object.values(actionTypesIndex || {}).map(actionType => ({ - value: actionType.id, - name: actionType.name, - })), + options: Object.values(actionTypesIndex || {}) + .map(actionType => ({ + value: actionType.id, + name: actionType.name, + })) + .sort((a, b) => { + if (a.name < b.name) return -1; + if (a.name > b.name) return 1; + return 0; + }), }, ]} toolsRight={[ From 70e86061212ecae38b801644dbb2a31dfd7d1e4f Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 18 Oct 2019 12:41:07 -0400 Subject: [PATCH 062/297] PR feedback pt1 --- x-pack/legacy/plugins/alerting_ui/index.ts | 5 +---- x-pack/legacy/plugins/alerting_ui/np_ready/kibana.json | 2 +- .../np_ready/public/application/constants/index.ts | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/index.ts b/x-pack/legacy/plugins/alerting_ui/index.ts index 3bf4c22b4ba6fe..49e76764eb1382 100644 --- a/x-pack/legacy/plugins/alerting_ui/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/index.ts @@ -15,10 +15,7 @@ export function alertingUI(kibana: any) { publicDir: resolve(__dirname, 'public'), require: ['kibana', 'actions'], isEnabled(config: Legacy.KibanaConfig) { - return ( - config.get('xpack.alerting_ui.enabled') === true && - config.get('xpack.actions.enabled') === true - ); + return config.get('xpack.alerting_ui.enabled') && config.get('xpack.actions.enabled'); }, config(Joi: Root) { return Joi.object() diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/kibana.json b/x-pack/legacy/plugins/alerting_ui/np_ready/kibana.json index db2848601f6980..e2a710ac343834 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/kibana.json +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/kibana.json @@ -1,5 +1,5 @@ { - "id": "alertingUI", + "id": "alerting_ui", "version": "kibana", "server": false, "ui": true diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts index 7c92d0b79686d6..baf7c50866c941 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts @@ -5,7 +5,7 @@ */ export const BASE_PATH = '/management/kibana/alerting'; -export const BASE_ACTION_API_PATH = '../api/action'; +export const BASE_ACTION_API_PATH = '/api/action'; export const DEFAULT_SECTION: Section = 'actions'; export type Section = 'actions'; From aca85c51ad563ec12e1670d78a8a46dbad07cae3 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 18 Oct 2019 12:48:35 -0400 Subject: [PATCH 063/297] Remove content wrapper --- .../actions_list/components/actions_list.tsx | 165 +++++++++--------- 1 file changed, 79 insertions(+), 86 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 1ab024bc8e8557..227998c4771a6c 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -175,96 +175,89 @@ export const ActionsList: React.FunctionComponent = () => { return (
- + - setSearchText(queryText)} - filters={[ - { - type: 'field_value_selection', - field: 'type', - name: i18n.translate('xpack.alertingUI.sections.actionsList.filters.typeName', { - defaultMessage: 'Type', - }), - multiSelect: 'or', - options: Object.values(actionTypesIndex || {}) - .map(actionType => ({ - value: actionType.id, - name: actionType.name, - })) - .sort((a, b) => { - if (a.name < b.name) return -1; - if (a.name > b.name) return 1; - return 0; + + setSearchText(queryText)} + filters={[ + { + type: 'field_value_selection', + field: 'type', + name: i18n.translate('xpack.alertingUI.sections.actionsList.filters.typeName', { + defaultMessage: 'Type', }), - }, - ]} - toolsRight={[ - - - , - , - ]} - > + multiSelect: 'or', + options: Object.values(actionTypesIndex || {}) + .map(actionType => ({ + value: actionType.id, + name: actionType.name, + })) + .sort((a, b) => { + if (a.name < b.name) return -1; + if (a.name > b.name) return 1; + return 0; + }), + }, + ]} + toolsRight={[ + + + , + , + ]} + > - + - ({ - 'data-test-subj': 'row', - })} - cellProps={() => ({ - 'data-test-subj': 'cell', - })} - data-test-subj="actionsTable" - pagination={{ - pageIndex: page.index, - pageSize: page.size, - totalItemCount, - }} - onChange={({ page: changedPage }: { page: Pagination }) => { - setPage(changedPage); - }} - selection={{ - onSelectionChange(updatedSelectedItemsList: Data[]) { - setSelectedItems(updatedSelectedItemsList); - }, - }} - /> - + ({ + 'data-test-subj': 'row', + })} + cellProps={() => ({ + 'data-test-subj': 'cell', + })} + data-test-subj="actionsTable" + pagination={{ + pageIndex: page.index, + pageSize: page.size, + totalItemCount, + }} + onChange={({ page: changedPage }: { page: Pagination }) => { + setPage(changedPage); + }} + selection={{ + onSelectionChange(updatedSelectedItemsList: Data[]) { + setSelectedItems(updatedSelectedItemsList); + }, + }} + /> + +
); }; - -export const ContentWrapper = ({ children }: { children: React.ReactNode }) => { - return ( - - - {children} - - ); -}; From afffcf36905e7b34ebfa5188a367e19a5896541d Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 18 Oct 2019 14:37:47 -0400 Subject: [PATCH 064/297] Switch to in memory table --- .../np_ready/public/application/lib/api.ts | 18 +- .../actions_list/components/actions_list.tsx | 163 +++++++++--------- 2 files changed, 90 insertions(+), 91 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index ba9572a50771b4..ec00f6eaf6bab8 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -6,6 +6,11 @@ import { HttpServiceBase } from 'kibana/public'; import { BASE_ACTION_API_PATH } from '../constants'; +// We are assuming there won't be many actions. This is why we will load +// all the actions in advance and assume the total count to not go over 100 or so. +// We'll set this max setting assuming it's never reached. +const MAX_ACTIONS_RETURNED = 10000; + export interface ActionType { id: string; name: string; @@ -32,8 +37,6 @@ export async function loadActionTypes({ export interface LoadActionsOpts { http: HttpServiceBase; - page: { index: number; size: number }; - searchText?: string; } export interface LoadActionsResponse { @@ -43,17 +46,10 @@ export interface LoadActionsResponse { data: Action[]; } -export async function loadActions({ - http, - page, - searchText, -}: LoadActionsOpts): Promise { +export async function loadAllActions({ http }: LoadActionsOpts): Promise { return http.get(`${BASE_ACTION_API_PATH}/_find`, { query: { - page: page.index + 1, - per_page: page.size, - search_fields: searchText ? 'description' : undefined, - search: searchText, + per_page: MAX_ACTIONS_RETURNED, }, }); } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 227998c4771a6c..4320b8d7d1eb58 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -6,19 +6,21 @@ import React, { Fragment, useState, useEffect } from 'react'; // @ts-ignore: EuiSearchBar not defined in TypeScript yet -import { EuiPageContent, EuiBasicTable, EuiSpacer, EuiSearchBar, EuiButton } from '@elastic/eui'; +import { EuiPageContent, EuiInMemoryTable, EuiSpacer, EuiSearchBar, EuiButton } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { Action, ActionType, deleteActions, loadActions, loadActionTypes } from '../../../lib/api'; import { ActionsContext } from '../../../context/app_context'; import { useAppDependencies } from '../../../index'; import { AlertingActionsDropdown } from './create_menu_popover'; +import { + Action, + ActionType, + deleteActions, + loadAllActions, + loadActionTypes, +} from '../../../lib/api'; type ActionTypeIndex = Record; -interface Pagination { - index: number; - size: number; -} interface Data extends Action { actionType: ActionType['name']; } @@ -37,13 +39,10 @@ export const ActionsList: React.FunctionComponent = () => { const [isLoadingActionTypes, setIsLoadingActionTypes] = useState(false); const [isLoadingActions, setIsLoadingActions] = useState(false); const [isDeletingActions, setIsDeletingActions] = useState(false); - const [totalItemCount, setTotalItemCount] = useState(0); - const [page, setPage] = useState({ index: 0, size: 10 }); - const [searchText, setSearchText] = useState(undefined); useEffect(() => { - loadActionsTable(); - }, [page, searchText]); + loadActions(); + }, []); useEffect(() => { (async () => { @@ -84,12 +83,11 @@ export const ActionsList: React.FunctionComponent = () => { setData(updatedData); }, [actions, actionTypesIndex]); - async function loadActionsTable() { + async function loadActions() { setIsLoadingActions(true); try { - const actionsResponse = await loadActions({ http, page, searchText }); + const actionsResponse = await loadAllActions({ http }); setActions(actionsResponse.data); - setTotalItemCount(actionsResponse.total); } catch (e) { toastNotifications.addDanger({ title: i18n.translate('xpack.alertingUI.sections.actionsList.unableToLoadActionsMessage', { @@ -103,9 +101,23 @@ export const ActionsList: React.FunctionComponent = () => { async function deleteItems(items: Data[]) { setIsDeletingActions(true); - await deleteActions({ http, ids: items.map(item => item.id) }); - await loadActionsTable(); - setIsDeletingActions(false); + const ids = items.map(item => item.id); + try { + await deleteActions({ http, ids }); + const updatedActions = actions.filter(action => !ids.includes(action.id)); + setActions(updatedActions); + } catch (e) { + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.alertingUI.sections.actionsList.failedToDeleteActionsMessage', + { defaultMessage: 'Failed to delete action(s)' } + ), + }); + // Refresh the actions from the server, some actions may have beend eleted + loadActions(); + } finally { + setIsDeletingActions(false); + } } async function deleteSelectedItems() { @@ -121,7 +133,7 @@ export const ActionsList: React.FunctionComponent = () => { defaultMessage: 'Description', } ), - sortable: false, + sortable: true, truncateText: true, }, { @@ -132,7 +144,7 @@ export const ActionsList: React.FunctionComponent = () => { defaultMessage: 'Action Type', } ), - sortable: false, + sortable: true, truncateText: true, }, { @@ -178,61 +190,10 @@ export const ActionsList: React.FunctionComponent = () => { - setSearchText(queryText)} - filters={[ - { - type: 'field_value_selection', - field: 'type', - name: i18n.translate('xpack.alertingUI.sections.actionsList.filters.typeName', { - defaultMessage: 'Type', - }), - multiSelect: 'or', - options: Object.values(actionTypesIndex || {}) - .map(actionType => ({ - value: actionType.id, - name: actionType.name, - })) - .sort((a, b) => { - if (a.name < b.name) return -1; - if (a.name > b.name) return 1; - return 0; - }), - }, - ]} - toolsRight={[ - - - , - , - ]} - > - - - - ({ @@ -242,19 +203,61 @@ export const ActionsList: React.FunctionComponent = () => { 'data-test-subj': 'cell', })} data-test-subj="actionsTable" - pagination={{ - pageIndex: page.index, - pageSize: page.size, - totalItemCount, - }} - onChange={({ page: changedPage }: { page: Pagination }) => { - setPage(changedPage); - }} + pagination={true} selection={{ onSelectionChange(updatedSelectedItemsList: Data[]) { setSelectedItems(updatedSelectedItemsList); }, }} + search={{ + filters: [ + { + type: 'field_value_selection', + field: 'actionTypeId', + name: i18n.translate( + 'xpack.alertingUI.sections.actionsList.filters.actionTypeIdName', + { defaultMessage: 'Action Type' } + ), + multiSelect: 'or', + options: Object.values(actionTypesIndex || {}) + .map(actionType => ({ + value: actionType.id, + name: actionType.name, + })) + .sort((a, b) => { + if (a.name < b.name) return -1; + if (a.name > b.name) return 1; + return 0; + }), + }, + ], + toolsRight: [ + + + , + , + ], + }} /> From ba533e9676121b2d666f54ec53249b97263a7080 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 18 Oct 2019 14:42:30 -0400 Subject: [PATCH 065/297] Cleanup imports --- .../sections/actions_list/components/actions_list.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 4320b8d7d1eb58..fb796115161e92 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -5,8 +5,7 @@ */ import React, { Fragment, useState, useEffect } from 'react'; -// @ts-ignore: EuiSearchBar not defined in TypeScript yet -import { EuiPageContent, EuiInMemoryTable, EuiSpacer, EuiSearchBar, EuiButton } from '@elastic/eui'; +import { EuiInMemoryTable, EuiSpacer, EuiButton } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { ActionsContext } from '../../../context/app_context'; From f8b31a22f5d7eea39ccb557e8c35c5173073f5d1 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 18 Oct 2019 14:50:49 -0400 Subject: [PATCH 066/297] Rename actions context filename --- .../context/{app_context.tsx => actions_context.tsx} | 0 .../sections/actions_list/components/actions_list.tsx | 2 +- .../sections/actions_list/components/create_menu_popover.tsx | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/{app_context.tsx => actions_context.tsx} (100%) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/app_context.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/actions_context.tsx similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/app_context.tsx rename to x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/actions_context.tsx diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index fb796115161e92..00560a4b4e5869 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -8,7 +8,7 @@ import React, { Fragment, useState, useEffect } from 'react'; import { EuiInMemoryTable, EuiSpacer, EuiButton } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { ActionsContext } from '../../../context/app_context'; +import { ActionsContext } from '../../../context/actions_context'; import { useAppDependencies } from '../../../index'; import { AlertingActionsDropdown } from './create_menu_popover'; import { diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx index e7fa67424b4f70..6ecb6995167f6f 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx @@ -17,7 +17,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { ActionsContext } from '../../../context/app_context'; +import { ActionsContext } from '../../../context/actions_context'; interface Props { actionTypes: any; From dfca1a1fa35cc4567bc0efd03e14ce9ffc38081a Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 18 Oct 2019 15:45:35 -0400 Subject: [PATCH 067/297] Rename ActionsPlugin to Plugin to match filename --- .../legacy/plugins/alerting_ui/np_ready/public/index.ts | 6 +++--- .../legacy/plugins/alerting_ui/np_ready/public/plugin.ts | 9 +++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/index.ts index 525f5e6df388e8..7eed516019dd01 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/index.ts @@ -5,11 +5,11 @@ */ import { PluginInitializerContext } from 'src/core/public'; -import { ActionsPlugin } from './plugin'; +import { Plugin } from './plugin'; export function plugin(ctx: PluginInitializerContext) { - return new ActionsPlugin(ctx); + return new Plugin(ctx); } -export { ActionsPlugin as Plugin }; +export { Plugin }; export * from './plugin'; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts index eebf20592bfb0d..5743d1d9ff0239 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts @@ -5,9 +5,14 @@ */ import { unmountComponentAtNode } from 'react-dom'; -import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'src/core/public'; import { i18n } from '@kbn/i18n'; import routes from 'ui/routes'; +import { + CoreSetup, + CoreStart, + Plugin as CorePlugin, + PluginInitializerContext, +} from 'src/core/public'; import template from '../../public/index.html'; import { renderReact } from './application'; @@ -20,7 +25,7 @@ export type Start = void; const REACT_ROOT_ID = 'alertingRoot'; -export class ActionsPlugin implements Plugin { +export class Plugin implements CorePlugin { constructor(initializerContext: PluginInitializerContext) {} public setup(core: CoreSetup, plugins: any): Setup { From 3d1b2f27b44b1511551ca5f4318b0c0e93ca3e27 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Sun, 20 Oct 2019 19:57:13 -0700 Subject: [PATCH 068/297] Provided registry functionality for action types supported by UI --- .../application/action_type_registry.ts | 58 ++++ .../constants/action_types_settings.ts | 254 ------------------ .../np_ready/public/application/index.tsx | 6 +- .../sections/action_add/action_add.tsx | 116 ++++---- .../action_add/action_fields/index.ts | 12 - .../action_fields/logging_action_fields.tsx | 23 -- .../email.tsx} | 84 +++++- .../es_index.tsx} | 28 +- .../action_add/buildin_action_types/index.ts | 26 ++ .../pagerduty.tsx} | 48 +++- .../buildin_action_types/server_log.tsx | 31 +++ .../slack.tsx} | 43 ++- .../webhook.tsx} | 70 ++++- .../actions_list/components/actions_list.tsx | 13 +- .../components/create_menu_popover.tsx | 16 +- .../alerting_ui/np_ready/public/plugin.ts | 15 +- .../alerting_ui/np_ready/public/types.ts | 23 ++ .../legacy/plugins/alerting_ui/public/shim.ts | 2 + 18 files changed, 449 insertions(+), 419 deletions(-) create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/action_type_registry.ts delete mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_types_settings.ts delete mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index.ts delete mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/logging_action_fields.tsx rename x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/{action_fields/email_action_fields.tsx => buildin_action_types/email.tsx} (65%) rename x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/{action_fields/index_action_fields.tsx => buildin_action_types/es_index.tsx} (60%) create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/index.ts rename x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/{action_fields/pagerduty_action_fields.tsx => buildin_action_types/pagerduty.tsx} (59%) create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx rename x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/{action_fields/slack_action_fields.tsx => buildin_action_types/slack.tsx} (53%) rename x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/{action_fields/webhook_action_fields.tsx => buildin_action_types/webhook.tsx} (79%) create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/action_type_registry.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/action_type_registry.ts new file mode 100644 index 00000000000000..ebe038cb97afac --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/action_type_registry.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 { i18n } from '@kbn/i18n'; +import { ActionTypeModel } from '../types'; + +export class ActionTypeRegistry { + private readonly actionTypes: Map = new Map(); + + /** + * Returns if the action type registry has the given action type registered + */ + public has(id: string) { + return this.actionTypes.has(id); + } + + /** + * Registers an action type to the action type registry + */ + public register(actionType: ActionTypeModel) { + if (this.has(actionType.id)) { + throw new Error( + i18n.translate( + 'xpack.actions.actionTypeRegistry.register.duplicateActionTypeErrorMessage', + { + defaultMessage: 'Action type "{id}" is already registered.', + values: { + id: actionType.id, + }, + } + ) + ); + } + this.actionTypes.set(actionType.id, actionType); + } + + /** + * Returns an action type, throws if not registered + */ + public get(id: string): ActionTypeModel | null { + if (!this.has(id)) { + return null; + } + return this.actionTypes.get(id)!; + } + + /** + * Returns a list of registered action types [{ id, name }] + */ + public list() { + return Array.from(this.actionTypes).map(([actionTypeId, actionType]) => ({ + id: actionTypeId, + })); + } +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_types_settings.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_types_settings.ts deleted file mode 100644 index a334cd5fa3f365..00000000000000 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_types_settings.ts +++ /dev/null @@ -1,254 +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 { i18n } from '@kbn/i18n'; -import { Action } from '../lib/api'; - -export const BUILDIN_ACTION_TYPES: { [key: string]: string } = { - EMAIL: '.email', - WEBHOOK: '.webhook', - INDEX: '.index', - LOGGING: '.server-log', - SLACK: '.slack', - PAGERDUTY: '.pagerduty', - CUSTOM: '.custom', -}; - -interface ActionTypeSettings { - iconClass: string; - selectMessage: string; - simulatePrompt: string; - validate: any; -} - -export const actionTypesSettings = (val: string): ActionTypeSettings => { - let res; - switch (val) { - case '.email': - res = { - iconClass: 'email', - selectMessage: i18n.translate( - 'xpack.alertingUI.sections.actions.emailAction.selectMessageText', - { - defaultMessage: 'Send an email from your server.', - } - ), - simulatePrompt: i18n.translate( - 'xpack.alertingUI.sections.actions.emailAction.simulateButtonLabel', - { - defaultMessage: 'Send test email', - } - ), - validate: (action: Action): any => { - const validationResult = { errors: {} }; - const errors = { - from: new Array(), - port: new Array(), - host: new Array(), - user: new Array(), - password: new Array(), - }; - validationResult.errors = errors; - if (!action.config.from) { - errors.from.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredFromText', { - defaultMessage: 'From is required.', - }) - ); - } - if (!action.config.port) { - errors.port.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredPortText', { - defaultMessage: 'Port is required.', - }) - ); - } - if (!action.config.host) { - errors.host.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHostText', { - defaultMessage: 'Host is required.', - }) - ); - } - if (!action.secrets.user) { - errors.user.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHostText', { - defaultMessage: 'User is required.', - }) - ); - } - if (!action.secrets.password) { - errors.password.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHostText', { - defaultMessage: 'Password is required.', - }) - ); - } - return validationResult; - }, - }; - break; - case '.slack': - res = { - iconClass: 'logoSlack', - selectMessage: i18n.translate( - 'xpack.alertingUI.sections.actions.slackAction.selectMessageText', - { - defaultMessage: 'Send a message to a Slack user or channel.', - } - ), - simulatePrompt: i18n.translate( - 'xpack.alertingUI.sections.actions.slackAction.simulateButtonLabel', - { - defaultMessage: 'Send a sample message', - } - ), - validate: (action: Action): any => { - const validationResult = { errors: {} }; - const errors = { - webhookUrl: new Array(), - }; - validationResult.errors = errors; - if (!action.secrets.webhookUrl) { - errors.webhookUrl.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredWebhookUrlText', { - defaultMessage: 'WebhookUrl is required.', - }) - ); - } - return validationResult; - }, - }; - break; - case '.server-log': - res = { - iconClass: 'loggingApp', - selectMessage: i18n.translate( - 'xpack.alertingUI.sections.actions.serverLogAction.selectMessageText', - { - defaultMessage: 'Add an item to the logs.', - } - ), - simulatePrompt: i18n.translate( - 'xpack.alertingUI.sections.actions.serverLogAction.simulateButtonLabel', - { - defaultMessage: 'Log a sample message', - } - ), - validate: (action: Action): any => { - return { errors: {} }; - }, - }; - break; - case '.index': - res = { - iconClass: 'indexOpen', - selectMessage: i18n.translate('xpack.watcher.models.indexAction.selectMessageText', { - defaultMessage: 'Index data into Elasticsearch.', - }), - simulatePrompt: i18n.translate('xpack.watcher.models.indexAction.simulateButtonLabel', { - defaultMessage: 'Index data', - }), - validate: (action: Action): any => { - return { errors: {} }; - }, - }; - break; - case '.pagerduty': - res = { - iconClass: 'apps', - selectMessage: i18n.translate('xpack.watcher.models.pagerDutyAction.selectMessageText', { - defaultMessage: 'Create an event in PagerDuty.', - }), - simulatePrompt: i18n.translate('xpack.watcher.models.pagerDutyAction.simulateButtonLabel', { - defaultMessage: 'Send a PagerDuty event', - }), - validate: (action: Action): any => { - const validationResult = { errors: {} }; - const errors = { - routingKey: new Array(), - apiUrl: new Array(), - }; - validationResult.errors = errors; - if (!action.secrets.routingKey) { - errors.routingKey.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredRoutingKeyText', { - defaultMessage: 'RoutingKey is required.', - }) - ); - } - if (!action.config.apiUrl) { - errors.apiUrl.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredApiUrlText', { - defaultMessage: 'ApiUrl is required.', - }) - ); - } - return validationResult; - }, - }; - break; - case '.webhook': - res = { - iconClass: 'logoWebhook', - selectMessage: i18n.translate('xpack.watcher.models.webhookAction.selectMessageText', { - defaultMessage: 'Send a request to a web service.', - }), - simulatePrompt: i18n.translate('xpack.watcher.models.webhookAction.simulateButtonLabel', { - defaultMessage: 'Send request', - }), - validate: (action: Action): any => { - const validationResult = { errors: {} }; - const errors = { - url: new Array(), - method: new Array(), - user: new Array(), - password: new Array(), - }; - validationResult.errors = errors; - if (!action.config.url) { - errors.url.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredUrlText', { - defaultMessage: 'Url is required.', - }) - ); - } - if (!action.config.method) { - errors.method.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredMethodText', { - defaultMessage: 'Method is required.', - }) - ); - } - if (!action.secrets.user) { - errors.user.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHostText', { - defaultMessage: 'User is required.', - }) - ); - } - if (!action.secrets.password) { - errors.password.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHostText', { - defaultMessage: 'Password is required.', - }) - ); - } - return validationResult; - }, - }; - break; - default: - res = { - iconClass: 'apps', - simulatePrompt: '', - selectMessage: '', - validate: (action: Action): any => { - return { errors: {} }; - }, - }; - } - return res; -}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/index.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/index.tsx index 74d021d574d7bd..46ea2e89a2a15c 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/index.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/index.tsx @@ -11,6 +11,7 @@ import { CoreStart } from 'src/core/public'; import { App } from './app'; import { AppDependencies, AppPlugins } from '../../../public/shim'; +import { ActionTypeRegistry } from './action_type_registry'; export { BASE_PATH as CLIENT_BASE_PATH } from './constants'; @@ -52,9 +53,10 @@ const getAppProviders = (deps: AppDependencies) => { export const renderReact = async ( elem: HTMLElement | null, core: CoreStart, - plugins: AppPlugins + plugins: AppPlugins, + actionTypeRegistry: ActionTypeRegistry ) => { - const Providers = getAppProviders({ core, plugins }); + const Providers = getAppProviders({ core, plugins, actionTypeRegistry }); render( diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx index 5ea78f079cbe24..fa7c371fc8ae90 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx @@ -28,29 +28,11 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { Action, ActionType, saveAction } from '../../lib/api'; import { ActionsContext } from '../../context/app_context'; -import { - WebhookActionFields, - LoggingActionFields, - IndexActionFields, - SlackActionFields, - EmailActionFields, - PagerDutyActionFields, -} from './action_fields'; import { SectionError, ErrableFormRow } from '../../../application/components/page_error'; -import { actionTypesSettings, BUILDIN_ACTION_TYPES } from '../../constants/action_types_settings'; import { useAppDependencies } from '../..'; import { ActionModel } from '../../models/action'; import { actionReducer } from './action_reducer'; -const actionFieldsComponentMap = { - [BUILDIN_ACTION_TYPES.LOGGING]: LoggingActionFields, - [BUILDIN_ACTION_TYPES.SLACK]: SlackActionFields, - [BUILDIN_ACTION_TYPES.EMAIL]: EmailActionFields, - [BUILDIN_ACTION_TYPES.INDEX]: IndexActionFields, - [BUILDIN_ACTION_TYPES.WEBHOOK]: WebhookActionFields, - [BUILDIN_ACTION_TYPES.PAGERDUTY]: PagerDutyActionFields, -}; - interface Props { actionType: ActionType; refreshList: () => void; @@ -59,6 +41,7 @@ interface Props { export const ActionAdd = ({ actionType, refreshList }: Props) => { const { core: { http }, + actionTypeRegistry, } = useAppDependencies(); const { flyoutVisible, setFlyoutVisibility } = useContext(ActionsContext); // hooks @@ -97,9 +80,10 @@ export const ActionAdd = ({ actionType, refreshList }: Props) => { return null; } - const FieldsComponent = actionFieldsComponentMap[actionType.id]; - const actionSettings = actionTypesSettings(actionType.id); - const errors = { ...actionSettings.validate(action).errors, ...action.validate().errors }; + const actionTypeRegisterd = actionTypeRegistry.get(actionType.id); + if (actionTypeRegisterd === null) return null; + const FieldsComponent = actionTypeRegisterd.actionFields; + const errors = { ...actionTypeRegisterd.validate(action).errors, ...action.validate().errors }; const hasErrors = !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); return ( @@ -107,7 +91,7 @@ export const ActionAdd = ({ actionType, refreshList }: Props) => { - + @@ -166,49 +150,51 @@ export const ActionAdd = ({ actionType, refreshList }: Props) => { /> - - {actionType.id === null ? ( - - - -

- - - - ), - }} - /> -

-
-
- -
- ) : null} -
+ {FieldsComponent !== null ? ( + + {actionType.id === null ? ( + + + +

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

+
+
+ +
+ ) : null} +
+ ) : null} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index.ts deleted file mode 100644 index 1934fbe3b3b02d..00000000000000 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index.ts +++ /dev/null @@ -1,12 +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 { EmailActionFields } from './email_action_fields'; -export { IndexActionFields } from './index_action_fields'; -export { LoggingActionFields } from './logging_action_fields'; -export { PagerDutyActionFields } from './pagerduty_action_fields'; -export { SlackActionFields } from './slack_action_fields'; -export { WebhookActionFields } from './webhook_action_fields'; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/logging_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/logging_action_fields.tsx deleted file mode 100644 index d476b658ed1b43..00000000000000 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/logging_action_fields.tsx +++ /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. - */ -import React, { Fragment } from 'react'; -import { Action } from '../../../lib/api'; - -interface Props { - action: Action; - editActionConfig: (property: string, value: any) => void; - errors: { [key: string]: string[] }; - hasErrors: boolean; -} - -export const LoggingActionFields: React.FunctionComponent = ({ - action, - editActionConfig, - errors, - hasErrors, -}) => { - return ; -}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/email_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx similarity index 65% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/email_action_fields.tsx rename to x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx index fb642b0fcdcab8..10b2e372878878 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/email_action_fields.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx @@ -14,16 +14,76 @@ import { import { i18n } from '@kbn/i18n'; import { Action } from '../../../lib/api'; import { ErrableFormRow } from '../../../components/page_error'; +import { ActionTypeModel, Props } from '../../../../types'; -interface Props { - action: Action; - editActionConfig: (property: string, value: any) => void; - editActionSecrets: (property: string, value: any) => void; - errors: { [key: string]: string[] }; - hasErrors: boolean; +export function getActionType(): ActionTypeModel { + return { + id: '.email', + iconClass: 'email', + selectMessage: i18n.translate( + 'xpack.alertingUI.sections.actions.emailAction.selectMessageText', + { + defaultMessage: 'Send an email from your server.', + } + ), + simulatePrompt: i18n.translate( + 'xpack.alertingUI.sections.actions.emailAction.simulateButtonLabel', + { + defaultMessage: 'Send test email', + } + ), + validate: (action: Action): any => { + const validationResult = { errors: {} }; + const errors = { + from: new Array(), + port: new Array(), + host: new Array(), + user: new Array(), + password: new Array(), + }; + validationResult.errors = errors; + if (!action.config.from) { + errors.from.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredFromText', { + defaultMessage: 'From is required.', + }) + ); + } + if (!action.config.port) { + errors.port.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredPortText', { + defaultMessage: 'Port is required.', + }) + ); + } + if (!action.config.host) { + errors.host.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHostText', { + defaultMessage: 'Host is required.', + }) + ); + } + if (!action.secrets.user) { + errors.user.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHostText', { + defaultMessage: 'User is required.', + }) + ); + } + if (!action.secrets.password) { + errors.password.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHostText', { + defaultMessage: 'Password is required.', + }) + ); + } + return validationResult; + }, + actionFields: EmailActionFields, + }; } -export const EmailActionFields: React.FunctionComponent = ({ +const EmailActionFields: React.FunctionComponent = ({ action, editActionConfig, editActionSecrets, @@ -40,7 +100,7 @@ export const EmailActionFields: React.FunctionComponent = ({ errorKey="from" fullWidth errors={errors} - isShowingErrors={hasErrors && from !== undefined} + isShowingErrors={hasErrors === true && from !== undefined} label={i18n.translate('xpack.alertingUI.sections.actionAdd.emailAction.fromFieldLabel', { defaultMessage: 'From', })} @@ -67,7 +127,7 @@ export const EmailActionFields: React.FunctionComponent = ({ errorKey="host" fullWidth errors={errors} - isShowingErrors={hasErrors && host !== undefined} + isShowingErrors={hasErrors === true && host !== undefined} label={i18n.translate('xpack.alertingUI.sections.actionAdd.emailHost.hostFieldLabel', { defaultMessage: 'Host', })} @@ -94,7 +154,7 @@ export const EmailActionFields: React.FunctionComponent = ({ errorKey="port" fullWidth errors={errors} - isShowingErrors={hasErrors && port !== undefined} + isShowingErrors={hasErrors === true && port !== undefined} label={i18n.translate('xpack.alertingUI.sections.actionAdd.emailPort.methodPortLabel', { defaultMessage: 'Port', })} @@ -124,7 +184,7 @@ export const EmailActionFields: React.FunctionComponent = ({ errorKey="user" fullWidth errors={errors} - isShowingErrors={hasErrors && user !== undefined} + isShowingErrors={hasErrors === true && user !== undefined} label={i18n.translate('xpack.alertingUI.sections.actionAdd.emailUser.userFieldLabel', { defaultMessage: 'User', })} @@ -151,7 +211,7 @@ export const EmailActionFields: React.FunctionComponent = ({ errorKey="password" fullWidth errors={errors} - isShowingErrors={hasErrors && password !== undefined} + isShowingErrors={hasErrors === true && password !== undefined} label={i18n.translate( 'xpack.alertingUI.sections.actionAdd.emailPassword.methodPasswordLabel', { diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx similarity index 60% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index_action_fields.tsx rename to x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx index 938055c46ea4b6..7cfd7071b4ae46 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/index_action_fields.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx @@ -7,20 +7,26 @@ import React from 'react'; import { EuiFieldText, EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { Action } from '../../../lib/api'; +import { ActionTypeModel, Props } from '../../../../types'; -interface Props { - action: Action; - editActionConfig: (property: string, value: any) => void; - errors: { [key: string]: string[] }; - hasErrors: boolean; +export function getActionType(): ActionTypeModel { + return { + id: '.index', + iconClass: 'indexOpen', + selectMessage: i18n.translate('xpack.watcher.models.indexAction.selectMessageText', { + defaultMessage: 'Index data into Elasticsearch.', + }), + simulatePrompt: i18n.translate('xpack.watcher.models.indexAction.simulateButtonLabel', { + defaultMessage: 'Index data', + }), + validate: (action: Action): any => { + return { errors: {} }; + }, + actionFields: IndexActionFields, + }; } -export const IndexActionFields: React.FunctionComponent = ({ - action, - editActionConfig, - errors, - hasErrors, -}) => { +const IndexActionFields: React.FunctionComponent = ({ action, editActionConfig }) => { const { index }: any = action.config; return ( void; - editActionSecrets: (property: string, value: any) => void; - errors: { [key: string]: string[] }; - hasErrors: boolean; +export function getActionType(): ActionTypeModel { + return { + id: '.pagerduty', + iconClass: 'apps', + selectMessage: i18n.translate('xpack.watcher.models.pagerDutyAction.selectMessageText', { + defaultMessage: 'Create an event in PagerDuty.', + }), + simulatePrompt: i18n.translate('xpack.watcher.models.pagerDutyAction.simulateButtonLabel', { + defaultMessage: 'Send a PagerDuty event', + }), + validate: (action: Action): any => { + const validationResult = { errors: {} }; + const errors = { + routingKey: new Array(), + apiUrl: new Array(), + }; + validationResult.errors = errors; + if (!action.secrets.routingKey) { + errors.routingKey.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredRoutingKeyText', { + defaultMessage: 'RoutingKey is required.', + }) + ); + } + if (!action.config.apiUrl) { + errors.apiUrl.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredApiUrlText', { + defaultMessage: 'ApiUrl is required.', + }) + ); + } + return validationResult; + }, + actionFields: PagerDutyActionFields, + }; } -export const PagerDutyActionFields: React.FunctionComponent = ({ +const PagerDutyActionFields: React.FunctionComponent = ({ errors, hasErrors, action, @@ -33,7 +63,7 @@ export const PagerDutyActionFields: React.FunctionComponent = ({ errorKey="apiUrl" fullWidth errors={errors} - isShowingErrors={hasErrors && apiUrl !== undefined} + isShowingErrors={hasErrors === true && apiUrl !== undefined} label={i18n.translate( 'xpack.alertingUI.sections.actionAdd.pagerDutyAction.apiUrlFieldLabel', { @@ -61,7 +91,7 @@ export const PagerDutyActionFields: React.FunctionComponent = ({ errorKey="routingKey" fullWidth errors={errors} - isShowingErrors={hasErrors && routingKey !== undefined} + isShowingErrors={hasErrors === true && routingKey !== undefined} label={i18n.translate( 'xpack.alertingUI.sections.actionAdd.pagerDutyAction.routingKeyFieldLabel', { diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx new file mode 100644 index 00000000000000..667492029a7b75 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { i18n } from '@kbn/i18n'; +import { Action } from '../../../lib/api'; +import { ActionTypeModel } from '../../../../types'; + +export function getActionType(): ActionTypeModel { + return { + id: '.server-log', + iconClass: 'loggingApp', + selectMessage: i18n.translate( + 'xpack.alertingUI.sections.actions.serverLogAction.selectMessageText', + { + defaultMessage: 'Add an item to the logs.', + } + ), + simulatePrompt: i18n.translate( + 'xpack.alertingUI.sections.actions.serverLogAction.simulateButtonLabel', + { + defaultMessage: 'Log a sample message', + } + ), + validate: (action: Action): any => { + return { errors: {} }; + }, + actionFields: null, + }; +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/slack_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx similarity index 53% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/slack_action_fields.tsx rename to x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx index 1636d2752b0d81..901ba40093ad1c 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/slack_action_fields.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx @@ -8,15 +8,44 @@ import { EuiFieldText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { Action } from '../../../lib/api'; import { ErrableFormRow } from '../../../components/page_error'; +import { ActionTypeModel, Props } from '../../../../types'; -interface Props { - action: Action; - editActionSecrets: (property: string, value: any) => void; - errors: { [key: string]: string[] }; - hasErrors: boolean; +export function getActionType(): ActionTypeModel { + return { + id: '.slack', + iconClass: 'logoSlack', + selectMessage: i18n.translate( + 'xpack.alertingUI.sections.actions.slackAction.selectMessageText', + { + defaultMessage: 'Send a message to a Slack user or channel.', + } + ), + simulatePrompt: i18n.translate( + 'xpack.alertingUI.sections.actions.slackAction.simulateButtonLabel', + { + defaultMessage: 'Send a sample message', + } + ), + validate: (action: Action): any => { + const validationResult = { errors: {} }; + const errors = { + webhookUrl: new Array(), + }; + validationResult.errors = errors; + if (!action.secrets.webhookUrl) { + errors.webhookUrl.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredWebhookUrlText', { + defaultMessage: 'WebhookUrl is required.', + }) + ); + } + return validationResult; + }, + actionFields: SlackActionFields, + }; } -export const SlackActionFields: React.FunctionComponent = ({ +const SlackActionFields: React.FunctionComponent = ({ action, editActionSecrets, errors, @@ -31,7 +60,7 @@ export const SlackActionFields: React.FunctionComponent = ({ errorKey="webhookUrl" fullWidth errors={errors} - isShowingErrors={hasErrors && webhookUrl !== undefined} + isShowingErrors={hasErrors === true && webhookUrl !== undefined} label={i18n.translate( 'xpack.alertingUI.sections.actionAdd.slackPassword.methodWebhookUrlLabel', { diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx similarity index 79% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx rename to x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx index 67dcd88d6a6ffa..1990bc3c8e3fbb 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_fields/webhook_action_fields.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx @@ -20,18 +20,64 @@ import { import { i18n } from '@kbn/i18n'; import { ErrableFormRow } from '../../../components/page_error'; import { Action } from '../../../lib/api'; - -interface Props { - action: Action; - editActionConfig: (property: string, value: any) => void; - editActionSecrets: (property: string, value: any) => void; - errors: { [key: string]: string[] }; - hasErrors: boolean; -} +import { ActionTypeModel, Props } from '../../../../types'; const HTTP_VERBS = ['post', 'put']; -export const WebhookActionFields: React.FunctionComponent = ({ +export function getActionType(): ActionTypeModel { + return { + id: '.webhook', + iconClass: 'logoWebhook', + selectMessage: i18n.translate('xpack.watcher.models.webhookAction.selectMessageText', { + defaultMessage: 'Send a request to a web service.', + }), + simulatePrompt: i18n.translate('xpack.watcher.models.webhookAction.simulateButtonLabel', { + defaultMessage: 'Send request', + }), + validate: (action: Action): any => { + const validationResult = { errors: {} }; + const errors = { + url: new Array(), + method: new Array(), + user: new Array(), + password: new Array(), + }; + validationResult.errors = errors; + if (!action.config.url) { + errors.url.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredUrlText', { + defaultMessage: 'Url is required.', + }) + ); + } + if (!action.config.method) { + errors.method.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredMethodText', { + defaultMessage: 'Method is required.', + }) + ); + } + if (!action.secrets.user) { + errors.user.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHostText', { + defaultMessage: 'User is required.', + }) + ); + } + if (!action.secrets.password) { + errors.password.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHostText', { + defaultMessage: 'Password is required.', + }) + ); + } + return validationResult; + }, + actionFields: WebhookActionFields, + }; +} + +const WebhookActionFields: React.FunctionComponent = ({ action, editActionConfig, editActionSecrets, @@ -114,7 +160,7 @@ export const WebhookActionFields: React.FunctionComponent = ({ fullWidth errorKey="url" errors={errors} - isShowingErrors={hasErrors && url !== undefined} + isShowingErrors={hasErrors === true && url !== undefined} label={i18n.translate('xpack.alertingUI.sections.slackPassword.methodUrlLabel', { defaultMessage: 'Url', })} @@ -143,7 +189,7 @@ export const WebhookActionFields: React.FunctionComponent = ({ errorKey="user" fullWidth errors={errors} - isShowingErrors={hasErrors && user !== undefined} + isShowingErrors={hasErrors === true && user !== undefined} label={i18n.translate('xpack.alertingUI.sections.webhookUser.userFieldLabel', { defaultMessage: 'User', })} @@ -170,7 +216,7 @@ export const WebhookActionFields: React.FunctionComponent = ({ errorKey="password" fullWidth errors={errors} - isShowingErrors={hasErrors && password !== undefined} + isShowingErrors={hasErrors === true && password !== undefined} label={i18n.translate('xpack.alertingUI.sections.webhookPassword.methodPasswordLabel', { defaultMessage: 'Password', })} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 276e505b09d81e..558984c4c921ad 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -5,6 +5,7 @@ */ import React, { Fragment, useState, useEffect } from 'react'; +// @ts-ignore: EuiSearchBar not defined in TypeScript yet import { EuiPageContent, EuiBasicTable, EuiSpacer, EuiSearchBar, EuiButton } from '@elastic/eui'; import { capabilities } from 'ui/capabilities'; import { i18n } from '@kbn/i18n'; @@ -15,6 +16,7 @@ import { ActionsContext } from '../../../context/app_context'; import { useAppDependencies } from '../../../index'; import { AlertingActionsDropdown } from './create_menu_popover'; import { ActionAdd } from '../../action_add'; +import { ActionTypeRegistry } from '../../../action_type_registry'; type ActionTypeIndex = Record; interface Pagination { @@ -30,6 +32,7 @@ const canDelete = capabilities.get().actions.delete; export const ActionsList: React.FunctionComponent = () => { const { core: { http }, + actionTypeRegistry, } = useAppDependencies(); const [actionTypesIndex, setActionTypesIndex] = useState(undefined); @@ -263,7 +266,11 @@ export const ActionsList: React.FunctionComponent = () => { return (
- + {content} {flyout} @@ -275,16 +282,18 @@ export const ActionsList: React.FunctionComponent = () => { export const ContentWrapper = ({ flyoutVisible, setFlyoutVisibility, + actionTypeRegistry, children, }: { flyoutVisible: boolean; setFlyoutVisibility: React.Dispatch>; + actionTypeRegistry: ActionTypeRegistry; children: React.ReactNode; }) => { return ( - + {children} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx index eb92264618f0ef..6dcdc37260d76b 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { useState } from 'react'; +import React, { useState, useContext } from 'react'; import { EuiSpacer, EuiText, @@ -16,8 +16,8 @@ import { EuiContextMenuItem, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { actionTypesSettings } from '../../../constants/action_types_settings'; import { ActionType } from '../../../lib/api'; +import { ActionsContext } from '../../../context/app_context'; interface Props { actionTypesIndex: Record | undefined; @@ -29,10 +29,11 @@ export const AlertingActionsDropdown: React.FunctionComponent = ({ createAction, }) => { const [isPopoverOpen, setIsPopOverOpen] = useState(false); - - const actions = Object.entries(!actionTypesIndex ? [] : actionTypesIndex).map( - ([actionType, { id, name }]: any) => { - const actionSettings = actionTypesSettings(id); + const { actionTypeRegistry } = useContext(ActionsContext); + const actions = Object.entries(!actionTypesIndex ? [] : actionTypesIndex) + .filter(aa => actionTypeRegistry.get(aa[1].id) !== null) + .map(([actionType, { id, name }]: any) => { + const actionSettings = actionTypeRegistry.get(id); const typeName = name; const iconClass = actionSettings.iconClass; const selectMessage = !actionSettings.selectMessage ? name : actionSettings.selectMessage; @@ -43,8 +44,7 @@ export const AlertingActionsDropdown: React.FunctionComponent = ({ iconClass, selectMessage, }; - } - ); + }); const button = ( { + private actionTypeRegistry?: ActionTypeRegistry; + constructor(initializerContext: PluginInitializerContext) {} public setup(core: CoreSetup, plugins: any): Setup { @@ -34,6 +38,13 @@ export class ActionsPlugin implements Plugin { management: { getSection }, } = plugins; + const actionTypeRegistry = new ActionTypeRegistry(); + this.actionTypeRegistry = actionTypeRegistry; + + registerBuiltInActionTypes({ + actionTypeRegistry, + }); + const kbnSection = getSection('kibana'); kbnSection.register('alerting', { display: i18n.translate('xpack.alertingUI.managementSection.displayName', { @@ -82,8 +93,8 @@ export class ActionsPlugin implements Plugin { $scope.$$postDigest(() => { unmountReactApp(); const elReactRoot = document.getElementById(REACT_ROOT_ID); - if (elReactRoot) { - renderReact(elReactRoot, core, plugins); + if (elReactRoot && this.actionTypeRegistry) { + renderReact(elReactRoot, core, plugins, this.actionTypeRegistry); } }); }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts new file mode 100644 index 00000000000000..52fc405c904933 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under 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 { Action } from './application/lib/api'; + +export interface Props { + action: Action; + editActionConfig: (property: string, value: any) => void; + editActionSecrets: (property: string, value: any) => void; + errors: { [key: string]: string[] }; + hasErrors?: boolean; +} + +export interface ActionTypeModel { + id: string; + iconClass: string; + selectMessage: string; + simulatePrompt: string; + validate: (action: Action) => any; + actionFields: React.FunctionComponent | null; +} diff --git a/x-pack/legacy/plugins/alerting_ui/public/shim.ts b/x-pack/legacy/plugins/alerting_ui/public/shim.ts index ec12afd337e0dd..11d48d711c823f 100644 --- a/x-pack/legacy/plugins/alerting_ui/public/shim.ts +++ b/x-pack/legacy/plugins/alerting_ui/public/shim.ts @@ -6,6 +6,7 @@ import { management, MANAGEMENT_BREADCRUMB } from 'ui/management'; import { CoreStart } from 'kibana/public'; +import { ActionTypeRegistry } from '../np_ready/public/application/action_type_registry'; export interface AppPlugins { management: { @@ -18,6 +19,7 @@ export interface AppPlugins { export interface AppDependencies { core: CoreStart; plugins: AppPlugins; + actionTypeRegistry: ActionTypeRegistry; } export function createShim() { From 74687508fabf277c757e82a46b33a1afec4291d8 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 21 Oct 2019 10:44:54 -0400 Subject: [PATCH 069/297] PR feedback --- .../sections/actions_list/components/actions_list.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 00560a4b4e5869..95a35314667bb5 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -223,11 +223,7 @@ export const ActionsList: React.FunctionComponent = () => { value: actionType.id, name: actionType.name, })) - .sort((a, b) => { - if (a.name < b.name) return -1; - if (a.name > b.name) return 1; - return 0; - }), + .sort((a, b) => a.name.localeCompare(b.name)), }, ], toolsRight: [ From 85578a4fc084818300dbc9fe472dab2050dce9a5 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 21 Oct 2019 14:15:49 -0400 Subject: [PATCH 070/297] Apply PR feedback --- .../plugins/actions/server/builtin_action_types/email.ts | 2 +- .../actions/server/builtin_action_types/es_index.ts | 2 +- .../actions/server/builtin_action_types/pagerduty.ts | 2 +- .../actions/server/builtin_action_types/server_log.ts | 2 +- .../plugins/actions/server/builtin_action_types/slack.ts | 2 +- .../actions/server/builtin_action_types/webhook.ts | 2 +- .../alerting_ui/np_ready/public/application/app.tsx | 2 +- .../components/page_error/page_error_forbidden.tsx | 2 +- .../components/page_error/page_error_not_exist.tsx | 4 ++-- .../np_ready/public/application/lib/doc_title.ts | 8 +++++--- 10 files changed, 15 insertions(+), 13 deletions(-) diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/email.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/email.ts index ace5443e778c08..a2365b95431a0a 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/email.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/email.ts @@ -102,7 +102,7 @@ function validateParams(paramsObject: any): string | void { export function getActionType({ logger }: { logger: Logger }): ActionType { return { id: '.email', - name: i18n.translate('xpack.actions.builtin.email.name', { + name: i18n.translate('xpack.actions.builtin.emailTitle', { defaultMessage: 'Email', }), validate: { diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/es_index.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/es_index.ts index 9bed5b50e0d5a8..6d74845c5f3366 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/es_index.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/es_index.ts @@ -38,7 +38,7 @@ const ParamsSchema = schema.object({ export function getActionType({ logger }: { logger: Logger }): ActionType { return { id: '.index', - name: i18n.translate('xpack.actions.builtin.esIndex.name', { + name: i18n.translate('xpack.actions.builtin.esIndexTitle', { defaultMessage: 'Index', }), validate: { diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/pagerduty.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/pagerduty.ts index 7f6eb57794b242..cbf097a92ca1e3 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/pagerduty.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/pagerduty.ts @@ -89,7 +89,7 @@ function validateParams(paramsObject: any): string | void { export function getActionType({ logger }: { logger: Logger }): ActionType { return { id: '.pagerduty', - name: i18n.translate('xpack.actions.builtin.pagerduty.name', { + name: i18n.translate('xpack.actions.builtin.pagerdutyTitle', { defaultMessage: 'PagerDuty', }), validate: { diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.ts index f7fd30d1d3f0ae..b727f05933e65a 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.ts @@ -31,7 +31,7 @@ const ParamsSchema = schema.object({ export function getActionType({ logger }: { logger: Logger }): ActionType { return { id: '.server-log', - name: i18n.translate('xpack.actions.builtin.serverLog.name', { + name: i18n.translate('xpack.actions.builtin.serverLogTitle', { defaultMessage: 'Server Log', }), validate: { diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/slack.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/slack.ts index 5e3021c37fac45..14789442af697e 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/slack.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/slack.ts @@ -42,7 +42,7 @@ export function getActionType( ): ActionType { return { id: '.slack', - name: i18n.translate('xpack.actions.builtin.slack.name', { + name: i18n.translate('xpack.actions.builtin.slackTitle', { defaultMessage: 'Slack', }), validate: { diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/webhook.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/webhook.ts index fcaf3471ff5637..80e2efc0ea7cb4 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/webhook.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/webhook.ts @@ -56,7 +56,7 @@ export function getActionType({ }): ActionType { return { id: '.webhook', - name: i18n.translate('xpack.actions.builtin.webhook.name', { + name: i18n.translate('xpack.actions.builtin.webhookTitle', { defaultMessage: 'Webhook', }), validate: { diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx index ca49d3edab6701..dca3d92ae51eb0 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx @@ -27,7 +27,7 @@ class ShareRouter extends Component { } } -export const App = (api: any) => { +export const App = () => { const sections: Section[] = ['actions']; const sectionsRegex = sections.join('|'); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx index eac701d03ce760..b046c7e7c1f3f8 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx @@ -17,7 +17,7 @@ export function PageErrorForbidden() { title={

diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx index b1c243af8e04c7..21c5abc3ad1a44 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx @@ -17,7 +17,7 @@ export function PageErrorNotExist({ id }: { id: any }) { title={

@@ -25,7 +25,7 @@ export function PageErrorNotExist({ id }: { id: any }) { body={

diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/doc_title.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/doc_title.ts index 8cb8a3189432e4..3b51191f021660 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/doc_title.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/doc_title.ts @@ -13,9 +13,7 @@ class DocTitleService { } public setTitle(page?: string): void { - let updatedTitle = i18n.translate('xpack.alertingUI.home.breadcrumbTitle', { - defaultMessage: 'Alerting UI', - }); + let updatedTitle: string; switch (page) { case 'actions': @@ -23,6 +21,10 @@ class DocTitleService { defaultMessage: 'Actions', }); break; + default: + updatedTitle = i18n.translate('xpack.alertingUI.home.breadcrumbTitle', { + defaultMessage: 'Alerting UI', + }); } this.changeDocTitle(updatedTitle); From bbbb99cae7dfaf3f269000503072aebfa946595d Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 21 Oct 2019 16:51:49 -0700 Subject: [PATCH 071/297] Fixed type definitions in actions dropdown, moved all types definitions to alerting_ui/np_ready/public/types --- .../np_ready/public/application/lib/api.ts | 44 +++++++------------ .../sections/action_add/action_add.tsx | 6 +-- .../action_add/buildin_action_types/email.tsx | 30 ++++++------- .../buildin_action_types/es_index.tsx | 5 +-- .../buildin_action_types/pagerduty.tsx | 3 +- .../buildin_action_types/server_log.tsx | 3 +- .../action_add/buildin_action_types/slack.tsx | 3 +- .../buildin_action_types/webhook.tsx | 3 +- .../actions_list/components/actions_list.tsx | 10 +---- .../components/create_menu_popover.tsx | 19 ++++---- .../alerting_ui/np_ready/public/types.ts | 21 +++++++-- 11 files changed, 69 insertions(+), 78 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index 41962f87ffb69e..744ac930455816 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -5,48 +5,41 @@ */ import { HttpServiceBase } from 'kibana/public'; import { BASE_ACTION_API_PATH } from '../constants'; +import { ActionType, Action } from '../../types'; // We are assuming there won't be many actions. This is why we will load // all the actions in advance and assume the total count to not go over 100 or so. // We'll set this max setting assuming it's never reached. const MAX_ACTIONS_RETURNED = 10000; -export interface ActionType { - id: string; - name: string; -} - -export interface Action { - secrets: Record; - id: string; - actionTypeId: string; - description: string; - config: Record; -} - -export interface LoadActionTypesOpts { +interface LoadActionTypesOpts { http: HttpServiceBase; } -export type LoadActionTypesResponse = ActionType[]; - -export async function loadActionTypes({ - http, -}: LoadActionTypesOpts): Promise { - return http.get(`${BASE_ACTION_API_PATH}/types`); -} +type LoadActionTypesResponse = ActionType[]; -export interface LoadActionsOpts { +interface LoadActionsOpts { http: HttpServiceBase; } -export interface LoadActionsResponse { +interface LoadActionsResponse { page: number; perPage: number; total: number; data: Action[]; } +interface DeleteActionsOpts { + ids: string[]; + http: HttpServiceBase; +} + +export async function loadActionTypes({ + http, +}: LoadActionTypesOpts): Promise { + return http.get(`${BASE_ACTION_API_PATH}/types`); +} + export async function loadAllActions({ http }: LoadActionsOpts): Promise { return http.get(`${BASE_ACTION_API_PATH}/_find`, { query: { @@ -67,11 +60,6 @@ export async function saveAction({ }); } -export interface DeleteActionsOpts { - ids: string[]; - http: HttpServiceBase; -} - export async function deleteActions({ ids, http }: DeleteActionsOpts): Promise { await Promise.all(ids.map(id => http.delete(`${BASE_ACTION_API_PATH}/${id}`))); } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx index 1bf0fd6026adf8..37dc6d47ba211c 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx @@ -26,12 +26,13 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { Action, ActionType, saveAction } from '../../lib/api'; +import { saveAction } from '../../lib/api'; import { SectionError, ErrableFormRow } from '../../../application/components/page_error'; import { useAppDependencies } from '../..'; import { ActionModel } from '../../models/action'; import { actionReducer } from './action_reducer'; import { ActionsContext } from '../../context/actions_context'; +import { ActionType, Action } from '../../../types'; interface Props { actionType: ActionType; @@ -41,9 +42,8 @@ interface Props { export const ActionAdd = ({ actionType, refreshList }: Props) => { const { core: { http }, - actionTypeRegistry, } = useAppDependencies(); - const { flyoutVisible, setFlyoutVisibility } = useContext(ActionsContext); + const { flyoutVisible, setFlyoutVisibility, actionTypeRegistry } = useContext(ActionsContext); // hooks const [{ action }, dispatch] = useReducer(actionReducer, { action: new ActionModel({ actionTypeId: actionType.id }), diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx index 10b2e372878878..e2a86b1dd65c29 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx @@ -12,9 +12,8 @@ import { EuiFieldPassword, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { Action } from '../../../lib/api'; import { ErrableFormRow } from '../../../components/page_error'; -import { ActionTypeModel, Props } from '../../../../types'; +import { ActionTypeModel, Props, Action } from '../../../../types'; export function getActionType(): ActionTypeModel { return { @@ -23,7 +22,7 @@ export function getActionType(): ActionTypeModel { selectMessage: i18n.translate( 'xpack.alertingUI.sections.actions.emailAction.selectMessageText', { - defaultMessage: 'Send an email from your server.', + defaultMessage: 'Send an email.', } ), simulatePrompt: i18n.translate( @@ -65,14 +64,14 @@ export function getActionType(): ActionTypeModel { } if (!action.secrets.user) { errors.user.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHostText', { + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredUserText', { defaultMessage: 'User is required.', }) ); } if (!action.secrets.password) { errors.password.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHostText', { + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredPasswordText', { defaultMessage: 'Password is required.', }) ); @@ -90,8 +89,8 @@ const EmailActionFields: React.FunctionComponent = ({ errors, hasErrors, }) => { - const { from, host, port }: any = action.config; - const { user, password }: any = action.secrets; + const { from, host, port }: Record = action.config; + const { user, password }: Record = action.secrets; return ( @@ -101,7 +100,7 @@ const EmailActionFields: React.FunctionComponent = ({ fullWidth errors={errors} isShowingErrors={hasErrors === true && from !== undefined} - label={i18n.translate('xpack.alertingUI.sections.actionAdd.emailAction.fromFieldLabel', { + label={i18n.translate('xpack.alertingUI.sections.actionAdd.emailActionLabel', { defaultMessage: 'From', })} > @@ -128,7 +127,7 @@ const EmailActionFields: React.FunctionComponent = ({ fullWidth errors={errors} isShowingErrors={hasErrors === true && host !== undefined} - label={i18n.translate('xpack.alertingUI.sections.actionAdd.emailHost.hostFieldLabel', { + label={i18n.translate('xpack.alertingUI.sections.actionAdd.emailHostLabel', { defaultMessage: 'Host', })} > @@ -155,7 +154,7 @@ const EmailActionFields: React.FunctionComponent = ({ fullWidth errors={errors} isShowingErrors={hasErrors === true && port !== undefined} - label={i18n.translate('xpack.alertingUI.sections.actionAdd.emailPort.methodPortLabel', { + label={i18n.translate('xpack.alertingUI.sections.actionAdd.emailPortLabel', { defaultMessage: 'Port', })} > @@ -185,7 +184,7 @@ const EmailActionFields: React.FunctionComponent = ({ fullWidth errors={errors} isShowingErrors={hasErrors === true && user !== undefined} - label={i18n.translate('xpack.alertingUI.sections.actionAdd.emailUser.userFieldLabel', { + label={i18n.translate('xpack.alertingUI.sections.actionAdd.emailUserLabel', { defaultMessage: 'User', })} > @@ -212,12 +211,9 @@ const EmailActionFields: React.FunctionComponent = ({ fullWidth errors={errors} isShowingErrors={hasErrors === true && password !== undefined} - label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.emailPassword.methodPasswordLabel', - { - defaultMessage: 'Password', - } - )} + label={i18n.translate('xpack.alertingUI.sections.actionAdd.emailPasswordLabel', { + defaultMessage: 'Password', + })} > = ({ action, editActionConfig }) => { - const { index }: any = action.config; + const { index }: Record = action.config; return ( ; interface Data extends Action { diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx index 89d1fc0057a94d..106f4140aeb651 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx @@ -16,8 +16,8 @@ import { EuiContextMenuItem, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { ActionType } from '../../../lib/api'; import { ActionsContext } from '../../../context/actions_context'; +import { ActionType } from '../../../../types'; interface Props { actionTypesIndex: Record | undefined; @@ -30,16 +30,19 @@ export const AlertingActionsDropdown: React.FunctionComponent = ({ }) => { const [isPopoverOpen, setIsPopOverOpen] = useState(false); const { actionTypeRegistry } = useContext(ActionsContext); + if (!actionTypesIndex) { + return null; + } const actions = Object.entries(!actionTypesIndex ? [] : actionTypesIndex) - .filter(aa => actionTypeRegistry.get(aa[1].id) !== null) - .map(([actionType, { id, name }]: any) => { - const actionSettings = actionTypeRegistry.get(id); - const typeName = name; + .filter(([index]) => actionTypeRegistry.get(index) !== null) + .map(([index, actionType]) => { + const actionSettings = actionTypeRegistry.get(actionType.id); + const typeName = actionType.name; const iconClass = actionSettings.iconClass; const selectMessage = !actionSettings.selectMessage ? name : actionSettings.selectMessage; return { - id, - name, + id: index, + name: index.replace('.', ''), typeName, iconClass, selectMessage, @@ -85,7 +88,7 @@ export const AlertingActionsDropdown: React.FunctionComponent = ({ }} > - + diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts index 52fc405c904933..dcee6bdaabeed7 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts @@ -3,8 +3,6 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Action } from './application/lib/api'; - export interface Props { action: Action; editActionConfig: (property: string, value: any) => void; @@ -18,6 +16,23 @@ export interface ActionTypeModel { iconClass: string; selectMessage: string; simulatePrompt: string; - validate: (action: Action) => any; + validate: (action: Action) => ValidationResult; actionFields: React.FunctionComponent | null; } + +export interface ValidationResult { + errors: Record; +} + +export interface ActionType { + id: string; + name: string; +} + +export interface Action { + secrets: Record; + id: string; + actionTypeId: string; + description: string; + config: Record; +} From e51e55670c9a6bd2789d5f57d99a8b88390555fb Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 21 Oct 2019 16:52:23 -0700 Subject: [PATCH 072/297] Added alerting UI styles --- x-pack/legacy/plugins/alerting_ui/index.ts | 1 + x-pack/legacy/plugins/alerting_ui/public/index.scss | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 x-pack/legacy/plugins/alerting_ui/public/index.scss diff --git a/x-pack/legacy/plugins/alerting_ui/index.ts b/x-pack/legacy/plugins/alerting_ui/index.ts index 49e76764eb1382..96b451d9cbe016 100644 --- a/x-pack/legacy/plugins/alerting_ui/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/index.ts @@ -26,6 +26,7 @@ export function alertingUI(kibana: any) { }, uiExports: { hacks: ['plugins/alerting_ui/hacks/register'], + styleSheetPaths: resolve(__dirname, 'public/index.scss'), managementSections: ['plugins/alerting_ui'], }, }); diff --git a/x-pack/legacy/plugins/alerting_ui/public/index.scss b/x-pack/legacy/plugins/alerting_ui/public/index.scss new file mode 100644 index 00000000000000..8bf963692ee58b --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/public/index.scss @@ -0,0 +1,8 @@ +// Import the EUI global scope so we can use EUI constants +@import 'src/legacy/ui/public/styles/_styling_constants'; + +// Alerting UI plugin styles + +.alertingUIActionContextMenuItem { + align-self: center; +} From 84bb909e40b40c9f51adbdfd653a034f8cfafbae Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 21 Oct 2019 18:12:46 -0700 Subject: [PATCH 073/297] Clean up any usage from creating forms --- .../action_add/buildin_action_types/email.tsx | 23 ++++--------- .../buildin_action_types/es_index.tsx | 13 +++----- .../buildin_action_types/pagerduty.tsx | 31 +++++++----------- .../buildin_action_types/server_log.tsx | 19 +++-------- .../action_add/buildin_action_types/slack.tsx | 32 ++++++------------- .../buildin_action_types/webhook.tsx | 31 ++++++++---------- .../components/create_menu_popover.tsx | 20 ++++-------- .../alerting_ui/np_ready/public/types.ts | 1 - 8 files changed, 59 insertions(+), 111 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx index e2a86b1dd65c29..599d0615c3fb19 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx @@ -13,25 +13,16 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ErrableFormRow } from '../../../components/page_error'; -import { ActionTypeModel, Props, Action } from '../../../../types'; +import { ActionTypeModel, Props, Action, ValidationResult } from '../../../../types'; export function getActionType(): ActionTypeModel { return { id: '.email', iconClass: 'email', - selectMessage: i18n.translate( - 'xpack.alertingUI.sections.actions.emailAction.selectMessageText', - { - defaultMessage: 'Send an email.', - } - ), - simulatePrompt: i18n.translate( - 'xpack.alertingUI.sections.actions.emailAction.simulateButtonLabel', - { - defaultMessage: 'Send test email', - } - ), - validate: (action: Action): any => { + selectMessage: i18n.translate('xpack.alertingUI.sections.actionAdd.selectMessageText', { + defaultMessage: 'Send an email.', + }), + validate: (action: Action): ValidationResult => { const validationResult = { errors: {} }; const errors = { from: new Array(), @@ -89,8 +80,8 @@ const EmailActionFields: React.FunctionComponent = ({ errors, hasErrors, }) => { - const { from, host, port }: Record = action.config; - const { user, password }: Record = action.secrets; + const { from, host, port } = action.config; + const { user, password } = action.secrets; return ( diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx index 224afbb701a43d..110f13bec529ce 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx @@ -6,19 +6,16 @@ import React from 'react'; import { EuiFieldText, EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ActionTypeModel, Props, Action } from '../../../../types'; +import { ActionTypeModel, Props, ValidationResult } from '../../../../types'; export function getActionType(): ActionTypeModel { return { id: '.index', iconClass: 'indexOpen', - selectMessage: i18n.translate('xpack.watcher.models.indexAction.selectMessageText', { + selectMessage: i18n.translate('xpack.alertingUI.sections.actionAdd.selectMessageText', { defaultMessage: 'Index data into Elasticsearch.', }), - simulatePrompt: i18n.translate('xpack.watcher.models.indexAction.simulateButtonLabel', { - defaultMessage: 'Index data', - }), - validate: (action: Action): any => { + validate: (): ValidationResult => { return { errors: {} }; }, actionFields: IndexActionFields, @@ -26,11 +23,11 @@ export function getActionType(): ActionTypeModel { } const IndexActionFields: React.FunctionComponent = ({ action, editActionConfig }) => { - const { index }: Record = action.config; + const { index } = action.config; return ( diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx index 7617805c23e77a..f36393f13dcf1d 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx @@ -7,19 +7,16 @@ import React, { Fragment } from 'react'; import { EuiFieldText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ErrableFormRow } from '../../../components/page_error'; -import { ActionTypeModel, Props, Action } from '../../../../types'; +import { ActionTypeModel, Props, Action, ValidationResult } from '../../../../types'; export function getActionType(): ActionTypeModel { return { id: '.pagerduty', iconClass: 'apps', - selectMessage: i18n.translate('xpack.watcher.models.pagerDutyAction.selectMessageText', { + selectMessage: i18n.translate('xpack.alertingUI.sections.actionAdd.selectMessageText', { defaultMessage: 'Create an event in PagerDuty.', }), - simulatePrompt: i18n.translate('xpack.watcher.models.pagerDutyAction.simulateButtonLabel', { - defaultMessage: 'Send a PagerDuty event', - }), - validate: (action: Action): any => { + validate: (action: Action): ValidationResult => { const validationResult = { errors: {} }; const errors = { routingKey: new Array(), @@ -28,14 +25,14 @@ export function getActionType(): ActionTypeModel { validationResult.errors = errors; if (!action.secrets.routingKey) { errors.routingKey.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredRoutingKeyText', { + i18n.translate('xpack.alertingUI.sections.actionAdd.error.requiredRoutingKeyText', { defaultMessage: 'RoutingKey is required.', }) ); } if (!action.config.apiUrl) { errors.apiUrl.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredApiUrlText', { + i18n.translate('xpack.alertingUI.sections.actionAdd.error.requiredApiUrlText', { defaultMessage: 'ApiUrl is required.', }) ); @@ -63,12 +60,9 @@ const PagerDutyActionFields: React.FunctionComponent = ({ fullWidth errors={errors} isShowingErrors={hasErrors === true && apiUrl !== undefined} - label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.pagerDutyAction.apiUrlFieldLabel', - { - defaultMessage: 'ApiUrl', - } - )} + label={i18n.translate('xpack.alertingUI.sections.actionAdd.apiUrlFieldLabel', { + defaultMessage: 'ApiUrl', + })} > = ({ fullWidth errors={errors} isShowingErrors={hasErrors === true && routingKey !== undefined} - label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.pagerDutyAction.routingKeyFieldLabel', - { - defaultMessage: 'RoutingKey', - } - )} + label={i18n.translate('xpack.alertingUI.sections.actionAdd.routingKeyFieldLabel', { + defaultMessage: 'RoutingKey', + })} > { + selectMessage: i18n.translate('xpack.alertingUI.sections.actionAdd.selectMessageText', { + defaultMessage: 'Add an item to the logs.', + }), + validate: (): ValidationResult => { return { errors: {} }; }, actionFields: null, diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx index 3fb2e96f59447a..c051ce6b12b189 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx @@ -7,25 +7,16 @@ import React, { Fragment } from 'react'; import { EuiFieldText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ErrableFormRow } from '../../../components/page_error'; -import { ActionTypeModel, Props, Action } from '../../../../types'; +import { ActionTypeModel, Props, Action, ValidationResult } from '../../../../types'; export function getActionType(): ActionTypeModel { return { id: '.slack', iconClass: 'logoSlack', - selectMessage: i18n.translate( - 'xpack.alertingUI.sections.actions.slackAction.selectMessageText', - { - defaultMessage: 'Send a message to a Slack user or channel.', - } - ), - simulatePrompt: i18n.translate( - 'xpack.alertingUI.sections.actions.slackAction.simulateButtonLabel', - { - defaultMessage: 'Send a sample message', - } - ), - validate: (action: Action): any => { + selectMessage: i18n.translate('xpack.alertingUI.sections.actionAdd.selectMessageText', { + defaultMessage: 'Send a message to a Slack user or channel.', + }), + validate: (action: Action): ValidationResult => { const validationResult = { errors: {} }; const errors = { webhookUrl: new Array(), @@ -33,7 +24,7 @@ export function getActionType(): ActionTypeModel { validationResult.errors = errors; if (!action.secrets.webhookUrl) { errors.webhookUrl.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredWebhookUrlText', { + i18n.translate('xpack.alertingUI.sections.actionAdd.error.requiredWebhookUrlText', { defaultMessage: 'WebhookUrl is required.', }) ); @@ -50,7 +41,7 @@ const SlackActionFields: React.FunctionComponent = ({ errors, hasErrors, }) => { - const { webhookUrl }: any = action.secrets; + const { webhookUrl } = action.secrets; return ( @@ -60,12 +51,9 @@ const SlackActionFields: React.FunctionComponent = ({ fullWidth errors={errors} isShowingErrors={hasErrors === true && webhookUrl !== undefined} - label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.slackPassword.methodWebhookUrlLabel', - { - defaultMessage: 'WebhookUrl', - } - )} + label={i18n.translate('xpack.alertingUI.sections.actionAdd.methodWebhookUrlLabel', { + defaultMessage: 'WebhookUrl', + })} > { + validate: (action: Action): ValidationResult => { const validationResult = { errors: {} }; const errors = { url: new Array(), @@ -44,7 +41,7 @@ export function getActionType(): ActionTypeModel { validationResult.errors = errors; if (!action.config.url) { errors.url.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredUrlText', { + i18n.translate('xpack.alertingUI.sections.actionAdd.error.requiredUrlText', { defaultMessage: 'Url is required.', }) ); @@ -86,8 +83,8 @@ const WebhookActionFields: React.FunctionComponent = ({ const [headerKey, setHeaderKey] = useState(''); const [headerValue, setHeaderValue] = useState(''); - const { user, password }: any = action.secrets; - const { method, url, headers }: any = action.config; + const { user, password } = action.secrets; + const { method, url, headers } = action.config; editActionConfig('method', 'post'); // set method to POST by default @@ -138,7 +135,7 @@ const WebhookActionFields: React.FunctionComponent = ({ @@ -160,7 +157,7 @@ const WebhookActionFields: React.FunctionComponent = ({ errorKey="url" errors={errors} isShowingErrors={hasErrors === true && url !== undefined} - label={i18n.translate('xpack.alertingUI.sections.slackPassword.methodUrlLabel', { + label={i18n.translate('xpack.alertingUI.sections.actionAdd.methodUrlLabel', { defaultMessage: 'Url', })} > @@ -189,7 +186,7 @@ const WebhookActionFields: React.FunctionComponent = ({ fullWidth errors={errors} isShowingErrors={hasErrors === true && user !== undefined} - label={i18n.translate('xpack.alertingUI.sections.webhookUser.userFieldLabel', { + label={i18n.translate('xpack.alertingUI.sections.actionAdd.userFieldLabel', { defaultMessage: 'User', })} > @@ -216,7 +213,7 @@ const WebhookActionFields: React.FunctionComponent = ({ fullWidth errors={errors} isShowingErrors={hasErrors === true && password !== undefined} - label={i18n.translate('xpack.alertingUI.sections.webhookPassword.methodPasswordLabel', { + label={i18n.translate('xpack.alertingUI.sections.actionAdd.methodPasswordLabel', { defaultMessage: 'Password', })} > @@ -248,7 +245,7 @@ const WebhookActionFields: React.FunctionComponent = ({ fullWidth errors={headerErrors} isShowingErrors={hasHeaderErrors && headerKey !== undefined} - label={i18n.translate('xpack.alertingUI.sections.webhookHeaders.keyFieldLabel', { + label={i18n.translate('xpack.alertingUI.sections.actionAdd.keyFieldLabel', { defaultMessage: 'Header Key', })} > @@ -270,7 +267,7 @@ const WebhookActionFields: React.FunctionComponent = ({ fullWidth errors={headerErrors} isShowingErrors={hasHeaderErrors && headerValue !== undefined} - label={i18n.translate('xpack.alertingUI.sections.webhookHeaders.valueFieldLabel', { + label={i18n.translate('xpack.alertingUI.sections.actionAdd.valueFieldLabel', { defaultMessage: 'Header Value', })} > @@ -292,8 +289,8 @@ const WebhookActionFields: React.FunctionComponent = ({ fill onClick={() => addHeader()} > - {i18n.translate('xpack.alertingUI.sections.webhookHeaders.AddHeaderButton', { - defaultMessage: 'Add header', + {i18n.translate('xpack.alertingUI.sections.actionAdd.addHeaderButton', { + defaultMessage: 'Add HTTP header', })} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx index 106f4140aeb651..e3fa94f5a7f63f 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx @@ -33,19 +33,13 @@ export const AlertingActionsDropdown: React.FunctionComponent = ({ if (!actionTypesIndex) { return null; } - const actions = Object.entries(!actionTypesIndex ? [] : actionTypesIndex) + const actions = Object.entries(actionTypesIndex) .filter(([index]) => actionTypeRegistry.get(index) !== null) .map(([index, actionType]) => { - const actionSettings = actionTypeRegistry.get(actionType.id); - const typeName = actionType.name; - const iconClass = actionSettings.iconClass; - const selectMessage = !actionSettings.selectMessage ? name : actionSettings.selectMessage; return { - id: index, - name: index.replace('.', ''), - typeName, - iconClass, - selectMessage, + ...actionTypeRegistry.get(actionType.id), + name: actionType.name, + typeName: index.replace('.', ''), }; }); @@ -79,9 +73,9 @@ export const AlertingActionsDropdown: React.FunctionComponent = ({ const description = action.selectMessage; return ( { setIsPopOverOpen(false); createAction(action); @@ -92,7 +86,7 @@ export const AlertingActionsDropdown: React.FunctionComponent = ({ - {action.typeName} + {action.name}

{description}

diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts index dcee6bdaabeed7..3da6b7e9e98390 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts @@ -15,7 +15,6 @@ export interface ActionTypeModel { id: string; iconClass: string; selectMessage: string; - simulatePrompt: string; validate: (action: Action) => ValidationResult; actionFields: React.FunctionComponent | null; } From b7bfa39406b1f684c9c530c5edcc1e06eef133f3 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 21 Oct 2019 18:21:50 -0700 Subject: [PATCH 074/297] Fixed comments from elastic/kibana-design --- x-pack/legacy/plugins/alerting_ui/index.ts | 1 - .../actions_list/components/create_menu_popover.tsx | 4 ++-- x-pack/legacy/plugins/alerting_ui/public/index.scss | 8 -------- 3 files changed, 2 insertions(+), 11 deletions(-) delete mode 100644 x-pack/legacy/plugins/alerting_ui/public/index.scss diff --git a/x-pack/legacy/plugins/alerting_ui/index.ts b/x-pack/legacy/plugins/alerting_ui/index.ts index 96b451d9cbe016..49e76764eb1382 100644 --- a/x-pack/legacy/plugins/alerting_ui/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/index.ts @@ -26,7 +26,6 @@ export function alertingUI(kibana: any) { }, uiExports: { hacks: ['plugins/alerting_ui/hacks/register'], - styleSheetPaths: resolve(__dirname, 'public/index.scss'), managementSections: ['plugins/alerting_ui'], }, }); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx index e3fa94f5a7f63f..e3c5beac7da78c 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx @@ -81,8 +81,8 @@ export const AlertingActionsDropdown: React.FunctionComponent = ({ createAction(action); }} > - - + + diff --git a/x-pack/legacy/plugins/alerting_ui/public/index.scss b/x-pack/legacy/plugins/alerting_ui/public/index.scss deleted file mode 100644 index 8bf963692ee58b..00000000000000 --- a/x-pack/legacy/plugins/alerting_ui/public/index.scss +++ /dev/null @@ -1,8 +0,0 @@ -// Import the EUI global scope so we can use EUI constants -@import 'src/legacy/ui/public/styles/_styling_constants'; - -// Alerting UI plugin styles - -.alertingUIActionContextMenuItem { - align-self: center; -} From 654ea75e1936142513d7b730bcb82cf5556542c2 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 21 Oct 2019 19:21:38 -0700 Subject: [PATCH 075/297] Removed unused types --- .../public/application/models/action.ts | 39 ------------------- .../sections/action_add/action_add.tsx | 29 ++++++++++++-- .../sections/action_add/action_reducer.ts | 17 ++++---- 3 files changed, 35 insertions(+), 50 deletions(-) delete mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/models/action.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/models/action.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/models/action.ts deleted file mode 100644 index fe845674202e2f..00000000000000 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/models/action.ts +++ /dev/null @@ -1,39 +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 { i18n } from '@kbn/i18n'; - -export class ActionModel { - id: string; - actionTypeId: string; - description: string; - config: Record; - secrets: Record; - - constructor(props = {}) { - this.id = get(props, 'id'); - this.actionTypeId = get(props, 'actionTypeId'); - this.description = get(props, 'description'); - this.config = get(props, 'config', {}); - this.secrets = get(props, 'secrets', {}); - } - - validate() { - const validationResult = { errors: {} }; - const errors = { - description: new Array(), - }; - validationResult.errors = errors; - if (!this.description) { - errors.description.push( - i18n.translate('xpack.watcher.sections.watchEdit.threshold.error.requiredNameText', { - defaultMessage: 'Description is required.', - }) - ); - } - return validationResult; - } -} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx index 37dc6d47ba211c..35012d2730245e 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx @@ -29,7 +29,6 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { saveAction } from '../../lib/api'; import { SectionError, ErrableFormRow } from '../../../application/components/page_error'; import { useAppDependencies } from '../..'; -import { ActionModel } from '../../models/action'; import { actionReducer } from './action_reducer'; import { ActionsContext } from '../../context/actions_context'; import { ActionType, Action } from '../../../types'; @@ -46,7 +45,7 @@ export const ActionAdd = ({ actionType, refreshList }: Props) => { const { flyoutVisible, setFlyoutVisibility, actionTypeRegistry } = useContext(ActionsContext); // hooks const [{ action }, dispatch] = useReducer(actionReducer, { - action: new ActionModel({ actionTypeId: actionType.id }), + action: { actionTypeId: actionType.id, config: {}, secrets: {} }, }); const setActionProperty = (property: string, value: any) => { @@ -62,7 +61,10 @@ export const ActionAdd = ({ actionType, refreshList }: Props) => { }; const getAction = () => { - dispatch({ command: 'setAction', payload: new ActionModel({ actionTypeId: actionType.id }) }); + dispatch({ + command: 'setAction', + payload: { actionTypeId: actionType.id, config: {}, secrets: {} }, + }); }; useEffect(() => { @@ -80,10 +82,29 @@ export const ActionAdd = ({ actionType, refreshList }: Props) => { return null; } + function validateBaseProperties(actionObject: Action) { + const validationResult = { errors: {} }; + const errors = { + description: new Array(), + }; + validationResult.errors = errors; + if (!actionObject.description) { + errors.description.push( + i18n.translate('xpack.alertingUI.sections.actionAdd.error.requiredNameText', { + defaultMessage: 'Description is required.', + }) + ); + } + return validationResult; + } + const actionTypeRegisterd = actionTypeRegistry.get(actionType.id); if (actionTypeRegisterd === null) return null; const FieldsComponent = actionTypeRegisterd.actionFields; - const errors = { ...actionTypeRegisterd.validate(action).errors, ...action.validate().errors }; + const errors = { + ...actionTypeRegisterd.validate(action).errors, + ...validateBaseProperties(action).errors, + }; const hasErrors = !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); return ( diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_reducer.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_reducer.ts index d9783beb156053..82f2b3d3a2263c 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_reducer.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_reducer.ts @@ -4,7 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ import { isEqual } from 'lodash'; -import { ActionModel } from '../../models/action'; + +export interface ActionState { + action: any; +} export const actionReducer = (state: any, actionItem: any) => { const { command, payload } = actionItem; @@ -23,10 +26,10 @@ export const actionReducer = (state: any, actionItem: any) => { } else { return { ...state, - action: new ActionModel({ + action: { ...action, [property]: value, - }), + }, }; } } @@ -37,13 +40,13 @@ export const actionReducer = (state: any, actionItem: any) => { } else { return { ...state, - action: new ActionModel({ + action: { ...action, config: { ...action.config, [property]: value, }, - }), + }, }; } } @@ -54,13 +57,13 @@ export const actionReducer = (state: any, actionItem: any) => { } else { return { ...state, - action: new ActionModel({ + action: { ...action, secrets: { ...action.secrets, [property]: value, }, - }), + }, }; } } From e5f56fc0a02f58dde6f92ac811a2c20500078bfd Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 21 Oct 2019 21:13:04 -0700 Subject: [PATCH 076/297] Changed Webhook action type form logic to hide text fields --- .../buildin_action_types/webhook.tsx | 129 +++++++++++------- 1 file changed, 77 insertions(+), 52 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx index 0db4ce5f54e268..6bfbb1eb23ba2b 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import React, { Fragment, useState } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; import { EuiFieldPassword, @@ -16,6 +17,7 @@ import { EuiButton, EuiButtonIcon, EuiText, + EuiTitle, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ErrableFormRow } from '../../../components/page_error'; @@ -82,6 +84,7 @@ const WebhookActionFields: React.FunctionComponent = ({ }) => { const [headerKey, setHeaderKey] = useState(''); const [headerValue, setHeaderValue] = useState(''); + const [isOpen, setOpen] = useState(false); const { user, password } = action.secrets; const { method, url, headers } = action.config; @@ -109,6 +112,10 @@ const WebhookActionFields: React.FunctionComponent = ({ const hasHeaderErrors = headerErrors.keyHeader.length > 0 || headerErrors.valueHeader.length > 0; function addHeader() { + if (!isOpen) { + setOpen(true); + return; + } if (headers && !!Object.keys(headers).find(key => key === headerKey)) { return; } @@ -130,6 +137,58 @@ const WebhookActionFields: React.FunctionComponent = ({ editActionConfig('headers', updatedHeaders); } + let headerControl; + if (isOpen) { + headerControl = ( + + + + { + setHeaderKey(e.target.value); + }} + /> + + + + + { + setHeaderValue(e.target.value); + }} + /> + + + + ); + } + return ( @@ -235,66 +294,32 @@ const WebhookActionFields: React.FunctionComponent = ({ - - - - - - { - setHeaderKey(e.target.value); - }} - /> - - - - - { - setHeaderValue(e.target.value); - }} - /> - - - addHeader()} > - {i18n.translate('xpack.alertingUI.sections.actionAdd.addHeaderButton', { - defaultMessage: 'Add HTTP header', - })} + + + + {headerControl} + {isOpen ? ( + +
+ +
+
+ ) : null} {Object.keys(headers || {}).map((key: string) => { return ( From ca069933efdb1867be50fc37f2635315bd03c236 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 22 Oct 2019 11:59:20 -0400 Subject: [PATCH 077/297] Initial work --- .../legacy/plugins/alerting/server/plugin.ts | 4 +- x-pack/legacy/plugins/alerting_ui/index.ts | 5 +- .../np_ready/public/application/app.tsx | 2 +- .../public/application/constants/index.ts | 4 +- .../application/context/alerts_context.tsx | 8 + .../np_ready/public/application/home.tsx | 17 +- .../np_ready/public/application/lib/api.ts | 54 +++- .../public/application/lib/breadcrumb.ts | 11 +- .../public/application/lib/doc_title.ts | 5 + .../alerts_list/components/alerts_list.tsx | 251 ++++++++++++++++++ .../alerting_ui/np_ready/public/plugin.ts | 6 +- .../alerting_ui/np_ready/public/types.ts | 27 ++ 12 files changed, 379 insertions(+), 15 deletions(-) create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/alerts_context.tsx create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx diff --git a/x-pack/legacy/plugins/alerting/server/plugin.ts b/x-pack/legacy/plugins/alerting/server/plugin.ts index d6c6d5907e7ac4..67ce5a0835a60d 100644 --- a/x-pack/legacy/plugins/alerting/server/plugin.ts +++ b/x-pack/legacy/plugins/alerting/server/plugin.ts @@ -70,7 +70,7 @@ export class Plugin { all: ['alert'], read: [], }, - ui: [], + ui: ['save', 'show', 'delete'], api: ['alerting-read', 'alerting-all'], }, read: { @@ -78,7 +78,7 @@ export class Plugin { all: [], read: ['alert'], }, - ui: [], + ui: ['show'], api: ['alerting-read'], }, }, diff --git a/x-pack/legacy/plugins/alerting_ui/index.ts b/x-pack/legacy/plugins/alerting_ui/index.ts index 49e76764eb1382..59a57fde4a9786 100644 --- a/x-pack/legacy/plugins/alerting_ui/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/index.ts @@ -15,7 +15,10 @@ export function alertingUI(kibana: any) { publicDir: resolve(__dirname, 'public'), require: ['kibana', 'actions'], isEnabled(config: Legacy.KibanaConfig) { - return config.get('xpack.alerting_ui.enabled') && config.get('xpack.actions.enabled'); + return ( + config.get('xpack.alerting_ui.enabled') && + (config.get('xpack.actions.enabled') || config.get('xpack.alerting.enabled')) + ); }, config(Joi: Root) { return Joi.object() diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx index dca3d92ae51eb0..d2bf883abc162e 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx @@ -28,7 +28,7 @@ class ShareRouter extends Component { } export const App = () => { - const sections: Section[] = ['actions']; + const sections: Section[] = ['alerts', 'actions']; const sectionsRegex = sections.join('|'); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts index baf7c50866c941..2c6ddffbc074a0 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts @@ -6,9 +6,11 @@ export const BASE_PATH = '/management/kibana/alerting'; export const BASE_ACTION_API_PATH = '/api/action'; +export const BASE_ALERT_API_PATH = '/api/alert'; export const DEFAULT_SECTION: Section = 'actions'; -export type Section = 'actions'; +export type Section = 'actions' | 'alerts'; export const routeToHome = `${BASE_PATH}`; export const routeToActions = `${BASE_PATH}/actions`; +export const routeToAlerts = `${BASE_PATH}/alerts`; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/alerts_context.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/alerts_context.tsx new file mode 100644 index 00000000000000..3ec66dfe2bc81a --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/alerts_context.tsx @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +export const AlertsContext = React.createContext({} as any); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx index ef05a0fb358e42..b5086ca93c99f6 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx @@ -8,12 +8,13 @@ import React, { useEffect } from 'react'; import { Route, RouteComponentProps, Switch } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiPageBody, EuiPageContent, EuiSpacer, EuiTab, EuiTabs } from '@elastic/eui'; -import { BASE_PATH, Section, routeToActions } from './constants'; +import { BASE_PATH, Section, routeToActions, routeToAlerts } from './constants'; import { breadcrumbService } from './lib/breadcrumb'; import { docTitleService } from './lib/doc_title'; import { useAppDependencies } from './index'; import { ActionsList } from './sections/actions_list/components/actions_list'; +import { AlertsList } from './sections/alerts_list/components/alerts_list'; interface MatchParams { section: Section; @@ -30,19 +31,24 @@ export const AlertsUIHome: React.FunctionComponent = []; + if (canShowAlerts) { + tabs.push({ + id: 'alerts', + name: , + }); + } + if (canShowActions) { tabs.push({ id: 'actions', name: ( - + ), }); } @@ -77,6 +83,7 @@ export const AlertsUIHome: React.FunctionComponent {canShowActions && } + {canShowAlerts && } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index 744ac930455816..bc1e580e4879ba 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ import { HttpServiceBase } from 'kibana/public'; -import { BASE_ACTION_API_PATH } from '../constants'; -import { ActionType, Action } from '../../types'; +import { BASE_ACTION_API_PATH, BASE_ALERT_API_PATH } from '../constants'; +import { Action, ActionType, Alert, AlertType } from '../../types'; // We are assuming there won't be many actions. This is why we will load // all the actions in advance and assume the total count to not go over 100 or so. @@ -63,3 +63,53 @@ export async function saveAction({ export async function deleteActions({ ids, http }: DeleteActionsOpts): Promise { await Promise.all(ids.map(id => http.delete(`${BASE_ACTION_API_PATH}/${id}`))); } + +export interface LoadAlertTypesOpts { + http: HttpServiceBase; +} + +export type LoadAlertTypesResponse = AlertType[]; + +export async function loadAlertTypes({ + http, +}: LoadAlertTypesOpts): Promise { + return http.get(`${BASE_ALERT_API_PATH}/types`); +} + +export interface LoadAlertsOpts { + http: HttpServiceBase; + page: { index: number; size: number }; + searchText?: string; +} + +export interface LoadAlertsResponse { + page: number; + perPage: number; + total: number; + data: Alert[]; +} + +export async function loadAlerts({ + http, + page, + searchText, +}: LoadAlertsOpts): Promise { + return http.get(`${BASE_ALERT_API_PATH}/_find`, { + query: { + page: page.index + 1, + per_page: page.size, + // TODO: Add search fields + // search_fields: searchText ? '' : undefined, + search: searchText, + }, + }); +} + +export interface DeleteAlertsOpts { + ids: string[]; + http: HttpServiceBase; +} + +export async function deleteAlerts({ ids, http }: DeleteAlertsOpts): Promise { + await Promise.all(ids.map(id => http.delete(`${BASE_ALERT_API_PATH}/${id}`))); +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts index df06fdace62a4b..4d1d8f1c5de292 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts @@ -5,7 +5,7 @@ */ import { i18n } from '@kbn/i18n'; -import { routeToHome, routeToActions } from '../constants'; +import { routeToHome, routeToActions, routeToAlerts } from '../constants'; class BreadcrumbService { private chrome: any; @@ -43,6 +43,15 @@ class BreadcrumbService { href: `#${routeToActions}`, }, ]; + this.breadcrumbs.alerts = [ + ...this.breadcrumbs.home, + { + text: i18n.translate('xpack.alertingUI.alerts.breadcrumbTitle', { + defaultMessage: 'Alerts', + }), + href: `#${routeToAlerts}`, + }, + ]; } public setBreadcrumbs(type: string): void { diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/doc_title.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/doc_title.ts index 3b51191f021660..c9258afe0e2f71 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/doc_title.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/doc_title.ts @@ -21,6 +21,11 @@ class DocTitleService { defaultMessage: 'Actions', }); break; + case 'alerts': + updatedTitle = i18n.translate('xpack.alertingUI.alerts.breadcrumbTitle', { + defaultMessage: 'Alerts', + }); + break; default: updatedTitle = i18n.translate('xpack.alertingUI.home.breadcrumbTitle', { defaultMessage: 'Alerting UI', diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx new file mode 100644 index 00000000000000..ccb28642053c4d --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -0,0 +1,251 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import React, { Fragment, useEffect, useState } from 'react'; +// @ts-ignore: EuiSearchBar not exported in TypeScript +import { EuiBasicTable, EuiButton, EuiSearchBar, EuiSpacer } from '@elastic/eui'; +import { AlertsContext } from '../../../context/alerts_context'; +import { useAppDependencies } from '../../../index'; +import { Alert, AlertType, deleteAlerts, loadAlerts, loadAlertTypes } from '../../../lib/api'; + +type AlertTypeIndex = Record; +interface Pagination { + index: number; + size: number; +} +interface Data extends Alert { + alertType: AlertType['name']; +} + +export const AlertsList: React.FunctionComponent = () => { + const { + core: { http }, + plugins: { capabilities, toastNotifications }, + } = useAppDependencies(); + const canDelete = capabilities.get().alerting.delete; + + const [alertTypesIndex, setAlertTypesIndex] = useState(undefined); + const [alerts, setAlerts] = useState([]); + const [data, setData] = useState([]); + const [selectedItems, setSelectedItems] = useState([]); + const [isLoadingAlertTypes, setIsLoadingAlertTypes] = useState(false); + const [isLoadingAlerts, setIsLoadingAlerts] = useState(false); + const [isDeletingActions, setIsDeletingActions] = useState(false); + const [totalItemCount, setTotalItemCount] = useState(0); + const [page, setPage] = useState({ index: 0, size: 10 }); + const [searchText, setSearchText] = useState(undefined); + + useEffect(() => { + loadAlertsData(); + }, [page, searchText]); + + useEffect(() => { + (async () => { + try { + setIsLoadingAlertTypes(true); + const alertTypes = await loadAlertTypes({ http }); + const index: AlertTypeIndex = {}; + for (const alertType of alertTypes) { + index[alertType.id] = alertType; + } + setAlertTypesIndex(index); + } catch (e) { + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.alertingUI.sections.alertsList.unableToLoadAlertTypesMessage', + { defaultMessage: 'Unable to load alert types' } + ), + }); + } finally { + setIsLoadingAlertTypes(false); + } + })(); + }, []); + + useEffect(() => { + // Avoid flickering before alert types load + if (typeof alertTypesIndex === 'undefined') { + return; + } + const updatedData = alerts.map(alert => ({ + ...alert, + alertType: alertTypesIndex[alert.alertTypeId] + ? alertTypesIndex[alert.alertTypeId].name + : alert.alertTypeId, + })); + setData(updatedData); + }, [alerts, alertTypesIndex]); + + async function loadAlertsData() { + setIsLoadingAlerts(true); + try { + const alertsResponse = await loadAlerts({ http, page, searchText }); + setAlerts(alertsResponse.data); + setTotalItemCount(alertsResponse.total); + } catch (e) { + toastNotifications.addDanger({ + title: i18n.translate('xpack.alertingUI.sections.alertsList.unableToLoadAlertsMessage', { + defaultMessage: 'Unable to load alerts', + }), + }); + } finally { + setIsLoadingAlerts(false); + } + } + + async function deleteItems(items: Data[]) { + setIsDeletingActions(true); + const ids = items.map(item => item.id); + try { + await deleteAlerts({ http, ids }); + await loadAlertsData(); + } catch (e) { + toastNotifications.addDanger({ + title: i18n.translate('xpack.alertingUI.sections.alertsList.failedToDeleteAlertsMessage', { + defaultMessage: 'Failed to delete alert(s)', + }), + }); + // Refresh the alerts from the server, some alerts may have been deleted + await loadAlertsData(); + } finally { + setIsDeletingActions(false); + } + } + + async function deleteSelectedItems() { + await deleteItems(selectedItems); + } + + const alertsTableColumns = [ + { + field: 'alertType', + name: i18n.translate( + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.alertType', + { defaultMessage: 'Alert Type' } + ), + sortable: false, + truncateText: true, + }, + { + field: 'alertTypeParams', + name: i18n.translate( + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.alertTypeParams', + { defaultMessage: 'Params' } + ), + sortable: false, + truncateText: true, + }, + { + name: i18n.translate('xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions', { + defaultMessage: 'Actions', + }), + actions: [ + { + enabled: () => canDelete, + name: i18n.translate( + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.deleteAlertName', + { defaultMessage: 'Delete' } + ), + description: canDelete + ? i18n.translate( + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.deleteAlertDescription', + { defaultMessage: 'Delete this alert' } + ) + : i18n.translate( + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.deleteAlertDisabledDescription', + { defaultMessage: 'Unable to delete alerts' } + ), + type: 'icon', + icon: 'trash', + onClick: (item: Data) => deleteItems([item]), + }, + ], + }, + ]; + + return ( +
+ + + + setSearchText(queryText)} + filters={[ + { + type: 'field_value_selection', + field: 'type', + name: i18n.translate( + 'xpack.alertingUI.sections.alertsList.filters.alertTypeIdName', + { defaultMessage: 'Alert Type' } + ), + multiSelect: 'or', + options: Object.values(alertTypesIndex || {}) + .map(alertType => ({ + value: alertType.id, + name: alertType.name, + })) + .sort((a, b) => a.name.localeCompare(b.name)), + }, + ]} + toolsRight={[ + + + , + ]} + > + + + + ({ + 'data-test-subj': 'row', + })} + cellProps={() => ({ + 'data-test-subj': 'cell', + })} + data-test-subj="alertsTable" + pagination={{ + pageIndex: page.index, + pageSize: page.size, + totalItemCount, + }} + selection={{ + onSelectionChange(updatedSelectedItemsList: Data[]) { + setSelectedItems(updatedSelectedItemsList); + }, + }} + onChange={({ page: changedPage }: { page: Pagination }) => { + setPage(changedPage); + }} + > + + +
+ ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts index 8d64158cfb993c..05eb117b07d105 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts @@ -45,7 +45,8 @@ export class Plugin implements CorePlugin { } = plugins; const canShowActions = capabilities.get().actions.show; - if (canShowActions) { + const canShowAlerts = capabilities.get().alerting.show; + if (canShowActions || canShowAlerts) { const actionTypeRegistry = new ActionTypeRegistry(); this.actionTypeRegistry = actionTypeRegistry; @@ -67,9 +68,10 @@ export class Plugin implements CorePlugin { public start(core: CoreStart, plugins: any) { const { capabilities } = plugins; const canShowActions = capabilities.get().actions.show; + const canShowAlerts = capabilities.get().alerting.show; // Don't register routes when user doesn't have access to the application - if (!canShowActions) { + if (!canShowActions && !canShowAlerts) { return; } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts index 3da6b7e9e98390..641d38dd29f6a3 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts @@ -35,3 +35,30 @@ export interface Action { description: string; config: Record; } + +export interface AlertType { + id: string; + name: string; +} + +export interface AlertAction { + group: string; + id: string; + params: Record; +} + +export interface Alert { + id: string; + enabled: boolean; + alertTypeId: string; + interval: string; + actions: AlertAction[]; + alertTypeParams: Record; + scheduledTaskId?: string; + createdBy: string | null; + updatedBy: string | null; + apiKeyOwner?: string; + throttle: string | null; + muteAll: boolean; + mutedInstanceIds: string[]; +} From 957d7deb435c5b0491a710cfc3fb3ccf992f73cc Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 22 Oct 2019 09:01:48 -0700 Subject: [PATCH 078/297] Fixed form labels --- .../action_add/buildin_action_types/email.tsx | 54 +++++--- .../buildin_action_types/es_index.tsx | 11 +- .../buildin_action_types/pagerduty.tsx | 45 ++++--- .../buildin_action_types/server_log.tsx | 9 +- .../action_add/buildin_action_types/slack.tsx | 27 ++-- .../buildin_action_types/webhook.tsx | 119 ++++++++++++------ 6 files changed, 176 insertions(+), 89 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx index 599d0615c3fb19..e626183eb3852b 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx @@ -19,9 +19,12 @@ export function getActionType(): ActionTypeModel { return { id: '.email', iconClass: 'email', - selectMessage: i18n.translate('xpack.alertingUI.sections.actionAdd.selectMessageText', { - defaultMessage: 'Send an email.', - }), + selectMessage: i18n.translate( + 'xpack.alertingUI.sections.actionAdd.emailAction.selectMessageText', + { + defaultMessage: 'Send an email.', + } + ), validate: (action: Action): ValidationResult => { const validationResult = { errors: {} }; const errors = { @@ -91,9 +94,12 @@ const EmailActionFields: React.FunctionComponent = ({ fullWidth errors={errors} isShowingErrors={hasErrors === true && from !== undefined} - label={i18n.translate('xpack.alertingUI.sections.actionAdd.emailActionLabel', { - defaultMessage: 'From', - })} + label={i18n.translate( + 'xpack.alertingUI.sections.actionAdd.emailAction.fromTextFieldLabel', + { + defaultMessage: 'From', + } + )} > = ({ fullWidth errors={errors} isShowingErrors={hasErrors === true && host !== undefined} - label={i18n.translate('xpack.alertingUI.sections.actionAdd.emailHostLabel', { - defaultMessage: 'Host', - })} + label={i18n.translate( + 'xpack.alertingUI.sections.actionAdd.emailAction.hostTextFieldLabel', + { + defaultMessage: 'Host', + } + )} > = ({ fullWidth errors={errors} isShowingErrors={hasErrors === true && port !== undefined} - label={i18n.translate('xpack.alertingUI.sections.actionAdd.emailPortLabel', { - defaultMessage: 'Port', - })} + label={i18n.translate( + 'xpack.alertingUI.sections.actionAdd.emailAction.portTextFieldLabel', + { + defaultMessage: 'Port', + } + )} > = ({ fullWidth errors={errors} isShowingErrors={hasErrors === true && user !== undefined} - label={i18n.translate('xpack.alertingUI.sections.actionAdd.emailUserLabel', { - defaultMessage: 'User', - })} + label={i18n.translate( + 'xpack.alertingUI.sections.actionAdd.emailAction.userTextFieldLabel', + { + defaultMessage: 'User', + } + )} > = ({ fullWidth errors={errors} isShowingErrors={hasErrors === true && password !== undefined} - label={i18n.translate('xpack.alertingUI.sections.actionAdd.emailPasswordLabel', { - defaultMessage: 'Password', - })} + label={i18n.translate( + 'xpack.alertingUI.sections.actionAdd.emailAction.passwordFieldLabel', + { + defaultMessage: 'Password', + } + )} > { return { errors: {} }; }, @@ -27,7 +30,7 @@ const IndexActionFields: React.FunctionComponent = ({ action, editActionC return ( diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx index f36393f13dcf1d..57e57067dfeac3 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx @@ -13,9 +13,12 @@ export function getActionType(): ActionTypeModel { return { id: '.pagerduty', iconClass: 'apps', - selectMessage: i18n.translate('xpack.alertingUI.sections.actionAdd.selectMessageText', { - defaultMessage: 'Create an event in PagerDuty.', - }), + selectMessage: i18n.translate( + 'xpack.alertingUI.sections.actionAdd.pagerDutyAction.selectMessageText', + { + defaultMessage: 'Create an event in PagerDuty.', + } + ), validate: (action: Action): ValidationResult => { const validationResult = { errors: {} }; const errors = { @@ -25,16 +28,22 @@ export function getActionType(): ActionTypeModel { validationResult.errors = errors; if (!action.secrets.routingKey) { errors.routingKey.push( - i18n.translate('xpack.alertingUI.sections.actionAdd.error.requiredRoutingKeyText', { - defaultMessage: 'RoutingKey is required.', - }) + i18n.translate( + 'xpack.alertingUI.sections.actionAdd.pagerDutyAction.error.requiredRoutingKeyText', + { + defaultMessage: 'Routing Key is required.', + } + ) ); } if (!action.config.apiUrl) { errors.apiUrl.push( - i18n.translate('xpack.alertingUI.sections.actionAdd.error.requiredApiUrlText', { - defaultMessage: 'ApiUrl is required.', - }) + i18n.translate( + 'xpack.alertingUI.sections.actionAdd.pagerDutyAction.error.requiredApiUrlText', + { + defaultMessage: 'ApiUrl is required.', + } + ) ); } return validationResult; @@ -60,9 +69,12 @@ const PagerDutyActionFields: React.FunctionComponent = ({ fullWidth errors={errors} isShowingErrors={hasErrors === true && apiUrl !== undefined} - label={i18n.translate('xpack.alertingUI.sections.actionAdd.apiUrlFieldLabel', { - defaultMessage: 'ApiUrl', - })} + label={i18n.translate( + 'xpack.alertingUI.sections.actionAdd.pagerDutyAction.apiUrlTextFieldLabel', + { + defaultMessage: 'ApiUrl', + } + )} > = ({ fullWidth errors={errors} isShowingErrors={hasErrors === true && routingKey !== undefined} - label={i18n.translate('xpack.alertingUI.sections.actionAdd.routingKeyFieldLabel', { - defaultMessage: 'RoutingKey', - })} + label={i18n.translate( + 'xpack.alertingUI.sections.actionAdd.pagerDutyAction.routingKeyTextFieldLabel', + { + defaultMessage: 'RoutingKey', + } + )} > { return { errors: {} }; }, diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx index c051ce6b12b189..e3b174b31f81cd 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx @@ -13,9 +13,12 @@ export function getActionType(): ActionTypeModel { return { id: '.slack', iconClass: 'logoSlack', - selectMessage: i18n.translate('xpack.alertingUI.sections.actionAdd.selectMessageText', { - defaultMessage: 'Send a message to a Slack user or channel.', - }), + selectMessage: i18n.translate( + 'xpack.alertingUI.sections.actionAdd.slackAction.selectMessageText', + { + defaultMessage: 'Send a message to a Slack user or channel.', + } + ), validate: (action: Action): ValidationResult => { const validationResult = { errors: {} }; const errors = { @@ -24,9 +27,12 @@ export function getActionType(): ActionTypeModel { validationResult.errors = errors; if (!action.secrets.webhookUrl) { errors.webhookUrl.push( - i18n.translate('xpack.alertingUI.sections.actionAdd.error.requiredWebhookUrlText', { - defaultMessage: 'WebhookUrl is required.', - }) + i18n.translate( + 'xpack.alertingUI.sections.actionAdd.slackAction.error.requiredWebhookUrlText', + { + defaultMessage: 'WebhookUrl is required.', + } + ) ); } return validationResult; @@ -51,9 +57,12 @@ const SlackActionFields: React.FunctionComponent = ({ fullWidth errors={errors} isShowingErrors={hasErrors === true && webhookUrl !== undefined} - label={i18n.translate('xpack.alertingUI.sections.actionAdd.methodWebhookUrlLabel', { - defaultMessage: 'WebhookUrl', - })} + label={i18n.translate( + 'xpack.alertingUI.sections.actionAdd.slackAction.webhookUrlTextFieldLabel', + { + defaultMessage: 'WebhookUrl', + } + )} > { const validationResult = { errors: {} }; const errors = { @@ -43,30 +46,42 @@ export function getActionType(): ActionTypeModel { validationResult.errors = errors; if (!action.config.url) { errors.url.push( - i18n.translate('xpack.alertingUI.sections.actionAdd.error.requiredUrlText', { - defaultMessage: 'Url is required.', - }) + i18n.translate( + 'xpack.alertingUI.sections.actionAdd.webhookAction.error.requiredUrlText', + { + defaultMessage: 'Url is required.', + } + ) ); } if (!action.config.method) { errors.method.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredMethodText', { - defaultMessage: 'Method is required.', - }) + i18n.translate( + 'xpack.alertingUI.sections.addAction.webhookAction.error.requiredMethodText', + { + defaultMessage: 'Method is required.', + } + ) ); } if (!action.secrets.user) { errors.user.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHostText', { - defaultMessage: 'User is required.', - }) + i18n.translate( + 'xpack.alertingUI.sections.addAction.webhookAction.error.requiredHostText', + { + defaultMessage: 'User is required.', + } + ) ); } if (!action.secrets.password) { errors.password.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHostText', { - defaultMessage: 'Password is required.', - }) + i18n.translate( + 'xpack.alertingUI.sections.addAction.webhookAction.error.requiredPasswordText', + { + defaultMessage: 'Password is required.', + } + ) ); } return validationResult; @@ -97,16 +112,22 @@ const WebhookActionFields: React.FunctionComponent = ({ }; if (!headerKey && headerValue) { headerErrors.keyHeader.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHeaderKeyText', { - defaultMessage: 'Header Key is required.', - }) + i18n.translate( + 'xpack.alertingUI.sections.addAction.webhookAction.error.requiredHeaderKeyText', + { + defaultMessage: 'Header Key is required.', + } + ) ); } if (headerKey && !headerValue) { headerErrors.valueHeader.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHeaderValueText', { - defaultMessage: 'Header Value is required.', - }) + i18n.translate( + 'xpack.alertingUI.sections.addAction.webhookAction.error.requiredHeaderValueText', + { + defaultMessage: 'Header Value is required.', + } + ) ); } const hasHeaderErrors = headerErrors.keyHeader.length > 0 || headerErrors.valueHeader.length > 0; @@ -148,9 +169,12 @@ const WebhookActionFields: React.FunctionComponent = ({ fullWidth errors={headerErrors} isShowingErrors={hasHeaderErrors && headerKey !== undefined} - label={i18n.translate('xpack.alertingUI.sections.actionAdd.keyFieldLabel', { - defaultMessage: 'Header Key', - })} + label={i18n.translate( + 'xpack.alertingUI.sections.actionAdd.webhookAction.keyTextFieldLabel', + { + defaultMessage: 'Header Key', + } + )} > = ({ fullWidth errors={headerErrors} isShowingErrors={hasHeaderErrors && headerValue !== undefined} - label={i18n.translate('xpack.alertingUI.sections.actionAdd.valueFieldLabel', { - defaultMessage: 'Header Value', - })} + label={i18n.translate( + 'xpack.alertingUI.sections.actionAdd.webhookAction.valueTextFieldLabel', + { + defaultMessage: 'Header Value', + } + )} > = ({ = ({ errorKey="url" errors={errors} isShowingErrors={hasErrors === true && url !== undefined} - label={i18n.translate('xpack.alertingUI.sections.actionAdd.methodUrlLabel', { - defaultMessage: 'Url', - })} + label={i18n.translate( + 'xpack.alertingUI.sections.actionAdd.webhookAction.urlTextFieldLabel', + { + defaultMessage: 'Url', + } + )} > = ({ fullWidth errors={errors} isShowingErrors={hasErrors === true && user !== undefined} - label={i18n.translate('xpack.alertingUI.sections.actionAdd.userFieldLabel', { - defaultMessage: 'User', - })} + label={i18n.translate( + 'xpack.alertingUI.sections.actionAdd.webhookAction.userTextFieldLabel', + { + defaultMessage: 'User', + } + )} > = ({ fullWidth errors={errors} isShowingErrors={hasErrors === true && password !== undefined} - label={i18n.translate('xpack.alertingUI.sections.actionAdd.methodPasswordLabel', { - defaultMessage: 'Password', - })} + label={i18n.translate( + 'xpack.alertingUI.sections.actionAdd.webhookAction.passwordTextFieldLabel', + { + defaultMessage: 'Password', + } + )} > = ({
From 9ae683589e46cfc28d196b08555d059aa1b040b4 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 22 Oct 2019 09:40:44 -0700 Subject: [PATCH 079/297] Removed unused action type registry functionality --- .../public/application/action_type_registry.ts | 11 +---------- .../actions_list/components/create_menu_popover.tsx | 4 ++-- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/action_type_registry.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/action_type_registry.ts index ebe038cb97afac..c9c1fa0a7ba406 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/action_type_registry.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/action_type_registry.ts @@ -38,7 +38,7 @@ export class ActionTypeRegistry { } /** - * Returns an action type, throws if not registered + * Returns an action type, null if not registered */ public get(id: string): ActionTypeModel | null { if (!this.has(id)) { @@ -46,13 +46,4 @@ export class ActionTypeRegistry { } return this.actionTypes.get(id)!; } - - /** - * Returns a list of registered action types [{ id, name }] - */ - public list() { - return Array.from(this.actionTypes).map(([actionTypeId, actionType]) => ({ - id: actionTypeId, - })); - } } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx index e3c5beac7da78c..1104bf00933efc 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx @@ -34,7 +34,7 @@ export const AlertingActionsDropdown: React.FunctionComponent = ({ return null; } const actions = Object.entries(actionTypesIndex) - .filter(([index]) => actionTypeRegistry.get(index) !== null) + .filter(([index]) => actionTypeRegistry.has(index)) .map(([index, actionType]) => { return { ...actionTypeRegistry.get(actionType.id), @@ -52,7 +52,7 @@ export const AlertingActionsDropdown: React.FunctionComponent = ({ onClick={() => setIsPopOverOpen(!isPopoverOpen)} >
From b0604acb1131edd5e1a0c1b42056860e64ab76b4 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 22 Oct 2019 09:51:50 -0700 Subject: [PATCH 080/297] Fixed any types in Webhook form --- .../buildin_action_types/webhook.tsx | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx index f2d9a52d29a317..f6c7fcaf460776 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx @@ -99,7 +99,7 @@ const WebhookActionFields: React.FunctionComponent = ({ }) => { const [headerKey, setHeaderKey] = useState(''); const [headerValue, setHeaderValue] = useState(''); - const [isOpen, setOpen] = useState(false); + const [hasHeaders, setHasHeaders] = useState(false); const { user, password } = action.secrets; const { method, url, headers } = action.config; @@ -133,8 +133,8 @@ const WebhookActionFields: React.FunctionComponent = ({ const hasHeaderErrors = headerErrors.keyHeader.length > 0 || headerErrors.valueHeader.length > 0; function addHeader() { - if (!isOpen) { - setOpen(true); + if (!hasHeaders) { + setHasHeaders(true); return; } if (headers && !!Object.keys(headers).find(key => key === headerKey)) { @@ -148,18 +148,18 @@ const WebhookActionFields: React.FunctionComponent = ({ setHeaderValue(''); } - function removeHeader(objKey: string) { + function removeHeader(keyToRemove: string) { const updatedHeaders = Object.keys(headers) - .filter(key => key !== objKey) - .reduce((obj: any, key: string) => { - obj[key] = headers[key]; - return obj; + .filter(key => key !== keyToRemove) + .reduce((headerToRemove: Record, key: string) => { + headerToRemove[key] = headers[key]; + return headerToRemove; }, {}); editActionConfig('headers', updatedHeaders); } let headerControl; - if (isOpen) { + if (hasHeaders) { headerControl = ( @@ -335,7 +335,7 @@ const WebhookActionFields: React.FunctionComponent = ({ addHeader()} > @@ -349,7 +349,7 @@ const WebhookActionFields: React.FunctionComponent = ({ {headerControl} - {isOpen ? ( + {hasHeaders ? (
Date: Tue, 22 Oct 2019 13:37:13 -0400 Subject: [PATCH 081/297] Fix type check failures --- .../sections/alerts_list/components/alerts_list.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index ccb28642053c4d..263b4e26ca782f 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -11,7 +11,8 @@ import React, { Fragment, useEffect, useState } from 'react'; import { EuiBasicTable, EuiButton, EuiSearchBar, EuiSpacer } from '@elastic/eui'; import { AlertsContext } from '../../../context/alerts_context'; import { useAppDependencies } from '../../../index'; -import { Alert, AlertType, deleteAlerts, loadAlerts, loadAlertTypes } from '../../../lib/api'; +import { Alert, AlertType } from '../../../../types'; +import { deleteAlerts, loadAlerts, loadAlertTypes } from '../../../lib/api'; type AlertTypeIndex = Record; interface Pagination { From e1fc7ed68a7bc8fa6c3c9b951a48ea5a5390b3eb Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 22 Oct 2019 14:10:08 -0400 Subject: [PATCH 082/297] Move some TS interfaces to types.ts --- .../actions_list/components/actions_list.tsx | 17 ++++++--------- .../alerts_list/components/alerts_list.tsx | 21 ++++++------------- .../alerting_ui/np_ready/public/types.ts | 17 +++++++++++++++ 3 files changed, 29 insertions(+), 26 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 6d499aa6c0be7d..a8337019f78636 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -13,12 +13,7 @@ import { useAppDependencies } from '../../../index'; import { AlertingActionsDropdown } from './create_menu_popover'; import { ActionAdd } from '../../action_add'; import { deleteActions, loadAllActions, loadActionTypes } from '../../../lib/api'; -import { ActionType, Action } from '../../../../types'; - -type ActionTypeIndex = Record; -interface Data extends Action { - actionType: ActionType['name']; -} +import { ActionType, Action, ActionTableItem, ActionTypeIndex } from '../../../../types'; export const ActionsList: React.FunctionComponent = () => { const { @@ -30,8 +25,8 @@ export const ActionsList: React.FunctionComponent = () => { const [actionTypesIndex, setActionTypesIndex] = useState(undefined); const [actions, setActions] = useState([]); - const [data, setData] = useState([]); - const [selectedItems, setSelectedItems] = useState([]); + const [data, setData] = useState([]); + const [selectedItems, setSelectedItems] = useState([]); const [isLoadingActionTypes, setIsLoadingActionTypes] = useState(false); const [isLoadingActions, setIsLoadingActions] = useState(false); const [isDeletingActions, setIsDeletingActions] = useState(false); @@ -97,7 +92,7 @@ export const ActionsList: React.FunctionComponent = () => { } } - async function deleteItems(items: Data[]) { + async function deleteItems(items: ActionTableItem[]) { setIsDeletingActions(true); const ids = items.map(item => item.id); try { @@ -177,7 +172,7 @@ export const ActionsList: React.FunctionComponent = () => { ), type: 'icon', icon: 'trash', - onClick: (item: Data) => deleteItems([item]), + onClick: (item: ActionTableItem) => deleteItems([item]), }, ], }, @@ -213,7 +208,7 @@ export const ActionsList: React.FunctionComponent = () => { data-test-subj="actionsTable" pagination={true} selection={{ - onSelectionChange(updatedSelectedItemsList: Data[]) { + onSelectionChange(updatedSelectedItemsList: ActionTableItem[]) { setSelectedItems(updatedSelectedItemsList); }, }} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 263b4e26ca782f..2e04118adfcb21 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -11,18 +11,9 @@ import React, { Fragment, useEffect, useState } from 'react'; import { EuiBasicTable, EuiButton, EuiSearchBar, EuiSpacer } from '@elastic/eui'; import { AlertsContext } from '../../../context/alerts_context'; import { useAppDependencies } from '../../../index'; -import { Alert, AlertType } from '../../../../types'; +import { Alert, AlertTableItem, AlertTypeIndex, Pagination } from '../../../../types'; import { deleteAlerts, loadAlerts, loadAlertTypes } from '../../../lib/api'; -type AlertTypeIndex = Record; -interface Pagination { - index: number; - size: number; -} -interface Data extends Alert { - alertType: AlertType['name']; -} - export const AlertsList: React.FunctionComponent = () => { const { core: { http }, @@ -32,8 +23,8 @@ export const AlertsList: React.FunctionComponent = () => { const [alertTypesIndex, setAlertTypesIndex] = useState(undefined); const [alerts, setAlerts] = useState([]); - const [data, setData] = useState([]); - const [selectedItems, setSelectedItems] = useState([]); + const [data, setData] = useState([]); + const [selectedItems, setSelectedItems] = useState([]); const [isLoadingAlertTypes, setIsLoadingAlertTypes] = useState(false); const [isLoadingAlerts, setIsLoadingAlerts] = useState(false); const [isDeletingActions, setIsDeletingActions] = useState(false); @@ -99,7 +90,7 @@ export const AlertsList: React.FunctionComponent = () => { } } - async function deleteItems(items: Data[]) { + async function deleteItems(items: AlertTableItem[]) { setIsDeletingActions(true); const ids = items.map(item => item.id); try { @@ -163,7 +154,7 @@ export const AlertsList: React.FunctionComponent = () => { ), type: 'icon', icon: 'trash', - onClick: (item: Data) => deleteItems([item]), + onClick: (item: AlertTableItem) => deleteItems([item]), }, ], }, @@ -237,7 +228,7 @@ export const AlertsList: React.FunctionComponent = () => { totalItemCount, }} selection={{ - onSelectionChange(updatedSelectedItemsList: Data[]) { + onSelectionChange(updatedSelectedItemsList: AlertTableItem[]) { setSelectedItems(updatedSelectedItemsList); }, }} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts index 641d38dd29f6a3..be84747911c407 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts @@ -3,6 +3,10 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ + +export type ActionTypeIndex = Record; +export type AlertTypeIndex = Record; + export interface Props { action: Action; editActionConfig: (property: string, value: any) => void; @@ -11,6 +15,11 @@ export interface Props { hasErrors?: boolean; } +export interface Pagination { + index: number; + size: number; +} + export interface ActionTypeModel { id: string; iconClass: string; @@ -36,6 +45,10 @@ export interface Action { config: Record; } +export interface ActionTableItem extends Action { + actionType: ActionType['name']; +} + export interface AlertType { id: string; name: string; @@ -62,3 +75,7 @@ export interface Alert { muteAll: boolean; mutedInstanceIds: string[]; } + +export interface AlertTableItem extends Alert { + alertType: AlertType['name']; +} From dfccb5c1d949d623eae69105a7fe22b0737bb40b Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 22 Oct 2019 14:16:06 -0400 Subject: [PATCH 083/297] Change EuiBasicTable spacing to match actions table --- .../sections/alerts_list/components/alerts_list.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 2e04118adfcb21..6ab414a731e35b 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -208,7 +208,8 @@ export const AlertsList: React.FunctionComponent = () => { ]} > - + {/* Large to remain consistent with ActionsList table spacing */} + Date: Tue, 22 Oct 2019 20:05:13 -0700 Subject: [PATCH 084/297] Created Add Alert flyout skeleton --- .../sections/alert_add/alert_add.tsx | 59 +++++++++++++++++++ .../application/sections/alert_add/index.ts | 7 +++ .../alerts_list/components/alerts_list.tsx | 17 +++++- 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/index.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx new file mode 100644 index 00000000000000..4c0fdb4cb1a67d --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -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 React, { Fragment, useContext, useState, useCallback, useReducer, useEffect } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + EuiButton, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiTitle, + EuiForm, + EuiSpacer, + EuiButtonEmpty, + EuiFlyoutFooter, + EuiFlyoutBody, + EuiFlyoutHeader, + EuiFlyout, + EuiFieldText, +} from '@elastic/eui'; +import { useAppDependencies } from '../..'; +import { AlertsContext } from '../../context/alerts_context'; + +interface Props { + refreshList: () => Promise; +} + +export const AlertAdd = ({ refreshList }: Props) => { + const { + core: { http }, + } = useAppDependencies(); + const { alertFlyoutVisible, setAlertFlyoutVisibility } = useContext(AlertsContext); + const closeFlyout = useCallback(() => setAlertFlyoutVisibility(false), []); + + if (!alertFlyoutVisible) { + return null; + } + + return ( + + + +

+ +

+
+
+ + + + +
+ ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/index.ts new file mode 100644 index 00000000000000..f88a8bb1c49d01 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { AlertAdd } from './alert_add'; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 2e04118adfcb21..06e80720a55038 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -13,6 +13,7 @@ import { AlertsContext } from '../../../context/alerts_context'; import { useAppDependencies } from '../../../index'; import { Alert, AlertTableItem, AlertTypeIndex, Pagination } from '../../../../types'; import { deleteAlerts, loadAlerts, loadAlertTypes } from '../../../lib/api'; +import { AlertAdd } from '../../alert_add'; export const AlertsList: React.FunctionComponent = () => { const { @@ -31,6 +32,7 @@ export const AlertsList: React.FunctionComponent = () => { const [totalItemCount, setTotalItemCount] = useState(0); const [page, setPage] = useState({ index: 0, size: 10 }); const [searchText, setSearchText] = useState(undefined); + const [alertFlyoutVisible, setAlertFlyoutVisibility] = useState(false); useEffect(() => { loadAlertsData(); @@ -164,7 +166,7 @@ export const AlertsList: React.FunctionComponent = () => {
- + setSearchText(queryText)} filters={[ @@ -205,6 +207,18 @@ export const AlertsList: React.FunctionComponent = () => { defaultMessage="Delete" /> , + setAlertFlyoutVisibility(true)} + > + + , ]} > @@ -236,6 +250,7 @@ export const AlertsList: React.FunctionComponent = () => { setPage(changedPage); }} > +
From 464e28cabd8b8c82dd8acac24904f3757dd85ab1 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 22 Oct 2019 20:29:13 -0700 Subject: [PATCH 085/297] Added saving new Alert api method and alertReducer skeleton --- .../np_ready/public/application/lib/api.ts | 12 ++++ .../sections/action_add/action_add.tsx | 42 ++++++------ .../sections/alert_add/alert_add.tsx | 64 ++++++++++++++++++- .../sections/alert_add/alert_reducer.ts | 23 +++++++ 4 files changed, 118 insertions(+), 23 deletions(-) create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index bc1e580e4879ba..bc6229b8f20d72 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -113,3 +113,15 @@ export interface DeleteAlertsOpts { export async function deleteAlerts({ ids, http }: DeleteAlertsOpts): Promise { await Promise.all(ids.map(id => http.delete(`${BASE_ALERT_API_PATH}/${id}`))); } + +export async function saveAlert({ + http, + alert, +}: { + http: HttpServiceBase; + alert: Alert; +}): Promise { + return http.post(`${BASE_ALERT_API_PATH}`, { + body: JSON.stringify(alert), + }); +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx index 35012d2730245e..3fdcc85147422b 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx @@ -5,7 +5,6 @@ */ import React, { Fragment, useContext, useState, useCallback, useReducer, useEffect } from 'react'; import { HttpServiceBase } from 'kibana/public'; -import { toastNotifications } from 'ui/notify'; import { EuiButton, EuiFlexGroup, @@ -41,6 +40,7 @@ interface Props { export const ActionAdd = ({ actionType, refreshList }: Props) => { const { core: { http }, + plugins: { toastNotifications }, } = useAppDependencies(); const { flyoutVisible, setFlyoutVisibility, actionTypeRegistry } = useContext(ActionsContext); // hooks @@ -107,6 +107,25 @@ export const ActionAdd = ({ actionType, refreshList }: Props) => { }; const hasErrors = !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); + async function onActionSave(): Promise { + try { + const newAction = await saveAction({ http, action }); + toastNotifications.addSuccess( + i18n.translate('xpack.alertingUI.sections.actionAdd.saveSuccessNotificationText', { + defaultMessage: "Saved '{actionName}'", + values: { + actionName: newAction.description, + }, + }) + ); + return newAction; + } catch (error) { + return { + error, + }; + } + } + return ( @@ -238,7 +257,7 @@ export const ActionAdd = ({ actionType, refreshList }: Props) => { isLoading={isSaving} onClick={async () => { setIsSaving(true); - const savedAction = await onActionSave(http, action); + const savedAction = await onActionSave(); setIsSaving(false); if (savedAction && savedAction.error) { return setServerError(savedAction.error); @@ -258,22 +277,3 @@ export const ActionAdd = ({ actionType, refreshList }: Props) => { ); }; - -export async function onActionSave(http: HttpServiceBase, action: Action): Promise { - try { - const newAction = await saveAction({ http, action }); - toastNotifications.addSuccess( - i18n.translate('xpack.alertingUI.sections.actionAdd.saveSuccessNotificationText', { - defaultMessage: "Saved '{actionName}'", - values: { - actionName: newAction.description, - }, - }) - ); - return newAction; - } catch (error) { - return { - error, - }; - } -} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 4c0fdb4cb1a67d..cdbd8ab351dfed 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import React, { Fragment, useContext, useState, useCallback, useReducer, useEffect } from 'react'; +import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButton, @@ -21,7 +22,9 @@ import { EuiFieldText, } from '@elastic/eui'; import { useAppDependencies } from '../..'; +import { saveAlert } from '../../lib/api'; import { AlertsContext } from '../../context/alerts_context'; +import { alertReducer } from './alert_reducer'; interface Props { refreshList: () => Promise; @@ -30,16 +33,41 @@ interface Props { export const AlertAdd = ({ refreshList }: Props) => { const { core: { http }, + plugins: { toastNotifications }, } = useAppDependencies(); const { alertFlyoutVisible, setAlertFlyoutVisibility } = useContext(AlertsContext); + // hooks + const [{ alert }, dispatch] = useReducer(alertReducer, { + action: {}, + }); + const [isSaving, setIsSaving] = useState(false); const closeFlyout = useCallback(() => setAlertFlyoutVisibility(false), []); if (!alertFlyoutVisible) { return null; } + async function onSaveAlert(): Promise { + try { + const newAlert = await saveAlert({ http, alert }); + toastNotifications.addSuccess( + i18n.translate('xpack.alertingUI.sections.alertAdd.saveSuccessNotificationText', { + defaultMessage: "Saved '{alertName}'", + values: { + alertName: newAlert.id, + }, + }) + ); + return newAlert; + } catch (error) { + return { + error, + }; + } + } + return ( - +

@@ -53,7 +81,39 @@ export const AlertAdd = ({ refreshList }: Props) => { - + + + + setAlertFlyoutVisibility(false)}> + {i18n.translate('xpack.alertingUI.sections.alertAdd.cancelButtonLabel', { + defaultMessage: 'Cancel', + })} + + + + { + setIsSaving(true); + const savedAlert = await onSaveAlert(); + setIsSaving(false); + setAlertFlyoutVisibility(false); + refreshList(); + }} + > + + + + + ); }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts new file mode 100644 index 00000000000000..6353e49ffa04ed --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under 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 { isEqual } from 'lodash'; + +export interface AlertState { + alert: any; +} + +export const alertReducer = (state: any, action: any) => { + const { command, payload } = action; + const { alert } = state; + + switch (command) { + case 'setAlert': + return { + ...state, + alert: payload, + }; + } +}; From e091c56a076b6672d3cfb2dacc2dd0c219115d0f Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 23 Oct 2019 08:09:37 -0400 Subject: [PATCH 086/297] Modify some columns for actions list --- .../actions_list/components/actions_list.tsx | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index a8337019f78636..75323d5a95193c 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -119,36 +119,27 @@ export const ActionsList: React.FunctionComponent = () => { const actionsTableColumns = [ { - field: 'description', + field: 'actionType', name: i18n.translate( - 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.description', + 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.actionType', { - defaultMessage: 'Description', + defaultMessage: 'Type', } ), sortable: true, truncateText: true, }, { - field: 'actionType', + field: 'description', name: i18n.translate( - 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.actionType', + 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.description', { - defaultMessage: 'Action Type', + defaultMessage: 'Title', } ), sortable: true, truncateText: true, }, - { - field: 'config', - name: i18n.translate( - 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.config', - { defaultMessage: 'Config' } - ), - sortable: false, - truncateText: false, - }, { name: i18n.translate( 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.actions', @@ -219,7 +210,7 @@ export const ActionsList: React.FunctionComponent = () => { field: 'actionTypeId', name: i18n.translate( 'xpack.alertingUI.sections.actionsList.filters.actionTypeIdName', - { defaultMessage: 'Action Type' } + { defaultMessage: 'Type' } ), multiSelect: 'or', options: Object.values(actionTypesIndex || {}) From 85c63342469f350a14ecee213c7ce9a8102f5d8d Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 23 Oct 2019 08:13:59 -0400 Subject: [PATCH 087/297] Re-arrange some alerts list columns --- x-pack/legacy/plugins/alerting_ui/index.ts | 39 +++++++++++++++++++ .../alerts_list/components/alerts_list.tsx | 12 +++--- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/index.ts b/x-pack/legacy/plugins/alerting_ui/index.ts index 59a57fde4a9786..7d418ac62ed6e4 100644 --- a/x-pack/legacy/plugins/alerting_ui/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/index.ts @@ -31,5 +31,44 @@ export function alertingUI(kibana: any) { hacks: ['plugins/alerting_ui/hacks/register'], managementSections: ['plugins/alerting_ui'], }, + // TODO: Remove init + init(server: any) { + server.plugins.alerting.setup.registerType({ + id: 'test.always-firing', + name: 'Test: Always Firing', + actionGroups: ['default', 'other'], + async executor({ services, params, state }: any) { + let group = 'default'; + + if (params.groupsToScheduleActionsInSeries) { + const index = state.groupInSeriesIndex || 0; + group = params.groupsToScheduleActionsInSeries[index]; + } + + if (group) { + services + .alertInstanceFactory('1') + .replaceState({ instanceStateValue: true }) + .scheduleActions(group, { + instanceContextValue: true, + }); + } + await services.callCluster('index', { + index: params.index, + refresh: 'wait_for', + body: { + state, + params, + reference: params.reference, + source: 'alert:test.always-firing', + }, + }); + return { + globalStateValue: true, + groupInSeriesIndex: (state.groupInSeriesIndex || 0) + 1, + }; + }, + }); + }, }); } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index b59b707ee675f1..8acb6d39a74122 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -120,19 +120,19 @@ export const AlertsList: React.FunctionComponent = () => { field: 'alertType', name: i18n.translate( 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.alertType', - { defaultMessage: 'Alert Type' } + { defaultMessage: 'Type' } ), sortable: false, truncateText: true, }, { - field: 'alertTypeParams', + field: 'interval', name: i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.alertTypeParams', - { defaultMessage: 'Params' } + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.interval', + { defaultMessage: 'Runs every' } ), sortable: false, - truncateText: true, + truncateText: false, }, { name: i18n.translate('xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions', { @@ -175,7 +175,7 @@ export const AlertsList: React.FunctionComponent = () => { field: 'type', name: i18n.translate( 'xpack.alertingUI.sections.alertsList.filters.alertTypeIdName', - { defaultMessage: 'Alert Type' } + { defaultMessage: 'Type' } ), multiSelect: 'or', options: Object.values(alertTypesIndex || {}) From 35dd487b53fc4f8b7f3a13ff1f450dca11e78d1c Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 23 Oct 2019 14:52:37 -0700 Subject: [PATCH 088/297] Added alert type registry base structure --- .../application/action_type_registry.ts | 2 +- .../public/application/alert_type_registry.ts | 43 +++++++++++++++++++ .../np_ready/public/application/index.tsx | 6 ++- .../sections/alert_add/alert_types/index.ts | 16 +++++++ .../alert_add/alert_types/threshold.tsx | 11 +++++ .../alerting_ui/np_ready/public/plugin.ts | 14 +++++- .../alerting_ui/np_ready/public/types.ts | 4 ++ .../legacy/plugins/alerting_ui/public/shim.ts | 2 + 8 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/alert_type_registry.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/index.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold.tsx diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/action_type_registry.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/action_type_registry.ts index c9c1fa0a7ba406..829ed8ae2de8fd 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/action_type_registry.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/action_type_registry.ts @@ -24,7 +24,7 @@ export class ActionTypeRegistry { if (this.has(actionType.id)) { throw new Error( i18n.translate( - 'xpack.actions.actionTypeRegistry.register.duplicateActionTypeErrorMessage', + 'xpack.alertingUI.actionTypeRegistry.register.duplicateActionTypeErrorMessage', { defaultMessage: 'Action type "{id}" is already registered.', values: { diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/alert_type_registry.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/alert_type_registry.ts new file mode 100644 index 00000000000000..5213d9c59e168e --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/alert_type_registry.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import { AlertTypeModel } from '../types'; + +export class AlertTypeRegistry { + private readonly alertTypes: Map = new Map(); + + public has(id: string) { + return this.alertTypes.has(id); + } + + public register(alertType: AlertTypeModel) { + if (this.has(alertType.id)) { + throw new Error( + i18n.translate('xpack.alertingUI.alertTypeRegistry.register.duplicateAlertTypeError', { + defaultMessage: 'Alert type "{id}" is already registered.', + values: { + id: alertType.id, + }, + }) + ); + } + this.alertTypes.set(alertType.id, alertType); + } + + public get(id: string): AlertTypeModel | null { + if (!this.has(id)) { + return null; + } + return this.alertTypes.get(id)!; + } + + public list() { + return Array.from(this.alertTypes).map(([alertTypeId, alertType]) => ({ + id: alertTypeId, + })); + } +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/index.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/index.tsx index 46ea2e89a2a15c..32a7d580f3102f 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/index.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/index.tsx @@ -12,6 +12,7 @@ import { App } from './app'; import { AppDependencies, AppPlugins } from '../../../public/shim'; import { ActionTypeRegistry } from './action_type_registry'; +import { AlertTypeRegistry } from './alert_type_registry'; export { BASE_PATH as CLIENT_BASE_PATH } from './constants'; @@ -54,9 +55,10 @@ export const renderReact = async ( elem: HTMLElement | null, core: CoreStart, plugins: AppPlugins, - actionTypeRegistry: ActionTypeRegistry + actionTypeRegistry: ActionTypeRegistry, + alertTypeRegistry: AlertTypeRegistry ) => { - const Providers = getAppProviders({ core, plugins, actionTypeRegistry }); + const Providers = getAppProviders({ core, plugins, actionTypeRegistry, alertTypeRegistry }); render( diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/index.ts new file mode 100644 index 00000000000000..a0f2e5e6671c80 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/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. + */ + +import { getActionType as getThresholdAlertType } from './threshold'; +import { AlertTypeRegistry } from '../../../alert_type_registry'; + +export function registerAlertTypes({ + alertTypeRegistry, +}: { + alertTypeRegistry: AlertTypeRegistry; +}) { + alertTypeRegistry.register(getThresholdAlertType()); +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold.tsx new file mode 100644 index 00000000000000..4dc081ff32ac34 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold.tsx @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { AlertTypeModel } from '../../../../types'; + +export function getActionType(): AlertTypeModel { + return { id: 'threshold' }; +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts index 05eb117b07d105..f263a050338a4e 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts @@ -21,6 +21,7 @@ import { breadcrumbService } from './application/lib/breadcrumb'; import { docTitleService } from './application/lib/doc_title'; import { ActionTypeRegistry } from './application/action_type_registry'; import { registerBuiltInActionTypes } from './application/sections/action_add/buildin_action_types'; +import { AlertTypeRegistry } from './application/alert_type_registry'; export type Setup = void; export type Start = void; @@ -29,6 +30,7 @@ const REACT_ROOT_ID = 'alertingRoot'; export class Plugin implements CorePlugin { private actionTypeRegistry?: ActionTypeRegistry; + private alertTypeRegistry?: AlertTypeRegistry; constructor(initializerContext: PluginInitializerContext) {} @@ -50,6 +52,8 @@ export class Plugin implements CorePlugin { const actionTypeRegistry = new ActionTypeRegistry(); this.actionTypeRegistry = actionTypeRegistry; + this.alertTypeRegistry = new AlertTypeRegistry(); + registerBuiltInActionTypes({ actionTypeRegistry, }); @@ -112,8 +116,14 @@ export class Plugin implements CorePlugin { $scope.$$postDigest(() => { unmountReactApp(); const elReactRoot = document.getElementById(REACT_ROOT_ID); - if (elReactRoot && this.actionTypeRegistry) { - renderReact(elReactRoot, core, plugins, this.actionTypeRegistry); + if (elReactRoot && this.actionTypeRegistry && this.alertTypeRegistry) { + renderReact( + elReactRoot, + core, + plugins, + this.actionTypeRegistry, + this.alertTypeRegistry + ); } }); }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts index be84747911c407..d03f3787dde412 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts @@ -79,3 +79,7 @@ export interface Alert { export interface AlertTableItem extends Alert { alertType: AlertType['name']; } + +export interface AlertTypeModel { + id: string; +} diff --git a/x-pack/legacy/plugins/alerting_ui/public/shim.ts b/x-pack/legacy/plugins/alerting_ui/public/shim.ts index f8c041fd29b39c..1a655d5f9a74b3 100644 --- a/x-pack/legacy/plugins/alerting_ui/public/shim.ts +++ b/x-pack/legacy/plugins/alerting_ui/public/shim.ts @@ -10,6 +10,7 @@ import { CoreStart } from 'kibana/public'; import { toastNotifications } from 'ui/notify'; import { docTitle } from 'ui/doc_title/doc_title'; import { ActionTypeRegistry } from '../np_ready/public/application/action_type_registry'; +import { AlertTypeRegistry } from '../np_ready/public/application/alert_type_registry'; export interface AppPlugins { management: { @@ -24,6 +25,7 @@ export interface AppDependencies { core: CoreStart; plugins: AppPlugins; actionTypeRegistry: ActionTypeRegistry; + alertTypeRegistry: AlertTypeRegistry; } export function createShim() { From f475471fae0c3da1a615c730dfe06b6209e702ef Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 23 Oct 2019 20:42:59 -0700 Subject: [PATCH 089/297] Redesined add action menu functionality to use select flyout panel instead of dropdown menu --- .../application/context/actions_context.tsx | 12 ++- .../sections/action_add/action_add_flyout.tsx | 49 +++++++++ .../{action_add.tsx => action_add_form.tsx} | 52 +++------ .../sections/action_add/action_type_menu.tsx | 74 +++++++++++++ .../application/sections/action_add/index.ts | 2 +- .../actions_list/components/actions_list.tsx | 44 ++++---- .../components/create_menu_popover.tsx | 102 ------------------ .../alerts_list/components/alerts_list.tsx | 3 +- 8 files changed, 175 insertions(+), 163 deletions(-) create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_flyout.tsx rename x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/{action_add.tsx => action_add_form.tsx} (85%) create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_type_menu.tsx delete mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/actions_context.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/actions_context.tsx index 2cf59d001dd538..8213a25591a7a8 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/actions_context.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/actions_context.tsx @@ -5,4 +5,14 @@ */ import React from 'react'; -export const ActionsContext = React.createContext({} as any); +import { ActionTypeRegistry } from '../action_type_registry'; +import { ActionType } from '../../types'; +export const ActionsContext = React.createContext({} as IActionContext); + +export interface IActionContext { + flyoutVisible: boolean; + setFlyoutVisibility: React.Dispatch>; + actionTypeRegistry: ActionTypeRegistry; + actionTypesIndex: Record | undefined; + loadActions: () => Promise; +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_flyout.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_flyout.tsx new file mode 100644 index 00000000000000..28140c40c75c62 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_flyout.tsx @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React, { useContext, useCallback, useState, useEffect } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiTitle, EuiFlyoutHeader, EuiFlyout } from '@elastic/eui'; +import { ActionsContext } from '../../context/actions_context'; +import { ActionTypeMenu } from './action_type_menu'; +import { ActionAddForm } from './action_add_form'; +import { ActionType } from '../../../types'; + +export const ActionAddFlyout = () => { + const { flyoutVisible, setFlyoutVisibility } = useContext(ActionsContext); + const [actionType, setActionType] = useState(undefined); + const closeFlyout = useCallback(() => setFlyoutVisibility(false), []); + + useEffect(() => { + setActionType(undefined); + }, [flyoutVisible]); + + if (!flyoutVisible) { + return null; + } + + let currentForm; + if (!actionType) { + currentForm = ; + } else { + currentForm = ; + } + + return ( + + + +

+ +

+
+
+ {currentForm} +
+ ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx similarity index 85% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx rename to x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx index 3fdcc85147422b..0a96975ea3789a 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx @@ -3,14 +3,11 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, useContext, useState, useCallback, useReducer, useEffect } from 'react'; -import { HttpServiceBase } from 'kibana/public'; +import React, { Fragment, useContext, useState, useReducer, useEffect } from 'react'; import { EuiButton, EuiFlexGroup, EuiFlexItem, - EuiIcon, - EuiTitle, EuiForm, EuiCallOut, EuiLink, @@ -18,15 +15,13 @@ import { EuiSpacer, EuiButtonEmpty, EuiFlyoutFooter, - EuiFlyoutBody, - EuiFlyoutHeader, - EuiFlyout, EuiFieldText, + EuiFlyoutBody, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { saveAction } from '../../lib/api'; -import { SectionError, ErrableFormRow } from '../../../application/components/page_error'; +import { SectionError, ErrableFormRow } from '../../components/page_error'; import { useAppDependencies } from '../..'; import { actionReducer } from './action_reducer'; import { ActionsContext } from '../../context/actions_context'; @@ -34,15 +29,18 @@ import { ActionType, Action } from '../../../types'; interface Props { actionType: ActionType; - refreshList: () => Promise; } -export const ActionAdd = ({ actionType, refreshList }: Props) => { +interface IErrorObject { + [key: string]: string[]; +} + +export const ActionAddForm = ({ actionType }: Props) => { const { core: { http }, plugins: { toastNotifications }, } = useAppDependencies(); - const { flyoutVisible, setFlyoutVisibility, actionTypeRegistry } = useContext(ActionsContext); + const { setFlyoutVisibility, actionTypeRegistry, loadActions } = useContext(ActionsContext); // hooks const [{ action }, dispatch] = useReducer(actionReducer, { action: { actionTypeId: actionType.id, config: {}, secrets: {} }, @@ -70,18 +68,13 @@ export const ActionAdd = ({ actionType, refreshList }: Props) => { useEffect(() => { getAction(); setServerError(null); - }, [flyoutVisible]); + }, [actionType]); - const closeFlyout = useCallback(() => setFlyoutVisibility(false), []); const [isSaving, setIsSaving] = useState(false); const [serverError, setServerError] = useState<{ body: { message: string; error: string }; } | null>(null); - if (!flyoutVisible) { - return null; - } - function validateBaseProperties(actionObject: Action) { const validationResult = { errors: {} }; const errors = { @@ -104,7 +97,7 @@ export const ActionAdd = ({ actionType, refreshList }: Props) => { const errors = { ...actionTypeRegisterd.validate(action).errors, ...validateBaseProperties(action).errors, - }; + } as IErrorObject; const hasErrors = !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); async function onActionSave(): Promise { @@ -127,24 +120,7 @@ export const ActionAdd = ({ actionType, refreshList }: Props) => { } return ( - - - - - - - - -

- -

-
-
-
-
+ {serverError && ( @@ -263,7 +239,7 @@ export const ActionAdd = ({ actionType, refreshList }: Props) => { return setServerError(savedAction.error); } setFlyoutVisibility(false); - refreshList(); + loadActions(); }} > { -
+ ); }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_type_menu.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_type_menu.tsx new file mode 100644 index 00000000000000..0d26055ec1f085 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_type_menu.tsx @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React, { Fragment, useContext } from 'react'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiCard, + EuiIcon, + EuiFlexGrid, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiButtonEmpty, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { ActionType } from '../../../types'; +import { ActionsContext } from '../../context/actions_context'; + +interface Props { + setActionType: React.Dispatch>; +} + +export const ActionTypeMenu = ({ setActionType }: Props) => { + const { actionTypesIndex, actionTypeRegistry, setFlyoutVisibility } = useContext(ActionsContext); + if (!actionTypesIndex) { + return null; + } + const actionTypes = Object.entries(actionTypesIndex) + .filter(([index]) => actionTypeRegistry.has(index)) + .map(([index, actionType]) => { + const actionTypeModel = actionTypeRegistry.get(index); + return { + iconClass: actionTypeModel ? actionTypeModel.iconClass : '', + selectMessage: actionTypeModel ? actionTypeModel.selectMessage : '', + actionType, + name: actionType.name, + typeName: index.replace('.', ''), + }; + }); + + const cardNodes = actionTypes.map(function(item, index): any { + return ( + + } + title={item.name} + description={item.selectMessage} + onClick={() => setActionType(item.actionType)} + /> + + ); + }); + + return ( + + + {cardNodes} + + + + + setFlyoutVisibility(false)}> + {i18n.translate('xpack.alertingUI.sections.actionAdd.cancelButtonLabel', { + defaultMessage: 'Cancel', + })} + + + + + + ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/index.ts index 31241220a0b483..f72e619fbc126b 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { ActionAdd } from './action_add'; +export { ActionAddFlyout } from './action_add_flyout'; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 75323d5a95193c..2a9cafe5202f9a 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -10,10 +10,9 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { ActionsContext } from '../../../context/actions_context'; import { useAppDependencies } from '../../../index'; -import { AlertingActionsDropdown } from './create_menu_popover'; -import { ActionAdd } from '../../action_add'; import { deleteActions, loadAllActions, loadActionTypes } from '../../../lib/api'; -import { ActionType, Action, ActionTableItem, ActionTypeIndex } from '../../../../types'; +import { Action, ActionTableItem, ActionTypeIndex } from '../../../../types'; +import { ActionAddFlyout } from '../../action_add'; export const ActionsList: React.FunctionComponent = () => { const { @@ -31,7 +30,6 @@ export const ActionsList: React.FunctionComponent = () => { const [isLoadingActions, setIsLoadingActions] = useState(false); const [isDeletingActions, setIsDeletingActions] = useState(false); const [flyoutVisible, setFlyoutVisibility] = useState(false); - const [actionType, setActionTypeId] = useState(null); useEffect(() => { loadActions(); @@ -169,21 +167,19 @@ export const ActionsList: React.FunctionComponent = () => { }, ]; - function createAction(actionTypeItem: ActionType) { - setFlyoutVisibility(true); - setActionTypeId(actionTypeItem); - } - - let flyout = null; - if (actionType) { - flyout = ; - } - return (
- + { defaultMessage="Delete" /> , - , + fill + iconType="plusInCircleFilled" + iconSide="left" + onClick={() => setFlyoutVisibility(true)} + > + + , ], }} /> - {flyout} +
diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx deleted file mode 100644 index 1104bf00933efc..00000000000000 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/create_menu_popover.tsx +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import React, { useState, useContext } from 'react'; -import { - EuiSpacer, - EuiText, - EuiFlexItem, - EuiIcon, - EuiFlexGroup, - EuiButton, - EuiPopover, - EuiContextMenuPanel, - EuiContextMenuItem, -} from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { ActionsContext } from '../../../context/actions_context'; -import { ActionType } from '../../../../types'; - -interface Props { - actionTypesIndex: Record | undefined; - createAction: (actionTypeItem: ActionType) => void; -} - -export const AlertingActionsDropdown: React.FunctionComponent = ({ - actionTypesIndex, - createAction, -}) => { - const [isPopoverOpen, setIsPopOverOpen] = useState(false); - const { actionTypeRegistry } = useContext(ActionsContext); - if (!actionTypesIndex) { - return null; - } - const actions = Object.entries(actionTypesIndex) - .filter(([index]) => actionTypeRegistry.has(index)) - .map(([index, actionType]) => { - return { - ...actionTypeRegistry.get(actionType.id), - name: actionType.name, - typeName: index.replace('.', ''), - }; - }); - - const button = ( - setIsPopOverOpen(!isPopoverOpen)} - > - - - ); - - return ( - setIsPopOverOpen(false)} - panelPaddingSize="none" - anchorPosition="downLeft" - > - { - const isActionDisabled = false; - const description = action.selectMessage; - return ( - { - setIsPopOverOpen(false); - createAction(action); - }} - > - - - - - - {action.name} - - -

{description}

-
-
-
-
- ); - })} - /> -
- ); -}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index b59b707ee675f1..41a15ab5fb1642 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -208,6 +208,7 @@ export const AlertsList: React.FunctionComponent = () => { /> , { onClick={() => setAlertFlyoutVisibility(true)} > , From f690719da0de4e190069e283b5b1db4e2bead235 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 24 Oct 2019 10:48:55 -0400 Subject: [PATCH 090/297] Start adding alert list actions --- .../np_ready/public/application/lib/api.ts | 40 ++++++ .../alerts_list/components/alerts_list.tsx | 117 ++++++++++++++++-- 2 files changed, 149 insertions(+), 8 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index bc6229b8f20d72..1ebe9bd35d67ed 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -125,3 +125,43 @@ export async function saveAlert({ body: JSON.stringify(alert), }); } + +export async function enableAlert({ + id, + http, +}: { + id: string; + http: HttpServiceBase; +}): Promise { + await http.post(`${BASE_ALERT_API_PATH}/${id}/_enable`); +} + +export async function disableAlert({ + id, + http, +}: { + id: string; + http: HttpServiceBase; +}): Promise { + await http.post(`${BASE_ALERT_API_PATH}/${id}/_disable`); +} + +export async function muteAllAlertInstances({ + id, + http, +}: { + id: string; + http: HttpServiceBase; +}): Promise { + await http.post(`${BASE_ALERT_API_PATH}/${id}/_mute_all`); +} + +export async function unmuteAllAlertInstances({ + id, + http, +}: { + id: string; + http: HttpServiceBase; +}): Promise { + await http.post(`${BASE_ALERT_API_PATH}/${id}/_unmute_all`); +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 698e3445bc81c8..e16123a3b09cf6 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -12,8 +12,16 @@ import { EuiBasicTable, EuiButton, EuiSearchBar, EuiSpacer } from '@elastic/eui' import { AlertsContext } from '../../../context/alerts_context'; import { useAppDependencies } from '../../../index'; import { Alert, AlertTableItem, AlertTypeIndex, Pagination } from '../../../../types'; -import { deleteAlerts, loadAlerts, loadAlertTypes } from '../../../lib/api'; import { AlertAdd } from '../../alert_add'; +import { + deleteAlerts, + disableAlert, + enableAlert, + loadAlerts, + loadAlertTypes, + muteAllAlertInstances, + unmuteAllAlertInstances, +} from '../../../lib/api'; export const AlertsList: React.FunctionComponent = () => { const { @@ -21,6 +29,7 @@ export const AlertsList: React.FunctionComponent = () => { plugins: { capabilities, toastNotifications }, } = useAppDependencies(); const canDelete = capabilities.get().alerting.delete; + const canSave = capabilities.get().alerting.save; const [alertTypesIndex, setAlertTypesIndex] = useState(undefined); const [alerts, setAlerts] = useState([]); @@ -28,7 +37,7 @@ export const AlertsList: React.FunctionComponent = () => { const [selectedItems, setSelectedItems] = useState([]); const [isLoadingAlertTypes, setIsLoadingAlertTypes] = useState(false); const [isLoadingAlerts, setIsLoadingAlerts] = useState(false); - const [isDeletingActions, setIsDeletingActions] = useState(false); + const [isPerformingAction, setIsPerformingAction] = useState(false); const [totalItemCount, setTotalItemCount] = useState(0); const [page, setPage] = useState({ index: 0, size: 10 }); const [searchText, setSearchText] = useState(undefined); @@ -93,7 +102,7 @@ export const AlertsList: React.FunctionComponent = () => { } async function deleteItems(items: AlertTableItem[]) { - setIsDeletingActions(true); + setIsPerformingAction(true); const ids = items.map(item => item.id); try { await deleteAlerts({ http, ids }); @@ -107,7 +116,7 @@ export const AlertsList: React.FunctionComponent = () => { // Refresh the alerts from the server, some alerts may have been deleted await loadAlertsData(); } finally { - setIsDeletingActions(false); + setIsPerformingAction(false); } } @@ -141,6 +150,9 @@ export const AlertsList: React.FunctionComponent = () => { actions: [ { enabled: () => canDelete, + type: 'icon', + icon: 'trash', + onClick: (item: AlertTableItem) => deleteItems([item]), name: i18n.translate( 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.deleteAlertName', { defaultMessage: 'Delete' } @@ -154,9 +166,98 @@ export const AlertsList: React.FunctionComponent = () => { 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.deleteAlertDisabledDescription', { defaultMessage: 'Unable to delete alerts' } ), - type: 'icon', - icon: 'trash', - onClick: (item: AlertTableItem) => deleteItems([item]), + }, + { + enabled: () => canSave, + available: (item: AlertTableItem) => !item.enabled, + onClick: async (item: AlertTableItem) => { + setIsPerformingAction(true); + await enableAlert({ http, id: item.id }); + await loadAlertsData(); + setIsPerformingAction(false); + }, + name: i18n.translate( + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.enableAlertTitle', + { defaultMessage: 'Enable' } + ), + description: canSave + ? i18n.translate( + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.enableAlertDescription', + { defaultMessage: 'Enable this alert' } + ) + : i18n.translate( + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.enableAlertDisabledDescription', + { defaultMessage: 'Unable to enable alerts' } + ), + }, + { + enabled: () => canSave, + available: (item: AlertTableItem) => item.enabled, + onClick: async (item: AlertTableItem) => { + setIsPerformingAction(true); + await disableAlert({ http, id: item.id }); + await loadAlertsData(); + setIsPerformingAction(false); + }, + name: i18n.translate( + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.disableAlertTitle', + { defaultMessage: 'Disable' } + ), + description: canSave + ? i18n.translate( + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.disableAlertDescription', + { defaultMessage: 'Disable this alert' } + ) + : i18n.translate( + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.disableAlertDisabledDescription', + { defaultMessage: 'Unable to disable alerts' } + ), + }, + { + enabled: () => canSave, + available: (item: AlertTableItem) => !item.muteAll, + onClick: async (item: AlertTableItem) => { + setIsPerformingAction(true); + await muteAllAlertInstances({ http, id: item.id }); + await loadAlertsData(); + setIsPerformingAction(false); + }, + name: i18n.translate( + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.muteAllAlertInstancesTitle', + { defaultMessage: 'Mute all' } + ), + description: canSave + ? i18n.translate( + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.muteAllAlertInstancesDescription', + { defaultMessage: 'Mute all alert instances' } + ) + : i18n.translate( + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.muteAllAlertInstancesDisabledDescription', + { defaultMessage: 'Unable to mute all alert instances' } + ), + }, + { + enabled: () => canSave, + available: (item: AlertTableItem) => item.muteAll, + onClick: async (item: AlertTableItem) => { + setIsPerformingAction(true); + await unmuteAllAlertInstances({ http, id: item.id }); + await loadAlertsData(); + setIsPerformingAction(false); + }, + name: i18n.translate( + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.unmuteAllAlertInstancesTitle', + { defaultMessage: 'Unmute all' } + ), + description: canSave + ? i18n.translate( + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.unmuteAllAlertInstancesDescription', + { defaultMessage: 'Unmute all alert instances' } + ) + : i18n.translate( + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.unmuteAllAlertInstancesDisabledDescription', + { defaultMessage: 'Unable to unmute all alert instances' } + ), }, ], }, @@ -227,7 +328,7 @@ export const AlertsList: React.FunctionComponent = () => { Date: Thu, 24 Oct 2019 13:36:38 -0400 Subject: [PATCH 091/297] Add some icons to alerts list actions --- .../sections/alerts_list/components/alerts_list.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index e16123a3b09cf6..8d234c4a454129 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -169,6 +169,8 @@ export const AlertsList: React.FunctionComponent = () => { }, { enabled: () => canSave, + type: 'icon', + icon: 'play', available: (item: AlertTableItem) => !item.enabled, onClick: async (item: AlertTableItem) => { setIsPerformingAction(true); @@ -192,6 +194,8 @@ export const AlertsList: React.FunctionComponent = () => { }, { enabled: () => canSave, + type: 'icon', + icon: 'stop', available: (item: AlertTableItem) => item.enabled, onClick: async (item: AlertTableItem) => { setIsPerformingAction(true); @@ -214,6 +218,7 @@ export const AlertsList: React.FunctionComponent = () => { ), }, { + // TODO: Icon enabled: () => canSave, available: (item: AlertTableItem) => !item.muteAll, onClick: async (item: AlertTableItem) => { @@ -238,6 +243,8 @@ export const AlertsList: React.FunctionComponent = () => { }, { enabled: () => canSave, + type: 'icon', + icon: 'bell', available: (item: AlertTableItem) => item.muteAll, onClick: async (item: AlertTableItem) => { setIsPerformingAction(true); From aa46b2ac50c51697365b23fe28c5f2937d2ec5ec Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 24 Oct 2019 20:24:00 -0700 Subject: [PATCH 092/297] Added functionality for select alert type panel based on the registered alert types --- .../public/application/alert_type_registry.ts | 2 + .../application/context/actions_context.tsx | 2 - .../sections/action_add/action_add_form.tsx | 3 +- .../sections/action_add/action_type_menu.tsx | 4 +- .../actions_list/components/actions_list.tsx | 1 - .../sections/alert_add/alert_add.tsx | 208 +++++++++++++++++- .../alert_add/alert_types/threshold.tsx | 6 +- .../alerting_ui/np_ready/public/plugin.ts | 8 +- .../alerting_ui/np_ready/public/types.ts | 2 + 9 files changed, 227 insertions(+), 9 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/alert_type_registry.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/alert_type_registry.ts index 5213d9c59e168e..e92f843f4bd21a 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/alert_type_registry.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/alert_type_registry.ts @@ -38,6 +38,8 @@ export class AlertTypeRegistry { public list() { return Array.from(this.alertTypes).map(([alertTypeId, alertType]) => ({ id: alertTypeId, + name: alertType.name, + iconClass: alertType.iconClass, })); } } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/actions_context.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/actions_context.tsx index 8213a25591a7a8..4d4d38a8201907 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/actions_context.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/actions_context.tsx @@ -5,14 +5,12 @@ */ import React from 'react'; -import { ActionTypeRegistry } from '../action_type_registry'; import { ActionType } from '../../types'; export const ActionsContext = React.createContext({} as IActionContext); export interface IActionContext { flyoutVisible: boolean; setFlyoutVisibility: React.Dispatch>; - actionTypeRegistry: ActionTypeRegistry; actionTypesIndex: Record | undefined; loadActions: () => Promise; } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx index 0a96975ea3789a..64a9c03fbcf712 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx @@ -39,8 +39,9 @@ export const ActionAddForm = ({ actionType }: Props) => { const { core: { http }, plugins: { toastNotifications }, + actionTypeRegistry, } = useAppDependencies(); - const { setFlyoutVisibility, actionTypeRegistry, loadActions } = useContext(ActionsContext); + const { setFlyoutVisibility, loadActions } = useContext(ActionsContext); // hooks const [{ action }, dispatch] = useReducer(actionReducer, { action: { actionTypeId: actionType.id, config: {}, secrets: {} }, diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_type_menu.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_type_menu.tsx index 0d26055ec1f085..d9cc4a778f61af 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_type_menu.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_type_menu.tsx @@ -17,13 +17,15 @@ import { import { i18n } from '@kbn/i18n'; import { ActionType } from '../../../types'; import { ActionsContext } from '../../context/actions_context'; +import { useAppDependencies } from '../..'; interface Props { setActionType: React.Dispatch>; } export const ActionTypeMenu = ({ setActionType }: Props) => { - const { actionTypesIndex, actionTypeRegistry, setFlyoutVisibility } = useContext(ActionsContext); + const { actionTypeRegistry } = useAppDependencies(); + const { actionTypesIndex, setFlyoutVisibility } = useContext(ActionsContext); if (!actionTypesIndex) { return null; } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 2a9cafe5202f9a..92c2eff44e6e6d 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -175,7 +175,6 @@ export const ActionsList: React.FunctionComponent = () => { value={{ flyoutVisible, setFlyoutVisibility, - actionTypeRegistry, actionTypesIndex, loadActions, }} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index cdbd8ab351dfed..3c243b5a3fc640 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -20,11 +20,22 @@ import { EuiFlyoutHeader, EuiFlyout, EuiFieldText, + EuiFlexGrid, + EuiFormRow, + EuiComboBox, + EuiComboBoxOptionProps, + EuiCard, + EuiTabs, + EuiTab, + EuiText, + EuiLink, } from '@elastic/eui'; import { useAppDependencies } from '../..'; import { saveAlert } from '../../lib/api'; import { AlertsContext } from '../../context/alerts_context'; import { alertReducer } from './alert_reducer'; +import { ErrableFormRow } from '../../components/page_error'; +import { AlertTypeModel } from '../../../types'; interface Props { refreshList: () => Promise; @@ -34,18 +45,49 @@ export const AlertAdd = ({ refreshList }: Props) => { const { core: { http }, plugins: { toastNotifications }, + alertTypeRegistry, } = useAppDependencies(); const { alertFlyoutVisible, setAlertFlyoutVisibility } = useContext(AlertsContext); // hooks const [{ alert }, dispatch] = useReducer(alertReducer, { - action: {}, + alert: { + validate: () => { + return { errors: {} }; + }, + }, }); const [isSaving, setIsSaving] = useState(false); + const [selectedTabId, setSelectedTabId] = useState('alert'); + const [alertType, setAlertType] = useState(undefined); const closeFlyout = useCallback(() => setAlertFlyoutVisibility(false), []); + const setAlertProperty = (property: string, value: any) => { + dispatch({ command: 'setProperty', payload: { property, value } }); + }; + if (!alertFlyoutVisible) { return null; } + const { errors } = alert.validate(); + const tagsOptions = []; + + const hasErrors = !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); + + const tabs = [ + { + id: 'alert', + name: 'Alert', + }, + { + id: 'warning', + name: 'Warning', + }, + { + id: 'escalation', + name: 'Escalation', + disabled: false, + }, + ]; async function onSaveAlert(): Promise { try { @@ -66,6 +108,103 @@ export const AlertAdd = ({ refreshList }: Props) => { } } + const alertTypeNodes = alertTypeRegistry.list().map(function(item, index): any { + return ( + + } + title={item.name} + description={''} + onClick={() => setAlertType(item)} + /> + + ); + }); + + const alertTabs = tabs.map(function(tab, index): any { + return ( + setSelectedTabId(tab.id)} + isSelected={tab.id === selectedTabId} + disabled={tab.disabled} + key={index} + > + {tab.name} + + ); + }); + + const alertDetails = ( + + + + +
+ +
+
+
+ + setAlertType(undefined)}> + + + +
+
+ ); + + const warningDetails = Warning; + + const escalationDetails = Escalation; + + let selectedTabContent; + switch (selectedTabId) { + case 'alert': + selectedTabContent = alertDetails; + break; + case 'warning': + selectedTabContent = warningDetails; + break; + case 'escalation': + selectedTabContent = escalationDetails; + break; + default: + selectedTabContent = null; + } + + let alertTypeArea; + if (alertType) { + alertTypeArea = ( + + {alertTabs} + + {selectedTabContent} + + ); + } else { + alertTypeArea = ( + + + +
+ +
+
+ + {alertTypeNodes} +
+ ); + } + return ( @@ -79,7 +218,72 @@ export const AlertAdd = ({ refreshList }: Props) => { - + + + + + } + errorKey="name" + isShowingErrors={hasErrors && alert.name !== undefined} + errors={errors} + > + { + setAlertProperty('name', e.target.value); + }} + onBlur={() => { + if (!alert.name) { + setAlertProperty('name', ''); + } + }} + /> + + + + + { + return { + label: anIndex, + value: anIndex, + }; + })} + onChange={async (selected: EuiComboBoxOptionProps[]) => { + setAlertProperty('tags', selected.map(aSelected => aSelected.value)); + }} + onBlur={() => { + if (!alert.tags) { + setAlertProperty('tags', []); + } + }} + /> + + + + {alertTypeArea} + diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold.tsx index 4dc081ff32ac34..6912d7b77f29fd 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold.tsx @@ -7,5 +7,9 @@ import { AlertTypeModel } from '../../../../types'; export function getActionType(): AlertTypeModel { - return { id: 'threshold' }; + return { + id: 'threshold', + name: 'Index Threshold', + iconClass: 'alert', + }; } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts index f263a050338a4e..ba657d4d75ef05 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts @@ -22,6 +22,7 @@ import { docTitleService } from './application/lib/doc_title'; import { ActionTypeRegistry } from './application/action_type_registry'; import { registerBuiltInActionTypes } from './application/sections/action_add/buildin_action_types'; import { AlertTypeRegistry } from './application/alert_type_registry'; +import { registerAlertTypes } from './application/sections/alert_add/alert_types'; export type Setup = void; export type Start = void; @@ -52,12 +53,17 @@ export class Plugin implements CorePlugin { const actionTypeRegistry = new ActionTypeRegistry(); this.actionTypeRegistry = actionTypeRegistry; - this.alertTypeRegistry = new AlertTypeRegistry(); + const alertTypeRegistry = new AlertTypeRegistry(); + this.alertTypeRegistry = alertTypeRegistry; registerBuiltInActionTypes({ actionTypeRegistry, }); + registerAlertTypes({ + alertTypeRegistry, + }); + const kbnSection = getSection('kibana'); kbnSection.register('alerting', { display: i18n.translate('xpack.alertingUI.managementSection.displayName', { diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts index d03f3787dde412..25a29175fe3bd8 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts @@ -82,4 +82,6 @@ export interface AlertTableItem extends Alert { export interface AlertTypeModel { id: string; + name: string; + iconClass: string; } From 4ac6c9a3f07a0e9319acec044a335fa24f98f6e4 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Sun, 27 Oct 2019 15:56:57 -0700 Subject: [PATCH 093/297] Added index threshold alert type expression base --- .../public/application/alert_type_registry.ts | 1 + .../constants/aggregation_types.ts | 17 ++ .../application/constants/comparators.ts | 13 ++ .../public/application/constants/index.ts | 7 + .../actions_list/components/actions_list.tsx | 1 - .../sections/alert_add/alert_add.tsx | 42 +++- .../sections/alert_add/alert_reducer.ts | 31 +++ .../alert_add/alert_types/threshold.tsx | 209 +++++++++++++++++- .../sections/alert_add/alert_types/types.ts | 25 +++ .../alerting_ui/np_ready/public/types.ts | 2 + 10 files changed, 342 insertions(+), 6 deletions(-) create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/aggregation_types.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/comparators.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/types.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/alert_type_registry.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/alert_type_registry.ts index e92f843f4bd21a..6098001d184202 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/alert_type_registry.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/alert_type_registry.ts @@ -40,6 +40,7 @@ export class AlertTypeRegistry { id: alertTypeId, name: alertType.name, iconClass: alertType.iconClass, + alertType, })); } } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/aggregation_types.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/aggregation_types.ts new file mode 100644 index 00000000000000..68c2818502b2c2 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/aggregation_types.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. + */ + +export const AGGREGATION_TYPES: { [key: string]: string } = { + COUNT: 'count', + + AVERAGE: 'avg', + + SUM: 'sum', + + MIN: 'min', + + MAX: 'max', +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/comparators.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/comparators.ts new file mode 100644 index 00000000000000..21b350c0f8ce41 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/comparators.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under 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 COMPARATORS: { [key: string]: string } = { + GREATER_THAN: '>', + GREATER_THAN_OR_EQUALS: '>=', + BETWEEN: 'between', + LESS_THAN: '<', + LESS_THAN_OR_EQUALS: '<=', +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts index 2c6ddffbc074a0..b1d5aff54cded2 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts @@ -14,3 +14,10 @@ export type Section = 'actions' | 'alerts'; export const routeToHome = `${BASE_PATH}`; export const routeToActions = `${BASE_PATH}/actions`; export const routeToAlerts = `${BASE_PATH}/alerts`; + +export { COMPARATORS } from './comparators'; +export { AGGREGATION_TYPES } from './aggregation_types'; +export const SORT_ORDERS: { [key: string]: string } = { + ASCENDING: 'asc', + DESCENDING: 'desc', +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 92c2eff44e6e6d..15b05843f7a8b7 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -17,7 +17,6 @@ import { ActionAddFlyout } from '../../action_add'; export const ActionsList: React.FunctionComponent = () => { const { core: { http }, - actionTypeRegistry, plugins: { capabilities, toastNotifications }, } = useAppDependencies(); const canDelete = capabilities.get().actions.delete; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 3c243b5a3fc640..44fef8e387f229 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -54,25 +54,50 @@ export const AlertAdd = ({ refreshList }: Props) => { validate: () => { return { errors: {} }; }, + alertTypeParams: {}, }, }); const [isSaving, setIsSaving] = useState(false); const [selectedTabId, setSelectedTabId] = useState('alert'); const [alertType, setAlertType] = useState(undefined); + const getAlert = () => { + dispatch({ + command: 'setAlert', + payload: { + validate: () => { + return { errors: {} }; + }, + alertTypeParams: {}, + alertTypeId: alertType ? alertType.id : null, + actions: [], + }, + }); + }; + + useEffect(() => { + getAlert(); + }, [alertType]); + const closeFlyout = useCallback(() => setAlertFlyoutVisibility(false), []); const setAlertProperty = (property: string, value: any) => { dispatch({ command: 'setProperty', payload: { property, value } }); }; + const setAlertTypeParams = (property: string, value: any) => { + dispatch({ command: 'setAlertTypeParams', payload: { property, value } }); + }; + if (!alertFlyoutVisible) { return null; } - const { errors } = alert.validate(); - const tagsOptions = []; + const tagsOptions = []; // TODO: move to alert instande when the server side will be done + const AlertTypeParamsExpressionComponent = alertType ? alertType.alertTypeParamsExpression : null; + const { errors } = alert.validate(); // TODO: decide how beter define the Alert UI validation const hasErrors = !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); + // TODO: define constants for the action groups const tabs = [ { id: 'alert', @@ -108,14 +133,14 @@ export const AlertAdd = ({ refreshList }: Props) => { } } - const alertTypeNodes = alertTypeRegistry.list().map(function(item, index): any { + const alertTypeNodes = alertTypeRegistry.list().map(function(item, index) { return ( } title={item.name} description={''} - onClick={() => setAlertType(item)} + onClick={() => setAlertType(item.alertType)} /> ); @@ -156,6 +181,14 @@ export const AlertAdd = ({ refreshList }: Props) => { + {AlertTypeParamsExpressionComponent ? ( + + ) : null} ); @@ -182,6 +215,7 @@ export const AlertAdd = ({ refreshList }: Props) => { if (alertType) { alertTypeArea = ( + {alertTabs} {selectedTabContent} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts index 6353e49ffa04ed..d19749de4845fe 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts @@ -19,5 +19,36 @@ export const alertReducer = (state: any, action: any) => { ...state, alert: payload, }; + case 'setProperty': { + const { property, value } = payload; + if (isEqual(alert[property], value)) { + return state; + } else { + return { + ...state, + alert: { + ...alert, + [property]: value, + }, + }; + } + } + case 'setAlertTypeParams': { + const { property, value } = payload; + if (isEqual(alert.alertTypeParams[property], value)) { + return state; + } else { + return { + ...state, + alert: { + ...alert, + alertTypeParams: { + ...alert.alertTypeParams, + [property]: value, + }, + }, + }; + } + } } }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold.tsx index 6912d7b77f29fd..28e6f5862eda6f 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold.tsx @@ -4,12 +4,219 @@ * you may not use this file except in compliance with the Elastic License. */ -import { AlertTypeModel } from '../../../../types'; +import React, { useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { + EuiFlexItem, + EuiFlexGroup, + EuiExpression, + EuiPopover, + EuiPopoverTitle, + EuiSelect, +} from '@elastic/eui'; +import { AlertTypeModel, AlertType, Alert } from '../../../../types'; +import { Comparator, AggregationType, GroupByType } from './types'; +import { COMPARATORS, AGGREGATION_TYPES } from '../../../constants'; + +const DEFAULT_VALUES = { + AGG_TYPE: 'count', + TERM_SIZE: 5, + THRESHOLD_COMPARATOR: COMPARATORS.GREATER_THAN, + TIME_WINDOW_SIZE: 5, + TIME_WINDOW_UNIT: 'm', + TRIGGER_INTERVAL_SIZE: 1, + TRIGGER_INTERVAL_UNIT: 'm', + THRESHOLD: [1000, 5000], + GROUP_BY: 'all', +}; export function getActionType(): AlertTypeModel { return { id: 'threshold', name: 'Index Threshold', iconClass: 'alert', + aggType: DEFAULT_VALUES.AGG_TYPE, + alertTypeParamsExpression: IndexThresholdAlertTypeExpression, }; } + +interface Props { + alert: Alert; + setAlertTypeParams: (property: string, value: any) => void; + errors: { [key: string]: string[] }; + hasErrors?: boolean; +} + +export const IndexThresholdAlertTypeExpression: React.FunctionComponent = ({ + alert, + setAlertTypeParams, + errors, + hasErrors, +}) => { + const [aggTypePopoverOpen, setAggTypePopoverOpen] = useState(false); + + const comparators: { [key: string]: Comparator } = { + [COMPARATORS.GREATER_THAN]: { + text: i18n.translate( + 'xpack.alertingUI.sections.alertAdd.threshold.comparators.isAboveLabel', + { + defaultMessage: 'Is above', + } + ), + value: COMPARATORS.GREATER_THAN, + requiredValues: 1, + }, + [COMPARATORS.GREATER_THAN_OR_EQUALS]: { + text: i18n.translate( + 'xpack.alertingUI.sections.alertAdd.threshold.comparators.isAboveOrEqualsLabel', + { + defaultMessage: 'Is above or equals', + } + ), + value: COMPARATORS.GREATER_THAN_OR_EQUALS, + requiredValues: 1, + }, + [COMPARATORS.LESS_THAN]: { + text: i18n.translate( + 'xpack.alertingUI.sections.alertAdd.threshold.comparators.isBelowLabel', + { + defaultMessage: 'Is below', + } + ), + value: COMPARATORS.LESS_THAN, + requiredValues: 1, + }, + [COMPARATORS.LESS_THAN_OR_EQUALS]: { + text: i18n.translate( + 'xpack.alertingUI.sections.alertAdd.threshold.comparators.isBelowOrEqualsLabel', + { + defaultMessage: 'Is below or equals', + } + ), + value: COMPARATORS.LESS_THAN_OR_EQUALS, + requiredValues: 1, + }, + [COMPARATORS.BETWEEN]: { + text: i18n.translate( + 'xpack.alertingUI.sections.alertAdd.threshold.comparators.isBetweenLabel', + { + defaultMessage: 'Is between', + } + ), + value: COMPARATORS.BETWEEN, + requiredValues: 2, + }, + }; + + const aggregationTypes: { [key: string]: AggregationType } = { + count: { + text: 'count()', + fieldRequired: false, + value: AGGREGATION_TYPES.COUNT, + validNormalizedTypes: [], + }, + avg: { + text: 'average()', + fieldRequired: true, + validNormalizedTypes: ['number'], + value: AGGREGATION_TYPES.AVERAGE, + }, + sum: { + text: 'sum()', + fieldRequired: true, + validNormalizedTypes: ['number'], + value: AGGREGATION_TYPES.SUM, + }, + min: { + text: 'min()', + fieldRequired: true, + validNormalizedTypes: ['number', 'date'], + value: AGGREGATION_TYPES.MIN, + }, + max: { + text: 'max()', + fieldRequired: true, + validNormalizedTypes: ['number', 'date'], + value: AGGREGATION_TYPES.MAX, + }, + }; + + const groupByTypes: { [key: string]: GroupByType } = { + all: { + text: i18n.translate( + 'xpack.watcher.thresholdWatchExpression.groupByLabel.allDocumentsLabel', + { + defaultMessage: 'all documents', + } + ), + sizeRequired: false, + value: 'all', + validNormalizedTypes: [], + }, + top: { + text: i18n.translate('xpack.watcher.thresholdWatchExpression.groupByLabel.topLabel', { + defaultMessage: 'top', + }), + sizeRequired: true, + value: 'top', + validNormalizedTypes: ['number', 'date', 'keyword'], + }, + }; + + return ( + + + { + setAggTypePopoverOpen(true); + }} + /> + } + isOpen={aggTypePopoverOpen} + closePopover={() => { + setAggTypePopoverOpen(false); + }} + ownFocus + withTitle + anchorPosition="downLeft" + > +
+ + {i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.whenButtonLabel', { + defaultMessage: 'when', + })} + + { + setAlertTypeParams('aggType', e.target.value); + setAggTypePopoverOpen(false); + }} + options={Object.values(aggregationTypes).map(({ text, value }) => { + return { + text, + value, + }; + })} + /> +
+
+
+
+ ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/types.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/types.ts new file mode 100644 index 00000000000000..fd2a401fe59f3b --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/types.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface Comparator { + text: string; + value: string; + requiredValues: number; +} + +export interface AggregationType { + text: string; + fieldRequired: boolean; + value: string; + validNormalizedTypes: string[]; +} + +export interface GroupByType { + text: string; + sizeRequired: boolean; + value: string; + validNormalizedTypes: string[]; +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts index 25a29175fe3bd8..31dd6af68c8fcd 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts @@ -84,4 +84,6 @@ export interface AlertTypeModel { id: string; name: string; iconClass: string; + aggType: string; + alertTypeParamsExpression: React.FunctionComponent; } From 508448737090e6b6cc330fd964f858348277b81b Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 28 Oct 2019 10:24:37 -0400 Subject: [PATCH 094/297] Use popover on table row actions --- .../alerts_list/components/alerts_list.tsx | 140 ++---------------- .../components/collapsed_item_actions.tsx | 128 ++++++++++++++++ 2 files changed, 138 insertions(+), 130 deletions(-) create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 8d234c4a454129..add9a60e7df1a8 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -13,15 +13,8 @@ import { AlertsContext } from '../../../context/alerts_context'; import { useAppDependencies } from '../../../index'; import { Alert, AlertTableItem, AlertTypeIndex, Pagination } from '../../../../types'; import { AlertAdd } from '../../alert_add'; -import { - deleteAlerts, - disableAlert, - enableAlert, - loadAlerts, - loadAlertTypes, - muteAllAlertInstances, - unmuteAllAlertInstances, -} from '../../../lib/api'; +import { CollapsedItemActions } from './collapsed_item_actions'; +import { deleteAlerts, loadAlerts, loadAlertTypes } from '../../../lib/api'; export const AlertsList: React.FunctionComponent = () => { const { @@ -29,7 +22,6 @@ export const AlertsList: React.FunctionComponent = () => { plugins: { capabilities, toastNotifications }, } = useAppDependencies(); const canDelete = capabilities.get().alerting.delete; - const canSave = capabilities.get().alerting.save; const [alertTypesIndex, setAlertTypesIndex] = useState(undefined); const [alerts, setAlerts] = useState([]); @@ -147,126 +139,14 @@ export const AlertsList: React.FunctionComponent = () => { name: i18n.translate('xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions', { defaultMessage: 'Actions', }), - actions: [ - { - enabled: () => canDelete, - type: 'icon', - icon: 'trash', - onClick: (item: AlertTableItem) => deleteItems([item]), - name: i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.deleteAlertName', - { defaultMessage: 'Delete' } - ), - description: canDelete - ? i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.deleteAlertDescription', - { defaultMessage: 'Delete this alert' } - ) - : i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.deleteAlertDisabledDescription', - { defaultMessage: 'Unable to delete alerts' } - ), - }, - { - enabled: () => canSave, - type: 'icon', - icon: 'play', - available: (item: AlertTableItem) => !item.enabled, - onClick: async (item: AlertTableItem) => { - setIsPerformingAction(true); - await enableAlert({ http, id: item.id }); - await loadAlertsData(); - setIsPerformingAction(false); - }, - name: i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.enableAlertTitle', - { defaultMessage: 'Enable' } - ), - description: canSave - ? i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.enableAlertDescription', - { defaultMessage: 'Enable this alert' } - ) - : i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.enableAlertDisabledDescription', - { defaultMessage: 'Unable to enable alerts' } - ), - }, - { - enabled: () => canSave, - type: 'icon', - icon: 'stop', - available: (item: AlertTableItem) => item.enabled, - onClick: async (item: AlertTableItem) => { - setIsPerformingAction(true); - await disableAlert({ http, id: item.id }); - await loadAlertsData(); - setIsPerformingAction(false); - }, - name: i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.disableAlertTitle', - { defaultMessage: 'Disable' } - ), - description: canSave - ? i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.disableAlertDescription', - { defaultMessage: 'Disable this alert' } - ) - : i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.disableAlertDisabledDescription', - { defaultMessage: 'Unable to disable alerts' } - ), - }, - { - // TODO: Icon - enabled: () => canSave, - available: (item: AlertTableItem) => !item.muteAll, - onClick: async (item: AlertTableItem) => { - setIsPerformingAction(true); - await muteAllAlertInstances({ http, id: item.id }); - await loadAlertsData(); - setIsPerformingAction(false); - }, - name: i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.muteAllAlertInstancesTitle', - { defaultMessage: 'Mute all' } - ), - description: canSave - ? i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.muteAllAlertInstancesDescription', - { defaultMessage: 'Mute all alert instances' } - ) - : i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.muteAllAlertInstancesDisabledDescription', - { defaultMessage: 'Unable to mute all alert instances' } - ), - }, - { - enabled: () => canSave, - type: 'icon', - icon: 'bell', - available: (item: AlertTableItem) => item.muteAll, - onClick: async (item: AlertTableItem) => { - setIsPerformingAction(true); - await unmuteAllAlertInstances({ http, id: item.id }); - await loadAlertsData(); - setIsPerformingAction(false); - }, - name: i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.unmuteAllAlertInstancesTitle', - { defaultMessage: 'Unmute all' } - ), - description: canSave - ? i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.unmuteAllAlertInstancesDescription', - { defaultMessage: 'Unmute all alert instances' } - ) - : i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions.unmuteAllAlertInstancesDisabledDescription', - { defaultMessage: 'Unable to unmute all alert instances' } - ), - }, - ], + render(item: AlertTableItem) { + return ( + loadAlertsData()} + > + ); + }, }, ]; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx new file mode 100644 index 00000000000000..cc1b6e5e15c26b --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx @@ -0,0 +1,128 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import React, { useState } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + EuiButtonEmpty, + EuiButtonIcon, + EuiFormRow, + EuiPopover, + EuiPopoverFooter, + EuiSwitch, +} from '@elastic/eui'; + +import { AlertTableItem } from '../../../../types'; +import { useAppDependencies } from '../../../index'; +import { + deleteAlerts, + disableAlert, + enableAlert, + muteAllAlertInstances, + unmuteAllAlertInstances, +} from '../../../lib/api'; + +export interface ComponentOpts { + item: AlertTableItem; + onDeleted: () => void; +} + +export const CollapsedItemActions: React.FunctionComponent = ({ + item, + onDeleted, +}: ComponentOpts) => { + const { + core: { http }, + plugins: { capabilities }, + } = useAppDependencies(); + + const canDelete = capabilities.get().alerting.delete; + const canSave = capabilities.get().alerting.save; + + const [isEnabled, setIsEnabled] = useState(item.enabled); + const [isMuted, setIsMuted] = useState(item.muteAll); + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + const button = ( + setIsPopoverOpen(!isPopoverOpen)} + aria-label={i18n.translate( + 'xpack.alertingUI.sections.alertsList.collapsedItemActons.popoverButtonTitle', + { defaultMessage: 'Actions' } + )} + > + ); + + return ( + setIsPopoverOpen(false)}> + + { + if (isEnabled) { + disableAlert({ http, id: item.id }); + setIsEnabled(false); + return; + } + enableAlert({ http, id: item.id }); + setIsEnabled(true); + }} + label={ + + } + /> + + + { + if (isMuted) { + unmuteAllAlertInstances({ http, id: item.id }); + setIsMuted(false); + return; + } + muteAllAlertInstances({ http, id: item.id }); + setIsMuted(true); + }} + label={ + + } + /> + + + + { + await deleteAlerts({ http, ids: [item.id] }); + onDeleted(); + }} + > + + + + + + ); +}; From 8b375d47ad0d5bf065ab0670c34f5e54835b25d7 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 28 Oct 2019 15:15:40 -0700 Subject: [PATCH 095/297] Added expression definition for the threshold alert --- .../public/application/constants/index.ts | 1 + .../application/constants/time_units.ts | 12 ++ .../np_ready/public/application/lib/api.ts | 27 ++++ .../application/lib/get_time_unit_label.ts | 33 +++++ .../alert_add/alert_types/threshold.tsx | 119 +++++++++++++++++- .../alerting_ui/np_ready/public/types.ts | 2 +- 6 files changed, 190 insertions(+), 4 deletions(-) create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/time_units.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/get_time_unit_label.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts index b1d5aff54cded2..06dfc53fca7b31 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts @@ -17,6 +17,7 @@ export const routeToAlerts = `${BASE_PATH}/alerts`; export { COMPARATORS } from './comparators'; export { AGGREGATION_TYPES } from './aggregation_types'; +export { TIME_UNITS } from './time_units'; export const SORT_ORDERS: { [key: string]: string } = { ASCENDING: 'asc', DESCENDING: 'desc', diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/time_units.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/time_units.ts new file mode 100644 index 00000000000000..c861d47416a804 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/time_units.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. + */ + +export const TIME_UNITS: { [key: string]: string } = { + SECOND: 's', + MINUTE: 'm', + HOUR: 'h', + DAY: 'd', +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index 1ebe9bd35d67ed..9739de53da97de 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -11,6 +11,7 @@ import { Action, ActionType, Alert, AlertType } from '../../types'; // all the actions in advance and assume the total count to not go over 100 or so. // We'll set this max setting assuming it's never reached. const MAX_ACTIONS_RETURNED = 10000; +const WATCHER_API_ROOT = '/api/watcher'; interface LoadActionTypesOpts { http: HttpServiceBase; @@ -165,3 +166,29 @@ export async function unmuteAllAlertInstances({ }): Promise { await http.post(`${BASE_ALERT_API_PATH}/${id}/_unmute_all`); } + +// TODO: replace watcher api with the proper from alerts + +export async function getMatchingIndicesForThresholdAlertType({ + pattern, + http, +}: { + pattern: string; + http: HttpServiceBase; +}): Promise> { + return await http.post(`${WATCHER_API_ROOT}/indices`, { + body: JSON.stringify(pattern), + }); +} + +export async function getThresholdAlertTypeFields({ + indices, + http, +}: { + indices: string[]; + http: HttpServiceBase; +}): Promise> { + return await http.post(`${WATCHER_API_ROOT}/fields`, { + body: JSON.stringify(indices), + }); +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/get_time_unit_label.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/get_time_unit_label.ts new file mode 100644 index 00000000000000..eae42eb3af35da --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/get_time_unit_label.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import { TIME_UNITS } from '../constants'; + +export function getTimeUnitLabel(timeUnit = TIME_UNITS.SECOND, timeValue = '0') { + switch (timeUnit) { + case TIME_UNITS.SECOND: + return i18n.translate('xpack.watcher.timeUnits.secondLabel', { + defaultMessage: '{timeValue, plural, one {second} other {seconds}}', + values: { timeValue }, + }); + case TIME_UNITS.MINUTE: + return i18n.translate('xpack.watcher.timeUnits.minuteLabel', { + defaultMessage: '{timeValue, plural, one {minute} other {minutes}}', + values: { timeValue }, + }); + case TIME_UNITS.HOUR: + return i18n.translate('xpack.watcher.timeUnits.hourLabel', { + defaultMessage: '{timeValue, plural, one {hour} other {hours}}', + values: { timeValue }, + }); + case TIME_UNITS.DAY: + return i18n.translate('xpack.watcher.timeUnits.dayLabel', { + defaultMessage: '{timeValue, plural, one {day} other {days}}', + values: { timeValue }, + }); + } +} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold.tsx index 28e6f5862eda6f..8751765e0d341c 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold.tsx @@ -14,9 +14,15 @@ import { EuiPopoverTitle, EuiSelect, } from '@elastic/eui'; -import { AlertTypeModel, AlertType, Alert } from '../../../../types'; +import { AlertTypeModel, AlertType, Alert, ValidationResult } from '../../../../types'; import { Comparator, AggregationType, GroupByType } from './types'; -import { COMPARATORS, AGGREGATION_TYPES } from '../../../constants'; +import { COMPARATORS, AGGREGATION_TYPES, TIME_UNITS } from '../../../constants'; +import { + getMatchingIndicesForThresholdAlertType, + getThresholdAlertTypeFields, +} from '../../../lib/api'; +import { getTimeUnitLabel } from '../../../lib/get_time_unit_label'; +import { useAppDependencies } from '../../..'; const DEFAULT_VALUES = { AGG_TYPE: 'count', @@ -35,8 +41,8 @@ export function getActionType(): AlertTypeModel { id: 'threshold', name: 'Index Threshold', iconClass: 'alert', - aggType: DEFAULT_VALUES.AGG_TYPE, alertTypeParamsExpression: IndexThresholdAlertTypeExpression, + validate: validateAlertType, }; } @@ -47,13 +53,34 @@ interface Props { hasErrors?: boolean; } +function validateAlertType(alert: Alert): ValidationResult { + return { errors: {} }; +} + export const IndexThresholdAlertTypeExpression: React.FunctionComponent = ({ alert, setAlertTypeParams, errors, hasErrors, }) => { + const { + core: { http }, + } = useAppDependencies(); + const firstFieldOption = { + text: i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.timeFieldOptionLabel', { + defaultMessage: 'Select a field', + }), + value: '', + }; + const [aggTypePopoverOpen, setAggTypePopoverOpen] = useState(false); + const [indexPattern, setIndexPattern] = useState([]); + const [esFields, setEsFields] = useState([]); + const [indexOptions, setIndexOptions] = useState([]); + const [timeFieldOptions, setTimeFieldOptions] = useState([firstFieldOption]); + + const [aggFieldPopoverOpen, setAggFieldPopoverOpen] = useState(false); + const [groupByPopoverOpen, setGroupByPopoverOpen] = useState(false); const comparators: { [key: string]: Comparator } = { [COMPARATORS.GREATER_THAN]: { @@ -163,6 +190,92 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = }, }; + const expressionErrorMessage = i18n.translate( + 'xpack.alertingUI.sections.alertAdd.threshold.fixErrorInExpressionBelowValidationMessage', + { + defaultMessage: 'Expression contains errors.', + } + ); + + const getTimeOptions = (unitSize: string) => + Object.entries(TIME_UNITS).map(([_key, value]) => { + return { + text: getTimeUnitLabel(value, unitSize), + value, + }; + }); + + const getFields = async (indices: string[]) => { + return await getThresholdAlertTypeFields({ indices, http }); + }; + const getTimeFieldOptions = (fields: any) => { + const options = [firstFieldOption]; + + fields.forEach((field: any) => { + if (field.type === 'date') { + options.push({ + text: field.name, + value: field.name, + }); + } + }); + return options; + }; + + interface IOption { + label: string; + options: Array<{ value: string; label: string }>; + } + + const getIndexOptions = async (pattern: string, indexPatterns: string[]) => { + const options: IOption[] = []; + + if (!pattern) { + return options; + } + + const matchingIndices = (await getMatchingIndicesForThresholdAlertType({ + pattern, + http, + })) as string[]; + const matchingIndexPatterns = indexPatterns.filter(anIndexPattern => { + return anIndexPattern.includes(pattern); + }) as string[]; + + if (matchingIndices.length || matchingIndexPatterns.length) { + const matchingOptions = _.uniq([...matchingIndices, ...matchingIndexPatterns]); + + options.push({ + label: i18n.translate( + 'xpack.alertingUI.sections.alertAdd.threshold.indicesAndIndexPatternsLabel', + { + defaultMessage: 'Based on your indices and index patterns', + } + ), + options: matchingOptions.map(match => { + return { + label: match, + value: match, + }; + }), + }); + } + + options.push({ + label: i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.chooseLabel', { + defaultMessage: 'Choose…', + }), + options: [ + { + value: pattern, + label: pattern, + }, + ], + }); + + return options; + }; + return ( diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts index 31dd6af68c8fcd..6681a0bc6f2cba 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts @@ -84,6 +84,6 @@ export interface AlertTypeModel { id: string; name: string; iconClass: string; - aggType: string; + validate: (alert: Alert) => ValidationResult; alertTypeParamsExpression: React.FunctionComponent; } From 363640eb73810a20f0b8871006097293b8d74b49 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 1 Nov 2019 13:50:08 -0400 Subject: [PATCH 096/297] Add name column --- .../np_ready/public/application/lib/api.ts | 3 +-- .../sections/alerts_list/components/alerts_list.tsx | 13 +++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index 9739de53da97de..b1d9ee5797ff44 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -99,8 +99,7 @@ export async function loadAlerts({ query: { page: page.index + 1, per_page: page.size, - // TODO: Add search fields - // search_fields: searchText ? '' : undefined, + search_fields: searchText ? 'name' : undefined, search: searchText, }, }); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index add9a60e7df1a8..a6b40453d12e21 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -117,10 +117,19 @@ export const AlertsList: React.FunctionComponent = () => { } const alertsTableColumns = [ + { + field: 'name', + name: i18n.translate( + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.nameTitle', + { defaultMessage: 'Name' } + ), + sortable: false, + truncateText: true, + }, { field: 'alertType', name: i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.alertType', + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.alertTypeTitle', { defaultMessage: 'Type' } ), sortable: false, @@ -129,7 +138,7 @@ export const AlertsList: React.FunctionComponent = () => { { field: 'interval', name: i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.interval', + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.intervalTitle', { defaultMessage: 'Runs every' } ), sortable: false, From 4c3b57c957b40de20324da5c818ce682db8989c4 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 1 Nov 2019 15:35:07 -0400 Subject: [PATCH 097/297] Add attached actions count column to actions list --- .../actions_list/components/actions_list.tsx | 22 ++++++++++++++----- .../alerting_ui/np_ready/public/types.ts | 2 ++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 15b05843f7a8b7..5d9f668ccbfea2 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -5,7 +5,7 @@ */ import React, { Fragment, useState, useEffect } from 'react'; -import { EuiInMemoryTable, EuiSpacer, EuiButton } from '@elastic/eui'; +import { EuiBadge, EuiInMemoryTable, EuiSpacer, EuiButton } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { ActionsContext } from '../../../context/actions_context'; @@ -118,25 +118,37 @@ export const ActionsList: React.FunctionComponent = () => { { field: 'actionType', name: i18n.translate( - 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.actionType', + 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.actionTypeTitle', { defaultMessage: 'Type', } ), - sortable: true, + sortable: false, truncateText: true, }, { field: 'description', name: i18n.translate( - 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.description', + 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.descriptionTitle', { defaultMessage: 'Title', } ), - sortable: true, + sortable: false, truncateText: true, }, + { + field: 'referencedByCount', + name: i18n.translate( + 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.referencedByCountTitle', + { defaultMessage: 'Attached actions' } + ), + sortable: false, + truncateText: true, + render: (value: number, item: ActionTableItem) => { + return {value}; + }, + }, { name: i18n.translate( 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.actions', diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts index 6681a0bc6f2cba..507c935f35df7b 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts @@ -42,6 +42,7 @@ export interface Action { id: string; actionTypeId: string; description: string; + referencedByCount: number; config: Record; } @@ -62,6 +63,7 @@ export interface AlertAction { export interface Alert { id: string; + name: string; enabled: boolean; alertTypeId: string; interval: string; From 6bf1baabed26cad4e4da10e7eda06b3d6be29554 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 14 Nov 2019 08:24:17 -0800 Subject: [PATCH 098/297] Refactored reducers type definitions --- .../application/constants/action_groups.ts | 13 +++ .../sections/action_add/action_add_form.tsx | 30 +++--- .../sections/action_add/action_reducer.ts | 50 ++++++---- .../sections/alert_add/alert_add.tsx | 93 ++++++++++++------- .../sections/alert_add/alert_reducer.ts | 44 ++++++--- .../alerting_ui/np_ready/public/types.ts | 4 + 6 files changed, 153 insertions(+), 81 deletions(-) create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_groups.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_groups.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_groups.ts new file mode 100644 index 00000000000000..9c251cea502a42 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_groups.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under 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 ACTION_GROUPS: { [key: string]: string } = { + ALERT: 'alert', + + WARNING: 'warning', + + ESCALATION: 'escalation', +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx index 64a9c03fbcf712..e42eddafa7dfb4 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx @@ -25,50 +25,48 @@ import { SectionError, ErrableFormRow } from '../../components/page_error'; import { useAppDependencies } from '../..'; import { actionReducer } from './action_reducer'; import { ActionsContext } from '../../context/actions_context'; -import { ActionType, Action } from '../../../types'; +import { ActionType, Action, IErrorObject } from '../../../types'; interface Props { actionType: ActionType; } -interface IErrorObject { - [key: string]: string[]; -} - export const ActionAddForm = ({ actionType }: Props) => { const { core: { http }, plugins: { toastNotifications }, actionTypeRegistry, } = useAppDependencies(); + const initialAction = { actionTypeId: actionType.id, config: {}, secrets: {} }; + const { setFlyoutVisibility, loadActions } = useContext(ActionsContext); + // hooks - const [{ action }, dispatch] = useReducer(actionReducer, { - action: { actionTypeId: actionType.id, config: {}, secrets: {} }, - }); + const [{ action }, dispatch] = useReducer(actionReducer, { action: initialAction }); - const setActionProperty = (property: string, value: any) => { - dispatch({ command: 'setProperty', payload: { property, value } }); + const setActionProperty = (key: string, value: any) => { + dispatch({ command: { type: 'setProperty' }, payload: { key, value } }); }; - const setActionConfigProperty = (property: string, value: any) => { - dispatch({ command: 'setConfigProperty', payload: { property, value } }); + const setActionConfigProperty = (key: string, value: any) => { + dispatch({ command: { type: 'setConfigProperty' }, payload: { key, value } }); }; - const setActionSecretsProperty = (property: string, value: any) => { - dispatch({ command: 'setSecretsProperty', payload: { property, value } }); + const setActionSecretsProperty = (key: string, value: any) => { + dispatch({ command: { type: 'setSecretsProperty' }, payload: { key, value } }); }; const getAction = () => { dispatch({ - command: 'setAction', - payload: { actionTypeId: actionType.id, config: {}, secrets: {} }, + command: { type: 'setAction' }, + payload: { key: 'action', value: { config: {}, secrets: {} } }, }); }; useEffect(() => { getAction(); setServerError(null); + setActionProperty('actionTypeId', actionType.id); }, [actionType]); const [isSaving, setIsSaving] = useState(false); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_reducer.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_reducer.ts index 82f2b3d3a2263c..1061f63088cde7 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_reducer.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_reducer.ts @@ -5,37 +5,55 @@ */ import { isEqual } from 'lodash'; +interface CommandType { + type: 'setAction' | 'setProperty' | 'setConfigProperty' | 'setSecretsProperty'; +} + export interface ActionState { action: any; } -export const actionReducer = (state: any, actionItem: any) => { +export interface ActionReducerItem { + command: CommandType; + payload: { + key: string; + value: {}; + }; +} + +export const actionReducer = (state: ActionState, actionItem: ActionReducerItem) => { const { command, payload } = actionItem; const { action } = state; - switch (command) { - case 'setAction': - return { - ...state, - action: payload, - }; + switch (command.type) { + case 'setAction': { + const { key, value } = payload; + if (key === 'action') { + return { + ...state, + action: value, + }; + } else { + return state; + } + } case 'setProperty': { - const { property, value } = payload; - if (isEqual(action[property], value)) { + const { key, value } = payload; + if (isEqual(action[key], value)) { return state; } else { return { ...state, action: { ...action, - [property]: value, + [key]: value, }, }; } } case 'setConfigProperty': { - const { property, value } = payload; - if (isEqual(action.config[property], value)) { + const { key, value } = payload; + if (isEqual(action.config[key], value)) { return state; } else { return { @@ -44,15 +62,15 @@ export const actionReducer = (state: any, actionItem: any) => { ...action, config: { ...action.config, - [property]: value, + [key]: value, }, }, }; } } case 'setSecretsProperty': { - const { property, value } = payload; - if (isEqual(action.secrets[property], value)) { + const { key, value } = payload; + if (isEqual(action.secrets[key], value)) { return state; } else { return { @@ -61,7 +79,7 @@ export const actionReducer = (state: any, actionItem: any) => { ...action, secrets: { ...action.secrets, - [property]: value, + [key]: value, }, }, }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 44fef8e387f229..b27943399c50a2 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -35,58 +35,77 @@ import { saveAlert } from '../../lib/api'; import { AlertsContext } from '../../context/alerts_context'; import { alertReducer } from './alert_reducer'; import { ErrableFormRow } from '../../components/page_error'; -import { AlertTypeModel } from '../../../types'; +import { AlertTypeModel, Alert, IErrorObject } from '../../../types'; +import { ACTION_GROUPS } from '../../constants/action_groups'; interface Props { refreshList: () => Promise; } +function validateBaseProperties(alertObject: Alert) { + const validationResult = { errors: {} }; + const errors = { + name: new Array(), + }; + validationResult.errors = errors; + if (!alertObject.name) { + errors.name.push( + i18n.translate('xpack.alertingUI.sections.alertAdd.error.requiredNameText', { + defaultMessage: 'Name is required.', + }) + ); + } + return validationResult; +} + export const AlertAdd = ({ refreshList }: Props) => { const { core: { http }, plugins: { toastNotifications }, alertTypeRegistry, } = useAppDependencies(); + const [alertType, setAlertType] = useState(undefined); + + const initialAlert = { + alertTypeParams: {}, + alertTypeId: null, + actions: [], + }; + const { alertFlyoutVisible, setAlertFlyoutVisibility } = useContext(AlertsContext); // hooks - const [{ alert }, dispatch] = useReducer(alertReducer, { - alert: { - validate: () => { - return { errors: {} }; - }, - alertTypeParams: {}, - }, - }); + const [{ alert }, dispatch] = useReducer(alertReducer, { alert: initialAlert }); const [isSaving, setIsSaving] = useState(false); const [selectedTabId, setSelectedTabId] = useState('alert'); - const [alertType, setAlertType] = useState(undefined); const getAlert = () => { dispatch({ - command: 'setAlert', + command: { type: 'setAlert' }, payload: { - validate: () => { - return { errors: {} }; + key: 'alert', + value: { + alertTypeParams: {}, + alertTypeId: null, + actions: [], }, - alertTypeParams: {}, - alertTypeId: alertType ? alertType.id : null, - actions: [], }, }); }; useEffect(() => { getAlert(); - }, [alertType]); - - const closeFlyout = useCallback(() => setAlertFlyoutVisibility(false), []); + setAlertType(undefined); + }, [alertFlyoutVisible]); - const setAlertProperty = (property: string, value: any) => { - dispatch({ command: 'setProperty', payload: { property, value } }); + const setAlertProperty = (key: string, value: any) => { + dispatch({ command: { type: 'setProperty' }, payload: { key, value } }); }; - const setAlertTypeParams = (property: string, value: any) => { - dispatch({ command: 'setAlertTypeParams', payload: { property, value } }); + const setAlertTypeParams = (key: string, value: any) => { + dispatch({ command: { type: 'setAlertTypeParams' }, payload: { key, value } }); }; + const closeFlyout = useCallback(() => setAlertFlyoutVisibility(false), [ + setAlertFlyoutVisibility, + ]); if (!alertFlyoutVisible) { return null; @@ -94,22 +113,24 @@ export const AlertAdd = ({ refreshList }: Props) => { const tagsOptions = []; // TODO: move to alert instande when the server side will be done const AlertTypeParamsExpressionComponent = alertType ? alertType.alertTypeParamsExpression : null; - const { errors } = alert.validate(); // TODO: decide how beter define the Alert UI validation + const errors = { + ...(alertType ? alertType.validate(alert).errors : []), + ...validateBaseProperties(alert).errors, + } as IErrorObject; const hasErrors = !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); - // TODO: define constants for the action groups const tabs = [ { - id: 'alert', - name: 'Alert', + id: ACTION_GROUPS.ALERT.toLowerCase(), + name: ACTION_GROUPS.ALERT, }, { - id: 'warning', - name: 'Warning', + id: ACTION_GROUPS.WARNING.toLowerCase(), + name: ACTION_GROUPS.WARNING, }, { - id: 'escalation', - name: 'Escalation', + id: ACTION_GROUPS.ESCALATION.toLowerCase(), + name: ACTION_GROUPS.ESCALATION, disabled: false, }, ]; @@ -187,7 +208,7 @@ export const AlertAdd = ({ refreshList }: Props) => { errors={errors} setAlertTypeParams={setAlertTypeParams} hasErrors={hasErrors} - > + /> ) : null}
); @@ -198,13 +219,13 @@ export const AlertAdd = ({ refreshList }: Props) => { let selectedTabContent; switch (selectedTabId) { - case 'alert': + case ACTION_GROUPS.ALERT.toLowerCase(): selectedTabContent = alertDetails; break; - case 'warning': + case ACTION_GROUPS.WARNING.toLowerCase(): selectedTabContent = warningDetails; break; - case 'escalation': + case ACTION_GROUPS.ESCALATION.toLowerCase(): selectedTabContent = escalationDetails; break; default: @@ -322,7 +343,7 @@ export const AlertAdd = ({ refreshList }: Props) => { - setAlertFlyoutVisibility(false)}> + {i18n.translate('xpack.alertingUI.sections.alertAdd.cancelButtonLabel', { defaultMessage: 'Cancel', })} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts index d19749de4845fe..e4f70a15e8a79b 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts @@ -5,37 +5,55 @@ */ import { isEqual } from 'lodash'; +interface CommandType { + type: 'setAlert' | 'setProperty' | 'setAlertTypeParams'; +} + export interface AlertState { alert: any; } -export const alertReducer = (state: any, action: any) => { +export interface ActionAlertReducerItem { + command: CommandType; + payload: { + key: string; + value: {}; + }; +} + +export const alertReducer = (state: any, action: ActionAlertReducerItem) => { const { command, payload } = action; const { alert } = state; - switch (command) { - case 'setAlert': - return { - ...state, - alert: payload, - }; + switch (command.type) { + case 'setAlert': { + const { key, value } = payload; + if (key === 'action') { + return { + ...state, + alert: value, + }; + } else { + return state; + } + } case 'setProperty': { - const { property, value } = payload; - if (isEqual(alert[property], value)) { + const { key, value } = payload; + if (isEqual(alert[key], value)) { return state; } else { return { ...state, alert: { ...alert, - [property]: value, + [key]: value, }, }; } } case 'setAlertTypeParams': { - const { property, value } = payload; - if (isEqual(alert.alertTypeParams[property], value)) { + const { key, value } = payload; + if (isEqual(alert.alertTypeParams[key], value)) { return state; } else { return { @@ -44,7 +62,7 @@ export const alertReducer = (state: any, action: any) => { ...alert, alertTypeParams: { ...alert.alertTypeParams, - [property]: value, + [key]: value, }, }, }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts index 507c935f35df7b..ff8a6af3b66ad4 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts @@ -89,3 +89,7 @@ export interface AlertTypeModel { validate: (alert: Alert) => ValidationResult; alertTypeParamsExpression: React.FunctionComponent; } + +export interface IErrorObject { + [key: string]: string[]; +} From cda5c24665965875f16146778cf510f6ea995b9b Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 14 Nov 2019 08:40:21 -0800 Subject: [PATCH 099/297] Fixed dependancy objects --- .../sections/action_add/action_add_form.tsx | 11 +++-------- .../application/sections/alert_add/alert_add.tsx | 15 ++++----------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx index e42eddafa7dfb4..e06cea3b1080c3 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx @@ -56,18 +56,13 @@ export const ActionAddForm = ({ actionType }: Props) => { dispatch({ command: { type: 'setSecretsProperty' }, payload: { key, value } }); }; - const getAction = () => { + useEffect(() => { dispatch({ command: { type: 'setAction' }, - payload: { key: 'action', value: { config: {}, secrets: {} } }, + payload: { key: 'action', value: initialAction }, }); - }; - - useEffect(() => { - getAction(); setServerError(null); - setActionProperty('actionTypeId', actionType.id); - }, [actionType]); + }, [initialAction]); const [isSaving, setIsSaving] = useState(false); const [serverError, setServerError] = useState<{ diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index b27943399c50a2..5a2f9635daa2ec 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -77,24 +77,17 @@ export const AlertAdd = ({ refreshList }: Props) => { const [{ alert }, dispatch] = useReducer(alertReducer, { alert: initialAlert }); const [isSaving, setIsSaving] = useState(false); const [selectedTabId, setSelectedTabId] = useState('alert'); - const getAlert = () => { + + useEffect(() => { dispatch({ command: { type: 'setAlert' }, payload: { key: 'alert', - value: { - alertTypeParams: {}, - alertTypeId: null, - actions: [], - }, + value: initialAlert, }, }); - }; - - useEffect(() => { - getAlert(); setAlertType(undefined); - }, [alertFlyoutVisible]); + }, [alertFlyoutVisible, initialAlert]); const setAlertProperty = (key: string, value: any) => { dispatch({ command: { type: 'setProperty' }, payload: { key, value } }); From d47238ef48c179e9d7192d82c94a1c0a21c1246b Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 14 Nov 2019 09:28:16 -0800 Subject: [PATCH 100/297] Fixed action add --- .../application/sections/action_add/action_add_form.tsx | 4 ++-- .../sections/action_add/buildin_action_types/es_index.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx index e06cea3b1080c3..3ec4bb75849099 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx @@ -59,10 +59,10 @@ export const ActionAddForm = ({ actionType }: Props) => { useEffect(() => { dispatch({ command: { type: 'setAction' }, - payload: { key: 'action', value: initialAction }, + payload: { key: 'action', value: { actionTypeId: actionType.id, config: {}, secrets: {} } }, }); setServerError(null); - }, [initialAction]); + }, [actionType]); const [isSaving, setIsSaving] = useState(false); const [serverError, setServerError] = useState<{ diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx index 2d936aab3a1af1..89a515a497fca1 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx @@ -38,7 +38,7 @@ const IndexActionFields: React.FunctionComponent = ({ action, editActionC fullWidth name="index" data-test-subj="indexInput" - value={index} + value={index || ''} onChange={(e: React.ChangeEvent) => { editActionConfig('index', e.target.value); }} From 298ee205b80c0e22ff1c4de4a1b68a9d6ef00da9 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 14 Nov 2019 09:30:46 -0800 Subject: [PATCH 101/297] Fixed logging app icon --- .../sections/action_add/buildin_action_types/server_log.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx index eac659d9522c37..06ec1eeb13b30e 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx @@ -9,7 +9,7 @@ import { ActionTypeModel, ValidationResult } from '../../../../types'; export function getActionType(): ActionTypeModel { return { id: '.server-log', - iconClass: 'loggingApp', + iconClass: 'logsApp', selectMessage: i18n.translate( 'xpack.alertingUI.sections.actionAdd.serverLogAction.selectMessageText', { From 9c4abbbbc1db0e212205adbcb8aefb72d722614a Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 14 Nov 2019 16:35:25 -0800 Subject: [PATCH 102/297] Added action types params fields --- .../application/action_type_registry.ts | 9 + .../application/constants/action_groups.ts | 2 +- .../action_add/buildin_action_types/email.tsx | 99 +++++++- .../buildin_action_types/es_index.tsx | 40 +++- .../buildin_action_types/pagerduty.tsx | 46 +++- .../buildin_action_types/server_log.tsx | 45 +++- .../action_add/buildin_action_types/slack.tsx | 71 +++++- .../buildin_action_types/webhook.tsx | 215 +++++++++++++++++- .../sections/alert_add/alert_add.tsx | 178 +++++++++++---- .../sections/alert_add/alert_reducer.ts | 7 +- .../alerting_ui/np_ready/public/types.ts | 8 + 11 files changed, 660 insertions(+), 60 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/action_type_registry.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/action_type_registry.ts index 829ed8ae2de8fd..2c10ea156e1929 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/action_type_registry.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/action_type_registry.ts @@ -46,4 +46,13 @@ export class ActionTypeRegistry { } return this.actionTypes.get(id)!; } + + public list() { + return Array.from(this.actionTypes).map(([actionTypeId, actionType]) => ({ + id: actionTypeId, + name: actionType.id, + iconClass: actionType.iconClass, + actionType, + })); + } } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_groups.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_groups.ts index 9c251cea502a42..e74d0577b577b0 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_groups.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_groups.ts @@ -9,5 +9,5 @@ export const ACTION_GROUPS: { [key: string]: string } = { WARNING: 'warning', - ESCALATION: 'escalation', + UNACKNOWLEDGED: 'unacknowledged', }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx index e626183eb3852b..d7d9177a4c1d1c 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx @@ -10,10 +10,13 @@ import { EuiFlexGroup, EuiFieldNumber, EuiFieldPassword, + EuiComboBox, + EuiFormRow, + EuiTextArea, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ErrableFormRow } from '../../../components/page_error'; -import { ActionTypeModel, Props, Action, ValidationResult } from '../../../../types'; +import { ActionTypeModel, Props, Action, ValidationResult, ParamsProps } from '../../../../types'; export function getActionType(): ActionTypeModel { return { @@ -73,6 +76,7 @@ export function getActionType(): ActionTypeModel { return validationResult; }, actionFields: EmailActionFields, + actionParamsFields: EmailParamsFields, }; } @@ -244,3 +248,96 @@ const EmailActionFields: React.FunctionComponent = ({ ); }; + +const EmailParamsFields: React.FunctionComponent = ({ + action, + editAction, + errors, + hasErrors, +}) => { + const { to, subject, body } = action; + const toOptions = to ? to.map((label: any) => ({ label })) : []; + + return ( + + + { + const newOptions = [...toOptions, { label: searchValue }]; + editAction( + 'to', + newOptions.map(newOption => newOption.label) + ); + }} + onChange={(selectedOptions: Array<{ label: string }>) => { + editAction( + 'to', + selectedOptions.map(selectedOption => selectedOption.label) + ); + }} + onBlur={() => { + if (!to) { + editAction('to', []); + } + }} + /> + + + + { + editAction('subject', e.target.value); + }} + /> + + + + { + editAction('body', e.target.value); + }} + /> + + + ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx index 89a515a497fca1..b80e1ec1fcfc24 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx @@ -6,7 +6,8 @@ import React from 'react'; import { EuiFieldText, EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ActionTypeModel, Props, ValidationResult } from '../../../../types'; +import { ActionTypeModel, Props, ValidationResult, ParamsProps } from '../../../../types'; +import { ErrableFormRow } from '../../../components/page_error'; export function getActionType(): ActionTypeModel { return { @@ -22,6 +23,7 @@ export function getActionType(): ActionTypeModel { return { errors: {} }; }, actionFields: IndexActionFields, + actionParamsFields: IndexParamsFields, }; } @@ -51,3 +53,39 @@ const IndexActionFields: React.FunctionComponent = ({ action, editActionC ); }; + +const IndexParamsFields: React.FunctionComponent = ({ + action, + editAction, + errors, + hasErrors, +}) => { + const { index } = action; + return ( + + ) => { + editAction('index', e.target.value); + }} + onBlur={() => { + if (!index) { + editAction('index', ''); + } + }} + /> + + ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx index 57e57067dfeac3..04e02560ef2f80 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx @@ -7,7 +7,7 @@ import React, { Fragment } from 'react'; import { EuiFieldText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ErrableFormRow } from '../../../components/page_error'; -import { ActionTypeModel, Props, Action, ValidationResult } from '../../../../types'; +import { ActionTypeModel, Props, Action, ValidationResult, ParamsProps } from '../../../../types'; export function getActionType(): ActionTypeModel { return { @@ -49,6 +49,7 @@ export function getActionType(): ActionTypeModel { return validationResult; }, actionFields: PagerDutyActionFields, + actionParamsFields: PagerDutyParamsFields, }; } @@ -122,3 +123,46 @@ const PagerDutyActionFields: React.FunctionComponent = ({ ); }; + +const PagerDutyParamsFields: React.FunctionComponent = ({ + action, + editAction, + errors, + hasErrors, + children, +}) => { + const { description } = action; + return ( + + {children} + + ) => { + editAction('description', e.target.value); + }} + onBlur={() => { + if (!description) { + editAction('description', ''); + } + }} + /> + + + ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx index 06ec1eeb13b30e..536f954087a5a7 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx @@ -3,8 +3,11 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import React from 'react'; import { i18n } from '@kbn/i18n'; -import { ActionTypeModel, ValidationResult } from '../../../../types'; +import { EuiFieldText } from '@elastic/eui'; +import { ActionTypeModel, ValidationResult, ParamsProps } from '../../../../types'; +import { ErrableFormRow } from '../../../components/page_error'; export function getActionType(): ActionTypeModel { return { @@ -20,5 +23,45 @@ export function getActionType(): ActionTypeModel { return { errors: {} }; }, actionFields: null, + actionParamsFields: ServerLogParamsFields, }; } + +export const ServerLogParamsFields: React.FunctionComponent = ({ + action, + editAction, + errors, + hasErrors, +}) => { + const { text } = action; + return ( + + ) => { + editAction('text', e.target.value); + }} + onBlur={() => { + if (!text) { + editAction('text', ''); + } + }} + /> + + ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx index e3b174b31f81cd..71435d710801dc 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx @@ -4,10 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ import React, { Fragment } from 'react'; -import { EuiFieldText } from '@elastic/eui'; +import { EuiFieldText, EuiFormRow, EuiComboBox, EuiTextArea } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ErrableFormRow } from '../../../components/page_error'; -import { ActionTypeModel, Props, Action, ValidationResult } from '../../../../types'; +import { ActionTypeModel, Props, Action, ValidationResult, ParamsProps } from '../../../../types'; export function getActionType(): ActionTypeModel { return { @@ -38,6 +38,7 @@ export function getActionType(): ActionTypeModel { return validationResult; }, actionFields: SlackActionFields, + actionParamsFields: SlackParamsFields, }; } @@ -82,3 +83,69 @@ const SlackActionFields: React.FunctionComponent = ({ ); }; + +const SlackParamsFields: React.FunctionComponent = ({ + action, + editAction, + errors, + hasErrors, + children, +}) => { + const { text, to } = action; + const toOptions = to ? to.map((label: any) => ({ label })) : []; + + return ( + + {children} + + { + const newOptions = [...toOptions, { label: searchValue }]; + editAction( + 'to', + newOptions.map(newOption => newOption.label) + ); + }} + onChange={(selectedOptions: Array<{ label: string }>) => { + editAction( + 'to', + selectedOptions.map(selectedOption => selectedOption.label) + ); + }} + /> + + + + { + editAction('text', e.target.value); + }} + /> + + + ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx index f6c7fcaf460776..82d7bfde062102 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, useState } from 'react'; +import React, { Fragment, useState, useEffect } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { @@ -18,10 +18,12 @@ import { EuiButtonIcon, EuiText, EuiTitle, + EuiFieldNumber, + EuiCodeEditor, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ErrableFormRow } from '../../../components/page_error'; -import { ActionTypeModel, Props, Action, ValidationResult } from '../../../../types'; +import { ActionTypeModel, Props, Action, ValidationResult, ParamsProps } from '../../../../types'; const HTTP_VERBS = ['post', 'put']; @@ -87,6 +89,7 @@ export function getActionType(): ActionTypeModel { return validationResult; }, actionFields: WebhookActionFields, + actionParamsFields: WebhookParamsFields, }; } @@ -378,3 +381,211 @@ const WebhookActionFields: React.FunctionComponent = ({ ); }; + +const WebhookParamsFields: React.FunctionComponent = ({ + action, + editAction, + errors, + hasErrors, +}) => { + const { method, host, port, path, body, username, password } = action; + + useEffect(() => { + editAction('contentType', 'application/json'); // set content-type for threshold watch to json by default + }, [editAction]); + + return ( + + + + + ({ text: verb.toUpperCase(), value: verb }))} + onChange={e => { + editAction('method', e.target.value); + }} + /> + + + + + + { + editAction('host', e.target.value); + }} + onBlur={() => { + if (!host) { + editAction('host', ''); + } + }} + /> + + + + + + { + editAction('port', parseInt(e.target.value, 10)); + }} + onBlur={() => { + if (!port) { + editAction('port', ''); + } + }} + /> + + + + + + { + editAction('path', e.target.value); + }} + /> + + + + + + + + { + editAction('username', e.target.value); + }} + /> + + + + + + { + editAction('password', e.target.value); + }} + /> + + + + + + + + { + editAction('body', json); + }} + /> + + + ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 5a2f9635daa2ec..130b1351ee3cdf 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -29,13 +29,14 @@ import { EuiTab, EuiText, EuiLink, + EuiPanel, } from '@elastic/eui'; import { useAppDependencies } from '../..'; import { saveAlert } from '../../lib/api'; import { AlertsContext } from '../../context/alerts_context'; import { alertReducer } from './alert_reducer'; import { ErrableFormRow } from '../../components/page_error'; -import { AlertTypeModel, Alert, IErrorObject } from '../../../types'; +import { AlertTypeModel, Alert, IErrorObject, ActionTypeModel, AlertAction } from '../../../types'; import { ACTION_GROUPS } from '../../constants/action_groups'; interface Props { @@ -63,6 +64,7 @@ export const AlertAdd = ({ refreshList }: Props) => { core: { http }, plugins: { toastNotifications }, alertTypeRegistry, + actionTypeRegistry, } = useAppDependencies(); const [alertType, setAlertType] = useState(undefined); @@ -77,17 +79,21 @@ export const AlertAdd = ({ refreshList }: Props) => { const [{ alert }, dispatch] = useReducer(alertReducer, { alert: initialAlert }); const [isSaving, setIsSaving] = useState(false); const [selectedTabId, setSelectedTabId] = useState('alert'); + const [alertAction, setAlertAction] = useState(undefined); useEffect(() => { dispatch({ command: { type: 'setAlert' }, payload: { key: 'alert', - value: initialAlert, + value: { + alertTypeParams: {}, + alertTypeId: null, + actions: [], + }, }, }); - setAlertType(undefined); - }, [alertFlyoutVisible, initialAlert]); + }, [alertFlyoutVisible]); const setAlertProperty = (key: string, value: any) => { dispatch({ command: { type: 'setProperty' }, payload: { key, value } }); @@ -96,9 +102,16 @@ export const AlertAdd = ({ refreshList }: Props) => { const setAlertTypeParams = (key: string, value: any) => { dispatch({ command: { type: 'setAlertTypeParams' }, payload: { key, value } }); }; - const closeFlyout = useCallback(() => setAlertFlyoutVisibility(false), [ - setAlertFlyoutVisibility, - ]); + + const setActionParams = (key: string, value: any) => { + dispatch({ command: { type: 'setAlertActionParam' }, payload: { key, value } }); + }; + const closeFlyout = useCallback(() => { + setAlertFlyoutVisibility(false); + setAlertType(undefined); + setAlertAction(undefined); + setSelectedTabId('alert'); + }, [setAlertFlyoutVisibility]); if (!alertFlyoutVisible) { return null; @@ -114,16 +127,22 @@ export const AlertAdd = ({ refreshList }: Props) => { const tabs = [ { - id: ACTION_GROUPS.ALERT.toLowerCase(), - name: ACTION_GROUPS.ALERT, + id: ACTION_GROUPS.ALERT, + name: i18n.translate('xpack.alertingUI.sections.alertAdd.alertTabText', { + defaultMessage: 'Alert', + }), }, { - id: ACTION_GROUPS.WARNING.toLowerCase(), - name: ACTION_GROUPS.WARNING, + id: ACTION_GROUPS.WARNING, + name: i18n.translate('xpack.alertingUI.sections.alertAdd.warningTabText', { + defaultMessage: 'Warning', + }), }, { - id: ACTION_GROUPS.ESCALATION.toLowerCase(), - name: ACTION_GROUPS.ESCALATION, + id: ACTION_GROUPS.UNACKNOWLEDGED, + name: i18n.translate('xpack.alertingUI.sections.alertAdd.unacknowledgedTabText', { + defaultMessage: 'If unacknowledged', + }), disabled: false, }, ]; @@ -147,6 +166,10 @@ export const AlertAdd = ({ refreshList }: Props) => { } } + function addActionType(actionType: ActionTypeModel) { + setAlertAction({ id: actionType.id, group: selectedTabId, params: {} }); + } + const alertTypeNodes = alertTypeRegistry.list().map(function(item, index) { return ( @@ -160,6 +183,19 @@ export const AlertAdd = ({ refreshList }: Props) => { ); }); + const actionTypeNodes = actionTypeRegistry.list().map(function(item, index) { + return ( + + } + title={item.name} + description={''} + onClick={() => addActionType(item.actionType)} + /> + + ); + }); + const alertTabs = tabs.map(function(tab, index): any { return ( { ); }); - const alertDetails = ( + const alertTypeDetails = ( - - - -
+ + + + +
+ +
+
+
+ + setAlertType(undefined)}> -
-
-
- - setAlertType(undefined)}> - - - -
- {AlertTypeParamsExpressionComponent ? ( - - ) : null} + +
+
+ {AlertTypeParamsExpressionComponent ? ( + + ) : null} + ); + let alertDetails; + if (!alertAction) { + alertDetails = ( + + + +
+ +
+
+ + {actionTypeNodes} +
+ ); + } else { + alert.actions.push(alertAction); + const actionTypeRegisterd = actionTypeRegistry.get(alert.actions[0].id); + if (actionTypeRegisterd === null) return null; + const ParamsFieldsComponent = actionTypeRegisterd.actionParamsFields; + alertDetails = ( + + {ParamsFieldsComponent !== null ? ( + + ) : null} + + ); + } + const warningDetails = Warning; - const escalationDetails = Escalation; + const unacknowledgedDetails = Unacknowledged; let selectedTabContent; switch (selectedTabId) { - case ACTION_GROUPS.ALERT.toLowerCase(): + case ACTION_GROUPS.ALERT: selectedTabContent = alertDetails; break; - case ACTION_GROUPS.WARNING.toLowerCase(): + case ACTION_GROUPS.WARNING: selectedTabContent = warningDetails; break; - case ACTION_GROUPS.ESCALATION.toLowerCase(): - selectedTabContent = escalationDetails; + case ACTION_GROUPS.UNACKNOWLEDGED: + selectedTabContent = unacknowledgedDetails; break; default: selectedTabContent = null; @@ -232,7 +306,9 @@ export const AlertAdd = ({ refreshList }: Props) => { {alertTabs} - {selectedTabContent} + {alertTypeDetails} + + {selectedTabContent} ); } else { @@ -242,7 +318,7 @@ export const AlertAdd = ({ refreshList }: Props) => {
@@ -302,7 +378,7 @@ export const AlertAdd = ({ refreshList }: Props) => { label={i18n.translate( 'xpack.alertingUI.sections.actionAdd.indexAction.indexTextFieldLabel', { - defaultMessage: 'Tags', + defaultMessage: 'Tags (optional)', } )} > @@ -319,7 +395,10 @@ export const AlertAdd = ({ refreshList }: Props) => { }; })} onChange={async (selected: EuiComboBoxOptionProps[]) => { - setAlertProperty('tags', selected.map(aSelected => aSelected.value)); + setAlertProperty( + 'tags', + selected.map(aSelected => aSelected.value) + ); }} onBlur={() => { if (!alert.tags) { @@ -349,6 +428,7 @@ export const AlertAdd = ({ refreshList }: Props) => { data-test-subj="saveActionButton" type="submit" iconType="check" + isDisabled={hasErrors} isLoading={isSaving} onClick={async () => { setIsSaving(true); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts index e4f70a15e8a79b..08f2a3f24a8820 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts @@ -6,7 +6,7 @@ import { isEqual } from 'lodash'; interface CommandType { - type: 'setAlert' | 'setProperty' | 'setAlertTypeParams'; + type: 'setAlert' | 'setProperty' | 'setAlertTypeParams' | 'setAlertActionParam'; } export interface AlertState { @@ -28,7 +28,7 @@ export const alertReducer = (state: any, action: ActionAlertReducerItem) => { switch (command.type) { case 'setAlert': { const { key, value } = payload; - if (key === 'action') { + if (key === 'alert') { return { ...state, alert: value, @@ -68,5 +68,8 @@ export const alertReducer = (state: any, action: ActionAlertReducerItem) => { }; } } + case 'setAlertActionParam': { + return state; + } } }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts index ff8a6af3b66ad4..2540361b970827 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts @@ -15,6 +15,13 @@ export interface Props { hasErrors?: boolean; } +export interface ParamsProps { + action: any; + editAction: (property: string, value: any) => void; + errors: { [key: string]: string[] }; + hasErrors?: boolean; +} + export interface Pagination { index: number; size: number; @@ -26,6 +33,7 @@ export interface ActionTypeModel { selectMessage: string; validate: (action: Action) => ValidationResult; actionFields: React.FunctionComponent | null; + actionParamsFields: React.FunctionComponent | null; } export interface ValidationResult { From b656a493470b4ce37bb9d75b66e333b3c9c0e09a Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 15 Nov 2019 13:02:38 -0800 Subject: [PATCH 103/297] Added fields for check and re-notify alert --- .../application/lib/get_time_unit_label.ts | 8 +- .../sections/alert_add/alert_add.tsx | 174 +++++++++++++----- .../alerting_ui/np_ready/public/types.ts | 5 + 3 files changed, 142 insertions(+), 45 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/get_time_unit_label.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/get_time_unit_label.ts index eae42eb3af35da..3cf91a3b55cdbc 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/get_time_unit_label.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/get_time_unit_label.ts @@ -10,22 +10,22 @@ import { TIME_UNITS } from '../constants'; export function getTimeUnitLabel(timeUnit = TIME_UNITS.SECOND, timeValue = '0') { switch (timeUnit) { case TIME_UNITS.SECOND: - return i18n.translate('xpack.watcher.timeUnits.secondLabel', { + return i18n.translate('xpack.alertingUI.timeUnits.secondLabel', { defaultMessage: '{timeValue, plural, one {second} other {seconds}}', values: { timeValue }, }); case TIME_UNITS.MINUTE: - return i18n.translate('xpack.watcher.timeUnits.minuteLabel', { + return i18n.translate('xpack.alertingUI.timeUnits.minuteLabel', { defaultMessage: '{timeValue, plural, one {minute} other {minutes}}', values: { timeValue }, }); case TIME_UNITS.HOUR: - return i18n.translate('xpack.watcher.timeUnits.hourLabel', { + return i18n.translate('xpack.alertingUI.timeUnits.hourLabel', { defaultMessage: '{timeValue, plural, one {hour} other {hours}}', values: { timeValue }, }); case TIME_UNITS.DAY: - return i18n.translate('xpack.watcher.timeUnits.dayLabel', { + return i18n.translate('xpack.alertingUI.timeUnits.dayLabel', { defaultMessage: '{timeValue, plural, one {day} other {days}}', values: { timeValue }, }); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 130b1351ee3cdf..1d2d51e98efb5a 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -30,6 +30,9 @@ import { EuiText, EuiLink, EuiPanel, + EuiFieldNumber, + EuiSelect, + EuiIconTip, } from '@elastic/eui'; import { useAppDependencies } from '../..'; import { saveAlert } from '../../lib/api'; @@ -38,6 +41,8 @@ import { alertReducer } from './alert_reducer'; import { ErrableFormRow } from '../../components/page_error'; import { AlertTypeModel, Alert, IErrorObject, ActionTypeModel, AlertAction } from '../../../types'; import { ACTION_GROUPS } from '../../constants/action_groups'; +import { getTimeUnitLabel } from '../../lib/get_time_unit_label'; +import { TIME_UNITS } from '../../constants'; interface Props { refreshList: () => Promise; @@ -59,6 +64,14 @@ function validateBaseProperties(alertObject: Alert) { return validationResult; } +const getTimeOptions = (unitSize: string) => + Object.entries(TIME_UNITS).map(([_key, value]) => { + return { + text: getTimeUnitLabel(value, unitSize), + value, + }; + }); + export const AlertAdd = ({ refreshList }: Props) => { const { core: { http }, @@ -211,36 +224,35 @@ export const AlertAdd = ({ refreshList }: Props) => { const alertTypeDetails = ( - - - - -
- -
-
-
- - setAlertType(undefined)}> + + + +
- - - - {AlertTypeParamsExpressionComponent ? ( - - ) : null} - +
+
+
+ + setAlertType(undefined)}> + + + +
+ {AlertTypeParamsExpressionComponent ? ( + + ) : null}
); @@ -248,7 +260,6 @@ export const AlertAdd = ({ refreshList }: Props) => { if (!alertAction) { alertDetails = ( -
{ let alertTypeArea; if (alertType) { - alertTypeArea = ( - - - {alertTabs} - - {alertTypeDetails} - - {selectedTabContent} - - ); + alertTypeArea = {alertTypeDetails}; } else { alertTypeArea = ( -
{ ); } + const labelForAlertChecked = ( + <> + {' '} + + + ); + + const labelForAlertRenotify = ( + <> + {' '} + + + ); + return ( @@ -409,7 +442,66 @@ export const AlertAdd = ({ refreshList }: Props) => { - {alertTypeArea} + + + + + + + { + setAlertProperty('checkIntervalSize', e.target.value); + }} + /> + + + setAlertProperty('checkIntervalUnit', e.target.value)} + fullWidth={true} + /> + + + + + + + + + { + setAlertProperty('renotifyIntervalSize', e.target.value); + }} + /> + + + + setAlertProperty('renotifyIntervalUnit', e.target.value) + } + fullWidth={true} + /> + + + + + + + {alertTabs} + + {alertTypeArea} + + {selectedTabContent} + diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts index 2540361b970827..10bc474c4db352 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts @@ -84,6 +84,11 @@ export interface Alert { throttle: string | null; muteAll: boolean; mutedInstanceIds: string[]; + // TODO: replace this temporary fields with the proper server relevant + checkIntervalSize?: number; + checkIntervalUnit?: string; + renotifyIntervalSize?: number; + renotifyIntervalUnit?: string; } export interface AlertTableItem extends Alert { From 1a631a22a5e202cfb97e33cbd81b7c56adef05e6 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 19 Nov 2019 11:40:30 -0500 Subject: [PATCH 104/297] Add tags to alert list --- .../sections/alerts_list/components/alerts_list.tsx | 9 +++++++++ .../legacy/plugins/alerting_ui/np_ready/public/types.ts | 2 ++ 2 files changed, 11 insertions(+) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index a6b40453d12e21..626b87eb8c5857 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -69,6 +69,7 @@ export const AlertsList: React.FunctionComponent = () => { } const updatedData = alerts.map(alert => ({ ...alert, + tagsText: alert.tags.join(', '), alertType: alertTypesIndex[alert.alertTypeId] ? alertTypesIndex[alert.alertTypeId].name : alert.alertTypeId, @@ -126,6 +127,14 @@ export const AlertsList: React.FunctionComponent = () => { sortable: false, truncateText: true, }, + { + field: 'tagsText', + name: i18n.translate( + 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.tagsText', + { defaultMessage: 'Tags' } + ), + sortable: false, + }, { field: 'alertType', name: i18n.translate( diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts index 10bc474c4db352..d6b84f6e8e4d5c 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts @@ -72,6 +72,7 @@ export interface AlertAction { export interface Alert { id: string; name: string; + tags: string[]; enabled: boolean; alertTypeId: string; interval: string; @@ -93,6 +94,7 @@ export interface Alert { export interface AlertTableItem extends Alert { alertType: AlertType['name']; + tagsText: string; } export interface AlertTypeModel { From bf85deee962750829e0c2d9f8767a9a487071340 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 19 Nov 2019 08:50:09 -0800 Subject: [PATCH 105/297] Adjusted threshold expression with validation, added visualization --- .../components/page_error/form_errors.tsx | 2 +- .../constants/expression_fields.ts | 19 + .../public/application/constants/index.ts | 1 + .../np_ready/public/application/lib/api.ts | 48 +- .../application/lib/get_time_options.ts | 30 + .../action_add/buildin_action_types/email.tsx | 12 +- .../sections/alert_add/alert_add.tsx | 67 +- .../sections/alert_add/alert_types/index.ts | 2 +- .../alert_add/alert_types/threshold.tsx | 335 ------ .../alert_types/threshold/expression.tsx | 1049 +++++++++++++++++ .../alert_types/threshold/visualization.tsx | 295 +++++ .../alerting_ui/np_ready/public/plugin.ts | 5 +- 12 files changed, 1502 insertions(+), 363 deletions(-) create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/expression_fields.ts create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/get_time_options.ts delete mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold.tsx create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx create mode 100644 x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/form_errors.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/form_errors.tsx index 0a35d6cb5d1046..da0b19f1f0bebf 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/form_errors.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/form_errors.tsx @@ -14,7 +14,7 @@ export const ErrableFormRow = ({ ...rest }: { errorKey: string; - isShowingErrors: boolean; + isShowingErrors?: boolean; errors: { [key: string]: string[] }; children: ReactElement; [key: string]: any; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/expression_fields.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/expression_fields.ts new file mode 100644 index 00000000000000..f4ddf3f1982ab6 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/expression_fields.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export const expressionFields = [ + 'aggType', + 'aggField', + 'termSize', + 'termField', + 'thresholdComparator', + 'timeWindowSize', + 'timeWindowUnit', + 'triggerIntervalSize', + 'triggerIntervalUnit', + 'threshold', + 'groupBy', +]; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts index 06dfc53fca7b31..093018908e7e58 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts @@ -18,6 +18,7 @@ export const routeToAlerts = `${BASE_PATH}/alerts`; export { COMPARATORS } from './comparators'; export { AGGREGATION_TYPES } from './aggregation_types'; export { TIME_UNITS } from './time_units'; +export { expressionFields } from './expression_fields'; export const SORT_ORDERS: { [key: string]: string } = { ASCENDING: 'asc', DESCENDING: 'desc', diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index b1d9ee5797ff44..2251cf3769e85d 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -175,9 +175,16 @@ export async function getMatchingIndicesForThresholdAlertType({ pattern: string; http: HttpServiceBase; }): Promise> { - return await http.post(`${WATCHER_API_ROOT}/indices`, { + if (!pattern.startsWith('*')) { + pattern = `*${pattern}`; + } + if (!pattern.endsWith('*')) { + pattern = `${pattern}*`; + } + const { indices } = await http.post(`${WATCHER_API_ROOT}/indices`, { body: JSON.stringify(pattern), }); + return indices; } export async function getThresholdAlertTypeFields({ @@ -187,7 +194,44 @@ export async function getThresholdAlertTypeFields({ indices: string[]; http: HttpServiceBase; }): Promise> { - return await http.post(`${WATCHER_API_ROOT}/fields`, { + const { fields } = await http.post(`${WATCHER_API_ROOT}/fields`, { body: JSON.stringify(indices), }); + return fields; +} + +let savedObjectsClient: any; + +export const setSavedObjectsClient = (aSavedObjectsClient: any) => { + savedObjectsClient = aSavedObjectsClient; +}; + +export const getSavedObjectsClient = () => { + return savedObjectsClient; +}; + +export const loadIndexPatterns = async () => { + const { savedObjects } = await getSavedObjectsClient().find({ + type: 'index-pattern', + fields: ['title'], + perPage: 10000, + }); + return savedObjects; +}; + +export async function getThresholdAlertVisualizationData({ + model, + visualizeOptions, + http, +}: { + model: any; + visualizeOptions: any; + http: HttpServiceBase; +}): Promise> { + return await http.post(`${WATCHER_API_ROOT}/watch/visualize`, { + body: JSON.stringify({ + watch: model, + options: visualizeOptions, + }), + }); } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/get_time_options.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/get_time_options.ts new file mode 100644 index 00000000000000..5df6b83a07a276 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/get_time_options.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { getTimeUnitLabel } from './get_time_unit_label'; +import { TIME_UNITS } from '../constants'; + +export const getTimeOptions = (unitSize: string) => + Object.entries(TIME_UNITS).map(([_key, value]) => { + return { + text: getTimeUnitLabel(value, unitSize), + value, + }; + }); + +export const getTimeFieldOptions = (fields: any, firstFieldOption: any) => { + const options = [firstFieldOption]; + + fields.forEach((field: any) => { + if (field.type === 'date') { + options.push({ + text: field.name, + value: field.name, + }); + } + }); + return options; +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx index d7d9177a4c1d1c..76b87a156b11a7 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx @@ -97,7 +97,7 @@ const EmailActionFields: React.FunctionComponent = ({ errorKey="from" fullWidth errors={errors} - isShowingErrors={hasErrors === true && from !== undefined} + isShowingErrors={hasErrors && from !== undefined} label={i18n.translate( 'xpack.alertingUI.sections.actionAdd.emailAction.fromTextFieldLabel', { @@ -127,7 +127,7 @@ const EmailActionFields: React.FunctionComponent = ({ errorKey="host" fullWidth errors={errors} - isShowingErrors={hasErrors === true && host !== undefined} + isShowingErrors={hasErrors && host !== undefined} label={i18n.translate( 'xpack.alertingUI.sections.actionAdd.emailAction.hostTextFieldLabel', { @@ -157,7 +157,7 @@ const EmailActionFields: React.FunctionComponent = ({ errorKey="port" fullWidth errors={errors} - isShowingErrors={hasErrors === true && port !== undefined} + isShowingErrors={hasErrors && port !== undefined} label={i18n.translate( 'xpack.alertingUI.sections.actionAdd.emailAction.portTextFieldLabel', { @@ -190,7 +190,7 @@ const EmailActionFields: React.FunctionComponent = ({ errorKey="user" fullWidth errors={errors} - isShowingErrors={hasErrors === true && user !== undefined} + isShowingErrors={hasErrors && user !== undefined} label={i18n.translate( 'xpack.alertingUI.sections.actionAdd.emailAction.userTextFieldLabel', { @@ -220,7 +220,7 @@ const EmailActionFields: React.FunctionComponent = ({ errorKey="password" fullWidth errors={errors} - isShowingErrors={hasErrors === true && password !== undefined} + isShowingErrors={hasErrors && password !== undefined} label={i18n.translate( 'xpack.alertingUI.sections.actionAdd.emailAction.passwordFieldLabel', { @@ -265,7 +265,7 @@ const EmailParamsFields: React.FunctionComponent = ({ errorKey="to" fullWidth errors={errors} - isShowingErrors={hasErrors === true && to !== undefined} + isShowingErrors={hasErrors && to !== undefined} label={i18n.translate( 'xpack.alertingUI.sections.actionAdd.emailAction.recipientTextFieldLabel', { diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 1d2d51e98efb5a..713b3284f441e1 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -27,7 +27,6 @@ import { EuiCard, EuiTabs, EuiTab, - EuiText, EuiLink, EuiPanel, EuiFieldNumber, @@ -35,14 +34,20 @@ import { EuiIconTip, } from '@elastic/eui'; import { useAppDependencies } from '../..'; -import { saveAlert } from '../../lib/api'; +import { saveAlert, loadActionTypes } from '../../lib/api'; import { AlertsContext } from '../../context/alerts_context'; import { alertReducer } from './alert_reducer'; import { ErrableFormRow } from '../../components/page_error'; -import { AlertTypeModel, Alert, IErrorObject, ActionTypeModel, AlertAction } from '../../../types'; +import { + AlertTypeModel, + Alert, + IErrorObject, + ActionTypeModel, + AlertAction, + ActionTypeIndex, +} from '../../../types'; import { ACTION_GROUPS } from '../../constants/action_groups'; -import { getTimeUnitLabel } from '../../lib/get_time_unit_label'; -import { TIME_UNITS } from '../../constants'; +import { getTimeOptions } from '../../lib/get_time_options'; interface Props { refreshList: () => Promise; @@ -64,14 +69,6 @@ function validateBaseProperties(alertObject: Alert) { return validationResult; } -const getTimeOptions = (unitSize: string) => - Object.entries(TIME_UNITS).map(([_key, value]) => { - return { - text: getTimeUnitLabel(value, unitSize), - value, - }; - }); - export const AlertAdd = ({ refreshList }: Props) => { const { core: { http }, @@ -79,8 +76,6 @@ export const AlertAdd = ({ refreshList }: Props) => { alertTypeRegistry, actionTypeRegistry, } = useAppDependencies(); - const [alertType, setAlertType] = useState(undefined); - const initialAlert = { alertTypeParams: {}, alertTypeId: null, @@ -89,10 +84,36 @@ export const AlertAdd = ({ refreshList }: Props) => { const { alertFlyoutVisible, setAlertFlyoutVisibility } = useContext(AlertsContext); // hooks + const [alertType, setAlertType] = useState(undefined); const [{ alert }, dispatch] = useReducer(alertReducer, { alert: initialAlert }); const [isSaving, setIsSaving] = useState(false); + const [isLoadingActionTypes, setIsLoadingActionTypes] = useState(false); const [selectedTabId, setSelectedTabId] = useState('alert'); const [alertAction, setAlertAction] = useState(undefined); + const [actionTypesIndex, setActionTypesIndex] = useState(undefined); + + useEffect(() => { + (async () => { + try { + setIsLoadingActionTypes(true); + const actionTypes = await loadActionTypes({ http }); + const index: ActionTypeIndex = {}; + for (const actionTypeItem of actionTypes) { + index[actionTypeItem.id] = actionTypeItem; + } + setActionTypesIndex(index); + } catch (e) { + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.alertingUI.sections.alertAdd.unableToLoadActionTypesMessage', + { defaultMessage: 'Unable to load action types' } + ), + }); + } finally { + setIsLoadingActionTypes(false); + } + })(); + }, [toastNotifications, http]); useEffect(() => { dispatch({ @@ -138,6 +159,18 @@ export const AlertAdd = ({ refreshList }: Props) => { } as IErrorObject; const hasErrors = !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); + const actionErrors = alert.actions.reduce((acc: any, action: any) => { + const actionValidationErrors = action.validate(); + acc[action.id] = actionValidationErrors; + return acc; + }, {}); + + const hasActionErrors = !!Object.keys(actionErrors).find(actionError => { + return !!Object.keys(actionErrors[actionError]).find((actionErrorKey: string) => { + return actionErrors[actionError][actionErrorKey].length >= 1; + }); + }); + const tabs = [ { id: ACTION_GROUPS.ALERT, @@ -201,7 +234,7 @@ export const AlertAdd = ({ refreshList }: Props) => { } - title={item.name} + title={actionTypesIndex ? actionTypesIndex[item.id].name : item.name} description={''} onClick={() => addActionType(item.actionType)} /> @@ -520,7 +553,7 @@ export const AlertAdd = ({ refreshList }: Props) => { data-test-subj="saveActionButton" type="submit" iconType="check" - isDisabled={hasErrors} + isDisabled={hasErrors || hasActionErrors} isLoading={isSaving} onClick={async () => { setIsSaving(true); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/index.ts index a0f2e5e6671c80..17fdffb40d2c17 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/index.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { getActionType as getThresholdAlertType } from './threshold'; +import { getActionType as getThresholdAlertType } from './threshold/expression'; import { AlertTypeRegistry } from '../../../alert_type_registry'; export function registerAlertTypes({ diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold.tsx deleted file mode 100644 index 8751765e0d341c..00000000000000 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold.tsx +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React, { useState } from 'react'; -import { i18n } from '@kbn/i18n'; -import { - EuiFlexItem, - EuiFlexGroup, - EuiExpression, - EuiPopover, - EuiPopoverTitle, - EuiSelect, -} from '@elastic/eui'; -import { AlertTypeModel, AlertType, Alert, ValidationResult } from '../../../../types'; -import { Comparator, AggregationType, GroupByType } from './types'; -import { COMPARATORS, AGGREGATION_TYPES, TIME_UNITS } from '../../../constants'; -import { - getMatchingIndicesForThresholdAlertType, - getThresholdAlertTypeFields, -} from '../../../lib/api'; -import { getTimeUnitLabel } from '../../../lib/get_time_unit_label'; -import { useAppDependencies } from '../../..'; - -const DEFAULT_VALUES = { - AGG_TYPE: 'count', - TERM_SIZE: 5, - THRESHOLD_COMPARATOR: COMPARATORS.GREATER_THAN, - TIME_WINDOW_SIZE: 5, - TIME_WINDOW_UNIT: 'm', - TRIGGER_INTERVAL_SIZE: 1, - TRIGGER_INTERVAL_UNIT: 'm', - THRESHOLD: [1000, 5000], - GROUP_BY: 'all', -}; - -export function getActionType(): AlertTypeModel { - return { - id: 'threshold', - name: 'Index Threshold', - iconClass: 'alert', - alertTypeParamsExpression: IndexThresholdAlertTypeExpression, - validate: validateAlertType, - }; -} - -interface Props { - alert: Alert; - setAlertTypeParams: (property: string, value: any) => void; - errors: { [key: string]: string[] }; - hasErrors?: boolean; -} - -function validateAlertType(alert: Alert): ValidationResult { - return { errors: {} }; -} - -export const IndexThresholdAlertTypeExpression: React.FunctionComponent = ({ - alert, - setAlertTypeParams, - errors, - hasErrors, -}) => { - const { - core: { http }, - } = useAppDependencies(); - const firstFieldOption = { - text: i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.timeFieldOptionLabel', { - defaultMessage: 'Select a field', - }), - value: '', - }; - - const [aggTypePopoverOpen, setAggTypePopoverOpen] = useState(false); - const [indexPattern, setIndexPattern] = useState([]); - const [esFields, setEsFields] = useState([]); - const [indexOptions, setIndexOptions] = useState([]); - const [timeFieldOptions, setTimeFieldOptions] = useState([firstFieldOption]); - - const [aggFieldPopoverOpen, setAggFieldPopoverOpen] = useState(false); - const [groupByPopoverOpen, setGroupByPopoverOpen] = useState(false); - - const comparators: { [key: string]: Comparator } = { - [COMPARATORS.GREATER_THAN]: { - text: i18n.translate( - 'xpack.alertingUI.sections.alertAdd.threshold.comparators.isAboveLabel', - { - defaultMessage: 'Is above', - } - ), - value: COMPARATORS.GREATER_THAN, - requiredValues: 1, - }, - [COMPARATORS.GREATER_THAN_OR_EQUALS]: { - text: i18n.translate( - 'xpack.alertingUI.sections.alertAdd.threshold.comparators.isAboveOrEqualsLabel', - { - defaultMessage: 'Is above or equals', - } - ), - value: COMPARATORS.GREATER_THAN_OR_EQUALS, - requiredValues: 1, - }, - [COMPARATORS.LESS_THAN]: { - text: i18n.translate( - 'xpack.alertingUI.sections.alertAdd.threshold.comparators.isBelowLabel', - { - defaultMessage: 'Is below', - } - ), - value: COMPARATORS.LESS_THAN, - requiredValues: 1, - }, - [COMPARATORS.LESS_THAN_OR_EQUALS]: { - text: i18n.translate( - 'xpack.alertingUI.sections.alertAdd.threshold.comparators.isBelowOrEqualsLabel', - { - defaultMessage: 'Is below or equals', - } - ), - value: COMPARATORS.LESS_THAN_OR_EQUALS, - requiredValues: 1, - }, - [COMPARATORS.BETWEEN]: { - text: i18n.translate( - 'xpack.alertingUI.sections.alertAdd.threshold.comparators.isBetweenLabel', - { - defaultMessage: 'Is between', - } - ), - value: COMPARATORS.BETWEEN, - requiredValues: 2, - }, - }; - - const aggregationTypes: { [key: string]: AggregationType } = { - count: { - text: 'count()', - fieldRequired: false, - value: AGGREGATION_TYPES.COUNT, - validNormalizedTypes: [], - }, - avg: { - text: 'average()', - fieldRequired: true, - validNormalizedTypes: ['number'], - value: AGGREGATION_TYPES.AVERAGE, - }, - sum: { - text: 'sum()', - fieldRequired: true, - validNormalizedTypes: ['number'], - value: AGGREGATION_TYPES.SUM, - }, - min: { - text: 'min()', - fieldRequired: true, - validNormalizedTypes: ['number', 'date'], - value: AGGREGATION_TYPES.MIN, - }, - max: { - text: 'max()', - fieldRequired: true, - validNormalizedTypes: ['number', 'date'], - value: AGGREGATION_TYPES.MAX, - }, - }; - - const groupByTypes: { [key: string]: GroupByType } = { - all: { - text: i18n.translate( - 'xpack.watcher.thresholdWatchExpression.groupByLabel.allDocumentsLabel', - { - defaultMessage: 'all documents', - } - ), - sizeRequired: false, - value: 'all', - validNormalizedTypes: [], - }, - top: { - text: i18n.translate('xpack.watcher.thresholdWatchExpression.groupByLabel.topLabel', { - defaultMessage: 'top', - }), - sizeRequired: true, - value: 'top', - validNormalizedTypes: ['number', 'date', 'keyword'], - }, - }; - - const expressionErrorMessage = i18n.translate( - 'xpack.alertingUI.sections.alertAdd.threshold.fixErrorInExpressionBelowValidationMessage', - { - defaultMessage: 'Expression contains errors.', - } - ); - - const getTimeOptions = (unitSize: string) => - Object.entries(TIME_UNITS).map(([_key, value]) => { - return { - text: getTimeUnitLabel(value, unitSize), - value, - }; - }); - - const getFields = async (indices: string[]) => { - return await getThresholdAlertTypeFields({ indices, http }); - }; - const getTimeFieldOptions = (fields: any) => { - const options = [firstFieldOption]; - - fields.forEach((field: any) => { - if (field.type === 'date') { - options.push({ - text: field.name, - value: field.name, - }); - } - }); - return options; - }; - - interface IOption { - label: string; - options: Array<{ value: string; label: string }>; - } - - const getIndexOptions = async (pattern: string, indexPatterns: string[]) => { - const options: IOption[] = []; - - if (!pattern) { - return options; - } - - const matchingIndices = (await getMatchingIndicesForThresholdAlertType({ - pattern, - http, - })) as string[]; - const matchingIndexPatterns = indexPatterns.filter(anIndexPattern => { - return anIndexPattern.includes(pattern); - }) as string[]; - - if (matchingIndices.length || matchingIndexPatterns.length) { - const matchingOptions = _.uniq([...matchingIndices, ...matchingIndexPatterns]); - - options.push({ - label: i18n.translate( - 'xpack.alertingUI.sections.alertAdd.threshold.indicesAndIndexPatternsLabel', - { - defaultMessage: 'Based on your indices and index patterns', - } - ), - options: matchingOptions.map(match => { - return { - label: match, - value: match, - }; - }), - }); - } - - options.push({ - label: i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.chooseLabel', { - defaultMessage: 'Choose…', - }), - options: [ - { - value: pattern, - label: pattern, - }, - ], - }); - - return options; - }; - - return ( - - - { - setAggTypePopoverOpen(true); - }} - /> - } - isOpen={aggTypePopoverOpen} - closePopover={() => { - setAggTypePopoverOpen(false); - }} - ownFocus - withTitle - anchorPosition="downLeft" - > -
- - {i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.whenButtonLabel', { - defaultMessage: 'when', - })} - - { - setAlertTypeParams('aggType', e.target.value); - setAggTypePopoverOpen(false); - }} - options={Object.values(aggregationTypes).map(({ text, value }) => { - return { - text, - value, - }; - })} - /> -
-
-
-
- ); -}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx new file mode 100644 index 00000000000000..ca54cf4b02fe73 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx @@ -0,0 +1,1049 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useState, Fragment, useEffect } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + EuiFlexItem, + EuiFlexGroup, + EuiExpression, + EuiPopover, + EuiPopoverTitle, + EuiSelect, + EuiSpacer, + EuiComboBox, + EuiFieldNumber, + EuiComboBoxOptionProps, + EuiText, +} from '@elastic/eui'; +import { AlertTypeModel, AlertType, Alert, ValidationResult } from '../../../../../types'; +import { Comparator, AggregationType, GroupByType } from '../types'; +import { COMPARATORS, AGGREGATION_TYPES, expressionFields } from '../../../../constants'; +import { + getMatchingIndicesForThresholdAlertType, + getThresholdAlertTypeFields, + loadIndexPatterns, +} from '../../../../lib/api'; +import { useAppDependencies } from '../../../..'; +import { ErrableFormRow } from '../../../../components/page_error'; +import { getTimeOptions, getTimeFieldOptions } from '../../../../lib/get_time_options'; +import { getTimeUnitLabel } from '../../../../lib/get_time_unit_label'; +import { ThresholdVisualization } from './visualization'; + +const DEFAULT_VALUES = { + AGGREGATION_TYPE: 'count', + TERM_SIZE: 5, + THRESHOLD_COMPARATOR: COMPARATORS.GREATER_THAN, + TIME_WINDOW_SIZE: 5, + TIME_WINDOW_UNIT: 'm', + TRIGGER_INTERVAL_SIZE: 1, + TRIGGER_INTERVAL_UNIT: 'm', + THRESHOLD: [1000, 5000], + GROUP_BY: 'all', +}; + +const expressionFieldsWithValidation = [ + 'index', + 'timeField', + 'triggerIntervalSize', + 'aggField', + 'termSize', + 'termField', + 'threshold0', + 'threshold1', + 'timeWindowSize', +]; + +export function getActionType(): AlertTypeModel { + return { + id: 'threshold', + name: 'Index Threshold', + iconClass: 'alert', + alertTypeParamsExpression: IndexThresholdAlertTypeExpression, + validate: validateAlertType, + }; +} + +export const aggregationTypes: { [key: string]: AggregationType } = { + count: { + text: 'count()', + fieldRequired: false, + value: AGGREGATION_TYPES.COUNT, + validNormalizedTypes: [], + }, + avg: { + text: 'average()', + fieldRequired: true, + validNormalizedTypes: ['number'], + value: AGGREGATION_TYPES.AVERAGE, + }, + sum: { + text: 'sum()', + fieldRequired: true, + validNormalizedTypes: ['number'], + value: AGGREGATION_TYPES.SUM, + }, + min: { + text: 'min()', + fieldRequired: true, + validNormalizedTypes: ['number', 'date'], + value: AGGREGATION_TYPES.MIN, + }, + max: { + text: 'max()', + fieldRequired: true, + validNormalizedTypes: ['number', 'date'], + value: AGGREGATION_TYPES.MAX, + }, +}; + +export const comparators: { [key: string]: Comparator } = { + [COMPARATORS.GREATER_THAN]: { + text: i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.comparators.isAboveLabel', { + defaultMessage: 'Is above', + }), + value: COMPARATORS.GREATER_THAN, + requiredValues: 1, + }, + [COMPARATORS.GREATER_THAN_OR_EQUALS]: { + text: i18n.translate( + 'xpack.alertingUI.sections.alertAdd.threshold.comparators.isAboveOrEqualsLabel', + { + defaultMessage: 'Is above or equals', + } + ), + value: COMPARATORS.GREATER_THAN_OR_EQUALS, + requiredValues: 1, + }, + [COMPARATORS.LESS_THAN]: { + text: i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.comparators.isBelowLabel', { + defaultMessage: 'Is below', + }), + value: COMPARATORS.LESS_THAN, + requiredValues: 1, + }, + [COMPARATORS.LESS_THAN_OR_EQUALS]: { + text: i18n.translate( + 'xpack.alertingUI.sections.alertAdd.threshold.comparators.isBelowOrEqualsLabel', + { + defaultMessage: 'Is below or equals', + } + ), + value: COMPARATORS.LESS_THAN_OR_EQUALS, + requiredValues: 1, + }, + [COMPARATORS.BETWEEN]: { + text: i18n.translate( + 'xpack.alertingUI.sections.alertAdd.threshold.comparators.isBetweenLabel', + { + defaultMessage: 'Is between', + } + ), + value: COMPARATORS.BETWEEN, + requiredValues: 2, + }, +}; + +interface Props { + alert: Alert; + setAlertTypeParams: (property: string, value: any) => void; + errors: { [key: string]: string[] }; + hasErrors?: boolean; +} + +function validateAlertType(alert: Alert): ValidationResult { + const validationResult = { errors: {} }; + const errors = { + aggField: new Array(), + termSize: new Array(), + termField: new Array(), + timeWindowSize: new Array(), + threshold0: new Array(), + threshold1: new Array(), + index: new Array(), + timeField: new Array(), + triggerIntervalSize: new Array(), + }; + validationResult.errors = errors; + if (!alert.alertTypeParams.index) { + errors.index.push( + i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredIndexText', { + defaultMessage: 'Index is required.', + }) + ); + } + if (!alert.alertTypeParams.timeField) { + errors.timeField.push( + i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredTimeFieldText', { + defaultMessage: 'Time field is required.', + }) + ); + } + if (!alert.alertTypeParams.triggerIntervalSize) { + errors.triggerIntervalSize.push( + i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredTriggerIntervalSizeText', { + defaultMessage: 'Trigger interval size is required.', + }) + ); + } + if (!alert.alertTypeParams.aggField) { + errors.aggField.push( + i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredAggFieldText', { + defaultMessage: 'Aggregation field is required.', + }) + ); + } + if (!alert.alertTypeParams.termSize) { + errors.termSize.push( + i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredTermSizedText', { + defaultMessage: 'Term size is required.', + }) + ); + } + if (!alert.alertTypeParams.termField) { + errors.termField.push( + i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredtTermFieldText', { + defaultMessage: 'Term field is required.', + }) + ); + } + if (!alert.alertTypeParams.timeWindowSize) { + errors.timeWindowSize.push( + i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredTimeWindowSizeText', { + defaultMessage: 'Time window size is required.', + }) + ); + } + if ( + alert.alertTypeParams.threshold && + alert.alertTypeParams.threshold.length > 0 && + !alert.alertTypeParams.threshold[0] + ) { + errors.threshold0.push( + i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredThreshold0Text', { + defaultMessage: 'Threshold0, is required.', + }) + ); + } + if ( + alert.alertTypeParams.threshold && + alert.alertTypeParams.threshold.length > 1 && + !alert.alertTypeParams.threshold[1] + ) { + errors.threshold1.push( + i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredThreshold1Text', { + defaultMessage: 'Threshold1 is required.', + }) + ); + } + return validationResult; +} + +export const IndexThresholdAlertTypeExpression: React.FunctionComponent = ({ + alert, + setAlertTypeParams, + errors, + hasErrors, +}) => { + const { + core: { http }, + } = useAppDependencies(); + + const { + index, + timeField, + triggerIntervalSize, + triggerIntervalUnit, + aggType, + aggField, + groupBy, + termSize, + termField, + thresholdComparator, + threshold, + timeWindowSize, + timeWindowUnit, + } = alert.alertTypeParams; + + const firstFieldOption = { + text: i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.timeFieldOptionLabel', { + defaultMessage: 'Select a field', + }), + value: '', + }; + + const [aggTypePopoverOpen, setAggTypePopoverOpen] = useState(false); + const [indexPopoverOpen, setIndexPopoverOpen] = useState(false); + const [indexPatterns, setIndexPatterns] = useState([]); + const [esFields, setEsFields] = useState>([]); + const [indexOptions, setIndexOptions] = useState([]); + const [timeFieldOptions, setTimeFieldOptions] = useState([firstFieldOption]); + const [isIndiciesLoading, setIsIndiciesLoading] = useState(false); + const [alertThresholdPopoverOpen, setAlertThresholdPopoverOpen] = useState(false); + const [alertDurationPopoverOpen, setAlertDurationPopoverOpen] = useState(false); + + const [aggFieldPopoverOpen, setAggFieldPopoverOpen] = useState(false); + const [groupByPopoverOpen, setGroupByPopoverOpen] = useState(false); + + const andThresholdText = i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.andLabel', { + defaultMessage: 'AND', + }); + + const hasExpressionErrors = !!Object.keys(errors).find( + errorKey => expressionFieldsWithValidation.includes(errorKey) && errors[errorKey].length >= 1 + ); + + const getIndexPatterns = async () => { + const indexPatternObjects = await loadIndexPatterns(); + const titles = indexPatternObjects.map((indexPattern: any) => indexPattern.attributes.title); + setIndexPatterns(titles); + }; + + const groupByTypes: { [key: string]: GroupByType } = { + all: { + text: i18n.translate( + 'xpack.alertingUI.sections.alertAdd.threshold.groupByLabel.allDocumentsLabel', + { + defaultMessage: 'all documents', + } + ), + sizeRequired: false, + value: 'all', + validNormalizedTypes: [], + }, + top: { + text: i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.groupByLabel.topLabel', { + defaultMessage: 'top', + }), + sizeRequired: true, + value: 'top', + validNormalizedTypes: ['number', 'date', 'keyword'], + }, + }; + + const expressionErrorMessage = i18n.translate( + 'xpack.alertingUI.sections.alertAdd.threshold.fixErrorInExpressionBelowValidationMessage', + { + defaultMessage: 'Expression contains errors.', + } + ); + + function setDefaultValues() { + setAlertTypeParams('aggType', DEFAULT_VALUES.AGGREGATION_TYPE); + setAlertTypeParams('termSize', DEFAULT_VALUES.TERM_SIZE); + setAlertTypeParams('thresholdComparator', DEFAULT_VALUES.THRESHOLD_COMPARATOR); + setAlertTypeParams('timeWindowSize', DEFAULT_VALUES.TIME_WINDOW_SIZE); + setAlertTypeParams('timeWindowUnit', DEFAULT_VALUES.TIME_WINDOW_UNIT); + setAlertTypeParams('triggerIntervalSize', DEFAULT_VALUES.TRIGGER_INTERVAL_SIZE); + setAlertTypeParams('triggerIntervalUnit', DEFAULT_VALUES.TRIGGER_INTERVAL_UNIT); + setAlertTypeParams('groupBy', DEFAULT_VALUES.GROUP_BY); + if (termField !== null) { + setAlertTypeParams('groupBy', 'top'); + } + setAlertTypeParams('threshold', DEFAULT_VALUES.THRESHOLD); + } + + const loadData = async () => { + if (index && index.length > 0) { + const allEsFields = await getFields(index); + const timeFields = getTimeFieldOptions(allEsFields, firstFieldOption); + setEsFields(allEsFields); + setTimeFieldOptions(timeFields); + setAlertTypeParams('timeFields', timeFields); + } + getIndexPatterns(); + }; + + useEffect(() => { + loadData(); + setDefaultValues(); + }); + + const getFields = async (indices: string[]) => { + return await getThresholdAlertTypeFields({ indices, http }); + }; + + interface IOption { + label: string; + options: Array<{ value: string; label: string }>; + } + + const getIndexOptions = async (pattern: string, indexPatternsParam: string[]) => { + const options: IOption[] = []; + + if (!pattern) { + return options; + } + + const matchingIndices = (await getMatchingIndicesForThresholdAlertType({ + pattern, + http, + })) as string[]; + const matchingIndexPatterns = indexPatternsParam.filter(anIndexPattern => { + return anIndexPattern.includes(pattern); + }) as string[]; + + if (matchingIndices.length || matchingIndexPatterns.length) { + const matchingOptions = _.uniq([...matchingIndices, ...matchingIndexPatterns]); + + options.push({ + label: i18n.translate( + 'xpack.alertingUI.sections.alertAdd.threshold.indicesAndIndexPatternsLabel', + { + defaultMessage: 'Based on your indices and index patterns', + } + ), + options: matchingOptions.map(match => { + return { + label: match, + value: match, + }; + }), + }); + } + + options.push({ + label: i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.chooseLabel', { + defaultMessage: 'Choose…', + }), + options: [ + { + value: pattern, + label: pattern, + }, + ], + }); + + return options; + }; + + const indexPopover = ( + + + + + + } + errorKey="index" + isShowingErrors={hasErrors && index !== undefined} + errors={errors} + helpText={ + + } + > + { + return { + label: anIndex, + value: anIndex, + }; + })} + onChange={async (selected: EuiComboBoxOptionProps[]) => { + setAlertTypeParams( + 'index', + selected.map(aSelected => aSelected.value) + ); + const indices = selected.map(s => s.value as string); + + // reset time field and expression fields if indices are deleted + if (indices.length === 0) { + setTimeFieldOptions(getTimeFieldOptions([], firstFieldOption)); + setAlertTypeParams('timeFields', []); + + expressionFields.forEach(expressionField => { + setAlertTypeParams(expressionField, null); + }); + return; + } + const currentEsFields = await getFields(indices); + const timeFields = getTimeFieldOptions(currentEsFields, firstFieldOption); + + setEsFields(currentEsFields); + setAlertTypeParams('timeFields', timeFields); + setTimeFieldOptions(timeFields); + }} + onSearchChange={async search => { + setIsIndiciesLoading(true); + setIndexOptions(await getIndexOptions(search, indexPatterns)); + setIsIndiciesLoading(false); + }} + onBlur={() => { + if (!index) { + setAlertTypeParams('index', []); + } + }} + /> + + + + + } + errorKey="timeField" + isShowingErrors={hasErrors && timeField !== undefined} + errors={errors} + > + { + setAlertTypeParams('timeField', e.target.value); + }} + onBlur={() => { + if (timeField === undefined) { + setAlertTypeParams('timeField', ''); + } + }} + /> + + + + + } + errorKey="triggerIntervalSize" + isShowingErrors={hasErrors && triggerIntervalSize !== undefined} + errors={errors} + > + + + { + const { value } = e.target; + const triggerIntervalSizeVal = value !== '' ? parseInt(value, 10) : value; + setAlertTypeParams('triggerIntervalSize', triggerIntervalSizeVal); + }} + onBlur={e => { + if (triggerIntervalSize === undefined) { + setAlertTypeParams('triggerIntervalSize', ''); + } + }} + /> + + + { + setAlertTypeParams('triggerIntervalUnit', e.target.value); + }} + options={getTimeOptions(triggerIntervalSize)} + /> + + + + + + + + ); + + return ( + + + + { + setIndexPopoverOpen(true); + }} + color={index ? 'secondary' : 'danger'} + /> + } + isOpen={indexPopoverOpen} + closePopover={() => { + setIndexPopoverOpen(false); + }} + ownFocus + withTitle + anchorPosition="downLeft" + > +
+ + {i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.insideButtonLabel', { + defaultMessage: 'inside', + })} + + {indexPopover} +
+
+
+ + { + setAggTypePopoverOpen(true); + }} + /> + } + isOpen={aggTypePopoverOpen} + closePopover={() => { + setAggTypePopoverOpen(false); + }} + ownFocus + withTitle + anchorPosition="downLeft" + > +
+ + {i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.whenButtonLabel', { + defaultMessage: 'when', + })} + + { + setAlertTypeParams('aggType', e.target.value); + setAggTypePopoverOpen(false); + }} + options={Object.values(aggregationTypes).map(({ text, value }) => { + return { + text, + value, + }; + })} + /> +
+
+
+ {aggType && aggregationTypes[aggType].fieldRequired ? ( + + { + setAggFieldPopoverOpen(true); + }} + color={aggField ? 'secondary' : 'danger'} + /> + } + isOpen={aggFieldPopoverOpen} + closePopover={() => { + setAggFieldPopoverOpen(false); + }} + anchorPosition="downLeft" + > +
+ + {i18n.translate('xpack.watcher.sections.watchEdit.threshold.ofButtonLabel', { + defaultMessage: 'of', + })} + + + + + { + if ( + aggregationTypes[aggType].validNormalizedTypes.includes( + field.normalizedType + ) + ) { + esFieldOptions.push({ + label: field.name, + }); + } + return esFieldOptions; + }, [])} + selectedOptions={aggField ? [{ label: aggField }] : []} + onChange={selectedOptions => { + setAlertTypeParams( + 'aggField', + selectedOptions.length === 1 ? selectedOptions[0].label : undefined + ); + setAggFieldPopoverOpen(false); + }} + /> + + + +
+
+
+ ) : null} + + { + setGroupByPopoverOpen(true); + }} + color={groupBy === 'all' || (termSize && termField) ? 'secondary' : 'danger'} + /> + } + isOpen={groupByPopoverOpen} + closePopover={() => { + setGroupByPopoverOpen(false); + }} + ownFocus + withTitle + anchorPosition="downLeft" + > +
+ + {i18n.translate('xpack.watcher.sections.watchEdit.threshold.overButtonLabel', { + defaultMessage: 'over', + })} + + + + { + setAlertTypeParams('termSize', null); + setAlertTypeParams('termField', null); + setAlertTypeParams('groupBy', e.target.value); + }} + options={Object.values(groupByTypes).map(({ text, value }) => { + return { + text, + value, + }; + })} + /> + + + {groupByTypes[groupBy || DEFAULT_VALUES.GROUP_BY].sizeRequired ? ( + + + + { + setAlertTypeParams('termSize', e.target.value); + }} + min={1} + /> + + + + + { + setAlertTypeParams('termField', e.target.value); + }} + options={esFields.reduce( + (options: any, field: any) => { + if ( + groupByTypes[ + groupBy || DEFAULT_VALUES.GROUP_BY + ].validNormalizedTypes.includes(field.normalizedType) + ) { + options.push({ + text: field.name, + value: field.name, + }); + } + return options; + }, + [firstFieldOption] + )} + /> + + + + ) : null} + +
+
+
+ + { + setAlertThresholdPopoverOpen(true); + }} + color={ + (errors.threshold0 && errors.threshold0.length) || + (errors.threshold1 && errors.threshold1.length) + ? 'danger' + : 'secondary' + } + /> + } + isOpen={alertThresholdPopoverOpen} + closePopover={() => { + setAlertThresholdPopoverOpen(false); + }} + ownFocus + withTitle + anchorPosition="downLeft" + > +
+ + {comparators[thresholdComparator || DEFAULT_VALUES.THRESHOLD_COMPARATOR].text} + + + + { + setAlertTypeParams('thresholdComparator', e.target.value); + }} + options={Object.values(comparators).map(({ text, value }) => { + return { text, value }; + })} + /> + + {Array.from( + Array( + comparators[thresholdComparator || DEFAULT_VALUES.THRESHOLD_COMPARATOR] + .requiredValues + ) + ).map((_notUsed, i) => { + return ( + + {i > 0 ? ( + + {andThresholdText} + {hasErrors && } + + ) : null} + + + { + const { value } = e.target; + const thresholdVal = value !== '' ? parseFloat(value) : value; + const newThreshold = [...threshold]; + newThreshold[i] = thresholdVal; + setAlertTypeParams('threshold', newThreshold); + }} + /> + + + + ); + })} + +
+
+
+ + { + setAlertDurationPopoverOpen(true); + }} + color={timeWindowSize ? 'secondary' : 'danger'} + /> + } + isOpen={alertDurationPopoverOpen} + closePopover={() => { + setAlertDurationPopoverOpen(false); + }} + ownFocus + withTitle + anchorPosition="downLeft" + > +
+ + + + + + + { + const { value } = e.target; + const timeWindowSizeVal = value !== '' ? parseInt(value, 10) : value; + setAlertTypeParams('timeWindowSize', timeWindowSizeVal); + }} + /> + + + + { + setAlertTypeParams('timeWindowUnit', e.target.value); + }} + options={getTimeOptions(timeWindowSize)} + /> + + +
+
+
+
+ {hasExpressionErrors ? ( + + + + {expressionErrorMessage} + + + + ) : null} + {hasErrors ? null : ( + + + + )} + +
+ ); +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx new file mode 100644 index 00000000000000..6652b89e0e0578 --- /dev/null +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx @@ -0,0 +1,295 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { Fragment, useContext, useEffect, useState } from 'react'; +import { + AnnotationDomainTypes, + Axis, + getAnnotationId, + getAxisId, + getSpecId, + Chart, + LineAnnotation, + LineSeries, + Position, + ScaleType, + Settings, +} from '@elastic/charts'; +import { TimeBuckets } from 'ui/time_buckets'; +import dateMath from '@elastic/datemath'; +import chrome from 'ui/chrome'; +import moment from 'moment-timezone'; +import { EuiCallOut, EuiLoadingChart, EuiSpacer, EuiEmptyPrompt, EuiText } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { VisualizeOptions } from 'plugins/watcher/models/visualize_options'; +import { ThresholdWatch } from 'plugins/watcher/models/watch/threshold_watch'; +import { npStart } from 'ui/new_platform'; +import { getThresholdAlertVisualizationData } from '../../../../lib/api'; +import { AlertsContext } from '../../../../context/alerts_context'; +import { comparators, aggregationTypes } from './expression'; +import { useAppDependencies } from '../../../..'; +import { SectionError } from '../../../../components/page_error/section_error'; + +const customTheme = () => { + return { + lineSeriesStyle: { + line: { + strokeWidth: 3, + }, + point: { + visible: false, + }, + }, + }; +}; + +const getTimezone = () => { + const config = chrome.getUiSettingsClient(); + const DATE_FORMAT_CONFIG_KEY = 'dateFormat:tz'; + const isCustomTimezone = !config.isDefault(DATE_FORMAT_CONFIG_KEY); + if (isCustomTimezone) { + return config.get(DATE_FORMAT_CONFIG_KEY); + } + + const detectedTimezone = moment.tz.guess(); + if (detectedTimezone) { + return detectedTimezone; + } + // default to UTC if we can't figure out the timezone + const tzOffset = moment().format('Z'); + return tzOffset; +}; + +const getDomain = (watch: any) => { + const VISUALIZE_TIME_WINDOW_MULTIPLIER = 5; + const fromExpression = `now-${watch.timeWindowSize * VISUALIZE_TIME_WINDOW_MULTIPLIER}${ + watch.timeWindowUnit + }`; + const toExpression = 'now'; + const fromMoment = dateMath.parse(fromExpression); + const toMoment = dateMath.parse(toExpression); + const visualizeTimeWindowFrom = fromMoment ? fromMoment.valueOf() : 0; + const visualizeTimeWindowTo = toMoment ? toMoment.valueOf() : 0; + return { + min: visualizeTimeWindowFrom, + max: visualizeTimeWindowTo, + }; +}; + +const getThreshold = (watch: any) => { + return watch.threshold.slice(0, comparators[watch.thresholdComparator].requiredValues); +}; + +const getTimeBuckets = (watch: any) => { + const domain = getDomain(watch); + const timeBuckets = new TimeBuckets(); + timeBuckets.setBounds(domain); + return timeBuckets; +}; + +export const ThresholdVisualization = () => { + const { + core: { http }, + } = useAppDependencies(); + const [isLoading, setIsLoading] = useState(false); + const [isInitialRequest, setIsInitialRequest] = useState(false); + const [error, setError] = useState(undefined); + const [visualizationData, setVisualizationData] = useState>([]); + + const { alert } = useContext(AlertsContext); + const chartsTheme = npStart.plugins.eui_utils.useChartsTheme(); + const { + index, + timeField, + triggerIntervalSize, + triggerIntervalUnit, + aggType, + aggField, + termSize, + termField, + thresholdComparator, + timeWindowSize, + timeWindowUnit, + groupBy, + threshold, + } = alert.alertTypeParams; + + const domain = getDomain(alert); + const timeBuckets = new TimeBuckets(); + timeBuckets.setBounds(domain); + const interval = timeBuckets.getInterval().expression; + const visualizeOptions = new VisualizeOptions({ + rangeFrom: domain.min, + rangeTo: domain.max, + interval, + timezone: getTimezone(), + }); + + // Fetching visualization data is independent of alert actions + const watchWithoutActions = new ThresholdWatch({ ...alert, actions: [] }); + + useEffect(() => { + // Prevent sending a second request on initial render. + if (isInitialRequest) { + return; + } + + async function loadVisualizationData() { + setIsLoading(true); + setVisualizationData( + await getThresholdAlertVisualizationData({ + model: watchWithoutActions, + visualizeOptions, + http, + }) + ); + } + loadVisualizationData(); + }, [ + index, + timeField, + triggerIntervalSize, + triggerIntervalUnit, + aggType, + aggField, + termSize, + termField, + thresholdComparator, + timeWindowSize, + timeWindowUnit, + groupBy, + threshold, + isInitialRequest, + watchWithoutActions, + visualizeOptions, + http, + ]); + + if (isInitialRequest && isLoading) { + return ( + } + body={ + + + + } + /> + ); + } + + if (error) { + return ( + + + + } + error={error} + /> + + + ); + } + + if (visualizationData) { + const watchVisualizationDataKeys = Object.keys(visualizationData); + const timezone = getTimezone(); + const actualThreshold = getThreshold(alert); + let maxY = actualThreshold[actualThreshold.length - 1]; + + (Object.values(visualizationData) as number[][][]).forEach(data => { + data.forEach(([, y]) => { + if (y > maxY) { + maxY = y; + } + }); + }); + const dateFormatter = (d: number) => { + return moment(d) + .tz(timezone) + .format(getTimeBuckets(alert).getScaledDateFormat()); + }; + const aggLabel = aggregationTypes[alert.alertTypeParams.aggType].text; + return ( +
+ + {watchVisualizationDataKeys.length ? ( + + + + + {watchVisualizationDataKeys.map((key: string) => { + return ( + + ); + })} + {actualThreshold.map((_value: any, i: number) => { + const specId = i === 0 ? 'threshold' : `threshold${i}`; + return ( + + ); + })} + + ) : ( + + } + color="warning" + > + + + )} + +
+ ); + } + + return null; +}; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts index ba657d4d75ef05..acf46383fd385a 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts @@ -7,6 +7,7 @@ import { unmountComponentAtNode } from 'react-dom'; import { i18n } from '@kbn/i18n'; import routes from 'ui/routes'; +import { SavedObjectsClientProvider } from 'ui/saved_objects'; import { CoreSetup, CoreStart, @@ -23,6 +24,7 @@ import { ActionTypeRegistry } from './application/action_type_registry'; import { registerBuiltInActionTypes } from './application/sections/action_add/buildin_action_types'; import { AlertTypeRegistry } from './application/alert_type_registry'; import { registerAlertTypes } from './application/sections/alert_add/alert_types'; +import { setSavedObjectsClient } from './application/lib/api'; export type Setup = void; export type Start = void; @@ -98,8 +100,9 @@ export class Plugin implements CorePlugin { routes.when(`${BASE_PATH}/:section?/:subsection?/:view?/:id?`, { template, controller: (() => { - return ($route: any, $scope: any) => { + return ($route: any, $scope: any, Private: any) => { const appRoute = $route.current; + setSavedObjectsClient(Private(SavedObjectsClientProvider)); const stopListeningForLocationChange = $scope.$on('$locationChangeSuccess', () => { const currentRoute = $route.current; const isNavigationInApp = currentRoute.$$route.template === appRoute.$$route.template; From d18132209c3fe246af3e406c27f0b3cf102aedba Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 19 Nov 2019 13:55:11 -0500 Subject: [PATCH 106/297] Move delete button to the left and hide when no selection --- .../actions_list/components/actions_list.tsx | 47 +++++++++++-------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 5d9f668ccbfea2..882168317b9381 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -227,27 +227,34 @@ export const ActionsList: React.FunctionComponent = () => { .sort((a, b) => a.name.localeCompare(b.name)), }, ], + toolsLeft: + selectedItems.length === 0 || !canDelete + ? [] + : [ + + + , + ], toolsRight: [ - - - , Date: Tue, 19 Nov 2019 13:56:05 -0500 Subject: [PATCH 107/297] Rename action list title column to name --- .../sections/actions_list/components/actions_list.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 882168317b9381..a1aea88b1271c8 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -131,7 +131,7 @@ export const ActionsList: React.FunctionComponent = () => { name: i18n.translate( 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.descriptionTitle', { - defaultMessage: 'Title', + defaultMessage: 'Name', } ), sortable: false, From 4ca52894b980ccd84ed6ab2eccaac0c993372a62 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 19 Nov 2019 12:39:43 -0800 Subject: [PATCH 108/297] fixed request --- .../action_add/buildin_action_types/email.tsx | 55 ++++++++++++++++-- .../sections/alert_add/alert_add.tsx | 58 ++++++++++--------- .../alert_types/threshold/expression.tsx | 34 +++++------ .../alerting_ui/np_ready/public/types.ts | 1 + 4 files changed, 96 insertions(+), 52 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx index 76b87a156b11a7..ad5892e89bff26 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx @@ -75,6 +75,10 @@ export function getActionType(): ActionTypeModel { } return validationResult; }, + validateParams: (action: Action): ValidationResult => { + const validationResult = { errors: {} }; + return validationResult; + }, actionFields: EmailActionFields, actionParamsFields: EmailParamsFields, }; @@ -255,8 +259,9 @@ const EmailParamsFields: React.FunctionComponent = ({ errors, hasErrors, }) => { - const { to, subject, body } = action; + const { to, cc, subject, body } = action; const toOptions = to ? to.map((label: any) => ({ label })) : []; + const ccOptions = cc ? cc.map((label: any) => ({ label })) : []; return ( @@ -298,6 +303,44 @@ const EmailParamsFields: React.FunctionComponent = ({ }} /> + + { + const newOptions = [...ccOptions, { label: searchValue }]; + editAction( + 'cc', + newOptions.map(newOption => newOption.label) + ); + }} + onChange={(selectedOptions: Array<{ label: string }>) => { + editAction( + 'cc', + selectedOptions.map(selectedOption => selectedOption.label) + ); + }} + onBlur={() => { + if (!cc) { + editAction('cc', []); + } + }} + /> + = ({ { - editAction('body', e.target.value); + editAction('message', e.target.value); }} /> diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 713b3284f441e1..eb45ac2c606198 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -159,9 +159,13 @@ export const AlertAdd = ({ refreshList }: Props) => { } as IErrorObject; const hasErrors = !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); - const actionErrors = alert.actions.reduce((acc: any, action: any) => { - const actionValidationErrors = action.validate(); - acc[action.id] = actionValidationErrors; + const actionErrors = alert.actions.reduce((acc: any, alertActionType: any) => { + const actionType = actionTypeRegistry.get(alertActionType.id); + if (!actionType) { + return []; + } + const actionValidationErrors = actionType.validateParams(alertActionType.params); + acc[alertActionType.id] = actionValidationErrors; return acc; }, {}); @@ -291,20 +295,7 @@ export const AlertAdd = ({ refreshList }: Props) => { let alertDetails; if (!alertAction) { - alertDetails = ( - - -
- -
-
- - {actionTypeNodes} -
- ); + alertDetails = null; } else { alert.actions.push(alertAction); const actionTypeRegisterd = actionTypeRegistry.get(alert.actions[0].id); @@ -312,14 +303,17 @@ export const AlertAdd = ({ refreshList }: Props) => { const ParamsFieldsComponent = actionTypeRegisterd.actionParamsFields; alertDetails = ( - {ParamsFieldsComponent !== null ? ( - - ) : null} + + + {ParamsFieldsComponent !== null ? ( + + ) : null} + ); } @@ -532,8 +526,20 @@ export const AlertAdd = ({ refreshList }: Props) => { {alertTabs} {alertTypeArea} + {selectedTabContent} - {selectedTabContent} + + +
+ +
+
+ + {actionTypeNodes} +
diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx index ca54cf4b02fe73..06db1234743cac 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useState, Fragment, useEffect } from 'react'; +import React, { useState, Fragment, useEffect, useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { @@ -332,7 +332,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = } ); - function setDefaultValues() { + const setDefaultValues = useCallback(() => { setAlertTypeParams('aggType', DEFAULT_VALUES.AGGREGATION_TYPE); setAlertTypeParams('termSize', DEFAULT_VALUES.TERM_SIZE); setAlertTypeParams('thresholdComparator', DEFAULT_VALUES.THRESHOLD_COMPARATOR); @@ -345,27 +345,21 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = setAlertTypeParams('groupBy', 'top'); } setAlertTypeParams('threshold', DEFAULT_VALUES.THRESHOLD); - } + }, [setAlertTypeParams, termField]); - const loadData = async () => { - if (index && index.length > 0) { - const allEsFields = await getFields(index); - const timeFields = getTimeFieldOptions(allEsFields, firstFieldOption); - setEsFields(allEsFields); - setTimeFieldOptions(timeFields); - setAlertTypeParams('timeFields', timeFields); - } - getIndexPatterns(); - }; + const getFields = useCallback( + (indices: string[]) => { + const fields = async () => { + return await getThresholdAlertTypeFields({ indices, http }); + }; + return fields(); + }, + [http] + ); useEffect(() => { - loadData(); - setDefaultValues(); - }); - - const getFields = async (indices: string[]) => { - return await getThresholdAlertTypeFields({ indices, http }); - }; + getIndexPatterns(); + }, []); interface IOption { label: string; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts index d6b84f6e8e4d5c..5edf02461a13c6 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts @@ -32,6 +32,7 @@ export interface ActionTypeModel { iconClass: string; selectMessage: string; validate: (action: Action) => ValidationResult; + validateParams: (actionParams: any) => ValidationResult; actionFields: React.FunctionComponent | null; actionParamsFields: React.FunctionComponent | null; } From a6ec11656982f697cd485bd6d15f6f99d85ea799 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 19 Nov 2019 12:45:37 -0800 Subject: [PATCH 109/297] Removed watcher labels --- .../alert_add/alert_types/threshold/expression.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx index 06db1234743cac..be0d65cec2e7b3 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx @@ -676,7 +676,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = button={ = >
- {i18n.translate('xpack.watcher.sections.watchEdit.threshold.ofButtonLabel', { + {i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.ofButtonLabel', { defaultMessage: 'of', })} @@ -747,12 +747,12 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = description={`${ groupByTypes[groupBy || DEFAULT_VALUES.GROUP_BY].sizeRequired ? i18n.translate( - 'xpack.watcher.sections.watchEdit.threshold.groupedOverLabel', + 'xpack.alertingUI.sections.alertAdd.threshold.groupedOverLabel', { defaultMessage: 'grouped over', } ) - : i18n.translate('xpack.watcher.sections.watchEdit.threshold.overLabel', { + : i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.overLabel', { defaultMessage: 'over', }) }`} @@ -778,7 +778,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = >
- {i18n.translate('xpack.watcher.sections.watchEdit.threshold.overButtonLabel', { + {i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.overButtonLabel', { defaultMessage: 'over', })} @@ -960,7 +960,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = button={ =
From 9b41eb12bbb6d9a67e3cec338ae734b6cbbfd92b Mon Sep 17 00:00:00 2001 From: Dave Snider Date: Tue, 19 Nov 2019 14:52:53 -0800 Subject: [PATCH 110/297] Design cleanup --- .../sections/alert_add/alert_add.tsx | 413 +++++++++--------- .../alert_types/threshold/expression.tsx | 20 +- 2 files changed, 223 insertions(+), 210 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index eb45ac2c606198..bcb2a9695be3d0 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -28,10 +28,11 @@ import { EuiTabs, EuiTab, EuiLink, - EuiPanel, EuiFieldNumber, EuiSelect, EuiIconTip, + EuiBadge, + EuiPortal, } from '@elastic/eui'; import { useAppDependencies } from '../..'; import { saveAlert, loadActionTypes } from '../../lib/api'; @@ -240,7 +241,9 @@ export const AlertAdd = ({ refreshList }: Props) => { icon={} title={actionTypesIndex ? actionTypesIndex[item.id].name : item.name} description={''} - onClick={() => addActionType(item.actionType)} + selectable={{ + onClick: () => addActionType(item.actionType), + }} /> ); @@ -261,12 +264,12 @@ export const AlertAdd = ({ refreshList }: Props) => { const alertTypeDetails = ( - - - + + +
@@ -295,7 +298,22 @@ export const AlertAdd = ({ refreshList }: Props) => { let alertDetails; if (!alertAction) { - alertDetails = null; + alertDetails = ( + + +
+ +
+
+ + + {actionTypeNodes} + +
+ ); } else { alert.actions.push(alertAction); const actionTypeRegisterd = actionTypeRegistry.get(alert.actions[0].id); @@ -303,17 +321,23 @@ export const AlertAdd = ({ refreshList }: Props) => { const ParamsFieldsComponent = actionTypeRegisterd.actionParamsFields; alertDetails = ( - - - {ParamsFieldsComponent !== null ? ( - +
+ - ) : null} - +
+ + + {ParamsFieldsComponent !== null ? ( + + ) : null}
); } @@ -343,7 +367,7 @@ export const AlertAdd = ({ refreshList }: Props) => { } else { alertTypeArea = ( - +
{
- {alertTypeNodes} + + {alertTypeNodes} +
); } @@ -390,193 +416,182 @@ export const AlertAdd = ({ refreshList }: Props) => { ); return ( - - - -

- -

-
-
- - - - - - } - errorKey="name" - isShowingErrors={hasErrors && alert.name !== undefined} - errors={errors} - > - { - setAlertProperty('name', e.target.value); - }} - onBlur={() => { - if (!alert.name) { - setAlertProperty('name', ''); - } - }} - /> - - - - + + + +

+ +

+
+
+ + + + + } - )} - > - + { + setAlertProperty('name', e.target.value); + }} + onBlur={() => { + if (!alert.name) { + setAlertProperty('name', ''); + } + }} + /> + + + + { - return { - label: anIndex, - value: anIndex, - }; - })} - onChange={async (selected: EuiComboBoxOptionProps[]) => { - setAlertProperty( - 'tags', - selected.map(aSelected => aSelected.value) - ); - }} - onBlur={() => { - if (!alert.tags) { - setAlertProperty('tags', []); + label={i18n.translate( + 'xpack.alertingUI.sections.actionAdd.indexAction.indexTextFieldLabel', + { + defaultMessage: 'Tags (optional)', } - }} - /> - - - - - + )} + > + { + return { + label: anIndex, + value: anIndex, + }; + })} + onChange={async (selected: EuiComboBoxOptionProps[]) => { + setAlertProperty( + 'tags', + selected.map(aSelected => aSelected.value) + ); + }} + onBlur={() => { + if (!alert.tags) { + setAlertProperty('tags', []); + } + }} + /> +
+
+
+ + + + + + + { + setAlertProperty('checkIntervalSize', e.target.value); + }} + /> + + + setAlertProperty('checkIntervalUnit', e.target.value)} + fullWidth={true} + /> + + + + + + + + + { + setAlertProperty('renotifyIntervalSize', e.target.value); + }} + /> + + + + setAlertProperty('renotifyIntervalUnit', e.target.value) + } + fullWidth={true} + /> + + + + + + + {alertTabs} + + {alertTypeArea} + + {selectedTabContent} +
+
+ + - - - - { - setAlertProperty('checkIntervalSize', e.target.value); - }} - /> - - - setAlertProperty('checkIntervalUnit', e.target.value)} - fullWidth={true} - /> - - - + + {i18n.translate('xpack.alertingUI.sections.alertAdd.cancelButtonLabel', { + defaultMessage: 'Cancel', + })} + - - - - { - setAlertProperty('renotifyIntervalSize', e.target.value); - }} - /> - - - - setAlertProperty('renotifyIntervalUnit', e.target.value) - } - fullWidth={true} - /> - - - - - - - {alertTabs} - - {alertTypeArea} - {selectedTabContent} - - - -
+ { + setIsSaving(true); + const savedAlert = await onSaveAlert(); + setIsSaving(false); + setAlertFlyoutVisibility(false); + refreshList(); + }} + > -
-
- - {actionTypeNodes} -
- - - - - - - - {i18n.translate('xpack.alertingUI.sections.alertAdd.cancelButtonLabel', { - defaultMessage: 'Cancel', - })} - - - - { - setIsSaving(true); - const savedAlert = await onSaveAlert(); - setIsSaving(false); - setAlertFlyoutVisibility(false); - refreshList(); - }} - > - - - - - -
+ + + + + + ); }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx index be0d65cec2e7b3..7617625d693a75 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx @@ -19,6 +19,7 @@ import { EuiFieldNumber, EuiComboBoxOptionProps, EuiText, + EuiCallOut, } from '@elastic/eui'; import { AlertTypeModel, AlertType, Alert, ValidationResult } from '../../../../../types'; import { Comparator, AggregationType, GroupByType } from '../types'; @@ -579,7 +580,14 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = return ( - + {hasExpressionErrors ? ( + + + + + + ) : null} + = - {hasExpressionErrors ? ( - - - - {expressionErrorMessage} - - - - ) : null} {hasErrors ? null : ( )} - ); }; From 5973bfbfd5c2a9ef93d1329de6380130f6dcdcbd Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 19 Nov 2019 16:32:18 -0800 Subject: [PATCH 111/297] Added expression default values --- .../sections/alert_add/alert_add.tsx | 1 + .../alert_types/threshold/expression.tsx | 135 +++++++++--------- 2 files changed, 68 insertions(+), 68 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index eb45ac2c606198..42e058ac9870ed 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -287,6 +287,7 @@ export const AlertAdd = ({ refreshList }: Props) => { alert={alert} errors={errors} setAlertTypeParams={setAlertTypeParams} + setAlertProperty={setAlertProperty} hasErrors={hasErrors} /> ) : null} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx index be0d65cec2e7b3..a3db2c24ab9049 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx @@ -148,14 +148,49 @@ export const comparators: { [key: string]: Comparator } = { }, }; +export const groupByTypes: { [key: string]: GroupByType } = { + all: { + text: i18n.translate( + 'xpack.alertingUI.sections.alertAdd.threshold.groupByLabel.allDocumentsLabel', + { + defaultMessage: 'all documents', + } + ), + sizeRequired: false, + value: 'all', + validNormalizedTypes: [], + }, + top: { + text: i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.groupByLabel.topLabel', { + defaultMessage: 'top', + }), + sizeRequired: true, + value: 'top', + validNormalizedTypes: ['number', 'date', 'keyword'], + }, +}; + interface Props { alert: Alert; setAlertTypeParams: (property: string, value: any) => void; + setAlertProperty: (key: string, value: any) => void; errors: { [key: string]: string[] }; hasErrors?: boolean; } function validateAlertType(alert: Alert): ValidationResult { + const { + index, + timeField, + triggerIntervalSize, + aggType, + aggField, + groupBy, + termSize, + termField, + threshold, + timeWindowSize, + } = alert.alertTypeParams; const validationResult = { errors: {} }; const errors = { aggField: new Array(), @@ -169,71 +204,63 @@ function validateAlertType(alert: Alert): ValidationResult { triggerIntervalSize: new Array(), }; validationResult.errors = errors; - if (!alert.alertTypeParams.index) { + if (!index) { errors.index.push( i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredIndexText', { defaultMessage: 'Index is required.', }) ); } - if (!alert.alertTypeParams.timeField) { + if (!timeField) { errors.timeField.push( i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredTimeFieldText', { defaultMessage: 'Time field is required.', }) ); } - if (!alert.alertTypeParams.triggerIntervalSize) { + if (!triggerIntervalSize) { errors.triggerIntervalSize.push( i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredTriggerIntervalSizeText', { defaultMessage: 'Trigger interval size is required.', }) ); } - if (!alert.alertTypeParams.aggField) { + if (aggType && aggregationTypes[aggType].fieldRequired && !aggField) { errors.aggField.push( i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredAggFieldText', { defaultMessage: 'Aggregation field is required.', }) ); } - if (!alert.alertTypeParams.termSize) { + if (!termSize) { errors.termSize.push( i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredTermSizedText', { defaultMessage: 'Term size is required.', }) ); } - if (!alert.alertTypeParams.termField) { + if (groupBy && groupByTypes[groupBy].sizeRequired && !termField) { errors.termField.push( i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredtTermFieldText', { defaultMessage: 'Term field is required.', }) ); } - if (!alert.alertTypeParams.timeWindowSize) { + if (!timeWindowSize) { errors.timeWindowSize.push( i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredTimeWindowSizeText', { defaultMessage: 'Time window size is required.', }) ); } - if ( - alert.alertTypeParams.threshold && - alert.alertTypeParams.threshold.length > 0 && - !alert.alertTypeParams.threshold[0] - ) { + if (threshold && threshold.length > 0 && !threshold[0]) { errors.threshold0.push( i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredThreshold0Text', { defaultMessage: 'Threshold0, is required.', }) ); } - if ( - alert.alertTypeParams.threshold && - alert.alertTypeParams.threshold.length > 1 && - !alert.alertTypeParams.threshold[1] - ) { + if (threshold && threshold.length > 1 && !threshold[1]) { errors.threshold1.push( i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredThreshold1Text', { defaultMessage: 'Threshold1 is required.', @@ -246,6 +273,7 @@ function validateAlertType(alert: Alert): ValidationResult { export const IndexThresholdAlertTypeExpression: React.FunctionComponent = ({ alert, setAlertTypeParams, + setAlertProperty, errors, hasErrors, }) => { @@ -285,7 +313,6 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = const [isIndiciesLoading, setIsIndiciesLoading] = useState(false); const [alertThresholdPopoverOpen, setAlertThresholdPopoverOpen] = useState(false); const [alertDurationPopoverOpen, setAlertDurationPopoverOpen] = useState(false); - const [aggFieldPopoverOpen, setAggFieldPopoverOpen] = useState(false); const [groupByPopoverOpen, setGroupByPopoverOpen] = useState(false); @@ -303,28 +330,6 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = setIndexPatterns(titles); }; - const groupByTypes: { [key: string]: GroupByType } = { - all: { - text: i18n.translate( - 'xpack.alertingUI.sections.alertAdd.threshold.groupByLabel.allDocumentsLabel', - { - defaultMessage: 'all documents', - } - ), - sizeRequired: false, - value: 'all', - validNormalizedTypes: [], - }, - top: { - text: i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.groupByLabel.topLabel', { - defaultMessage: 'top', - }), - sizeRequired: true, - value: 'top', - validNormalizedTypes: ['number', 'date', 'keyword'], - }, - }; - const expressionErrorMessage = i18n.translate( 'xpack.alertingUI.sections.alertAdd.threshold.fixErrorInExpressionBelowValidationMessage', { @@ -332,35 +337,29 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = } ); - const setDefaultValues = useCallback(() => { - setAlertTypeParams('aggType', DEFAULT_VALUES.AGGREGATION_TYPE); - setAlertTypeParams('termSize', DEFAULT_VALUES.TERM_SIZE); - setAlertTypeParams('thresholdComparator', DEFAULT_VALUES.THRESHOLD_COMPARATOR); - setAlertTypeParams('timeWindowSize', DEFAULT_VALUES.TIME_WINDOW_SIZE); - setAlertTypeParams('timeWindowUnit', DEFAULT_VALUES.TIME_WINDOW_UNIT); - setAlertTypeParams('triggerIntervalSize', DEFAULT_VALUES.TRIGGER_INTERVAL_SIZE); - setAlertTypeParams('triggerIntervalUnit', DEFAULT_VALUES.TRIGGER_INTERVAL_UNIT); - setAlertTypeParams('groupBy', DEFAULT_VALUES.GROUP_BY); - if (termField !== null) { - setAlertTypeParams('groupBy', 'top'); - } - setAlertTypeParams('threshold', DEFAULT_VALUES.THRESHOLD); - }, [setAlertTypeParams, termField]); - - const getFields = useCallback( - (indices: string[]) => { - const fields = async () => { - return await getThresholdAlertTypeFields({ indices, http }); - }; - return fields(); - }, - [http] - ); + const getFields = async (indices: string[]) => { + return await getThresholdAlertTypeFields({ indices, http }); + }; useEffect(() => { getIndexPatterns(); }, []); + useEffect(() => { + setAlertProperty('alertTypeParams', { + aggType: DEFAULT_VALUES.AGGREGATION_TYPE, + termSize: DEFAULT_VALUES.TERM_SIZE, + thresholdComparator: DEFAULT_VALUES.THRESHOLD_COMPARATOR, + timeWindowSize: DEFAULT_VALUES.TIME_WINDOW_SIZE, + timeWindowUnit: DEFAULT_VALUES.TIME_WINDOW_UNIT, + triggerIntervalSize: DEFAULT_VALUES.TRIGGER_INTERVAL_SIZE, + triggerIntervalUnit: DEFAULT_VALUES.TRIGGER_INTERVAL_UNIT, + groupBy: DEFAULT_VALUES.GROUP_BY, + threshold: DEFAULT_VALUES.THRESHOLD, + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + interface IOption { label: string; options: Array<{ value: string; label: string }>; @@ -539,7 +538,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = { const { value } = e.target; @@ -654,7 +653,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = })} { setAlertTypeParams('aggType', e.target.value); setAggTypePopoverOpen(false); @@ -934,7 +933,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = > { @@ -1000,7 +999,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = > { const { value } = e.target; const timeWindowSizeVal = value !== '' ? parseInt(value, 10) : value; From 2bad656e94b92be571fa34ea6aecb3ef9b83b86a Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 19 Nov 2019 18:29:12 -0800 Subject: [PATCH 112/297] Added visualization for index threshold alert --- .../np_ready/public/application/lib/api.ts | 3 +- .../alert_types/threshold/expression.tsx | 30 +++--- .../alert_types/threshold/visualization.tsx | 98 +++++++++++-------- 3 files changed, 77 insertions(+), 54 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index 2251cf3769e85d..6bbaf7326123ad 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -228,10 +228,11 @@ export async function getThresholdAlertVisualizationData({ visualizeOptions: any; http: HttpServiceBase; }): Promise> { - return await http.post(`${WATCHER_API_ROOT}/watch/visualize`, { + const { visualizeData } = await http.post(`${WATCHER_API_ROOT}/watch/visualize`, { body: JSON.stringify({ watch: model, options: visualizeOptions, }), }); + return visualizeData; } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx index 56092b812ff560..a73a63c2def5b0 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx @@ -338,15 +338,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = } ); - const getFields = async (indices: string[]) => { - return await getThresholdAlertTypeFields({ indices, http }); - }; - - useEffect(() => { - getIndexPatterns(); - }, []); - - useEffect(() => { + const setDefaultExpressionValues = () => { setAlertProperty('alertTypeParams', { aggType: DEFAULT_VALUES.AGGREGATION_TYPE, termSize: DEFAULT_VALUES.TERM_SIZE, @@ -358,6 +350,18 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = groupBy: DEFAULT_VALUES.GROUP_BY, threshold: DEFAULT_VALUES.THRESHOLD, }); + }; + + const getFields = async (indices: string[]) => { + return await getThresholdAlertTypeFields({ indices, http }); + }; + + useEffect(() => { + getIndexPatterns(); + }, []); + + useEffect(() => { + setDefaultExpressionValues(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -464,9 +468,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = setTimeFieldOptions(getTimeFieldOptions([], firstFieldOption)); setAlertTypeParams('timeFields', []); - expressionFields.forEach(expressionField => { - setAlertTypeParams(expressionField, null); - }); + setDefaultExpressionValues(); return; } const currentEsFields = await getFields(indices); @@ -539,7 +541,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = { const { value } = e.target; @@ -1032,7 +1034,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = {hasErrors ? null : ( - + )} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx index 6652b89e0e0578..606bb6d0d6e785 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx @@ -5,6 +5,7 @@ */ import React, { Fragment, useContext, useEffect, useState } from 'react'; +import { UiSettingsClient } from 'kibana/public'; import { AnnotationDomainTypes, Axis, @@ -20,18 +21,15 @@ import { } from '@elastic/charts'; import { TimeBuckets } from 'ui/time_buckets'; import dateMath from '@elastic/datemath'; -import chrome from 'ui/chrome'; import moment from 'moment-timezone'; import { EuiCallOut, EuiLoadingChart, EuiSpacer, EuiEmptyPrompt, EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { VisualizeOptions } from 'plugins/watcher/models/visualize_options'; -import { ThresholdWatch } from 'plugins/watcher/models/watch/threshold_watch'; import { npStart } from 'ui/new_platform'; import { getThresholdAlertVisualizationData } from '../../../../lib/api'; -import { AlertsContext } from '../../../../context/alerts_context'; import { comparators, aggregationTypes } from './expression'; import { useAppDependencies } from '../../../..'; import { SectionError } from '../../../../components/page_error/section_error'; +import { Alert } from '../../../../../types'; const customTheme = () => { return { @@ -46,8 +44,26 @@ const customTheme = () => { }; }; -const getTimezone = () => { - const config = chrome.getUiSettingsClient(); +const getTimezone = ( + uiSettings: Pick< + UiSettingsClient, + | 'getAll' + | 'get' + | 'get$' + | 'set' + | 'remove' + | 'isDeclared' + | 'isDefault' + | 'isCustom' + | 'isOverridden' + | 'overrideLocalDefault' + | 'getUpdate$' + | 'getSaved$' + | 'getUpdateErrors$' + | 'stop' + > +) => { + const config = uiSettings; const DATE_FORMAT_CONFIG_KEY = 'dateFormat:tz'; const isCustomTimezone = !config.isDefault(DATE_FORMAT_CONFIG_KEY); if (isCustomTimezone) { @@ -63,10 +79,10 @@ const getTimezone = () => { return tzOffset; }; -const getDomain = (watch: any) => { +const getDomain = (alertTypeParams: any) => { const VISUALIZE_TIME_WINDOW_MULTIPLIER = 5; - const fromExpression = `now-${watch.timeWindowSize * VISUALIZE_TIME_WINDOW_MULTIPLIER}${ - watch.timeWindowUnit + const fromExpression = `now-${alertTypeParams.timeWindowSize * VISUALIZE_TIME_WINDOW_MULTIPLIER}${ + alertTypeParams.timeWindowUnit }`; const toExpression = 'now'; const fromMoment = dateMath.parse(fromExpression); @@ -79,27 +95,33 @@ const getDomain = (watch: any) => { }; }; -const getThreshold = (watch: any) => { - return watch.threshold.slice(0, comparators[watch.thresholdComparator].requiredValues); +const getThreshold = (alertTypeParams: any) => { + return alertTypeParams.threshold.slice( + 0, + comparators[alertTypeParams.thresholdComparator].requiredValues + ); }; -const getTimeBuckets = (watch: any) => { - const domain = getDomain(watch); +const getTimeBuckets = (alertTypeParams: any) => { + const domain = getDomain(alertTypeParams); const timeBuckets = new TimeBuckets(); timeBuckets.setBounds(domain); return timeBuckets; }; -export const ThresholdVisualization = () => { +interface Props { + alert: Alert; +} + +export const ThresholdVisualization: React.FunctionComponent = ({ alert }) => { const { - core: { http }, + core: { http, uiSettings }, } = useAppDependencies(); const [isLoading, setIsLoading] = useState(false); const [isInitialRequest, setIsInitialRequest] = useState(false); const [error, setError] = useState(undefined); const [visualizationData, setVisualizationData] = useState>([]); - const { alert } = useContext(AlertsContext); const chartsTheme = npStart.plugins.eui_utils.useChartsTheme(); const { index, @@ -117,19 +139,19 @@ export const ThresholdVisualization = () => { threshold, } = alert.alertTypeParams; - const domain = getDomain(alert); + const domain = getDomain(alert.alertTypeParams); const timeBuckets = new TimeBuckets(); timeBuckets.setBounds(domain); const interval = timeBuckets.getInterval().expression; - const visualizeOptions = new VisualizeOptions({ + const visualizeOptions = { rangeFrom: domain.min, rangeTo: domain.max, interval, - timezone: getTimezone(), - }); + timezone: getTimezone(uiSettings), + }; // Fetching visualization data is independent of alert actions - const watchWithoutActions = new ThresholdWatch({ ...alert, actions: [] }); + const alertWithoutActions = { ...alert.alertTypeParams, actions: [], type: 'threshold' }; useEffect(() => { // Prevent sending a second request on initial render. @@ -141,13 +163,14 @@ export const ThresholdVisualization = () => { setIsLoading(true); setVisualizationData( await getThresholdAlertVisualizationData({ - model: watchWithoutActions, + model: alertWithoutActions, visualizeOptions, http, }) ); } loadVisualizationData(); + /* eslint-disable react-hooks/exhaustive-deps */ }, [ index, timeField, @@ -162,11 +185,8 @@ export const ThresholdVisualization = () => { timeWindowUnit, groupBy, threshold, - isInitialRequest, - watchWithoutActions, - visualizeOptions, - http, ]); + /* eslint-enable react-hooks/exhaustive-deps */ if (isInitialRequest && isLoading) { return ( @@ -175,8 +195,8 @@ export const ThresholdVisualization = () => { body={ } @@ -191,8 +211,8 @@ export const ThresholdVisualization = () => { } error={error} @@ -203,9 +223,9 @@ export const ThresholdVisualization = () => { } if (visualizationData) { - const watchVisualizationDataKeys = Object.keys(visualizationData); - const timezone = getTimezone(); - const actualThreshold = getThreshold(alert); + const alertVisualizationDataKeys = Object.keys(visualizationData); + const timezone = getTimezone(uiSettings); + const actualThreshold = getThreshold(alert.alertTypeParams); let maxY = actualThreshold[actualThreshold.length - 1]; (Object.values(visualizationData) as number[][][]).forEach(data => { @@ -218,13 +238,13 @@ export const ThresholdVisualization = () => { const dateFormatter = (d: number) => { return moment(d) .tz(timezone) - .format(getTimeBuckets(alert).getScaledDateFormat()); + .format(getTimeBuckets(alert.alertTypeParams).getScaledDateFormat()); }; const aggLabel = aggregationTypes[alert.alertTypeParams.aggType].text; return ( -
+
- {watchVisualizationDataKeys.length ? ( + {alertVisualizationDataKeys.length ? ( { title={aggLabel} position={Position.Left} /> - {watchVisualizationDataKeys.map((key: string) => { + {alertVisualizationDataKeys.map((key: string) => { return ( { } color="warning" > From ae9757a29989131f7d03e52268398756feb6e726 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 20 Nov 2019 09:29:46 -0500 Subject: [PATCH 113/297] Rename Actions tab to Connectors --- .../alerting_ui/np_ready/public/application/app.tsx | 2 +- .../np_ready/public/application/constants/index.ts | 6 +++--- .../alerting_ui/np_ready/public/application/home.tsx | 11 +++++++---- .../np_ready/public/application/lib/breadcrumb.ts | 10 +++++----- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx index d2bf883abc162e..35115c21441a4d 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx @@ -28,7 +28,7 @@ class ShareRouter extends Component { } export const App = () => { - const sections: Section[] = ['alerts', 'actions']; + const sections: Section[] = ['alerts', 'connectors']; const sectionsRegex = sections.join('|'); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts index 093018908e7e58..781ce5e1ed0821 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts @@ -8,11 +8,11 @@ export const BASE_PATH = '/management/kibana/alerting'; export const BASE_ACTION_API_PATH = '/api/action'; export const BASE_ALERT_API_PATH = '/api/alert'; -export const DEFAULT_SECTION: Section = 'actions'; -export type Section = 'actions' | 'alerts'; +export const DEFAULT_SECTION: Section = 'connectors'; +export type Section = 'connectors' | 'alerts'; export const routeToHome = `${BASE_PATH}`; -export const routeToActions = `${BASE_PATH}/actions`; +export const routeToConnectors = `${BASE_PATH}/connectors`; export const routeToAlerts = `${BASE_PATH}/alerts`; export { COMPARATORS } from './comparators'; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx index b5086ca93c99f6..4513fd5bb75e07 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx @@ -8,7 +8,7 @@ import React, { useEffect } from 'react'; import { Route, RouteComponentProps, Switch } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiPageBody, EuiPageContent, EuiSpacer, EuiTab, EuiTabs } from '@elastic/eui'; -import { BASE_PATH, Section, routeToActions, routeToAlerts } from './constants'; +import { BASE_PATH, Section, routeToConnectors, routeToAlerts } from './constants'; import { breadcrumbService } from './lib/breadcrumb'; import { docTitleService } from './lib/doc_title'; import { useAppDependencies } from './index'; @@ -46,9 +46,12 @@ export const AlertsUIHome: React.FunctionComponent + ), }); } @@ -82,7 +85,7 @@ export const AlertsUIHome: React.FunctionComponent - {canShowActions && } + {canShowActions && } {canShowAlerts && } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts index 4d1d8f1c5de292..e56ed1c4a9a4eb 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts @@ -5,7 +5,7 @@ */ import { i18n } from '@kbn/i18n'; -import { routeToHome, routeToActions, routeToAlerts } from '../constants'; +import { routeToHome, routeToConnectors, routeToAlerts } from '../constants'; class BreadcrumbService { private chrome: any; @@ -34,13 +34,13 @@ class BreadcrumbService { href: `#${routeToHome}`, }, ]; - this.breadcrumbs.actions = [ + this.breadcrumbs.connectors = [ ...this.breadcrumbs.home, { - text: i18n.translate('xpack.alertingUI.actions.breadcrumbTitle', { - defaultMessage: 'Actions', + text: i18n.translate('xpack.alertingUI.connectors.breadcrumbTitle', { + defaultMessage: 'Connectors', }), - href: `#${routeToActions}`, + href: `#${routeToConnectors}`, }, ]; this.breadcrumbs.alerts = [ From 155f38eaa6cc6c5de48db3b9ee65b7e42294d838 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 20 Nov 2019 09:31:52 -0500 Subject: [PATCH 114/297] Rename "create action" to "create connector" --- .../application/sections/action_add/action_add_flyout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_flyout.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_flyout.tsx index 28140c40c75c62..5e5e94277e2f38 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_flyout.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_flyout.tsx @@ -37,7 +37,7 @@ export const ActionAddFlyout = () => {

From 5ed0b68ee3941cc8d50438ba5aca2ca4d98af584 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 20 Nov 2019 09:39:59 -0500 Subject: [PATCH 115/297] Remove actions column name --- .../sections/actions_list/components/actions_list.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index a1aea88b1271c8..13ee3365a655c7 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -150,10 +150,7 @@ export const ActionsList: React.FunctionComponent = () => { }, }, { - name: i18n.translate( - 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.actions', - { defaultMessage: 'Actions' } - ), + name: '', actions: [ { enabled: () => canDelete, From 3fb9efd5ae72cd4de083d52ea48c6f07897b2f98 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 20 Nov 2019 09:52:52 -0500 Subject: [PATCH 116/297] Add count per action type --- .../actions_list/components/actions_list.tsx | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 13ee3365a655c7..1634e10ed9991b 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -29,6 +29,9 @@ export const ActionsList: React.FunctionComponent = () => { const [isLoadingActions, setIsLoadingActions] = useState(false); const [isDeletingActions, setIsDeletingActions] = useState(false); const [flyoutVisible, setFlyoutVisibility] = useState(false); + const [actionTypesList, setActionTypesList] = useState>( + [] + ); useEffect(() => { loadActions(); @@ -62,6 +65,7 @@ export const ActionsList: React.FunctionComponent = () => { if (typeof actionTypesIndex === 'undefined') { return; } + // Update the data for the table const updatedData = actions.map(action => { return { ...action, @@ -71,6 +75,14 @@ export const ActionsList: React.FunctionComponent = () => { }; }); setData(updatedData); + // Update the action types list for the filter + const actionTypes = Object.values(actionTypesIndex) + .map(actionType => ({ + value: actionType.id, + name: `${actionType.name} (${getActionsCountByActionType(actions, actionType.id)})`, + })) + .sort((a, b) => a.name.localeCompare(b.name)); + setActionTypesList(actionTypes); }, [actions, actionTypesIndex]); async function loadActions() { @@ -216,12 +228,7 @@ export const ActionsList: React.FunctionComponent = () => { { defaultMessage: 'Type' } ), multiSelect: 'or', - options: Object.values(actionTypesIndex || {}) - .map(actionTypesIndexItem => ({ - value: actionTypesIndexItem.id, - name: actionTypesIndexItem.name, - })) - .sort((a, b) => a.name.localeCompare(b.name)), + options: actionTypesList, }, ], toolsLeft: @@ -274,3 +281,7 @@ export const ActionsList: React.FunctionComponent = () => {

); }; + +function getActionsCountByActionType(actions: Action[], actionTypeId: string) { + return actions.filter(action => action.actionTypeId === actionTypeId).length; +} From 84e90cccc092a12356bcb5bdc98c946f4e36e325 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 20 Nov 2019 09:58:58 -0500 Subject: [PATCH 117/297] Hide checkboxes when user can't delete --- .../actions_list/components/actions_list.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 1634e10ed9991b..673e4195e70fdd 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -213,11 +213,13 @@ export const ActionsList: React.FunctionComponent = () => { })} data-test-subj="actionsTable" pagination={true} - selection={{ - onSelectionChange(updatedSelectedItemsList: ActionTableItem[]) { - setSelectedItems(updatedSelectedItemsList); - }, - }} + selection={ + canDelete && { + onSelectionChange(updatedSelectedItemsList: ActionTableItem[]) { + setSelectedItems(updatedSelectedItemsList); + }, + } + } search={{ filters: [ { From 3d5781571cb7a9ff2e9fcaa9179fd578f174f7e8 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 20 Nov 2019 10:26:51 -0500 Subject: [PATCH 118/297] Add title to home, rename Alerting UI breadcrumb (remove UI part) --- .../np_ready/public/application/home.tsx | 21 ++++++++++++++++++- .../public/application/lib/breadcrumb.ts | 2 +- .../public/application/lib/doc_title.ts | 2 +- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx index 4513fd5bb75e07..d99f4eec914d62 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx @@ -7,7 +7,17 @@ import React, { useEffect } from 'react'; import { Route, RouteComponentProps, Switch } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiPageBody, EuiPageContent, EuiSpacer, EuiTab, EuiTabs } from '@elastic/eui'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiPageBody, + EuiPageContent, + EuiSpacer, + EuiTab, + EuiTabs, + EuiTitle, +} from '@elastic/eui'; + import { BASE_PATH, Section, routeToConnectors, routeToAlerts } from './constants'; import { breadcrumbService } from './lib/breadcrumb'; import { docTitleService } from './lib/doc_title'; @@ -69,6 +79,15 @@ export const AlertsUIHome: React.FunctionComponent + + + +

+ +

+
+
+
{tabs.map(tab => ( Date: Wed, 20 Nov 2019 09:52:39 -0800 Subject: [PATCH 119/297] Added correct binding for interval and throttle --- .../sections/alert_add/alert_add.tsx | 69 +++++++++++++++---- .../alerting_ui/np_ready/public/types.ts | 5 -- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 39ffe9ff13ba6a..53247d4491cbed 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -31,7 +31,6 @@ import { EuiFieldNumber, EuiSelect, EuiIconTip, - EuiBadge, EuiPortal, } from '@elastic/eui'; import { useAppDependencies } from '../..'; @@ -58,6 +57,8 @@ function validateBaseProperties(alertObject: Alert) { const validationResult = { errors: {} }; const errors = { name: new Array(), + interval: new Array(), + alertTypeId: new Array(), }; validationResult.errors = errors; if (!alertObject.name) { @@ -67,6 +68,20 @@ function validateBaseProperties(alertObject: Alert) { }) ); } + if (!alertObject.interval) { + errors.interval.push( + i18n.translate('xpack.alertingUI.sections.alertAdd.error.requiredIntervalText', { + defaultMessage: 'Check interval is required.', + }) + ); + } + if (!alertObject.alertTypeId) { + errors.alertTypeId.push( + i18n.translate('xpack.alertingUI.sections.alertAdd.error.requiredAlertTypeIdText', { + defaultMessage: 'Alert trigger is required.', + }) + ); + } return validationResult; } @@ -80,6 +95,7 @@ export const AlertAdd = ({ refreshList }: Props) => { const initialAlert = { alertTypeParams: {}, alertTypeId: null, + interval: '1m', actions: [], }; @@ -92,6 +108,10 @@ export const AlertAdd = ({ refreshList }: Props) => { const [selectedTabId, setSelectedTabId] = useState('alert'); const [alertAction, setAlertAction] = useState(undefined); const [actionTypesIndex, setActionTypesIndex] = useState(undefined); + const [alertInterval, setAlertInterval] = useState(null); + const [alertIntervalUnit, setAlertIntervalUnit] = useState('m'); + const [alertThrottle, setAlertThrottle] = useState(null); + const [alertThrottleUnit, setAlertThrottleUnit] = useState(''); useEffect(() => { (async () => { @@ -124,6 +144,7 @@ export const AlertAdd = ({ refreshList }: Props) => { value: { alertTypeParams: {}, alertTypeId: null, + interval: '1m', actions: [], }, }, @@ -228,7 +249,10 @@ export const AlertAdd = ({ refreshList }: Props) => { icon={} title={item.name} description={''} - onClick={() => setAlertType(item.alertType)} + onClick={() => { + setAlertProperty('alertTypeId', item.id); + setAlertType(item.alertType); + }} />
); @@ -277,7 +301,12 @@ export const AlertAdd = ({ refreshList }: Props) => { - setAlertType(undefined)}> + { + setAlertProperty('alertTypeId', null); + setAlertType(undefined); + }} + > { { - setAlertProperty('checkIntervalSize', e.target.value); + const interval = + e.target.value !== '' ? parseInt(e.target.value, 10) : null; + setAlertInterval(interval); + setAlertProperty('interval', `${e.target.value}${alertIntervalUnit}`); }} /> setAlertProperty('checkIntervalUnit', e.target.value)} + value={alertIntervalUnit} + options={getTimeOptions((alertInterval ? alertInterval : 1).toString())} + onChange={(e: any) => { + setAlertIntervalUnit(e.target.value); + setAlertProperty('interval', `${alertInterval}${e.target.value}`); + }} fullWidth={true} /> @@ -528,11 +563,14 @@ export const AlertAdd = ({ refreshList }: Props) => { { - setAlertProperty('renotifyIntervalSize', e.target.value); + const throttle = + e.target.value !== '' ? parseInt(e.target.value, 10) : null; + setAlertThrottle(throttle); + setAlertProperty('throttle', `${e.target.value}${alertThrottleUnit}`); }} /> @@ -540,9 +578,10 @@ export const AlertAdd = ({ refreshList }: Props) => { - setAlertProperty('renotifyIntervalUnit', e.target.value) - } + onChange={(e: any) => { + setAlertThrottleUnit(e.target.value); + setAlertProperty('throttle', `${alertThrottle}${e.target.value}`); + }} fullWidth={true} /> diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts index 5edf02461a13c6..1db5d83e663203 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts @@ -86,11 +86,6 @@ export interface Alert { throttle: string | null; muteAll: boolean; mutedInstanceIds: string[]; - // TODO: replace this temporary fields with the proper server relevant - checkIntervalSize?: number; - checkIntervalUnit?: string; - renotifyIntervalSize?: number; - renotifyIntervalUnit?: string; } export interface AlertTableItem extends Alert { From d3b37e97c0cf34ad612da3ccb7b17eae1d81ffe6 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 20 Nov 2019 10:29:24 -0800 Subject: [PATCH 120/297] Added tags support for create Alert UI --- .../sections/alert_add/alert_add.tsx | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 53247d4491cbed..7e9aee380e5419 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -97,6 +97,7 @@ export const AlertAdd = ({ refreshList }: Props) => { alertTypeId: null, interval: '1m', actions: [], + tags: ['sfdfsfsd'], }; const { alertFlyoutVisible, setAlertFlyoutVisibility } = useContext(AlertsContext); @@ -112,6 +113,7 @@ export const AlertAdd = ({ refreshList }: Props) => { const [alertIntervalUnit, setAlertIntervalUnit] = useState('m'); const [alertThrottle, setAlertThrottle] = useState(null); const [alertThrottleUnit, setAlertThrottleUnit] = useState(''); + const tagsOptions = alert.tags ? alert.tags.map((label: string) => ({ label })) : []; useEffect(() => { (async () => { @@ -146,6 +148,7 @@ export const AlertAdd = ({ refreshList }: Props) => { alertTypeId: null, interval: '1m', actions: [], + tags: [], }, }, }); @@ -172,7 +175,7 @@ export const AlertAdd = ({ refreshList }: Props) => { if (!alertFlyoutVisible) { return null; } - const tagsOptions = []; // TODO: move to alert instande when the server side will be done + const AlertTypeParamsExpressionComponent = alertType ? alertType.alertTypeParamsExpression : null; const errors = { @@ -500,21 +503,21 @@ export const AlertAdd = ({ refreshList }: Props) => { )} > { - return { - label: anIndex, - value: anIndex, - }; - })} - onChange={async (selected: EuiComboBoxOptionProps[]) => { + selectedOptions={tagsOptions} + onCreateOption={(searchValue: string) => { + const newOptions = [...tagsOptions, { label: searchValue }]; + setAlertProperty( + 'tags', + newOptions.map(newOption => newOption.label) + ); + }} + onChange={(selectedOptions: Array<{ label: string }>) => { setAlertProperty( 'tags', - selected.map(aSelected => aSelected.value) + selectedOptions.map(selectedOption => selectedOption.label) ); }} onBlur={() => { From 04443a22812f7bf252f7e59262560a009b2439c2 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 20 Nov 2019 10:39:36 -0800 Subject: [PATCH 121/297] Added server error display in UI on save alert --- .../sections/alert_add/alert_add.tsx | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 7e9aee380e5419..62147155c0c6e1 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -37,7 +37,7 @@ import { useAppDependencies } from '../..'; import { saveAlert, loadActionTypes } from '../../lib/api'; import { AlertsContext } from '../../context/alerts_context'; import { alertReducer } from './alert_reducer'; -import { ErrableFormRow } from '../../components/page_error'; +import { ErrableFormRow, SectionError } from '../../components/page_error'; import { AlertTypeModel, Alert, @@ -114,6 +114,9 @@ export const AlertAdd = ({ refreshList }: Props) => { const [alertThrottle, setAlertThrottle] = useState(null); const [alertThrottleUnit, setAlertThrottleUnit] = useState(''); const tagsOptions = alert.tags ? alert.tags.map((label: string) => ({ label })) : []; + const [serverError, setServerError] = useState<{ + body: { message: string; error: string }; + } | null>(null); useEffect(() => { (async () => { @@ -170,6 +173,7 @@ export const AlertAdd = ({ refreshList }: Props) => { setAlertType(undefined); setAlertAction(undefined); setSelectedTabId('alert'); + setServerError(null); }, [setAlertFlyoutVisibility]); if (!alertFlyoutVisible) { @@ -463,6 +467,20 @@ export const AlertAdd = ({ refreshList }: Props) => {
+ {serverError && ( + + + } + error={serverError} + /> + + + )} { setIsSaving(true); const savedAlert = await onSaveAlert(); setIsSaving(false); - setAlertFlyoutVisibility(false); + if (savedAlert && savedAlert.error) { + return setServerError(savedAlert.error); + } + closeFlyout(); refreshList(); }} > From 5473f025494cb35cdea15f20a0ff02b5501738e7 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 20 Nov 2019 21:32:47 -0800 Subject: [PATCH 122/297] Added connectors for action forms --- .../action_add/buildin_action_types/email.tsx | 88 ++++-- .../buildin_action_types/es_index.tsx | 81 ++++-- .../buildin_action_types/pagerduty.tsx | 37 ++- .../buildin_action_types/server_log.tsx | 97 ++++--- .../action_add/buildin_action_types/slack.tsx | 68 ++--- .../buildin_action_types/webhook.tsx | 185 ++----------- .../sections/alert_add/alert_add.tsx | 251 ++++++++++++++---- .../sections/alert_add/alert_reducer.ts | 52 +++- .../alerting_ui/np_ready/public/types.ts | 7 +- 9 files changed, 499 insertions(+), 367 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx index ad5892e89bff26..7f1a776a1a3491 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx @@ -16,7 +16,13 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ErrableFormRow } from '../../../components/page_error'; -import { ActionTypeModel, Props, Action, ValidationResult, ParamsProps } from '../../../../types'; +import { + ActionTypeModel, + Props, + Action, + ValidationResult, + ActionParamsProps, +} from '../../../../types'; export function getActionType(): ActionTypeModel { return { @@ -253,15 +259,17 @@ const EmailActionFields: React.FunctionComponent = ({ ); }; -const EmailParamsFields: React.FunctionComponent = ({ +const EmailParamsFields: React.FunctionComponent = ({ action, editAction, + index, errors, hasErrors, }) => { - const { to, cc, subject, body } = action; - const toOptions = to ? to.map((label: any) => ({ label })) : []; - const ccOptions = cc ? cc.map((label: any) => ({ label })) : []; + const { to, cc, bcc, subject, message } = action; + const toOptions = to ? to.map((label: string) => ({ label })) : []; + const ccOptions = cc ? cc.map((label: string) => ({ label })) : []; + const bccOptions = bcc ? bcc.map((label: string) => ({ label })) : []; return ( @@ -274,7 +282,7 @@ const EmailParamsFields: React.FunctionComponent = ({ label={i18n.translate( 'xpack.alertingUI.sections.actionAdd.emailAction.recipientTextFieldLabel', { - defaultMessage: 'To email address', + defaultMessage: 'To', } )} > @@ -287,18 +295,20 @@ const EmailParamsFields: React.FunctionComponent = ({ const newOptions = [...toOptions, { label: searchValue }]; editAction( 'to', - newOptions.map(newOption => newOption.label) + newOptions.map(newOption => newOption.label), + index ); }} onChange={(selectedOptions: Array<{ label: string }>) => { editAction( 'to', - selectedOptions.map(selectedOption => selectedOption.label) + selectedOptions.map(selectedOption => selectedOption.label), + index ); }} onBlur={() => { if (!to) { - editAction('to', []); + editAction('to', [], index); } }} /> @@ -312,7 +322,7 @@ const EmailParamsFields: React.FunctionComponent = ({ label={i18n.translate( 'xpack.alertingUI.sections.actionAdd.emailAction.recipientCopyTextFieldLabel', { - defaultMessage: 'CC email address', + defaultMessage: 'Cc', } )} > @@ -325,29 +335,70 @@ const EmailParamsFields: React.FunctionComponent = ({ const newOptions = [...ccOptions, { label: searchValue }]; editAction( 'cc', - newOptions.map(newOption => newOption.label) + newOptions.map(newOption => newOption.label), + index ); }} onChange={(selectedOptions: Array<{ label: string }>) => { editAction( 'cc', - selectedOptions.map(selectedOption => selectedOption.label) + selectedOptions.map(selectedOption => selectedOption.label), + index ); }} onBlur={() => { if (!cc) { - editAction('cc', []); + editAction('cc', [], index); + } + }} + /> + + + { + const newOptions = [...bccOptions, { label: searchValue }]; + editAction( + 'bcc', + newOptions.map(newOption => newOption.label), + index + ); + }} + onChange={(selectedOptions: Array<{ label: string }>) => { + editAction( + 'bcc', + selectedOptions.map(selectedOption => selectedOption.label), + index + ); + }} + onBlur={() => { + if (!bcc) { + editAction('bcc', [], index); } }} /> - @@ -357,11 +408,10 @@ const EmailParamsFields: React.FunctionComponent = ({ data-test-subj="emailSubjectInput" value={subject || ''} onChange={e => { - editAction('subject', e.target.value); + editAction('subject', e.target.value, index); }} /> - = ({ > { - editAction('message', e.target.value); + editAction('message', e.target.value, index); }} /> diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx index b80e1ec1fcfc24..95fb597b9d43a9 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx @@ -3,10 +3,17 @@ * 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 { EuiFieldText, EuiFormRow } from '@elastic/eui'; +import React, { Fragment } from 'react'; +import { EuiFieldText, EuiFormRow, EuiSwitch } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { ActionTypeModel, Props, ValidationResult, ParamsProps } from '../../../../types'; +import { + ActionTypeModel, + Props, + Action, + ValidationResult, + ActionParamsProps, +} from '../../../../types'; import { ErrableFormRow } from '../../../components/page_error'; export function getActionType(): ActionTypeModel { @@ -24,6 +31,10 @@ export function getActionType(): ActionTypeModel { }, actionFields: IndexActionFields, actionParamsFields: IndexParamsFields, + validateParams: (action: Action): ValidationResult => { + const validationResult = { errors: {} }; + return validationResult; + }, }; } @@ -54,38 +65,54 @@ const IndexActionFields: React.FunctionComponent = ({ action, editActionC ); }; -const IndexParamsFields: React.FunctionComponent = ({ +const IndexParamsFields: React.FunctionComponent = ({ action, + index, editAction, errors, hasErrors, }) => { - const { index } = action; + const { refresh, executionTimeField, documents } = action; return ( - - + ) => { - editAction('index', e.target.value); - }} - onBlur={() => { - if (!index) { - editAction('index', ''); - } + errors={errors} + isShowingErrors={hasErrors === true && action.index !== undefined} + label={i18n.translate('xpack.alertingUI.sections.actionAdd.indexAction.indexFieldLabel', { + defaultMessage: 'Index', + })} + > + ) => { + editAction('index', e.target.value, index); + }} + onBlur={() => { + if (!action.index) { + editAction('index', '', index); + } + }} + /> + + { + editAction('refresh', e.target.checked, index); }} + label={ + + } /> - + ); }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx index 04e02560ef2f80..120c1c192951b8 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx @@ -7,7 +7,13 @@ import React, { Fragment } from 'react'; import { EuiFieldText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ErrableFormRow } from '../../../components/page_error'; -import { ActionTypeModel, Props, Action, ValidationResult, ParamsProps } from '../../../../types'; +import { + ActionTypeModel, + Props, + Action, + ValidationResult, + ActionParamsProps, +} from '../../../../types'; export function getActionType(): ActionTypeModel { return { @@ -48,6 +54,10 @@ export function getActionType(): ActionTypeModel { } return validationResult; }, + validateParams: (action: Action): ValidationResult => { + const validationResult = { errors: {} }; + return validationResult; + }, actionFields: PagerDutyActionFields, actionParamsFields: PagerDutyParamsFields, }; @@ -124,41 +134,42 @@ const PagerDutyActionFields: React.FunctionComponent = ({ ); }; -const PagerDutyParamsFields: React.FunctionComponent = ({ +const PagerDutyParamsFields: React.FunctionComponent = ({ action, editAction, + index, errors, hasErrors, children, }) => { - const { description } = action; + const { eventAction, dedupKey, summary, source, severity, timestamp, component, group } = action; return ( {children} ) => { - editAction('description', e.target.value); + editAction('summary', e.target.value, index); }} onBlur={() => { - if (!description) { - editAction('description', ''); + if (!summary) { + editAction('summary', '', index); } }} /> diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx index 536f954087a5a7..321ee874887aa5 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx @@ -3,10 +3,10 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { Fragment } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiFieldText } from '@elastic/eui'; -import { ActionTypeModel, ValidationResult, ParamsProps } from '../../../../types'; +import { EuiSelect, EuiTextArea } from '@elastic/eui'; +import { ActionTypeModel, ValidationResult, ActionParamsProps, Action } from '../../../../types'; import { ErrableFormRow } from '../../../components/page_error'; export function getActionType(): ActionTypeModel { @@ -22,46 +22,81 @@ export function getActionType(): ActionTypeModel { validate: (): ValidationResult => { return { errors: {} }; }, + validateParams: (action: Action): ValidationResult => { + const validationResult = { errors: {} }; + return validationResult; + }, actionFields: null, actionParamsFields: ServerLogParamsFields, }; } -export const ServerLogParamsFields: React.FunctionComponent = ({ +export const ServerLogParamsFields: React.FunctionComponent = ({ action, editAction, + index, errors, hasErrors, }) => { - const { text } = action; + const { message, level } = action; + const levelOptions = [ + { value: 'trace', text: 'Trace' }, + { value: 'debug', text: 'Debug' }, + { value: 'info', text: 'Info' }, + { value: 'warn', text: 'Warning' }, + { value: 'error', text: 'Error' }, + { value: 'fatal', text: 'Fatal' }, + ]; + return ( - - + + { + editAction('level', e.target.value, index); + }} + /> + + ) => { - editAction('text', e.target.value); - }} - onBlur={() => { - if (!text) { - editAction('text', ''); + errors={errors} + isShowingErrors={hasErrors && message !== undefined} + label={i18n.translate( + 'xpack.alertingUI.sections.actionAdd.serverLogAction.logMessageFieldLabel', + { + defaultMessage: 'Message', } - }} - /> - + )} + > + { + editAction('message', e.target.value, index); + }} + /> + + ); }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx index 71435d710801dc..702775c68178ce 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx @@ -4,10 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ import React, { Fragment } from 'react'; -import { EuiFieldText, EuiFormRow, EuiComboBox, EuiTextArea } from '@elastic/eui'; +import { EuiFieldText, EuiTextArea } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ErrableFormRow } from '../../../components/page_error'; -import { ActionTypeModel, Props, Action, ValidationResult, ParamsProps } from '../../../../types'; +import { + ActionTypeModel, + Props, + Action, + ValidationResult, + ActionParamsProps, +} from '../../../../types'; export function getActionType(): ActionTypeModel { return { @@ -37,6 +43,10 @@ export function getActionType(): ActionTypeModel { } return validationResult; }, + validateParams: (action: Action): ValidationResult => { + const validationResult = { errors: {} }; + return validationResult; + }, actionFields: SlackActionFields, actionParamsFields: SlackParamsFields, }; @@ -84,68 +94,40 @@ const SlackActionFields: React.FunctionComponent = ({ ); }; -const SlackParamsFields: React.FunctionComponent = ({ +const SlackParamsFields: React.FunctionComponent = ({ action, editAction, + index, errors, hasErrors, - children, }) => { - const { text, to } = action; - const toOptions = to ? to.map((label: any) => ({ label })) : []; + const { message } = action; return ( - {children} - - { - const newOptions = [...toOptions, { label: searchValue }]; - editAction( - 'to', - newOptions.map(newOption => newOption.label) - ); - }} - onChange={(selectedOptions: Array<{ label: string }>) => { - editAction( - 'to', - selectedOptions.map(selectedOption => selectedOption.label) - ); - }} - /> - - - { - editAction('text', e.target.value); + editAction('message', e.target.value, index); }} /> - + ); }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx index 82d7bfde062102..724f79536a1969 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx @@ -18,12 +18,17 @@ import { EuiButtonIcon, EuiText, EuiTitle, - EuiFieldNumber, EuiCodeEditor, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ErrableFormRow } from '../../../components/page_error'; -import { ActionTypeModel, Props, Action, ValidationResult, ParamsProps } from '../../../../types'; +import { + ActionTypeModel, + Props, + Action, + ValidationResult, + ActionParamsProps, +} from '../../../../types'; const HTTP_VERBS = ['post', 'put']; @@ -88,6 +93,10 @@ export function getActionType(): ActionTypeModel { } return validationResult; }, + validateParams: (action: Action): ValidationResult => { + const validationResult = { errors: {} }; + return validationResult; + }, actionFields: WebhookActionFields, actionParamsFields: WebhookParamsFields, }; @@ -382,181 +391,17 @@ const WebhookActionFields: React.FunctionComponent = ({ ); }; -const WebhookParamsFields: React.FunctionComponent = ({ +const WebhookParamsFields: React.FunctionComponent = ({ action, editAction, + index, errors, hasErrors, }) => { - const { method, host, port, path, body, username, password } = action; - - useEffect(() => { - editAction('contentType', 'application/json'); // set content-type for threshold watch to json by default - }, [editAction]); + const { body } = action; return ( - - - - ({ text: verb.toUpperCase(), value: verb }))} - onChange={e => { - editAction('method', e.target.value); - }} - /> - - - - - - { - editAction('host', e.target.value); - }} - onBlur={() => { - if (!host) { - editAction('host', ''); - } - }} - /> - - - - - - { - editAction('port', parseInt(e.target.value, 10)); - }} - onBlur={() => { - if (!port) { - editAction('port', ''); - } - }} - /> - - - - - - { - editAction('path', e.target.value); - }} - /> - - - - - - - - { - editAction('username', e.target.value); - }} - /> - - - - - - { - editAction('password', e.target.value); - }} - /> - - - - - - = ({ )} value={body || ''} onChange={(json: string) => { - editAction('body', json); + editAction('body', json, index); }} /> diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 62147155c0c6e1..0694d047f13fb8 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -23,7 +23,6 @@ import { EuiFlexGrid, EuiFormRow, EuiComboBox, - EuiComboBoxOptionProps, EuiCard, EuiTabs, EuiTab, @@ -32,9 +31,11 @@ import { EuiSelect, EuiIconTip, EuiPortal, + EuiAccordion, + EuiButtonIcon, } from '@elastic/eui'; import { useAppDependencies } from '../..'; -import { saveAlert, loadActionTypes } from '../../lib/api'; +import { saveAlert, loadActionTypes, loadAllActions } from '../../lib/api'; import { AlertsContext } from '../../context/alerts_context'; import { alertReducer } from './alert_reducer'; import { ErrableFormRow, SectionError } from '../../components/page_error'; @@ -45,6 +46,7 @@ import { ActionTypeModel, AlertAction, ActionTypeIndex, + Action, } from '../../../types'; import { ACTION_GROUPS } from '../../constants/action_groups'; import { getTimeOptions } from '../../lib/get_time_options'; @@ -97,7 +99,7 @@ export const AlertAdd = ({ refreshList }: Props) => { alertTypeId: null, interval: '1m', actions: [], - tags: ['sfdfsfsd'], + tags: [], }; const { alertFlyoutVisible, setAlertFlyoutVisibility } = useContext(AlertsContext); @@ -107,16 +109,17 @@ export const AlertAdd = ({ refreshList }: Props) => { const [isSaving, setIsSaving] = useState(false); const [isLoadingActionTypes, setIsLoadingActionTypes] = useState(false); const [selectedTabId, setSelectedTabId] = useState('alert'); - const [alertAction, setAlertAction] = useState(undefined); const [actionTypesIndex, setActionTypesIndex] = useState(undefined); const [alertInterval, setAlertInterval] = useState(null); const [alertIntervalUnit, setAlertIntervalUnit] = useState('m'); const [alertThrottle, setAlertThrottle] = useState(null); const [alertThrottleUnit, setAlertThrottleUnit] = useState(''); - const tagsOptions = alert.tags ? alert.tags.map((label: string) => ({ label })) : []; const [serverError, setServerError] = useState<{ body: { message: string; error: string }; } | null>(null); + const [isAddActionPanelOpen, setIsAddActionPanelOpen] = useState(true); + const [connectors, setConnectors] = useState([]); + const [actionsConnectors, setActionsConnectors] = useState([]); useEffect(() => { (async () => { @@ -157,6 +160,11 @@ export const AlertAdd = ({ refreshList }: Props) => { }); }, [alertFlyoutVisible]); + useEffect(() => { + loadConnectors(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [alertFlyoutVisible]); + const setAlertProperty = (key: string, value: any) => { dispatch({ command: { type: 'setProperty' }, payload: { key, value } }); }; @@ -165,13 +173,17 @@ export const AlertAdd = ({ refreshList }: Props) => { dispatch({ command: { type: 'setAlertTypeParams' }, payload: { key, value } }); }; - const setActionParams = (key: string, value: any) => { - dispatch({ command: { type: 'setAlertActionParam' }, payload: { key, value } }); + const setActionParamsProperty = (key: string, value: any, index: number) => { + dispatch({ command: { type: 'setAlertActionParams' }, payload: { key, value, index } }); }; + + const setActionProperty = (key: string, value: any, index: number) => { + dispatch({ command: { type: 'setAlertActionProperty' }, payload: { key, value, index } }); + }; + const closeFlyout = useCallback(() => { setAlertFlyoutVisibility(false); setAlertType(undefined); - setAlertAction(undefined); setSelectedTabId('alert'); setServerError(null); }, [setAlertFlyoutVisibility]); @@ -180,6 +192,21 @@ export const AlertAdd = ({ refreshList }: Props) => { return null; } + const tagsOptions = alert.tags ? alert.tags.map((label: string) => ({ label })) : []; + + async function loadConnectors() { + try { + const actionsResponse = await loadAllActions({ http }); + setConnectors(actionsResponse.data); + } catch (e) { + toastNotifications.addDanger({ + title: i18n.translate('xpack.alertingUI.sections.alertAdd.unableToLoadActionsMessage', { + defaultMessage: 'Unable to load actions', + }), + }); + } + } + const AlertTypeParamsExpressionComponent = alertType ? alertType.alertTypeParamsExpression : null; const errors = { @@ -188,13 +215,13 @@ export const AlertAdd = ({ refreshList }: Props) => { } as IErrorObject; const hasErrors = !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); - const actionErrors = alert.actions.reduce((acc: any, alertActionType: any) => { - const actionType = actionTypeRegistry.get(alertActionType.id); + const actionErrors = alert.actions.reduce((acc: any, alertAction: AlertAction) => { + const actionType = actionTypeRegistry.get(alertAction.id); if (!actionType) { return []; } - const actionValidationErrors = actionType.validateParams(alertActionType.params); - acc[alertActionType.id] = actionValidationErrors; + const actionValidationErrors = actionType.validateParams(alertAction.params); + acc[alertAction.id] = actionValidationErrors; return acc; }, {}); @@ -245,8 +272,16 @@ export const AlertAdd = ({ refreshList }: Props) => { } } - function addActionType(actionType: ActionTypeModel) { - setAlertAction({ id: actionType.id, group: selectedTabId, params: {} }); + function addActionType(actionTypeModel: ActionTypeModel) { + setIsAddActionPanelOpen(false); + const actionTypeConnectors = connectors.filter( + field => field.actionTypeId === actionTypeModel.id + ); + if (actionTypeConnectors.length > 0) { + alert.actions.push({ id: actionTypeConnectors[0].id, group: selectedTabId, params: {} }); + actionsConnectors.push(actionTypeConnectors[0].actionTypeId); + setActionsConnectors(actionsConnectors); + } } const alertTypeNodes = alertTypeRegistry.list().map(function(item, index) { @@ -333,51 +368,135 @@ export const AlertAdd = ({ refreshList }: Props) => { ); - let alertDetails; - if (!alertAction) { - alertDetails = ( - - -
- -
-
- - - {actionTypeNodes} - -
- ); - } else { - alert.actions.push(alertAction); - const actionTypeRegisterd = actionTypeRegistry.get(alert.actions[0].id); - if (actionTypeRegisterd === null) return null; - const ParamsFieldsComponent = actionTypeRegisterd.actionParamsFields; - alertDetails = ( - - -
- -
-
- - {ParamsFieldsComponent !== null ? ( - { + const val = connectors.find(connector => connector.id === actionItemId); + if (!val) { + return []; + } + return [ + { + label: val.description, + value: val.description, + id: actionItemId, + }, + ]; + }; + + const alertDetails = ( + + {alert.actions.map((actionItem: AlertAction, index: number) => { + const optionsList = connectors + .filter(field => field.actionTypeId === actionsConnectors[index]) + .map(({ description, id }) => ({ + label: description, + value: description, + id, + })); + const actionTypeRegisterd = actionTypeRegistry.get(actionsConnectors[index]); + if (actionTypeRegisterd === null) return null; + const ParamsFieldsComponent = actionTypeRegisterd.actionParamsFields; + return ( + + + + + + +
+ +
+
+
+ + } + extraAction={ + { + const updatedActions = alert.actions.filter( + (item: AlertAction) => item.id !== actionItem.id + ); + setAlertProperty('actions', updatedActions); + }} + /> + } + paddingSize="l" + > + + } + errorKey="name" + isShowingErrors={hasErrors && alert.name !== undefined} + errors={errors} + > + { + setActionProperty('id', selectedOptions[0].id, index); + }} + isClearable={false} + /> + + + {ParamsFieldsComponent ? ( + + ) : null} +
+ ); + })} + + {!isAddActionPanelOpen ? ( + setIsAddActionPanelOpen(true)} + > + - ) : null} -
- ); - } + + ) : null} +
+ ); const warningDetails = Warning; @@ -616,6 +735,22 @@ export const AlertAdd = ({ refreshList }: Props) => { {alertTypeArea} {selectedTabContent} + {isAddActionPanelOpen || alert.actions.length === 0 ? ( + + +
+ +
+
+ + + {actionTypeNodes} + +
+ ) : null}
diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts index 08f2a3f24a8820..a52b2b04c701f4 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts @@ -6,7 +6,12 @@ import { isEqual } from 'lodash'; interface CommandType { - type: 'setAlert' | 'setProperty' | 'setAlertTypeParams' | 'setAlertActionParam'; + type: + | 'setAlert' + | 'setProperty' + | 'setAlertTypeParams' + | 'setAlertActionParams' + | 'setAlertActionProperty'; } export interface AlertState { @@ -18,6 +23,7 @@ export interface ActionAlertReducerItem { payload: { key: string; value: {}; + index?: number; }; } @@ -68,8 +74,48 @@ export const alertReducer = (state: any, action: ActionAlertReducerItem) => { }; } } - case 'setAlertActionParam': { - return state; + case 'setAlertActionParams': { + const { key, value, index } = payload; + if (index === undefined || isEqual(alert.actions[index][key], value)) { + return state; + } else { + const oldAction = alert.actions.splice(index, 1)[0]; + const updatedAction = { + ...oldAction, + params: { + ...oldAction.params, + [key]: value, + }, + }; + + return { + ...state, + alert: { + ...alert, + actions: [...alert.actions, updatedAction], + }, + }; + } + } + case 'setAlertActionProperty': { + const { key, value, index } = payload; + if (index === undefined || isEqual(alert.actions[index][key], value)) { + return state; + } else { + const oldAction = alert.actions.splice(index, 1)[0]; + const updatedAction = { + ...oldAction, + [key]: value, + }; + + return { + ...state, + alert: { + ...alert, + actions: [...alert.actions, updatedAction], + }, + }; + } } } }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts index 1db5d83e663203..4ba8f36b7b8fae 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts @@ -15,9 +15,10 @@ export interface Props { hasErrors?: boolean; } -export interface ParamsProps { +export interface ActionParamsProps { action: any; - editAction: (property: string, value: any) => void; + index: number; + editAction: (property: string, value: any, index: number) => void; errors: { [key: string]: string[] }; hasErrors?: boolean; } @@ -34,7 +35,7 @@ export interface ActionTypeModel { validate: (action: Action) => ValidationResult; validateParams: (actionParams: any) => ValidationResult; actionFields: React.FunctionComponent | null; - actionParamsFields: React.FunctionComponent | null; + actionParamsFields: React.FunctionComponent | null; } export interface ValidationResult { From 4fd67832703a200da312db6043a7b2a50492510e Mon Sep 17 00:00:00 2001 From: defazio Date: Thu, 21 Nov 2019 10:18:26 -0500 Subject: [PATCH 123/297] Update button styles --- .../sections/actions_list/components/actions_list.tsx | 2 +- .../public/application/sections/alert_add/alert_add.tsx | 2 +- .../application/sections/alerts_list/components/alerts_list.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 673e4195e70fdd..6818b1e198f218 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -265,7 +265,7 @@ export const ActionsList: React.FunctionComponent = () => { data-test-subj="createActionButton" key="create-action" fill - iconType="plusInCircleFilled" + iconType="plusInCircle" iconSide="left" onClick={() => setFlyoutVisibility(true)} > diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 0694d047f13fb8..2cc109845ccb07 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -485,7 +485,7 @@ export const AlertAdd = ({ refreshList }: Props) => { {!isAddActionPanelOpen ? ( setIsAddActionPanelOpen(true)} > diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 626b87eb8c5857..a2b598fdf114e7 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -217,7 +217,7 @@ export const AlertsList: React.FunctionComponent = () => { key="create-alert" data-test-subj="createAlertButton" fill - iconType="plusInCircleFilled" + iconType="plusInCircle" iconSide="left" onClick={() => setAlertFlyoutVisibility(true)} > From c6f2218406e424b1ddf772a2c577b51e2c6b3119 Mon Sep 17 00:00:00 2001 From: defazio Date: Thu, 21 Nov 2019 12:54:20 -0500 Subject: [PATCH 124/297] Switch inputs to compressed forms --- .../sections/alert_add/alert_add.tsx | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 2cc109845ccb07..080da945ded8ac 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -603,6 +603,7 @@ export const AlertAdd = ({ refreshList }: Props) => { { errors={errors} > { { @@ -668,11 +672,13 @@ export const AlertAdd = ({ refreshList }: Props) => { - + - - + + { { setAlertIntervalUnit(e.target.value); setAlertProperty('interval', `${alertInterval}${e.target.value}`); }} - fullWidth={true} /> - + - - + + { { setAlertThrottleUnit(e.target.value); setAlertProperty('throttle', `${alertThrottle}${e.target.value}`); }} - fullWidth={true} /> From ba3172edfc11551b56c3f432376200f963f295a0 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 21 Nov 2019 10:42:17 -0800 Subject: [PATCH 125/297] Fixed some fields for add alert form --- .../action_add/buildin_action_types/slack.tsx | 12 ++++- .../sections/alert_add/alert_add.tsx | 51 ++++++++----------- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx index 702775c68178ce..192e602a1e6735 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ import React, { Fragment } from 'react'; -import { EuiFieldText, EuiTextArea } from '@elastic/eui'; +import { EuiFieldText, EuiTextArea, EuiFlexGroup, EuiFlexItem, EuiButtonIcon } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { ErrableFormRow } from '../../../components/page_error'; import { @@ -105,6 +106,15 @@ const SlackParamsFields: React.FunctionComponent = ({ return ( + + + window.alert('Button clicked')} + iconType="indexOpen" + aria-label="Add variable" + /> + + { } | null>(null); const [isAddActionPanelOpen, setIsAddActionPanelOpen] = useState(true); const [connectors, setConnectors] = useState([]); - const [actionsConnectors, setActionsConnectors] = useState([]); useEffect(() => { (async () => { @@ -279,8 +278,6 @@ export const AlertAdd = ({ refreshList }: Props) => { ); if (actionTypeConnectors.length > 0) { alert.actions.push({ id: actionTypeConnectors[0].id, group: selectedTabId, params: {} }); - actionsConnectors.push(actionTypeConnectors[0].actionTypeId); - setActionsConnectors(actionsConnectors); } } @@ -318,7 +315,14 @@ export const AlertAdd = ({ refreshList }: Props) => { const alertTabs = tabs.map(function(tab, index): any { return ( setSelectedTabId(tab.id)} + onClick={() => { + setSelectedTabId(tab.id); + if (!alert.actions.find((action: AlertAction) => action.group === tab.id)) { + setIsAddActionPanelOpen(true); + } else { + setIsAddActionPanelOpen(false); + } + }} isSelected={tab.id === selectedTabId} disabled={tab.disabled} key={index} @@ -382,18 +386,22 @@ export const AlertAdd = ({ refreshList }: Props) => { ]; }; - const alertDetails = ( + const actionsListForGroup = ( {alert.actions.map((actionItem: AlertAction, index: number) => { + const actionConnector = connectors.find(field => field.id === actionItem.id); + if (!actionConnector) { + return null; + } const optionsList = connectors - .filter(field => field.actionTypeId === actionsConnectors[index]) + .filter(field => field.actionTypeId === actionConnector.actionTypeId) .map(({ description, id }) => ({ label: description, value: description, id, })); - const actionTypeRegisterd = actionTypeRegistry.get(actionsConnectors[index]); - if (actionTypeRegisterd === null) return null; + const actionTypeRegisterd = actionTypeRegistry.get(actionConnector.actionTypeId); + if (actionTypeRegisterd === null || actionItem.group !== selectedTabId) return null; const ParamsFieldsComponent = actionTypeRegisterd.actionParamsFields; return ( {
@@ -449,8 +457,8 @@ export const AlertAdd = ({ refreshList }: Props) => { defaultMessage="{connectorInstance} instance" values={{ connectorInstance: actionTypesIndex - ? actionTypesIndex[actionsConnectors[index]].name - : actionsConnectors[index], + ? actionTypesIndex[actionConnector.actionTypeId].name + : actionConnector.actionTypeId, }} /> } @@ -498,25 +506,6 @@ export const AlertAdd = ({ refreshList }: Props) => {
); - const warningDetails = Warning; - - const unacknowledgedDetails = Unacknowledged; - - let selectedTabContent; - switch (selectedTabId) { - case ACTION_GROUPS.ALERT: - selectedTabContent = alertDetails; - break; - case ACTION_GROUPS.WARNING: - selectedTabContent = warningDetails; - break; - case ACTION_GROUPS.UNACKNOWLEDGED: - selectedTabContent = unacknowledgedDetails; - break; - default: - selectedTabContent = null; - } - let alertTypeArea; if (alertType) { alertTypeArea = {alertTypeDetails}; @@ -743,7 +732,7 @@ export const AlertAdd = ({ refreshList }: Props) => { {alertTypeArea} - {selectedTabContent} + {actionsListForGroup} {isAddActionPanelOpen || alert.actions.length === 0 ? ( From 2b3cb2d026e47028723242becabe7a00d103c39d Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 21 Nov 2019 13:03:23 -0800 Subject: [PATCH 126/297] Fixed updating action by index --- .../application/sections/alert_add/alert_reducer.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts index a52b2b04c701f4..95bdcfbb82bed9 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts @@ -87,12 +87,12 @@ export const alertReducer = (state: any, action: ActionAlertReducerItem) => { [key]: value, }, }; - + alert.actions.splice(index, 0, updatedAction); return { ...state, alert: { ...alert, - actions: [...alert.actions, updatedAction], + actions: [...alert.actions], }, }; } @@ -107,12 +107,12 @@ export const alertReducer = (state: any, action: ActionAlertReducerItem) => { ...oldAction, [key]: value, }; - + alert.actions.splice(index, 0, updatedAction); return { ...state, alert: { ...alert, - actions: [...alert.actions, updatedAction], + actions: [...alert.actions], }, }; } From 88ee52ef8b37a92b0c75f136d9859acb4e298370 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 21 Nov 2019 14:20:54 -0800 Subject: [PATCH 127/297] Fixed filter for index/fields api requests --- .../alerting_ui/np_ready/public/application/lib/api.ts | 8 ++++---- .../alert_add/alert_types/threshold/expression.tsx | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts index 6bbaf7326123ad..af2056fca9ef82 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts @@ -182,20 +182,20 @@ export async function getMatchingIndicesForThresholdAlertType({ pattern = `${pattern}*`; } const { indices } = await http.post(`${WATCHER_API_ROOT}/indices`, { - body: JSON.stringify(pattern), + body: JSON.stringify({ pattern }), }); return indices; } export async function getThresholdAlertTypeFields({ - indices, + indexes, http, }: { - indices: string[]; + indexes: string[]; http: HttpServiceBase; }): Promise> { const { fields } = await http.post(`${WATCHER_API_ROOT}/fields`, { - body: JSON.stringify(indices), + body: JSON.stringify({ indexes }), }); return fields; } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx index a73a63c2def5b0..205b012f5a2ea6 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx @@ -352,8 +352,8 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = }); }; - const getFields = async (indices: string[]) => { - return await getThresholdAlertTypeFields({ indices, http }); + const getFields = async (indexes: string[]) => { + return await getThresholdAlertTypeFields({ indexes, http }); }; useEffect(() => { From a0560ddda7f66ed66ed20a74efb51b27a0f2b0a2 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 22 Nov 2019 13:18:23 -0500 Subject: [PATCH 128/297] Remove the test alert type that was in the init function --- x-pack/legacy/plugins/alerting_ui/index.ts | 39 ---------------------- 1 file changed, 39 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/index.ts b/x-pack/legacy/plugins/alerting_ui/index.ts index 7d418ac62ed6e4..59a57fde4a9786 100644 --- a/x-pack/legacy/plugins/alerting_ui/index.ts +++ b/x-pack/legacy/plugins/alerting_ui/index.ts @@ -31,44 +31,5 @@ export function alertingUI(kibana: any) { hacks: ['plugins/alerting_ui/hacks/register'], managementSections: ['plugins/alerting_ui'], }, - // TODO: Remove init - init(server: any) { - server.plugins.alerting.setup.registerType({ - id: 'test.always-firing', - name: 'Test: Always Firing', - actionGroups: ['default', 'other'], - async executor({ services, params, state }: any) { - let group = 'default'; - - if (params.groupsToScheduleActionsInSeries) { - const index = state.groupInSeriesIndex || 0; - group = params.groupsToScheduleActionsInSeries[index]; - } - - if (group) { - services - .alertInstanceFactory('1') - .replaceState({ instanceStateValue: true }) - .scheduleActions(group, { - instanceContextValue: true, - }); - } - await services.callCluster('index', { - index: params.index, - refresh: 'wait_for', - body: { - state, - params, - reference: params.reference, - source: 'alert:test.always-firing', - }, - }); - return { - globalStateValue: true, - groupInSeriesIndex: (state.groupInSeriesIndex || 0) + 1, - }; - }, - }); - }, }); } From bb43d3967aad9514d482b2107f870551d092ad83 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 25 Nov 2019 09:29:20 -0800 Subject: [PATCH 129/297] Fixed action type icon on add connector form and did small refactoring on action forms; added action validation --- .../sections/action_add/action_add_flyout.tsx | 42 +++- .../action_add/buildin_action_types/email.tsx | 58 +++++- .../buildin_action_types/es_index.tsx | 10 +- .../buildin_action_types/pagerduty.tsx | 187 ++++++++++++++++- .../buildin_action_types/server_log.tsx | 4 +- .../action_add/buildin_action_types/slack.tsx | 2 +- .../buildin_action_types/webhook.tsx | 4 +- .../sections/alert_add/alert_add.tsx | 31 ++- .../alert_types/threshold/expression.tsx | 192 +++++++++--------- 9 files changed, 386 insertions(+), 144 deletions(-) diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_flyout.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_flyout.tsx index 5e5e94277e2f38..5d22a15f82c023 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_flyout.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_flyout.tsx @@ -5,16 +5,25 @@ */ import React, { useContext, useCallback, useState, useEffect } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiTitle, EuiFlyoutHeader, EuiFlyout } from '@elastic/eui'; +import { + EuiTitle, + EuiFlyoutHeader, + EuiFlyout, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, +} from '@elastic/eui'; import { ActionsContext } from '../../context/actions_context'; import { ActionTypeMenu } from './action_type_menu'; import { ActionAddForm } from './action_add_form'; import { ActionType } from '../../../types'; +import { useAppDependencies } from '../..'; export const ActionAddFlyout = () => { + const { actionTypeRegistry } = useAppDependencies(); const { flyoutVisible, setFlyoutVisibility } = useContext(ActionsContext); const [actionType, setActionType] = useState(undefined); - const closeFlyout = useCallback(() => setFlyoutVisibility(false), []); + const closeFlyout = useCallback(() => setFlyoutVisibility(false), [setFlyoutVisibility]); useEffect(() => { setActionType(undefined); @@ -25,23 +34,34 @@ export const ActionAddFlyout = () => { } let currentForm; + let actionTypeModel; if (!actionType) { - currentForm = ; + currentForm = ; } else { + actionTypeModel = actionTypeRegistry.get(actionType.id); currentForm = ; } return ( - -

- -

-
+ + {actionTypeModel ? ( + + + + ) : null} + + +

+ +

+
+
+
{currentForm}
diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx index 7f1a776a1a3491..15087621b1d7cc 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx @@ -11,7 +11,6 @@ import { EuiFieldNumber, EuiFieldPassword, EuiComboBox, - EuiFormRow, EuiTextArea, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -81,8 +80,46 @@ export function getActionType(): ActionTypeModel { } return validationResult; }, - validateParams: (action: Action): ValidationResult => { + validateParams: (actionParams: any): ValidationResult => { const validationResult = { errors: {} }; + const errors = { + to: new Array(), + cc: new Array(), + bcc: new Array(), + message: new Array(), + subject: new Array(), + }; + validationResult.errors = errors; + if ( + ((!actionParams.to || actionParams.to.length === 0) && + (!actionParams.cc || actionParams.cc.length === 0)) || + !actionParams.bcc || + actionParams.bcc.length === 0 + ) { + const errorText = i18n.translate( + 'xpack.alertingUI.sections.addAction.error.requiredEntryText', + { + defaultMessage: 'No [to], [cc], or [bcc] entries. At least one entry is required.', + } + ); + errors.to.push(errorText); + errors.cc.push(errorText); + errors.bcc.push(errorText); + } + if (!actionParams.message) { + errors.message.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredMessageText', { + defaultMessage: 'Message is required.', + }) + ); + } + if (!actionParams.subject) { + errors.subject.push( + i18n.translate('xpack.alertingUI.sections.addAction.error.requiredSubjectText', { + defaultMessage: 'Subject is required.', + }) + ); + } return validationResult; }, actionFields: EmailActionFields, @@ -274,7 +311,6 @@ const EmailParamsFields: React.FunctionComponent = ({ return ( = ({ /> = ({ /> = ({ }} /> - = ({ editAction('subject', e.target.value, index); }} /> - - + = ({ editAction('message', e.target.value, index); }} /> - +
); }; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx index 95fb597b9d43a9..0ca67ed133b618 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx @@ -7,13 +7,7 @@ import React, { Fragment } from 'react'; import { EuiFieldText, EuiFormRow, EuiSwitch } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { - ActionTypeModel, - Props, - Action, - ValidationResult, - ActionParamsProps, -} from '../../../../types'; +import { ActionTypeModel, Props, ValidationResult, ActionParamsProps } from '../../../../types'; import { ErrableFormRow } from '../../../components/page_error'; export function getActionType(): ActionTypeModel { @@ -31,7 +25,7 @@ export function getActionType(): ActionTypeModel { }, actionFields: IndexActionFields, actionParamsFields: IndexParamsFields, - validateParams: (action: Action): ValidationResult => { + validateParams: (actionParams: any): ValidationResult => { const validationResult = { errors: {} }; return validationResult; }, diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx index 120c1c192951b8..d58dc532fef0a5 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import React, { Fragment } from 'react'; -import { EuiFieldText } from '@elastic/eui'; +import { EuiFieldText, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiSelect } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ErrableFormRow } from '../../../components/page_error'; import { @@ -54,7 +54,7 @@ export function getActionType(): ActionTypeModel { } return validationResult; }, - validateParams: (action: Action): ValidationResult => { + validateParams: (actionParams: any): ValidationResult => { const validationResult = { errors: {} }; return validationResult; }, @@ -140,12 +140,191 @@ const PagerDutyParamsFields: React.FunctionComponent = ({ index, errors, hasErrors, - children, }) => { const { eventAction, dedupKey, summary, source, severity, timestamp, component, group } = action; + const severityOptions = [ + { value: 'critical', text: 'Critical' }, + { value: 'info', text: 'Info' }, + { value: 'warning', text: 'Warning' }, + { value: 'error', text: 'Error' }, + ]; + const eventActionOptions = [ + { value: 'trigger', text: 'Trigger' }, + { value: 'resolve', text: 'Resolve' }, + { value: 'acknowledge', text: 'Acknowledge' }, + ]; return ( - {children} + + + + { + editAction('severity', e.target.value, index); + }} + /> + + + + + { + editAction('eventAction', e.target.value, index); + }} + /> + + + + + + + ) => { + editAction('dedupKey', e.target.value, index); + }} + onBlur={() => { + if (!index) { + editAction('dedupKey', '', index); + } + }} + /> + + + + + ) => { + editAction('timestamp', e.target.value, index); + }} + onBlur={() => { + if (!index) { + editAction('timestamp', '', index); + } + }} + /> + + + + + ) => { + editAction('component', e.target.value, index); + }} + onBlur={() => { + if (!index) { + editAction('component', '', index); + } + }} + /> + + + ) => { + editAction('group', e.target.value, index); + }} + onBlur={() => { + if (!index) { + editAction('group', '', index); + } + }} + /> + + + ) => { + editAction('source', e.target.value, index); + }} + onBlur={() => { + if (!index) { + editAction('source', '', index); + } + }} + /> + { return { errors: {} }; }, - validateParams: (action: Action): ValidationResult => { + validateParams: (actionParams: any): ValidationResult => { const validationResult = { errors: {} }; return validationResult; }, diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx index 192e602a1e6735..38285f8da7a9b7 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx @@ -44,7 +44,7 @@ export function getActionType(): ActionTypeModel { } return validationResult; }, - validateParams: (action: Action): ValidationResult => { + validateParams: (actionParams: any): ValidationResult => { const validationResult = { errors: {} }; return validationResult; }, diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx index 724f79536a1969..56a27fd526af2e 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, useState, useEffect } from 'react'; +import React, { Fragment, useState } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { @@ -93,7 +93,7 @@ export function getActionType(): ActionTypeModel { } return validationResult; }, - validateParams: (action: Action): ValidationResult => { + validateParams: (actionParams: any): ValidationResult => { const validationResult = { errors: {} }; return validationResult; }, diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 86bf6785425438..1566936722f3b0 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -183,6 +183,7 @@ export const AlertAdd = ({ refreshList }: Props) => { const closeFlyout = useCallback(() => { setAlertFlyoutVisibility(false); setAlertType(undefined); + setIsAddActionPanelOpen(true); setSelectedTabId('alert'); setServerError(null); }, [setAlertFlyoutVisibility]); @@ -215,7 +216,11 @@ export const AlertAdd = ({ refreshList }: Props) => { const hasErrors = !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); const actionErrors = alert.actions.reduce((acc: any, alertAction: AlertAction) => { - const actionType = actionTypeRegistry.get(alertAction.id); + const actionTypeConnectors = connectors.find(field => field.id === alertAction.id); + if (!actionTypeConnectors) { + return []; + } + const actionType = actionTypeRegistry.get(actionTypeConnectors.actionTypeId); if (!actionType) { return []; } @@ -403,6 +408,11 @@ export const AlertAdd = ({ refreshList }: Props) => { const actionTypeRegisterd = actionTypeRegistry.get(actionConnector.actionTypeId); if (actionTypeRegisterd === null || actionItem.group !== selectedTabId) return null; const ParamsFieldsComponent = actionTypeRegisterd.actionParamsFields; + const actionParamsErrors = + Object.keys(actionErrors).length > 0 ? actionErrors[actionItem.id] : []; + const hasActionParamsErrors = !!Object.keys(actionParamsErrors).find( + errorKey => actionParamsErrors[errorKey].length >= 1 + ); return ( {
-
+
{ } paddingSize="l" > - { }} /> } - errorKey="name" - isShowingErrors={hasErrors && alert.name !== undefined} - errors={errors} + // errorKey="name" + // isShowingErrors={hasErrors} + // errors={errors} > { }} isClearable={false} /> - + {ParamsFieldsComponent ? ( ) : null} @@ -733,7 +742,7 @@ export const AlertAdd = ({ refreshList }: Props) => { {alertTypeArea} {actionsListForGroup} - {isAddActionPanelOpen || alert.actions.length === 0 ? ( + {isAddActionPanelOpen ? (
diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx index 205b012f5a2ea6..1b4a7424dbda3e 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx +++ b/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useState, Fragment, useEffect, useCallback } from 'react'; +import React, { useState, Fragment, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { @@ -21,9 +21,9 @@ import { EuiText, EuiCallOut, } from '@elastic/eui'; -import { AlertTypeModel, AlertType, Alert, ValidationResult } from '../../../../../types'; +import { AlertTypeModel, Alert, ValidationResult } from '../../../../../types'; import { Comparator, AggregationType, GroupByType } from '../types'; -import { COMPARATORS, AGGREGATION_TYPES, expressionFields } from '../../../../constants'; +import { COMPARATORS, AGGREGATION_TYPES } from '../../../../constants'; import { getMatchingIndicesForThresholdAlertType, getThresholdAlertTypeFields, @@ -59,6 +59,98 @@ const expressionFieldsWithValidation = [ 'timeWindowSize', ]; +const validateAlertType = (alert: Alert): ValidationResult => { + const { + index, + timeField, + triggerIntervalSize, + aggType, + aggField, + groupBy, + termSize, + termField, + threshold, + timeWindowSize, + } = alert.alertTypeParams; + const validationResult = { errors: {} }; + const errors = { + aggField: new Array(), + termSize: new Array(), + termField: new Array(), + timeWindowSize: new Array(), + threshold0: new Array(), + threshold1: new Array(), + index: new Array(), + timeField: new Array(), + triggerIntervalSize: new Array(), + }; + validationResult.errors = errors; + if (!index) { + errors.index.push( + i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredIndexText', { + defaultMessage: 'Index is required.', + }) + ); + } + if (!timeField) { + errors.timeField.push( + i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredTimeFieldText', { + defaultMessage: 'Time field is required.', + }) + ); + } + if (!triggerIntervalSize) { + errors.triggerIntervalSize.push( + i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredTriggerIntervalSizeText', { + defaultMessage: 'Trigger interval size is required.', + }) + ); + } + if (aggType && aggregationTypes[aggType].fieldRequired && !aggField) { + errors.aggField.push( + i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredAggFieldText', { + defaultMessage: 'Aggregation field is required.', + }) + ); + } + if (!termSize) { + errors.termSize.push( + i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredTermSizedText', { + defaultMessage: 'Term size is required.', + }) + ); + } + if (groupBy && groupByTypes[groupBy].sizeRequired && !termField) { + errors.termField.push( + i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredtTermFieldText', { + defaultMessage: 'Term field is required.', + }) + ); + } + if (!timeWindowSize) { + errors.timeWindowSize.push( + i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredTimeWindowSizeText', { + defaultMessage: 'Time window size is required.', + }) + ); + } + if (threshold && threshold.length > 0 && !threshold[0]) { + errors.threshold0.push( + i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredThreshold0Text', { + defaultMessage: 'Threshold0, is required.', + }) + ); + } + if (threshold && threshold.length > 1 && !threshold[1]) { + errors.threshold1.push( + i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredThreshold1Text', { + defaultMessage: 'Threshold1 is required.', + }) + ); + } + return validationResult; +}; + export function getActionType(): AlertTypeModel { return { id: 'threshold', @@ -179,98 +271,6 @@ interface Props { hasErrors?: boolean; } -function validateAlertType(alert: Alert): ValidationResult { - const { - index, - timeField, - triggerIntervalSize, - aggType, - aggField, - groupBy, - termSize, - termField, - threshold, - timeWindowSize, - } = alert.alertTypeParams; - const validationResult = { errors: {} }; - const errors = { - aggField: new Array(), - termSize: new Array(), - termField: new Array(), - timeWindowSize: new Array(), - threshold0: new Array(), - threshold1: new Array(), - index: new Array(), - timeField: new Array(), - triggerIntervalSize: new Array(), - }; - validationResult.errors = errors; - if (!index) { - errors.index.push( - i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredIndexText', { - defaultMessage: 'Index is required.', - }) - ); - } - if (!timeField) { - errors.timeField.push( - i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredTimeFieldText', { - defaultMessage: 'Time field is required.', - }) - ); - } - if (!triggerIntervalSize) { - errors.triggerIntervalSize.push( - i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredTriggerIntervalSizeText', { - defaultMessage: 'Trigger interval size is required.', - }) - ); - } - if (aggType && aggregationTypes[aggType].fieldRequired && !aggField) { - errors.aggField.push( - i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredAggFieldText', { - defaultMessage: 'Aggregation field is required.', - }) - ); - } - if (!termSize) { - errors.termSize.push( - i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredTermSizedText', { - defaultMessage: 'Term size is required.', - }) - ); - } - if (groupBy && groupByTypes[groupBy].sizeRequired && !termField) { - errors.termField.push( - i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredtTermFieldText', { - defaultMessage: 'Term field is required.', - }) - ); - } - if (!timeWindowSize) { - errors.timeWindowSize.push( - i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredTimeWindowSizeText', { - defaultMessage: 'Time window size is required.', - }) - ); - } - if (threshold && threshold.length > 0 && !threshold[0]) { - errors.threshold0.push( - i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredThreshold0Text', { - defaultMessage: 'Threshold0, is required.', - }) - ); - } - if (threshold && threshold.length > 1 && !threshold[1]) { - errors.threshold1.push( - i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredThreshold1Text', { - defaultMessage: 'Threshold1 is required.', - }) - ); - } - return validationResult; -} - export const IndexThresholdAlertTypeExpression: React.FunctionComponent = ({ alert, setAlertTypeParams, @@ -449,7 +449,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = isLoading={isIndiciesLoading} noSuggestions={!indexOptions.length} options={indexOptions} - data-test-subj="indicesComboBox" + data-test-subj="thresholdIndexesComboBox" selectedOptions={(index || []).map((anIndex: string) => { return { label: anIndex, From 2281c23ff393eae7a69cd3e28dde6127c5bde758 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 25 Nov 2019 11:10:43 -0800 Subject: [PATCH 130/297] Rename alerting UI plugin to triggers and actions UI (or something else) #50305 --- x-pack/.i18nrc.json | 2 +- x-pack/index.js | 4 +- .../plugins/alerting_ui/public/index.html | 3 - .../index.ts | 12 +- .../np_ready/kibana.json | 2 +- .../application/action_type_registry.ts | 2 +- .../public/application/alert_type_registry.ts | 15 +- .../np_ready/public/application/app.tsx | 8 +- .../components/page_error/form_errors.tsx | 0 .../components/page_error/index.ts | 0 .../components/page_error/page_error.tsx | 0 .../page_error/page_error_forbidden.tsx | 2 +- .../page_error/page_error_not_exist.tsx | 4 +- .../components/page_error/section_error.tsx | 0 .../application/constants/action_groups.ts | 0 .../constants/aggregation_types.ts | 0 .../application/constants/comparators.ts | 0 .../constants/expression_fields.ts | 0 .../public/application/constants/index.ts | 2 +- .../application/constants/time_units.ts | 0 .../application/context/actions_context.tsx | 0 .../application/context/alerts_context.tsx | 0 .../np_ready/public/application/home.tsx | 16 +- .../np_ready/public/application/index.tsx | 0 .../np_ready/public/application/lib/api.ts | 0 .../public/application/lib/breadcrumb.ts | 8 +- .../public/application/lib/doc_title.ts | 6 +- .../application/lib/get_time_options.ts | 0 .../application/lib/get_time_unit_label.ts | 8 +- .../sections/action_add/action_add_flyout.tsx | 2 +- .../sections/action_add/action_add_form.tsx | 18 +-- .../sections/action_add/action_reducer.ts | 0 .../sections/action_add/action_type_menu.tsx | 2 +- .../action_add/buildin_action_types/email.tsx | 38 ++--- .../buildin_action_types/es_index.tsx | 22 ++- .../action_add/buildin_action_types/index.ts | 0 .../buildin_action_types/pagerduty.tsx | 26 +-- .../buildin_action_types/server_log.tsx | 6 +- .../action_add/buildin_action_types/slack.tsx | 8 +- .../buildin_action_types/webhook.tsx | 41 ++--- .../application/sections/action_add/index.ts | 0 .../actions_list/components/actions_list.tsx | 35 ++-- .../sections/alert_add/alert_add.tsx | 61 +++---- .../sections/alert_add/alert_reducer.ts | 0 .../sections/alert_add/alert_types/index.ts | 0 .../alert_types/threshold/expression.tsx | 151 +++++++++++------- .../alert_types/threshold/visualization.tsx | 8 +- .../sections/alert_add/alert_types/types.ts | 0 .../application/sections/alert_add/index.ts | 0 .../alerts_list/components/alerts_list.tsx | 60 +++---- .../components/collapsed_item_actions.tsx | 10 +- .../np_ready/public/index.ts | 0 .../np_ready/public/legacy.ts | 0 .../np_ready/public/plugin.ts | 6 +- .../np_ready/public/types.ts | 0 .../public/hacks/register.ts | 12 +- .../triggers_actions_ui/public/index.html | 3 + .../public/index.ts | 0 .../public/shim.ts | 0 59 files changed, 337 insertions(+), 266 deletions(-) delete mode 100644 x-pack/legacy/plugins/alerting_ui/public/index.html rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/index.ts (72%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/kibana.json (67%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/action_type_registry.ts (93%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/alert_type_registry.ts (78%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/app.tsx (87%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/components/page_error/form_errors.tsx (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/components/page_error/index.ts (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/components/page_error/page_error.tsx (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/components/page_error/page_error_forbidden.tsx (91%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/components/page_error/page_error_not_exist.tsx (86%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/components/page_error/section_error.tsx (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/constants/action_groups.ts (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/constants/aggregation_types.ts (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/constants/comparators.ts (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/constants/expression_fields.ts (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/constants/index.ts (93%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/constants/time_units.ts (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/context/actions_context.tsx (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/context/alerts_context.tsx (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/home.tsx (85%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/index.tsx (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/lib/api.ts (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/lib/breadcrumb.ts (85%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/lib/doc_title.ts (76%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/lib/get_time_options.ts (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/lib/get_time_unit_label.ts (76%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/action_add/action_add_flyout.tsx (96%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/action_add/action_add_form.tsx (89%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/action_add/action_reducer.ts (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/action_add/action_type_menu.tsx (96%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx (87%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx (84%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/action_add/buildin_action_types/index.ts (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx (88%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx (90%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx (90%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx (87%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/action_add/index.ts (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/actions_list/components/actions_list.tsx (84%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/alert_add/alert_add.tsx (90%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/alert_add/alert_reducer.ts (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/alert_add/alert_types/index.ts (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx (87%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx (95%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/alert_add/alert_types/types.ts (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/alert_add/index.ts (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx (81%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx (89%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/index.ts (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/legacy.ts (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/plugin.ts (97%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/np_ready/public/types.ts (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/public/hacks/register.ts (65%) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/public/index.html rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/public/index.ts (100%) rename x-pack/legacy/plugins/{alerting_ui => triggers_actions_ui}/public/shim.ts (100%) diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index 40764d9633d59b..6eea8932edded0 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -4,7 +4,7 @@ "xpack.actions": "legacy/plugins/actions", "xpack.advancedUiActions": "plugins/advanced_ui_actions", "xpack.alerting": "legacy/plugins/alerting", - "xpack.alertingUI": "legacy/plugins/alerting_ui", + "xpack.alertingUI": "legacy/plugins/triggers_actions_ui", "xpack.apm": "legacy/plugins/apm", "xpack.beatsManagement": "legacy/plugins/beats_management", "xpack.canvas": "legacy/plugins/canvas", diff --git a/x-pack/index.js b/x-pack/index.js index d74f200e0d4957..10eae9df93e554 100644 --- a/x-pack/index.js +++ b/x-pack/index.js @@ -43,7 +43,7 @@ import { transform } from './legacy/plugins/transform'; import { actions } from './legacy/plugins/actions'; import { alerting } from './legacy/plugins/alerting'; import { lens } from './legacy/plugins/lens'; -import { alertingUI } from './legacy/plugins/alerting_ui'; +import { triggersActionsUI } from './legacy/plugins/triggers_actions_ui'; module.exports = function (kibana) { return [ @@ -86,6 +86,6 @@ module.exports = function (kibana) { snapshotRestore(kibana), actions(kibana), alerting(kibana), - alertingUI(kibana), + triggersActionsUI(kibana), ]; }; diff --git a/x-pack/legacy/plugins/alerting_ui/public/index.html b/x-pack/legacy/plugins/alerting_ui/public/index.html deleted file mode 100644 index 1fa034c65347b4..00000000000000 --- a/x-pack/legacy/plugins/alerting_ui/public/index.html +++ /dev/null @@ -1,3 +0,0 @@ - -
-
diff --git a/x-pack/legacy/plugins/alerting_ui/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/index.ts similarity index 72% rename from x-pack/legacy/plugins/alerting_ui/index.ts rename to x-pack/legacy/plugins/triggers_actions_ui/index.ts index 59a57fde4a9786..ab2bdbead115b9 100644 --- a/x-pack/legacy/plugins/alerting_ui/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/index.ts @@ -8,15 +8,15 @@ import { Legacy } from 'kibana'; import { Root } from 'joi'; import { resolve } from 'path'; -export function alertingUI(kibana: any) { +export function triggersActionsUI(kibana: any) { return new kibana.Plugin({ - id: 'alerting_ui', - configPrefix: 'xpack.alerting_ui', + id: 'triggers_actions_ui', + configPrefix: 'xpack.triggers_actions_ui', publicDir: resolve(__dirname, 'public'), require: ['kibana', 'actions'], isEnabled(config: Legacy.KibanaConfig) { return ( - config.get('xpack.alerting_ui.enabled') && + config.get('xpack.triggers_actions_ui.enabled') && (config.get('xpack.actions.enabled') || config.get('xpack.alerting.enabled')) ); }, @@ -28,8 +28,8 @@ export function alertingUI(kibana: any) { .default(); }, uiExports: { - hacks: ['plugins/alerting_ui/hacks/register'], - managementSections: ['plugins/alerting_ui'], + hacks: ['plugins/triggers_actions_ui/hacks/register'], + managementSections: ['plugins/triggers_actions_ui'], }, }); } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/kibana.json b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/kibana.json similarity index 67% rename from x-pack/legacy/plugins/alerting_ui/np_ready/kibana.json rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/kibana.json index e2a710ac343834..3fd7389aef494e 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/kibana.json +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/kibana.json @@ -1,5 +1,5 @@ { - "id": "alerting_ui", + "id": "triggers_actions_ui", "version": "kibana", "server": false, "ui": true diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/action_type_registry.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.ts similarity index 93% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/action_type_registry.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.ts index 2c10ea156e1929..c9c8b30c60a49f 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/action_type_registry.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.ts @@ -24,7 +24,7 @@ export class ActionTypeRegistry { if (this.has(actionType.id)) { throw new Error( i18n.translate( - 'xpack.alertingUI.actionTypeRegistry.register.duplicateActionTypeErrorMessage', + 'xpack.triggersActionsUI.actionTypeRegistry.register.duplicateActionTypeErrorMessage', { defaultMessage: 'Action type "{id}" is already registered.', values: { diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/alert_type_registry.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.ts similarity index 78% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/alert_type_registry.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.ts index 6098001d184202..62d0ab02de34e9 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/alert_type_registry.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.ts @@ -17,12 +17,15 @@ export class AlertTypeRegistry { public register(alertType: AlertTypeModel) { if (this.has(alertType.id)) { throw new Error( - i18n.translate('xpack.alertingUI.alertTypeRegistry.register.duplicateAlertTypeError', { - defaultMessage: 'Alert type "{id}" is already registered.', - values: { - id: alertType.id, - }, - }) + i18n.translate( + 'xpack.triggersActionsUI.alertTypeRegistry.register.duplicateAlertTypeError', + { + defaultMessage: 'Alert type "{id}" is already registered.', + values: { + id: alertType.id, + }, + } + ) ); } this.alertTypes.set(alertType.id, alertType); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx similarity index 87% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx index 35115c21441a4d..299455a2837bc7 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/app.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx @@ -7,7 +7,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { Switch, Route, Redirect } from 'react-router-dom'; import { BASE_PATH, Section, DEFAULT_SECTION } from './constants'; -import { AlertsUIHome } from './home'; +import { TriggersActionsUIHome } from './home'; class ShareRouter extends Component { static contextTypes = { @@ -41,7 +41,11 @@ export const App = () => { export const AppWithoutRouter = ({ sectionsRegex }: any) => ( - + ); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/form_errors.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/form_errors.tsx similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/form_errors.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/form_errors.tsx diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/index.ts similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/index.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/index.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/page_error.tsx similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/page_error.tsx diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx similarity index 91% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx index b046c7e7c1f3f8..bffce8746f5b60 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx @@ -17,7 +17,7 @@ export function PageErrorForbidden() { title={

diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx similarity index 86% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx index 21c5abc3ad1a44..0cd5759aff141c 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx @@ -17,7 +17,7 @@ export function PageErrorNotExist({ id }: { id: any }) { title={

@@ -25,7 +25,7 @@ export function PageErrorNotExist({ id }: { id: any }) { body={

diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/section_error.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/section_error.tsx similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/components/page_error/section_error.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/section_error.tsx diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_groups.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/action_groups.ts similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/action_groups.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/action_groups.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/aggregation_types.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/aggregation_types.ts similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/aggregation_types.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/aggregation_types.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/comparators.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/comparators.ts similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/comparators.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/comparators.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/expression_fields.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/expression_fields.ts similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/expression_fields.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/expression_fields.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/index.ts similarity index 93% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/index.ts index 781ce5e1ed0821..c337c847ef1f50 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/index.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -export const BASE_PATH = '/management/kibana/alerting'; +export const BASE_PATH = '/management/kibana/triggersActions'; export const BASE_ACTION_API_PATH = '/api/action'; export const BASE_ALERT_API_PATH = '/api/alert'; diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/time_units.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/time_units.ts similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/constants/time_units.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/time_units.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/actions_context.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_context.tsx similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/actions_context.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_context.tsx diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/alerts_context.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/alerts_context.tsx similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/context/alerts_context.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/alerts_context.tsx diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx similarity index 85% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx index d99f4eec914d62..36dbc3179fb291 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/home.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx @@ -30,7 +30,7 @@ interface MatchParams { section: Section; } -export const AlertsUIHome: React.FunctionComponent> = ({ +export const TriggersActionsUIHome: React.FunctionComponent> = ({ match: { params: { section }, }, @@ -50,7 +50,12 @@ export const AlertsUIHome: React.FunctionComponent, + name: ( + + ), }); } @@ -59,7 +64,7 @@ export const AlertsUIHome: React.FunctionComponent ), @@ -83,7 +88,10 @@ export const AlertsUIHome: React.FunctionComponent

- +

diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/index.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/index.tsx similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/index.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/index.tsx diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/api.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.ts similarity index 85% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.ts index 90751d75bce332..564c602d9ae68d 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/breadcrumb.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.ts @@ -28,8 +28,8 @@ class BreadcrumbService { this.breadcrumbs.home = [ ...this.breadcrumbs.management, { - text: i18n.translate('xpack.alertingUI.home.breadcrumbTitle', { - defaultMessage: 'Alerting', + text: i18n.translate('xpack.triggersActionsUI.home.breadcrumbTitle', { + defaultMessage: 'Triggers and Actions', }), href: `#${routeToHome}`, }, @@ -37,7 +37,7 @@ class BreadcrumbService { this.breadcrumbs.connectors = [ ...this.breadcrumbs.home, { - text: i18n.translate('xpack.alertingUI.connectors.breadcrumbTitle', { + text: i18n.translate('xpack.triggersActionsUI.connectors.breadcrumbTitle', { defaultMessage: 'Connectors', }), href: `#${routeToConnectors}`, @@ -46,7 +46,7 @@ class BreadcrumbService { this.breadcrumbs.alerts = [ ...this.breadcrumbs.home, { - text: i18n.translate('xpack.alertingUI.alerts.breadcrumbTitle', { + text: i18n.translate('xpack.triggersActionsUI.alerts.breadcrumbTitle', { defaultMessage: 'Alerts', }), href: `#${routeToAlerts}`, diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/doc_title.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.ts similarity index 76% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/doc_title.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.ts index b2b2ab5e6a4cf4..e0778db099f793 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/doc_title.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.ts @@ -17,17 +17,17 @@ class DocTitleService { switch (page) { case 'actions': - updatedTitle = i18n.translate('xpack.alertingUI.actions.breadcrumbTitle', { + updatedTitle = i18n.translate('xpack.triggersActionsUI.actions.breadcrumbTitle', { defaultMessage: 'Actions', }); break; case 'alerts': - updatedTitle = i18n.translate('xpack.alertingUI.alerts.breadcrumbTitle', { + updatedTitle = i18n.translate('xpack.triggersActionsUI.alerts.breadcrumbTitle', { defaultMessage: 'Alerts', }); break; default: - updatedTitle = i18n.translate('xpack.alertingUI.home.breadcrumbTitle', { + updatedTitle = i18n.translate('xpack.triggersActionsUI.home.breadcrumbTitle', { defaultMessage: 'Alerting', }); } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/get_time_options.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/get_time_options.ts similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/get_time_options.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/get_time_options.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/get_time_unit_label.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/get_time_unit_label.ts similarity index 76% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/get_time_unit_label.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/get_time_unit_label.ts index 3cf91a3b55cdbc..a6218554153287 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/lib/get_time_unit_label.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/get_time_unit_label.ts @@ -10,22 +10,22 @@ import { TIME_UNITS } from '../constants'; export function getTimeUnitLabel(timeUnit = TIME_UNITS.SECOND, timeValue = '0') { switch (timeUnit) { case TIME_UNITS.SECOND: - return i18n.translate('xpack.alertingUI.timeUnits.secondLabel', { + return i18n.translate('xpack.triggersActionsUI.timeUnits.secondLabel', { defaultMessage: '{timeValue, plural, one {second} other {seconds}}', values: { timeValue }, }); case TIME_UNITS.MINUTE: - return i18n.translate('xpack.alertingUI.timeUnits.minuteLabel', { + return i18n.translate('xpack.triggersActionsUI.timeUnits.minuteLabel', { defaultMessage: '{timeValue, plural, one {minute} other {minutes}}', values: { timeValue }, }); case TIME_UNITS.HOUR: - return i18n.translate('xpack.alertingUI.timeUnits.hourLabel', { + return i18n.translate('xpack.triggersActionsUI.timeUnits.hourLabel', { defaultMessage: '{timeValue, plural, one {hour} other {hours}}', values: { timeValue }, }); case TIME_UNITS.DAY: - return i18n.translate('xpack.alertingUI.timeUnits.dayLabel', { + return i18n.translate('xpack.triggersActionsUI.timeUnits.dayLabel', { defaultMessage: '{timeValue, plural, one {day} other {days}}', values: { timeValue }, }); diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/action_add_flyout.tsx similarity index 96% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_flyout.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/action_add_flyout.tsx index 5d22a15f82c023..f0d4bd3171be97 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/action_add_flyout.tsx @@ -56,7 +56,7 @@ export const ActionAddFlyout = () => {

diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/action_add_form.tsx similarity index 89% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/action_add_form.tsx index 3ec4bb75849099..4677dd6f8d08e0 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_add_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/action_add_form.tsx @@ -77,7 +77,7 @@ export const ActionAddForm = ({ actionType }: Props) => { validationResult.errors = errors; if (!actionObject.description) { errors.description.push( - i18n.translate('xpack.alertingUI.sections.actionAdd.error.requiredNameText', { + i18n.translate('xpack.triggersActionsUI.sections.actionAdd.error.requiredNameText', { defaultMessage: 'Description is required.', }) ); @@ -98,7 +98,7 @@ export const ActionAddForm = ({ actionType }: Props) => { try { const newAction = await saveAction({ http, action }); toastNotifications.addSuccess( - i18n.translate('xpack.alertingUI.sections.actionAdd.saveSuccessNotificationText', { + i18n.translate('xpack.triggersActionsUI.sections.actionAdd.saveSuccessNotificationText', { defaultMessage: "Saved '{actionName}'", values: { actionName: newAction.description, @@ -122,7 +122,7 @@ export const ActionAddForm = ({ actionType }: Props) => { } @@ -136,7 +136,7 @@ export const ActionAddForm = ({ actionType }: Props) => { fullWidth label={ } @@ -172,7 +172,7 @@ export const ActionAddForm = ({ actionType }: Props) => { {

@@ -211,7 +211,7 @@ export const ActionAddForm = ({ actionType }: Props) => { setFlyoutVisibility(false)}> - {i18n.translate('xpack.alertingUI.sections.actionAdd.cancelButtonLabel', { + {i18n.translate('xpack.triggersActionsUI.sections.actionAdd.cancelButtonLabel', { defaultMessage: 'Cancel', })} @@ -237,7 +237,7 @@ export const ActionAddForm = ({ actionType }: Props) => { }} > diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_reducer.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/action_reducer.ts similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_reducer.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/action_reducer.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_type_menu.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/action_type_menu.tsx similarity index 96% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_type_menu.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/action_type_menu.tsx index d9cc4a778f61af..0d7c1e53d8e6ed 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/action_type_menu.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/action_type_menu.tsx @@ -64,7 +64,7 @@ export const ActionTypeMenu = ({ setActionType }: Props) => { setFlyoutVisibility(false)}> - {i18n.translate('xpack.alertingUI.sections.actionAdd.cancelButtonLabel', { + {i18n.translate('xpack.triggersActionsUI.sections.actionAdd.cancelButtonLabel', { defaultMessage: 'Cancel', })} diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx similarity index 87% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx index 15087621b1d7cc..a57136eb41d4bd 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx @@ -28,7 +28,7 @@ export function getActionType(): ActionTypeModel { id: '.email', iconClass: 'email', selectMessage: i18n.translate( - 'xpack.alertingUI.sections.actionAdd.emailAction.selectMessageText', + 'xpack.triggersActionsUI.sections.actionAdd.emailAction.selectMessageText', { defaultMessage: 'Send an email.', } @@ -45,35 +45,35 @@ export function getActionType(): ActionTypeModel { validationResult.errors = errors; if (!action.config.from) { errors.from.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredFromText', { + i18n.translate('xpack.triggersActionsUI.sections.addAction.error.requiredFromText', { defaultMessage: 'From is required.', }) ); } if (!action.config.port) { errors.port.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredPortText', { + i18n.translate('xpack.triggersActionsUI.sections.addAction.error.requiredPortText', { defaultMessage: 'Port is required.', }) ); } if (!action.config.host) { errors.host.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredHostText', { + i18n.translate('xpack.triggersActionsUI.sections.addAction.error.requiredHostText', { defaultMessage: 'Host is required.', }) ); } if (!action.secrets.user) { errors.user.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredUserText', { + i18n.translate('xpack.triggersActionsUI.sections.addAction.error.requiredUserText', { defaultMessage: 'User is required.', }) ); } if (!action.secrets.password) { errors.password.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredPasswordText', { + i18n.translate('xpack.triggersActionsUI.sections.addAction.error.requiredPasswordText', { defaultMessage: 'Password is required.', }) ); @@ -97,7 +97,7 @@ export function getActionType(): ActionTypeModel { actionParams.bcc.length === 0 ) { const errorText = i18n.translate( - 'xpack.alertingUI.sections.addAction.error.requiredEntryText', + 'xpack.triggersActionsUI.sections.addAction.error.requiredEntryText', { defaultMessage: 'No [to], [cc], or [bcc] entries. At least one entry is required.', } @@ -108,14 +108,14 @@ export function getActionType(): ActionTypeModel { } if (!actionParams.message) { errors.message.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredMessageText', { + i18n.translate('xpack.triggersActionsUI.sections.addAction.error.requiredMessageText', { defaultMessage: 'Message is required.', }) ); } if (!actionParams.subject) { errors.subject.push( - i18n.translate('xpack.alertingUI.sections.addAction.error.requiredSubjectText', { + i18n.translate('xpack.triggersActionsUI.sections.addAction.error.requiredSubjectText', { defaultMessage: 'Subject is required.', }) ); @@ -146,7 +146,7 @@ const EmailActionFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors && from !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.emailAction.fromTextFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.emailAction.fromTextFieldLabel', { defaultMessage: 'From', } @@ -176,7 +176,7 @@ const EmailActionFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors && host !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.emailAction.hostTextFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.emailAction.hostTextFieldLabel', { defaultMessage: 'Host', } @@ -206,7 +206,7 @@ const EmailActionFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors && port !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.emailAction.portTextFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.emailAction.portTextFieldLabel', { defaultMessage: 'Port', } @@ -239,7 +239,7 @@ const EmailActionFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors && user !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.emailAction.userTextFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.emailAction.userTextFieldLabel', { defaultMessage: 'User', } @@ -269,7 +269,7 @@ const EmailActionFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors && password !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.emailAction.passwordFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.emailAction.passwordFieldLabel', { defaultMessage: 'Password', } @@ -316,7 +316,7 @@ const EmailParamsFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors && to !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.emailAction.recipientTextFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.emailAction.recipientTextFieldLabel', { defaultMessage: 'To', } @@ -355,7 +355,7 @@ const EmailParamsFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors && cc !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.emailAction.recipientCopyTextFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.emailAction.recipientCopyTextFieldLabel', { defaultMessage: 'Cc', } @@ -394,7 +394,7 @@ const EmailParamsFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors && bcc !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.emailAction.recipientBccTextFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.emailAction.recipientBccTextFieldLabel', { defaultMessage: 'Bcc', } @@ -433,7 +433,7 @@ const EmailParamsFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors && message !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.emailAction.subjectTextFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.emailAction.subjectTextFieldLabel', { defaultMessage: 'Subject', } @@ -455,7 +455,7 @@ const EmailParamsFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors && message !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.emailAction.messageTextAreaFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.emailAction.messageTextAreaFieldLabel', { defaultMessage: 'Message', } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx similarity index 84% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx index 0ca67ed133b618..1662ad1cab1cc9 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx @@ -15,7 +15,7 @@ export function getActionType(): ActionTypeModel { id: '.index', iconClass: 'indexOpen', selectMessage: i18n.translate( - 'xpack.alertingUI.sections.actionAdd.indexAction.selectMessageText', + 'xpack.triggersActionsUI.sections.actionAdd.indexAction.selectMessageText', { defaultMessage: 'Index data into Elasticsearch.', } @@ -37,9 +37,12 @@ const IndexActionFields: React.FunctionComponent = ({ action, editActionC return ( = ({ fullWidth errors={errors} isShowingErrors={hasErrors === true && action.index !== undefined} - label={i18n.translate('xpack.alertingUI.sections.actionAdd.indexAction.indexFieldLabel', { - defaultMessage: 'Index', - })} + label={i18n.translate( + 'xpack.triggersActionsUI.sections.actionAdd.indexAction.indexFieldLabel', + { + defaultMessage: 'Index', + } + )} > = ({ }} label={ } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/index.ts similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/index.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/index.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx similarity index 88% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx index d58dc532fef0a5..4a5bb0de35e0dc 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx @@ -20,7 +20,7 @@ export function getActionType(): ActionTypeModel { id: '.pagerduty', iconClass: 'apps', selectMessage: i18n.translate( - 'xpack.alertingUI.sections.actionAdd.pagerDutyAction.selectMessageText', + 'xpack.triggersActionsUI.sections.actionAdd.pagerDutyAction.selectMessageText', { defaultMessage: 'Create an event in PagerDuty.', } @@ -35,7 +35,7 @@ export function getActionType(): ActionTypeModel { if (!action.secrets.routingKey) { errors.routingKey.push( i18n.translate( - 'xpack.alertingUI.sections.actionAdd.pagerDutyAction.error.requiredRoutingKeyText', + 'xpack.triggersActionsUI.sections.actionAdd.pagerDutyAction.error.requiredRoutingKeyText', { defaultMessage: 'Routing Key is required.', } @@ -45,7 +45,7 @@ export function getActionType(): ActionTypeModel { if (!action.config.apiUrl) { errors.apiUrl.push( i18n.translate( - 'xpack.alertingUI.sections.actionAdd.pagerDutyAction.error.requiredApiUrlText', + 'xpack.triggersActionsUI.sections.actionAdd.pagerDutyAction.error.requiredApiUrlText', { defaultMessage: 'ApiUrl is required.', } @@ -81,7 +81,7 @@ const PagerDutyActionFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors === true && apiUrl !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.pagerDutyAction.apiUrlTextFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.pagerDutyAction.apiUrlTextFieldLabel', { defaultMessage: 'ApiUrl', } @@ -109,7 +109,7 @@ const PagerDutyActionFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors === true && routingKey !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.pagerDutyAction.routingKeyTextFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.pagerDutyAction.routingKeyTextFieldLabel', { defaultMessage: 'RoutingKey', } @@ -160,7 +160,7 @@ const PagerDutyParamsFields: React.FunctionComponent = ({ = ({ = ({ = ({ = ({ = ({ = ({ = ({ errors={errors} isShowingErrors={hasErrors === true && summary !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.pagerDutyAction.summaryFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.pagerDutyAction.summaryFieldLabel', { defaultMessage: 'Summary', } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx similarity index 90% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx index f53569cc0a8d23..241c49e6de4155 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx @@ -14,7 +14,7 @@ export function getActionType(): ActionTypeModel { id: '.server-log', iconClass: 'logsApp', selectMessage: i18n.translate( - 'xpack.alertingUI.sections.actionAdd.serverLogAction.selectMessageText', + 'xpack.triggersActionsUI.sections.actionAdd.serverLogAction.selectMessageText', { defaultMessage: 'Add an item to the logs.', } @@ -57,7 +57,7 @@ export const ServerLogParamsFields: React.FunctionComponent = errors={errors} isShowingErrors={hasErrors && level !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.serverLogAction.logLevelFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.serverLogAction.logLevelFieldLabel', { defaultMessage: 'Level', } @@ -81,7 +81,7 @@ export const ServerLogParamsFields: React.FunctionComponent = errors={errors} isShowingErrors={hasErrors && message !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.serverLogAction.logMessageFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.serverLogAction.logMessageFieldLabel', { defaultMessage: 'Message', } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx similarity index 90% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx index 38285f8da7a9b7..12c79735d1c8da 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx @@ -21,7 +21,7 @@ export function getActionType(): ActionTypeModel { id: '.slack', iconClass: 'logoSlack', selectMessage: i18n.translate( - 'xpack.alertingUI.sections.actionAdd.slackAction.selectMessageText', + 'xpack.triggersActionsUI.sections.actionAdd.slackAction.selectMessageText', { defaultMessage: 'Send a message to a Slack user or channel.', } @@ -35,7 +35,7 @@ export function getActionType(): ActionTypeModel { if (!action.secrets.webhookUrl) { errors.webhookUrl.push( i18n.translate( - 'xpack.alertingUI.sections.actionAdd.slackAction.error.requiredWebhookUrlText', + 'xpack.triggersActionsUI.sections.actionAdd.slackAction.error.requiredWebhookUrlText', { defaultMessage: 'WebhookUrl is required.', } @@ -70,7 +70,7 @@ const SlackActionFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors === true && webhookUrl !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.slackAction.webhookUrlTextFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.slackAction.webhookUrlTextFieldLabel', { defaultMessage: 'WebhookUrl', } @@ -122,7 +122,7 @@ const SlackParamsFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors && message !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.slackAction.messageTextAreaFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.slackAction.messageTextAreaFieldLabel', { defaultMessage: 'Message', } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx similarity index 87% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx index 56a27fd526af2e..cae6c6c3a203e3 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx @@ -37,7 +37,7 @@ export function getActionType(): ActionTypeModel { id: '.webhook', iconClass: 'logoWebhook', selectMessage: i18n.translate( - 'xpack.alertingUI.sections.actionAdd.webhookAction.selectMessageText', + 'xpack.triggersActionsUI.sections.actionAdd.webhookAction.selectMessageText', { defaultMessage: 'Send a request to a web service.', } @@ -54,7 +54,7 @@ export function getActionType(): ActionTypeModel { if (!action.config.url) { errors.url.push( i18n.translate( - 'xpack.alertingUI.sections.actionAdd.webhookAction.error.requiredUrlText', + 'xpack.triggersActionsUI.sections.actionAdd.webhookAction.error.requiredUrlText', { defaultMessage: 'Url is required.', } @@ -64,7 +64,7 @@ export function getActionType(): ActionTypeModel { if (!action.config.method) { errors.method.push( i18n.translate( - 'xpack.alertingUI.sections.addAction.webhookAction.error.requiredMethodText', + 'xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredMethodText', { defaultMessage: 'Method is required.', } @@ -74,7 +74,7 @@ export function getActionType(): ActionTypeModel { if (!action.secrets.user) { errors.user.push( i18n.translate( - 'xpack.alertingUI.sections.addAction.webhookAction.error.requiredHostText', + 'xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredHostText', { defaultMessage: 'User is required.', } @@ -84,7 +84,7 @@ export function getActionType(): ActionTypeModel { if (!action.secrets.password) { errors.password.push( i18n.translate( - 'xpack.alertingUI.sections.addAction.webhookAction.error.requiredPasswordText', + 'xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredPasswordText', { defaultMessage: 'Password is required.', } @@ -125,7 +125,7 @@ const WebhookActionFields: React.FunctionComponent = ({ if (!headerKey && headerValue) { headerErrors.keyHeader.push( i18n.translate( - 'xpack.alertingUI.sections.addAction.webhookAction.error.requiredHeaderKeyText', + 'xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredHeaderKeyText', { defaultMessage: 'Header Key is required.', } @@ -135,7 +135,7 @@ const WebhookActionFields: React.FunctionComponent = ({ if (headerKey && !headerValue) { headerErrors.valueHeader.push( i18n.translate( - 'xpack.alertingUI.sections.addAction.webhookAction.error.requiredHeaderValueText', + 'xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredHeaderValueText', { defaultMessage: 'Header Value is required.', } @@ -182,7 +182,7 @@ const WebhookActionFields: React.FunctionComponent = ({ errors={headerErrors} isShowingErrors={hasHeaderErrors && headerKey !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.webhookAction.keyTextFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.webhookAction.keyTextFieldLabel', { defaultMessage: 'Header Key', } @@ -207,7 +207,7 @@ const WebhookActionFields: React.FunctionComponent = ({ errors={headerErrors} isShowingErrors={hasHeaderErrors && headerValue !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.webhookAction.valueTextFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.webhookAction.valueTextFieldLabel', { defaultMessage: 'Header Value', } @@ -234,7 +234,7 @@ const WebhookActionFields: React.FunctionComponent = ({ = ({ errors={errors} isShowingErrors={hasErrors === true && url !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.webhookAction.urlTextFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.webhookAction.urlTextFieldLabel', { defaultMessage: 'Url', } @@ -291,7 +291,7 @@ const WebhookActionFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors === true && user !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.webhookAction.userTextFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.webhookAction.userTextFieldLabel', { defaultMessage: 'User', } @@ -321,7 +321,7 @@ const WebhookActionFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors === true && password !== undefined} label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.webhookAction.passwordTextFieldLabel', + 'xpack.triggersActionsUI.sections.actionAdd.webhookAction.passwordTextFieldLabel', { defaultMessage: 'Password', } @@ -353,7 +353,7 @@ const WebhookActionFields: React.FunctionComponent = ({ > @@ -366,7 +366,7 @@ const WebhookActionFields: React.FunctionComponent = ({

@@ -404,9 +404,12 @@ const WebhookParamsFields: React.FunctionComponent = ({ = ({ theme="github" data-test-subj="webhookBodyEditor" aria-label={i18n.translate( - 'xpack.alertingUI.sections.actionAdd.webhookAction.bodyCodeEditorAriaLabel', + 'xpack.triggersActionsUI.sections.actionAdd.webhookAction.bodyCodeEditorAriaLabel', { defaultMessage: 'Code editor', } diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/index.ts similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/action_add/index.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/index.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx similarity index 84% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 6818b1e198f218..baa03bc2fe6f37 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -35,6 +35,7 @@ export const ActionsList: React.FunctionComponent = () => { useEffect(() => { loadActions(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { @@ -50,7 +51,7 @@ export const ActionsList: React.FunctionComponent = () => { } catch (e) { toastNotifications.addDanger({ title: i18n.translate( - 'xpack.alertingUI.sections.actionsList.unableToLoadActionTypesMessage', + 'xpack.triggersActionsUI.sections.actionsList.unableToLoadActionTypesMessage', { defaultMessage: 'Unable to load action types' } ), }); @@ -58,6 +59,7 @@ export const ActionsList: React.FunctionComponent = () => { setIsLoadingActionTypes(false); } })(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { @@ -92,9 +94,12 @@ export const ActionsList: React.FunctionComponent = () => { setActions(actionsResponse.data); } catch (e) { toastNotifications.addDanger({ - title: i18n.translate('xpack.alertingUI.sections.actionsList.unableToLoadActionsMessage', { - defaultMessage: 'Unable to load actions', - }), + title: i18n.translate( + 'xpack.triggersActionsUI.sections.actionsList.unableToLoadActionsMessage', + { + defaultMessage: 'Unable to load actions', + } + ), }); } finally { setIsLoadingActions(false); @@ -111,7 +116,7 @@ export const ActionsList: React.FunctionComponent = () => { } catch (e) { toastNotifications.addDanger({ title: i18n.translate( - 'xpack.alertingUI.sections.actionsList.failedToDeleteActionsMessage', + 'xpack.triggersActionsUI.sections.actionsList.failedToDeleteActionsMessage', { defaultMessage: 'Failed to delete action(s)' } ), }); @@ -130,7 +135,7 @@ export const ActionsList: React.FunctionComponent = () => { { field: 'actionType', name: i18n.translate( - 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.actionTypeTitle', + 'xpack.triggersActionsUI.sections.actionsList.actionsListTable.columns.actionTypeTitle', { defaultMessage: 'Type', } @@ -141,7 +146,7 @@ export const ActionsList: React.FunctionComponent = () => { { field: 'description', name: i18n.translate( - 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.descriptionTitle', + 'xpack.triggersActionsUI.sections.actionsList.actionsListTable.columns.descriptionTitle', { defaultMessage: 'Name', } @@ -152,7 +157,7 @@ export const ActionsList: React.FunctionComponent = () => { { field: 'referencedByCount', name: i18n.translate( - 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.referencedByCountTitle', + 'xpack.triggersActionsUI.sections.actionsList.actionsListTable.columns.referencedByCountTitle', { defaultMessage: 'Attached actions' } ), sortable: false, @@ -167,16 +172,16 @@ export const ActionsList: React.FunctionComponent = () => { { enabled: () => canDelete, name: i18n.translate( - 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.actions.deleteActionName', + 'xpack.triggersActionsUI.sections.actionsList.actionsListTable.columns.actions.deleteActionName', { defaultMessage: 'Delete' } ), description: canDelete ? i18n.translate( - 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.actions.deleteActionDescription', + 'xpack.triggersActionsUI.sections.actionsList.actionsListTable.columns.actions.deleteActionDescription', { defaultMessage: 'Delete this action' } ) : i18n.translate( - 'xpack.alertingUI.sections.actionsList.actionsListTable.columns.actions.deleteActionDisabledDescription', + 'xpack.triggersActionsUI.sections.actionsList.actionsListTable.columns.actions.deleteActionDisabledDescription', { defaultMessage: 'Unable to delete actions' } ), type: 'icon', @@ -226,7 +231,7 @@ export const ActionsList: React.FunctionComponent = () => { type: 'field_value_selection', field: 'actionTypeId', name: i18n.translate( - 'xpack.alertingUI.sections.actionsList.filters.actionTypeIdName', + 'xpack.triggersActionsUI.sections.actionsList.filters.actionTypeIdName', { defaultMessage: 'Type' } ), multiSelect: 'or', @@ -246,13 +251,13 @@ export const ActionsList: React.FunctionComponent = () => { canDelete ? undefined : i18n.translate( - 'xpack.alertingUI.sections.actionsList.buttons.deleteDisabledTitle', + 'xpack.triggersActionsUI.sections.actionsList.buttons.deleteDisabledTitle', { defaultMessage: 'Unable to delete actions' } ) } > { onClick={() => setFlyoutVisibility(true)} > , diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx similarity index 90% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 1566936722f3b0..34a2a424c18b12 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -65,21 +65,21 @@ function validateBaseProperties(alertObject: Alert) { validationResult.errors = errors; if (!alertObject.name) { errors.name.push( - i18n.translate('xpack.alertingUI.sections.alertAdd.error.requiredNameText', { + i18n.translate('xpack.triggersActionsUI.sections.alertAdd.error.requiredNameText', { defaultMessage: 'Name is required.', }) ); } if (!alertObject.interval) { errors.interval.push( - i18n.translate('xpack.alertingUI.sections.alertAdd.error.requiredIntervalText', { + i18n.translate('xpack.triggersActionsUI.sections.alertAdd.error.requiredIntervalText', { defaultMessage: 'Check interval is required.', }) ); } if (!alertObject.alertTypeId) { errors.alertTypeId.push( - i18n.translate('xpack.alertingUI.sections.alertAdd.error.requiredAlertTypeIdText', { + i18n.translate('xpack.triggersActionsUI.sections.alertAdd.error.requiredAlertTypeIdText', { defaultMessage: 'Alert trigger is required.', }) ); @@ -133,7 +133,7 @@ export const AlertAdd = ({ refreshList }: Props) => { } catch (e) { toastNotifications.addDanger({ title: i18n.translate( - 'xpack.alertingUI.sections.alertAdd.unableToLoadActionTypesMessage', + 'xpack.triggersActionsUI.sections.alertAdd.unableToLoadActionTypesMessage', { defaultMessage: 'Unable to load action types' } ), }); @@ -200,9 +200,12 @@ export const AlertAdd = ({ refreshList }: Props) => { setConnectors(actionsResponse.data); } catch (e) { toastNotifications.addDanger({ - title: i18n.translate('xpack.alertingUI.sections.alertAdd.unableToLoadActionsMessage', { - defaultMessage: 'Unable to load actions', - }), + title: i18n.translate( + 'xpack.triggersActionsUI.sections.alertAdd.unableToLoadActionsMessage', + { + defaultMessage: 'Unable to load actions', + } + ), }); } } @@ -238,19 +241,19 @@ export const AlertAdd = ({ refreshList }: Props) => { const tabs = [ { id: ACTION_GROUPS.ALERT, - name: i18n.translate('xpack.alertingUI.sections.alertAdd.alertTabText', { + name: i18n.translate('xpack.triggersActionsUI.sections.alertAdd.alertTabText', { defaultMessage: 'Alert', }), }, { id: ACTION_GROUPS.WARNING, - name: i18n.translate('xpack.alertingUI.sections.alertAdd.warningTabText', { + name: i18n.translate('xpack.triggersActionsUI.sections.alertAdd.warningTabText', { defaultMessage: 'Warning', }), }, { id: ACTION_GROUPS.UNACKNOWLEDGED, - name: i18n.translate('xpack.alertingUI.sections.alertAdd.unacknowledgedTabText', { + name: i18n.translate('xpack.triggersActionsUI.sections.alertAdd.unacknowledgedTabText', { defaultMessage: 'If unacknowledged', }), disabled: false, @@ -261,7 +264,7 @@ export const AlertAdd = ({ refreshList }: Props) => { try { const newAlert = await saveAlert({ http, alert }); toastNotifications.addSuccess( - i18n.translate('xpack.alertingUI.sections.alertAdd.saveSuccessNotificationText', { + i18n.translate('xpack.triggersActionsUI.sections.alertAdd.saveSuccessNotificationText', { defaultMessage: "Saved '{alertName}'", values: { alertName: newAlert.id, @@ -345,7 +348,7 @@ export const AlertAdd = ({ refreshList }: Props) => {
@@ -360,7 +363,7 @@ export const AlertAdd = ({ refreshList }: Props) => { > @@ -431,7 +434,7 @@ export const AlertAdd = ({ refreshList }: Props) => {
@@ -444,7 +447,7 @@ export const AlertAdd = ({ refreshList }: Props) => { color="danger" className="euiAccordionForm__extraAction" aria-label={i18n.translate( - 'xpack.alertingUI.sections.alertAdd.accordion.deleteIconAriaLabel', + 'xpack.triggersActionsUI.sections.alertAdd.accordion.deleteIconAriaLabel', { defaultMessage: 'Delete', } @@ -462,7 +465,7 @@ export const AlertAdd = ({ refreshList }: Props) => { { onClick={() => setIsAddActionPanelOpen(true)} > @@ -525,7 +528,7 @@ export const AlertAdd = ({ refreshList }: Props) => {
@@ -540,13 +543,13 @@ export const AlertAdd = ({ refreshList }: Props) => { const labelForAlertChecked = ( <> {' '} @@ -556,13 +559,13 @@ export const AlertAdd = ({ refreshList }: Props) => { const labelForAlertRenotify = ( <> {' '} @@ -577,7 +580,7 @@ export const AlertAdd = ({ refreshList }: Props) => {

@@ -589,7 +592,7 @@ export const AlertAdd = ({ refreshList }: Props) => { } @@ -605,7 +608,7 @@ export const AlertAdd = ({ refreshList }: Props) => { id="alertName" label={ } @@ -634,7 +637,7 @@ export const AlertAdd = ({ refreshList }: Props) => { {
@@ -764,7 +767,7 @@ export const AlertAdd = ({ refreshList }: Props) => { - {i18n.translate('xpack.alertingUI.sections.alertAdd.cancelButtonLabel', { + {i18n.translate('xpack.triggersActionsUI.sections.alertAdd.cancelButtonLabel', { defaultMessage: 'Cancel', })} @@ -790,7 +793,7 @@ export const AlertAdd = ({ refreshList }: Props) => { }} > diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/index.ts similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/index.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/index.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx similarity index 87% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx index 1b4a7424dbda3e..7222705ca4037c 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx @@ -87,63 +87,66 @@ const validateAlertType = (alert: Alert): ValidationResult => { validationResult.errors = errors; if (!index) { errors.index.push( - i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredIndexText', { + i18n.translate('xpack.triggersActionsUI.sections.addAlert.error.requiredIndexText', { defaultMessage: 'Index is required.', }) ); } if (!timeField) { errors.timeField.push( - i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredTimeFieldText', { + i18n.translate('xpack.triggersActionsUI.sections.addAlert.error.requiredTimeFieldText', { defaultMessage: 'Time field is required.', }) ); } if (!triggerIntervalSize) { errors.triggerIntervalSize.push( - i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredTriggerIntervalSizeText', { - defaultMessage: 'Trigger interval size is required.', - }) + i18n.translate( + 'xpack.triggersActionsUI.sections.addAlert.error.requiredTriggerIntervalSizeText', + { + defaultMessage: 'Trigger interval size is required.', + } + ) ); } if (aggType && aggregationTypes[aggType].fieldRequired && !aggField) { errors.aggField.push( - i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredAggFieldText', { + i18n.translate('xpack.triggersActionsUI.sections.addAlert.error.requiredAggFieldText', { defaultMessage: 'Aggregation field is required.', }) ); } if (!termSize) { errors.termSize.push( - i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredTermSizedText', { + i18n.translate('xpack.triggersActionsUI.sections.addAlert.error.requiredTermSizedText', { defaultMessage: 'Term size is required.', }) ); } if (groupBy && groupByTypes[groupBy].sizeRequired && !termField) { errors.termField.push( - i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredtTermFieldText', { + i18n.translate('xpack.triggersActionsUI.sections.addAlert.error.requiredtTermFieldText', { defaultMessage: 'Term field is required.', }) ); } if (!timeWindowSize) { errors.timeWindowSize.push( - i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredTimeWindowSizeText', { + i18n.translate('xpack.triggersActionsUI.sections.addAlert.error.requiredTimeWindowSizeText', { defaultMessage: 'Time window size is required.', }) ); } if (threshold && threshold.length > 0 && !threshold[0]) { errors.threshold0.push( - i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredThreshold0Text', { + i18n.translate('xpack.triggersActionsUI.sections.addAlert.error.requiredThreshold0Text', { defaultMessage: 'Threshold0, is required.', }) ); } if (threshold && threshold.length > 1 && !threshold[1]) { errors.threshold1.push( - i18n.translate('xpack.alertingUI.sections.addAlert.error.requiredThreshold1Text', { + i18n.translate('xpack.triggersActionsUI.sections.addAlert.error.requiredThreshold1Text', { defaultMessage: 'Threshold1 is required.', }) ); @@ -196,15 +199,18 @@ export const aggregationTypes: { [key: string]: AggregationType } = { export const comparators: { [key: string]: Comparator } = { [COMPARATORS.GREATER_THAN]: { - text: i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.comparators.isAboveLabel', { - defaultMessage: 'Is above', - }), + text: i18n.translate( + 'xpack.triggersActionsUI.sections.alertAdd.threshold.comparators.isAboveLabel', + { + defaultMessage: 'Is above', + } + ), value: COMPARATORS.GREATER_THAN, requiredValues: 1, }, [COMPARATORS.GREATER_THAN_OR_EQUALS]: { text: i18n.translate( - 'xpack.alertingUI.sections.alertAdd.threshold.comparators.isAboveOrEqualsLabel', + 'xpack.triggersActionsUI.sections.alertAdd.threshold.comparators.isAboveOrEqualsLabel', { defaultMessage: 'Is above or equals', } @@ -213,15 +219,18 @@ export const comparators: { [key: string]: Comparator } = { requiredValues: 1, }, [COMPARATORS.LESS_THAN]: { - text: i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.comparators.isBelowLabel', { - defaultMessage: 'Is below', - }), + text: i18n.translate( + 'xpack.triggersActionsUI.sections.alertAdd.threshold.comparators.isBelowLabel', + { + defaultMessage: 'Is below', + } + ), value: COMPARATORS.LESS_THAN, requiredValues: 1, }, [COMPARATORS.LESS_THAN_OR_EQUALS]: { text: i18n.translate( - 'xpack.alertingUI.sections.alertAdd.threshold.comparators.isBelowOrEqualsLabel', + 'xpack.triggersActionsUI.sections.alertAdd.threshold.comparators.isBelowOrEqualsLabel', { defaultMessage: 'Is below or equals', } @@ -231,7 +240,7 @@ export const comparators: { [key: string]: Comparator } = { }, [COMPARATORS.BETWEEN]: { text: i18n.translate( - 'xpack.alertingUI.sections.alertAdd.threshold.comparators.isBetweenLabel', + 'xpack.triggersActionsUI.sections.alertAdd.threshold.comparators.isBetweenLabel', { defaultMessage: 'Is between', } @@ -244,7 +253,7 @@ export const comparators: { [key: string]: Comparator } = { export const groupByTypes: { [key: string]: GroupByType } = { all: { text: i18n.translate( - 'xpack.alertingUI.sections.alertAdd.threshold.groupByLabel.allDocumentsLabel', + 'xpack.triggersActionsUI.sections.alertAdd.threshold.groupByLabel.allDocumentsLabel', { defaultMessage: 'all documents', } @@ -254,9 +263,12 @@ export const groupByTypes: { [key: string]: GroupByType } = { validNormalizedTypes: [], }, top: { - text: i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.groupByLabel.topLabel', { - defaultMessage: 'top', - }), + text: i18n.translate( + 'xpack.triggersActionsUI.sections.alertAdd.threshold.groupByLabel.topLabel', + { + defaultMessage: 'top', + } + ), sizeRequired: true, value: 'top', validNormalizedTypes: ['number', 'date', 'keyword'], @@ -299,9 +311,12 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = } = alert.alertTypeParams; const firstFieldOption = { - text: i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.timeFieldOptionLabel', { - defaultMessage: 'Select a field', - }), + text: i18n.translate( + 'xpack.triggersActionsUI.sections.alertAdd.threshold.timeFieldOptionLabel', + { + defaultMessage: 'Select a field', + } + ), value: '', }; @@ -317,9 +332,12 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = const [aggFieldPopoverOpen, setAggFieldPopoverOpen] = useState(false); const [groupByPopoverOpen, setGroupByPopoverOpen] = useState(false); - const andThresholdText = i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.andLabel', { - defaultMessage: 'AND', - }); + const andThresholdText = i18n.translate( + 'xpack.triggersActionsUI.sections.alertAdd.threshold.andLabel', + { + defaultMessage: 'AND', + } + ); const hasExpressionErrors = !!Object.keys(errors).find( errorKey => expressionFieldsWithValidation.includes(errorKey) && errors[errorKey].length >= 1 @@ -332,7 +350,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = }; const expressionErrorMessage = i18n.translate( - 'xpack.alertingUI.sections.alertAdd.threshold.fixErrorInExpressionBelowValidationMessage', + 'xpack.triggersActionsUI.sections.alertAdd.threshold.fixErrorInExpressionBelowValidationMessage', { defaultMessage: 'Expression contains errors.', } @@ -390,7 +408,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = options.push({ label: i18n.translate( - 'xpack.alertingUI.sections.alertAdd.threshold.indicesAndIndexPatternsLabel', + 'xpack.triggersActionsUI.sections.alertAdd.threshold.indicesAndIndexPatternsLabel', { defaultMessage: 'Based on your indices and index patterns', } @@ -405,7 +423,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = } options.push({ - label: i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.chooseLabel', { + label: i18n.translate('xpack.triggersActionsUI.sections.alertAdd.threshold.chooseLabel', { defaultMessage: 'Choose…', }), options: [ @@ -429,7 +447,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = fullWidth label={ } @@ -438,7 +456,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = errors={errors} helpText={ } @@ -497,7 +515,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = fullWidth label={ } @@ -528,7 +546,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = fullWidth label={ } @@ -560,7 +578,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = fullWidth value={triggerIntervalUnit} aria-label={i18n.translate( - 'xpack.alertingUI.sections.alertAdd.threshold.durationAriaLabel', + 'xpack.triggersActionsUI.sections.alertAdd.threshold.durationAriaLabel', { defaultMessage: 'Duration time unit', } @@ -595,7 +613,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = button={ = >
- {i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.insideButtonLabel', { - defaultMessage: 'inside', - })} + {i18n.translate( + 'xpack.triggersActionsUI.sections.alertAdd.threshold.insideButtonLabel', + { + defaultMessage: 'inside', + } + )} {indexPopover}
@@ -632,7 +653,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = button={ = >
- {i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.whenButtonLabel', { - defaultMessage: 'when', - })} + {i18n.translate( + 'xpack.triggersActionsUI.sections.alertAdd.threshold.whenButtonLabel', + { + defaultMessage: 'when', + } + )} = button={ = >
- {i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.ofButtonLabel', { - defaultMessage: 'of', - })} + {i18n.translate( + 'xpack.triggersActionsUI.sections.alertAdd.threshold.ofButtonLabel', + { + defaultMessage: 'of', + } + )} @@ -756,14 +783,17 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = description={`${ groupByTypes[groupBy || DEFAULT_VALUES.GROUP_BY].sizeRequired ? i18n.translate( - 'xpack.alertingUI.sections.alertAdd.threshold.groupedOverLabel', + 'xpack.triggersActionsUI.sections.alertAdd.threshold.groupedOverLabel', { defaultMessage: 'grouped over', } ) - : i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.overLabel', { - defaultMessage: 'over', - }) + : i18n.translate( + 'xpack.triggersActionsUI.sections.alertAdd.threshold.overLabel', + { + defaultMessage: 'over', + } + ) }`} value={`${groupByTypes[groupBy || DEFAULT_VALUES.GROUP_BY].text} ${ groupByTypes[groupBy || DEFAULT_VALUES.GROUP_BY].sizeRequired @@ -787,9 +817,12 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = >
- {i18n.translate('xpack.alertingUI.sections.alertAdd.threshold.overButtonLabel', { - defaultMessage: 'over', - })} + {i18n.translate( + 'xpack.triggersActionsUI.sections.alertAdd.threshold.overButtonLabel', + { + defaultMessage: 'over', + } + )} @@ -969,7 +1002,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = button={ =
diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx similarity index 95% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx index 606bb6d0d6e785..f61b03e698965f 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx @@ -195,7 +195,7 @@ export const ThresholdVisualization: React.FunctionComponent = ({ alert } body={ @@ -211,7 +211,7 @@ export const ThresholdVisualization: React.FunctionComponent = ({ alert } } @@ -294,14 +294,14 @@ export const ThresholdVisualization: React.FunctionComponent = ({ alert } } color="warning" > diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/types.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/types.ts similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/alert_types/types.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/types.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/index.ts similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alert_add/index.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/index.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx similarity index 81% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index a2b598fdf114e7..8fa8df89901ff3 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -37,6 +37,7 @@ export const AlertsList: React.FunctionComponent = () => { useEffect(() => { loadAlertsData(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, [page, searchText]); useEffect(() => { @@ -52,7 +53,7 @@ export const AlertsList: React.FunctionComponent = () => { } catch (e) { toastNotifications.addDanger({ title: i18n.translate( - 'xpack.alertingUI.sections.alertsList.unableToLoadAlertTypesMessage', + 'xpack.triggersActionsUI.sections.alertsList.unableToLoadAlertTypesMessage', { defaultMessage: 'Unable to load alert types' } ), }); @@ -60,6 +61,7 @@ export const AlertsList: React.FunctionComponent = () => { setIsLoadingAlertTypes(false); } })(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { @@ -85,9 +87,12 @@ export const AlertsList: React.FunctionComponent = () => { setTotalItemCount(alertsResponse.total); } catch (e) { toastNotifications.addDanger({ - title: i18n.translate('xpack.alertingUI.sections.alertsList.unableToLoadAlertsMessage', { - defaultMessage: 'Unable to load alerts', - }), + title: i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.unableToLoadAlertsMessage', + { + defaultMessage: 'Unable to load alerts', + } + ), }); } finally { setIsLoadingAlerts(false); @@ -102,9 +107,12 @@ export const AlertsList: React.FunctionComponent = () => { await loadAlertsData(); } catch (e) { toastNotifications.addDanger({ - title: i18n.translate('xpack.alertingUI.sections.alertsList.failedToDeleteAlertsMessage', { - defaultMessage: 'Failed to delete alert(s)', - }), + title: i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.failedToDeleteAlertsMessage', + { + defaultMessage: 'Failed to delete alert(s)', + } + ), }); // Refresh the alerts from the server, some alerts may have been deleted await loadAlertsData(); @@ -121,7 +129,7 @@ export const AlertsList: React.FunctionComponent = () => { { field: 'name', name: i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.nameTitle', + 'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.nameTitle', { defaultMessage: 'Name' } ), sortable: false, @@ -130,7 +138,7 @@ export const AlertsList: React.FunctionComponent = () => { { field: 'tagsText', name: i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.tagsText', + 'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.tagsText', { defaultMessage: 'Tags' } ), sortable: false, @@ -138,7 +146,7 @@ export const AlertsList: React.FunctionComponent = () => { { field: 'alertType', name: i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.alertTypeTitle', + 'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.alertTypeTitle', { defaultMessage: 'Type' } ), sortable: false, @@ -147,23 +155,21 @@ export const AlertsList: React.FunctionComponent = () => { { field: 'interval', name: i18n.translate( - 'xpack.alertingUI.sections.alertsList.alertsListTable.columns.intervalTitle', + 'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.intervalTitle', { defaultMessage: 'Runs every' } ), sortable: false, truncateText: false, }, { - name: i18n.translate('xpack.alertingUI.sections.alertsList.alertsListTable.columns.actions', { - defaultMessage: 'Actions', - }), + name: i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.actions', + { + defaultMessage: 'Actions', + } + ), render(item: AlertTableItem) { - return ( - loadAlertsData()} - > - ); + return loadAlertsData()} />; }, }, ]; @@ -180,7 +186,7 @@ export const AlertsList: React.FunctionComponent = () => { type: 'field_value_selection', field: 'type', name: i18n.translate( - 'xpack.alertingUI.sections.alertsList.filters.alertTypeIdName', + 'xpack.triggersActionsUI.sections.alertsList.filters.alertTypeIdName', { defaultMessage: 'Type' } ), multiSelect: 'or', @@ -203,13 +209,13 @@ export const AlertsList: React.FunctionComponent = () => { canDelete ? undefined : i18n.translate( - 'xpack.alertingUI.sections.alertsList.buttons.deleteDisabledTitle', + 'xpack.triggersActionsUI.sections.alertsList.buttons.deleteDisabledTitle', { defaultMessage: 'Unable to delete alerts' } ) } > , @@ -222,12 +228,12 @@ export const AlertsList: React.FunctionComponent = () => { onClick={() => setAlertFlyoutVisibility(true)} > , ]} - > + /> {/* Large to remain consistent with ActionsList table spacing */} @@ -257,8 +263,8 @@ export const AlertsList: React.FunctionComponent = () => { onChange={({ page: changedPage }: { page: Pagination }) => { setPage(changedPage); }} - > - + /> +
diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx similarity index 89% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx index cc1b6e5e15c26b..6251e04a84a0c8 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx @@ -53,10 +53,10 @@ export const CollapsedItemActions: React.FunctionComponent = ({ iconType="boxesVertical" onClick={() => setIsPopoverOpen(!isPopoverOpen)} aria-label={i18n.translate( - 'xpack.alertingUI.sections.alertsList.collapsedItemActons.popoverButtonTitle', + 'xpack.triggersActionsUI.sections.alertsList.collapsedItemActons.popoverButtonTitle', { defaultMessage: 'Actions' } )} - > + /> ); return ( @@ -77,7 +77,7 @@ export const CollapsedItemActions: React.FunctionComponent = ({ }} label={ } @@ -99,7 +99,7 @@ export const CollapsedItemActions: React.FunctionComponent = ({ }} label={ } @@ -117,7 +117,7 @@ export const CollapsedItemActions: React.FunctionComponent = ({ }} > diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/index.ts similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/index.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/index.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/legacy.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/legacy.ts similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/legacy.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/legacy.ts diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts similarity index 97% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts index acf46383fd385a..0d879d236c4a54 100644 --- a/x-pack/legacy/plugins/alerting_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts @@ -29,7 +29,7 @@ import { setSavedObjectsClient } from './application/lib/api'; export type Setup = void; export type Start = void; -const REACT_ROOT_ID = 'alertingRoot'; +const REACT_ROOT_ID = 'triggersActionsRoot'; export class Plugin implements CorePlugin { private actionTypeRegistry?: ActionTypeRegistry; @@ -67,9 +67,9 @@ export class Plugin implements CorePlugin { }); const kbnSection = getSection('kibana'); - kbnSection.register('alerting', { + kbnSection.register('triggersActions', { display: i18n.translate('xpack.alertingUI.managementSection.displayName', { - defaultMessage: 'Alerting', + defaultMessage: 'Triggers and Actions', }), order: 7, url: `#${BASE_PATH}`, diff --git a/x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/np_ready/public/types.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts diff --git a/x-pack/legacy/plugins/alerting_ui/public/hacks/register.ts b/x-pack/legacy/plugins/triggers_actions_ui/public/hacks/register.ts similarity index 65% rename from x-pack/legacy/plugins/alerting_ui/public/hacks/register.ts rename to x-pack/legacy/plugins/triggers_actions_ui/public/hacks/register.ts index 71143525a840bb..229064c64930e1 100644 --- a/x-pack/legacy/plugins/alerting_ui/public/hacks/register.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/public/hacks/register.ts @@ -12,13 +12,13 @@ import { FeatureCatalogueRegistryProvider.register(() => { return { - id: 'alerting', - title: 'Alerting', // This is a product name so we don't translate it. - description: i18n.translate('xpack.alertingUI.AlertingDescription', { - defaultMessage: 'Data by creating, managing, and monitoring alerts.', + id: 'triggersActions', + title: 'Triggers and Actions', // This is a product name so we don't translate it. + description: i18n.translate('xpack.triggersActionsUI.triggersActionsDescription', { + defaultMessage: 'Data by creating, managing, and monitoring triggers and actions.', }), - icon: 'alertingApp', - path: '/app/kibana#/management/kibana/alerting', + icon: 'triggersActionsApp', + path: '/app/kibana#/management/kibana/triggersActions', showOnHomePage: true, category: FeatureCatalogueCategory.ADMIN, }; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/public/index.html b/x-pack/legacy/plugins/triggers_actions_ui/public/index.html new file mode 100644 index 00000000000000..a982be5cbb8776 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/public/index.html @@ -0,0 +1,3 @@ + +
+
diff --git a/x-pack/legacy/plugins/alerting_ui/public/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/public/index.ts similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/public/index.ts rename to x-pack/legacy/plugins/triggers_actions_ui/public/index.ts diff --git a/x-pack/legacy/plugins/alerting_ui/public/shim.ts b/x-pack/legacy/plugins/triggers_actions_ui/public/shim.ts similarity index 100% rename from x-pack/legacy/plugins/alerting_ui/public/shim.ts rename to x-pack/legacy/plugins/triggers_actions_ui/public/shim.ts From 966352c4b4c2712d990545873ec5af8d4061b4f7 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 25 Nov 2019 19:19:25 -0800 Subject: [PATCH 131/297] Implemented action connector edit UI --- .../components/section_loading.tsx | 23 ++++ .../application/context/actions_context.tsx | 9 +- .../np_ready/public/application/lib/api.ts | 26 +++- .../action_add_flyout.tsx | 20 ++- .../action_form/action_edit_flyout.tsx | 110 ++++++++++++++++ .../action_form.tsx} | 57 ++++---- .../action_reducer.ts | 0 .../action_type_menu.tsx | 4 +- .../buildin_action_types/email.tsx | 123 ++++++++--------- .../buildin_action_types/es_index.tsx | 0 .../buildin_action_types/index.ts | 0 .../buildin_action_types/pagerduty.tsx | 57 ++++---- .../buildin_action_types/server_log.tsx | 0 .../buildin_action_types/slack.tsx | 7 +- .../buildin_action_types/webhook.tsx | 124 +++++++++--------- .../{action_add => action_form}/index.ts | 1 + .../actions_list/components/actions_list.tsx | 47 +++++-- .../np_ready/public/plugin.ts | 2 +- .../np_ready/public/types.ts | 6 +- 19 files changed, 416 insertions(+), 200 deletions(-) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/section_loading.tsx rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/{action_add => action_form}/action_add_flyout.tsx (78%) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_edit_flyout.tsx rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/{action_add/action_add_form.tsx => action_form/action_form.tsx} (84%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/{action_add => action_form}/action_reducer.ts (100%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/{action_add => action_form}/action_type_menu.tsx (93%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/{action_add => action_form}/buildin_action_types/email.tsx (84%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/{action_add => action_form}/buildin_action_types/es_index.tsx (100%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/{action_add => action_form}/buildin_action_types/index.ts (100%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/{action_add => action_form}/buildin_action_types/pagerduty.tsx (90%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/{action_add => action_form}/buildin_action_types/server_log.tsx (100%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/{action_add => action_form}/buildin_action_types/slack.tsx (97%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/{action_add => action_form}/buildin_action_types/webhook.tsx (82%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/{action_add => action_form}/index.ts (83%) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/section_loading.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/section_loading.tsx new file mode 100644 index 00000000000000..4c6273682a0e4c --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/section_loading.tsx @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under 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 { EuiEmptyPrompt, EuiLoadingSpinner, EuiText } from '@elastic/eui'; + +interface Props { + children: React.ReactNode; +} + +export const SectionLoading: React.FunctionComponent = ({ children }) => { + return ( + } + body={{children}} + data-test-subj="sectionLoading" + /> + ); +}; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_context.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_context.tsx index 4d4d38a8201907..e5cf2a280c2f1b 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_context.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_context.tsx @@ -5,12 +5,15 @@ */ import React from 'react'; -import { ActionType } from '../../types'; +import { ActionType, ActionTableItem } from '../../types'; export const ActionsContext = React.createContext({} as IActionContext); export interface IActionContext { - flyoutVisible: boolean; - setFlyoutVisibility: React.Dispatch>; + addFlyoutVisible: boolean; + editFlyoutVisible: boolean; + setEditFlyoutVisibility: React.Dispatch>; + setAddFlyoutVisibility: React.Dispatch>; actionTypesIndex: Record | undefined; loadActions: () => Promise; + editedActionItem: ActionTableItem | undefined; } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts index af2056fca9ef82..c227d0f2a7d633 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts @@ -49,7 +49,17 @@ export async function loadAllActions({ http }: LoadActionsOpts): Promise { + return http.get(`${BASE_ACTION_API_PATH}/${id}`); +} + +export async function createAction({ http, action, }: { @@ -61,6 +71,20 @@ export async function saveAction({ }); } +export async function updateAction({ + http, + action, + id, +}: { + http: HttpServiceBase; + action: Action; + id: string; +}): Promise { + return http.put(`${BASE_ACTION_API_PATH}/${id}`, { + body: JSON.stringify({ ...action, id: undefined, actionTypeId: undefined, secrets: undefined }), + }); +} + export async function deleteActions({ ids, http }: DeleteActionsOpts): Promise { await Promise.all(ids.map(id => http.delete(`${BASE_ACTION_API_PATH}/${id}`))); } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/action_add_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_add_flyout.tsx similarity index 78% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/action_add_flyout.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_add_flyout.tsx index f0d4bd3171be97..bbfc82b5700402 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/action_add_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_add_flyout.tsx @@ -15,21 +15,21 @@ import { } from '@elastic/eui'; import { ActionsContext } from '../../context/actions_context'; import { ActionTypeMenu } from './action_type_menu'; -import { ActionAddForm } from './action_add_form'; +import { ActionForm } from './action_form'; import { ActionType } from '../../../types'; import { useAppDependencies } from '../..'; export const ActionAddFlyout = () => { const { actionTypeRegistry } = useAppDependencies(); - const { flyoutVisible, setFlyoutVisibility } = useContext(ActionsContext); + const { addFlyoutVisible, setAddFlyoutVisibility } = useContext(ActionsContext); const [actionType, setActionType] = useState(undefined); - const closeFlyout = useCallback(() => setFlyoutVisibility(false), [setFlyoutVisibility]); + const closeFlyout = useCallback(() => setAddFlyoutVisibility(false), [setAddFlyoutVisibility]); useEffect(() => { setActionType(undefined); - }, [flyoutVisible]); + }, [addFlyoutVisible]); - if (!flyoutVisible) { + if (!addFlyoutVisible) { return null; } @@ -39,7 +39,15 @@ export const ActionAddFlyout = () => { currentForm = ; } else { actionTypeModel = actionTypeRegistry.get(actionType.id); - currentForm = ; + const initialAction = { actionTypeId: actionType.id, config: {}, secrets: {} }; + + currentForm = ( + + ); } return ( diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_edit_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_edit_flyout.tsx new file mode 100644 index 00000000000000..e275a2116fa3d3 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_edit_flyout.tsx @@ -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 React, { useContext, useCallback, useEffect, useState } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + EuiTitle, + EuiFlyoutHeader, + EuiFlyout, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { ActionsContext } from '../../context/actions_context'; +import { ActionForm } from './action_form'; +import { useAppDependencies } from '../..'; +import { getActionById } from '../../lib/api'; +import { Action } from '../../../types'; +import { SectionLoading } from '../../components/section_loading'; + +export const ActionEditFlyout = () => { + const { + core: { http }, + plugins: { toastNotifications }, + actionTypeRegistry, + } = useAppDependencies(); + const { editFlyoutVisible, setEditFlyoutVisibility, editedActionItem } = useContext( + ActionsContext + ); + const [isLoadingAction, setIsLoadingAction] = useState(false); + const [action, setAction] = useState(undefined); + + const closeFlyout = useCallback(() => setEditFlyoutVisibility(false), [setEditFlyoutVisibility]); + + useEffect(() => { + if (editedActionItem && editedActionItem.id) { + loadActionById(editedActionItem.id); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [editFlyoutVisible]); + + async function loadActionById(actionItemId: string) { + setIsLoadingAction(true); + try { + const actionResponse = await getActionById({ id: actionItemId, http }); + setAction(actionResponse); + } catch (e) { + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.triggersActionsUI.sections.actionEdit.unableToLoadActionMessage', + { + defaultMessage: 'Unable to load action', + } + ), + }); + } finally { + setIsLoadingAction(false); + } + } + + if (!editFlyoutVisible) { + return null; + } + + let actionTypeModel; + if (editedActionItem) { + actionTypeModel = actionTypeRegistry.get(editedActionItem.actionTypeId); + } + + return ( + + + + {actionTypeModel ? ( + + + + ) : null} + + +

+ +

+
+
+
+
+ {action && editedActionItem ? ( + + ) : ( + + + + )} +
+ ); +}; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/action_add_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_form.tsx similarity index 84% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/action_add_form.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_form.tsx index 4677dd6f8d08e0..cc5b450aa84e0c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/action_add_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_form.tsx @@ -20,26 +20,27 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { saveAction } from '../../lib/api'; +import { createAction, updateAction } from '../../lib/api'; import { SectionError, ErrableFormRow } from '../../components/page_error'; import { useAppDependencies } from '../..'; import { actionReducer } from './action_reducer'; import { ActionsContext } from '../../context/actions_context'; -import { ActionType, Action, IErrorObject } from '../../../types'; +import { Action, IErrorObject } from '../../../types'; interface Props { - actionType: ActionType; + initialAction: Action; + actionTypeName: string; + setFlyoutVisibility: React.Dispatch>; } -export const ActionAddForm = ({ actionType }: Props) => { +export const ActionForm = ({ initialAction, actionTypeName, setFlyoutVisibility }: Props) => { const { core: { http }, plugins: { toastNotifications }, actionTypeRegistry, } = useAppDependencies(); - const initialAction = { actionTypeId: actionType.id, config: {}, secrets: {} }; - const { setFlyoutVisibility, loadActions } = useContext(ActionsContext); + const { loadActions } = useContext(ActionsContext); // hooks const [{ action }, dispatch] = useReducer(actionReducer, { action: initialAction }); @@ -57,12 +58,8 @@ export const ActionAddForm = ({ actionType }: Props) => { }; useEffect(() => { - dispatch({ - command: { type: 'setAction' }, - payload: { key: 'action', value: { actionTypeId: actionType.id, config: {}, secrets: {} } }, - }); setServerError(null); - }, [actionType]); + }, []); const [isSaving, setIsSaving] = useState(false); const [serverError, setServerError] = useState<{ @@ -85,7 +82,7 @@ export const ActionAddForm = ({ actionType }: Props) => { return validationResult; } - const actionTypeRegisterd = actionTypeRegistry.get(actionType.id); + const actionTypeRegisterd = actionTypeRegistry.get(initialAction.actionTypeId); if (actionTypeRegisterd === null) return null; const FieldsComponent = actionTypeRegisterd.actionFields; const errors = { @@ -96,15 +93,29 @@ export const ActionAddForm = ({ actionType }: Props) => { async function onActionSave(): Promise { try { - const newAction = await saveAction({ http, action }); - toastNotifications.addSuccess( - i18n.translate('xpack.triggersActionsUI.sections.actionAdd.saveSuccessNotificationText', { - defaultMessage: "Saved '{actionName}'", - values: { - actionName: newAction.description, - }, - }) - ); + let newAction; + if (action.id === undefined) { + newAction = await createAction({ http, action }); + toastNotifications.addSuccess( + i18n.translate('xpack.triggersActionsUI.sections.actionAdd.saveSuccessNotificationText', { + defaultMessage: "Created '{actionName}'", + values: { + actionName: newAction.description, + }, + }) + ); + } else { + newAction = await updateAction({ http, action, id: action.id }); + toastNotifications.addSuccess( + i18n.translate('xpack.triggersActionsUI.sections.actionAdd.saveSuccessNotificationText', { + defaultMessage: "Updated '{actionName}'", + values: { + actionName: newAction.description, + }, + }) + ); + } + return newAction; } catch (error) { return { @@ -168,7 +179,7 @@ export const ActionAddForm = ({ actionType }: Props) => { editActionSecrets={setActionSecretsProperty} hasErrors={hasErrors} > - {actionType.id === null ? ( + {initialAction.actionTypeId === null ? ( { id="xpack.triggersActionsUI.sections.actionAdd.actions.actionConfigurationWarningDescriptionText" defaultMessage="To create this action, you must configure at least one {accountType} account. {docLink}" values={{ - accountType: actionType.name, + accountType: actionTypeName, docLink: ( { const { actionTypeRegistry } = useAppDependencies(); - const { actionTypesIndex, setFlyoutVisibility } = useContext(ActionsContext); + const { actionTypesIndex, setAddFlyoutVisibility } = useContext(ActionsContext); if (!actionTypesIndex) { return null; } @@ -63,7 +63,7 @@ export const ActionTypeMenu = ({ setActionType }: Props) => { - setFlyoutVisibility(false)}> + setAddFlyoutVisibility(false)}> {i18n.translate('xpack.triggersActionsUI.sections.actionAdd.cancelButtonLabel', { defaultMessage: 'Cancel', })} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/email.tsx similarity index 84% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/email.tsx index a57136eb41d4bd..1c6c1e921ccec4 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/email.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/email.tsx @@ -64,14 +64,14 @@ export function getActionType(): ActionTypeModel { }) ); } - if (!action.secrets.user) { + if (action.secrets && !action.secrets.user) { errors.user.push( i18n.translate('xpack.triggersActionsUI.sections.addAction.error.requiredUserText', { defaultMessage: 'User is required.', }) ); } - if (!action.secrets.password) { + if (action.secrets && !action.secrets.password) { errors.password.push( i18n.translate('xpack.triggersActionsUI.sections.addAction.error.requiredPasswordText', { defaultMessage: 'Password is required.', @@ -135,7 +135,6 @@ const EmailActionFields: React.FunctionComponent = ({ hasErrors, }) => { const { from, host, port } = action.config; - const { user, password } = action.secrets; return ( @@ -230,68 +229,70 @@ const EmailActionFields: React.FunctionComponent = ({ - - - - + + { - editActionSecrets('user', e.target.value); - }} - onBlur={() => { - if (!user) { - editActionSecrets('user', ''); + errors={errors} + isShowingErrors={hasErrors && action.secrets.user !== undefined} + label={i18n.translate( + 'xpack.triggersActionsUI.sections.actionAdd.emailAction.userTextFieldLabel', + { + defaultMessage: 'User', } - }} - /> - - - - - + { + editActionSecrets('user', e.target.value); + }} + onBlur={() => { + if (!action.secrets.user) { + editActionSecrets('user', ''); + } + }} + /> + + + + { - editActionSecrets('password', e.target.value); - }} - onBlur={() => { - if (!password) { - editActionSecrets('password', ''); + errors={errors} + isShowingErrors={hasErrors && action.secrets.password !== undefined} + label={i18n.translate( + 'xpack.triggersActionsUI.sections.actionAdd.emailAction.passwordFieldLabel', + { + defaultMessage: 'Password', } - }} - /> - - - + )} + > + { + editActionSecrets('password', e.target.value); + }} + onBlur={() => { + if (!action.secrets.password) { + editActionSecrets('password', ''); + } + }} + /> + + + + ) : null} ); }; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/es_index.tsx similarity index 100% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/es_index.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/es_index.tsx diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/index.ts similarity index 100% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/index.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/index.ts diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/pagerduty.tsx similarity index 90% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/pagerduty.tsx index 4a5bb0de35e0dc..6c21b0cf21d26f 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/pagerduty.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/pagerduty.tsx @@ -32,7 +32,7 @@ export function getActionType(): ActionTypeModel { apiUrl: new Array(), }; validationResult.errors = errors; - if (!action.secrets.routingKey) { + if (action.secrets && !action.secrets.routingKey) { errors.routingKey.push( i18n.translate( 'xpack.triggersActionsUI.sections.actionAdd.pagerDutyAction.error.requiredRoutingKeyText', @@ -71,7 +71,6 @@ const PagerDutyActionFields: React.FunctionComponent = ({ editActionSecrets, }) => { const { apiUrl } = action.config; - const { routingKey } = action.secrets; return ( = ({ }} /> - - ) => { - editActionSecrets('routingKey', e.target.value); - }} - onBlur={() => { - if (!routingKey) { - editActionSecrets('routingKey', ''); + errors={errors} + isShowingErrors={hasErrors === true && action.secrets.routingKey !== undefined} + label={i18n.translate( + 'xpack.triggersActionsUI.sections.actionAdd.pagerDutyAction.routingKeyTextFieldLabel', + { + defaultMessage: 'RoutingKey', } - }} - /> - + )} + > + ) => { + editActionSecrets('routingKey', e.target.value); + }} + onBlur={() => { + if (!action.secrets.routingKey) { + editActionSecrets('routingKey', ''); + } + }} + /> + + ) : null} ); }; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/server_log.tsx similarity index 100% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/server_log.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/server_log.tsx diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/slack.tsx similarity index 97% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/slack.tsx index 12c79735d1c8da..816e0e5d2b6b1f 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/slack.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/slack.tsx @@ -5,7 +5,6 @@ */ import React, { Fragment } from 'react'; import { EuiFieldText, EuiTextArea, EuiFlexGroup, EuiFlexItem, EuiButtonIcon } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { ErrableFormRow } from '../../../components/page_error'; import { @@ -32,7 +31,7 @@ export function getActionType(): ActionTypeModel { webhookUrl: new Array(), }; validationResult.errors = errors; - if (!action.secrets.webhookUrl) { + if (action.secrets && !action.secrets.webhookUrl) { errors.webhookUrl.push( i18n.translate( 'xpack.triggersActionsUI.sections.actionAdd.slackAction.error.requiredWebhookUrlText', @@ -59,6 +58,10 @@ const SlackActionFields: React.FunctionComponent = ({ errors, hasErrors, }) => { + if (!action.secrets) { + return null; + } + const { webhookUrl } = action.secrets; return ( diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/webhook.tsx similarity index 82% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/webhook.tsx index cae6c6c3a203e3..5b1403a3ae93e3 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_add/buildin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/webhook.tsx @@ -71,7 +71,7 @@ export function getActionType(): ActionTypeModel { ) ); } - if (!action.secrets.user) { + if (action.secrets && !action.secrets.user) { errors.user.push( i18n.translate( 'xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredHostText', @@ -81,7 +81,7 @@ export function getActionType(): ActionTypeModel { ) ); } - if (!action.secrets.password) { + if (action.secrets && !action.secrets.password) { errors.password.push( i18n.translate( 'xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredPasswordText', @@ -113,7 +113,6 @@ const WebhookActionFields: React.FunctionComponent = ({ const [headerValue, setHeaderValue] = useState(''); const [hasHeaders, setHasHeaders] = useState(false); - const { user, password } = action.secrets; const { method, url, headers } = action.config; editActionConfig('method', 'post'); // set method to POST by default @@ -282,69 +281,70 @@ const WebhookActionFields: React.FunctionComponent = ({ - - - - + + { - editActionSecrets('user', e.target.value); - }} - onBlur={() => { - if (!user) { - editActionSecrets('user', ''); + errors={errors} + isShowingErrors={hasErrors === true && action.secrets.user !== undefined} + label={i18n.translate( + 'xpack.triggersActionsUI.sections.actionAdd.webhookAction.userTextFieldLabel', + { + defaultMessage: 'User', } - }} - /> - - - - - + { + editActionSecrets('user', e.target.value); + }} + onBlur={() => { + if (!action.secrets.user) { + editActionSecrets('user', ''); + } + }} + /> + + + + { - editActionSecrets('password', e.target.value); - }} - onBlur={() => { - if (!password) { - editActionSecrets('password', ''); + errors={errors} + isShowingErrors={hasErrors === true && action.secrets.password !== undefined} + label={i18n.translate( + 'xpack.triggersActionsUI.sections.actionAdd.webhookAction.passwordTextFieldLabel', + { + defaultMessage: 'Password', } - }} - /> - - - - + )} + > + { + editActionSecrets('password', e.target.value); + }} + onBlur={() => { + if (!action.secrets.password) { + editActionSecrets('password', ''); + } + }} + /> + + + + ) : null} { const { @@ -20,6 +20,7 @@ export const ActionsList: React.FunctionComponent = () => { plugins: { capabilities, toastNotifications }, } = useAppDependencies(); const canDelete = capabilities.get().actions.delete; + const canEdit = capabilities.get().actions.delete; const [actionTypesIndex, setActionTypesIndex] = useState(undefined); const [actions, setActions] = useState([]); @@ -28,10 +29,12 @@ export const ActionsList: React.FunctionComponent = () => { const [isLoadingActionTypes, setIsLoadingActionTypes] = useState(false); const [isLoadingActions, setIsLoadingActions] = useState(false); const [isDeletingActions, setIsDeletingActions] = useState(false); - const [flyoutVisible, setFlyoutVisibility] = useState(false); + const [editFlyoutVisible, setEditFlyoutVisibility] = useState(false); + const [addFlyoutVisible, setAddFlyoutVisibility] = useState(false); const [actionTypesList, setActionTypesList] = useState>( [] ); + const [editedActionItem, setEditedActionItem] = useState(undefined); useEffect(() => { loadActions(); @@ -108,10 +111,10 @@ export const ActionsList: React.FunctionComponent = () => { async function deleteItems(items: ActionTableItem[]) { setIsDeletingActions(true); - const ids = items.map(item => item.id); + const ids = items.map(item => (item.id ? item.id : '')); try { await deleteActions({ http, ids }); - const updatedActions = actions.filter(action => !ids.includes(action.id)); + const updatedActions = actions.filter(action => action.id && !ids.includes(action.id)); setActions(updatedActions); } catch (e) { toastNotifications.addDanger({ @@ -120,13 +123,18 @@ export const ActionsList: React.FunctionComponent = () => { { defaultMessage: 'Failed to delete action(s)' } ), }); - // Refresh the actions from the server, some actions may have beend eleted + // Refresh the actions from the server, some actions may have beend deleted loadActions(); } finally { setIsDeletingActions(false); } } + async function editItem(actionTableItem: ActionTableItem) { + setEditedActionItem(actionTableItem); + setEditFlyoutVisibility(true); + } + async function deleteSelectedItems() { await deleteItems(selectedItems); } @@ -169,6 +177,25 @@ export const ActionsList: React.FunctionComponent = () => { { name: '', actions: [ + { + enabled: () => canEdit, + name: i18n.translate( + 'xpack.triggersActionsUI.sections.actionsList.actionsListTable.columns.actions.editActionName', + { defaultMessage: 'Edit' } + ), + description: canEdit + ? i18n.translate( + 'xpack.triggersActionsUI.sections.actionsList.actionsListTable.columns.actions.editActionDescription', + { defaultMessage: 'Edit this action' } + ) + : i18n.translate( + 'xpack.triggersActionsUI.sections.actionsList.actionsListTable.columns.actions.editActionDisabledDescription', + { defaultMessage: 'Unable to edit actions' } + ), + type: 'icon', + icon: 'pencil', + onClick: (item: ActionTableItem) => editItem(item), + }, { enabled: () => canDelete, name: i18n.translate( @@ -198,10 +225,13 @@ export const ActionsList: React.FunctionComponent = () => { { fill iconType="plusInCircle" iconSide="left" - onClick={() => setFlyoutVisibility(true)} + onClick={() => setAddFlyoutVisibility(true)} > { }} /> +
diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts index 0d879d236c4a54..c320dbcc9b11d4 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts @@ -21,7 +21,7 @@ import { BASE_PATH } from './application/constants'; import { breadcrumbService } from './application/lib/breadcrumb'; import { docTitleService } from './application/lib/doc_title'; import { ActionTypeRegistry } from './application/action_type_registry'; -import { registerBuiltInActionTypes } from './application/sections/action_add/buildin_action_types'; +import { registerBuiltInActionTypes } from './application/sections/action_form/buildin_action_types'; import { AlertTypeRegistry } from './application/alert_type_registry'; import { registerAlertTypes } from './application/sections/alert_add/alert_types'; import { setSavedObjectsClient } from './application/lib/api'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts index 4ba8f36b7b8fae..ce36393c99cac6 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts @@ -49,10 +49,10 @@ export interface ActionType { export interface Action { secrets: Record; - id: string; + id?: string; actionTypeId: string; - description: string; - referencedByCount: number; + description?: string; + referencedByCount?: number; config: Record; } From 577806e46265a70879d3291bd352bfaec253fd68 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 26 Nov 2019 11:29:26 -0500 Subject: [PATCH 132/297] Add bulk actions to alerts list --- .../np_ready/public/application/lib/api.ts | 32 +-- .../actions_list/components/actions_list.tsx | 2 +- .../alerts_list/components/alerts_list.tsx | 94 +++----- .../components/bulk_action_popover.tsx | 228 ++++++++++++++++++ .../components/collapsed_item_actions.tsx | 36 +-- 5 files changed, 304 insertions(+), 88 deletions(-) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts index c227d0f2a7d633..6adbe9297b38cf 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts @@ -150,44 +150,44 @@ export async function saveAlert({ }); } -export async function enableAlert({ - id, +export async function enableAlerts({ + ids, http, }: { - id: string; + ids: string[]; http: HttpServiceBase; }): Promise { - await http.post(`${BASE_ALERT_API_PATH}/${id}/_enable`); + await Promise.all(ids.map(id => http.post(`${BASE_ALERT_API_PATH}/${id}/_enable`))); } -export async function disableAlert({ - id, +export async function disableAlerts({ + ids, http, }: { - id: string; + ids: string[]; http: HttpServiceBase; }): Promise { - await http.post(`${BASE_ALERT_API_PATH}/${id}/_disable`); + await Promise.all(ids.map(id => http.post(`${BASE_ALERT_API_PATH}/${id}/_disable`))); } -export async function muteAllAlertInstances({ - id, +export async function muteAlerts({ + ids, http, }: { - id: string; + ids: string[]; http: HttpServiceBase; }): Promise { - await http.post(`${BASE_ALERT_API_PATH}/${id}/_mute_all`); + await Promise.all(ids.map(id => http.post(`${BASE_ALERT_API_PATH}/${id}/_mute_all`))); } -export async function unmuteAllAlertInstances({ - id, +export async function unmuteAlerts({ + ids, http, }: { - id: string; + ids: string[]; http: HttpServiceBase; }): Promise { - await http.post(`${BASE_ALERT_API_PATH}/${id}/_unmute_all`); + await Promise.all(ids.map(id => http.post(`${BASE_ALERT_API_PATH}/${id}/_unmute_all`))); } // TODO: replace watcher api with the proper from alerts diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 83baacc93639f6..fddcc2ef156082 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -171,7 +171,7 @@ export const ActionsList: React.FunctionComponent = () => { sortable: false, truncateText: true, render: (value: number, item: ActionTableItem) => { - return {value}; + return {value}; }, }, { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 8fa8df89901ff3..3896ff82541a20 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -8,13 +8,14 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { Fragment, useEffect, useState } from 'react'; // @ts-ignore: EuiSearchBar not exported in TypeScript -import { EuiBasicTable, EuiButton, EuiSearchBar, EuiSpacer } from '@elastic/eui'; +import { EuiBasicTable, EuiButton, EuiButtonEmpty, EuiSearchBar, EuiSpacer } from '@elastic/eui'; import { AlertsContext } from '../../../context/alerts_context'; import { useAppDependencies } from '../../../index'; import { Alert, AlertTableItem, AlertTypeIndex, Pagination } from '../../../../types'; import { AlertAdd } from '../../alert_add'; +import { BulkActionPopover } from './bulk_action_popover'; import { CollapsedItemActions } from './collapsed_item_actions'; -import { deleteAlerts, loadAlerts, loadAlertTypes } from '../../../lib/api'; +import { loadAlerts, loadAlertTypes } from '../../../lib/api'; export const AlertsList: React.FunctionComponent = () => { const { @@ -40,6 +41,19 @@ export const AlertsList: React.FunctionComponent = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [page, searchText]); + // The bulk action menu needs updated data within "selectedItems" when "data" changes + useEffect(() => { + const updatedSelectedItems: AlertTableItem[] = []; + selectedItems.forEach(item => { + const updatedItem = data.find(({ id }) => item.id === id); + if (updatedItem) { + updatedSelectedItems.push(updatedItem); + } + }); + setSelectedItems(updatedSelectedItems); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [data]); + useEffect(() => { (async () => { try { @@ -99,32 +113,6 @@ export const AlertsList: React.FunctionComponent = () => { } } - async function deleteItems(items: AlertTableItem[]) { - setIsPerformingAction(true); - const ids = items.map(item => item.id); - try { - await deleteAlerts({ http, ids }); - await loadAlertsData(); - } catch (e) { - toastNotifications.addDanger({ - title: i18n.translate( - 'xpack.triggersActionsUI.sections.alertsList.failedToDeleteAlertsMessage', - { - defaultMessage: 'Failed to delete alert(s)', - } - ), - }); - // Refresh the alerts from the server, some alerts may have been deleted - await loadAlertsData(); - } finally { - setIsPerformingAction(false); - } - } - - async function deleteSelectedItems() { - await deleteItems(selectedItems); - } - const alertsTableColumns = [ { field: 'name', @@ -169,7 +157,9 @@ export const AlertsList: React.FunctionComponent = () => { } ), render(item: AlertTableItem) { - return loadAlertsData()} />; + return ( + loadAlertsData()} /> + ); }, }, ]; @@ -198,27 +188,21 @@ export const AlertsList: React.FunctionComponent = () => { .sort((a, b) => a.name.localeCompare(b.name)), }, ]} + toolsLeft={ + selectedItems.length === 0 || !canDelete + ? [] + : [ + setIsPerformingAction(true)} + onActionPerformed={() => { + loadAlertsData(); + setIsPerformingAction(false); + }} + />, + ] + } toolsRight={[ - - - , { pageSize: page.size, totalItemCount, }} - selection={{ - onSelectionChange(updatedSelectedItemsList: AlertTableItem[]) { - setSelectedItems(updatedSelectedItemsList); - }, - }} + selection={ + canDelete && { + onSelectionChange(updatedSelectedItemsList: AlertTableItem[]) { + setSelectedItems(updatedSelectedItemsList); + }, + } + } onChange={({ page: changedPage }: { page: Pagination }) => { setPage(changedPage); }} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx new file mode 100644 index 00000000000000..585500db77e14f --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx @@ -0,0 +1,228 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import React, { useState } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiButton, EuiButtonEmpty, EuiFormRow, EuiPopover } from '@elastic/eui'; + +import { AlertTableItem } from '../../../../types'; +import { useAppDependencies } from '../../../index'; +import { + deleteAlerts, + disableAlerts, + enableAlerts, + muteAlerts, + unmuteAlerts, +} from '../../../lib/api'; + +export interface ComponentOpts { + selectedItems: AlertTableItem[]; + onPerformingAction: () => void; + onActionPerformed: () => void; +} + +export const BulkActionPopover: React.FunctionComponent = ({ + selectedItems, + onPerformingAction, + onActionPerformed, +}: ComponentOpts) => { + const { + core: { http }, + plugins: { toastNotifications }, + } = useAppDependencies(); + + const selectionContainsEnabledAlerts = selectedItems.some(isAlertEnabled); + const selectionContainsDisabledAlerts = selectedItems.some(isAlertDisabled); + const selectedContainsUnmutedAlerts = selectedItems.some(isAlertUnmuted); + const selectionContainsMutedAlerts = selectedItems.some(isAlertOrInstancesMuted); + + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + async function onmMuteAllClick() { + setIsPopoverOpen(false); + onPerformingAction(); + const ids = selectedItems.filter(isAlertUnmuted).map(item => item.id); + try { + await muteAlerts({ http, ids }); + } catch (e) { + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.bulkActionPopover.failedToMuteAlertsMessage', + { + defaultMessage: 'Failed to mute alert(s)', + } + ), + }); + } finally { + onActionPerformed(); + } + } + + async function onUnmuteAllClick() { + setIsPopoverOpen(false); + onPerformingAction(); + const ids = selectedItems.filter(isAlertOrInstancesMuted).map(item => item.id); + try { + await unmuteAlerts({ http, ids }); + } catch (e) { + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.bulkActionPopover.failedToUnmuteAlertsMessage', + { + defaultMessage: 'Failed to unmute alert(s)', + } + ), + }); + } finally { + onActionPerformed(); + } + } + + async function onEnableAllClick() { + setIsPopoverOpen(false); + onPerformingAction(); + const ids = selectedItems.filter(isAlertDisabled).map(item => item.id); + try { + await enableAlerts({ http, ids }); + } catch (e) { + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.bulkActionPopover.failedToEnableAlertsMessage', + { + defaultMessage: 'Failed to enable alert(s)', + } + ), + }); + } finally { + onActionPerformed(); + } + } + + async function onDisableAllClick() { + setIsPopoverOpen(false); + onPerformingAction(); + const ids = selectedItems.filter(isAlertEnabled).map(item => item.id); + try { + await disableAlerts({ http, ids }); + } catch (e) { + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.bulkActionPopover.failedToDisableAlertsMessage', + { + defaultMessage: 'Failed to disable alert(s)', + } + ), + }); + } finally { + onActionPerformed(); + } + } + + async function deleteSelectedItems() { + setIsPopoverOpen(false); + onPerformingAction(); + const ids = selectedItems.map(item => item.id); + try { + await deleteAlerts({ http, ids }); + } catch (e) { + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.bulkActionPopover.failedToDeleteAlertsMessage', + { + defaultMessage: 'Failed to delete alert(s)', + } + ), + }); + } finally { + onActionPerformed(); + } + } + + return ( + setIsPopoverOpen(false)} + button={ + setIsPopoverOpen(!isPopoverOpen)} + > + + + } + > + {selectedContainsUnmutedAlerts && ( + + + + + + )} + {selectionContainsMutedAlerts && ( + + + + + + )} + {selectionContainsDisabledAlerts && ( + + + + + + )} + {selectionContainsEnabledAlerts && ( + + + + + + )} + + + + + + + ); +}; + +function isAlertEnabled(alert: AlertTableItem) { + return alert.enabled === true; +} + +function isAlertDisabled(alert: AlertTableItem) { + return alert.enabled === false; +} + +function isAlertUnmuted(alert: AlertTableItem) { + return alert.muteAll === false; +} + +function isAlertOrInstancesMuted(alert: AlertTableItem) { + return alert.muteAll === true || alert.mutedInstanceIds.length > 0; +} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx index 6251e04a84a0c8..5c1cd754d1a707 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx @@ -20,20 +20,20 @@ import { AlertTableItem } from '../../../../types'; import { useAppDependencies } from '../../../index'; import { deleteAlerts, - disableAlert, - enableAlert, - muteAllAlertInstances, - unmuteAllAlertInstances, + disableAlerts, + enableAlerts, + muteAlerts, + unmuteAlerts, } from '../../../lib/api'; export interface ComponentOpts { item: AlertTableItem; - onDeleted: () => void; + onAlertChanged: () => void; } export const CollapsedItemActions: React.FunctionComponent = ({ item, - onDeleted, + onAlertChanged, }: ComponentOpts) => { const { core: { http }, @@ -66,14 +66,15 @@ export const CollapsedItemActions: React.FunctionComponent = ({ name="enable" disabled={!canSave} checked={isEnabled} - onChange={() => { + onChange={async () => { if (isEnabled) { - disableAlert({ http, id: item.id }); setIsEnabled(false); - return; + await disableAlerts({ http, ids: [item.id] }); + } else { + setIsEnabled(true); + await enableAlerts({ http, ids: [item.id] }); } - enableAlert({ http, id: item.id }); - setIsEnabled(true); + onAlertChanged(); }} label={ = ({ name="mute" checked={isMuted} disabled={!canSave || !isEnabled} - onChange={() => { + onChange={async () => { if (isMuted) { - unmuteAllAlertInstances({ http, id: item.id }); setIsMuted(false); - return; + await unmuteAlerts({ http, ids: [item.id] }); + } else { + setIsMuted(true); + await muteAlerts({ http, ids: [item.id] }); } - muteAllAlertInstances({ http, id: item.id }); - setIsMuted(true); + onAlertChanged(); }} label={ = ({ color="text" onClick={async () => { await deleteAlerts({ http, ids: [item.id] }); - onDeleted(); + onAlertChanged(); }} > Date: Tue, 26 Nov 2019 14:11:55 -0500 Subject: [PATCH 133/297] Update home title spacing --- .../np_ready/public/application/home.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx index 36dbc3179fb291..a904cba1fef602 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx @@ -12,6 +12,8 @@ import { EuiFlexItem, EuiPageBody, EuiPageContent, + EuiPageContentHeader, + EuiPageContentHeaderSection, EuiSpacer, EuiTab, EuiTabs, @@ -84,18 +86,19 @@ export const TriggersActionsUIHome: React.FunctionComponent - - - + + +

-
-
-
+ + + + {tabs.map(tab => ( Date: Tue, 26 Nov 2019 11:43:38 -0800 Subject: [PATCH 134/297] Fixed editing secrets action property --- .../np_ready/public/application/lib/api.ts | 2 +- .../action_form/action_add_flyout.tsx | 4 +- .../action_form/action_edit_flyout.tsx | 9 +- .../sections/action_form/action_type_menu.tsx | 2 +- .../buildin_action_types/email.tsx | 123 +++++++++-------- .../buildin_action_types/pagerduty.tsx | 57 ++++---- .../buildin_action_types/slack.tsx | 6 +- .../buildin_action_types/webhook.tsx | 124 +++++++++--------- 8 files changed, 162 insertions(+), 165 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts index 6adbe9297b38cf..15de72f4246451 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts @@ -81,7 +81,7 @@ export async function updateAction({ id: string; }): Promise { return http.put(`${BASE_ACTION_API_PATH}/${id}`, { - body: JSON.stringify({ ...action, id: undefined, actionTypeId: undefined, secrets: undefined }), + body: JSON.stringify({ ...action, id: undefined, actionTypeId: undefined }), }); } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_add_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_add_flyout.tsx index bbfc82b5700402..44cf591301ac93 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_add_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_add_flyout.tsx @@ -26,7 +26,9 @@ export const ActionAddFlyout = () => { const closeFlyout = useCallback(() => setAddFlyoutVisibility(false), [setAddFlyoutVisibility]); useEffect(() => { - setActionType(undefined); + if (addFlyoutVisible) { + setActionType(undefined); + } }, [addFlyoutVisible]); if (!addFlyoutVisible) { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_edit_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_edit_flyout.tsx index e275a2116fa3d3..d54617683548bf 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_edit_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_edit_flyout.tsx @@ -36,7 +36,8 @@ export const ActionEditFlyout = () => { const closeFlyout = useCallback(() => setEditFlyoutVisibility(false), [setEditFlyoutVisibility]); useEffect(() => { - if (editedActionItem && editedActionItem.id) { + setAction(undefined); + if (editFlyoutVisible && editedActionItem && editedActionItem.id) { loadActionById(editedActionItem.id); } // eslint-disable-next-line react-hooks/exhaustive-deps @@ -46,7 +47,7 @@ export const ActionEditFlyout = () => { setIsLoadingAction(true); try { const actionResponse = await getActionById({ id: actionItemId, http }); - setAction(actionResponse); + setAction({ ...actionResponse, secrets: {} }); } catch (e) { toastNotifications.addDanger({ title: i18n.translate( @@ -61,7 +62,7 @@ export const ActionEditFlyout = () => { } } - if (!editFlyoutVisible) { + if (!editFlyoutVisible && !action) { return null; } @@ -100,7 +101,7 @@ export const ActionEditFlyout = () => { ) : ( diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_type_menu.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_type_menu.tsx index 7135b965c75c35..4ba004e41a4306 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_type_menu.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_type_menu.tsx @@ -42,7 +42,7 @@ export const ActionTypeMenu = ({ setActionType }: Props) => { }; }); - const cardNodes = actionTypes.map(function(item, index): any { + const cardNodes = actionTypes.map((item, index): any => { return ( = ({ hasErrors, }) => { const { from, host, port } = action.config; + const { user, password } = action.secrets; return ( @@ -229,70 +230,68 @@ const EmailActionFields: React.FunctionComponent = ({ - {action.secrets ? ( - - - + + + { + editActionSecrets('user', e.target.value); + }} + onBlur={() => { + if (!user) { + editActionSecrets('user', ''); } - )} - > - { - editActionSecrets('user', e.target.value); - }} - onBlur={() => { - if (!action.secrets.user) { - editActionSecrets('user', ''); - } - }} - /> - - - - + + + + + { + editActionSecrets('password', e.target.value); + }} + onBlur={() => { + if (!password) { + editActionSecrets('password', ''); } - )} - > - { - editActionSecrets('password', e.target.value); - }} - onBlur={() => { - if (!action.secrets.password) { - editActionSecrets('password', ''); - } - }} - /> - - - - ) : null} + }} + /> + + + ); }; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/pagerduty.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/pagerduty.tsx index 6c21b0cf21d26f..4a5bb0de35e0dc 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/pagerduty.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/pagerduty.tsx @@ -32,7 +32,7 @@ export function getActionType(): ActionTypeModel { apiUrl: new Array(), }; validationResult.errors = errors; - if (action.secrets && !action.secrets.routingKey) { + if (!action.secrets.routingKey) { errors.routingKey.push( i18n.translate( 'xpack.triggersActionsUI.sections.actionAdd.pagerDutyAction.error.requiredRoutingKeyText', @@ -71,6 +71,7 @@ const PagerDutyActionFields: React.FunctionComponent = ({ editActionSecrets, }) => { const { apiUrl } = action.config; + const { routingKey } = action.secrets; return ( = ({ }} /> - {action.secrets ? ( - + ) => { + editActionSecrets('routingKey', e.target.value); + }} + onBlur={() => { + if (!routingKey) { + editActionSecrets('routingKey', ''); } - )} - > - ) => { - editActionSecrets('routingKey', e.target.value); - }} - onBlur={() => { - if (!action.secrets.routingKey) { - editActionSecrets('routingKey', ''); - } - }} - /> - - ) : null} + }} + /> + ); }; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/slack.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/slack.tsx index 816e0e5d2b6b1f..37af24175217b8 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/slack.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/slack.tsx @@ -31,7 +31,7 @@ export function getActionType(): ActionTypeModel { webhookUrl: new Array(), }; validationResult.errors = errors; - if (action.secrets && !action.secrets.webhookUrl) { + if (!action.secrets.webhookUrl) { errors.webhookUrl.push( i18n.translate( 'xpack.triggersActionsUI.sections.actionAdd.slackAction.error.requiredWebhookUrlText', @@ -58,10 +58,6 @@ const SlackActionFields: React.FunctionComponent = ({ errors, hasErrors, }) => { - if (!action.secrets) { - return null; - } - const { webhookUrl } = action.secrets; return ( diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/webhook.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/webhook.tsx index 5b1403a3ae93e3..cae6c6c3a203e3 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/webhook.tsx @@ -71,7 +71,7 @@ export function getActionType(): ActionTypeModel { ) ); } - if (action.secrets && !action.secrets.user) { + if (!action.secrets.user) { errors.user.push( i18n.translate( 'xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredHostText', @@ -81,7 +81,7 @@ export function getActionType(): ActionTypeModel { ) ); } - if (action.secrets && !action.secrets.password) { + if (!action.secrets.password) { errors.password.push( i18n.translate( 'xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredPasswordText', @@ -113,6 +113,7 @@ const WebhookActionFields: React.FunctionComponent = ({ const [headerValue, setHeaderValue] = useState(''); const [hasHeaders, setHasHeaders] = useState(false); + const { user, password } = action.secrets; const { method, url, headers } = action.config; editActionConfig('method', 'post'); // set method to POST by default @@ -281,70 +282,69 @@ const WebhookActionFields: React.FunctionComponent = ({ - {action.secrets ? ( - - - + + + { + editActionSecrets('user', e.target.value); + }} + onBlur={() => { + if (!user) { + editActionSecrets('user', ''); } - )} - > - { - editActionSecrets('user', e.target.value); - }} - onBlur={() => { - if (!action.secrets.user) { - editActionSecrets('user', ''); - } - }} - /> - - - - + + + + + { + editActionSecrets('password', e.target.value); + }} + onBlur={() => { + if (!password) { + editActionSecrets('password', ''); } - )} - > - { - editActionSecrets('password', e.target.value); - }} - onBlur={() => { - if (!action.secrets.password) { - editActionSecrets('password', ''); - } - }} - /> - - - - ) : null} + }} + /> + + + + Date: Tue, 26 Nov 2019 16:49:08 -0500 Subject: [PATCH 135/297] Changing behaviour of bulk actions and disable buttons during request --- .../alerts_list/components/alerts_list.tsx | 32 ++++--- .../components/bulk_action_popover.tsx | 88 ++++++++++++------- 2 files changed, 70 insertions(+), 50 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 3896ff82541a20..8816552d776a7f 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -27,7 +27,7 @@ export const AlertsList: React.FunctionComponent = () => { const [alertTypesIndex, setAlertTypesIndex] = useState(undefined); const [alerts, setAlerts] = useState([]); const [data, setData] = useState([]); - const [selectedItems, setSelectedItems] = useState([]); + const [selectedIds, setSelectedIds] = useState([]); const [isLoadingAlertTypes, setIsLoadingAlertTypes] = useState(false); const [isLoadingAlerts, setIsLoadingAlerts] = useState(false); const [isPerformingAction, setIsPerformingAction] = useState(false); @@ -41,19 +41,6 @@ export const AlertsList: React.FunctionComponent = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [page, searchText]); - // The bulk action menu needs updated data within "selectedItems" when "data" changes - useEffect(() => { - const updatedSelectedItems: AlertTableItem[] = []; - selectedItems.forEach(item => { - const updatedItem = data.find(({ id }) => item.id === id); - if (updatedItem) { - updatedSelectedItems.push(updatedItem); - } - }); - setSelectedItems(updatedSelectedItems); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [data]); - useEffect(() => { (async () => { try { @@ -189,11 +176,11 @@ export const AlertsList: React.FunctionComponent = () => { }, ]} toolsLeft={ - selectedItems.length === 0 || !canDelete + selectedIds.length === 0 || !canDelete ? [] : [ setIsPerformingAction(true)} onActionPerformed={() => { loadAlertsData(); @@ -242,7 +229,7 @@ export const AlertsList: React.FunctionComponent = () => { selection={ canDelete && { onSelectionChange(updatedSelectedItemsList: AlertTableItem[]) { - setSelectedItems(updatedSelectedItemsList); + setSelectedIds(updatedSelectedItemsList.map(item => item.id)); }, } } @@ -256,3 +243,14 @@ export const AlertsList: React.FunctionComponent = () => {
); }; + +function pickFromData(data: AlertTableItem[], ids: string[]): AlertTableItem[] { + const result: AlertTableItem[] = []; + for (const id of ids) { + const match = data.find(item => item.id === id); + if (match) { + result.push(match); + } + } + return result; +} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx index 585500db77e14f..42a294fe377d78 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx @@ -5,7 +5,7 @@ */ import { i18n } from '@kbn/i18n'; -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButton, EuiButtonEmpty, EuiFormRow, EuiPopover } from '@elastic/eui'; @@ -35,17 +35,22 @@ export const BulkActionPopover: React.FunctionComponent = ({ plugins: { toastNotifications }, } = useAppDependencies(); - const selectionContainsEnabledAlerts = selectedItems.some(isAlertEnabled); - const selectionContainsDisabledAlerts = selectedItems.some(isAlertDisabled); - const selectedContainsUnmutedAlerts = selectedItems.some(isAlertUnmuted); - const selectionContainsMutedAlerts = selectedItems.some(isAlertOrInstancesMuted); - const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const [isMutingAlerts, setIsMutingAlerts] = useState(false); + const [isUnmutingAlerts, setIsUnmutingAlerts] = useState(false); + const [isEnablingAlerts, setIsEnablingAlerts] = useState(false); + const [isDisablingAlerts, setIsDisablingAlerts] = useState(false); + const [isDeletingAlerts, setIsDeletingAlerts] = useState(false); + + const allAlertsMuted = selectedItems.every(isAlertMuted); + const allAlertsDisabled = selectedItems.every(isAlertDisabled); + const isPerformingAction = + isMutingAlerts || isUnmutingAlerts || isEnablingAlerts || isDisablingAlerts || isDeletingAlerts; async function onmMuteAllClick() { - setIsPopoverOpen(false); onPerformingAction(); - const ids = selectedItems.filter(isAlertUnmuted).map(item => item.id); + setIsMutingAlerts(true); + const ids = selectedItems.filter(item => !isAlertMuted(item)).map(item => item.id); try { await muteAlerts({ http, ids }); } catch (e) { @@ -58,14 +63,15 @@ export const BulkActionPopover: React.FunctionComponent = ({ ), }); } finally { + setIsMutingAlerts(false); onActionPerformed(); } } async function onUnmuteAllClick() { - setIsPopoverOpen(false); onPerformingAction(); - const ids = selectedItems.filter(isAlertOrInstancesMuted).map(item => item.id); + setIsUnmutingAlerts(true); + const ids = selectedItems.filter(isAlertMuted).map(item => item.id); try { await unmuteAlerts({ http, ids }); } catch (e) { @@ -78,13 +84,14 @@ export const BulkActionPopover: React.FunctionComponent = ({ ), }); } finally { + setIsUnmutingAlerts(false); onActionPerformed(); } } async function onEnableAllClick() { - setIsPopoverOpen(false); onPerformingAction(); + setIsEnablingAlerts(true); const ids = selectedItems.filter(isAlertDisabled).map(item => item.id); try { await enableAlerts({ http, ids }); @@ -98,14 +105,15 @@ export const BulkActionPopover: React.FunctionComponent = ({ ), }); } finally { + setIsEnablingAlerts(false); onActionPerformed(); } } async function onDisableAllClick() { - setIsPopoverOpen(false); onPerformingAction(); - const ids = selectedItems.filter(isAlertEnabled).map(item => item.id); + setIsDisablingAlerts(true); + const ids = selectedItems.filter(item => !isAlertDisabled(item)).map(item => item.id); try { await disableAlerts({ http, ids }); } catch (e) { @@ -118,13 +126,14 @@ export const BulkActionPopover: React.FunctionComponent = ({ ), }); } finally { + setIsDisablingAlerts(false); onActionPerformed(); } } async function deleteSelectedItems() { - setIsPopoverOpen(false); onPerformingAction(); + setIsDeletingAlerts(true); const ids = selectedItems.map(item => item.id); try { await deleteAlerts({ http, ids }); @@ -138,6 +147,7 @@ export const BulkActionPopover: React.FunctionComponent = ({ ), }); } finally { + setIsDeletingAlerts(false); onActionPerformed(); } } @@ -159,9 +169,13 @@ export const BulkActionPopover: React.FunctionComponent = ({ } > - {selectedContainsUnmutedAlerts && ( + {!allAlertsMuted && ( - + = ({ )} - {selectionContainsMutedAlerts && ( + {allAlertsMuted && ( - + = ({ )} - {selectionContainsDisabledAlerts && ( + {allAlertsDisabled && ( - + = ({ )} - {selectionContainsEnabledAlerts && ( + {!allAlertsDisabled && ( - + = ({ )} - + = ({ ); }; -function isAlertEnabled(alert: AlertTableItem) { - return alert.enabled === true; -} - function isAlertDisabled(alert: AlertTableItem) { return alert.enabled === false; } -function isAlertUnmuted(alert: AlertTableItem) { - return alert.muteAll === false; -} - -function isAlertOrInstancesMuted(alert: AlertTableItem) { - return alert.muteAll === true || alert.mutedInstanceIds.length > 0; +function isAlertMuted(alert: AlertTableItem) { + return alert.muteAll === true; } From 01dcba6b5e570c9a831020515418f379e4b1db2d Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 26 Nov 2019 17:19:19 -0800 Subject: [PATCH 136/297] Refactored plugin definition with appdependency interface --- .../np_ready/public/application/index.tsx | 15 ++----- .../np_ready/public/plugin.ts | 45 ++++++++++--------- 2 files changed, 26 insertions(+), 34 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/index.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/index.tsx index 32a7d580f3102f..3cdddf999e1c08 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/index.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/index.tsx @@ -7,12 +7,9 @@ import React, { createContext, useContext, ReactNode } from 'react'; import { HashRouter } from 'react-router-dom'; import { render } from 'react-dom'; -import { CoreStart } from 'src/core/public'; import { App } from './app'; -import { AppDependencies, AppPlugins } from '../../../public/shim'; -import { ActionTypeRegistry } from './action_type_registry'; -import { AlertTypeRegistry } from './alert_type_registry'; +import { AppDependencies } from '../../../public/shim'; export { BASE_PATH as CLIENT_BASE_PATH } from './constants'; @@ -51,14 +48,8 @@ const getAppProviders = (deps: AppDependencies) => { ); }; -export const renderReact = async ( - elem: HTMLElement | null, - core: CoreStart, - plugins: AppPlugins, - actionTypeRegistry: ActionTypeRegistry, - alertTypeRegistry: AlertTypeRegistry -) => { - const Providers = getAppProviders({ core, plugins, actionTypeRegistry, alertTypeRegistry }); +export const renderReact = async (elem: HTMLElement, appDependencies: AppDependencies) => { + const Providers = getAppProviders(appDependencies); render( diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts index c320dbcc9b11d4..89d4b620f1dc5b 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts @@ -32,10 +32,16 @@ export type Start = void; const REACT_ROOT_ID = 'triggersActionsRoot'; export class Plugin implements CorePlugin { - private actionTypeRegistry?: ActionTypeRegistry; - private alertTypeRegistry?: AlertTypeRegistry; + private actionTypeRegistry: ActionTypeRegistry; + private alertTypeRegistry: AlertTypeRegistry; - constructor(initializerContext: PluginInitializerContext) {} + constructor(initializerContext: PluginInitializerContext) { + const actionTypeRegistry = new ActionTypeRegistry(); + this.actionTypeRegistry = actionTypeRegistry; + + const alertTypeRegistry = new AlertTypeRegistry(); + this.alertTypeRegistry = alertTypeRegistry; + } public setup(core: CoreSetup, plugins: any): Setup { /* @@ -52,23 +58,17 @@ export class Plugin implements CorePlugin { const canShowActions = capabilities.get().actions.show; const canShowAlerts = capabilities.get().alerting.show; if (canShowActions || canShowAlerts) { - const actionTypeRegistry = new ActionTypeRegistry(); - this.actionTypeRegistry = actionTypeRegistry; - - const alertTypeRegistry = new AlertTypeRegistry(); - this.alertTypeRegistry = alertTypeRegistry; - registerBuiltInActionTypes({ - actionTypeRegistry, + actionTypeRegistry: this.actionTypeRegistry, }); registerAlertTypes({ - alertTypeRegistry, + alertTypeRegistry: this.alertTypeRegistry, }); const kbnSection = getSection('kibana'); kbnSection.register('triggersActions', { - display: i18n.translate('xpack.alertingUI.managementSection.displayName', { + display: i18n.translate('xpack.triggersActionsUI.managementSection.displayName', { defaultMessage: 'Triggers and Actions', }), order: 7, @@ -81,6 +81,13 @@ export class Plugin implements CorePlugin { const { capabilities } = plugins; const canShowActions = capabilities.get().actions.show; const canShowAlerts = capabilities.get().alerting.show; + // AppCore/AppPlugins to be passed on as React context + const AppDependencies = { + core, + plugins, + actionTypeRegistry: this.actionTypeRegistry, + alertTypeRegistry: this.alertTypeRegistry, + }; // Don't register routes when user doesn't have access to the application if (!canShowActions && !canShowAlerts) { @@ -107,11 +114,11 @@ export class Plugin implements CorePlugin { const currentRoute = $route.current; const isNavigationInApp = currentRoute.$$route.template === appRoute.$$route.template; - // When we navigate within SR, prevent Angular from re-matching the route and rebuild the app + // When we navigate within Transform, prevent Angular from re-matching the route and rebuild the app if (isNavigationInApp) { $route.current = appRoute; } else { - // Any clean up when user leaves SR + // Any clean up when user leaves Transform } $scope.$on('$destroy', () => { @@ -125,14 +132,8 @@ export class Plugin implements CorePlugin { $scope.$$postDigest(() => { unmountReactApp(); const elReactRoot = document.getElementById(REACT_ROOT_ID); - if (elReactRoot && this.actionTypeRegistry && this.alertTypeRegistry) { - renderReact( - elReactRoot, - core, - plugins, - this.actionTypeRegistry, - this.alertTypeRegistry - ); + if (elReactRoot) { + renderReact(elReactRoot, AppDependencies); } }); }; From 13372fa7aaff26255ad6710ae9a64207d7f09c40 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 26 Nov 2019 17:53:29 -0800 Subject: [PATCH 137/297] Moved add dependencies to the separate file --- .../public/application/app_dependencies.tsx | 41 ++++++++++++++++++ .../np_ready/public/application/home.tsx | 4 +- .../np_ready/public/application/index.tsx | 42 +------------------ .../action_form/action_add_flyout.tsx | 2 +- .../action_form/action_edit_flyout.tsx | 2 +- .../sections/action_form/action_form.tsx | 4 +- .../sections/action_form/action_reducer.ts | 2 +- .../sections/action_form/action_type_menu.tsx | 2 +- .../actions_list/components/actions_list.tsx | 2 +- .../sections/alert_add/alert_add.tsx | 2 +- .../alert_types/threshold/expression.tsx | 2 +- .../alert_types/threshold/visualization.tsx | 2 +- .../alerts_list/components/alerts_list.tsx | 2 +- .../components/bulk_action_popover.tsx | 2 +- .../components/collapsed_item_actions.tsx | 2 +- .../np_ready/public/types.ts | 4 +- 16 files changed, 59 insertions(+), 58 deletions(-) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app_dependencies.tsx diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app_dependencies.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app_dependencies.tsx new file mode 100644 index 00000000000000..dd2746e115f4b0 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app_dependencies.tsx @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { createContext, useContext, ReactNode } from 'react'; +import { HashRouter } from 'react-router-dom'; +import { AppDependencies } from '../../../public/shim'; + +let DependenciesContext: React.Context; + +export const setAppDependencies = (deps: AppDependencies) => { + DependenciesContext = createContext(deps); + return DependenciesContext.Provider; +}; + +export const useAppDependencies = () => { + if (!DependenciesContext) { + throw new Error(`The app dependencies Context hasn't been set. + Use the "setAppDependencies()" method when bootstrapping the app.`); + } + return useContext(DependenciesContext); +}; + +export const getAppProviders = (deps: AppDependencies) => { + const { + i18n: { Context: I18nContext }, + } = deps.core; + + // Create App dependencies context and get its provider + const AppDependenciesProvider = setAppDependencies(deps); + + return ({ children }: { children: ReactNode }) => ( + + + {children} + + + ); +}; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx index a904cba1fef602..07f4fc265e7eab 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx @@ -8,8 +8,6 @@ import React, { useEffect } from 'react'; import { Route, RouteComponentProps, Switch } from 'react-router-dom'; import { FormattedMessage } from '@kbn/i18n/react'; import { - EuiFlexGroup, - EuiFlexItem, EuiPageBody, EuiPageContent, EuiPageContentHeader, @@ -23,7 +21,7 @@ import { import { BASE_PATH, Section, routeToConnectors, routeToAlerts } from './constants'; import { breadcrumbService } from './lib/breadcrumb'; import { docTitleService } from './lib/doc_title'; -import { useAppDependencies } from './index'; +import { useAppDependencies } from './app_dependencies'; import { ActionsList } from './sections/actions_list/components/actions_list'; import { AlertsList } from './sections/alerts_list/components/alerts_list'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/index.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/index.tsx index 3cdddf999e1c08..fec6be07f16f35 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/index.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/index.tsx @@ -4,49 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { createContext, useContext, ReactNode } from 'react'; -import { HashRouter } from 'react-router-dom'; +import React from 'react'; import { render } from 'react-dom'; import { App } from './app'; - import { AppDependencies } from '../../../public/shim'; - -export { BASE_PATH as CLIENT_BASE_PATH } from './constants'; - -/** - * App dependencies - */ -let DependenciesContext: React.Context; - -export const setAppDependencies = (deps: AppDependencies) => { - DependenciesContext = createContext(deps); - return DependenciesContext.Provider; -}; - -export const useAppDependencies = () => { - if (!DependenciesContext) { - throw new Error(`The app dependencies Context hasn't been set. - Use the "setAppDependencies()" method when bootstrapping the app.`); - } - return useContext(DependenciesContext); -}; - -const getAppProviders = (deps: AppDependencies) => { - const { - i18n: { Context: I18nContext }, - } = deps.core; - - // Create App dependencies context and get its provider - const AppDependenciesProvider = setAppDependencies(deps); - - return ({ children }: { children: ReactNode }) => ( - - - {children} - - - ); -}; +import { getAppProviders } from './app_dependencies'; export const renderReact = async (elem: HTMLElement, appDependencies: AppDependencies) => { const Providers = getAppProviders(appDependencies); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_add_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_add_flyout.tsx index 44cf591301ac93..4e1c4b6a32c028 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_add_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_add_flyout.tsx @@ -17,7 +17,7 @@ import { ActionsContext } from '../../context/actions_context'; import { ActionTypeMenu } from './action_type_menu'; import { ActionForm } from './action_form'; import { ActionType } from '../../../types'; -import { useAppDependencies } from '../..'; +import { useAppDependencies } from '../../app_dependencies'; export const ActionAddFlyout = () => { const { actionTypeRegistry } = useAppDependencies(); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_edit_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_edit_flyout.tsx index d54617683548bf..af7380898ec0b8 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_edit_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_edit_flyout.tsx @@ -16,7 +16,7 @@ import { import { i18n } from '@kbn/i18n'; import { ActionsContext } from '../../context/actions_context'; import { ActionForm } from './action_form'; -import { useAppDependencies } from '../..'; +import { useAppDependencies } from '../../app_dependencies'; import { getActionById } from '../../lib/api'; import { Action } from '../../../types'; import { SectionLoading } from '../../components/section_loading'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_form.tsx index cc5b450aa84e0c..b95089febd38a6 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_form.tsx @@ -22,13 +22,13 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { createAction, updateAction } from '../../lib/api'; import { SectionError, ErrableFormRow } from '../../components/page_error'; -import { useAppDependencies } from '../..'; +import { useAppDependencies } from '../../app_dependencies'; import { actionReducer } from './action_reducer'; import { ActionsContext } from '../../context/actions_context'; import { Action, IErrorObject } from '../../../types'; interface Props { - initialAction: Action; + initialAction: any; actionTypeName: string; setFlyoutVisibility: React.Dispatch>; } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_reducer.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_reducer.ts index 1061f63088cde7..3b47bfbdb63dbe 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_reducer.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_reducer.ts @@ -17,7 +17,7 @@ export interface ActionReducerItem { command: CommandType; payload: { key: string; - value: {}; + value: any; }; } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_type_menu.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_type_menu.tsx index 4ba004e41a4306..9a7eac611fb581 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_type_menu.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_type_menu.tsx @@ -17,7 +17,7 @@ import { import { i18n } from '@kbn/i18n'; import { ActionType } from '../../../types'; import { ActionsContext } from '../../context/actions_context'; -import { useAppDependencies } from '../..'; +import { useAppDependencies } from '../../app_dependencies'; interface Props { setActionType: React.Dispatch>; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index fddcc2ef156082..124441d85708fa 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -9,7 +9,7 @@ import { EuiBadge, EuiInMemoryTable, EuiSpacer, EuiButton } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { ActionsContext } from '../../../context/actions_context'; -import { useAppDependencies } from '../../../index'; +import { useAppDependencies } from '../../../app_dependencies'; import { deleteActions, loadAllActions, loadActionTypes } from '../../../lib/api'; import { Action, ActionTableItem, ActionTypeIndex } from '../../../../types'; import { ActionAddFlyout, ActionEditFlyout } from '../../action_form'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 34a2a424c18b12..b08f05b382b867 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -34,7 +34,7 @@ import { EuiAccordion, EuiButtonIcon, } from '@elastic/eui'; -import { useAppDependencies } from '../..'; +import { useAppDependencies } from '../../app_dependencies'; import { saveAlert, loadActionTypes, loadAllActions } from '../../lib/api'; import { AlertsContext } from '../../context/alerts_context'; import { alertReducer } from './alert_reducer'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx index 7222705ca4037c..260f3a079821f7 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx @@ -29,7 +29,7 @@ import { getThresholdAlertTypeFields, loadIndexPatterns, } from '../../../../lib/api'; -import { useAppDependencies } from '../../../..'; +import { useAppDependencies } from '../../../../app_dependencies'; import { ErrableFormRow } from '../../../../components/page_error'; import { getTimeOptions, getTimeFieldOptions } from '../../../../lib/get_time_options'; import { getTimeUnitLabel } from '../../../../lib/get_time_unit_label'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx index f61b03e698965f..b4232619a8c66f 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx @@ -27,7 +27,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { npStart } from 'ui/new_platform'; import { getThresholdAlertVisualizationData } from '../../../../lib/api'; import { comparators, aggregationTypes } from './expression'; -import { useAppDependencies } from '../../../..'; +import { useAppDependencies } from '../../../../app_dependencies'; import { SectionError } from '../../../../components/page_error/section_error'; import { Alert } from '../../../../../types'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 8816552d776a7f..ad56f8aefa800e 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -10,7 +10,7 @@ import React, { Fragment, useEffect, useState } from 'react'; // @ts-ignore: EuiSearchBar not exported in TypeScript import { EuiBasicTable, EuiButton, EuiButtonEmpty, EuiSearchBar, EuiSpacer } from '@elastic/eui'; import { AlertsContext } from '../../../context/alerts_context'; -import { useAppDependencies } from '../../../index'; +import { useAppDependencies } from '../../../app_dependencies'; import { Alert, AlertTableItem, AlertTypeIndex, Pagination } from '../../../../types'; import { AlertAdd } from '../../alert_add'; import { BulkActionPopover } from './bulk_action_popover'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx index 42a294fe377d78..4877a7958762f9 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx @@ -10,7 +10,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButton, EuiButtonEmpty, EuiFormRow, EuiPopover } from '@elastic/eui'; import { AlertTableItem } from '../../../../types'; -import { useAppDependencies } from '../../../index'; +import { useAppDependencies } from '../../../app_dependencies'; import { deleteAlerts, disableAlerts, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx index 5c1cd754d1a707..9a911226cf7577 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx @@ -17,7 +17,7 @@ import { } from '@elastic/eui'; import { AlertTableItem } from '../../../../types'; -import { useAppDependencies } from '../../../index'; +import { useAppDependencies } from '../../../app_dependencies'; import { deleteAlerts, disableAlerts, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts index ce36393c99cac6..46e269078bb5fb 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts @@ -49,9 +49,9 @@ export interface ActionType { export interface Action { secrets: Record; - id?: string; + id: string; actionTypeId: string; - description?: string; + description: string; referencedByCount?: number; config: Record; } From c59868caa3ddd6ced2e164515ba735cb4743bd3b Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 26 Nov 2019 19:09:07 -0800 Subject: [PATCH 138/297] Enable visualization if only hasExpressionErrors passed --- .../sections/alert_add/alert_types/threshold/expression.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx index 260f3a079821f7..b6624785ee1762 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx @@ -1065,7 +1065,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = - {hasErrors ? null : ( + {hasExpressionErrors ? null : ( From dc9c442db6ab9592eb2ef28663f0f517ad321969 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 26 Nov 2019 20:49:26 -0800 Subject: [PATCH 139/297] Fixed add action twice on click card --- .../public/application/sections/alert_add/alert_add.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index b08f05b382b867..d5a7f51cf4a12a 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -61,6 +61,7 @@ function validateBaseProperties(alertObject: Alert) { name: new Array(), interval: new Array(), alertTypeId: new Array(), + actionConnectors: new Array(), }; validationResult.errors = errors; if (!alertObject.name) { @@ -312,9 +313,7 @@ export const AlertAdd = ({ refreshList }: Props) => { icon={} title={actionTypesIndex ? actionTypesIndex[item.id].name : item.name} description={''} - selectable={{ - onClick: () => addActionType(item.actionType), - }} + onClick={() => addActionType(item.actionType)} /> ); @@ -679,6 +678,7 @@ export const AlertAdd = ({ refreshList }: Props) => { { Date: Wed, 27 Nov 2019 08:58:08 -0500 Subject: [PATCH 140/297] Fix actions column in alert list --- .../sections/alerts_list/components/alerts_list.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index ad56f8aefa800e..db1d41e3f836c5 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -137,12 +137,8 @@ export const AlertsList: React.FunctionComponent = () => { truncateText: false, }, { - name: i18n.translate( - 'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.actions', - { - defaultMessage: 'Actions', - } - ), + name: '', + width: '40px', render(item: AlertTableItem) { return ( loadAlertsData()} /> From fcc6e4a5f1a1d542d84d27dd186f6e191c60d8fe Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 27 Nov 2019 09:33:29 -0800 Subject: [PATCH 141/297] Fixed action canSave capability --- .../sections/actions_list/components/actions_list.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx index 124441d85708fa..bae474d059fab0 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx @@ -20,7 +20,7 @@ export const ActionsList: React.FunctionComponent = () => { plugins: { capabilities, toastNotifications }, } = useAppDependencies(); const canDelete = capabilities.get().actions.delete; - const canEdit = capabilities.get().actions.delete; + const canSave = capabilities.get().actions.save; const [actionTypesIndex, setActionTypesIndex] = useState(undefined); const [actions, setActions] = useState([]); @@ -178,12 +178,12 @@ export const ActionsList: React.FunctionComponent = () => { name: '', actions: [ { - enabled: () => canEdit, + enabled: () => canSave, name: i18n.translate( 'xpack.triggersActionsUI.sections.actionsList.actionsListTable.columns.actions.editActionName', { defaultMessage: 'Edit' } ), - description: canEdit + description: canSave ? i18n.translate( 'xpack.triggersActionsUI.sections.actionsList.actionsListTable.columns.actions.editActionDescription', { defaultMessage: 'Edit this action' } From ee041447b6504bce79db5f0631550385095d31aa Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 27 Nov 2019 11:18:17 -0800 Subject: [PATCH 142/297] Renamed Actions to ActionConnectors in appropriate UI files --- .../buildin_action_types/email.tsx | 81 ++++++++++++------- .../buildin_action_types/es_index.tsx | 26 +++--- .../buildin_action_types/index.ts | 2 +- .../buildin_action_types/pagerduty.tsx | 40 ++++----- .../buildin_action_types/server_log.tsx | 14 ++-- .../buildin_action_types/slack.tsx | 22 ++--- .../buildin_action_types/webhook.tsx | 38 ++++----- ...ext.tsx => actions_connectors_context.tsx} | 4 +- .../np_ready/public/application/home.tsx | 6 +- .../np_ready/public/application/lib/api.ts | 26 +++--- .../action_connector_form.tsx} | 40 ++++----- .../action_type_menu.tsx | 4 +- .../connector_add_flyout.tsx} | 10 +-- .../connector_edit_flyout.tsx} | 14 ++-- .../connector_reducer.ts} | 40 ++++----- .../index.ts | 4 +- .../components/actions_connectors_list.tsx} | 20 ++--- .../sections/alert_add/alert_add.tsx | 7 +- .../sections/alert_add/alert_reducer.ts | 4 +- .../np_ready/public/plugin.ts | 2 +- .../np_ready/public/types.ts | 12 +-- 21 files changed, 226 insertions(+), 190 deletions(-) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/{sections/action_form => components}/buildin_action_types/email.tsx (86%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/{sections/action_form => components}/buildin_action_types/es_index.tsx (77%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/{sections/action_form => components}/buildin_action_types/index.ts (94%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/{sections/action_form => components}/buildin_action_types/pagerduty.tsx (83%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/{sections/action_form => components}/buildin_action_types/server_log.tsx (84%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/{sections/action_form => components}/buildin_action_types/slack.tsx (81%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/{sections/action_form => components}/buildin_action_types/webhook.tsx (87%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/{actions_context.tsx => actions_connectors_context.tsx} (83%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/{action_form/action_form.tsx => action_connector_form/action_connector_form.tsx} (86%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/{action_form => action_connector_form}/action_type_menu.tsx (95%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/{action_form/action_add_flyout.tsx => action_connector_form/connector_add_flyout.tsx} (90%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/{action_form/action_edit_flyout.tsx => action_connector_form/connector_edit_flyout.tsx} (89%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/{action_form/action_reducer.ts => action_connector_form/connector_reducer.ts} (63%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/{action_form => action_connector_form}/index.ts (66%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/{actions_list/components/actions_list.tsx => actions_connectors_list/components/actions_connectors_list.tsx} (94%) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/email.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/email.tsx similarity index 86% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/email.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/email.tsx index a57136eb41d4bd..104ac6599de6db 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/email.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/email.tsx @@ -14,26 +14,26 @@ import { EuiTextArea, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ErrableFormRow } from '../../../components/page_error'; +import { ErrableFormRow } from '../page_error'; import { ActionTypeModel, - Props, - Action, + ActionConnectorFieldsProps, + ActionConnector, ValidationResult, ActionParamsProps, -} from '../../../../types'; +} from '../../../types'; export function getActionType(): ActionTypeModel { return { id: '.email', iconClass: 'email', selectMessage: i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.emailAction.selectMessageText', + 'xpack.triggersActionsUI.components.buildin_action_types.emailAction.selectMessageText', { defaultMessage: 'Send an email.', } ), - validate: (action: Action): ValidationResult => { + validateConnector: (action: ActionConnector): ValidationResult => { const validationResult = { errors: {} }; const errors = { from: new Array(), @@ -45,37 +45,52 @@ export function getActionType(): ActionTypeModel { validationResult.errors = errors; if (!action.config.from) { errors.from.push( - i18n.translate('xpack.triggersActionsUI.sections.addAction.error.requiredFromText', { - defaultMessage: 'From is required.', - }) + i18n.translate( + 'xpack.triggersActionsUI.components.buildin_action_types.error.requiredFromText', + { + defaultMessage: 'From is required.', + } + ) ); } if (!action.config.port) { errors.port.push( - i18n.translate('xpack.triggersActionsUI.sections.addAction.error.requiredPortText', { - defaultMessage: 'Port is required.', - }) + i18n.translate( + 'xpack.triggersActionsUI.components.buildin_action_types.error.requiredPortText', + { + defaultMessage: 'Port is required.', + } + ) ); } if (!action.config.host) { errors.host.push( - i18n.translate('xpack.triggersActionsUI.sections.addAction.error.requiredHostText', { - defaultMessage: 'Host is required.', - }) + i18n.translate( + 'xpack.triggersActionsUI.components.buildin_action_types.error.requiredHostText', + { + defaultMessage: 'Host is required.', + } + ) ); } if (!action.secrets.user) { errors.user.push( - i18n.translate('xpack.triggersActionsUI.sections.addAction.error.requiredUserText', { - defaultMessage: 'User is required.', - }) + i18n.translate( + 'xpack.triggersActionsUI.components.buildin_action_types.error.requiredUserText', + { + defaultMessage: 'User is required.', + } + ) ); } if (!action.secrets.password) { errors.password.push( - i18n.translate('xpack.triggersActionsUI.sections.addAction.error.requiredPasswordText', { - defaultMessage: 'Password is required.', - }) + i18n.translate( + 'xpack.triggersActionsUI.components.buildin_action_types.error.requiredPasswordText', + { + defaultMessage: 'Password is required.', + } + ) ); } return validationResult; @@ -97,7 +112,7 @@ export function getActionType(): ActionTypeModel { actionParams.bcc.length === 0 ) { const errorText = i18n.translate( - 'xpack.triggersActionsUI.sections.addAction.error.requiredEntryText', + 'xpack.triggersActionsUI.components.buildin_action_types.error.requiredEntryText', { defaultMessage: 'No [to], [cc], or [bcc] entries. At least one entry is required.', } @@ -108,26 +123,32 @@ export function getActionType(): ActionTypeModel { } if (!actionParams.message) { errors.message.push( - i18n.translate('xpack.triggersActionsUI.sections.addAction.error.requiredMessageText', { - defaultMessage: 'Message is required.', - }) + i18n.translate( + 'xpack.triggersActionsUI.components.buildin_action_types.error.requiredMessageText', + { + defaultMessage: 'Message is required.', + } + ) ); } if (!actionParams.subject) { errors.subject.push( - i18n.translate('xpack.triggersActionsUI.sections.addAction.error.requiredSubjectText', { - defaultMessage: 'Subject is required.', - }) + i18n.translate( + 'xpack.triggersActionsUI.components.buildin_action_types.error.requiredSubjectText', + { + defaultMessage: 'Subject is required.', + } + ) ); } return validationResult; }, - actionFields: EmailActionFields, + actionConnectorFields: EmailActionConnectorFields, actionParamsFields: EmailParamsFields, }; } -const EmailActionFields: React.FunctionComponent = ({ +const EmailActionConnectorFields: React.FunctionComponent = ({ action, editActionConfig, editActionSecrets, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/es_index.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/es_index.tsx similarity index 77% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/es_index.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/es_index.tsx index 1662ad1cab1cc9..03b4c72e34cbd2 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/es_index.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/es_index.tsx @@ -7,23 +7,28 @@ import React, { Fragment } from 'react'; import { EuiFieldText, EuiFormRow, EuiSwitch } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { ActionTypeModel, Props, ValidationResult, ActionParamsProps } from '../../../../types'; -import { ErrableFormRow } from '../../../components/page_error'; +import { + ActionTypeModel, + ActionConnectorFieldsProps, + ValidationResult, + ActionParamsProps, +} from '../../../types'; +import { ErrableFormRow } from '../page_error'; export function getActionType(): ActionTypeModel { return { id: '.index', iconClass: 'indexOpen', selectMessage: i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.indexAction.selectMessageText', + 'xpack.triggersActionsUI.components.buildin_action_types.indexAction.selectMessageText', { defaultMessage: 'Index data into Elasticsearch.', } ), - validate: (): ValidationResult => { + validateConnector: (): ValidationResult => { return { errors: {} }; }, - actionFields: IndexActionFields, + actionConnectorFields: IndexActionConnectorFields, actionParamsFields: IndexParamsFields, validateParams: (actionParams: any): ValidationResult => { const validationResult = { errors: {} }; @@ -32,13 +37,16 @@ export function getActionType(): ActionTypeModel { }; } -const IndexActionFields: React.FunctionComponent = ({ action, editActionConfig }) => { +const IndexActionConnectorFields: React.FunctionComponent = ({ + action, + editActionConfig, +}) => { const { index } = action.config; return ( = ({ errors={errors} isShowingErrors={hasErrors === true && action.index !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.indexAction.indexFieldLabel', + 'xpack.triggersActionsUI.components.buildin_action_types.indexAction.indexFieldLabel', { defaultMessage: 'Index', } @@ -108,7 +116,7 @@ const IndexParamsFields: React.FunctionComponent = ({ }} label={ } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/index.ts similarity index 94% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/index.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/index.ts index 28dd9a34955120..adab604330486e 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/index.ts @@ -10,7 +10,7 @@ import { getActionType as getEmailActionType } from './email'; import { getActionType as getIndexActionType } from './es_index'; import { getActionType as getPagerDutyActionType } from './pagerduty'; import { getActionType as getWebhookActionType } from './webhook'; -import { ActionTypeRegistry } from '../../../action_type_registry'; +import { ActionTypeRegistry } from '../../action_type_registry'; export function registerBuiltInActionTypes({ actionTypeRegistry, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/pagerduty.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/pagerduty.tsx similarity index 83% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/pagerduty.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/pagerduty.tsx index 4a5bb0de35e0dc..2ebf89e9f88393 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/pagerduty.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/pagerduty.tsx @@ -6,26 +6,26 @@ import React, { Fragment } from 'react'; import { EuiFieldText, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiSelect } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ErrableFormRow } from '../../../components/page_error'; +import { ErrableFormRow } from '../page_error'; import { ActionTypeModel, - Props, - Action, + ActionConnectorFieldsProps, + ActionConnector, ValidationResult, ActionParamsProps, -} from '../../../../types'; +} from '../../../types'; export function getActionType(): ActionTypeModel { return { id: '.pagerduty', iconClass: 'apps', selectMessage: i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.pagerDutyAction.selectMessageText', + 'xpack.triggersActionsUI.components.buildin_action_types.pagerDutyAction.selectMessageText', { defaultMessage: 'Create an event in PagerDuty.', } ), - validate: (action: Action): ValidationResult => { + validateConnector: (action: ActionConnector): ValidationResult => { const validationResult = { errors: {} }; const errors = { routingKey: new Array(), @@ -35,7 +35,7 @@ export function getActionType(): ActionTypeModel { if (!action.secrets.routingKey) { errors.routingKey.push( i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.pagerDutyAction.error.requiredRoutingKeyText', + 'xpack.triggersActionsUI.components.buildin_action_types.pagerDutyAction.error.requiredRoutingKeyText', { defaultMessage: 'Routing Key is required.', } @@ -45,7 +45,7 @@ export function getActionType(): ActionTypeModel { if (!action.config.apiUrl) { errors.apiUrl.push( i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.pagerDutyAction.error.requiredApiUrlText', + 'xpack.triggersActionsUI.components.buildin_action_types.pagerDutyAction.error.requiredApiUrlText', { defaultMessage: 'ApiUrl is required.', } @@ -58,12 +58,12 @@ export function getActionType(): ActionTypeModel { const validationResult = { errors: {} }; return validationResult; }, - actionFields: PagerDutyActionFields, + actionConnectorFields: PagerDutyActionConnectorFields, actionParamsFields: PagerDutyParamsFields, }; } -const PagerDutyActionFields: React.FunctionComponent = ({ +const PagerDutyActionConnectorFields: React.FunctionComponent = ({ errors, hasErrors, action, @@ -81,7 +81,7 @@ const PagerDutyActionFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors === true && apiUrl !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.pagerDutyAction.apiUrlTextFieldLabel', + 'xpack.triggersActionsUI.components.buildin_action_types.pagerDutyAction.apiUrlTextFieldLabel', { defaultMessage: 'ApiUrl', } @@ -109,7 +109,7 @@ const PagerDutyActionFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors === true && routingKey !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.pagerDutyAction.routingKeyTextFieldLabel', + 'xpack.triggersActionsUI.components.buildin_action_types.pagerDutyAction.routingKeyTextFieldLabel', { defaultMessage: 'RoutingKey', } @@ -160,7 +160,7 @@ const PagerDutyParamsFields: React.FunctionComponent = ({ = ({ = ({ = ({ = ({ = ({ = ({ = ({ errors={errors} isShowingErrors={hasErrors === true && summary !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.pagerDutyAction.summaryFieldLabel', + 'xpack.triggersActionsUI.components.buildin_action_types.pagerDutyAction.summaryFieldLabel', { defaultMessage: 'Summary', } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/server_log.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/server_log.tsx similarity index 84% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/server_log.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/server_log.tsx index 241c49e6de4155..2227ff864f9e64 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/server_log.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/server_log.tsx @@ -6,27 +6,27 @@ import React, { Fragment } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiSelect, EuiTextArea } from '@elastic/eui'; -import { ActionTypeModel, ValidationResult, ActionParamsProps } from '../../../../types'; -import { ErrableFormRow } from '../../../components/page_error'; +import { ActionTypeModel, ValidationResult, ActionParamsProps } from '../../../types'; +import { ErrableFormRow } from '../page_error'; export function getActionType(): ActionTypeModel { return { id: '.server-log', iconClass: 'logsApp', selectMessage: i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.serverLogAction.selectMessageText', + 'xpack.triggersActionsUI.components.buildin_action_types.serverLogAction.selectMessageText', { defaultMessage: 'Add an item to the logs.', } ), - validate: (): ValidationResult => { + validateConnector: (): ValidationResult => { return { errors: {} }; }, validateParams: (actionParams: any): ValidationResult => { const validationResult = { errors: {} }; return validationResult; }, - actionFields: null, + actionConnectorFields: null, actionParamsFields: ServerLogParamsFields, }; } @@ -57,7 +57,7 @@ export const ServerLogParamsFields: React.FunctionComponent = errors={errors} isShowingErrors={hasErrors && level !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.serverLogAction.logLevelFieldLabel', + 'xpack.triggersActionsUI.components.buildin_action_types.serverLogAction.logLevelFieldLabel', { defaultMessage: 'Level', } @@ -81,7 +81,7 @@ export const ServerLogParamsFields: React.FunctionComponent = errors={errors} isShowingErrors={hasErrors && message !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.serverLogAction.logMessageFieldLabel', + 'xpack.triggersActionsUI.components.buildin_action_types.serverLogAction.logMessageFieldLabel', { defaultMessage: 'Message', } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/slack.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/slack.tsx similarity index 81% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/slack.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/slack.tsx index 37af24175217b8..c8cd2bf2c9315f 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/slack.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/slack.tsx @@ -6,26 +6,26 @@ import React, { Fragment } from 'react'; import { EuiFieldText, EuiTextArea, EuiFlexGroup, EuiFlexItem, EuiButtonIcon } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ErrableFormRow } from '../../../components/page_error'; +import { ErrableFormRow } from '../page_error'; import { ActionTypeModel, - Props, - Action, + ActionConnectorFieldsProps, + ActionConnector, ValidationResult, ActionParamsProps, -} from '../../../../types'; +} from '../../../types'; export function getActionType(): ActionTypeModel { return { id: '.slack', iconClass: 'logoSlack', selectMessage: i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.slackAction.selectMessageText', + 'xpack.triggersActionsUI.components.buildin_action_types.slackAction.selectMessageText', { defaultMessage: 'Send a message to a Slack user or channel.', } ), - validate: (action: Action): ValidationResult => { + validateConnector: (action: ActionConnector): ValidationResult => { const validationResult = { errors: {} }; const errors = { webhookUrl: new Array(), @@ -34,7 +34,7 @@ export function getActionType(): ActionTypeModel { if (!action.secrets.webhookUrl) { errors.webhookUrl.push( i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.slackAction.error.requiredWebhookUrlText', + 'xpack.triggersActionsUI.components.buildin_action_types.slackAction.error.requiredWebhookUrlText', { defaultMessage: 'WebhookUrl is required.', } @@ -47,12 +47,12 @@ export function getActionType(): ActionTypeModel { const validationResult = { errors: {} }; return validationResult; }, - actionFields: SlackActionFields, + actionConnectorFields: SlackActionFields, actionParamsFields: SlackParamsFields, }; } -const SlackActionFields: React.FunctionComponent = ({ +const SlackActionFields: React.FunctionComponent = ({ action, editActionSecrets, errors, @@ -69,7 +69,7 @@ const SlackActionFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors === true && webhookUrl !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.slackAction.webhookUrlTextFieldLabel', + 'xpack.triggersActionsUI.components.buildin_action_types.slackAction.webhookUrlTextFieldLabel', { defaultMessage: 'WebhookUrl', } @@ -121,7 +121,7 @@ const SlackParamsFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors && message !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.slackAction.messageTextAreaFieldLabel', + 'xpack.triggersActionsUI.components.buildin_action_types.slackAction.messageTextAreaFieldLabel', { defaultMessage: 'Message', } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/webhook.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/webhook.tsx similarity index 87% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/webhook.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/webhook.tsx index cae6c6c3a203e3..0daf9a899214da 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/buildin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/webhook.tsx @@ -21,14 +21,14 @@ import { EuiCodeEditor, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ErrableFormRow } from '../../../components/page_error'; +import { ErrableFormRow } from '../page_error'; import { ActionTypeModel, - Props, - Action, + ActionConnectorFieldsProps, + ActionConnector, ValidationResult, ActionParamsProps, -} from '../../../../types'; +} from '../../../types'; const HTTP_VERBS = ['post', 'put']; @@ -37,12 +37,12 @@ export function getActionType(): ActionTypeModel { id: '.webhook', iconClass: 'logoWebhook', selectMessage: i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.webhookAction.selectMessageText', + 'xpack.triggersActionsUI.components.buildin_action_types.webhookAction.selectMessageText', { defaultMessage: 'Send a request to a web service.', } ), - validate: (action: Action): ValidationResult => { + validateConnector: (action: ActionConnector): ValidationResult => { const validationResult = { errors: {} }; const errors = { url: new Array(), @@ -54,7 +54,7 @@ export function getActionType(): ActionTypeModel { if (!action.config.url) { errors.url.push( i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.webhookAction.error.requiredUrlText', + 'xpack.triggersActionsUI.components.buildin_action_types.webhookAction.error.requiredUrlText', { defaultMessage: 'Url is required.', } @@ -97,12 +97,12 @@ export function getActionType(): ActionTypeModel { const validationResult = { errors: {} }; return validationResult; }, - actionFields: WebhookActionFields, + actionConnectorFields: WebhookActionConnectorFields, actionParamsFields: WebhookParamsFields, }; } -const WebhookActionFields: React.FunctionComponent = ({ +const WebhookActionConnectorFields: React.FunctionComponent = ({ action, editActionConfig, editActionSecrets, @@ -182,7 +182,7 @@ const WebhookActionFields: React.FunctionComponent = ({ errors={headerErrors} isShowingErrors={hasHeaderErrors && headerKey !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.webhookAction.keyTextFieldLabel', + 'xpack.triggersActionsUI.components.buildin_action_types.webhookAction.keyTextFieldLabel', { defaultMessage: 'Header Key', } @@ -207,7 +207,7 @@ const WebhookActionFields: React.FunctionComponent = ({ errors={headerErrors} isShowingErrors={hasHeaderErrors && headerValue !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.webhookAction.valueTextFieldLabel', + 'xpack.triggersActionsUI.components.buildin_action_types.webhookAction.valueTextFieldLabel', { defaultMessage: 'Header Value', } @@ -234,7 +234,7 @@ const WebhookActionFields: React.FunctionComponent = ({ = ({ errors={errors} isShowingErrors={hasErrors === true && url !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.webhookAction.urlTextFieldLabel', + 'xpack.triggersActionsUI.components.buildin_action_types.webhookAction.urlTextFieldLabel', { defaultMessage: 'Url', } @@ -291,7 +291,7 @@ const WebhookActionFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors === true && user !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.webhookAction.userTextFieldLabel', + 'xpack.triggersActionsUI.components.buildin_action_types.webhookAction.userTextFieldLabel', { defaultMessage: 'User', } @@ -321,7 +321,7 @@ const WebhookActionFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors === true && password !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.webhookAction.passwordTextFieldLabel', + 'xpack.triggersActionsUI.components.buildin_action_types.webhookAction.passwordTextFieldLabel', { defaultMessage: 'Password', } @@ -353,7 +353,7 @@ const WebhookActionFields: React.FunctionComponent = ({ > @@ -366,7 +366,7 @@ const WebhookActionFields: React.FunctionComponent = ({
@@ -405,7 +405,7 @@ const WebhookParamsFields: React.FunctionComponent = ({ = ({ theme="github" data-test-subj="webhookBodyEditor" aria-label={i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.webhookAction.bodyCodeEditorAriaLabel', + 'xpack.triggersActionsUI.components.buildin_action_types.webhookAction.bodyCodeEditorAriaLabel', { defaultMessage: 'Code editor', } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_context.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_connectors_context.tsx similarity index 83% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_context.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_connectors_context.tsx index e5cf2a280c2f1b..924bacdf256e7c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_context.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_connectors_context.tsx @@ -6,9 +6,9 @@ import React from 'react'; import { ActionType, ActionTableItem } from '../../types'; -export const ActionsContext = React.createContext({} as IActionContext); +export const ActionsConnectorsContext = React.createContext({} as IActionsConnectorsContext); -export interface IActionContext { +export interface IActionsConnectorsContext { addFlyoutVisible: boolean; editFlyoutVisible: boolean; setEditFlyoutVisibility: React.Dispatch>; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx index 07f4fc265e7eab..6a15aefeadfe43 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx @@ -23,7 +23,7 @@ import { breadcrumbService } from './lib/breadcrumb'; import { docTitleService } from './lib/doc_title'; import { useAppDependencies } from './app_dependencies'; -import { ActionsList } from './sections/actions_list/components/actions_list'; +import { ActionsConnectorsList } from './sections/actions_connectors_list/components/actions_connectors_list'; import { AlertsList } from './sections/alerts_list/components/alerts_list'; interface MatchParams { @@ -113,7 +113,9 @@ export const TriggersActionsUIHome: React.FunctionComponent - {canShowActions && } + {canShowActions && ( + + )} {canShowAlerts && } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts index 15de72f4246451..fe9e5ffe4da7b3 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts @@ -5,7 +5,7 @@ */ import { HttpServiceBase } from 'kibana/public'; import { BASE_ACTION_API_PATH, BASE_ALERT_API_PATH } from '../constants'; -import { Action, ActionType, Alert, AlertType } from '../../types'; +import { ActionConnector, ActionType, Alert, AlertType } from '../../types'; // We are assuming there won't be many actions. This is why we will load // all the actions in advance and assume the total count to not go over 100 or so. @@ -27,7 +27,7 @@ interface LoadActionsResponse { page: number; perPage: number; total: number; - data: Action[]; + data: ActionConnector[]; } interface DeleteActionsOpts { @@ -55,33 +55,33 @@ export async function getActionById({ }: { id: string; http: HttpServiceBase; -}): Promise { +}): Promise { return http.get(`${BASE_ACTION_API_PATH}/${id}`); } -export async function createAction({ +export async function createActionConnector({ http, - action, + connector, }: { http: HttpServiceBase; - action: Action; -}): Promise { + connector: ActionConnector; +}): Promise { return http.post(`${BASE_ACTION_API_PATH}`, { - body: JSON.stringify(action), + body: JSON.stringify(connector), }); } -export async function updateAction({ +export async function updateActionConnector({ http, - action, + connector, id, }: { http: HttpServiceBase; - action: Action; + connector: ActionConnector; id: string; -}): Promise { +}): Promise { return http.put(`${BASE_ACTION_API_PATH}/${id}`, { - body: JSON.stringify({ ...action, id: undefined, actionTypeId: undefined }), + body: JSON.stringify({ ...connector, id: undefined, actionTypeId: undefined }), }); } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx similarity index 86% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_form.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index b95089febd38a6..5577b7520dd9b7 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -20,12 +20,12 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { createAction, updateAction } from '../../lib/api'; +import { createActionConnector, updateActionConnector } from '../../lib/api'; import { SectionError, ErrableFormRow } from '../../components/page_error'; import { useAppDependencies } from '../../app_dependencies'; -import { actionReducer } from './action_reducer'; -import { ActionsContext } from '../../context/actions_context'; -import { Action, IErrorObject } from '../../../types'; +import { connectorReducer } from './connector_reducer'; +import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; +import { ActionConnector, IErrorObject } from '../../../types'; interface Props { initialAction: any; @@ -33,17 +33,21 @@ interface Props { setFlyoutVisibility: React.Dispatch>; } -export const ActionForm = ({ initialAction, actionTypeName, setFlyoutVisibility }: Props) => { +export const ActionConnectorForm = ({ + initialAction, + actionTypeName, + setFlyoutVisibility, +}: Props) => { const { core: { http }, plugins: { toastNotifications }, actionTypeRegistry, } = useAppDependencies(); - const { loadActions } = useContext(ActionsContext); + const { loadActions } = useContext(ActionsConnectorsContext); // hooks - const [{ action }, dispatch] = useReducer(actionReducer, { action: initialAction }); + const [{ connector }, dispatch] = useReducer(connectorReducer, { connector: initialAction }); const setActionProperty = (key: string, value: any) => { dispatch({ command: { type: 'setProperty' }, payload: { key, value } }); @@ -66,7 +70,7 @@ export const ActionForm = ({ initialAction, actionTypeName, setFlyoutVisibility body: { message: string; error: string }; } | null>(null); - function validateBaseProperties(actionObject: Action) { + function validateBaseProperties(actionObject: ActionConnector) { const validationResult = { errors: {} }; const errors = { description: new Array(), @@ -84,18 +88,18 @@ export const ActionForm = ({ initialAction, actionTypeName, setFlyoutVisibility const actionTypeRegisterd = actionTypeRegistry.get(initialAction.actionTypeId); if (actionTypeRegisterd === null) return null; - const FieldsComponent = actionTypeRegisterd.actionFields; + const FieldsComponent = actionTypeRegisterd.actionConnectorFields; const errors = { - ...actionTypeRegisterd.validate(action).errors, - ...validateBaseProperties(action).errors, + ...actionTypeRegisterd.validateConnector(connector).errors, + ...validateBaseProperties(connector).errors, } as IErrorObject; const hasErrors = !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); async function onActionSave(): Promise { try { let newAction; - if (action.id === undefined) { - newAction = await createAction({ http, action }); + if (connector.id === undefined) { + newAction = await createActionConnector({ http, connector }); toastNotifications.addSuccess( i18n.translate('xpack.triggersActionsUI.sections.actionAdd.saveSuccessNotificationText', { defaultMessage: "Created '{actionName}'", @@ -105,7 +109,7 @@ export const ActionForm = ({ initialAction, actionTypeName, setFlyoutVisibility }) ); } else { - newAction = await updateAction({ http, action, id: action.id }); + newAction = await updateActionConnector({ http, connector, id: connector.id }); toastNotifications.addSuccess( i18n.translate('xpack.triggersActionsUI.sections.actionAdd.saveSuccessNotificationText', { defaultMessage: "Updated '{actionName}'", @@ -152,19 +156,19 @@ export const ActionForm = ({ initialAction, actionTypeName, setFlyoutVisibility /> } errorKey="description" - isShowingErrors={hasErrors && action.description !== undefined} + isShowingErrors={hasErrors && connector.description !== undefined} errors={errors} > { setActionProperty('description', e.target.value); }} onBlur={() => { - if (!action.description) { + if (!connector.description) { setActionProperty('description', ''); } }} @@ -173,7 +177,7 @@ export const ActionForm = ({ initialAction, actionTypeName, setFlyoutVisibility {FieldsComponent !== null ? ( { const { actionTypeRegistry } = useAppDependencies(); - const { actionTypesIndex, setAddFlyoutVisibility } = useContext(ActionsContext); + const { actionTypesIndex, setAddFlyoutVisibility } = useContext(ActionsConnectorsContext); if (!actionTypesIndex) { return null; } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_add_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx similarity index 90% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_add_flyout.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx index 4e1c4b6a32c028..51880c03cd5808 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/action_add_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx @@ -13,15 +13,15 @@ import { EuiFlexItem, EuiIcon, } from '@elastic/eui'; -import { ActionsContext } from '../../context/actions_context'; +import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; import { ActionTypeMenu } from './action_type_menu'; -import { ActionForm } from './action_form'; +import { ActionConnectorForm } from './action_connector_form'; import { ActionType } from '../../../types'; import { useAppDependencies } from '../../app_dependencies'; -export const ActionAddFlyout = () => { +export const ConnectorAddFlyout = () => { const { actionTypeRegistry } = useAppDependencies(); - const { addFlyoutVisible, setAddFlyoutVisibility } = useContext(ActionsContext); + const { addFlyoutVisible, setAddFlyoutVisibility } = useContext(ActionsConnectorsContext); const [actionType, setActionType] = useState(undefined); const closeFlyout = useCallback(() => setAddFlyoutVisibility(false), [setAddFlyoutVisibility]); @@ -44,7 +44,7 @@ export const ActionAddFlyout = () => { const initialAction = { actionTypeId: actionType.id, config: {}, secrets: {} }; currentForm = ( - { +export const ConnectorEditFlyout = () => { const { core: { http }, plugins: { toastNotifications }, actionTypeRegistry, } = useAppDependencies(); const { editFlyoutVisible, setEditFlyoutVisibility, editedActionItem } = useContext( - ActionsContext + ActionsConnectorsContext ); const [isLoadingAction, setIsLoadingAction] = useState(false); - const [action, setAction] = useState(undefined); + const [action, setAction] = useState(undefined); const closeFlyout = useCallback(() => setEditFlyoutVisibility(false), [setEditFlyoutVisibility]); @@ -93,7 +93,7 @@ export const ActionEditFlyout = () => { {action && editedActionItem ? ( - { - const { command, payload } = actionItem; - const { action } = state; +export const connectorReducer = (state: ActionState, action: ReducerAction) => { + const { command, payload } = action; + const { connector } = state; switch (command.type) { - case 'setAction': { + case 'setConnector': { const { key, value } = payload; - if (key === 'action') { + if (key === 'connector') { return { ...state, - action: value, + connector: value, }; } else { return state; @@ -39,13 +39,13 @@ export const actionReducer = (state: ActionState, actionItem: ActionReducerItem) } case 'setProperty': { const { key, value } = payload; - if (isEqual(action[key], value)) { + if (isEqual(connector[key], value)) { return state; } else { return { ...state, - action: { - ...action, + connector: { + ...connector, [key]: value, }, }; @@ -53,15 +53,15 @@ export const actionReducer = (state: ActionState, actionItem: ActionReducerItem) } case 'setConfigProperty': { const { key, value } = payload; - if (isEqual(action.config[key], value)) { + if (isEqual(connector.config[key], value)) { return state; } else { return { ...state, - action: { - ...action, + connector: { + ...connector, config: { - ...action.config, + ...connector.config, [key]: value, }, }, @@ -70,15 +70,15 @@ export const actionReducer = (state: ActionState, actionItem: ActionReducerItem) } case 'setSecretsProperty': { const { key, value } = payload; - if (isEqual(action.secrets[key], value)) { + if (isEqual(connector.secrets[key], value)) { return state; } else { return { ...state, - action: { - ...action, + connector: { + ...connector, secrets: { - ...action.secrets, + ...connector.secrets, [key]: value, }, }, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/index.ts similarity index 66% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/index.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/index.ts index 74d5f59d7cae0b..aac7a514948d14 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_form/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/index.ts @@ -4,5 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export { ActionAddFlyout } from './action_add_flyout'; -export { ActionEditFlyout } from './action_edit_flyout'; +export { ConnectorAddFlyout } from './connector_add_flyout'; +export { ConnectorEditFlyout } from './connector_edit_flyout'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx similarity index 94% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index bae474d059fab0..c77545d6715ee2 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_list/components/actions_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -8,13 +8,13 @@ import React, { Fragment, useState, useEffect } from 'react'; import { EuiBadge, EuiInMemoryTable, EuiSpacer, EuiButton } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { ActionsContext } from '../../../context/actions_context'; +import { ActionsConnectorsContext } from '../../../context/actions_connectors_context'; import { useAppDependencies } from '../../../app_dependencies'; import { deleteActions, loadAllActions, loadActionTypes } from '../../../lib/api'; -import { Action, ActionTableItem, ActionTypeIndex } from '../../../../types'; -import { ActionAddFlyout, ActionEditFlyout } from '../../action_form'; +import { ActionConnector, ActionTableItem, ActionTypeIndex } from '../../../../types'; +import { ConnectorAddFlyout, ConnectorEditFlyout } from '../../action_connector_form'; -export const ActionsList: React.FunctionComponent = () => { +export const ActionsConnectorsList: React.FunctionComponent = () => { const { core: { http }, plugins: { capabilities, toastNotifications }, @@ -23,7 +23,7 @@ export const ActionsList: React.FunctionComponent = () => { const canSave = capabilities.get().actions.save; const [actionTypesIndex, setActionTypesIndex] = useState(undefined); - const [actions, setActions] = useState([]); + const [actions, setActions] = useState([]); const [data, setData] = useState([]); const [selectedItems, setSelectedItems] = useState([]); const [isLoadingActionTypes, setIsLoadingActionTypes] = useState(false); @@ -223,7 +223,7 @@ export const ActionsList: React.FunctionComponent = () => {
- { ], }} /> - - - + + +
); }; -function getActionsCountByActionType(actions: Action[], actionTypeId: string) { +function getActionsCountByActionType(actions: ActionConnector[], actionTypeId: string) { return actions.filter(action => action.actionTypeId === actionTypeId).length; } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index d5a7f51cf4a12a..eebf3ca4bd0660 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -33,6 +33,7 @@ import { EuiPortal, EuiAccordion, EuiButtonIcon, + EuiComboBoxOptionProps, } from '@elastic/eui'; import { useAppDependencies } from '../../app_dependencies'; import { saveAlert, loadActionTypes, loadAllActions } from '../../lib/api'; @@ -46,7 +47,7 @@ import { ActionTypeModel, AlertAction, ActionTypeIndex, - Action, + ActionConnector, } from '../../../types'; import { ACTION_GROUPS } from '../../constants/action_groups'; import { getTimeOptions } from '../../lib/get_time_options'; @@ -119,7 +120,7 @@ export const AlertAdd = ({ refreshList }: Props) => { body: { message: string; error: string }; } | null>(null); const [isAddActionPanelOpen, setIsAddActionPanelOpen] = useState(true); - const [connectors, setConnectors] = useState([]); + const [connectors, setConnectors] = useState([]); useEffect(() => { (async () => { @@ -404,7 +405,7 @@ export const AlertAdd = ({ refreshList }: Props) => { .filter(field => field.actionTypeId === actionConnector.actionTypeId) .map(({ description, id }) => ({ label: description, - value: description, + key: id, id, })); const actionTypeRegisterd = actionTypeRegistry.get(actionConnector.actionTypeId); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts index 95bdcfbb82bed9..c93eb77d087ca0 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts @@ -18,7 +18,7 @@ export interface AlertState { alert: any; } -export interface ActionAlertReducerItem { +export interface AlertReducerAction { command: CommandType; payload: { key: string; @@ -27,7 +27,7 @@ export interface ActionAlertReducerItem { }; } -export const alertReducer = (state: any, action: ActionAlertReducerItem) => { +export const alertReducer = (state: any, action: AlertReducerAction) => { const { command, payload } = action; const { alert } = state; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts index 89d4b620f1dc5b..f34528dcf69901 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts @@ -21,7 +21,7 @@ import { BASE_PATH } from './application/constants'; import { breadcrumbService } from './application/lib/breadcrumb'; import { docTitleService } from './application/lib/doc_title'; import { ActionTypeRegistry } from './application/action_type_registry'; -import { registerBuiltInActionTypes } from './application/sections/action_form/buildin_action_types'; +import { registerBuiltInActionTypes } from './application/components/buildin_action_types'; import { AlertTypeRegistry } from './application/alert_type_registry'; import { registerAlertTypes } from './application/sections/alert_add/alert_types'; import { setSavedObjectsClient } from './application/lib/api'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts index 46e269078bb5fb..773c74d245ef39 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts @@ -7,8 +7,8 @@ export type ActionTypeIndex = Record; export type AlertTypeIndex = Record; -export interface Props { - action: Action; +export interface ActionConnectorFieldsProps { + action: ActionConnector; editActionConfig: (property: string, value: any) => void; editActionSecrets: (property: string, value: any) => void; errors: { [key: string]: string[] }; @@ -32,9 +32,9 @@ export interface ActionTypeModel { id: string; iconClass: string; selectMessage: string; - validate: (action: Action) => ValidationResult; + validateConnector: (action: ActionConnector) => ValidationResult; validateParams: (actionParams: any) => ValidationResult; - actionFields: React.FunctionComponent | null; + actionConnectorFields: React.FunctionComponent | null; actionParamsFields: React.FunctionComponent | null; } @@ -47,7 +47,7 @@ export interface ActionType { name: string; } -export interface Action { +export interface ActionConnector { secrets: Record; id: string; actionTypeId: string; @@ -56,7 +56,7 @@ export interface Action { config: Record; } -export interface ActionTableItem extends Action { +export interface ActionTableItem extends ActionConnector { actionType: ActionType['name']; } From dcaa961a5f9cb8015fcfe48363539c10cf3daa64 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 27 Nov 2019 12:34:53 -0800 Subject: [PATCH 143/297] Renamed alertTypeParams to params in UI code --- .../sections/alert_add/alert_add.tsx | 16 +++--- .../sections/alert_add/alert_reducer.ts | 10 ++-- .../alert_types/threshold/expression.tsx | 52 +++++++++---------- .../alert_types/threshold/visualization.tsx | 32 ++++++------ .../np_ready/public/types.ts | 4 +- 5 files changed, 57 insertions(+), 57 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index eebf3ca4bd0660..1b47152b12bb46 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -97,7 +97,7 @@ export const AlertAdd = ({ refreshList }: Props) => { actionTypeRegistry, } = useAppDependencies(); const initialAlert = { - alertTypeParams: {}, + params: {}, alertTypeId: null, interval: '1m', actions: [], @@ -151,7 +151,7 @@ export const AlertAdd = ({ refreshList }: Props) => { payload: { key: 'alert', value: { - alertTypeParams: {}, + params: {}, alertTypeId: null, interval: '1m', actions: [], @@ -170,8 +170,8 @@ export const AlertAdd = ({ refreshList }: Props) => { dispatch({ command: { type: 'setProperty' }, payload: { key, value } }); }; - const setAlertTypeParams = (key: string, value: any) => { - dispatch({ command: { type: 'setAlertTypeParams' }, payload: { key, value } }); + const setAlertParams = (key: string, value: any) => { + dispatch({ command: { type: 'setAlertParams' }, payload: { key, value } }); }; const setActionParamsProperty = (key: string, value: any, index: number) => { @@ -212,7 +212,7 @@ export const AlertAdd = ({ refreshList }: Props) => { } } - const AlertTypeParamsExpressionComponent = alertType ? alertType.alertTypeParamsExpression : null; + const AlertParamsExpressionComponent = alertType ? alertType.alertParamsExpression : null; const errors = { ...(alertType ? alertType.validate(alert).errors : []), @@ -368,11 +368,11 @@ export const AlertAdd = ({ refreshList }: Props) => {
- {AlertTypeParamsExpressionComponent ? ( - diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts index c93eb77d087ca0..9c2260f0178be8 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_reducer.ts @@ -9,7 +9,7 @@ interface CommandType { type: | 'setAlert' | 'setProperty' - | 'setAlertTypeParams' + | 'setAlertParams' | 'setAlertActionParams' | 'setAlertActionProperty'; } @@ -57,17 +57,17 @@ export const alertReducer = (state: any, action: AlertReducerAction) => { }; } } - case 'setAlertTypeParams': { + case 'setAlertParams': { const { key, value } = payload; - if (isEqual(alert.alertTypeParams[key], value)) { + if (isEqual(alert.params[key], value)) { return state; } else { return { ...state, alert: { ...alert, - alertTypeParams: { - ...alert.alertTypeParams, + params: { + ...alert.params, [key]: value, }, }, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx index b6624785ee1762..d004f88a6b6a8e 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx @@ -71,7 +71,7 @@ const validateAlertType = (alert: Alert): ValidationResult => { termField, threshold, timeWindowSize, - } = alert.alertTypeParams; + } = alert.params; const validationResult = { errors: {} }; const errors = { aggField: new Array(), @@ -159,7 +159,7 @@ export function getActionType(): AlertTypeModel { id: 'threshold', name: 'Index Threshold', iconClass: 'alert', - alertTypeParamsExpression: IndexThresholdAlertTypeExpression, + alertParamsExpression: IndexThresholdAlertTypeExpression, validate: validateAlertType, }; } @@ -277,7 +277,7 @@ export const groupByTypes: { [key: string]: GroupByType } = { interface Props { alert: Alert; - setAlertTypeParams: (property: string, value: any) => void; + setAlertParams: (property: string, value: any) => void; setAlertProperty: (key: string, value: any) => void; errors: { [key: string]: string[] }; hasErrors?: boolean; @@ -285,7 +285,7 @@ interface Props { export const IndexThresholdAlertTypeExpression: React.FunctionComponent = ({ alert, - setAlertTypeParams, + setAlertParams, setAlertProperty, errors, hasErrors, @@ -308,7 +308,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = threshold, timeWindowSize, timeWindowUnit, - } = alert.alertTypeParams; + } = alert.params; const firstFieldOption = { text: i18n.translate( @@ -357,7 +357,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = ); const setDefaultExpressionValues = () => { - setAlertProperty('alertTypeParams', { + setAlertProperty('params', { aggType: DEFAULT_VALUES.AGGREGATION_TYPE, termSize: DEFAULT_VALUES.TERM_SIZE, thresholdComparator: DEFAULT_VALUES.THRESHOLD_COMPARATOR, @@ -475,7 +475,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = }; })} onChange={async (selected: EuiComboBoxOptionProps[]) => { - setAlertTypeParams( + setAlertParams( 'index', selected.map(aSelected => aSelected.value) ); @@ -484,7 +484,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = // reset time field and expression fields if indices are deleted if (indices.length === 0) { setTimeFieldOptions(getTimeFieldOptions([], firstFieldOption)); - setAlertTypeParams('timeFields', []); + setAlertParams('timeFields', []); setDefaultExpressionValues(); return; @@ -493,7 +493,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = const timeFields = getTimeFieldOptions(currentEsFields, firstFieldOption); setEsFields(currentEsFields); - setAlertTypeParams('timeFields', timeFields); + setAlertParams('timeFields', timeFields); setTimeFieldOptions(timeFields); }} onSearchChange={async search => { @@ -503,7 +503,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = }} onBlur={() => { if (!index) { - setAlertTypeParams('index', []); + setAlertParams('index', []); } }} /> @@ -530,11 +530,11 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = data-test-subj="watchTimeFieldSelect" value={timeField} onChange={e => { - setAlertTypeParams('timeField', e.target.value); + setAlertParams('timeField', e.target.value); }} onBlur={() => { if (timeField === undefined) { - setAlertTypeParams('timeField', ''); + setAlertParams('timeField', ''); } }} /> @@ -564,11 +564,11 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = onChange={e => { const { value } = e.target; const triggerIntervalSizeVal = value !== '' ? parseInt(value, 10) : value; - setAlertTypeParams('triggerIntervalSize', triggerIntervalSizeVal); + setAlertParams('triggerIntervalSize', triggerIntervalSizeVal); }} onBlur={e => { if (triggerIntervalSize === undefined) { - setAlertTypeParams('triggerIntervalSize', ''); + setAlertParams('triggerIntervalSize', ''); } }} /> @@ -584,7 +584,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = } )} onChange={e => { - setAlertTypeParams('triggerIntervalUnit', e.target.value); + setAlertParams('triggerIntervalUnit', e.target.value); }} options={getTimeOptions(triggerIntervalSize)} /> @@ -689,7 +689,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = { - setAlertTypeParams('aggType', e.target.value); + setAlertParams('aggType', e.target.value); setAggTypePopoverOpen(false); }} options={Object.values(aggregationTypes).map(({ text, value }) => { @@ -761,7 +761,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = }, [])} selectedOptions={aggField ? [{ label: aggField }] : []} onChange={selectedOptions => { - setAlertTypeParams( + setAlertParams( 'aggField', selectedOptions.length === 1 ? selectedOptions[0].label : undefined ); @@ -829,9 +829,9 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = { - setAlertTypeParams('termSize', null); - setAlertTypeParams('termField', null); - setAlertTypeParams('groupBy', e.target.value); + setAlertParams('termSize', null); + setAlertParams('termField', null); + setAlertParams('groupBy', e.target.value); }} options={Object.values(groupByTypes).map(({ text, value }) => { return { @@ -853,7 +853,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = { - setAlertTypeParams('termSize', e.target.value); + setAlertParams('termSize', e.target.value); }} min={1} /> @@ -868,7 +868,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = { - setAlertTypeParams('termField', e.target.value); + setAlertParams('termField', e.target.value); }} options={esFields.reduce( (options: any, field: any) => { @@ -944,7 +944,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = { - setAlertTypeParams('thresholdComparator', e.target.value); + setAlertParams('thresholdComparator', e.target.value); }} options={Object.values(comparators).map(({ text, value }) => { return { text, value }; @@ -984,7 +984,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = const thresholdVal = value !== '' ? parseFloat(value) : value; const newThreshold = [...threshold]; newThreshold[i] = thresholdVal; - setAlertTypeParams('threshold', newThreshold); + setAlertParams('threshold', newThreshold); }} /> @@ -1046,7 +1046,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = onChange={e => { const { value } = e.target; const timeWindowSizeVal = value !== '' ? parseInt(value, 10) : value; - setAlertTypeParams('timeWindowSize', timeWindowSizeVal); + setAlertParams('timeWindowSize', timeWindowSizeVal); }} /> @@ -1055,7 +1055,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = { - setAlertTypeParams('timeWindowUnit', e.target.value); + setAlertParams('timeWindowUnit', e.target.value); }} options={getTimeOptions(timeWindowSize)} /> diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx index b4232619a8c66f..368b98ea032a69 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx @@ -79,10 +79,10 @@ const getTimezone = ( return tzOffset; }; -const getDomain = (alertTypeParams: any) => { +const getDomain = (alertParams: any) => { const VISUALIZE_TIME_WINDOW_MULTIPLIER = 5; - const fromExpression = `now-${alertTypeParams.timeWindowSize * VISUALIZE_TIME_WINDOW_MULTIPLIER}${ - alertTypeParams.timeWindowUnit + const fromExpression = `now-${alertParams.timeWindowSize * VISUALIZE_TIME_WINDOW_MULTIPLIER}${ + alertParams.timeWindowUnit }`; const toExpression = 'now'; const fromMoment = dateMath.parse(fromExpression); @@ -95,15 +95,15 @@ const getDomain = (alertTypeParams: any) => { }; }; -const getThreshold = (alertTypeParams: any) => { - return alertTypeParams.threshold.slice( +const getThreshold = (alertParams: any) => { + return alertParams.threshold.slice( 0, - comparators[alertTypeParams.thresholdComparator].requiredValues + comparators[alertParams.thresholdComparator].requiredValues ); }; -const getTimeBuckets = (alertTypeParams: any) => { - const domain = getDomain(alertTypeParams); +const getTimeBuckets = (alertParams: any) => { + const domain = getDomain(alertParams); const timeBuckets = new TimeBuckets(); timeBuckets.setBounds(domain); return timeBuckets; @@ -137,9 +137,9 @@ export const ThresholdVisualization: React.FunctionComponent = ({ alert } timeWindowUnit, groupBy, threshold, - } = alert.alertTypeParams; + } = alert.params; - const domain = getDomain(alert.alertTypeParams); + const domain = getDomain(alert.params); const timeBuckets = new TimeBuckets(); timeBuckets.setBounds(domain); const interval = timeBuckets.getInterval().expression; @@ -151,7 +151,7 @@ export const ThresholdVisualization: React.FunctionComponent = ({ alert } }; // Fetching visualization data is independent of alert actions - const alertWithoutActions = { ...alert.alertTypeParams, actions: [], type: 'threshold' }; + const alertWithoutActions = { ...alert.params, actions: [], type: 'threshold' }; useEffect(() => { // Prevent sending a second request on initial render. @@ -225,7 +225,7 @@ export const ThresholdVisualization: React.FunctionComponent = ({ alert } if (visualizationData) { const alertVisualizationDataKeys = Object.keys(visualizationData); const timezone = getTimezone(uiSettings); - const actualThreshold = getThreshold(alert.alertTypeParams); + const actualThreshold = getThreshold(alert.params); let maxY = actualThreshold[actualThreshold.length - 1]; (Object.values(visualizationData) as number[][][]).forEach(data => { @@ -238,9 +238,9 @@ export const ThresholdVisualization: React.FunctionComponent = ({ alert } const dateFormatter = (d: number) => { return moment(d) .tz(timezone) - .format(getTimeBuckets(alert.alertTypeParams).getScaledDateFormat()); + .format(getTimeBuckets(alert.params).getScaledDateFormat()); }; - const aggLabel = aggregationTypes[alert.alertTypeParams.aggType].text; + const aggLabel = aggregationTypes[aggType].text; return (
@@ -249,7 +249,7 @@ export const ThresholdVisualization: React.FunctionComponent = ({ alert } = ({ alert } key={specId} annotationId={getAnnotationId(specId)} domainType={AnnotationDomainTypes.YDomain} - dataValues={[{ dataValue: alert.alertTypeParams.threshold[i], details: specId }]} + dataValues={[{ dataValue: threshold[i], details: specId }]} /> ); })} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts index 773c74d245ef39..42a175bb2c3137 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts @@ -79,7 +79,7 @@ export interface Alert { alertTypeId: string; interval: string; actions: AlertAction[]; - alertTypeParams: Record; + params: Record; scheduledTaskId?: string; createdBy: string | null; updatedBy: string | null; @@ -99,7 +99,7 @@ export interface AlertTypeModel { name: string; iconClass: string; validate: (alert: Alert) => ValidationResult; - alertTypeParamsExpression: React.FunctionComponent; + alertParamsExpression: React.FunctionComponent; } export interface IErrorObject { From 303ed70927d0aa3e944ad012fc950d6fc3192e76 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 27 Nov 2019 15:38:36 -0500 Subject: [PATCH 144/297] Add filter for tags --- .../legacy/plugins/alerting/server/plugin.ts | 7 ++ .../np_ready/public/application/lib/api.ts | 6 ++ .../alerts_list/components/alerts_list.tsx | 10 ++- .../components/bulk_action_popover.tsx | 2 +- .../alerts_list/components/tags_filter.tsx | 68 +++++++++++++++++++ 5 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/tags_filter.tsx diff --git a/x-pack/legacy/plugins/alerting/server/plugin.ts b/x-pack/legacy/plugins/alerting/server/plugin.ts index 9889e01e0ca19e..14ac794b104557 100644 --- a/x-pack/legacy/plugins/alerting/server/plugin.ts +++ b/x-pack/legacy/plugins/alerting/server/plugin.ts @@ -118,6 +118,13 @@ export class Plugin { core.http.route(muteAlertInstanceRoute); core.http.route(unmuteAlertInstanceRoute); + alertTypeRegistry.register({ + id: 'test', + name: 'test', + actionGroups: ['default'], + executor(): any {}, + }); + return { registerType: alertTypeRegistry.register.bind(alertTypeRegistry), }; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts index 15de72f4246451..2154a5782b1e7c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts @@ -105,6 +105,7 @@ export interface LoadAlertsOpts { http: HttpServiceBase; page: { index: number; size: number }; searchText?: string; + tagsFilter?: string[]; } export interface LoadAlertsResponse { @@ -118,6 +119,7 @@ export async function loadAlerts({ http, page, searchText, + tagsFilter, }: LoadAlertsOpts): Promise { return http.get(`${BASE_ALERT_API_PATH}/_find`, { query: { @@ -125,6 +127,10 @@ export async function loadAlerts({ per_page: page.size, search_fields: searchText ? 'name' : undefined, search: searchText, + filter: + tagsFilter && tagsFilter.length > 0 + ? `alert.attributes.tags:(${tagsFilter.join(' and ')})` + : undefined, }, }); } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index db1d41e3f836c5..ce6d39960116db 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -8,13 +8,15 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { Fragment, useEffect, useState } from 'react'; // @ts-ignore: EuiSearchBar not exported in TypeScript -import { EuiBasicTable, EuiButton, EuiButtonEmpty, EuiSearchBar, EuiSpacer } from '@elastic/eui'; +import { EuiBasicTable, EuiButton, EuiSearchBar, EuiSpacer } from '@elastic/eui'; + import { AlertsContext } from '../../../context/alerts_context'; import { useAppDependencies } from '../../../app_dependencies'; import { Alert, AlertTableItem, AlertTypeIndex, Pagination } from '../../../../types'; import { AlertAdd } from '../../alert_add'; import { BulkActionPopover } from './bulk_action_popover'; import { CollapsedItemActions } from './collapsed_item_actions'; +import { TagsFilter } from './tags_filter'; import { loadAlerts, loadAlertTypes } from '../../../lib/api'; export const AlertsList: React.FunctionComponent = () => { @@ -34,12 +36,13 @@ export const AlertsList: React.FunctionComponent = () => { const [totalItemCount, setTotalItemCount] = useState(0); const [page, setPage] = useState({ index: 0, size: 10 }); const [searchText, setSearchText] = useState(undefined); + const [tagsFilter, setTagsFilter] = useState([]); const [alertFlyoutVisible, setAlertFlyoutVisibility] = useState(false); useEffect(() => { loadAlertsData(); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [page, searchText]); + }, [page, searchText, tagsFilter]); useEffect(() => { (async () => { @@ -83,7 +86,7 @@ export const AlertsList: React.FunctionComponent = () => { async function loadAlertsData() { setIsLoadingAlerts(true); try { - const alertsResponse = await loadAlerts({ http, page, searchText }); + const alertsResponse = await loadAlerts({ http, page, searchText, tagsFilter }); setAlerts(alertsResponse.data); setTotalItemCount(alertsResponse.total); } catch (e) { @@ -186,6 +189,7 @@ export const AlertsList: React.FunctionComponent = () => { ] } toolsRight={[ + setTagsFilter(tags)} />, void; +} + +export const TagsFilter: React.FunctionComponent = ({ onChange }) => { + const [selectedOptions, setSelectedOptions] = useState([]); + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + useEffect(() => { + if (onChange) { + onChange(selectedOptions.map(item => item.label)); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [selectedOptions]); + + return ( + + setIsPopoverOpen(false)} + button={ + 0} + numActiveFilters={selectedOptions.length} + numFilters={selectedOptions.length} + onClick={() => setIsPopoverOpen(!isPopoverOpen)} + > + + + } + > +
+ { + setSelectedOptions(selectedOptions.concat({ label: searchValue })); + }} + onChange={(updatedSelectedOptions: EuiComboBoxOptionProps[]) => { + setSelectedOptions(updatedSelectedOptions); + }} + /> +
+
+
+ ); +}; From a9785aaffc87e30dee1312de78e2f058a89fc977 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 27 Nov 2019 15:44:12 -0500 Subject: [PATCH 145/297] Cleanup previous commit --- x-pack/legacy/plugins/alerting/server/plugin.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/x-pack/legacy/plugins/alerting/server/plugin.ts b/x-pack/legacy/plugins/alerting/server/plugin.ts index 14ac794b104557..9889e01e0ca19e 100644 --- a/x-pack/legacy/plugins/alerting/server/plugin.ts +++ b/x-pack/legacy/plugins/alerting/server/plugin.ts @@ -118,13 +118,6 @@ export class Plugin { core.http.route(muteAlertInstanceRoute); core.http.route(unmuteAlertInstanceRoute); - alertTypeRegistry.register({ - id: 'test', - name: 'test', - actionGroups: ['default'], - executor(): any {}, - }); - return { registerType: alertTypeRegistry.register.bind(alertTypeRegistry), }; From ce60ff8f341d8624f6930f711da13d34ede267f3 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 27 Nov 2019 16:30:00 -0500 Subject: [PATCH 146/297] Fix alert type filter --- .../np_ready/public/application/lib/api.ts | 14 +++- .../alerts_list/components/alerts_list.tsx | 32 ++++---- .../alerts_list/components/type_filter.tsx | 74 +++++++++++++++++++ 3 files changed, 97 insertions(+), 23 deletions(-) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/type_filter.tsx diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts index 7c8c05ee9ec4e2..2eb3acf0ee7954 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts @@ -106,6 +106,7 @@ export interface LoadAlertsOpts { page: { index: number; size: number }; searchText?: string; tagsFilter?: string[]; + typesFilter?: string[]; } export interface LoadAlertsResponse { @@ -120,17 +121,22 @@ export async function loadAlerts({ page, searchText, tagsFilter, + typesFilter, }: LoadAlertsOpts): Promise { + const filters = []; + if (tagsFilter && tagsFilter.length) { + filters.push(`alert.attributes.tags:(${tagsFilter.join(' and ')})`); + } + if (typesFilter && typesFilter.length) { + filters.push(`alert.attributes.alertTypeId:(${typesFilter.join(' or ')})`); + } return http.get(`${BASE_ALERT_API_PATH}/_find`, { query: { page: page.index + 1, per_page: page.size, search_fields: searchText ? 'name' : undefined, search: searchText, - filter: - tagsFilter && tagsFilter.length > 0 - ? `alert.attributes.tags:(${tagsFilter.join(' and ')})` - : undefined, + filter: filters.length ? filters.join(' ') : undefined, }, }); } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index ce6d39960116db..ad46cbb80af964 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -17,6 +17,7 @@ import { AlertAdd } from '../../alert_add'; import { BulkActionPopover } from './bulk_action_popover'; import { CollapsedItemActions } from './collapsed_item_actions'; import { TagsFilter } from './tags_filter'; +import { TypeFilter } from './type_filter'; import { loadAlerts, loadAlertTypes } from '../../../lib/api'; export const AlertsList: React.FunctionComponent = () => { @@ -37,12 +38,13 @@ export const AlertsList: React.FunctionComponent = () => { const [page, setPage] = useState({ index: 0, size: 10 }); const [searchText, setSearchText] = useState(undefined); const [tagsFilter, setTagsFilter] = useState([]); + const [typesFilter, setTypesFilter] = useState([]); const [alertFlyoutVisible, setAlertFlyoutVisibility] = useState(false); useEffect(() => { loadAlertsData(); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [page, searchText, tagsFilter]); + }, [page, searchText, tagsFilter, typesFilter]); useEffect(() => { (async () => { @@ -86,7 +88,7 @@ export const AlertsList: React.FunctionComponent = () => { async function loadAlertsData() { setIsLoadingAlerts(true); try { - const alertsResponse = await loadAlerts({ http, page, searchText, tagsFilter }); + const alertsResponse = await loadAlerts({ http, page, searchText, tagsFilter, typesFilter }); setAlerts(alertsResponse.data); setTotalItemCount(alertsResponse.total); } catch (e) { @@ -157,23 +159,6 @@ export const AlertsList: React.FunctionComponent = () => { setSearchText(queryText)} - filters={[ - { - type: 'field_value_selection', - field: 'type', - name: i18n.translate( - 'xpack.triggersActionsUI.sections.alertsList.filters.alertTypeIdName', - { defaultMessage: 'Type' } - ), - multiSelect: 'or', - options: Object.values(alertTypesIndex || {}) - .map(alertType => ({ - value: alertType.id, - name: alertType.name, - })) - .sort((a, b) => a.name.localeCompare(b.name)), - }, - ]} toolsLeft={ selectedIds.length === 0 || !canDelete ? [] @@ -189,6 +174,15 @@ export const AlertsList: React.FunctionComponent = () => { ] } toolsRight={[ + setTypesFilter(types)} + options={Object.values(alertTypesIndex || {}) + .map(alertType => ({ + value: alertType.id, + name: alertType.name, + })) + .sort((a, b) => a.name.localeCompare(b.name))} + />, setTagsFilter(tags)} />, ; + onChange?: (selectedTags: string[]) => void; +} + +export const TypeFilter: React.FunctionComponent = ({ + options, + onChange, +}: TypeFilterProps) => { + const [selectedValues, setSelectedValues] = useState([]); + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + useEffect(() => { + if (onChange) { + onChange(selectedValues); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [selectedValues]); + + return ( + + setIsPopoverOpen(false)} + button={ + 0} + numActiveFilters={selectedValues.length} + numFilters={selectedValues.length} + onClick={() => setIsPopoverOpen(!isPopoverOpen)} + > + + + } + > +
+ {options.map((item, index) => ( + { + const isPreviouslyChecked = selectedValues.includes(item.value); + if (isPreviouslyChecked) { + setSelectedValues(selectedValues.filter(val => val !== item.value)); + } else { + setSelectedValues(selectedValues.concat(item.value)); + } + }} + checked={selectedValues.includes(item.value) ? 'on' : undefined} + > + {item.name} + + ))} +
+
+
+ ) +}; From 59655bcc05871954bf128745d47395375ef4dbde Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 27 Nov 2019 14:22:34 -0800 Subject: [PATCH 147/297] Refactored edit form to use ActionTableItem --- .../context/actions_connectors_context.tsx | 3 +- .../np_ready/public/application/lib/api.ts | 10 --- .../action_connector_form.tsx | 4 +- .../connector_edit_flyout.tsx | 68 +++++-------------- .../components/actions_connectors_list.tsx | 9 +-- 5 files changed, 26 insertions(+), 68 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_connectors_context.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_connectors_context.tsx index 924bacdf256e7c..f5e3be2d688489 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_connectors_context.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_connectors_context.tsx @@ -5,7 +5,7 @@ */ import React from 'react'; -import { ActionType, ActionTableItem } from '../../types'; +import { ActionType } from '../../types'; export const ActionsConnectorsContext = React.createContext({} as IActionsConnectorsContext); export interface IActionsConnectorsContext { @@ -15,5 +15,4 @@ export interface IActionsConnectorsContext { setAddFlyoutVisibility: React.Dispatch>; actionTypesIndex: Record | undefined; loadActions: () => Promise; - editedActionItem: ActionTableItem | undefined; } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts index 2eb3acf0ee7954..f684bf3824363c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts @@ -49,16 +49,6 @@ export async function loadAllActions({ http }: LoadActionsOpts): Promise { - return http.get(`${BASE_ACTION_API_PATH}/${id}`); -} - export async function createActionConnector({ http, connector, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index 5577b7520dd9b7..89b6b657c9aad3 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -27,7 +27,7 @@ import { connectorReducer } from './connector_reducer'; import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; import { ActionConnector, IErrorObject } from '../../../types'; -interface Props { +interface ActionConnectorProps { initialAction: any; actionTypeName: string; setFlyoutVisibility: React.Dispatch>; @@ -37,7 +37,7 @@ export const ActionConnectorForm = ({ initialAction, actionTypeName, setFlyoutVisibility, -}: Props) => { +}: ActionConnectorProps) => { const { core: { http }, plugins: { toastNotifications }, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx index 7a2c71fd4cd0e4..ea5f5e6bc3866a 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { useContext, useCallback, useEffect, useState } from 'react'; +import React, { useContext, useCallback } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiTitle, @@ -13,63 +13,26 @@ import { EuiFlexItem, EuiIcon, } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; import { ActionConnectorForm } from './action_connector_form'; import { useAppDependencies } from '../../app_dependencies'; -import { getActionById } from '../../lib/api'; -import { ActionConnector } from '../../../types'; import { SectionLoading } from '../../components/section_loading'; +import { ActionTableItem } from '../../../types'; -export const ConnectorEditFlyout = () => { - const { - core: { http }, - plugins: { toastNotifications }, - actionTypeRegistry, - } = useAppDependencies(); - const { editFlyoutVisible, setEditFlyoutVisibility, editedActionItem } = useContext( - ActionsConnectorsContext - ); - const [isLoadingAction, setIsLoadingAction] = useState(false); - const [action, setAction] = useState(undefined); +export interface ConnectorEditProps { + connector: ActionTableItem; +} +export const ConnectorEditFlyout = ({ connector }: ConnectorEditProps) => { + const { actionTypeRegistry } = useAppDependencies(); + const { editFlyoutVisible, setEditFlyoutVisibility } = useContext(ActionsConnectorsContext); const closeFlyout = useCallback(() => setEditFlyoutVisibility(false), [setEditFlyoutVisibility]); - useEffect(() => { - setAction(undefined); - if (editFlyoutVisible && editedActionItem && editedActionItem.id) { - loadActionById(editedActionItem.id); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [editFlyoutVisible]); - - async function loadActionById(actionItemId: string) { - setIsLoadingAction(true); - try { - const actionResponse = await getActionById({ id: actionItemId, http }); - setAction({ ...actionResponse, secrets: {} }); - } catch (e) { - toastNotifications.addDanger({ - title: i18n.translate( - 'xpack.triggersActionsUI.sections.actionEdit.unableToLoadActionMessage', - { - defaultMessage: 'Unable to load action', - } - ), - }); - } finally { - setIsLoadingAction(false); - } - } - - if (!editFlyoutVisible && !action) { + if (!editFlyoutVisible) { return null; } - let actionTypeModel; - if (editedActionItem) { - actionTypeModel = actionTypeRegistry.get(editedActionItem.actionTypeId); - } + const actionTypeModel = actionTypeRegistry.get(connector.actionTypeId); return ( @@ -92,10 +55,15 @@ export const ConnectorEditFlyout = () => { - {action && editedActionItem ? ( + {connector ? ( ) : ( diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index c77545d6715ee2..e4342cf7e335be 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -34,7 +34,9 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { const [actionTypesList, setActionTypesList] = useState>( [] ); - const [editedActionItem, setEditedActionItem] = useState(undefined); + const [editedConnectorItem, setEditedConnectorItem] = useState( + undefined + ); useEffect(() => { loadActions(); @@ -131,7 +133,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { } async function editItem(actionTableItem: ActionTableItem) { - setEditedActionItem(actionTableItem); + setEditedConnectorItem(actionTableItem); setEditFlyoutVisibility(true); } @@ -231,7 +233,6 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { setEditFlyoutVisibility, actionTypesIndex, loadActions, - editedActionItem, }} > { }} /> - + {editedConnectorItem ? : null} From 7abe75ea1d12c92c8c58cfd45c227c469ecdb29d Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 27 Nov 2019 15:05:29 -0800 Subject: [PATCH 148/297] Renamed ActionTableItem to ActionConnectorTableItem --- .../connector_edit_flyout.tsx | 4 +-- .../components/actions_connectors_list.tsx | 26 +++++++++---------- .../np_ready/public/types.ts | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx index ea5f5e6bc3866a..352d76b63b9112 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx @@ -17,10 +17,10 @@ import { ActionsConnectorsContext } from '../../context/actions_connectors_conte import { ActionConnectorForm } from './action_connector_form'; import { useAppDependencies } from '../../app_dependencies'; import { SectionLoading } from '../../components/section_loading'; -import { ActionTableItem } from '../../../types'; +import { ActionConnectorTableItem } from '../../../types'; export interface ConnectorEditProps { - connector: ActionTableItem; + connector: ActionConnectorTableItem; } export const ConnectorEditFlyout = ({ connector }: ConnectorEditProps) => { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index e4342cf7e335be..0867ed54a65d04 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -11,7 +11,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { ActionsConnectorsContext } from '../../../context/actions_connectors_context'; import { useAppDependencies } from '../../../app_dependencies'; import { deleteActions, loadAllActions, loadActionTypes } from '../../../lib/api'; -import { ActionConnector, ActionTableItem, ActionTypeIndex } from '../../../../types'; +import { ActionConnector, ActionConnectorTableItem, ActionTypeIndex } from '../../../../types'; import { ConnectorAddFlyout, ConnectorEditFlyout } from '../../action_connector_form'; export const ActionsConnectorsList: React.FunctionComponent = () => { @@ -24,8 +24,8 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { const [actionTypesIndex, setActionTypesIndex] = useState(undefined); const [actions, setActions] = useState([]); - const [data, setData] = useState([]); - const [selectedItems, setSelectedItems] = useState([]); + const [data, setData] = useState([]); + const [selectedItems, setSelectedItems] = useState([]); const [isLoadingActionTypes, setIsLoadingActionTypes] = useState(false); const [isLoadingActions, setIsLoadingActions] = useState(false); const [isDeletingActions, setIsDeletingActions] = useState(false); @@ -34,9 +34,9 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { const [actionTypesList, setActionTypesList] = useState>( [] ); - const [editedConnectorItem, setEditedConnectorItem] = useState( - undefined - ); + const [editedConnectorItem, setEditedConnectorItem] = useState< + ActionConnectorTableItem | undefined + >(undefined); useEffect(() => { loadActions(); @@ -111,7 +111,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { } } - async function deleteItems(items: ActionTableItem[]) { + async function deleteItems(items: ActionConnectorTableItem[]) { setIsDeletingActions(true); const ids = items.map(item => (item.id ? item.id : '')); try { @@ -132,8 +132,8 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { } } - async function editItem(actionTableItem: ActionTableItem) { - setEditedConnectorItem(actionTableItem); + async function editItem(connectorTableItem: ActionConnectorTableItem) { + setEditedConnectorItem(connectorTableItem); setEditFlyoutVisibility(true); } @@ -172,7 +172,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { ), sortable: false, truncateText: true, - render: (value: number, item: ActionTableItem) => { + render: (value: number, item: ActionConnectorTableItem) => { return {value}; }, }, @@ -196,7 +196,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { ), type: 'icon', icon: 'pencil', - onClick: (item: ActionTableItem) => editItem(item), + onClick: (item: ActionConnectorTableItem) => editItem(item), }, { enabled: () => canDelete, @@ -215,7 +215,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { ), type: 'icon', icon: 'trash', - onClick: (item: ActionTableItem) => deleteItems([item]), + onClick: (item: ActionConnectorTableItem) => deleteItems([item]), }, ], }, @@ -251,7 +251,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { pagination={true} selection={ canDelete && { - onSelectionChange(updatedSelectedItemsList: ActionTableItem[]) { + onSelectionChange(updatedSelectedItemsList: ActionConnectorTableItem[]) { setSelectedItems(updatedSelectedItemsList); }, } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts index 42a175bb2c3137..d8ed784cfe4790 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts @@ -56,7 +56,7 @@ export interface ActionConnector { config: Record; } -export interface ActionTableItem extends ActionConnector { +export interface ActionConnectorTableItem extends ActionConnector { actionType: ActionType['name']; } From 114b4f1b41fe6193850244aab10193a6a2847a0d Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 27 Nov 2019 15:06:15 -0800 Subject: [PATCH 149/297] Fixed missing button key error for alerts list filter --- .../sections/alerts_list/components/alerts_list.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index ad46cbb80af964..231ce7a7520a60 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -175,6 +175,7 @@ export const AlertsList: React.FunctionComponent = () => { } toolsRight={[ setTypesFilter(types)} options={Object.values(alertTypesIndex || {}) .map(alertType => ({ @@ -183,7 +184,7 @@ export const AlertsList: React.FunctionComponent = () => { })) .sort((a, b) => a.name.localeCompare(b.name))} />, - setTagsFilter(tags)} />, + setTagsFilter(tags)} />, Date: Wed, 27 Nov 2019 15:13:51 -0800 Subject: [PATCH 150/297] Renamed translation labels for connectors --- .../action_connector_form.tsx | 60 +++++++++++-------- .../action_type_menu.tsx | 9 ++- .../connector_add_flyout.tsx | 2 +- .../connector_edit_flyout.tsx | 4 +- .../components/actions_connectors_list.tsx | 32 +++++----- 5 files changed, 61 insertions(+), 46 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index 89b6b657c9aad3..e78402a82155d0 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -78,9 +78,12 @@ export const ActionConnectorForm = ({ validationResult.errors = errors; if (!actionObject.description) { errors.description.push( - i18n.translate('xpack.triggersActionsUI.sections.actionAdd.error.requiredNameText', { - defaultMessage: 'Description is required.', - }) + i18n.translate( + 'xpack.triggersActionsUI.sections.actionConnectorForm.error.requiredNameText', + { + defaultMessage: 'Description is required.', + } + ) ); } return validationResult; @@ -101,22 +104,28 @@ export const ActionConnectorForm = ({ if (connector.id === undefined) { newAction = await createActionConnector({ http, connector }); toastNotifications.addSuccess( - i18n.translate('xpack.triggersActionsUI.sections.actionAdd.saveSuccessNotificationText', { - defaultMessage: "Created '{actionName}'", - values: { - actionName: newAction.description, - }, - }) + i18n.translate( + 'xpack.triggersActionsUI.sections.actionConnectorForm.saveSuccessNotificationText', + { + defaultMessage: "Created '{actionName}'", + values: { + actionName: newAction.description, + }, + } + ) ); } else { newAction = await updateActionConnector({ http, connector, id: connector.id }); toastNotifications.addSuccess( - i18n.translate('xpack.triggersActionsUI.sections.actionAdd.saveSuccessNotificationText', { - defaultMessage: "Updated '{actionName}'", - values: { - actionName: newAction.description, - }, - }) + i18n.translate( + 'xpack.triggersActionsUI.sections.actionConnectorForm.saveSuccessNotificationText', + { + defaultMessage: "Updated '{actionName}'", + values: { + actionName: newAction.description, + }, + } + ) ); } @@ -137,7 +146,7 @@ export const ActionConnectorForm = ({ } @@ -151,7 +160,7 @@ export const ActionConnectorForm = ({ fullWidth label={ } @@ -187,7 +196,7 @@ export const ActionConnectorForm = ({

@@ -226,9 +235,12 @@ export const ActionConnectorForm = ({ setFlyoutVisibility(false)}> - {i18n.translate('xpack.triggersActionsUI.sections.actionAdd.cancelButtonLabel', { - defaultMessage: 'Cancel', - })} + {i18n.translate( + 'xpack.triggersActionsUI.sections.actionConnectorForm.cancelButtonLabel', + { + defaultMessage: 'Cancel', + } + )} @@ -252,7 +264,7 @@ export const ActionConnectorForm = ({ }} > diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx index 4da8859ea972ec..2efae6b950412a 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx @@ -64,9 +64,12 @@ export const ActionTypeMenu = ({ setActionType }: Props) => { setAddFlyoutVisibility(false)}> - {i18n.translate('xpack.triggersActionsUI.sections.actionAdd.cancelButtonLabel', { - defaultMessage: 'Cancel', - })} + {i18n.translate( + 'xpack.triggersActionsUI.sections.actionConnectorForm.cancelButtonLabel', + { + defaultMessage: 'Cancel', + } + )} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx index 51880c03cd5808..1c56d976e9e955 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx @@ -66,7 +66,7 @@ export const ConnectorAddFlyout = () => {

diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx index 352d76b63b9112..4109f124153a80 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx @@ -48,7 +48,7 @@ export const ConnectorEditFlyout = ({ connector }: ConnectorEditProps) => {

@@ -69,7 +69,7 @@ export const ConnectorEditFlyout = ({ connector }: ConnectorEditProps) => { ) : ( diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index 0867ed54a65d04..1d20e4c1e5cfa2 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -56,7 +56,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { } catch (e) { toastNotifications.addDanger({ title: i18n.translate( - 'xpack.triggersActionsUI.sections.actionsList.unableToLoadActionTypesMessage', + 'xpack.triggersActionsUI.sections.actionsConnectorsList.unableToLoadActionTypesMessage', { defaultMessage: 'Unable to load action types' } ), }); @@ -100,7 +100,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { } catch (e) { toastNotifications.addDanger({ title: i18n.translate( - 'xpack.triggersActionsUI.sections.actionsList.unableToLoadActionsMessage', + 'xpack.triggersActionsUI.sections.actionsConnectorsList.unableToLoadActionsMessage', { defaultMessage: 'Unable to load actions', } @@ -121,7 +121,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { } catch (e) { toastNotifications.addDanger({ title: i18n.translate( - 'xpack.triggersActionsUI.sections.actionsList.failedToDeleteActionsMessage', + 'xpack.triggersActionsUI.sections.actionsConnectorsList.failedToDeleteActionsMessage', { defaultMessage: 'Failed to delete action(s)' } ), }); @@ -145,7 +145,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { { field: 'actionType', name: i18n.translate( - 'xpack.triggersActionsUI.sections.actionsList.actionsListTable.columns.actionTypeTitle', + 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actionTypeTitle', { defaultMessage: 'Type', } @@ -156,7 +156,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { { field: 'description', name: i18n.translate( - 'xpack.triggersActionsUI.sections.actionsList.actionsListTable.columns.descriptionTitle', + 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.descriptionTitle', { defaultMessage: 'Name', } @@ -167,7 +167,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { { field: 'referencedByCount', name: i18n.translate( - 'xpack.triggersActionsUI.sections.actionsList.actionsListTable.columns.referencedByCountTitle', + 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.referencedByCountTitle', { defaultMessage: 'Attached actions' } ), sortable: false, @@ -182,16 +182,16 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { { enabled: () => canSave, name: i18n.translate( - 'xpack.triggersActionsUI.sections.actionsList.actionsListTable.columns.actions.editActionName', + 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.editActionName', { defaultMessage: 'Edit' } ), description: canSave ? i18n.translate( - 'xpack.triggersActionsUI.sections.actionsList.actionsListTable.columns.actions.editActionDescription', + 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.editActionDescription', { defaultMessage: 'Edit this action' } ) : i18n.translate( - 'xpack.triggersActionsUI.sections.actionsList.actionsListTable.columns.actions.editActionDisabledDescription', + 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.editActionDisabledDescription', { defaultMessage: 'Unable to edit actions' } ), type: 'icon', @@ -201,16 +201,16 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { { enabled: () => canDelete, name: i18n.translate( - 'xpack.triggersActionsUI.sections.actionsList.actionsListTable.columns.actions.deleteActionName', + 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.deleteActionName', { defaultMessage: 'Delete' } ), description: canDelete ? i18n.translate( - 'xpack.triggersActionsUI.sections.actionsList.actionsListTable.columns.actions.deleteActionDescription', + 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.deleteActionDescription', { defaultMessage: 'Delete this action' } ) : i18n.translate( - 'xpack.triggersActionsUI.sections.actionsList.actionsListTable.columns.actions.deleteActionDisabledDescription', + 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.deleteActionDisabledDescription', { defaultMessage: 'Unable to delete actions' } ), type: 'icon', @@ -262,7 +262,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { type: 'field_value_selection', field: 'actionTypeId', name: i18n.translate( - 'xpack.triggersActionsUI.sections.actionsList.filters.actionTypeIdName', + 'xpack.triggersActionsUI.sections.actionsConnectorsList.filters.actionTypeIdName', { defaultMessage: 'Type' } ), multiSelect: 'or', @@ -282,13 +282,13 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { canDelete ? undefined : i18n.translate( - 'xpack.triggersActionsUI.sections.actionsList.buttons.deleteDisabledTitle', + 'xpack.triggersActionsUI.sections.actionsConnectorsList.buttons.deleteDisabledTitle', { defaultMessage: 'Unable to delete actions' } ) } > { onClick={() => setAddFlyoutVisibility(true)} >
, From 9f2dfba0c4abbba7e8850a310f0e32d55962c0c5 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 28 Nov 2019 11:10:59 -0500 Subject: [PATCH 151/297] Enable UI plugin by default --- x-pack/legacy/plugins/triggers_actions_ui/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/index.ts index ab2bdbead115b9..f2cf9b5cd7e99a 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/index.ts @@ -23,7 +23,7 @@ export function triggersActionsUI(kibana: any) { config(Joi: Root) { return Joi.object() .keys({ - enabled: Joi.boolean().default(false), + enabled: Joi.boolean().default(true), }) .default(); }, From 2b70b715b09dc96e133a0159ab7e38d6996798fa Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 28 Nov 2019 13:12:55 -0500 Subject: [PATCH 152/297] Rename buildin to builtin --- .../email.tsx | 18 ++--- .../es_index.tsx | 8 +- .../index.ts | 0 .../pagerduty.tsx | 26 +++---- .../server_log.tsx | 6 +- .../slack.tsx | 8 +- .../webhook.tsx | 24 +++--- .../np_ready/public/application/lib/api.ts | 78 +++++++------------ .../np_ready/public/plugin.ts | 2 +- 9 files changed, 75 insertions(+), 95 deletions(-) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/{buildin_action_types => builtin_action_types}/email.tsx (94%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/{buildin_action_types => builtin_action_types}/es_index.tsx (89%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/{buildin_action_types => builtin_action_types}/index.ts (100%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/{buildin_action_types => builtin_action_types}/pagerduty.tsx (86%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/{buildin_action_types => builtin_action_types}/server_log.tsx (89%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/{buildin_action_types => builtin_action_types}/slack.tsx (89%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/{buildin_action_types => builtin_action_types}/webhook.tsx (90%) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/email.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx similarity index 94% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/email.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx index 104ac6599de6db..6b21ce0e5f6182 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/email.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx @@ -28,7 +28,7 @@ export function getActionType(): ActionTypeModel { id: '.email', iconClass: 'email', selectMessage: i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.emailAction.selectMessageText', + 'xpack.triggersActionsUI.components.builtinActionTypes.emailAction.selectMessageText', { defaultMessage: 'Send an email.', } @@ -46,7 +46,7 @@ export function getActionType(): ActionTypeModel { if (!action.config.from) { errors.from.push( i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.error.requiredFromText', + 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredFromText', { defaultMessage: 'From is required.', } @@ -56,7 +56,7 @@ export function getActionType(): ActionTypeModel { if (!action.config.port) { errors.port.push( i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.error.requiredPortText', + 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredPortText', { defaultMessage: 'Port is required.', } @@ -66,7 +66,7 @@ export function getActionType(): ActionTypeModel { if (!action.config.host) { errors.host.push( i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.error.requiredHostText', + 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredHostText', { defaultMessage: 'Host is required.', } @@ -76,7 +76,7 @@ export function getActionType(): ActionTypeModel { if (!action.secrets.user) { errors.user.push( i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.error.requiredUserText', + 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredUserText', { defaultMessage: 'User is required.', } @@ -86,7 +86,7 @@ export function getActionType(): ActionTypeModel { if (!action.secrets.password) { errors.password.push( i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.error.requiredPasswordText', + 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredPasswordText', { defaultMessage: 'Password is required.', } @@ -112,7 +112,7 @@ export function getActionType(): ActionTypeModel { actionParams.bcc.length === 0 ) { const errorText = i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.error.requiredEntryText', + 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredEntryText', { defaultMessage: 'No [to], [cc], or [bcc] entries. At least one entry is required.', } @@ -124,7 +124,7 @@ export function getActionType(): ActionTypeModel { if (!actionParams.message) { errors.message.push( i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.error.requiredMessageText', + 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredMessageText', { defaultMessage: 'Message is required.', } @@ -134,7 +134,7 @@ export function getActionType(): ActionTypeModel { if (!actionParams.subject) { errors.subject.push( i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.error.requiredSubjectText', + 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredSubjectText', { defaultMessage: 'Subject is required.', } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/es_index.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.tsx similarity index 89% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/es_index.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.tsx index 03b4c72e34cbd2..8d61d52fc21254 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/es_index.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.tsx @@ -20,7 +20,7 @@ export function getActionType(): ActionTypeModel { id: '.index', iconClass: 'indexOpen', selectMessage: i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.indexAction.selectMessageText', + 'xpack.triggersActionsUI.components.builtinActionTypes.indexAction.selectMessageText', { defaultMessage: 'Index data into Elasticsearch.', } @@ -46,7 +46,7 @@ const IndexActionConnectorFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors === true && action.index !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.indexAction.indexFieldLabel', + 'xpack.triggersActionsUI.components.builtinActionTypes.indexAction.indexFieldLabel', { defaultMessage: 'Index', } @@ -116,7 +116,7 @@ const IndexParamsFields: React.FunctionComponent = ({ }} label={ } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/index.ts similarity index 100% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/index.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/index.ts diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/pagerduty.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.tsx similarity index 86% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/pagerduty.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.tsx index 2ebf89e9f88393..8a05f9320f7951 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/pagerduty.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.tsx @@ -20,7 +20,7 @@ export function getActionType(): ActionTypeModel { id: '.pagerduty', iconClass: 'apps', selectMessage: i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.pagerDutyAction.selectMessageText', + 'xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.selectMessageText', { defaultMessage: 'Create an event in PagerDuty.', } @@ -35,7 +35,7 @@ export function getActionType(): ActionTypeModel { if (!action.secrets.routingKey) { errors.routingKey.push( i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.pagerDutyAction.error.requiredRoutingKeyText', + 'xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.error.requiredRoutingKeyText', { defaultMessage: 'Routing Key is required.', } @@ -45,7 +45,7 @@ export function getActionType(): ActionTypeModel { if (!action.config.apiUrl) { errors.apiUrl.push( i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.pagerDutyAction.error.requiredApiUrlText', + 'xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.error.requiredApiUrlText', { defaultMessage: 'ApiUrl is required.', } @@ -81,7 +81,7 @@ const PagerDutyActionConnectorFields: React.FunctionComponent = ({ = ({ = ({ = ({ = ({ = ({ = ({ = ({ errors={errors} isShowingErrors={hasErrors === true && summary !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.pagerDutyAction.summaryFieldLabel', + 'xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.summaryFieldLabel', { defaultMessage: 'Summary', } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/server_log.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.tsx similarity index 89% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/server_log.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.tsx index 2227ff864f9e64..1309c6f70f49ee 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/server_log.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.tsx @@ -14,7 +14,7 @@ export function getActionType(): ActionTypeModel { id: '.server-log', iconClass: 'logsApp', selectMessage: i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.serverLogAction.selectMessageText', + 'xpack.triggersActionsUI.components.builtinActionTypes.serverLogAction.selectMessageText', { defaultMessage: 'Add an item to the logs.', } @@ -57,7 +57,7 @@ export const ServerLogParamsFields: React.FunctionComponent = errors={errors} isShowingErrors={hasErrors && level !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.serverLogAction.logLevelFieldLabel', + 'xpack.triggersActionsUI.components.builtinActionTypes.serverLogAction.logLevelFieldLabel', { defaultMessage: 'Level', } @@ -81,7 +81,7 @@ export const ServerLogParamsFields: React.FunctionComponent = errors={errors} isShowingErrors={hasErrors && message !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.serverLogAction.logMessageFieldLabel', + 'xpack.triggersActionsUI.components.builtinActionTypes.serverLogAction.logMessageFieldLabel', { defaultMessage: 'Message', } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/slack.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx similarity index 89% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/slack.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx index c8cd2bf2c9315f..176464dcefac59 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/slack.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx @@ -20,7 +20,7 @@ export function getActionType(): ActionTypeModel { id: '.slack', iconClass: 'logoSlack', selectMessage: i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.slackAction.selectMessageText', + 'xpack.triggersActionsUI.components.builtinActionTypes.slackAction.selectMessageText', { defaultMessage: 'Send a message to a Slack user or channel.', } @@ -34,7 +34,7 @@ export function getActionType(): ActionTypeModel { if (!action.secrets.webhookUrl) { errors.webhookUrl.push( i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.slackAction.error.requiredWebhookUrlText', + 'xpack.triggersActionsUI.components.builtinActionTypes.slackAction.error.requiredWebhookUrlText', { defaultMessage: 'WebhookUrl is required.', } @@ -69,7 +69,7 @@ const SlackActionFields: React.FunctionComponent = ( errors={errors} isShowingErrors={hasErrors === true && webhookUrl !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.slackAction.webhookUrlTextFieldLabel', + 'xpack.triggersActionsUI.components.builtinActionTypes.slackAction.webhookUrlTextFieldLabel', { defaultMessage: 'WebhookUrl', } @@ -121,7 +121,7 @@ const SlackParamsFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors && message !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.slackAction.messageTextAreaFieldLabel', + 'xpack.triggersActionsUI.components.builtinActionTypes.slackAction.messageTextAreaFieldLabel', { defaultMessage: 'Message', } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/webhook.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx similarity index 90% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/webhook.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx index 0daf9a899214da..0a593694f5f759 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/buildin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx @@ -37,7 +37,7 @@ export function getActionType(): ActionTypeModel { id: '.webhook', iconClass: 'logoWebhook', selectMessage: i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.webhookAction.selectMessageText', + 'xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.selectMessageText', { defaultMessage: 'Send a request to a web service.', } @@ -54,7 +54,7 @@ export function getActionType(): ActionTypeModel { if (!action.config.url) { errors.url.push( i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.webhookAction.error.requiredUrlText', + 'xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.error.requiredUrlText', { defaultMessage: 'Url is required.', } @@ -182,7 +182,7 @@ const WebhookActionConnectorFields: React.FunctionComponent
@@ -366,7 +366,7 @@ const WebhookActionConnectorFields: React.FunctionComponent @@ -405,7 +405,7 @@ const WebhookParamsFields: React.FunctionComponent = ({ = ({ theme="github" data-test-subj="webhookBodyEditor" aria-label={i18n.translate( - 'xpack.triggersActionsUI.components.buildin_action_types.webhookAction.bodyCodeEditorAriaLabel', + 'xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.bodyCodeEditorAriaLabel', { defaultMessage: 'Code editor', } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts index f684bf3824363c..75c439aec789db 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts @@ -13,35 +13,20 @@ import { ActionConnector, ActionType, Alert, AlertType } from '../../types'; const MAX_ACTIONS_RETURNED = 10000; const WATCHER_API_ROOT = '/api/watcher'; -interface LoadActionTypesOpts { - http: HttpServiceBase; +export async function loadActionTypes({ http }: { http: HttpServiceBase }): Promise { + return http.get(`${BASE_ACTION_API_PATH}/types`); } -type LoadActionTypesResponse = ActionType[]; - -interface LoadActionsOpts { +export async function loadAllActions({ + http, +}: { http: HttpServiceBase; -} - -interface LoadActionsResponse { +}): Promise<{ page: number; perPage: number; total: number; data: ActionConnector[]; -} - -interface DeleteActionsOpts { - ids: string[]; - http: HttpServiceBase; -} - -export async function loadActionTypes({ - http, -}: LoadActionTypesOpts): Promise { - return http.get(`${BASE_ACTION_API_PATH}/types`); -} - -export async function loadAllActions({ http }: LoadActionsOpts): Promise { +}> { return http.get(`${BASE_ACTION_API_PATH}/_find`, { query: { per_page: MAX_ACTIONS_RETURNED, @@ -75,44 +60,38 @@ export async function updateActionConnector({ }); } -export async function deleteActions({ ids, http }: DeleteActionsOpts): Promise { - await Promise.all(ids.map(id => http.delete(`${BASE_ACTION_API_PATH}/${id}`))); -} - -export interface LoadAlertTypesOpts { +export async function deleteActions({ + ids, + http, +}: { + ids: string[]; http: HttpServiceBase; +}): Promise { + await Promise.all(ids.map(id => http.delete(`${BASE_ACTION_API_PATH}/${id}`))); } -export type LoadAlertTypesResponse = AlertType[]; - -export async function loadAlertTypes({ - http, -}: LoadAlertTypesOpts): Promise { +export async function loadAlertTypes({ http }: { http: HttpServiceBase }): Promise { return http.get(`${BASE_ALERT_API_PATH}/types`); } -export interface LoadAlertsOpts { +export async function loadAlerts({ + http, + page, + searchText, + tagsFilter, + typesFilter, +}: { http: HttpServiceBase; page: { index: number; size: number }; searchText?: string; tagsFilter?: string[]; typesFilter?: string[]; -} - -export interface LoadAlertsResponse { +}): Promise<{ page: number; perPage: number; total: number; data: Alert[]; -} - -export async function loadAlerts({ - http, - page, - searchText, - tagsFilter, - typesFilter, -}: LoadAlertsOpts): Promise { +}> { const filters = []; if (tagsFilter && tagsFilter.length) { filters.push(`alert.attributes.tags:(${tagsFilter.join(' and ')})`); @@ -131,12 +110,13 @@ export async function loadAlerts({ }); } -export interface DeleteAlertsOpts { +export async function deleteAlerts({ + ids, + http, +}: { ids: string[]; http: HttpServiceBase; -} - -export async function deleteAlerts({ ids, http }: DeleteAlertsOpts): Promise { +}): Promise { await Promise.all(ids.map(id => http.delete(`${BASE_ALERT_API_PATH}/${id}`))); } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts index f34528dcf69901..74e0c3c9a27c19 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts @@ -21,7 +21,7 @@ import { BASE_PATH } from './application/constants'; import { breadcrumbService } from './application/lib/breadcrumb'; import { docTitleService } from './application/lib/doc_title'; import { ActionTypeRegistry } from './application/action_type_registry'; -import { registerBuiltInActionTypes } from './application/components/buildin_action_types'; +import { registerBuiltInActionTypes } from './application/components/builtin_action_types'; import { AlertTypeRegistry } from './application/alert_type_registry'; import { registerAlertTypes } from './application/sections/alert_add/alert_types'; import { setSavedObjectsClient } from './application/lib/api'; From 4a24c94b3c6473eb5a648be57977e2e5b4b51199 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 28 Nov 2019 13:17:14 -0500 Subject: [PATCH 153/297] Fix some type checks --- .../application/components/builtin_action_types/es_index.tsx | 2 +- .../public/application/sections/alert_add/alert_add.tsx | 1 - .../sections/alert_add/alert_types/threshold/visualization.tsx | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.tsx index 8d61d52fc21254..96ca6222f777db 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.tsx @@ -77,7 +77,7 @@ const IndexParamsFields: React.FunctionComponent = ({ errors, hasErrors, }) => { - const { refresh, executionTimeField, documents } = action; + const { refresh } = action; return ( Date: Thu, 28 Nov 2019 14:55:56 -0500 Subject: [PATCH 154/297] Add API tests --- .../public/application/lib/api.test.ts | 528 ++++++++++++++++++ .../np_ready/public/application/lib/api.ts | 47 +- .../sections/alert_add/alert_add.tsx | 4 +- .../np_ready/public/types.ts | 4 + 4 files changed, 568 insertions(+), 15 deletions(-) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.test.ts diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.test.ts new file mode 100644 index 00000000000000..2569af8ed05f25 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.test.ts @@ -0,0 +1,528 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under 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 { + ActionConnector, + ActionConnectorWithoutId, + ActionType, + Alert, + AlertType, +} from '../../types'; +import { httpServiceMock } from '../../../../../../../../src/core/public/mocks'; +import { + createAlert, + createActionConnector, + deleteActions, + deleteAlerts, + disableAlerts, + enableAlerts, + loadActionTypes, + loadAlerts, + loadAlertTypes, + loadAllActions, + muteAlerts, + unmuteAlerts, + updateActionConnector, + updateAlert, +} from './api'; + +const http = httpServiceMock.createStartContract(); + +beforeEach(() => jest.resetAllMocks()); + +describe('loadActionTypes', () => { + test('should call get types API', async () => { + const resolvedValue: ActionType[] = [ + { + id: 'test', + name: 'Test', + }, + ]; + http.get.mockResolvedValueOnce(resolvedValue); + + const result = await loadActionTypes({ http }); + expect(result).toEqual(resolvedValue); + expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/api/action/types", + ] + `); + }); +}); + +describe('loadAllActions', () => { + test('should call find actions API', async () => { + const resolvedValue = { + page: 1, + perPage: 10000, + total: 0, + data: [], + }; + http.get.mockResolvedValueOnce(resolvedValue); + + const result = await loadAllActions({ http }); + expect(result).toEqual(resolvedValue); + expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/api/action/_find", + Object { + "query": Object { + "per_page": 10000, + }, + }, + ] + `); + }); +}); + +describe('createActionConnector', () => { + test('should call create action API', async () => { + const connector: ActionConnectorWithoutId = { + actionTypeId: 'test', + description: 'My test', + config: {}, + secrets: {}, + }; + const resolvedValue: ActionConnector = { ...connector, id: '123' }; + http.post.mockResolvedValueOnce(resolvedValue); + + const result = await createActionConnector({ http, connector }); + expect(result).toEqual(resolvedValue); + expect(http.post.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/api/action", + Object { + "body": "{\\"actionTypeId\\":\\"test\\",\\"description\\":\\"My test\\",\\"config\\":{},\\"secrets\\":{}}", + }, + ] + `); + }); +}); + +describe('updateActionConnector', () => { + test('should call the update API', async () => { + const id = '123'; + const connector: ActionConnectorWithoutId = { + actionTypeId: 'test', + description: 'My test', + config: {}, + secrets: {}, + }; + const resolvedValue = { ...connector, id }; + http.put.mockResolvedValueOnce(resolvedValue); + + const result = await updateActionConnector({ http, connector, id }); + expect(result).toEqual(resolvedValue); + expect(http.put.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/api/action/123", + Object { + "body": "{\\"description\\":\\"My test\\",\\"config\\":{},\\"secrets\\":{}}", + }, + ] + `); + }); +}); + +describe('deleteActions', () => { + test('should call delete API per action', async () => { + const ids = ['1', '2', '3']; + + const result = await deleteActions({ ids, http }); + expect(result).toEqual(undefined); + expect(http.delete.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "/api/action/1", + ], + Array [ + "/api/action/2", + ], + Array [ + "/api/action/3", + ], + ] + `); + }); +}); + +describe('loadAlertTypes', () => { + test('should call get alert types API', async () => { + const resolvedValue: AlertType[] = [ + { + id: 'test', + name: 'Test', + }, + ]; + http.get.mockResolvedValueOnce(resolvedValue); + + const result = await loadAlertTypes({ http }); + expect(result).toEqual(resolvedValue); + expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/api/alert/types", + ] + `); + }); +}); + +describe('loadAlerts', () => { + test('should call find API with base parameters', async () => { + const resolvedValue = { + page: 1, + perPage: 10, + total: 0, + data: [], + }; + http.get.mockResolvedValueOnce(resolvedValue); + + const result = await loadAlerts({ http, page: { index: 0, size: 10 } }); + expect(result).toEqual(resolvedValue); + expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/api/alert/_find", + Object { + "query": Object { + "filter": undefined, + "page": 1, + "per_page": 10, + "search": undefined, + "search_fields": undefined, + }, + }, + ] + `); + }); + + test('should call find API with searchText', async () => { + const resolvedValue = { + page: 1, + perPage: 10, + total: 0, + data: [], + }; + http.get.mockResolvedValueOnce(resolvedValue); + + const result = await loadAlerts({ http, searchText: 'apples', page: { index: 0, size: 10 } }); + expect(result).toEqual(resolvedValue); + expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/api/alert/_find", + Object { + "query": Object { + "filter": undefined, + "page": 1, + "per_page": 10, + "search": "apples", + "search_fields": "name", + }, + }, + ] + `); + }); + + test('should call find API with tagsFilter', async () => { + const resolvedValue = { + page: 1, + perPage: 10, + total: 0, + data: [], + }; + http.get.mockResolvedValueOnce(resolvedValue); + + const result = await loadAlerts({ + http, + tagsFilter: ['foo', 'bar'], + page: { index: 0, size: 10 }, + }); + expect(result).toEqual(resolvedValue); + expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/api/alert/_find", + Object { + "query": Object { + "filter": "alert.attributes.tags:(foo and bar)", + "page": 1, + "per_page": 10, + "search": undefined, + "search_fields": undefined, + }, + }, + ] + `); + }); + + test('should call find API with typesFilter', async () => { + const resolvedValue = { + page: 1, + perPage: 10, + total: 0, + data: [], + }; + http.get.mockResolvedValueOnce(resolvedValue); + + const result = await loadAlerts({ + http, + typesFilter: ['foo', 'bar'], + page: { index: 0, size: 10 }, + }); + expect(result).toEqual(resolvedValue); + expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/api/alert/_find", + Object { + "query": Object { + "filter": "alert.attributes.alertTypeId:(foo or bar)", + "page": 1, + "per_page": 10, + "search": undefined, + "search_fields": undefined, + }, + }, + ] + `); + }); + + test('should call find API with tagsFilter and typesFilter', async () => { + const resolvedValue = { + page: 1, + perPage: 10, + total: 0, + data: [], + }; + http.get.mockResolvedValueOnce(resolvedValue); + + const result = await loadAlerts({ + http, + tagsFilter: ['foo', 'baz'], + typesFilter: ['foo', 'bar'], + page: { index: 0, size: 10 }, + }); + expect(result).toEqual(resolvedValue); + expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/api/alert/_find", + Object { + "query": Object { + "filter": "alert.attributes.tags:(foo and baz) and alert.attributes.alertTypeId:(foo or bar)", + "page": 1, + "per_page": 10, + "search": undefined, + "search_fields": undefined, + }, + }, + ] + `); + }); + + test('should call find API with searchText and tagsFilter and typesFilter', async () => { + const resolvedValue = { + page: 1, + perPage: 10, + total: 0, + data: [], + }; + http.get.mockResolvedValueOnce(resolvedValue); + + const result = await loadAlerts({ + http, + searchText: 'apples', + tagsFilter: ['foo', 'baz'], + typesFilter: ['foo', 'bar'], + page: { index: 0, size: 10 }, + }); + expect(result).toEqual(resolvedValue); + expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/api/alert/_find", + Object { + "query": Object { + "filter": "alert.attributes.tags:(foo and baz) and alert.attributes.alertTypeId:(foo or bar)", + "page": 1, + "per_page": 10, + "search": "apples", + "search_fields": "name", + }, + }, + ] + `); + }); +}); + +describe('deleteAlerts', () => { + test('should call delete API for each alert', async () => { + const ids = ['1', '2', '3']; + const result = await deleteAlerts({ http, ids }); + expect(result).toEqual(undefined); + expect(http.delete.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "/api/alert/1", + ], + Array [ + "/api/alert/2", + ], + Array [ + "/api/alert/3", + ], + ] + `); + }); +}); + +describe('createAlert', () => { + test('should call create alert API', async () => { + const alertToCreate = { + name: 'test', + tags: ['foo'], + enabled: true, + alertTypeId: 'test', + interval: '1m', + actions: [], + params: {}, + throttle: null, + }; + const resolvedValue: Alert = { + ...alertToCreate, + id: '123', + createdBy: null, + updatedBy: null, + muteAll: false, + mutedInstanceIds: [], + }; + http.post.mockResolvedValueOnce(resolvedValue); + + const result = await createAlert({ http, alert: alertToCreate }); + expect(result).toEqual(resolvedValue); + expect(http.post.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/api/alert", + Object { + "body": "{\\"name\\":\\"test\\",\\"tags\\":[\\"foo\\"],\\"enabled\\":true,\\"alertTypeId\\":\\"test\\",\\"interval\\":\\"1m\\",\\"actions\\":[],\\"params\\":{},\\"throttle\\":null}", + }, + ] + `); + }); +}); + +describe('updateAlert', () => { + test('should call alert update API', async () => { + const alertToUpdate = { + throttle: '1m', + name: 'test', + tags: ['foo'], + interval: '1m', + params: {}, + actions: [], + }; + const resolvedValue: Alert = { + ...alertToUpdate, + id: '123', + enabled: true, + alertTypeId: 'test', + createdBy: null, + updatedBy: null, + muteAll: false, + mutedInstanceIds: [], + }; + http.put.mockResolvedValueOnce(resolvedValue); + + const result = await updateAlert({ http, id: '123', alert: alertToUpdate }); + expect(result).toEqual(resolvedValue); + expect(http.put.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/api/alert/123", + Object { + "body": "{\\"throttle\\":\\"1m\\",\\"name\\":\\"test\\",\\"tags\\":[\\"foo\\"],\\"interval\\":\\"1m\\",\\"params\\":{},\\"actions\\":[]}", + }, + ] + `); + }); +}); + +describe('enableAlerts', () => { + test('should call enable alert API per alert', async () => { + const ids = ['1', '2', '3']; + const result = await enableAlerts({ http, ids }); + expect(result).toEqual(undefined); + expect(http.post.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "/api/alert/1/_enable", + ], + Array [ + "/api/alert/2/_enable", + ], + Array [ + "/api/alert/3/_enable", + ], + ] + `); + }); +}); + +describe('disableAlerts', () => { + test('should call disable alert API per alert', async () => { + const ids = ['1', '2', '3']; + const result = await disableAlerts({ http, ids }); + expect(result).toEqual(undefined); + expect(http.post.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "/api/alert/1/_disable", + ], + Array [ + "/api/alert/2/_disable", + ], + Array [ + "/api/alert/3/_disable", + ], + ] + `); + }); +}); + +describe('muteAlerts', () => { + test('should call mute alert API per alert', async () => { + const ids = ['1', '2', '3']; + const result = await muteAlerts({ http, ids }); + expect(result).toEqual(undefined); + expect(http.post.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "/api/alert/1/_mute_all", + ], + Array [ + "/api/alert/2/_mute_all", + ], + Array [ + "/api/alert/3/_mute_all", + ], + ] + `); + }); +}); + +describe('unmuteAlerts', () => { + test('should call unmute alert API per alert', async () => { + const ids = ['1', '2', '3']; + const result = await unmuteAlerts({ http, ids }); + expect(result).toEqual(undefined); + expect(http.post.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "/api/alert/1/_unmute_all", + ], + Array [ + "/api/alert/2/_unmute_all", + ], + Array [ + "/api/alert/3/_unmute_all", + ], + ] + `); + }); +}); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts index 75c439aec789db..4ab9a1add565d1 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts @@ -5,7 +5,14 @@ */ import { HttpServiceBase } from 'kibana/public'; import { BASE_ACTION_API_PATH, BASE_ALERT_API_PATH } from '../constants'; -import { ActionConnector, ActionType, Alert, AlertType } from '../../types'; +import { + ActionConnector, + ActionConnectorWithoutId, + ActionType, + Alert, + AlertType, + AlertWithoutId, +} from '../../types'; // We are assuming there won't be many actions. This is why we will load // all the actions in advance and assume the total count to not go over 100 or so. @@ -14,7 +21,7 @@ const MAX_ACTIONS_RETURNED = 10000; const WATCHER_API_ROOT = '/api/watcher'; export async function loadActionTypes({ http }: { http: HttpServiceBase }): Promise { - return http.get(`${BASE_ACTION_API_PATH}/types`); + return await http.get(`${BASE_ACTION_API_PATH}/types`); } export async function loadAllActions({ @@ -27,7 +34,7 @@ export async function loadAllActions({ total: number; data: ActionConnector[]; }> { - return http.get(`${BASE_ACTION_API_PATH}/_find`, { + return await http.get(`${BASE_ACTION_API_PATH}/_find`, { query: { per_page: MAX_ACTIONS_RETURNED, }, @@ -39,9 +46,9 @@ export async function createActionConnector({ connector, }: { http: HttpServiceBase; - connector: ActionConnector; + connector: Omit; }): Promise { - return http.post(`${BASE_ACTION_API_PATH}`, { + return await http.post(`${BASE_ACTION_API_PATH}`, { body: JSON.stringify(connector), }); } @@ -52,10 +59,10 @@ export async function updateActionConnector({ id, }: { http: HttpServiceBase; - connector: ActionConnector; + connector: Pick; id: string; }): Promise { - return http.put(`${BASE_ACTION_API_PATH}/${id}`, { + return await http.put(`${BASE_ACTION_API_PATH}/${id}`, { body: JSON.stringify({ ...connector, id: undefined, actionTypeId: undefined }), }); } @@ -71,7 +78,7 @@ export async function deleteActions({ } export async function loadAlertTypes({ http }: { http: HttpServiceBase }): Promise { - return http.get(`${BASE_ALERT_API_PATH}/types`); + return await http.get(`${BASE_ALERT_API_PATH}/types`); } export async function loadAlerts({ @@ -99,13 +106,13 @@ export async function loadAlerts({ if (typesFilter && typesFilter.length) { filters.push(`alert.attributes.alertTypeId:(${typesFilter.join(' or ')})`); } - return http.get(`${BASE_ALERT_API_PATH}/_find`, { + return await http.get(`${BASE_ALERT_API_PATH}/_find`, { query: { page: page.index + 1, per_page: page.size, search_fields: searchText ? 'name' : undefined, search: searchText, - filter: filters.length ? filters.join(' ') : undefined, + filter: filters.length ? filters.join(' and ') : undefined, }, }); } @@ -120,14 +127,28 @@ export async function deleteAlerts({ await Promise.all(ids.map(id => http.delete(`${BASE_ALERT_API_PATH}/${id}`))); } -export async function saveAlert({ +export async function createAlert({ http, alert, }: { http: HttpServiceBase; - alert: Alert; + alert: Omit; }): Promise { - return http.post(`${BASE_ALERT_API_PATH}`, { + return await http.post(`${BASE_ALERT_API_PATH}`, { + body: JSON.stringify(alert), + }); +} + +export async function updateAlert({ + http, + alert, + id, +}: { + http: HttpServiceBase; + alert: Pick; + id: string; +}): Promise { + return await http.put(`${BASE_ALERT_API_PATH}/${id}`, { body: JSON.stringify(alert), }); } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 6563ace3e2cfc0..d3c5d8f3bcb1be 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -35,7 +35,7 @@ import { EuiButtonIcon, } from '@elastic/eui'; import { useAppDependencies } from '../../app_dependencies'; -import { saveAlert, loadActionTypes, loadAllActions } from '../../lib/api'; +import { createAlert, loadActionTypes, loadAllActions } from '../../lib/api'; import { AlertsContext } from '../../context/alerts_context'; import { alertReducer } from './alert_reducer'; import { ErrableFormRow, SectionError } from '../../components/page_error'; @@ -263,7 +263,7 @@ export const AlertAdd = ({ refreshList }: Props) => { async function onSaveAlert(): Promise { try { - const newAlert = await saveAlert({ http, alert }); + const newAlert = await createAlert({ http, alert }); toastNotifications.addSuccess( i18n.translate('xpack.triggersActionsUI.sections.alertAdd.saveSuccessNotificationText', { defaultMessage: "Saved '{alertName}'", diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts index d8ed784cfe4790..dbcd6f463ec240 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts @@ -56,6 +56,8 @@ export interface ActionConnector { config: Record; } +export type ActionConnectorWithoutId = Omit; + export interface ActionConnectorTableItem extends ActionConnector { actionType: ActionType['name']; } @@ -89,6 +91,8 @@ export interface Alert { mutedInstanceIds: string[]; } +export type AlertWithoutId = Omit; + export interface AlertTableItem extends Alert { alertType: AlertType['name']; tagsText: string; From 466f847bb4657b739e8e271196f0c1ce75bffcfb Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 28 Nov 2019 15:06:00 -0500 Subject: [PATCH 155/297] Split API file into smaller files --- .../lib/action_connector_api.test.ts | 135 +++++++++++++ .../application/lib/action_connector_api.ts | 71 +++++++ .../lib/{api.test.ts => alert_api.test.ts} | 131 +----------- .../public/application/lib/alert_api.ts | 125 ++++++++++++ .../np_ready/public/application/lib/api.ts | 186 ------------------ .../action_connector_form.tsx | 2 +- .../components/actions_connectors_list.tsx | 2 +- .../sections/alert_add/alert_add.tsx | 3 +- .../alerts_list/components/alerts_list.tsx | 2 +- .../components/bulk_action_popover.tsx | 2 +- .../components/collapsed_item_actions.tsx | 2 +- 11 files changed, 340 insertions(+), 321 deletions(-) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.test.ts create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/{api.test.ts => alert_api.test.ts} (75%) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.ts diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.test.ts new file mode 100644 index 00000000000000..c0270647178839 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.test.ts @@ -0,0 +1,135 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under 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 { ActionConnector, ActionConnectorWithoutId, ActionType } from '../../types'; +import { httpServiceMock } from '../../../../../../../../src/core/public/mocks'; +import { + createActionConnector, + deleteActions, + loadActionTypes, + loadAllActions, + updateActionConnector, +} from './action_connector_api'; + +const http = httpServiceMock.createStartContract(); + +beforeEach(() => jest.resetAllMocks()); + +describe('loadActionTypes', () => { + test('should call get types API', async () => { + const resolvedValue: ActionType[] = [ + { + id: 'test', + name: 'Test', + }, + ]; + http.get.mockResolvedValueOnce(resolvedValue); + + const result = await loadActionTypes({ http }); + expect(result).toEqual(resolvedValue); + expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/api/action/types", + ] + `); + }); +}); + +describe('loadAllActions', () => { + test('should call find actions API', async () => { + const resolvedValue = { + page: 1, + perPage: 10000, + total: 0, + data: [], + }; + http.get.mockResolvedValueOnce(resolvedValue); + + const result = await loadAllActions({ http }); + expect(result).toEqual(resolvedValue); + expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/api/action/_find", + Object { + "query": Object { + "per_page": 10000, + }, + }, + ] + `); + }); +}); + +describe('createActionConnector', () => { + test('should call create action API', async () => { + const connector: ActionConnectorWithoutId = { + actionTypeId: 'test', + description: 'My test', + config: {}, + secrets: {}, + }; + const resolvedValue: ActionConnector = { ...connector, id: '123' }; + http.post.mockResolvedValueOnce(resolvedValue); + + const result = await createActionConnector({ http, connector }); + expect(result).toEqual(resolvedValue); + expect(http.post.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/api/action", + Object { + "body": "{\\"actionTypeId\\":\\"test\\",\\"description\\":\\"My test\\",\\"config\\":{},\\"secrets\\":{}}", + }, + ] + `); + }); +}); + +describe('updateActionConnector', () => { + test('should call the update API', async () => { + const id = '123'; + const connector: ActionConnectorWithoutId = { + actionTypeId: 'test', + description: 'My test', + config: {}, + secrets: {}, + }; + const resolvedValue = { ...connector, id }; + http.put.mockResolvedValueOnce(resolvedValue); + + const result = await updateActionConnector({ http, connector, id }); + expect(result).toEqual(resolvedValue); + expect(http.put.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/api/action/123", + Object { + "body": "{\\"description\\":\\"My test\\",\\"config\\":{},\\"secrets\\":{}}", + }, + ] + `); + }); +}); + +describe('deleteActions', () => { + test('should call delete API per action', async () => { + const ids = ['1', '2', '3']; + + const result = await deleteActions({ ids, http }); + expect(result).toEqual(undefined); + expect(http.delete.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "/api/action/1", + ], + Array [ + "/api/action/2", + ], + Array [ + "/api/action/3", + ], + ] + `); + }); +}); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts new file mode 100644 index 00000000000000..0a9a9eef3ecc99 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { HttpServiceBase } from 'kibana/public'; +import { BASE_ACTION_API_PATH } from '../constants'; +import { ActionConnector, ActionConnectorWithoutId, ActionType } from '../../types'; + +// We are assuming there won't be many actions. This is why we will load +// all the actions in advance and assume the total count to not go over 100 or so. +// We'll set this max setting assuming it's never reached. +const MAX_ACTIONS_RETURNED = 10000; + +export async function loadActionTypes({ http }: { http: HttpServiceBase }): Promise { + return await http.get(`${BASE_ACTION_API_PATH}/types`); +} + +export async function loadAllActions({ + http, +}: { + http: HttpServiceBase; +}): Promise<{ + page: number; + perPage: number; + total: number; + data: ActionConnector[]; +}> { + return await http.get(`${BASE_ACTION_API_PATH}/_find`, { + query: { + per_page: MAX_ACTIONS_RETURNED, + }, + }); +} + +export async function createActionConnector({ + http, + connector, +}: { + http: HttpServiceBase; + connector: Omit; +}): Promise { + return await http.post(`${BASE_ACTION_API_PATH}`, { + body: JSON.stringify(connector), + }); +} + +export async function updateActionConnector({ + http, + connector, + id, +}: { + http: HttpServiceBase; + connector: Pick; + id: string; +}): Promise { + return await http.put(`${BASE_ACTION_API_PATH}/${id}`, { + body: JSON.stringify({ ...connector, id: undefined, actionTypeId: undefined }), + }); +} + +export async function deleteActions({ + ids, + http, +}: { + ids: string[]; + http: HttpServiceBase; +}): Promise { + await Promise.all(ids.map(id => http.delete(`${BASE_ACTION_API_PATH}/${id}`))); +} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.test.ts similarity index 75% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.test.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.test.ts index 2569af8ed05f25..e31cfe826d34f1 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.test.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.test.ts @@ -4,151 +4,24 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - ActionConnector, - ActionConnectorWithoutId, - ActionType, - Alert, - AlertType, -} from '../../types'; +import { Alert, AlertType } from '../../types'; import { httpServiceMock } from '../../../../../../../../src/core/public/mocks'; import { createAlert, - createActionConnector, - deleteActions, deleteAlerts, disableAlerts, enableAlerts, - loadActionTypes, loadAlerts, loadAlertTypes, - loadAllActions, muteAlerts, unmuteAlerts, - updateActionConnector, updateAlert, -} from './api'; +} from './alert_api'; const http = httpServiceMock.createStartContract(); beforeEach(() => jest.resetAllMocks()); -describe('loadActionTypes', () => { - test('should call get types API', async () => { - const resolvedValue: ActionType[] = [ - { - id: 'test', - name: 'Test', - }, - ]; - http.get.mockResolvedValueOnce(resolvedValue); - - const result = await loadActionTypes({ http }); - expect(result).toEqual(resolvedValue); - expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "/api/action/types", - ] - `); - }); -}); - -describe('loadAllActions', () => { - test('should call find actions API', async () => { - const resolvedValue = { - page: 1, - perPage: 10000, - total: 0, - data: [], - }; - http.get.mockResolvedValueOnce(resolvedValue); - - const result = await loadAllActions({ http }); - expect(result).toEqual(resolvedValue); - expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "/api/action/_find", - Object { - "query": Object { - "per_page": 10000, - }, - }, - ] - `); - }); -}); - -describe('createActionConnector', () => { - test('should call create action API', async () => { - const connector: ActionConnectorWithoutId = { - actionTypeId: 'test', - description: 'My test', - config: {}, - secrets: {}, - }; - const resolvedValue: ActionConnector = { ...connector, id: '123' }; - http.post.mockResolvedValueOnce(resolvedValue); - - const result = await createActionConnector({ http, connector }); - expect(result).toEqual(resolvedValue); - expect(http.post.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "/api/action", - Object { - "body": "{\\"actionTypeId\\":\\"test\\",\\"description\\":\\"My test\\",\\"config\\":{},\\"secrets\\":{}}", - }, - ] - `); - }); -}); - -describe('updateActionConnector', () => { - test('should call the update API', async () => { - const id = '123'; - const connector: ActionConnectorWithoutId = { - actionTypeId: 'test', - description: 'My test', - config: {}, - secrets: {}, - }; - const resolvedValue = { ...connector, id }; - http.put.mockResolvedValueOnce(resolvedValue); - - const result = await updateActionConnector({ http, connector, id }); - expect(result).toEqual(resolvedValue); - expect(http.put.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "/api/action/123", - Object { - "body": "{\\"description\\":\\"My test\\",\\"config\\":{},\\"secrets\\":{}}", - }, - ] - `); - }); -}); - -describe('deleteActions', () => { - test('should call delete API per action', async () => { - const ids = ['1', '2', '3']; - - const result = await deleteActions({ ids, http }); - expect(result).toEqual(undefined); - expect(http.delete.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - "/api/action/1", - ], - Array [ - "/api/action/2", - ], - Array [ - "/api/action/3", - ], - ] - `); - }); -}); - describe('loadAlertTypes', () => { test('should call get alert types API', async () => { const resolvedValue: AlertType[] = [ diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.ts new file mode 100644 index 00000000000000..d38338773bb731 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.ts @@ -0,0 +1,125 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { HttpServiceBase } from 'kibana/public'; +import { BASE_ALERT_API_PATH } from '../constants'; +import { Alert, AlertType, AlertWithoutId } from '../../types'; + +export async function loadAlertTypes({ http }: { http: HttpServiceBase }): Promise { + return await http.get(`${BASE_ALERT_API_PATH}/types`); +} + +export async function loadAlerts({ + http, + page, + searchText, + tagsFilter, + typesFilter, +}: { + http: HttpServiceBase; + page: { index: number; size: number }; + searchText?: string; + tagsFilter?: string[]; + typesFilter?: string[]; +}): Promise<{ + page: number; + perPage: number; + total: number; + data: Alert[]; +}> { + const filters = []; + if (tagsFilter && tagsFilter.length) { + filters.push(`alert.attributes.tags:(${tagsFilter.join(' and ')})`); + } + if (typesFilter && typesFilter.length) { + filters.push(`alert.attributes.alertTypeId:(${typesFilter.join(' or ')})`); + } + return await http.get(`${BASE_ALERT_API_PATH}/_find`, { + query: { + page: page.index + 1, + per_page: page.size, + search_fields: searchText ? 'name' : undefined, + search: searchText, + filter: filters.length ? filters.join(' and ') : undefined, + }, + }); +} + +export async function deleteAlerts({ + ids, + http, +}: { + ids: string[]; + http: HttpServiceBase; +}): Promise { + await Promise.all(ids.map(id => http.delete(`${BASE_ALERT_API_PATH}/${id}`))); +} + +export async function createAlert({ + http, + alert, +}: { + http: HttpServiceBase; + alert: Omit; +}): Promise { + return await http.post(`${BASE_ALERT_API_PATH}`, { + body: JSON.stringify(alert), + }); +} + +export async function updateAlert({ + http, + alert, + id, +}: { + http: HttpServiceBase; + alert: Pick; + id: string; +}): Promise { + return await http.put(`${BASE_ALERT_API_PATH}/${id}`, { + body: JSON.stringify(alert), + }); +} + +export async function enableAlerts({ + ids, + http, +}: { + ids: string[]; + http: HttpServiceBase; +}): Promise { + await Promise.all(ids.map(id => http.post(`${BASE_ALERT_API_PATH}/${id}/_enable`))); +} + +export async function disableAlerts({ + ids, + http, +}: { + ids: string[]; + http: HttpServiceBase; +}): Promise { + await Promise.all(ids.map(id => http.post(`${BASE_ALERT_API_PATH}/${id}/_disable`))); +} + +export async function muteAlerts({ + ids, + http, +}: { + ids: string[]; + http: HttpServiceBase; +}): Promise { + await Promise.all(ids.map(id => http.post(`${BASE_ALERT_API_PATH}/${id}/_mute_all`))); +} + +export async function unmuteAlerts({ + ids, + http, +}: { + ids: string[]; + http: HttpServiceBase; +}): Promise { + await Promise.all(ids.map(id => http.post(`${BASE_ALERT_API_PATH}/${id}/_unmute_all`))); +} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts index 4ab9a1add565d1..0012c2526d05a0 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts @@ -4,195 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ import { HttpServiceBase } from 'kibana/public'; -import { BASE_ACTION_API_PATH, BASE_ALERT_API_PATH } from '../constants'; -import { - ActionConnector, - ActionConnectorWithoutId, - ActionType, - Alert, - AlertType, - AlertWithoutId, -} from '../../types'; -// We are assuming there won't be many actions. This is why we will load -// all the actions in advance and assume the total count to not go over 100 or so. -// We'll set this max setting assuming it's never reached. -const MAX_ACTIONS_RETURNED = 10000; const WATCHER_API_ROOT = '/api/watcher'; -export async function loadActionTypes({ http }: { http: HttpServiceBase }): Promise { - return await http.get(`${BASE_ACTION_API_PATH}/types`); -} - -export async function loadAllActions({ - http, -}: { - http: HttpServiceBase; -}): Promise<{ - page: number; - perPage: number; - total: number; - data: ActionConnector[]; -}> { - return await http.get(`${BASE_ACTION_API_PATH}/_find`, { - query: { - per_page: MAX_ACTIONS_RETURNED, - }, - }); -} - -export async function createActionConnector({ - http, - connector, -}: { - http: HttpServiceBase; - connector: Omit; -}): Promise { - return await http.post(`${BASE_ACTION_API_PATH}`, { - body: JSON.stringify(connector), - }); -} - -export async function updateActionConnector({ - http, - connector, - id, -}: { - http: HttpServiceBase; - connector: Pick; - id: string; -}): Promise { - return await http.put(`${BASE_ACTION_API_PATH}/${id}`, { - body: JSON.stringify({ ...connector, id: undefined, actionTypeId: undefined }), - }); -} - -export async function deleteActions({ - ids, - http, -}: { - ids: string[]; - http: HttpServiceBase; -}): Promise { - await Promise.all(ids.map(id => http.delete(`${BASE_ACTION_API_PATH}/${id}`))); -} - -export async function loadAlertTypes({ http }: { http: HttpServiceBase }): Promise { - return await http.get(`${BASE_ALERT_API_PATH}/types`); -} - -export async function loadAlerts({ - http, - page, - searchText, - tagsFilter, - typesFilter, -}: { - http: HttpServiceBase; - page: { index: number; size: number }; - searchText?: string; - tagsFilter?: string[]; - typesFilter?: string[]; -}): Promise<{ - page: number; - perPage: number; - total: number; - data: Alert[]; -}> { - const filters = []; - if (tagsFilter && tagsFilter.length) { - filters.push(`alert.attributes.tags:(${tagsFilter.join(' and ')})`); - } - if (typesFilter && typesFilter.length) { - filters.push(`alert.attributes.alertTypeId:(${typesFilter.join(' or ')})`); - } - return await http.get(`${BASE_ALERT_API_PATH}/_find`, { - query: { - page: page.index + 1, - per_page: page.size, - search_fields: searchText ? 'name' : undefined, - search: searchText, - filter: filters.length ? filters.join(' and ') : undefined, - }, - }); -} - -export async function deleteAlerts({ - ids, - http, -}: { - ids: string[]; - http: HttpServiceBase; -}): Promise { - await Promise.all(ids.map(id => http.delete(`${BASE_ALERT_API_PATH}/${id}`))); -} - -export async function createAlert({ - http, - alert, -}: { - http: HttpServiceBase; - alert: Omit; -}): Promise { - return await http.post(`${BASE_ALERT_API_PATH}`, { - body: JSON.stringify(alert), - }); -} - -export async function updateAlert({ - http, - alert, - id, -}: { - http: HttpServiceBase; - alert: Pick; - id: string; -}): Promise { - return await http.put(`${BASE_ALERT_API_PATH}/${id}`, { - body: JSON.stringify(alert), - }); -} - -export async function enableAlerts({ - ids, - http, -}: { - ids: string[]; - http: HttpServiceBase; -}): Promise { - await Promise.all(ids.map(id => http.post(`${BASE_ALERT_API_PATH}/${id}/_enable`))); -} - -export async function disableAlerts({ - ids, - http, -}: { - ids: string[]; - http: HttpServiceBase; -}): Promise { - await Promise.all(ids.map(id => http.post(`${BASE_ALERT_API_PATH}/${id}/_disable`))); -} - -export async function muteAlerts({ - ids, - http, -}: { - ids: string[]; - http: HttpServiceBase; -}): Promise { - await Promise.all(ids.map(id => http.post(`${BASE_ALERT_API_PATH}/${id}/_mute_all`))); -} - -export async function unmuteAlerts({ - ids, - http, -}: { - ids: string[]; - http: HttpServiceBase; -}): Promise { - await Promise.all(ids.map(id => http.post(`${BASE_ALERT_API_PATH}/${id}/_unmute_all`))); -} - // TODO: replace watcher api with the proper from alerts export async function getMatchingIndicesForThresholdAlertType({ diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index e78402a82155d0..ff161cf866a548 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -20,7 +20,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { createActionConnector, updateActionConnector } from '../../lib/api'; +import { createActionConnector, updateActionConnector } from '../../lib/action_connector_api'; import { SectionError, ErrableFormRow } from '../../components/page_error'; import { useAppDependencies } from '../../app_dependencies'; import { connectorReducer } from './connector_reducer'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index 1d20e4c1e5cfa2..bb2f7a6f057ebd 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { ActionsConnectorsContext } from '../../../context/actions_connectors_context'; import { useAppDependencies } from '../../../app_dependencies'; -import { deleteActions, loadAllActions, loadActionTypes } from '../../../lib/api'; +import { deleteActions, loadAllActions, loadActionTypes } from '../../../lib/action_connector_api'; import { ActionConnector, ActionConnectorTableItem, ActionTypeIndex } from '../../../../types'; import { ConnectorAddFlyout, ConnectorEditFlyout } from '../../action_connector_form'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index d3c5d8f3bcb1be..8baa035a8dadc8 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -35,7 +35,8 @@ import { EuiButtonIcon, } from '@elastic/eui'; import { useAppDependencies } from '../../app_dependencies'; -import { createAlert, loadActionTypes, loadAllActions } from '../../lib/api'; +import { createAlert } from '../../lib/alert_api'; +import { loadActionTypes, loadAllActions } from '../../lib/action_connector_api'; import { AlertsContext } from '../../context/alerts_context'; import { alertReducer } from './alert_reducer'; import { ErrableFormRow, SectionError } from '../../components/page_error'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 231ce7a7520a60..82a5fa5f766f6d 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -18,7 +18,7 @@ import { BulkActionPopover } from './bulk_action_popover'; import { CollapsedItemActions } from './collapsed_item_actions'; import { TagsFilter } from './tags_filter'; import { TypeFilter } from './type_filter'; -import { loadAlerts, loadAlertTypes } from '../../../lib/api'; +import { loadAlerts, loadAlertTypes } from '../../../lib/alert_api'; export const AlertsList: React.FunctionComponent = () => { const { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx index 7b98f6a2047f70..b5984f8f37c534 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx @@ -17,7 +17,7 @@ import { enableAlerts, muteAlerts, unmuteAlerts, -} from '../../../lib/api'; +} from '../../../lib/alert_api'; export interface ComponentOpts { selectedItems: AlertTableItem[]; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx index 9a911226cf7577..6d32170548f697 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx @@ -24,7 +24,7 @@ import { enableAlerts, muteAlerts, unmuteAlerts, -} from '../../../lib/api'; +} from '../../../lib/alert_api'; export interface ComponentOpts { item: AlertTableItem; From f6daeb3d5ea8c281fa3ce7393015ce5684cbd25a Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 28 Nov 2019 15:09:59 -0500 Subject: [PATCH 156/297] Rename plugin id --- x-pack/.i18nrc.json | 2 +- x-pack/legacy/plugins/triggers_actions_ui/index.ts | 2 +- x-pack/legacy/plugins/triggers_actions_ui/np_ready/kibana.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index 6eea8932edded0..55fbb290c5670c 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -4,7 +4,7 @@ "xpack.actions": "legacy/plugins/actions", "xpack.advancedUiActions": "plugins/advanced_ui_actions", "xpack.alerting": "legacy/plugins/alerting", - "xpack.alertingUI": "legacy/plugins/triggers_actions_ui", + "xpack.alertingUI": "legacy/plugins/triggersActionsUI", "xpack.apm": "legacy/plugins/apm", "xpack.beatsManagement": "legacy/plugins/beats_management", "xpack.canvas": "legacy/plugins/canvas", diff --git a/x-pack/legacy/plugins/triggers_actions_ui/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/index.ts index f2cf9b5cd7e99a..a28d632646fabf 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/index.ts @@ -10,7 +10,7 @@ import { resolve } from 'path'; export function triggersActionsUI(kibana: any) { return new kibana.Plugin({ - id: 'triggers_actions_ui', + id: 'triggersActionsUI', configPrefix: 'xpack.triggers_actions_ui', publicDir: resolve(__dirname, 'public'), require: ['kibana', 'actions'], diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/kibana.json b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/kibana.json index 3fd7389aef494e..3ec1b3c7190f06 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/kibana.json +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/kibana.json @@ -1,5 +1,5 @@ { - "id": "triggers_actions_ui", + "id": "triggersActionsUI", "version": "kibana", "server": false, "ui": true From d567daef9e59c889da34a43c0844392c461c7bc1 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 28 Nov 2019 15:16:38 -0500 Subject: [PATCH 157/297] Remove dependency on actions plugin (should be optional dep in NP) --- x-pack/legacy/plugins/triggers_actions_ui/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/index.ts index a28d632646fabf..319e7147ef63d8 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/index.ts @@ -13,7 +13,7 @@ export function triggersActionsUI(kibana: any) { id: 'triggersActionsUI', configPrefix: 'xpack.triggers_actions_ui', publicDir: resolve(__dirname, 'public'), - require: ['kibana', 'actions'], + require: ['kibana'], isEnabled(config: Legacy.KibanaConfig) { return ( config.get('xpack.triggers_actions_ui.enabled') && From e1f70954b9dcefedfd7ead20b041c5d7432884a1 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 28 Nov 2019 15:22:34 -0500 Subject: [PATCH 158/297] Fix some translation ids --- .../components/builtin_action_types/email.tsx | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx index 6b21ce0e5f6182..08adb3d6a132ed 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx @@ -167,7 +167,7 @@ const EmailActionConnectorFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors && to !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.emailAction.recipientTextFieldLabel', + 'xpack.triggersActionsUI.sections.builtinActionTypes.emailAction.recipientTextFieldLabel', { defaultMessage: 'To', } @@ -376,7 +376,7 @@ const EmailParamsFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors && cc !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.emailAction.recipientCopyTextFieldLabel', + 'xpack.triggersActionsUI.sections.builtinActionTypes.emailAction.recipientCopyTextFieldLabel', { defaultMessage: 'Cc', } @@ -415,7 +415,7 @@ const EmailParamsFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors && bcc !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.emailAction.recipientBccTextFieldLabel', + 'xpack.triggersActionsUI.sections.builtinActionTypes.emailAction.recipientBccTextFieldLabel', { defaultMessage: 'Bcc', } @@ -454,7 +454,7 @@ const EmailParamsFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors && message !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.emailAction.subjectTextFieldLabel', + 'xpack.triggersActionsUI.sections.builtinActionTypes.emailAction.subjectTextFieldLabel', { defaultMessage: 'Subject', } @@ -476,7 +476,7 @@ const EmailParamsFields: React.FunctionComponent = ({ errors={errors} isShowingErrors={hasErrors && message !== undefined} label={i18n.translate( - 'xpack.triggersActionsUI.sections.actionAdd.emailAction.messageTextAreaFieldLabel', + 'xpack.triggersActionsUI.sections.builtinActionTypes.emailAction.messageTextAreaFieldLabel', { defaultMessage: 'Message', } From 48fd098ea42f4f582ec5f24c7cb78f0b83c80f1c Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 2 Dec 2019 09:56:14 -0500 Subject: [PATCH 159/297] Revert "Rename plugin id" This reverts commit f6daeb3d5ea8c281fa3ce7393015ce5684cbd25a. --- x-pack/.i18nrc.json | 2 +- x-pack/legacy/plugins/triggers_actions_ui/index.ts | 2 +- x-pack/legacy/plugins/triggers_actions_ui/np_ready/kibana.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index 55fbb290c5670c..6eea8932edded0 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -4,7 +4,7 @@ "xpack.actions": "legacy/plugins/actions", "xpack.advancedUiActions": "plugins/advanced_ui_actions", "xpack.alerting": "legacy/plugins/alerting", - "xpack.alertingUI": "legacy/plugins/triggersActionsUI", + "xpack.alertingUI": "legacy/plugins/triggers_actions_ui", "xpack.apm": "legacy/plugins/apm", "xpack.beatsManagement": "legacy/plugins/beats_management", "xpack.canvas": "legacy/plugins/canvas", diff --git a/x-pack/legacy/plugins/triggers_actions_ui/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/index.ts index 319e7147ef63d8..3be7ff189db3d3 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/index.ts @@ -10,7 +10,7 @@ import { resolve } from 'path'; export function triggersActionsUI(kibana: any) { return new kibana.Plugin({ - id: 'triggersActionsUI', + id: 'triggers_actions_ui', configPrefix: 'xpack.triggers_actions_ui', publicDir: resolve(__dirname, 'public'), require: ['kibana'], diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/kibana.json b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/kibana.json index 3ec1b3c7190f06..3fd7389aef494e 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/kibana.json +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/kibana.json @@ -1,5 +1,5 @@ { - "id": "triggersActionsUI", + "id": "triggers_actions_ui", "version": "kibana", "server": false, "ui": true From 75679d2b12a641ce41cfb8e98f22ffc8298e0f6a Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 2 Dec 2019 08:22:09 -0800 Subject: [PATCH 160/297] Rename method for loading connectors --- .../context/actions_connectors_context.tsx | 2 +- .../action_connector_form.tsx | 59 ++++++++----------- .../components/actions_connectors_list.tsx | 2 +- 3 files changed, 28 insertions(+), 35 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_connectors_context.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_connectors_context.tsx index f5e3be2d688489..ac49e9c2c77ece 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_connectors_context.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_connectors_context.tsx @@ -14,5 +14,5 @@ export interface IActionsConnectorsContext { setEditFlyoutVisibility: React.Dispatch>; setAddFlyoutVisibility: React.Dispatch>; actionTypesIndex: Record | undefined; - loadActions: () => Promise; + reloadConnectors: () => Promise; } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index ff161cf866a548..81ea09feb35492 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -44,7 +44,7 @@ export const ActionConnectorForm = ({ actionTypeRegistry, } = useAppDependencies(); - const { loadActions } = useContext(ActionsConnectorsContext); + const { reloadConnectors } = useContext(ActionsConnectorsContext); // hooks const [{ connector }, dispatch] = useReducer(connectorReducer, { connector: initialAction }); @@ -70,6 +70,9 @@ export const ActionConnectorForm = ({ body: { message: string; error: string }; } | null>(null); + const actionTypeRegisterd = actionTypeRegistry.get(initialAction.actionTypeId); + if (actionTypeRegisterd === null) return null; + function validateBaseProperties(actionObject: ActionConnector) { const validationResult = { errors: {} }; const errors = { @@ -89,8 +92,6 @@ export const ActionConnectorForm = ({ return validationResult; } - const actionTypeRegisterd = actionTypeRegistry.get(initialAction.actionTypeId); - if (actionTypeRegisterd === null) return null; const FieldsComponent = actionTypeRegisterd.actionConnectorFields; const errors = { ...actionTypeRegisterd.validateConnector(connector).errors, @@ -98,38 +99,30 @@ export const ActionConnectorForm = ({ } as IErrorObject; const hasErrors = !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); - async function onActionSave(): Promise { + async function onActionConnectorSave(): Promise { try { - let newAction; + let savingMessage; + let savedConnector; if (connector.id === undefined) { - newAction = await createActionConnector({ http, connector }); - toastNotifications.addSuccess( - i18n.translate( - 'xpack.triggersActionsUI.sections.actionConnectorForm.saveSuccessNotificationText', - { - defaultMessage: "Created '{actionName}'", - values: { - actionName: newAction.description, - }, - } - ) - ); + savedConnector = await createActionConnector({ http, connector }); + savingMessage = 'Updated'; } else { - newAction = await updateActionConnector({ http, connector, id: connector.id }); - toastNotifications.addSuccess( - i18n.translate( - 'xpack.triggersActionsUI.sections.actionConnectorForm.saveSuccessNotificationText', - { - defaultMessage: "Updated '{actionName}'", - values: { - actionName: newAction.description, - }, - } - ) - ); + savedConnector = await updateActionConnector({ http, connector, id: connector.id }); + savingMessage = 'Created'; } - - return newAction; + toastNotifications.addSuccess( + i18n.translate( + 'xpack.triggersActionsUI.sections.actionConnectorForm.saveSuccessNotificationText', + { + defaultMessage: "{savingMessage} '{connectorName}'", + values: { + connectorName: savedConnector.description, + savingMessage, + }, + } + ) + ); + return savedConnector; } catch (error) { return { error, @@ -254,13 +247,13 @@ export const ActionConnectorForm = ({ isLoading={isSaving} onClick={async () => { setIsSaving(true); - const savedAction = await onActionSave(); + const savedAction = await onActionConnectorSave(); setIsSaving(false); if (savedAction && savedAction.error) { return setServerError(savedAction.error); } setFlyoutVisibility(false); - loadActions(); + reloadConnectors(); }} > { editFlyoutVisible, setEditFlyoutVisibility, actionTypesIndex, - loadActions, + reloadConnectors: loadActions, }} > Date: Mon, 2 Dec 2019 12:01:33 -0800 Subject: [PATCH 161/297] Added functional tests base --- .../np_ready/public/application/home.tsx | 2 +- .../components/actions_connectors_list.tsx | 6 ++- .../apps/triggers_actions_ui/home_page.ts | 52 +++++++++++++++++++ .../apps/triggers_actions_ui/index.ts | 14 +++++ x-pack/test/functional/config.js | 7 ++- x-pack/test/functional/page_objects/index.ts | 2 + .../page_objects/triggers_actions_ui_page.ts | 50 ++++++++++++++++++ 7 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 x-pack/test/functional/apps/triggers_actions_ui/home_page.ts create mode 100644 x-pack/test/functional/apps/triggers_actions_ui/index.ts create mode 100644 x-pack/test/functional/page_objects/triggers_actions_ui_page.ts diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx index 6a15aefeadfe43..aaefb2797a25f6 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx @@ -103,7 +103,7 @@ export const TriggersActionsUIHome: React.FunctionComponent onSectionChange(tab.id)} isSelected={tab.id === section} key={tab.id} - data-test-subj="tab" + data-test-subj={`${tab.id}Tab`} > {tab.name} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index 97292be285d2fc..10a58cd7368893 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -144,6 +144,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { const actionsTableColumns = [ { field: 'actionType', + 'data-test-subj': 'connectorsTableCell-actionType', name: i18n.translate( 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actionTypeTitle', { @@ -155,6 +156,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { }, { field: 'description', + 'data-test-subj': 'connectorsTableCell-description', name: i18n.translate( 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.descriptionTitle', { @@ -166,6 +168,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { }, { field: 'referencedByCount', + 'data-test-subj': 'connectorsTableCell-referencedByCount', name: i18n.translate( 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.referencedByCountTitle', { defaultMessage: 'Attached actions' } @@ -242,7 +245,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { itemId="id" columns={actionsTableColumns} rowProps={() => ({ - 'data-test-subj': 'row', + 'data-test-subj': 'connectors-row', })} cellProps={() => ({ 'data-test-subj': 'cell', @@ -261,6 +264,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { { type: 'field_value_selection', field: 'actionTypeId', + 'data-test-subj': 'typeFilterButton', name: i18n.translate( 'xpack.triggersActionsUI.sections.actionsConnectorsList.filters.actionTypeIdName', { defaultMessage: 'Type' } diff --git a/x-pack/test/functional/apps/triggers_actions_ui/home_page.ts b/x-pack/test/functional/apps/triggers_actions_ui/home_page.ts new file mode 100644 index 00000000000000..0e9b9e7decb65b --- /dev/null +++ b/x-pack/test/functional/apps/triggers_actions_ui/home_page.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 expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default ({ getPageObjects, getService }: FtrProviderContext) => { + const testSubjects = getService('testSubjects'); + const pageObjects = getPageObjects(['common', 'triggersActionsUI', 'header']); + const log = getService('log'); + const browser = getService('browser'); + + describe('Home page', function() { + before(async () => { + await pageObjects.common.navigateToApp('triggersActions'); + }); + + it('Loads the app', async () => { + await log.debug('Checking for section heading to say Triggers and Actions.'); + + const headingText = await pageObjects.triggersActionsUI.sectionHeadingText(); + expect(headingText).to.be('Triggers and Actions'); + + const actionsConnectorsList = await testSubjects.exists('actionsList'); + expect(actionsConnectorsList).to.be(true); + + // TODO: find the way to add data-test-subj to typeFilterButton + // const typeFilterButton = await pageObjects.triggersActionsUI.typeFilterButton(); + // expect(await typeFilterButton.isDisplayed()).to.be(true); + }); + + describe('Alerts tab', () => { + it('renders the alerts tab', async () => { + // Navigate to the alerts tab + pageObjects.triggersActionsUI.changeTabs('alertsTab'); + + await pageObjects.header.waitUntilLoadingHasFinished(); + + // Verify url + const url = await browser.getCurrentUrl(); + expect(url).to.contain(`/alerts`); + + // Verify content + const alertsList = await testSubjects.exists('alertsList'); + expect(alertsList).to.be(true); + }); + }); + }); +}; diff --git a/x-pack/test/functional/apps/triggers_actions_ui/index.ts b/x-pack/test/functional/apps/triggers_actions_ui/index.ts new file mode 100644 index 00000000000000..c2d17fb46880ff --- /dev/null +++ b/x-pack/test/functional/apps/triggers_actions_ui/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default ({ loadTestFile, getService }: FtrProviderContext) => { + describe('Actions and Triggers app', function() { + this.tags('ciGroup3'); // not sure about which CI group this tests should belong to + loadTestFile(require.resolve('./home_page')); + }); +}; diff --git a/x-pack/test/functional/config.js b/x-pack/test/functional/config.js index f4b2be34202980..063ab65400d62d 100644 --- a/x-pack/test/functional/config.js +++ b/x-pack/test/functional/config.js @@ -58,6 +58,7 @@ export default async function ({ readConfigFile }) { resolve(__dirname, './apps/transform'), // This license_management file must be last because it is destructive. resolve(__dirname, './apps/license_management'), + resolve(__dirname, './apps/triggers_actions_ui'), ], services, @@ -196,7 +197,11 @@ export default async function ({ readConfigFile }) { transform: { pathname: '/app/kibana/', hash: '/management/elasticsearch/transform' - } + }, + triggersActions: { + pathname: '/app/kibana', + hash: '/management/kibana/triggersActions', + }, }, // choose where esArchiver should load archives from diff --git a/x-pack/test/functional/page_objects/index.ts b/x-pack/test/functional/page_objects/index.ts index 82011c48d44603..88e70001d93df6 100644 --- a/x-pack/test/functional/page_objects/index.ts +++ b/x-pack/test/functional/page_objects/index.ts @@ -46,6 +46,7 @@ import { RemoteClustersPageProvider } from './remote_clusters_page'; import { CopySavedObjectsToSpacePageProvider } from './copy_saved_objects_to_space_page'; import { LensPageProvider } from './lens_page'; import { InfraMetricExplorerProvider } from './infra_metric_explorer'; +import { TriggersActionsPageProvider } from './triggers_actions_ui_page'; // just like services, PageObjects are defined as a map of // names to Providers. Merge in Kibana's or pick specific ones @@ -78,4 +79,5 @@ export const pageObjects = { remoteClusters: RemoteClustersPageProvider, copySavedObjectsToSpace: CopySavedObjectsToSpacePageProvider, lens: LensPageProvider, + triggersActionsUI: TriggersActionsPageProvider, }; diff --git a/x-pack/test/functional/page_objects/triggers_actions_ui_page.ts b/x-pack/test/functional/page_objects/triggers_actions_ui_page.ts new file mode 100644 index 00000000000000..f3d53baf6857e1 --- /dev/null +++ b/x-pack/test/functional/page_objects/triggers_actions_ui_page.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { FtrProviderContext } from '../ftr_provider_context'; + +export function TriggersActionsPageProvider({ getService }: FtrProviderContext) { + const find = getService('find'); + const testSubjects = getService('testSubjects'); + + return { + async sectionHeadingText() { + return await testSubjects.getVisibleText('appTitle'); + }, + async selectActionTypeFilter() { + await testSubjects.click('typeFilterButton'); + }, + async typeFilterButton() { + return await testSubjects.find('typeFilterButton'); + }, + async createActionConnector() { + await testSubjects.click('createActionButton'); + }, + + async getActionConnectorsList() { + const table = await find.byCssSelector('table'); + const $ = await table.parseDomContent(); + return $.findTestSubjects('connectors-row') + .toArray() + .map(row => { + return { + indexHealth: $(row) + .findTestSubject('cell-actionType') + .text(), + indexStatus: $(row) + .findTestSubject('cell-description') + .text(), + indexPrimary: $(row) + .findTestSubject('cell-referencedByCount') + .text(), + }; + }); + }, + async changeTabs(tab: 'alertsTab' | 'connectorsTab') { + return await testSubjects.click(tab); + }, + }; +} From 5bd6278f67fef39d0ee872800e5f0dc97314df02 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 2 Dec 2019 15:47:30 -0500 Subject: [PATCH 162/297] Fix functional test type filter --- x-pack/test/functional/apps/triggers_actions_ui/home_page.ts | 5 ++--- .../test/functional/page_objects/triggers_actions_ui_page.ts | 5 ++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/x-pack/test/functional/apps/triggers_actions_ui/home_page.ts b/x-pack/test/functional/apps/triggers_actions_ui/home_page.ts index 0e9b9e7decb65b..8d6f41a4a76c77 100644 --- a/x-pack/test/functional/apps/triggers_actions_ui/home_page.ts +++ b/x-pack/test/functional/apps/triggers_actions_ui/home_page.ts @@ -27,9 +27,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const actionsConnectorsList = await testSubjects.exists('actionsList'); expect(actionsConnectorsList).to.be(true); - // TODO: find the way to add data-test-subj to typeFilterButton - // const typeFilterButton = await pageObjects.triggersActionsUI.typeFilterButton(); - // expect(await typeFilterButton.isDisplayed()).to.be(true); + const typeFilterButton = await pageObjects.triggersActionsUI.typeFilterButton(); + expect(await typeFilterButton.isDisplayed()).to.be(true); }); describe('Alerts tab', () => { diff --git a/x-pack/test/functional/page_objects/triggers_actions_ui_page.ts b/x-pack/test/functional/page_objects/triggers_actions_ui_page.ts index f3d53baf6857e1..8a25249e5c81eb 100644 --- a/x-pack/test/functional/page_objects/triggers_actions_ui_page.ts +++ b/x-pack/test/functional/page_objects/triggers_actions_ui_page.ts @@ -18,7 +18,10 @@ export function TriggersActionsPageProvider({ getService }: FtrProviderContext) await testSubjects.click('typeFilterButton'); }, async typeFilterButton() { - return await testSubjects.find('typeFilterButton'); + const typeFilter = await find.allByCssSelector( + '.euiFilterButton__textShift[data-text="Type"]' + ); + return typeFilter[0]; }, async createActionConnector() { await testSubjects.click('createActionButton'); From 9fc0bfb283a6a6175547e7d673a19593fc4979ad Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 3 Dec 2019 11:23:44 -0500 Subject: [PATCH 163/297] Add test alert type for now --- x-pack/legacy/plugins/alerting/server/plugin.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/x-pack/legacy/plugins/alerting/server/plugin.ts b/x-pack/legacy/plugins/alerting/server/plugin.ts index 9889e01e0ca19e..a114f9e4e110cc 100644 --- a/x-pack/legacy/plugins/alerting/server/plugin.ts +++ b/x-pack/legacy/plugins/alerting/server/plugin.ts @@ -118,6 +118,14 @@ export class Plugin { core.http.route(muteAlertInstanceRoute); core.http.route(unmuteAlertInstanceRoute); + // TODO: Remove, this is only for dev purposes and should be removed before branch is merged + alertTypeRegistry.register({ + id: 'test', + name: 'Test', + actionGroups: ['default'], + executor(): any {}, + }); + return { registerType: alertTypeRegistry.register.bind(alertTypeRegistry), }; From c86e99ec146ace28176b74accb05f0687ab5c382 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 3 Dec 2019 13:29:40 -0500 Subject: [PATCH 164/297] Initial connectors functional tests --- .../action_connector_form.tsx | 25 ++-- .../action_type_menu.tsx | 1 + .../components/actions_connectors_list.tsx | 2 + .../apps/triggers_actions_ui/connectors.ts | 137 ++++++++++++++++++ .../apps/triggers_actions_ui/index.ts | 1 + 5 files changed, 156 insertions(+), 10 deletions(-) create mode 100644 x-pack/test/functional/apps/triggers_actions_ui/connectors.ts diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index 81ea09feb35492..e92eb5f8b980c2 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -101,27 +101,32 @@ export const ActionConnectorForm = ({ async function onActionConnectorSave(): Promise { try { - let savingMessage; + let message; let savedConnector; if (connector.id === undefined) { savedConnector = await createActionConnector({ http, connector }); - savingMessage = 'Updated'; + message = i18n.translate( + 'xpack.triggersActionsUI.sections.actionConnectorForm.saveSuccessNotificationText', + { + defaultMessage: "Created '{connectorName}'", + values: { + connectorName: savedConnector.description, + }, + } + ); } else { savedConnector = await updateActionConnector({ http, connector, id: connector.id }); - savingMessage = 'Created'; - } - toastNotifications.addSuccess( - i18n.translate( + message = i18n.translate( 'xpack.triggersActionsUI.sections.actionConnectorForm.saveSuccessNotificationText', { - defaultMessage: "{savingMessage} '{connectorName}'", + defaultMessage: "Updated '{connectorName}'", values: { connectorName: savedConnector.description, - savingMessage, }, } - ) - ); + ); + } + toastNotifications.addSuccess(message); return savedConnector; } catch (error) { return { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx index 2efae6b950412a..b8b9f94bdb9ac7 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx @@ -46,6 +46,7 @@ export const ActionTypeMenu = ({ setActionType }: Props) => { return ( } title={item.name} description={item.selectMessage} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index 10a58cd7368893..5ec30e07b67969 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -184,6 +184,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { actions: [ { enabled: () => canSave, + 'data-test-subj': 'editConnector', name: i18n.translate( 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.editActionName', { defaultMessage: 'Edit' } @@ -203,6 +204,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { }, { enabled: () => canDelete, + 'data-test-subj': 'deleteConnector', name: i18n.translate( 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.deleteActionName', { defaultMessage: 'Delete' } diff --git a/x-pack/test/functional/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional/apps/triggers_actions_ui/connectors.ts new file mode 100644 index 00000000000000..df3c39b23d2c2c --- /dev/null +++ b/x-pack/test/functional/apps/triggers_actions_ui/connectors.ts @@ -0,0 +1,137 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +const ENTER_KEY = '\uE007'; + +export default ({ getPageObjects, getService }: FtrProviderContext) => { + const testSubjects = getService('testSubjects'); + const pageObjects = getPageObjects(['common', 'triggersActionsUI', 'header']); + const find = getService('find'); + + describe('Connectors', function() { + before(async () => { + await pageObjects.common.navigateToApp('triggersActions'); + }); + + it('should create a connector', async () => { + await pageObjects.triggersActionsUI.createActionConnector(); + + const serverLogCard = await testSubjects.find('.server-log-card'); + await serverLogCard.click(); + + const descriptionInput = await testSubjects.find('descriptionInput'); + await descriptionInput.click(); + await descriptionInput.clearValue(); + await descriptionInput.type('My server log connector'); + + const saveButton = await find.byCssSelector( + '[data-test-subj="saveActionButton"]:not(disabled)' + ); + await saveButton.click(); + + const toastMessage = await find.byCssSelector( + '[data-test-subj="euiToastHeader"] .euiToastHeader__title' + ); + expect(await toastMessage.getVisibleText()).to.eql(`Created 'My server log connector'`); + + const closeButton = await testSubjects.find('toastCloseButton'); + await closeButton.click(); + }); + + it('should edit a connector', async () => { + await pageObjects.triggersActionsUI.createActionConnector(); + + const serverLogCard = await testSubjects.find('.server-log-card'); + await serverLogCard.click(); + + const descriptionInput = await testSubjects.find('descriptionInput'); + await descriptionInput.click(); + await descriptionInput.clearValue(); + await descriptionInput.type('My server log connector to update'); + + const saveButton = await find.byCssSelector( + '[data-test-subj="saveActionButton"]:not(disabled)' + ); + await saveButton.click(); + + const closeToastButton = await testSubjects.find('toastCloseButton'); + await closeToastButton.click(); + + const searchBox = await find.byCssSelector('[data-test-subj="actionsList"] .euiFieldSearch'); + await searchBox.click(); + await searchBox.clearValue(); + await searchBox.type('My server log connector to update'); + await searchBox.pressKeys(ENTER_KEY); + + const rowsBeforeDelete = await testSubjects.findAll('connectors-row'); + expect(rowsBeforeDelete.length).to.eql(1); + + const deleteConnectorBtn = await testSubjects.find('editConnector'); + await deleteConnectorBtn.click(); + + const descriptionInputToUpdate = await testSubjects.find('descriptionInput'); + await descriptionInputToUpdate.click(); + await descriptionInputToUpdate.type(' is now updated'); + + const saveEditButton = await find.byCssSelector( + '[data-test-subj="saveActionButton"]:not(disabled)' + ); + await saveEditButton.click(); + + const toastMessage = await find.byCssSelector( + '[data-test-subj="euiToastHeader"] .euiToastHeader__title' + ); + expect(await toastMessage.getVisibleText()).to.eql( + `Updated 'My server log connector to update is now updated'` + ); + + const closeToastUpdatedButton = await testSubjects.find('toastCloseButton'); + await closeToastUpdatedButton.click(); + }); + + it('should delete a connector', async () => { + await pageObjects.triggersActionsUI.createActionConnector(); + + const serverLogCard = await testSubjects.find('.server-log-card'); + await serverLogCard.click(); + + const descriptionInput = await testSubjects.find('descriptionInput'); + await descriptionInput.click(); + await descriptionInput.clearValue(); + await descriptionInput.type('My server log connector to delete'); + + const saveButton = await find.byCssSelector( + '[data-test-subj="saveActionButton"]:not(disabled)' + ); + await saveButton.click(); + + await testSubjects.exists('euiToastHeader'); + + const closeButton = await testSubjects.find('toastCloseButton'); + await closeButton.click(); + + const searchBox = await find.byCssSelector('[data-test-subj="actionsList"] .euiFieldSearch'); + await searchBox.click(); + await searchBox.clearValue(); + await searchBox.type('My server log connector to delete'); + await searchBox.pressKeys(ENTER_KEY); + + const rowsBeforeDelete = await testSubjects.findAll('connectors-row'); + expect(rowsBeforeDelete.length).to.eql(1); + + const deleteConnectorBtn = await testSubjects.find('deleteConnector'); + await deleteConnectorBtn.click(); + + await find.byCssSelector('[data-test-subj="actionsTable"]:not(.euiBasicTable-loading)'); + + const rowsAfterDelete = await testSubjects.findAll('connectors-row'); + expect(rowsAfterDelete.length).to.eql(0); + }); + }); +}; diff --git a/x-pack/test/functional/apps/triggers_actions_ui/index.ts b/x-pack/test/functional/apps/triggers_actions_ui/index.ts index c2d17fb46880ff..a3cbb27f50d353 100644 --- a/x-pack/test/functional/apps/triggers_actions_ui/index.ts +++ b/x-pack/test/functional/apps/triggers_actions_ui/index.ts @@ -10,5 +10,6 @@ export default ({ loadTestFile, getService }: FtrProviderContext) => { describe('Actions and Triggers app', function() { this.tags('ciGroup3'); // not sure about which CI group this tests should belong to loadTestFile(require.resolve('./home_page')); + loadTestFile(require.resolve('./connectors')); }); }; From 570a358fd2f2a74b62b08ea486cf5a171f819019 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 3 Dec 2019 13:48:24 -0500 Subject: [PATCH 165/297] Rename description to name --- .../lib/action_connector_api.test.ts | 8 ++--- .../application/lib/action_connector_api.ts | 2 +- .../action_connector_form.tsx | 28 ++++++++--------- .../components/actions_connectors_list.tsx | 6 ++-- .../sections/alert_add/alert_add.tsx | 10 +++---- .../np_ready/public/types.ts | 2 +- .../apps/triggers_actions_ui/connectors.ts | 30 +++++++++---------- 7 files changed, 43 insertions(+), 43 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.test.ts index c0270647178839..ad5a75d577515b 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.test.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.test.ts @@ -67,7 +67,7 @@ describe('createActionConnector', () => { test('should call create action API', async () => { const connector: ActionConnectorWithoutId = { actionTypeId: 'test', - description: 'My test', + name: 'My test', config: {}, secrets: {}, }; @@ -80,7 +80,7 @@ describe('createActionConnector', () => { Array [ "/api/action", Object { - "body": "{\\"actionTypeId\\":\\"test\\",\\"description\\":\\"My test\\",\\"config\\":{},\\"secrets\\":{}}", + "body": "{\\"actionTypeId\\":\\"test\\",\\"name\\":\\"My test\\",\\"config\\":{},\\"secrets\\":{}}", }, ] `); @@ -92,7 +92,7 @@ describe('updateActionConnector', () => { const id = '123'; const connector: ActionConnectorWithoutId = { actionTypeId: 'test', - description: 'My test', + name: 'My test', config: {}, secrets: {}, }; @@ -105,7 +105,7 @@ describe('updateActionConnector', () => { Array [ "/api/action/123", Object { - "body": "{\\"description\\":\\"My test\\",\\"config\\":{},\\"secrets\\":{}}", + "body": "{\\"name\\":\\"My test\\",\\"config\\":{},\\"secrets\\":{}}", }, ] `); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts index 0a9a9eef3ecc99..ab8ec7777df225 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts @@ -52,7 +52,7 @@ export async function updateActionConnector({ id, }: { http: HttpServiceBase; - connector: Pick; + connector: Pick; id: string; }): Promise { return await http.put(`${BASE_ACTION_API_PATH}/${id}`, { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index e92eb5f8b980c2..7acd2c6274a766 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -79,7 +79,7 @@ export const ActionConnectorForm = ({ description: new Array(), }; validationResult.errors = errors; - if (!actionObject.description) { + if (!actionObject.name) { errors.description.push( i18n.translate( 'xpack.triggersActionsUI.sections.actionConnectorForm.error.requiredNameText', @@ -110,7 +110,7 @@ export const ActionConnectorForm = ({ { defaultMessage: "Created '{connectorName}'", values: { - connectorName: savedConnector.description, + connectorName: savedConnector.name, }, } ); @@ -121,7 +121,7 @@ export const ActionConnectorForm = ({ { defaultMessage: "Updated '{connectorName}'", values: { - connectorName: savedConnector.description, + connectorName: savedConnector.name, }, } ); @@ -154,29 +154,29 @@ export const ActionConnectorForm = ({ )} } - errorKey="description" - isShowingErrors={hasErrors && connector.description !== undefined} + errorKey="name" + isShowingErrors={hasErrors && connector.name !== undefined} errors={errors} > { - setActionProperty('description', e.target.value); + setActionProperty('name', e.target.value); }} onBlur={() => { - if (!connector.description) { - setActionProperty('description', ''); + if (!connector.name) { + setActionProperty('name', ''); } }} /> diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index 5ec30e07b67969..3b68da010af94c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -155,10 +155,10 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { truncateText: true, }, { - field: 'description', - 'data-test-subj': 'connectorsTableCell-description', + field: 'name', + 'data-test-subj': 'connectorsTableCell-name', name: i18n.translate( - 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.descriptionTitle', + 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.nameTitle', { defaultMessage: 'Name', } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 8baa035a8dadc8..ff6b2b202de3bc 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -387,8 +387,8 @@ export const AlertAdd = ({ refreshList }: Props) => { } return [ { - label: val.description, - value: val.description, + label: val.name, + value: val.name, id: actionItemId, }, ]; @@ -403,8 +403,8 @@ export const AlertAdd = ({ refreshList }: Props) => { } const optionsList = connectors .filter(field => field.actionTypeId === actionConnector.actionTypeId) - .map(({ description, id }) => ({ - label: description, + .map(({ name, id }) => ({ + label: name, key: id, id, })); @@ -433,7 +433,7 @@ export const AlertAdd = ({ refreshList }: Props) => {
diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts index dbcd6f463ec240..c60854310bab15 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts @@ -51,7 +51,7 @@ export interface ActionConnector { secrets: Record; id: string; actionTypeId: string; - description: string; + name: string; referencedByCount?: number; config: Record; } diff --git a/x-pack/test/functional/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional/apps/triggers_actions_ui/connectors.ts index df3c39b23d2c2c..2e3d591cda678d 100644 --- a/x-pack/test/functional/apps/triggers_actions_ui/connectors.ts +++ b/x-pack/test/functional/apps/triggers_actions_ui/connectors.ts @@ -25,10 +25,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const serverLogCard = await testSubjects.find('.server-log-card'); await serverLogCard.click(); - const descriptionInput = await testSubjects.find('descriptionInput'); - await descriptionInput.click(); - await descriptionInput.clearValue(); - await descriptionInput.type('My server log connector'); + const nameInput = await testSubjects.find('nameInput'); + await nameInput.click(); + await nameInput.clearValue(); + await nameInput.type('My server log connector'); const saveButton = await find.byCssSelector( '[data-test-subj="saveActionButton"]:not(disabled)' @@ -50,10 +50,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const serverLogCard = await testSubjects.find('.server-log-card'); await serverLogCard.click(); - const descriptionInput = await testSubjects.find('descriptionInput'); - await descriptionInput.click(); - await descriptionInput.clearValue(); - await descriptionInput.type('My server log connector to update'); + const nameInput = await testSubjects.find('nameInput'); + await nameInput.click(); + await nameInput.clearValue(); + await nameInput.type('My server log connector to update'); const saveButton = await find.byCssSelector( '[data-test-subj="saveActionButton"]:not(disabled)' @@ -75,9 +75,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const deleteConnectorBtn = await testSubjects.find('editConnector'); await deleteConnectorBtn.click(); - const descriptionInputToUpdate = await testSubjects.find('descriptionInput'); - await descriptionInputToUpdate.click(); - await descriptionInputToUpdate.type(' is now updated'); + const nameInputToUpdate = await testSubjects.find('nameInput'); + await nameInputToUpdate.click(); + await nameInputToUpdate.type(' is now updated'); const saveEditButton = await find.byCssSelector( '[data-test-subj="saveActionButton"]:not(disabled)' @@ -101,10 +101,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const serverLogCard = await testSubjects.find('.server-log-card'); await serverLogCard.click(); - const descriptionInput = await testSubjects.find('descriptionInput'); - await descriptionInput.click(); - await descriptionInput.clearValue(); - await descriptionInput.type('My server log connector to delete'); + const nameInput = await testSubjects.find('nameInput'); + await nameInput.click(); + await nameInput.clearValue(); + await nameInput.type('My server log connector to delete'); const saveButton = await find.byCssSelector( '[data-test-subj="saveActionButton"]:not(disabled)' From b0437874b5da0f30545f508f814772ed882d381d Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 3 Dec 2019 13:58:18 -0500 Subject: [PATCH 166/297] Use unique connector names to allow re-running tests --- .../apps/triggers_actions_ui/connectors.ts | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/x-pack/test/functional/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional/apps/triggers_actions_ui/connectors.ts index 2e3d591cda678d..6c9ead231fbb58 100644 --- a/x-pack/test/functional/apps/triggers_actions_ui/connectors.ts +++ b/x-pack/test/functional/apps/triggers_actions_ui/connectors.ts @@ -4,11 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ +import uuid from 'uuid'; import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; const ENTER_KEY = '\uE007'; +function generateUniqueKey() { + return uuid.v4().replace(/-/g, ''); +} + export default ({ getPageObjects, getService }: FtrProviderContext) => { const testSubjects = getService('testSubjects'); const pageObjects = getPageObjects(['common', 'triggersActionsUI', 'header']); @@ -20,6 +25,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('should create a connector', async () => { + const connectorName = generateUniqueKey(); + await pageObjects.triggersActionsUI.createActionConnector(); const serverLogCard = await testSubjects.find('.server-log-card'); @@ -28,7 +35,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const nameInput = await testSubjects.find('nameInput'); await nameInput.click(); await nameInput.clearValue(); - await nameInput.type('My server log connector'); + await nameInput.type(connectorName); const saveButton = await find.byCssSelector( '[data-test-subj="saveActionButton"]:not(disabled)' @@ -38,13 +45,16 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const toastMessage = await find.byCssSelector( '[data-test-subj="euiToastHeader"] .euiToastHeader__title' ); - expect(await toastMessage.getVisibleText()).to.eql(`Created 'My server log connector'`); + expect(await toastMessage.getVisibleText()).to.eql(`Created '${connectorName}'`); const closeButton = await testSubjects.find('toastCloseButton'); await closeButton.click(); }); it('should edit a connector', async () => { + const connectorName = generateUniqueKey(); + const updatedConnectorName = `${connectorName}updated`; + await pageObjects.triggersActionsUI.createActionConnector(); const serverLogCard = await testSubjects.find('.server-log-card'); @@ -53,7 +63,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const nameInput = await testSubjects.find('nameInput'); await nameInput.click(); await nameInput.clearValue(); - await nameInput.type('My server log connector to update'); + await nameInput.type(connectorName); const saveButton = await find.byCssSelector( '[data-test-subj="saveActionButton"]:not(disabled)' @@ -66,7 +76,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const searchBox = await find.byCssSelector('[data-test-subj="actionsList"] .euiFieldSearch'); await searchBox.click(); await searchBox.clearValue(); - await searchBox.type('My server log connector to update'); + await searchBox.type(connectorName); await searchBox.pressKeys(ENTER_KEY); const rowsBeforeDelete = await testSubjects.findAll('connectors-row'); @@ -77,7 +87,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const nameInputToUpdate = await testSubjects.find('nameInput'); await nameInputToUpdate.click(); - await nameInputToUpdate.type(' is now updated'); + await nameInputToUpdate.clearValue(); + await nameInputToUpdate.type(updatedConnectorName); const saveEditButton = await find.byCssSelector( '[data-test-subj="saveActionButton"]:not(disabled)' @@ -87,15 +98,15 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const toastMessage = await find.byCssSelector( '[data-test-subj="euiToastHeader"] .euiToastHeader__title' ); - expect(await toastMessage.getVisibleText()).to.eql( - `Updated 'My server log connector to update is now updated'` - ); + expect(await toastMessage.getVisibleText()).to.eql(`Updated '${updatedConnectorName}'`); const closeToastUpdatedButton = await testSubjects.find('toastCloseButton'); await closeToastUpdatedButton.click(); }); it('should delete a connector', async () => { + const connectorName = generateUniqueKey(); + await pageObjects.triggersActionsUI.createActionConnector(); const serverLogCard = await testSubjects.find('.server-log-card'); @@ -104,7 +115,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const nameInput = await testSubjects.find('nameInput'); await nameInput.click(); await nameInput.clearValue(); - await nameInput.type('My server log connector to delete'); + await nameInput.type(connectorName); const saveButton = await find.byCssSelector( '[data-test-subj="saveActionButton"]:not(disabled)' @@ -119,7 +130,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const searchBox = await find.byCssSelector('[data-test-subj="actionsList"] .euiFieldSearch'); await searchBox.click(); await searchBox.clearValue(); - await searchBox.type('My server log connector to delete'); + await searchBox.type(connectorName); await searchBox.pressKeys(ENTER_KEY); const rowsBeforeDelete = await testSubjects.findAll('connectors-row'); From fba026f01feeed0e54952a7408c0a3e64ca18bfc Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 3 Dec 2019 14:09:01 -0500 Subject: [PATCH 167/297] Assert on more things --- .../apps/triggers_actions_ui/connectors.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/x-pack/test/functional/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional/apps/triggers_actions_ui/connectors.ts index 6c9ead231fbb58..28562521829a8c 100644 --- a/x-pack/test/functional/apps/triggers_actions_ui/connectors.ts +++ b/x-pack/test/functional/apps/triggers_actions_ui/connectors.ts @@ -49,6 +49,17 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const closeButton = await testSubjects.find('toastCloseButton'); await closeButton.click(); + + const searchBox = await find.byCssSelector('[data-test-subj="actionsList"] .euiFieldSearch'); + await searchBox.click(); + await searchBox.clearValue(); + await searchBox.type(connectorName); + await searchBox.pressKeys(ENTER_KEY); + + const textShownInConnectorsList = await testSubjects.getVisibleText( + 'connectorsTableCell-name' + ); + expect(textShownInConnectorsList).to.eql(connectorName); }); it('should edit a connector', async () => { @@ -102,6 +113,16 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const closeToastUpdatedButton = await testSubjects.find('toastCloseButton'); await closeToastUpdatedButton.click(); + + await searchBox.click(); + await searchBox.clearValue(); + await searchBox.type(updatedConnectorName); + await searchBox.pressKeys(ENTER_KEY); + + const textShownInConnectorsList = await testSubjects.getVisibleText( + 'connectorsTableCell-name' + ); + expect(textShownInConnectorsList).to.eql(updatedConnectorName); }); it('should delete a connector', async () => { From a48bb41d554026f65e97f3760d642a2a916641f3 Mon Sep 17 00:00:00 2001 From: defazio Date: Tue, 3 Dec 2019 16:44:34 -0500 Subject: [PATCH 168/297] Update alert/action menu items. Flyout width. Add index.scss file --- .../plugins/triggers_actions_ui/index.ts | 1 + .../sections/alert_add/alert_add.tsx | 58 ++++++++++--------- .../triggers_actions_ui/public/index.scss | 2 + 3 files changed, 35 insertions(+), 26 deletions(-) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/public/index.scss diff --git a/x-pack/legacy/plugins/triggers_actions_ui/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/index.ts index f2cf9b5cd7e99a..42aaf14a47f2e6 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/index.ts @@ -30,6 +30,7 @@ export function triggersActionsUI(kibana: any) { uiExports: { hacks: ['plugins/triggers_actions_ui/hacks/register'], managementSections: ['plugins/triggers_actions_ui'], + styleSheetPaths: resolve(__dirname, 'public/index.scss'), }, }); } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 8baa035a8dadc8..4da4e0c52a48f2 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -24,6 +24,8 @@ import { EuiFormRow, EuiComboBox, EuiCard, + EuiKeyPadMenu, + EuiKeyPadMenuItem, EuiTabs, EuiTab, EuiLink, @@ -293,30 +295,28 @@ export const AlertAdd = ({ refreshList }: Props) => { const alertTypeNodes = alertTypeRegistry.list().map(function(item, index) { return ( - - } - title={item.name} - description={''} - onClick={() => { - setAlertProperty('alertTypeId', item.id); - setAlertType(item.alertType); - }} - /> - + { + setAlertProperty('alertTypeId', item.id); + setAlertType(item.alertType); + }} + > + + ); }); const actionTypeNodes = actionTypeRegistry.list().map(function(item, index) { return ( - - } - title={actionTypesIndex ? actionTypesIndex[item.id].name : item.name} - description={''} - onClick={() => addActionType(item.actionType)} - /> - + addActionType(item.actionType)} + > + + ); }); @@ -532,10 +532,10 @@ export const AlertAdd = ({ refreshList }: Props) => { />
- - + + {alertTypeNodes} - + ); } @@ -574,7 +574,13 @@ export const AlertAdd = ({ refreshList }: Props) => { return ( - +

@@ -757,10 +763,10 @@ export const AlertAdd = ({ refreshList }: Props) => { />

- - + + {actionTypeNodes} - + ) : null} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/public/index.scss b/x-pack/legacy/plugins/triggers_actions_ui/public/index.scss new file mode 100644 index 00000000000000..d66cf4d1433dbe --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/public/index.scss @@ -0,0 +1,2 @@ +// Alerting Styles + From 3c9ddb8df64a00281816a590a767b2350d542b53 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 3 Dec 2019 22:30:53 -0800 Subject: [PATCH 169/297] Added action connector list unit tests --- .../connector_add_flyout.tsx | 2 +- .../connector_edit_flyout.tsx | 28 ++-- .../actions_connectors_list.test.tsx | 120 ++++++++++++++++++ .../components/actions_connectors_list.tsx | 1 + 4 files changed, 130 insertions(+), 21 deletions(-) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx index 1c56d976e9e955..af762b883a892b 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx @@ -56,7 +56,7 @@ export const ConnectorAddFlyout = () => { - {actionTypeModel ? ( + {actionTypeModel && actionTypeModel.iconClass ? ( diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx index 4109f124153a80..e58ba2f7bac360 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx @@ -16,7 +16,6 @@ import { import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; import { ActionConnectorForm } from './action_connector_form'; import { useAppDependencies } from '../../app_dependencies'; -import { SectionLoading } from '../../components/section_loading'; import { ActionConnectorTableItem } from '../../../types'; export interface ConnectorEditProps { @@ -55,25 +54,14 @@ export const ConnectorEditFlyout = ({ connector }: ConnectorEditProps) => { - {connector ? ( - - ) : ( - - - - )} + ); }; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx new file mode 100644 index 00000000000000..dcf6dc60ffe1b1 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx @@ -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 * as React from 'react'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { ActionsConnectorsList } from './actions_connectors_list'; +import { setAppDependencies } from '../../../app_dependencies'; +import { coreMock } from '../../../../../../../../../../src/core/public/mocks'; +import { ReactWrapper } from 'enzyme'; +import { act } from 'react-dom/test-utils'; +jest.mock('../../../context/actions_connectors_context'); +jest.mock('../../../lib/action_connector_api', () => ({ + loadAllActions: jest.fn(), + loadActionTypes: jest.fn(), +})); + +describe('actions_connectors_list', () => { + let wrapper: ReactWrapper; + + beforeEach(async () => { + const { loadAllActions, loadActionTypes } = jest.requireMock( + '../../../lib/action_connector_api' + ); + loadAllActions.mockResolvedValueOnce({ + page: 1, + perPage: 10000, + total: 2, + data: [ + { + id: '1', + actionTypeId: 'test', + description: 'My test', + referencedByCount: 1, + config: {}, + }, + { + id: '2', + actionTypeId: 'test2', + description: 'My test 2', + referencedByCount: 1, + config: {}, + }, + ], + }); + loadActionTypes.mockResolvedValueOnce([ + { + id: 'test', + name: 'Test', + }, + { + id: 'test2', + name: 'Test2', + }, + ]); + const deps = { + core: coreMock.createStart(), + plugins: { + capabilities: { + get() { + return { + actions: { + delete: true, + save: true, + show: true, + }, + }; + }, + }, + } as any, + actionTypeRegistry: { + get() { + return null; + }, + } as any, + alertTypeRegistry: {} as any, + }; + const AppDependenciesProvider = setAppDependencies(deps); + + await act(async () => { + wrapper = mountWithIntl( + + + + ); + }); + + await waitForRender(wrapper); + + expect(loadAllActions).toHaveBeenCalled(); + }); + + it('renders table of connectors', () => { + expect(wrapper.find('EuiInMemoryTable')).toHaveLength(1); + expect(wrapper.find('EuiTableRow')).toHaveLength(2); + }); + + it('select item for edit should render ConnectorEditFlyout', () => { + wrapper + .find('[data-test-subj="edit"]') + .first() + .simulate('click'); + expect(wrapper.find('ConnectorEditFlyout')).toHaveLength(1); + }); + + it('change capability', () => { + wrapper + .find('[data-test-subj="edit"]') + .first() + .simulate('click'); + expect(wrapper.find('ConnectorEditFlyout')).toHaveLength(1); + }); +}); + +async function waitForRender(wrapper: ReactWrapper) { + await Promise.resolve(); + await Promise.resolve(); + wrapper.update(); +} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index 3b68da010af94c..4078e3bb7dc581 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -200,6 +200,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { ), type: 'icon', icon: 'pencil', + 'data-test-subj': 'edit', onClick: (item: ActionConnectorTableItem) => editItem(item), }, { From 365367ec78bd7bc4d3175cd3418d203b3d4d3a1f Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 4 Dec 2019 11:14:47 -0500 Subject: [PATCH 170/297] Add bulk delete functional test --- .../components/actions_connectors_list.tsx | 2 +- .../apps/triggers_actions_ui/connectors.ts | 48 ++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index 3b68da010af94c..8d0b61276203cb 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -266,7 +266,6 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { { type: 'field_value_selection', field: 'actionTypeId', - 'data-test-subj': 'typeFilterButton', name: i18n.translate( 'xpack.triggersActionsUI.sections.actionsConnectorsList.filters.actionTypeIdName', { defaultMessage: 'Type' } @@ -283,6 +282,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { key="delete" iconType="trash" color="danger" + data-test-subj="bulkDelete" onClick={deleteSelectedItems} title={ canDelete diff --git a/x-pack/test/functional/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional/apps/triggers_actions_ui/connectors.ts index 28562521829a8c..6f09463d087e6d 100644 --- a/x-pack/test/functional/apps/triggers_actions_ui/connectors.ts +++ b/x-pack/test/functional/apps/triggers_actions_ui/connectors.ts @@ -162,7 +162,53 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await find.byCssSelector('[data-test-subj="actionsTable"]:not(.euiBasicTable-loading)'); - const rowsAfterDelete = await testSubjects.findAll('connectors-row'); + const rowsAfterDelete = await testSubjects.findAll('connectors-row', 0); + expect(rowsAfterDelete.length).to.eql(0); + }); + + it('should bulk delete connectors', async () => { + const connectorName = generateUniqueKey(); + + await pageObjects.triggersActionsUI.createActionConnector(); + + const serverLogCard = await testSubjects.find('.server-log-card'); + await serverLogCard.click(); + + const nameInput = await testSubjects.find('nameInput'); + await nameInput.click(); + await nameInput.clearValue(); + await nameInput.type(connectorName); + + const saveButton = await find.byCssSelector( + '[data-test-subj="saveActionButton"]:not(disabled)' + ); + await saveButton.click(); + + await testSubjects.exists('euiToastHeader'); + + const closeButton = await testSubjects.find('toastCloseButton'); + await closeButton.click(); + + const searchBox = await find.byCssSelector('[data-test-subj="actionsList"] .euiFieldSearch'); + await searchBox.click(); + await searchBox.clearValue(); + await searchBox.type(connectorName); + await searchBox.pressKeys(ENTER_KEY); + + const rowsBeforeDelete = await testSubjects.findAll('connectors-row'); + expect(rowsBeforeDelete.length).to.eql(1); + + const deleteCheckbox = await find.byCssSelector( + '.euiTableRowCellCheckbox .euiCheckbox__input' + ); + await deleteCheckbox.click(); + + const bulkDeleteBtn = await testSubjects.find('bulkDelete'); + await bulkDeleteBtn.click(); + + await find.byCssSelector('[data-test-subj="actionsTable"]:not(.euiBasicTable-loading)'); + + const rowsAfterDelete = await testSubjects.findAll('connectors-row', 0); expect(rowsAfterDelete.length).to.eql(0); }); }); From 27bd7f144a42b7ee4a6f20f2a71d9f1155df226b Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 4 Dec 2019 13:08:24 -0500 Subject: [PATCH 171/297] Move tests to SSL functional environment --- .../components/page_error/form_errors.tsx | 2 +- x-pack/scripts/functional_tests.js | 1 + x-pack/test/functional/config.js | 5 -- x-pack/test/functional/page_objects/index.ts | 2 - .../apps/triggers_actions_ui/connectors.ts | 5 ++ .../apps/triggers_actions_ui/home_page.ts | 0 .../apps/triggers_actions_ui/index.ts | 0 x-pack/test/functional_with_es_ssl/config.ts | 54 +++++++++++++++++++ .../ftr_provider_context.d.ts | 12 +++++ .../page_objects/index.ts | 13 +++++ .../page_objects/triggers_actions_ui_page.ts | 0 .../functional_with_es_ssl/services/index.ts | 11 ++++ 12 files changed, 97 insertions(+), 8 deletions(-) rename x-pack/test/{functional => functional_with_es_ssl}/apps/triggers_actions_ui/connectors.ts (96%) rename x-pack/test/{functional => functional_with_es_ssl}/apps/triggers_actions_ui/home_page.ts (100%) rename x-pack/test/{functional => functional_with_es_ssl}/apps/triggers_actions_ui/index.ts (100%) create mode 100644 x-pack/test/functional_with_es_ssl/config.ts create mode 100644 x-pack/test/functional_with_es_ssl/ftr_provider_context.d.ts create mode 100644 x-pack/test/functional_with_es_ssl/page_objects/index.ts rename x-pack/test/{functional => functional_with_es_ssl}/page_objects/triggers_actions_ui_page.ts (100%) create mode 100644 x-pack/test/functional_with_es_ssl/services/index.ts diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/form_errors.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/form_errors.tsx index da0b19f1f0bebf..68a8a5601c584c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/form_errors.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/form_errors.tsx @@ -21,7 +21,7 @@ export const ErrableFormRow = ({ }) => { return ( 0} + isInvalid={isShowingErrors && errors[errorKey] && errors[errorKey].length > 0} error={errors[errorKey]} {...rest} > diff --git a/x-pack/scripts/functional_tests.js b/x-pack/scripts/functional_tests.js index 2ac8fff6ef8ab7..55d4ffba8acfda 100644 --- a/x-pack/scripts/functional_tests.js +++ b/x-pack/scripts/functional_tests.js @@ -10,6 +10,7 @@ require('@kbn/test').runTestsCli([ require.resolve('../test/reporting/configs/chromium_functional.js'), require.resolve('../test/reporting/configs/generate_api'), require.resolve('../test/functional/config.js'), + require.resolve('../test/functional_with_es_ssl/config.ts'), require.resolve('../test/api_integration/config_security_basic.js'), require.resolve('../test/api_integration/config.js'), require.resolve('../test/alerting_api_integration/spaces_only/config.ts'), diff --git a/x-pack/test/functional/config.js b/x-pack/test/functional/config.js index 063ab65400d62d..e4daf9c65410fc 100644 --- a/x-pack/test/functional/config.js +++ b/x-pack/test/functional/config.js @@ -58,7 +58,6 @@ export default async function ({ readConfigFile }) { resolve(__dirname, './apps/transform'), // This license_management file must be last because it is destructive. resolve(__dirname, './apps/license_management'), - resolve(__dirname, './apps/triggers_actions_ui'), ], services, @@ -198,10 +197,6 @@ export default async function ({ readConfigFile }) { pathname: '/app/kibana/', hash: '/management/elasticsearch/transform' }, - triggersActions: { - pathname: '/app/kibana', - hash: '/management/kibana/triggersActions', - }, }, // choose where esArchiver should load archives from diff --git a/x-pack/test/functional/page_objects/index.ts b/x-pack/test/functional/page_objects/index.ts index 88e70001d93df6..82011c48d44603 100644 --- a/x-pack/test/functional/page_objects/index.ts +++ b/x-pack/test/functional/page_objects/index.ts @@ -46,7 +46,6 @@ import { RemoteClustersPageProvider } from './remote_clusters_page'; import { CopySavedObjectsToSpacePageProvider } from './copy_saved_objects_to_space_page'; import { LensPageProvider } from './lens_page'; import { InfraMetricExplorerProvider } from './infra_metric_explorer'; -import { TriggersActionsPageProvider } from './triggers_actions_ui_page'; // just like services, PageObjects are defined as a map of // names to Providers. Merge in Kibana's or pick specific ones @@ -79,5 +78,4 @@ export const pageObjects = { remoteClusters: RemoteClustersPageProvider, copySavedObjectsToSpace: CopySavedObjectsToSpacePageProvider, lens: LensPageProvider, - triggersActionsUI: TriggersActionsPageProvider, }; diff --git a/x-pack/test/functional/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts similarity index 96% rename from x-pack/test/functional/apps/triggers_actions_ui/connectors.ts rename to x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts index 6f09463d087e6d..f7a9044557a9a9 100644 --- a/x-pack/test/functional/apps/triggers_actions_ui/connectors.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts @@ -49,6 +49,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const closeButton = await testSubjects.find('toastCloseButton'); await closeButton.click(); + await testSubjects.waitForHidden('toastCloseButton'); const searchBox = await find.byCssSelector('[data-test-subj="actionsList"] .euiFieldSearch'); await searchBox.click(); @@ -83,6 +84,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const closeToastButton = await testSubjects.find('toastCloseButton'); await closeToastButton.click(); + await testSubjects.waitForHidden('toastCloseButton'); const searchBox = await find.byCssSelector('[data-test-subj="actionsList"] .euiFieldSearch'); await searchBox.click(); @@ -113,6 +115,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const closeToastUpdatedButton = await testSubjects.find('toastCloseButton'); await closeToastUpdatedButton.click(); + await testSubjects.waitForHidden('toastCloseButton'); await searchBox.click(); await searchBox.clearValue(); @@ -147,6 +150,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const closeButton = await testSubjects.find('toastCloseButton'); await closeButton.click(); + await testSubjects.waitForHidden('toastCloseButton'); const searchBox = await find.byCssSelector('[data-test-subj="actionsList"] .euiFieldSearch'); await searchBox.click(); @@ -188,6 +192,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const closeButton = await testSubjects.find('toastCloseButton'); await closeButton.click(); + await testSubjects.waitForHidden('toastCloseButton'); const searchBox = await find.byCssSelector('[data-test-subj="actionsList"] .euiFieldSearch'); await searchBox.click(); diff --git a/x-pack/test/functional/apps/triggers_actions_ui/home_page.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts similarity index 100% rename from x-pack/test/functional/apps/triggers_actions_ui/home_page.ts rename to x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts diff --git a/x-pack/test/functional/apps/triggers_actions_ui/index.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts similarity index 100% rename from x-pack/test/functional/apps/triggers_actions_ui/index.ts rename to x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts diff --git a/x-pack/test/functional_with_es_ssl/config.ts b/x-pack/test/functional_with_es_ssl/config.ts new file mode 100644 index 00000000000000..3c1a6a1cdedcb5 --- /dev/null +++ b/x-pack/test/functional_with_es_ssl/config.ts @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { resolve } from 'path'; +import { CA_CERT_PATH } from '@kbn/dev-utils'; +import { FtrConfigProviderContext } from '@kbn/test/types/ftr'; +import { services } from './services'; +import { pageObjects } from './page_objects'; + +// eslint-disable-next-line import/no-default-export +export default async function({ readConfigFile }: FtrConfigProviderContext) { + const xpackFunctionalConfig = await readConfigFile(require.resolve('../functional/config.js')); + + const servers = { + ...xpackFunctionalConfig.get('servers'), + elasticsearch: { + ...xpackFunctionalConfig.get('servers.elasticsearch'), + protocol: 'https', + }, + }; + + const returnedObject = { + ...xpackFunctionalConfig.getAll(), + servers, + services, + pageObjects, + // list paths to the files that contain your plugins tests + testFiles: [resolve(__dirname, './apps/triggers_actions_ui')], + apps: { + ...xpackFunctionalConfig.get('apps'), + triggersActions: { + pathname: '/app/kibana', + hash: '/management/kibana/triggersActions', + }, + }, + esTestCluster: { + ...xpackFunctionalConfig.get('esTestCluster'), + ssl: true, + }, + kbnTestServer: { + ...xpackFunctionalConfig.get('kbnTestServer'), + serverArgs: [ + ...xpackFunctionalConfig.get('kbnTestServer.serverArgs'), + `--elasticsearch.hosts=https://${servers.elasticsearch.hostname}:${servers.elasticsearch.port}`, + `--elasticsearch.ssl.certificateAuthorities=${CA_CERT_PATH}`, + ], + }, + }; + + return returnedObject; +} diff --git a/x-pack/test/functional_with_es_ssl/ftr_provider_context.d.ts b/x-pack/test/functional_with_es_ssl/ftr_provider_context.d.ts new file mode 100644 index 00000000000000..bb257cdcbfe1b5 --- /dev/null +++ b/x-pack/test/functional_with_es_ssl/ftr_provider_context.d.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 { GenericFtrProviderContext } from '@kbn/test/types/ftr'; + +import { pageObjects } from './page_objects'; +import { services } from './services'; + +export type FtrProviderContext = GenericFtrProviderContext; diff --git a/x-pack/test/functional_with_es_ssl/page_objects/index.ts b/x-pack/test/functional_with_es_ssl/page_objects/index.ts new file mode 100644 index 00000000000000..a068ba7dfe81d3 --- /dev/null +++ b/x-pack/test/functional_with_es_ssl/page_objects/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under 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 { pageObjects as xpackFunctionalPageObjects } from '../../functional/page_objects'; +import { TriggersActionsPageProvider } from './triggers_actions_ui_page'; + +export const pageObjects = { + ...xpackFunctionalPageObjects, + triggersActionsUI: TriggersActionsPageProvider, +}; diff --git a/x-pack/test/functional/page_objects/triggers_actions_ui_page.ts b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts similarity index 100% rename from x-pack/test/functional/page_objects/triggers_actions_ui_page.ts rename to x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts diff --git a/x-pack/test/functional_with_es_ssl/services/index.ts b/x-pack/test/functional_with_es_ssl/services/index.ts new file mode 100644 index 00000000000000..6e96921c25a316 --- /dev/null +++ b/x-pack/test/functional_with_es_ssl/services/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { services as xpackFunctionalServices } from '../../functional/services'; + +export const services = { + ...xpackFunctionalServices, +}; From e3cf18b772df3a697cca7304f52cc4f51350a1cd Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 4 Dec 2019 13:16:38 -0500 Subject: [PATCH 172/297] Fix tests --- .../components/actions_connectors_list.tsx | 1 - .../apps/triggers_actions_ui/connectors.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index f620279b7c6493..4ab804a7b5209d 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -184,7 +184,6 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { actions: [ { enabled: () => canSave, - 'data-test-subj': 'editConnector', name: i18n.translate( 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.editActionName', { defaultMessage: 'Edit' } diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts index f7a9044557a9a9..57c27d9338a23d 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts @@ -95,7 +95,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const rowsBeforeDelete = await testSubjects.findAll('connectors-row'); expect(rowsBeforeDelete.length).to.eql(1); - const deleteConnectorBtn = await testSubjects.find('editConnector'); + const deleteConnectorBtn = await testSubjects.find('edit'); await deleteConnectorBtn.click(); const nameInputToUpdate = await testSubjects.find('nameInput'); From cbafbee42c428a195bae3dd431932b32129efcf6 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 4 Dec 2019 19:35:50 -0800 Subject: [PATCH 173/297] Added unit tests for actionTypeRegistry and alertTypeRegistry --- .../application/action_type_registry.mock.ts | 21 ++++ .../application/action_type_registry.test.ts | 106 ++++++++++++++++++ .../application/alert_type_registry.mock.ts | 21 ++++ .../application/alert_type_registry.test.ts | 102 +++++++++++++++++ .../np_ready/public/types.ts | 4 + 5 files changed, 254 insertions(+) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.mock.ts create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.test.ts create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.mock.ts create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.test.ts diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.mock.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.mock.ts new file mode 100644 index 00000000000000..11ace90e867c38 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.mock.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 { ActionTypeRegistryContract } from '../types'; + +const createActionTypeRegistryMock = () => { + const mocked: jest.Mocked = { + has: jest.fn(), + register: jest.fn(), + get: jest.fn(), + list: jest.fn(), + }; + return mocked; +}; + +export const actionTypeRegistryMock = { + create: createActionTypeRegistryMock, +}; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.test.ts new file mode 100644 index 00000000000000..c8b74fb6b7de45 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.test.ts @@ -0,0 +1,106 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ActionTypeRegistry } from './action_type_registry'; +import { ValidationResult } from '../types'; + +const getTestActionType = (id?: string, iconClass?: string, selectedMessage?: string) => { + return { + id: id || 'my-action-type', + iconClass: iconClass || 'test', + selectMessage: selectedMessage || 'test', + validateConnector: (): ValidationResult => { + return { errors: {} }; + }, + validateParams: (): ValidationResult => { + const validationResult = { errors: {} }; + return validationResult; + }, + actionConnectorFields: null, + actionParamsFields: null, + }; +}; + +beforeEach(() => jest.resetAllMocks()); + +describe('register()', () => { + test('able to register action types', () => { + const actionTypeRegistry = new ActionTypeRegistry(); + actionTypeRegistry.register(getTestActionType()); + expect(actionTypeRegistry.has('my-action-type')).toEqual(true); + }); + + test('throws error if action type already registered', () => { + const actionTypeRegistry = new ActionTypeRegistry(); + actionTypeRegistry.register(getTestActionType('my-test-action-type-1')); + expect(() => + actionTypeRegistry.register(getTestActionType('my-test-action-type-1')) + ).toThrowErrorMatchingInlineSnapshot( + `"Action type \\"my-test-action-type-1\\" is already registered."` + ); + }); +}); + +describe('get()', () => { + test('returns action type', () => { + const actionTypeRegistry = new ActionTypeRegistry(); + actionTypeRegistry.register(getTestActionType('my-action-type-snapshot')); + const actionType = actionTypeRegistry.get('my-action-type-snapshot'); + expect(actionType).toMatchInlineSnapshot(` + Object { + "actionConnectorFields": null, + "actionParamsFields": null, + "iconClass": "test", + "id": "my-action-type-snapshot", + "selectMessage": "test", + "validateConnector": [Function], + "validateParams": [Function], + } + `); + }); + + test(`return null when action type doesn't exist`, () => { + const actionTypeRegistry = new ActionTypeRegistry(); + expect(actionTypeRegistry.get('not-exist-action-type')).toBeNull(); + }); +}); + +describe('list()', () => { + test('returns list of action types', () => { + const actionTypeRegistry = new ActionTypeRegistry(); + actionTypeRegistry.register(getTestActionType()); + const actionTypes = actionTypeRegistry.list(); + expect(JSON.stringify(actionTypes)).toEqual( + JSON.stringify([ + { + id: 'my-action-type', + name: 'my-action-type', + iconClass: 'test', + actionType: { + id: 'my-action-type', + iconClass: 'test', + selectMessage: 'test', + actionConnectorFields: null, + actionParamsFields: null, + }, + }, + ]) + ); + }); +}); + +describe('has()', () => { + test('returns false for unregistered action types', () => { + const actionTypeRegistry = new ActionTypeRegistry(); + expect(actionTypeRegistry.has('my-action-type')).toEqual(false); + }); + + test('returns true after registering an action type', () => { + const actionTypeRegistry = new ActionTypeRegistry(); + actionTypeRegistry.register(getTestActionType()); + expect(actionTypeRegistry.has('my-action-type')); + }); +}); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.mock.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.mock.ts new file mode 100644 index 00000000000000..89eca7563a4e1c --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.mock.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 { AlertTypeRegistryContract } from '../types'; + +const createAlertTypeRegistryMock = () => { + const mocked: jest.Mocked = { + has: jest.fn(), + register: jest.fn(), + get: jest.fn(), + list: jest.fn(), + }; + return mocked; +}; + +export const alertTypeRegistryMock = { + create: createAlertTypeRegistryMock, +}; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.test.ts new file mode 100644 index 00000000000000..e5613b88516ba1 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.test.ts @@ -0,0 +1,102 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { AlertTypeRegistry } from './alert_type_registry'; +import { ValidationResult } from '../types'; + +export const ExpressionComponent: React.FunctionComponent = () => { + return null; +}; + +const getTestAlertType = (id?: string, name?: string, iconClass?: string) => { + return { + id: id || 'test-alet-type', + name: name || 'Test alert type', + iconClass: iconClass || 'icon', + validate: (): ValidationResult => { + return { errors: {} }; + }, + alertParamsExpression: ExpressionComponent, + }; +}; + +beforeEach(() => jest.resetAllMocks()); + +describe('register()', () => { + test('able to register alert types', () => { + const alertTypeRegistry = new AlertTypeRegistry(); + alertTypeRegistry.register(getTestAlertType()); + expect(alertTypeRegistry.has('test-alet-type')).toEqual(true); + }); + + test('throws error if alert type already registered', () => { + const alertTypeRegistry = new AlertTypeRegistry(); + alertTypeRegistry.register(getTestAlertType('my-test-alert-type-1')); + expect(() => + alertTypeRegistry.register(getTestAlertType('my-test-alert-type-1')) + ).toThrowErrorMatchingInlineSnapshot( + `"Alert type \\"my-test-alert-type-1\\" is already registered."` + ); + }); +}); + +describe('get()', () => { + test('returns alert type', () => { + const alertTypeRegistry = new AlertTypeRegistry(); + alertTypeRegistry.register(getTestAlertType('my-alert-type-snapshot')); + const alertType = alertTypeRegistry.get('my-alert-type-snapshot'); + expect(alertType).toMatchInlineSnapshot(` + Object { + "alertParamsExpression": [Function], + "iconClass": "icon", + "id": "my-alert-type-snapshot", + "name": "Test alert type", + "validate": [Function], + } + `); + }); + + test(`return null when alert type doesn't exist`, () => { + const alertTypeRegistry = new AlertTypeRegistry(); + expect(alertTypeRegistry.get('not-exist-alert-type')).toBeNull(); + }); +}); + +describe('list()', () => { + test('returns list of alert types', () => { + const alertTypeRegistry = new AlertTypeRegistry(); + alertTypeRegistry.register(getTestAlertType()); + const alertTypes = alertTypeRegistry.list(); + expect(JSON.stringify(alertTypes)).toEqual( + JSON.stringify([ + { + id: 'test-alet-type', + name: 'Test alert type', + iconClass: 'icon', + alertType: { + id: 'test-alet-type', + name: 'Test alert type', + iconClass: 'icon', + alertParamsExpression: ExpressionComponent, + }, + }, + ]) + ); + }); +}); + +describe('has()', () => { + test('returns false for unregistered alert types', () => { + const alertTypeRegistry = new AlertTypeRegistry(); + expect(alertTypeRegistry.has('my-alert-type')).toEqual(false); + }); + + test('returns true after registering an alert type', () => { + const alertTypeRegistry = new AlertTypeRegistry(); + alertTypeRegistry.register(getTestAlertType()); + expect(alertTypeRegistry.has('test-alet-type')); + }); +}); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts index c60854310bab15..ed3be1376ceb6e 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts @@ -3,9 +3,13 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { ActionTypeRegistry } from './application/action_type_registry'; +import { AlertTypeRegistry } from './application/alert_type_registry'; export type ActionTypeIndex = Record; export type AlertTypeIndex = Record; +export type ActionTypeRegistryContract = PublicMethodsOf; +export type AlertTypeRegistryContract = PublicMethodsOf; export interface ActionConnectorFieldsProps { action: ActionConnector; From 5751d383cb523db7fb364e2b247d49d562b68bad Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 4 Dec 2019 20:51:25 -0800 Subject: [PATCH 174/297] Fixed update connector with only properties --- .../np_ready/public/application/lib/action_connector_api.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts index ab8ec7777df225..72c66da3e6149e 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts @@ -56,7 +56,11 @@ export async function updateActionConnector({ id: string; }): Promise { return await http.put(`${BASE_ACTION_API_PATH}/${id}`, { - body: JSON.stringify({ ...connector, id: undefined, actionTypeId: undefined }), + body: JSON.stringify({ + name: connector.name, + config: connector.config, + secrets: connector.secrets, + }), }); } From baed2f6df61cd52cc364a28de10f67fa27d683e6 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Thu, 5 Dec 2019 08:41:12 -0500 Subject: [PATCH 175/297] Added some functional tests for alerts with TODOs --- .../alerts_list/components/alerts_list.tsx | 4 +- .../components/bulk_action_popover.tsx | 6 + .../components/collapsed_item_actions.tsx | 10 +- x-pack/test/functional/services/index.ts | 1 + .../apps/triggers_actions_ui/alerts.ts | 247 ++++++++++++++++++ .../apps/triggers_actions_ui/index.ts | 1 + 6 files changed, 266 insertions(+), 3 deletions(-) create mode 100644 x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 82a5fa5f766f6d..e1ca35b5a842a6 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -210,12 +210,12 @@ export const AlertsList: React.FunctionComponent = () => { itemId="id" columns={alertsTableColumns} rowProps={() => ({ - 'data-test-subj': 'row', + 'data-test-subj': 'alert-row', })} cellProps={() => ({ 'data-test-subj': 'cell', })} - data-test-subj="alertsTable" + data-test-subj="alertsList" pagination={{ pageIndex: page.index, pageSize: page.size, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx index b5984f8f37c534..806d2fda324fae 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx @@ -156,6 +156,7 @@ export const BulkActionPopover: React.FunctionComponent = ({ setIsPopoverOpen(false)} + data-test-subj="bulkAction" button={ = ({ onClick={onmMuteAllClick} isLoading={isMutingAlerts} isDisabled={isPerformingAction} + data-test-subj="muteAll" > = ({ onClick={onUnmuteAllClick} isLoading={isUnmutingAlerts} isDisabled={isPerformingAction} + data-test-subj="unmuteAll" > = ({ onClick={onEnableAllClick} isLoading={isEnablingAlerts} isDisabled={isPerformingAction} + data-test-subj="enableAll" > = ({ onClick={onDisableAllClick} isLoading={isDisablingAlerts} isDisabled={isPerformingAction} + data-test-subj="disableAll" > = ({ onClick={deleteSelectedItems} isLoading={isDeletingAlerts} isDisabled={isPerformingAction} + data-test-subj="deleteAll" > = ({ ); return ( - setIsPopoverOpen(false)}> + setIsPopoverOpen(false)} + data-test-subj="collapsedItemActions" + > { if (isEnabled) { setIsEnabled(false); @@ -89,6 +95,7 @@ export const CollapsedItemActions: React.FunctionComponent = ({ name="mute" checked={isMuted} disabled={!canSave || !isEnabled} + data-test-subj="muteSwitch" onChange={async () => { if (isMuted) { setIsMuted(false); @@ -113,6 +120,7 @@ export const CollapsedItemActions: React.FunctionComponent = ({ isDisabled={!canDelete} iconType="trash" color="text" + data-test-subj="deleteAlert" onClick={async () => { await deleteAlerts({ http, ids: [item.id] }); onAlertChanged(); diff --git a/x-pack/test/functional/services/index.ts b/x-pack/test/functional/services/index.ts index a8e5749004afe2..c225467e910a28 100644 --- a/x-pack/test/functional/services/index.ts +++ b/x-pack/test/functional/services/index.ts @@ -56,6 +56,7 @@ import { SecurityServiceProvider, SpacesServiceProvider } from '../../common/ser // only the built-in services will be available export const services = { ...kibanaFunctionalServices, + supertest: kibanaApiIntegrationServices.supertest, esSupertest: kibanaApiIntegrationServices.esSupertest, monitoringNoData: MonitoringNoDataProvider, monitoringClusterList: MonitoringClusterListProvider, diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts new file mode 100644 index 00000000000000..e638a769d4e4a0 --- /dev/null +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts @@ -0,0 +1,247 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import uuid from 'uuid'; +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +const ENTER_KEY = '\uE007'; + +function generateUniqueKey() { + return uuid.v4().replace(/-/g, ''); +} + +export default ({ getPageObjects, getService }: FtrProviderContext) => { + const testSubjects = getService('testSubjects'); + const pageObjects = getPageObjects(['common', 'triggersActionsUI', 'header']); + const find = getService('find'); + const supertest = getService('supertest'); + + async function createAlert() { + const { body: createdAlert } = await supertest + .post(`/api/alert`) + .set('kbn-xsrf', 'foo') + .send({ + enabled: true, + name: generateUniqueKey(), + tags: ['foo'], + alertTypeId: 'test', + interval: '1m', + throttle: '1m', + actions: [], + params: {}, + }) + .expect(200); + return createdAlert; + } + + describe('alerts', function() { + before(async () => { + await pageObjects.common.navigateToApp('triggersActions'); + const alertsTab = await testSubjects.find('alertsTab'); + await alertsTab.click(); + }); + + it('should search for alert', async () => { + const createdAlert = await createAlert(); + const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); + await searchBox.click(); + await searchBox.clearValue(); + await searchBox.type(createdAlert.name); + await searchBox.pressKeys(ENTER_KEY); + + const rows = await testSubjects.findAll('alert-row'); + expect(rows.length).to.eql(1); + }); + + it('should disable single alert', async () => { + const createdAlert = await createAlert(); + const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); + await searchBox.click(); + await searchBox.clearValue(); + await searchBox.type(createdAlert.name); + await searchBox.pressKeys(ENTER_KEY); + + const collapsedItemActions = await testSubjects.find('collapsedItemActions'); + await collapsedItemActions.click(); + + const enableSwitch = await testSubjects.find('enableSwitch'); + await enableSwitch.click(); + + const searchBoxAfterUpdate = await find.byCssSelector( + '[data-test-subj="alertsList"] .euiFieldSearch' + ); + await searchBoxAfterUpdate.click(); + + // TODO: More assertions + }); + + it('should re-enable single alert', async () => { + // TODO + }); + + it('should mute single alert', async () => { + const createdAlert = await createAlert(); + const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); + await searchBox.click(); + await searchBox.clearValue(); + await searchBox.type(createdAlert.name); + await searchBox.pressKeys(ENTER_KEY); + + const collapsedItemActions = await testSubjects.find('collapsedItemActions'); + await collapsedItemActions.click(); + + const muteSwitch = await testSubjects.find('muteSwitch'); + await muteSwitch.click(); + + const searchBoxAfterUpdate = await find.byCssSelector( + '[data-test-subj="alertsList"] .euiFieldSearch' + ); + await searchBoxAfterUpdate.click(); + + // TODO: More assertions + }); + + it('should unmute single alert', async () => { + // TODO + }); + + it('should delete single alert', async () => { + const createdAlert = await createAlert(); + const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); + await searchBox.click(); + await searchBox.clearValue(); + await searchBox.type(createdAlert.name); + await searchBox.pressKeys(ENTER_KEY); + + const collapsedItemActions = await testSubjects.find('collapsedItemActions'); + await collapsedItemActions.click(); + + const deleteBtn = await testSubjects.find('deleteAlert'); + await deleteBtn.click(); + + // TODO: More assertions + }); + + it('should mute all selection', async () => { + const createdAlert = await createAlert(); + const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); + await searchBox.click(); + await searchBox.clearValue(); + await searchBox.type(createdAlert.name); + await searchBox.pressKeys(ENTER_KEY); + + const checkbox = await testSubjects.find(`checkboxSelectRow-${createdAlert.id}`); + await checkbox.click(); + + const bulkActionBtn = await testSubjects.find('bulkAction'); + await bulkActionBtn.click(); + + const muteAllBtn = await testSubjects.find('muteAll'); + await muteAllBtn.click(); + + // Unmute all button shows after clicking mute all + await testSubjects.exists('unmuteAll'); + + // TODO: More assertions + }); + + it('should unmute all selection', async () => { + const createdAlert = await createAlert(); + const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); + await searchBox.click(); + await searchBox.clearValue(); + await searchBox.type(createdAlert.name); + await searchBox.pressKeys(ENTER_KEY); + + const checkbox = await testSubjects.find(`checkboxSelectRow-${createdAlert.id}`); + await checkbox.click(); + + const bulkActionBtn = await testSubjects.find('bulkAction'); + await bulkActionBtn.click(); + + const muteAllBtn = await testSubjects.find('muteAll'); + await muteAllBtn.click(); + + const unmuteAllBtn = await testSubjects.find('unmuteAll'); + await unmuteAllBtn.click(); + + // Mute all button shows after clicking unmute all + await testSubjects.exists('muteAll'); + + // TODO: More assertions + }); + + it('should disable all selection', async () => { + const createdAlert = await createAlert(); + const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); + await searchBox.click(); + await searchBox.clearValue(); + await searchBox.type(createdAlert.name); + await searchBox.pressKeys(ENTER_KEY); + + const checkbox = await testSubjects.find(`checkboxSelectRow-${createdAlert.id}`); + await checkbox.click(); + + const bulkActionBtn = await testSubjects.find('bulkAction'); + await bulkActionBtn.click(); + + const disableAllBtn = await testSubjects.find('disableAll'); + await disableAllBtn.click(); + + // Enable all button shows after clicking disable all + await testSubjects.exists('enableAll'); + + // TODO: More assertions + }); + + it('should enable all selection', async () => { + const createdAlert = await createAlert(); + const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); + await searchBox.click(); + await searchBox.clearValue(); + await searchBox.type(createdAlert.name); + await searchBox.pressKeys(ENTER_KEY); + + const checkbox = await testSubjects.find(`checkboxSelectRow-${createdAlert.id}`); + await checkbox.click(); + + const bulkActionBtn = await testSubjects.find('bulkAction'); + await bulkActionBtn.click(); + + const disableAllBtn = await testSubjects.find('disableAll'); + await disableAllBtn.click(); + + const enableAllBtn = await testSubjects.find('enableAll'); + await enableAllBtn.click(); + + // Disable all button shows after clicking enable all + await testSubjects.exists('disableAll'); + + // TODO: More assertions + }); + + it('should delete all selection', async () => { + const createdAlert = await createAlert(); + const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); + await searchBox.click(); + await searchBox.clearValue(); + await searchBox.type(createdAlert.name); + await searchBox.pressKeys(ENTER_KEY); + + const checkbox = await testSubjects.find(`checkboxSelectRow-${createdAlert.id}`); + await checkbox.click(); + + const bulkActionBtn = await testSubjects.find('bulkAction'); + await bulkActionBtn.click(); + + const deleteAllBtn = await testSubjects.find('deleteAll'); + await deleteAllBtn.click(); + + // TODO: More assertions + }); + }); +}; diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts index a3cbb27f50d353..e2e0c25d112958 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts @@ -11,5 +11,6 @@ export default ({ loadTestFile, getService }: FtrProviderContext) => { this.tags('ciGroup3'); // not sure about which CI group this tests should belong to loadTestFile(require.resolve('./home_page')); loadTestFile(require.resolve('./connectors')); + loadTestFile(require.resolve('./alerts')); }); }; From f3531f4cd49a685e249376fe8250b36ec7ef7c82 Mon Sep 17 00:00:00 2001 From: Dave Snider Date: Thu, 5 Dec 2019 14:09:51 -0800 Subject: [PATCH 176/297] connectors list page cleanup --- .../np_ready/public/application/home.tsx | 4 +- .../public/application/lib/breadcrumb.ts | 2 +- .../components/_index.scss | 1 + .../components/actions_connectors_list.scss | 3 + .../components/actions_connectors_list.tsx | 185 +++++++++++------- .../np_ready/public/plugin.ts | 2 +- .../public/hacks/register.ts | 2 +- .../triggers_actions_ui/public/index.scss | 5 +- .../apps/triggers_actions_ui/home_page.ts | 2 +- 9 files changed, 132 insertions(+), 74 deletions(-) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/_index.scss create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.scss diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx index aaefb2797a25f6..799820edae2306 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx @@ -86,11 +86,11 @@ export const TriggersActionsUIHome: React.FunctionComponent - +

diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.ts index 564c602d9ae68d..de658d5aabc1e2 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.ts @@ -29,7 +29,7 @@ class BreadcrumbService { ...this.breadcrumbs.management, { text: i18n.translate('xpack.triggersActionsUI.home.breadcrumbTitle', { - defaultMessage: 'Triggers and Actions', + defaultMessage: 'Alerts and actions', }), href: `#${routeToHome}`, }, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/_index.scss b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/_index.scss new file mode 100644 index 00000000000000..98c6c2a307a748 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/_index.scss @@ -0,0 +1 @@ +@import 'actions_connectors_list'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.scss b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.scss new file mode 100644 index 00000000000000..7a824aaeaa8d8b --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.scss @@ -0,0 +1,3 @@ +.actConnectorsList__logo + .actConnectorsList__logo { + margin-left: $euiSize; +} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index 4ab804a7b5209d..406eeba4a8dcb6 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -5,7 +5,16 @@ */ import React, { Fragment, useState, useEffect } from 'react'; -import { EuiBadge, EuiInMemoryTable, EuiSpacer, EuiButton } from '@elastic/eui'; +import { + EuiBadge, + EuiInMemoryTable, + EuiSpacer, + EuiButton, + EuiIcon, + EuiEmptyPrompt, + EuiFlexGroup, + EuiFlexItem, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { ActionsConnectorsContext } from '../../../context/actions_connectors_context'; @@ -240,69 +249,111 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { reloadConnectors: loadActions, }} > - ({ - 'data-test-subj': 'connectors-row', - })} - cellProps={() => ({ - 'data-test-subj': 'cell', - })} - data-test-subj="actionsTable" - pagination={true} - selection={ - canDelete && { - onSelectionChange(updatedSelectedItemsList: ActionConnectorTableItem[]) { - setSelectedItems(updatedSelectedItemsList); - }, + {data.length > 0 ? ( + ({ + 'data-test-subj': 'connectors-row', + })} + cellProps={() => ({ + 'data-test-subj': 'cell', + })} + data-test-subj="actionsTable" + pagination={true} + selection={ + canDelete && { + onSelectionChange(updatedSelectedItemsList: ActionConnectorTableItem[]) { + setSelectedItems(updatedSelectedItemsList); + }, + } } - } - search={{ - filters: [ - { - type: 'field_value_selection', - field: 'actionTypeId', - name: i18n.translate( - 'xpack.triggersActionsUI.sections.actionsConnectorsList.filters.actionTypeIdName', - { defaultMessage: 'Type' } - ), - multiSelect: 'or', - options: actionTypesList, - }, - ], - toolsLeft: - selectedItems.length === 0 || !canDelete - ? [] - : [ - - - , - ], - toolsRight: [ + search={{ + filters: [ + { + type: 'field_value_selection', + field: 'actionTypeId', + name: i18n.translate( + 'xpack.triggersActionsUI.sections.actionsConnectorsList.filters.actionTypeIdName', + { defaultMessage: 'Type' } + ), + multiSelect: 'or', + options: actionTypesList, + }, + ], + toolsLeft: + selectedItems.length === 0 || !canDelete + ? [] + : [ + + + , + ], + toolsRight: [ + setAddFlyoutVisibility(true)} + > + + , + ], + }} + /> + ) : ( + + + + } + body={ + +

+ +

+ + + +
+ } + actions={ { id="xpack.triggersActionsUI.sections.actionsConnectorsList.addActionButtonLabel" defaultMessage="Create" /> - , - ], - }} - /> +
+ } + /> + )} {editedConnectorItem ? : null} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts index 74e0c3c9a27c19..1f170156b29250 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts @@ -69,7 +69,7 @@ export class Plugin implements CorePlugin { const kbnSection = getSection('kibana'); kbnSection.register('triggersActions', { display: i18n.translate('xpack.triggersActionsUI.managementSection.displayName', { - defaultMessage: 'Triggers and Actions', + defaultMessage: 'Alerts and actions', }), order: 7, url: `#${BASE_PATH}`, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/public/hacks/register.ts b/x-pack/legacy/plugins/triggers_actions_ui/public/hacks/register.ts index 229064c64930e1..897c956ec12327 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/public/hacks/register.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/public/hacks/register.ts @@ -13,7 +13,7 @@ import { FeatureCatalogueRegistryProvider.register(() => { return { id: 'triggersActions', - title: 'Triggers and Actions', // This is a product name so we don't translate it. + title: 'Alerts and actions', // This is a product name so we don't translate it. description: i18n.translate('xpack.triggersActionsUI.triggersActionsDescription', { defaultMessage: 'Data by creating, managing, and monitoring triggers and actions.', }), diff --git a/x-pack/legacy/plugins/triggers_actions_ui/public/index.scss b/x-pack/legacy/plugins/triggers_actions_ui/public/index.scss index d66cf4d1433dbe..6faad81630b2be 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/public/index.scss +++ b/x-pack/legacy/plugins/triggers_actions_ui/public/index.scss @@ -1,2 +1,5 @@ -// Alerting Styles +// Imported EUI +@import 'src/legacy/ui/public/styles/_styling_constants'; +// Styling within the app +@import '../np_ready/public/application/sections/actions_connectors_list/components/index'; diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts index 8d6f41a4a76c77..4d2fe6ae82d37f 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts @@ -22,7 +22,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await log.debug('Checking for section heading to say Triggers and Actions.'); const headingText = await pageObjects.triggersActionsUI.sectionHeadingText(); - expect(headingText).to.be('Triggers and Actions'); + expect(headingText).to.be('Alerts and actions'); const actionsConnectorsList = await testSubjects.exists('actionsList'); expect(actionsConnectorsList).to.be(true); From 16fbe367f8e76c7a54cfbc13d8501c7e5014ed04 Mon Sep 17 00:00:00 2001 From: Dave Snider Date: Thu, 5 Dec 2019 14:30:26 -0800 Subject: [PATCH 177/297] empty state cleanup --- .../components/actions_connectors_list.tsx | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index 406eeba4a8dcb6..25381b509916dc 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -12,8 +12,7 @@ import { EuiButton, EuiIcon, EuiEmptyPrompt, - EuiFlexGroup, - EuiFlexItem, + EuiTitle, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -331,28 +330,30 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { /> ) : ( - - - } - body={ -

- -

+ + +

+ +

+
} + body={ +

+ +

+ } actions={ Date: Thu, 5 Dec 2019 21:04:14 -0800 Subject: [PATCH 178/297] Added connector edit flyout unit test --- .../application/action_type_registry.mock.ts | 2 +- .../connector_add_flyout.test.tsx | 94 +++++++++++++++++++ .../alert_types/threshold/visualization.tsx | 22 +---- 3 files changed, 97 insertions(+), 21 deletions(-) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.test.tsx diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.mock.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.mock.ts index 11ace90e867c38..8ebfd7f933cd34 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.mock.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.mock.ts @@ -8,7 +8,7 @@ import { ActionTypeRegistryContract } from '../types'; const createActionTypeRegistryMock = () => { const mocked: jest.Mocked = { - has: jest.fn(), + has: jest.fn(x => true), register: jest.fn(), get: jest.fn(), list: jest.fn(), diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.test.tsx new file mode 100644 index 00000000000000..1f96250ee28f85 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.test.tsx @@ -0,0 +1,94 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import * as React from 'react'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { setAppDependencies } from '../../app_dependencies'; +import { coreMock } from '../../../../../../../../../src/core/public/mocks'; +import { ReactWrapper } from 'enzyme'; +import { act } from 'react-dom/test-utils'; +import { ConnectorAddFlyout } from './connector_add_flyout'; +import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; +import { actionTypeRegistryMock } from '../../action_type_registry.mock'; +import { ValidationResult } from '../../../types'; +jest.mock('../../context/actions_connectors_context'); +const actionTypeRegistry = actionTypeRegistryMock.create(); + +describe('connector_add_flyout', () => { + let wrapper: ReactWrapper; + + beforeEach(async () => { + const deps = { + core: coreMock.createStart(), + plugins: { + capabilities: { + get() { + return { + actions: { + delete: true, + save: true, + show: true, + }, + }; + }, + }, + } as any, + actionTypeRegistry: actionTypeRegistry as any, + alertTypeRegistry: {} as any, + }; + const AppDependenciesProvider = setAppDependencies(deps); + + await act(async () => { + wrapper = mountWithIntl( + + {}, + editFlyoutVisible: false, + setEditFlyoutVisibility: state => {}, + actionTypesIndex: { 'my-action-type': { id: 'my-action-type', name: 'test' } }, + reloadConnectors: () => { + return new Promise(() => {}); + }, + }} + > + + + + ); + }); + + await waitForRender(wrapper); + }); + + it('renders action type menu on flyout open', () => { + const actionType = { + id: 'my-action-type', + iconClass: 'test', + selectMessage: 'test', + validateConnector: (): ValidationResult => { + return { errors: {} }; + }, + validateParams: (): ValidationResult => { + const validationResult = { errors: {} }; + return validationResult; + }, + actionConnectorFields: null, + actionParamsFields: null, + }; + actionTypeRegistry.get.mockReturnValueOnce(actionType); + actionTypeRegistry.has.mockReturnValue(true); + + expect(wrapper.find('ActionTypeMenu')).toHaveLength(1); + expect(wrapper.find('[data-test-subj="my-action-type-card"]').exists()).toBeTruthy(); + }); +}); + +async function waitForRender(wrapper: ReactWrapper) { + await Promise.resolve(); + await Promise.resolve(); + wrapper.update(); +} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx index 2af83455e16169..8f8215fd401183 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx @@ -5,7 +5,7 @@ */ import React, { Fragment, useEffect, useState } from 'react'; -import { UiSettingsClient } from 'kibana/public'; +import { IUiSettingsClient } from 'kibana/public'; import { AnnotationDomainTypes, Axis, @@ -44,25 +44,7 @@ const customTheme = () => { }; }; -const getTimezone = ( - uiSettings: Pick< - UiSettingsClient, - | 'getAll' - | 'get' - | 'get$' - | 'set' - | 'remove' - | 'isDeclared' - | 'isDefault' - | 'isCustom' - | 'isOverridden' - | 'overrideLocalDefault' - | 'getUpdate$' - | 'getSaved$' - | 'getUpdateErrors$' - | 'stop' - > -) => { +const getTimezone = (uiSettings: IUiSettingsClient) => { const config = uiSettings; const DATE_FORMAT_CONFIG_KEY = 'dateFormat:tz'; const isCustomTimezone = !config.isDefault(DATE_FORMAT_CONFIG_KEY); From 411fee5a2ffa212ab1022f3ba47339918eaedbfe Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 6 Dec 2019 11:31:05 -0500 Subject: [PATCH 179/297] Fix functional tests --- .../apps/triggers_actions_ui/alerts.ts | 8 ++++---- .../apps/triggers_actions_ui/connectors.ts | 4 ++-- .../apps/triggers_actions_ui/home_page.ts | 9 ++------- .../apps/triggers_actions_ui/index.ts | 2 +- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts index e638a769d4e4a0..aa24cb8ad3dec1 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts @@ -144,7 +144,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await muteAllBtn.click(); // Unmute all button shows after clicking mute all - await testSubjects.exists('unmuteAll'); + await testSubjects.existOrFail('unmuteAll'); // TODO: More assertions }); @@ -170,7 +170,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await unmuteAllBtn.click(); // Mute all button shows after clicking unmute all - await testSubjects.exists('muteAll'); + await testSubjects.existOrFail('muteAll'); // TODO: More assertions }); @@ -193,7 +193,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await disableAllBtn.click(); // Enable all button shows after clicking disable all - await testSubjects.exists('enableAll'); + await testSubjects.existOrFail('enableAll'); // TODO: More assertions }); @@ -219,7 +219,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await enableAllBtn.click(); // Disable all button shows after clicking enable all - await testSubjects.exists('disableAll'); + await testSubjects.existOrFail('disableAll'); // TODO: More assertions }); diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts index 57c27d9338a23d..43776faea3be02 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts @@ -146,7 +146,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ); await saveButton.click(); - await testSubjects.exists('euiToastHeader'); + await testSubjects.existOrFail('euiToastHeader'); const closeButton = await testSubjects.find('toastCloseButton'); await closeButton.click(); @@ -188,7 +188,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ); await saveButton.click(); - await testSubjects.exists('euiToastHeader'); + await testSubjects.existOrFail('euiToastHeader'); const closeButton = await testSubjects.find('toastCloseButton'); await closeButton.click(); diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts index 4d2fe6ae82d37f..bff5e50181092c 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts @@ -24,11 +24,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const headingText = await pageObjects.triggersActionsUI.sectionHeadingText(); expect(headingText).to.be('Alerts and actions'); - const actionsConnectorsList = await testSubjects.exists('actionsList'); - expect(actionsConnectorsList).to.be(true); - - const typeFilterButton = await pageObjects.triggersActionsUI.typeFilterButton(); - expect(await typeFilterButton.isDisplayed()).to.be(true); + await testSubjects.existOrFail('createActionButton'); }); describe('Alerts tab', () => { @@ -43,8 +39,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(url).to.contain(`/alerts`); // Verify content - const alertsList = await testSubjects.exists('alertsList'); - expect(alertsList).to.be(true); + await testSubjects.existOrFail('alertsList'); }); }); }); diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts index e2e0c25d112958..c76f477c8cfbef 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default ({ loadTestFile, getService }: FtrProviderContext) => { describe('Actions and Triggers app', function() { - this.tags('ciGroup3'); // not sure about which CI group this tests should belong to + this.tags('ciGroup3'); loadTestFile(require.resolve('./home_page')); loadTestFile(require.resolve('./connectors')); loadTestFile(require.resolve('./alerts')); From 898efbe8a6f35ade3688eac3d0994fecace20888 Mon Sep 17 00:00:00 2001 From: Dave Snider Date: Fri, 6 Dec 2019 08:36:01 -0800 Subject: [PATCH 180/297] text cleanup --- .../components/builtin_action_types/email.tsx | 2 +- .../builtin_action_types/pagerduty.tsx | 2 +- .../builtin_action_types/server_log.tsx | 2 +- .../components/builtin_action_types/slack.tsx | 2 +- .../connector_add_flyout.tsx | 40 ++++++++++++++----- .../components/actions_connectors_list.tsx | 30 +++++++++----- .../public/models/action/logging_action.js | 6 +-- .../public/models/action/slack_action.js | 29 +++++++------- 8 files changed, 72 insertions(+), 41 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx index 08adb3d6a132ed..745aa19cdaecf7 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx @@ -30,7 +30,7 @@ export function getActionType(): ActionTypeModel { selectMessage: i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.emailAction.selectMessageText', { - defaultMessage: 'Send an email.', + defaultMessage: 'Configure SMTP settings to send email from your servers', } ), validateConnector: (action: ActionConnector): ValidationResult => { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.tsx index 8a05f9320f7951..1ed59bbf7b19f7 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.tsx @@ -22,7 +22,7 @@ export function getActionType(): ActionTypeModel { selectMessage: i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.selectMessageText', { - defaultMessage: 'Create an event in PagerDuty.', + defaultMessage: 'Configure PageDuty API details to send events to their system', } ), validateConnector: (action: ActionConnector): ValidationResult => { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.tsx index 1309c6f70f49ee..69ee4e2f433d85 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.tsx @@ -16,7 +16,7 @@ export function getActionType(): ActionTypeModel { selectMessage: i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.serverLogAction.selectMessageText', { - defaultMessage: 'Add an item to the logs.', + defaultMessage: 'Adds a log line with a message you define', } ), validateConnector: (): ValidationResult => { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx index 176464dcefac59..6797c61944ad2c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx @@ -22,7 +22,7 @@ export function getActionType(): ActionTypeModel { selectMessage: i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.slackAction.selectMessageText', { - defaultMessage: 'Send a message to a Slack user or channel.', + defaultMessage: 'Configure Slack using a webhook url they provide', } ), validateConnector: (action: ActionConnector): ValidationResult => { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx index af762b883a892b..70d5e9cc1cf0b7 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { useContext, useCallback, useState, useEffect } from 'react'; +import React, { useContext, useCallback, useState, useEffect, Fragment } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiTitle, @@ -12,6 +12,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiIcon, + EuiText, } from '@elastic/eui'; import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; import { ActionTypeMenu } from './action_type_menu'; @@ -55,21 +56,38 @@ export const ConnectorAddFlyout = () => { return ( - + {actionTypeModel && actionTypeModel.iconClass ? ( - + ) : null} - -

- -

-
+ {actionTypeModel ? ( + + +

+ + {actionType.name} +

+
+ + {actionTypeModel.selectMessage} + +
+ ) : ( + +

+ +

+
+ )}
diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index 25381b509916dc..b2f39b70081d4f 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -13,6 +13,7 @@ import { EuiIcon, EuiEmptyPrompt, EuiTitle, + EuiLink, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -151,24 +152,31 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { const actionsTableColumns = [ { - field: 'actionType', - 'data-test-subj': 'connectorsTableCell-actionType', + field: 'name', + 'data-test-subj': 'connectorsTableCell-name', name: i18n.translate( - 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actionTypeTitle', + 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.nameTitle', { - defaultMessage: 'Type', + defaultMessage: 'Name', } ), sortable: false, truncateText: true, + render: (item: ActionConnectorTableItem) => { + return ( + editItem(item)} key={item.id}> + {item} + + ); + }, }, { - field: 'name', - 'data-test-subj': 'connectorsTableCell-name', + field: 'actionType', + 'data-test-subj': 'connectorsTableCell-actionType', name: i18n.translate( - 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.nameTitle', + 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actionTypeTitle', { - defaultMessage: 'Name', + defaultMessage: 'Type', } ), sortable: false, @@ -184,7 +192,11 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { sortable: false, truncateText: true, render: (value: number, item: ActionConnectorTableItem) => { - return {value}; + return ( + + {value} + + ); }, }, { diff --git a/x-pack/legacy/plugins/watcher/public/models/action/logging_action.js b/x-pack/legacy/plugins/watcher/public/models/action/logging_action.js index 477ee9e2230b4c..29afadcf46cb1c 100644 --- a/x-pack/legacy/plugins/watcher/public/models/action/logging_action.js +++ b/x-pack/legacy/plugins/watcher/public/models/action/logging_action.js @@ -16,7 +16,7 @@ export class LoggingAction extends BaseAction { defaultMessage: 'Watch [{context}] has exceeded the threshold', values: { context: '{{ctx.metadata.name}}', - } + }, }); this.text = get(props, 'text', props.ignoreDefaults ? null : defaultText); } @@ -43,7 +43,7 @@ export class LoggingAction extends BaseAction { text, logging: { text, - } + }, }); return result; @@ -70,7 +70,7 @@ export class LoggingAction extends BaseAction { }); static iconClass = 'logsApp'; static selectMessage = i18n.translate('xpack.watcher.models.loggingAction.selectMessageText', { - defaultMessage: 'Add an item to the logs.', + defaultMessage: 'Adds a log line with a message you define', }); static simulatePrompt = i18n.translate('xpack.watcher.models.loggingAction.simulateButtonLabel', { defaultMessage: 'Log a sample message', diff --git a/x-pack/legacy/plugins/watcher/public/models/action/slack_action.js b/x-pack/legacy/plugins/watcher/public/models/action/slack_action.js index da0f3cf5fb0c7d..680b7b3806f2d6 100644 --- a/x-pack/legacy/plugins/watcher/public/models/action/slack_action.js +++ b/x-pack/legacy/plugins/watcher/public/models/action/slack_action.js @@ -13,13 +13,13 @@ export class SlackAction extends BaseAction { super(props); const toArray = get(props, 'to'); - this.to = isArray(toArray) ? toArray : toArray && [ toArray ]; + this.to = isArray(toArray) ? toArray : toArray && [toArray]; const defaultText = i18n.translate('xpack.watcher.models.slackAction.defaultText', { defaultMessage: 'Watch [{context}] has exceeded the threshold', values: { context: '{{ctx.metadata.name}}', - } + }, }); this.text = get(props, 'text', props.ignoreDefaults ? null : defaultText); } @@ -36,17 +36,18 @@ export class SlackAction extends BaseAction { get upstreamJson() { const result = super.upstreamJson; const to = this.to && this.to.length > 0 ? this.to : undefined; - const message = this.text || to - ? { - text: this.text, - to, - } - : {}; + const message = + this.text || to + ? { + text: this.text, + to, + } + : {}; Object.assign(result, { to, text: this.text, slack: { - message + message, }, }); @@ -59,7 +60,7 @@ export class SlackAction extends BaseAction { defaultMessage: 'Sample Slack message sent {toList}.', values: { toList: toList ? `to ${toList}` : '', - } + }, }); } @@ -69,7 +70,7 @@ export class SlackAction extends BaseAction { defaultMessage: 'Failed to send sample Slack message {toList}.', values: { toList: toList ? `to ${toList}` : '', - } + }, }); } @@ -78,13 +79,13 @@ export class SlackAction extends BaseAction { } static typeName = i18n.translate('xpack.watcher.models.slackAction.TypeName', { - defaultMessage: 'Slack' + defaultMessage: 'Slack', }); static iconClass = 'logoSlack'; static selectMessage = i18n.translate('xpack.watcher.models.slackAction.selectMessageText', { - defaultMessage: 'Send a message to a Slack user or channel.' + defaultMessage: 'Send a message to a Slack user or channel', }); static simulatePrompt = i18n.translate('xpack.watcher.models.slackAction.simulateButtonLabel', { - defaultMessage: 'Send a sample message' + defaultMessage: 'Send a sample message', }); } From 6b0cbf4047b09412950bcfd1213b720a3f4fb6b6 Mon Sep 17 00:00:00 2001 From: Dave Snider Date: Fri, 6 Dec 2019 09:05:31 -0800 Subject: [PATCH 181/297] zindex fix for index threshold trigger --- .../sections/alert_add/alert_types/threshold/expression.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx index d004f88a6b6a8e..549d9b66ad9fb3 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx @@ -633,6 +633,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = ownFocus withTitle anchorPosition="downLeft" + zIndex={8000} >
From 40f10e6d66382e0e0e2a6f52e1f5c9ba8ae5fab7 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 6 Dec 2019 16:29:40 -0500 Subject: [PATCH 182/297] Expand the functional tests, add assertions --- .../alerts_list/components/alerts_list.tsx | 4 + .../apps/triggers_actions_ui/alerts.ts | 207 ++++++++++++------ .../apps/triggers_actions_ui/connectors.ts | 123 ++++------- .../apps/triggers_actions_ui/home_page.ts | 2 +- .../page_objects/triggers_actions_ui_page.ts | 73 ++++-- 5 files changed, 240 insertions(+), 169 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index e1ca35b5a842a6..3fcb5232144e74 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -114,6 +114,7 @@ export const AlertsList: React.FunctionComponent = () => { ), sortable: false, truncateText: true, + 'data-test-subj': 'alertsTableCell-name', }, { field: 'tagsText', @@ -122,6 +123,7 @@ export const AlertsList: React.FunctionComponent = () => { { defaultMessage: 'Tags' } ), sortable: false, + 'data-test-subj': 'alertsTableCell-tagsText', }, { field: 'alertType', @@ -131,6 +133,7 @@ export const AlertsList: React.FunctionComponent = () => { ), sortable: false, truncateText: true, + 'data-test-subj': 'alertsTableCell-alertType', }, { field: 'interval', @@ -140,6 +143,7 @@ export const AlertsList: React.FunctionComponent = () => { ), sortable: false, truncateText: false, + 'data-test-subj': 'alertsTableCell-interval', }, { name: '', diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts index aa24cb8ad3dec1..9b64f25ddfc9d1 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts @@ -8,8 +8,6 @@ import uuid from 'uuid'; import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; -const ENTER_KEY = '\uE007'; - function generateUniqueKey() { return uuid.v4().replace(/-/g, ''); } @@ -17,7 +15,6 @@ function generateUniqueKey() { export default ({ getPageObjects, getService }: FtrProviderContext) => { const testSubjects = getService('testSubjects'); const pageObjects = getPageObjects(['common', 'triggersActionsUI', 'header']); - const find = getService('find'); const supertest = getService('supertest'); async function createAlert() { @@ -27,7 +24,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { .send({ enabled: true, name: generateUniqueKey(), - tags: ['foo'], + tags: ['foo', 'bar'], alertTypeId: 'test', interval: '1m', throttle: '1m', @@ -47,23 +44,24 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('should search for alert', async () => { const createdAlert = await createAlert(); - const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); - await searchBox.click(); - await searchBox.clearValue(); - await searchBox.type(createdAlert.name); - await searchBox.pressKeys(ENTER_KEY); - - const rows = await testSubjects.findAll('alert-row'); - expect(rows.length).to.eql(1); + + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); + + const searchResults = await pageObjects.triggersActionsUI.getAlertsList(); + expect(searchResults).to.eql([ + { + name: createdAlert.name, + tagsText: 'foo, bar', + alertType: 'test', + interval: '1m', + }, + ]); }); it('should disable single alert', async () => { const createdAlert = await createAlert(); - const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); - await searchBox.click(); - await searchBox.clearValue(); - await searchBox.type(createdAlert.name); - await searchBox.pressKeys(ENTER_KEY); + + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); const collapsedItemActions = await testSubjects.find('collapsedItemActions'); await collapsedItemActions.click(); @@ -71,25 +69,49 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const enableSwitch = await testSubjects.find('enableSwitch'); await enableSwitch.click(); - const searchBoxAfterUpdate = await find.byCssSelector( - '[data-test-subj="alertsList"] .euiFieldSearch' - ); - await searchBoxAfterUpdate.click(); + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); + + const collapsedItemActionsAfterDisable = await testSubjects.find('collapsedItemActions'); + await collapsedItemActionsAfterDisable.click(); - // TODO: More assertions + const enableSwitchAfterDisable = await testSubjects.find('enableSwitch'); + const isChecked = await enableSwitchAfterDisable.getAttribute('aria-checked'); + expect(isChecked).to.eql('false'); }); it('should re-enable single alert', async () => { - // TODO + const createdAlert = await createAlert(); + + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); + + const collapsedItemActions = await testSubjects.find('collapsedItemActions'); + await collapsedItemActions.click(); + + const enableSwitch = await testSubjects.find('enableSwitch'); + await enableSwitch.click(); + + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); + + const collapsedItemActionsAfterDisable = await testSubjects.find('collapsedItemActions'); + await collapsedItemActionsAfterDisable.click(); + + const enableSwitchAfterDisable = await testSubjects.find('enableSwitch'); + await enableSwitchAfterDisable.click(); + + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); + + const collapsedItemActionsAfterReEnable = await testSubjects.find('collapsedItemActions'); + await collapsedItemActionsAfterReEnable.click(); + + const enableSwitchAfterReEnable = await testSubjects.find('enableSwitch'); + const isChecked = await enableSwitchAfterReEnable.getAttribute('aria-checked'); + expect(isChecked).to.eql('true'); }); it('should mute single alert', async () => { const createdAlert = await createAlert(); - const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); - await searchBox.click(); - await searchBox.clearValue(); - await searchBox.type(createdAlert.name); - await searchBox.pressKeys(ENTER_KEY); + + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); const collapsedItemActions = await testSubjects.find('collapsedItemActions'); await collapsedItemActions.click(); @@ -97,25 +119,50 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const muteSwitch = await testSubjects.find('muteSwitch'); await muteSwitch.click(); - const searchBoxAfterUpdate = await find.byCssSelector( - '[data-test-subj="alertsList"] .euiFieldSearch' - ); - await searchBoxAfterUpdate.click(); + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); + + const collapsedItemActionsAfterMute = await testSubjects.find('collapsedItemActions'); + await collapsedItemActionsAfterMute.click(); - // TODO: More assertions + const muteSwitchAfterMute = await testSubjects.find('muteSwitch'); + const isChecked = await muteSwitchAfterMute.getAttribute('aria-checked'); + expect(isChecked).to.eql('true'); }); it('should unmute single alert', async () => { - // TODO + const createdAlert = await createAlert(); + + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); + + const collapsedItemActions = await testSubjects.find('collapsedItemActions'); + await collapsedItemActions.click(); + + const muteSwitch = await testSubjects.find('muteSwitch'); + await muteSwitch.click(); + + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); + + const collapsedItemActionsAfterMute = await testSubjects.find('collapsedItemActions'); + await collapsedItemActionsAfterMute.click(); + + const muteSwitchAfterMute = await testSubjects.find('muteSwitch'); + await muteSwitchAfterMute.click(); + + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); + + const collapsedItemActionsAfterUnmute = await testSubjects.find('collapsedItemActions'); + await collapsedItemActionsAfterUnmute.click(); + + const muteSwitchAfterUnmute = await testSubjects.find('muteSwitch'); + const isChecked = await muteSwitchAfterUnmute.getAttribute('aria-checked'); + expect(isChecked).to.eql('false'); }); + // TODO: wait for delete to finish it('should delete single alert', async () => { const createdAlert = await createAlert(); - const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); - await searchBox.click(); - await searchBox.clearValue(); - await searchBox.type(createdAlert.name); - await searchBox.pressKeys(ENTER_KEY); + + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); const collapsedItemActions = await testSubjects.find('collapsedItemActions'); await collapsedItemActions.click(); @@ -123,16 +170,16 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const deleteBtn = await testSubjects.find('deleteAlert'); await deleteBtn.click(); - // TODO: More assertions + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); + + const searchResults = await pageObjects.triggersActionsUI.getAlertsList(); + expect(searchResults.length).to.eql(0); }); it('should mute all selection', async () => { const createdAlert = await createAlert(); - const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); - await searchBox.click(); - await searchBox.clearValue(); - await searchBox.type(createdAlert.name); - await searchBox.pressKeys(ENTER_KEY); + + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); const checkbox = await testSubjects.find(`checkboxSelectRow-${createdAlert.id}`); await checkbox.click(); @@ -146,16 +193,20 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Unmute all button shows after clicking mute all await testSubjects.existOrFail('unmuteAll'); - // TODO: More assertions + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); + + const collapsedItemActions = await testSubjects.find('collapsedItemActions'); + await collapsedItemActions.click(); + + const muteSwitch = await testSubjects.find('muteSwitch'); + const isChecked = await muteSwitch.getAttribute('aria-checked'); + expect(isChecked).to.eql('true'); }); it('should unmute all selection', async () => { const createdAlert = await createAlert(); - const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); - await searchBox.click(); - await searchBox.clearValue(); - await searchBox.type(createdAlert.name); - await searchBox.pressKeys(ENTER_KEY); + + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); const checkbox = await testSubjects.find(`checkboxSelectRow-${createdAlert.id}`); await checkbox.click(); @@ -172,16 +223,20 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Mute all button shows after clicking unmute all await testSubjects.existOrFail('muteAll'); - // TODO: More assertions + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); + + const collapsedItemActions = await testSubjects.find('collapsedItemActions'); + await collapsedItemActions.click(); + + const muteSwitch = await testSubjects.find('muteSwitch'); + const isChecked = await muteSwitch.getAttribute('aria-checked'); + expect(isChecked).to.eql('false'); }); it('should disable all selection', async () => { const createdAlert = await createAlert(); - const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); - await searchBox.click(); - await searchBox.clearValue(); - await searchBox.type(createdAlert.name); - await searchBox.pressKeys(ENTER_KEY); + + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); const checkbox = await testSubjects.find(`checkboxSelectRow-${createdAlert.id}`); await checkbox.click(); @@ -195,16 +250,20 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Enable all button shows after clicking disable all await testSubjects.existOrFail('enableAll'); - // TODO: More assertions + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); + + const collapsedItemActions = await testSubjects.find('collapsedItemActions'); + await collapsedItemActions.click(); + + const enableSwitch = await testSubjects.find('enableSwitch'); + const isChecked = await enableSwitch.getAttribute('aria-checked'); + expect(isChecked).to.eql('false'); }); it('should enable all selection', async () => { const createdAlert = await createAlert(); - const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); - await searchBox.click(); - await searchBox.clearValue(); - await searchBox.type(createdAlert.name); - await searchBox.pressKeys(ENTER_KEY); + + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); const checkbox = await testSubjects.find(`checkboxSelectRow-${createdAlert.id}`); await checkbox.click(); @@ -221,16 +280,21 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Disable all button shows after clicking enable all await testSubjects.existOrFail('disableAll'); - // TODO: More assertions + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); + + const collapsedItemActions = await testSubjects.find('collapsedItemActions'); + await collapsedItemActions.click(); + + const enableSwitch = await testSubjects.find('enableSwitch'); + const isChecked = await enableSwitch.getAttribute('aria-checked'); + expect(isChecked).to.eql('true'); }); + // TODO: wait for delete to finish it('should delete all selection', async () => { const createdAlert = await createAlert(); - const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); - await searchBox.click(); - await searchBox.clearValue(); - await searchBox.type(createdAlert.name); - await searchBox.pressKeys(ENTER_KEY); + + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); const checkbox = await testSubjects.find(`checkboxSelectRow-${createdAlert.id}`); await checkbox.click(); @@ -241,7 +305,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const deleteAllBtn = await testSubjects.find('deleteAll'); await deleteAllBtn.click(); - // TODO: More assertions + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); + + const searchResults = await pageObjects.triggersActionsUI.getAlertsList(); + expect(searchResults.length).to.eql(0); }); }); }; diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts index 43776faea3be02..d25b56d449e151 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts @@ -8,8 +8,6 @@ import uuid from 'uuid'; import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; -const ENTER_KEY = '\uE007'; - function generateUniqueKey() { return uuid.v4().replace(/-/g, ''); } @@ -27,7 +25,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('should create a connector', async () => { const connectorName = generateUniqueKey(); - await pageObjects.triggersActionsUI.createActionConnector(); + await pageObjects.triggersActionsUI.clickCreateConnectorButton(); const serverLogCard = await testSubjects.find('.server-log-card'); await serverLogCard.click(); @@ -42,32 +40,26 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ); await saveButton.click(); - const toastMessage = await find.byCssSelector( - '[data-test-subj="euiToastHeader"] .euiToastHeader__title' - ); - expect(await toastMessage.getVisibleText()).to.eql(`Created '${connectorName}'`); - - const closeButton = await testSubjects.find('toastCloseButton'); - await closeButton.click(); - await testSubjects.waitForHidden('toastCloseButton'); + const toastTitle = await pageObjects.common.closeToast(); + expect(toastTitle).to.eql(`Created '${connectorName}'`); - const searchBox = await find.byCssSelector('[data-test-subj="actionsList"] .euiFieldSearch'); - await searchBox.click(); - await searchBox.clearValue(); - await searchBox.type(connectorName); - await searchBox.pressKeys(ENTER_KEY); + await pageObjects.triggersActionsUI.searchConnectors(connectorName); - const textShownInConnectorsList = await testSubjects.getVisibleText( - 'connectorsTableCell-name' - ); - expect(textShownInConnectorsList).to.eql(connectorName); + const searchResults = await pageObjects.triggersActionsUI.getConnectorsList(); + expect(searchResults).to.eql([ + { + name: connectorName, + actionType: 'Server Log', + referencedByCount: '0', + }, + ]); }); it('should edit a connector', async () => { const connectorName = generateUniqueKey(); const updatedConnectorName = `${connectorName}updated`; - await pageObjects.triggersActionsUI.createActionConnector(); + await pageObjects.triggersActionsUI.clickCreateConnectorButton(); const serverLogCard = await testSubjects.find('.server-log-card'); await serverLogCard.click(); @@ -82,21 +74,15 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ); await saveButton.click(); - const closeToastButton = await testSubjects.find('toastCloseButton'); - await closeToastButton.click(); - await testSubjects.waitForHidden('toastCloseButton'); + await pageObjects.common.closeToast(); - const searchBox = await find.byCssSelector('[data-test-subj="actionsList"] .euiFieldSearch'); - await searchBox.click(); - await searchBox.clearValue(); - await searchBox.type(connectorName); - await searchBox.pressKeys(ENTER_KEY); + await pageObjects.triggersActionsUI.searchConnectors(connectorName); - const rowsBeforeDelete = await testSubjects.findAll('connectors-row'); - expect(rowsBeforeDelete.length).to.eql(1); + const searchResultsBeforeEdit = await pageObjects.triggersActionsUI.getConnectorsList(); + expect(searchResultsBeforeEdit.length).to.eql(1); - const deleteConnectorBtn = await testSubjects.find('edit'); - await deleteConnectorBtn.click(); + const editConnectorBtn = await testSubjects.find('edit'); + await editConnectorBtn.click(); const nameInputToUpdate = await testSubjects.find('nameInput'); await nameInputToUpdate.click(); @@ -108,30 +94,25 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ); await saveEditButton.click(); - const toastMessage = await find.byCssSelector( - '[data-test-subj="euiToastHeader"] .euiToastHeader__title' - ); - expect(await toastMessage.getVisibleText()).to.eql(`Updated '${updatedConnectorName}'`); - - const closeToastUpdatedButton = await testSubjects.find('toastCloseButton'); - await closeToastUpdatedButton.click(); - await testSubjects.waitForHidden('toastCloseButton'); + const toastTitle = await pageObjects.common.closeToast(); + expect(toastTitle).to.eql(`Updated '${updatedConnectorName}'`); - await searchBox.click(); - await searchBox.clearValue(); - await searchBox.type(updatedConnectorName); - await searchBox.pressKeys(ENTER_KEY); + await pageObjects.triggersActionsUI.searchConnectors(updatedConnectorName); - const textShownInConnectorsList = await testSubjects.getVisibleText( - 'connectorsTableCell-name' - ); - expect(textShownInConnectorsList).to.eql(updatedConnectorName); + const searchResultsAfterEdit = await pageObjects.triggersActionsUI.getConnectorsList(); + expect(searchResultsAfterEdit).to.eql([ + { + name: updatedConnectorName, + actionType: 'Server Log', + referencedByCount: '0', + }, + ]); }); it('should delete a connector', async () => { const connectorName = generateUniqueKey(); - await pageObjects.triggersActionsUI.createActionConnector(); + await pageObjects.triggersActionsUI.clickCreateConnectorButton(); const serverLogCard = await testSubjects.find('.server-log-card'); await serverLogCard.click(); @@ -146,34 +127,26 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ); await saveButton.click(); - await testSubjects.existOrFail('euiToastHeader'); + await pageObjects.common.closeToast(); - const closeButton = await testSubjects.find('toastCloseButton'); - await closeButton.click(); - await testSubjects.waitForHidden('toastCloseButton'); + await pageObjects.triggersActionsUI.searchConnectors(connectorName); - const searchBox = await find.byCssSelector('[data-test-subj="actionsList"] .euiFieldSearch'); - await searchBox.click(); - await searchBox.clearValue(); - await searchBox.type(connectorName); - await searchBox.pressKeys(ENTER_KEY); - - const rowsBeforeDelete = await testSubjects.findAll('connectors-row'); - expect(rowsBeforeDelete.length).to.eql(1); + const searchResultsBeforeDelete = await pageObjects.triggersActionsUI.getConnectorsList(); + expect(searchResultsBeforeDelete.length).to.eql(1); const deleteConnectorBtn = await testSubjects.find('deleteConnector'); await deleteConnectorBtn.click(); await find.byCssSelector('[data-test-subj="actionsTable"]:not(.euiBasicTable-loading)'); - const rowsAfterDelete = await testSubjects.findAll('connectors-row', 0); - expect(rowsAfterDelete.length).to.eql(0); + const searchResultsAfterDelete = await pageObjects.triggersActionsUI.getConnectorsList(); + expect(searchResultsAfterDelete.length).to.eql(0); }); it('should bulk delete connectors', async () => { const connectorName = generateUniqueKey(); - await pageObjects.triggersActionsUI.createActionConnector(); + await pageObjects.triggersActionsUI.clickCreateConnectorButton(); const serverLogCard = await testSubjects.find('.server-log-card'); await serverLogCard.click(); @@ -188,20 +161,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ); await saveButton.click(); - await testSubjects.existOrFail('euiToastHeader'); - - const closeButton = await testSubjects.find('toastCloseButton'); - await closeButton.click(); - await testSubjects.waitForHidden('toastCloseButton'); + await pageObjects.common.closeToast(); - const searchBox = await find.byCssSelector('[data-test-subj="actionsList"] .euiFieldSearch'); - await searchBox.click(); - await searchBox.clearValue(); - await searchBox.type(connectorName); - await searchBox.pressKeys(ENTER_KEY); + await pageObjects.triggersActionsUI.searchConnectors(connectorName); - const rowsBeforeDelete = await testSubjects.findAll('connectors-row'); - expect(rowsBeforeDelete.length).to.eql(1); + const searchResultsBeforeDelete = await pageObjects.triggersActionsUI.getConnectorsList(); + expect(searchResultsBeforeDelete.length).to.eql(1); const deleteCheckbox = await find.byCssSelector( '.euiTableRowCellCheckbox .euiCheckbox__input' @@ -213,8 +178,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await find.byCssSelector('[data-test-subj="actionsTable"]:not(.euiBasicTable-loading)'); - const rowsAfterDelete = await testSubjects.findAll('connectors-row', 0); - expect(rowsAfterDelete.length).to.eql(0); + const searchResultsAfterDelete = await pageObjects.triggersActionsUI.getConnectorsList(); + expect(searchResultsAfterDelete.length).to.eql(0); }); }); }; diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts index bff5e50181092c..2addfe9339e03c 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts @@ -21,7 +21,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('Loads the app', async () => { await log.debug('Checking for section heading to say Triggers and Actions.'); - const headingText = await pageObjects.triggersActionsUI.sectionHeadingText(); + const headingText = await pageObjects.triggersActionsUI.getSectionHeadingText(); expect(headingText).to.be('Alerts and actions'); await testSubjects.existOrFail('createActionButton'); diff --git a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts index 8a25249e5c81eb..91d3c68bfe7c5e 100644 --- a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts +++ b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts @@ -6,42 +6,77 @@ import { FtrProviderContext } from '../ftr_provider_context'; +const ENTER_KEY = '\uE007'; + export function TriggersActionsPageProvider({ getService }: FtrProviderContext) { const find = getService('find'); const testSubjects = getService('testSubjects'); return { - async sectionHeadingText() { + async getSectionHeadingText() { return await testSubjects.getVisibleText('appTitle'); }, - async selectActionTypeFilter() { - await testSubjects.click('typeFilterButton'); + async clickCreateConnectorButton() { + await testSubjects.click('createActionButton'); }, - async typeFilterButton() { - const typeFilter = await find.allByCssSelector( - '.euiFilterButton__textShift[data-text="Type"]' - ); - return typeFilter[0]; + async searchConnectors(searchText: string) { + const searchBox = await find.byCssSelector('[data-test-subj="actionsList"] .euiFieldSearch'); + await searchBox.click(); + await searchBox.clearValue(); + await searchBox.type(searchText); + await searchBox.pressKeys(ENTER_KEY); }, - async createActionConnector() { - await testSubjects.click('createActionButton'); + async searchAlerts(searchText: string) { + const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); + await searchBox.click(); + await searchBox.clearValue(); + await searchBox.type(searchText); + await searchBox.pressKeys(ENTER_KEY); }, - - async getActionConnectorsList() { - const table = await find.byCssSelector('table'); + async getConnectorsList() { + const table = await find.byCssSelector('[data-test-subj="actionsList"] table'); const $ = await table.parseDomContent(); return $.findTestSubjects('connectors-row') .toArray() .map(row => { return { - indexHealth: $(row) - .findTestSubject('cell-actionType') + name: $(row) + .findTestSubject('connectorsTableCell-name') + .find('.euiTableCellContent') + .text(), + actionType: $(row) + .findTestSubject('connectorsTableCell-actionType') + .find('.euiTableCellContent') + .text(), + referencedByCount: $(row) + .findTestSubject('connectorsTableCell-referencedByCount') + .find('.euiTableCellContent') + .text(), + }; + }); + }, + async getAlertsList() { + const table = await find.byCssSelector('[data-test-subj="alertsList"] table'); + const $ = await table.parseDomContent(); + return $.findTestSubjects('alert-row') + .toArray() + .map(row => { + return { + name: $(row) + .findTestSubject('lertsTableCell-name') + .find('.euiTableCellContent') + .text(), + tagsText: $(row) + .findTestSubject('alertsTableCell-tagsText') + .find('.euiTableCellContent') .text(), - indexStatus: $(row) - .findTestSubject('cell-description') + alertType: $(row) + .findTestSubject('alertsTableCell-alertType') + .find('.euiTableCellContent') .text(), - indexPrimary: $(row) - .findTestSubject('cell-referencedByCount') + interval: $(row) + .findTestSubject('alertsTableCell-interval') + .find('.euiTableCellContent') .text(), }; }); From 2dc2ec61e0c4987ff3bf742fe73bca9ed65f043b Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 6 Dec 2019 15:42:49 -0800 Subject: [PATCH 183/297] Fixed edit connector from the Name column, and removed pencil button --- .../connector_add_flyout.tsx | 2 +- .../actions_connectors_list.test.tsx | 4 +-- .../components/actions_connectors_list.tsx | 26 +++---------------- 3 files changed, 6 insertions(+), 26 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx index 70d5e9cc1cf0b7..c9ea55ceed68a1 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx @@ -63,7 +63,7 @@ export const ConnectorAddFlyout = () => { ) : null} - {actionTypeModel ? ( + {actionTypeModel && actionType ? (

diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx index dcf6dc60ffe1b1..095c4604a44364 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx @@ -98,7 +98,7 @@ describe('actions_connectors_list', () => { it('select item for edit should render ConnectorEditFlyout', () => { wrapper - .find('[data-test-subj="edit"]') + .find('[data-test-subj="edit1"]') .first() .simulate('click'); expect(wrapper.find('ConnectorEditFlyout')).toHaveLength(1); @@ -106,7 +106,7 @@ describe('actions_connectors_list', () => { it('change capability', () => { wrapper - .find('[data-test-subj="edit"]') + .find('[data-test-subj="edit1"]') .first() .simulate('click'); expect(wrapper.find('ConnectorEditFlyout')).toHaveLength(1); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index b2f39b70081d4f..15a3fd5f810d39 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -162,10 +162,10 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { ), sortable: false, truncateText: true, - render: (item: ActionConnectorTableItem) => { + render: (value: string, item: ActionConnectorTableItem) => { return ( - editItem(item)} key={item.id}> - {item} + editItem(item)} key={item.id}> + {value} ); }, @@ -202,26 +202,6 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { { name: '', actions: [ - { - enabled: () => canSave, - name: i18n.translate( - 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.editActionName', - { defaultMessage: 'Edit' } - ), - description: canSave - ? i18n.translate( - 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.editActionDescription', - { defaultMessage: 'Edit this action' } - ) - : i18n.translate( - 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.actions.editActionDisabledDescription', - { defaultMessage: 'Unable to edit actions' } - ), - type: 'icon', - icon: 'pencil', - 'data-test-subj': 'edit', - onClick: (item: ActionConnectorTableItem) => editItem(item), - }, { enabled: () => canDelete, 'data-test-subj': 'deleteConnector', From d6e46fb488e4e35d245da7fc9f46cebd92a1fba4 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 9 Dec 2019 09:32:38 -0500 Subject: [PATCH 184/297] Remove tags filter, use search bar instead --- .../public/application/lib/alert_api.ts | 8 +-- .../alerts_list/components/alerts_list.tsx | 7 +- .../alerts_list/components/tags_filter.tsx | 68 ------------------- 3 files changed, 4 insertions(+), 79 deletions(-) delete mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/tags_filter.tsx diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.ts index d38338773bb731..d30bff1ce35cdd 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.ts @@ -16,13 +16,11 @@ export async function loadAlerts({ http, page, searchText, - tagsFilter, typesFilter, }: { http: HttpServiceBase; page: { index: number; size: number }; searchText?: string; - tagsFilter?: string[]; typesFilter?: string[]; }): Promise<{ page: number; @@ -31,9 +29,6 @@ export async function loadAlerts({ data: Alert[]; }> { const filters = []; - if (tagsFilter && tagsFilter.length) { - filters.push(`alert.attributes.tags:(${tagsFilter.join(' and ')})`); - } if (typesFilter && typesFilter.length) { filters.push(`alert.attributes.alertTypeId:(${typesFilter.join(' or ')})`); } @@ -41,9 +36,10 @@ export async function loadAlerts({ query: { page: page.index + 1, per_page: page.size, - search_fields: searchText ? 'name' : undefined, + search_fields: searchText ? JSON.stringify(['name', 'tags']) : undefined, search: searchText, filter: filters.length ? filters.join(' and ') : undefined, + default_search_operator: 'AND', }, }); } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 3fcb5232144e74..3b975e2a875828 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -16,7 +16,6 @@ import { Alert, AlertTableItem, AlertTypeIndex, Pagination } from '../../../../t import { AlertAdd } from '../../alert_add'; import { BulkActionPopover } from './bulk_action_popover'; import { CollapsedItemActions } from './collapsed_item_actions'; -import { TagsFilter } from './tags_filter'; import { TypeFilter } from './type_filter'; import { loadAlerts, loadAlertTypes } from '../../../lib/alert_api'; @@ -37,14 +36,13 @@ export const AlertsList: React.FunctionComponent = () => { const [totalItemCount, setTotalItemCount] = useState(0); const [page, setPage] = useState({ index: 0, size: 10 }); const [searchText, setSearchText] = useState(undefined); - const [tagsFilter, setTagsFilter] = useState([]); const [typesFilter, setTypesFilter] = useState([]); const [alertFlyoutVisible, setAlertFlyoutVisibility] = useState(false); useEffect(() => { loadAlertsData(); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [page, searchText, tagsFilter, typesFilter]); + }, [page, searchText, typesFilter]); useEffect(() => { (async () => { @@ -88,7 +86,7 @@ export const AlertsList: React.FunctionComponent = () => { async function loadAlertsData() { setIsLoadingAlerts(true); try { - const alertsResponse = await loadAlerts({ http, page, searchText, tagsFilter, typesFilter }); + const alertsResponse = await loadAlerts({ http, page, searchText, typesFilter }); setAlerts(alertsResponse.data); setTotalItemCount(alertsResponse.total); } catch (e) { @@ -188,7 +186,6 @@ export const AlertsList: React.FunctionComponent = () => { })) .sort((a, b) => a.name.localeCompare(b.name))} />, - setTagsFilter(tags)} />, void; -} - -export const TagsFilter: React.FunctionComponent = ({ onChange }) => { - const [selectedOptions, setSelectedOptions] = useState([]); - const [isPopoverOpen, setIsPopoverOpen] = useState(false); - - useEffect(() => { - if (onChange) { - onChange(selectedOptions.map(item => item.label)); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [selectedOptions]); - - return ( - - setIsPopoverOpen(false)} - button={ - 0} - numActiveFilters={selectedOptions.length} - numFilters={selectedOptions.length} - onClick={() => setIsPopoverOpen(!isPopoverOpen)} - > - - - } - > -
- { - setSelectedOptions(selectedOptions.concat({ label: searchValue })); - }} - onChange={(updatedSelectedOptions: EuiComboBoxOptionProps[]) => { - setSelectedOptions(updatedSelectedOptions); - }} - /> -
-
-
- ); -}; From b182b7c2264fdf716a0a30b85486b080871ff7ca Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 9 Dec 2019 10:02:04 -0500 Subject: [PATCH 185/297] Finalize functional tests --- .../apps/triggers_actions_ui/alerts.ts | 37 ++++++++++++++----- .../apps/triggers_actions_ui/connectors.ts | 4 +- .../page_objects/triggers_actions_ui_page.ts | 2 +- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts index 9b64f25ddfc9d1..37fb68d8a1df3c 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts @@ -16,6 +16,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const testSubjects = getService('testSubjects'); const pageObjects = getPageObjects(['common', 'triggersActionsUI', 'header']); const supertest = getService('supertest'); + const retry = getService('retry'); async function createAlert() { const { body: createdAlert } = await supertest @@ -52,7 +53,23 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { { name: createdAlert.name, tagsText: 'foo, bar', - alertType: 'test', + alertType: 'Test', + interval: '1m', + }, + ]); + }); + + it('should search for tags', async () => { + const createdAlert = await createAlert(); + + await pageObjects.triggersActionsUI.searchAlerts(`${createdAlert.name} foo`); + + const searchResults = await pageObjects.triggersActionsUI.getAlertsList(); + expect(searchResults).to.eql([ + { + name: createdAlert.name, + tagsText: 'foo, bar', + alertType: 'Test', interval: '1m', }, ]); @@ -158,7 +175,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(isChecked).to.eql('false'); }); - // TODO: wait for delete to finish it('should delete single alert', async () => { const createdAlert = await createAlert(); @@ -170,10 +186,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const deleteBtn = await testSubjects.find('deleteAlert'); await deleteBtn.click(); - await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); + retry.try(async () => { + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); - const searchResults = await pageObjects.triggersActionsUI.getAlertsList(); - expect(searchResults.length).to.eql(0); + const searchResults = await pageObjects.triggersActionsUI.getAlertsList(); + expect(searchResults.length).to.eql(0); + }); }); it('should mute all selection', async () => { @@ -290,7 +308,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(isChecked).to.eql('true'); }); - // TODO: wait for delete to finish it('should delete all selection', async () => { const createdAlert = await createAlert(); @@ -305,10 +322,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const deleteAllBtn = await testSubjects.find('deleteAll'); await deleteAllBtn.click(); - await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); + retry.try(async () => { + await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); - const searchResults = await pageObjects.triggersActionsUI.getAlertsList(); - expect(searchResults.length).to.eql(0); + const searchResults = await pageObjects.triggersActionsUI.getAlertsList(); + expect(searchResults.length).to.eql(0); + }); }); }); }; diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts index d25b56d449e151..8ec366c109fc55 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts @@ -81,7 +81,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const searchResultsBeforeEdit = await pageObjects.triggersActionsUI.getConnectorsList(); expect(searchResultsBeforeEdit.length).to.eql(1); - const editConnectorBtn = await testSubjects.find('edit'); + const editConnectorBtn = await find.byCssSelector( + '[data-test-subj="connectorsTableCell-name"] button' + ); await editConnectorBtn.click(); const nameInputToUpdate = await testSubjects.find('nameInput'); diff --git a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts index 91d3c68bfe7c5e..fbcd57b8ef95f3 100644 --- a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts +++ b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts @@ -63,7 +63,7 @@ export function TriggersActionsPageProvider({ getService }: FtrProviderContext) .map(row => { return { name: $(row) - .findTestSubject('lertsTableCell-name') + .findTestSubject('alertsTableCell-name') .find('.euiTableCellContent') .text(), tagsText: $(row) From ec9361454cf4296f9d0865b06992b7fd8894683a Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 9 Dec 2019 19:29:06 -0500 Subject: [PATCH 186/297] Support filtering alerts by action type --- .../public/application/lib/alert_api.test.ts | 24 ++++--- .../public/application/lib/alert_api.ts | 11 +++ .../components/action_type_filter.tsx | 72 +++++++++++++++++++ .../alerts_list/components/alerts_list.tsx | 39 ++++++++-- .../alerts_list/components/type_filter.tsx | 2 +- 5 files changed, 134 insertions(+), 14 deletions(-) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/action_type_filter.tsx diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.test.ts index e31cfe826d34f1..a5c68cebb2f918 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.test.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.test.ts @@ -59,6 +59,7 @@ describe('loadAlerts', () => { "/api/alert/_find", Object { "query": Object { + "default_search_operator": "AND", "filter": undefined, "page": 1, "per_page": 10, @@ -86,18 +87,19 @@ describe('loadAlerts', () => { "/api/alert/_find", Object { "query": Object { + "default_search_operator": "AND", "filter": undefined, "page": 1, "per_page": 10, "search": "apples", - "search_fields": "name", + "search_fields": "[\\"name\\",\\"tags\\"]", }, }, ] `); }); - test('should call find API with tagsFilter', async () => { + test('should call find API with actionTypesFilter', async () => { const resolvedValue = { page: 1, perPage: 10, @@ -108,7 +110,7 @@ describe('loadAlerts', () => { const result = await loadAlerts({ http, - tagsFilter: ['foo', 'bar'], + actionTypesFilter: ['foo', 'bar'], page: { index: 0, size: 10 }, }); expect(result).toEqual(resolvedValue); @@ -117,7 +119,8 @@ describe('loadAlerts', () => { "/api/alert/_find", Object { "query": Object { - "filter": "alert.attributes.tags:(foo and bar)", + "default_search_operator": "AND", + "filter": "(alert.attributes.actions:{ actionTypeId:foo } OR alert.attributes.actions:{ actionTypeId:bar })", "page": 1, "per_page": 10, "search": undefined, @@ -148,6 +151,7 @@ describe('loadAlerts', () => { "/api/alert/_find", Object { "query": Object { + "default_search_operator": "AND", "filter": "alert.attributes.alertTypeId:(foo or bar)", "page": 1, "per_page": 10, @@ -159,7 +163,7 @@ describe('loadAlerts', () => { `); }); - test('should call find API with tagsFilter and typesFilter', async () => { + test('should call find API with actionTypesFilter and typesFilter', async () => { const resolvedValue = { page: 1, perPage: 10, @@ -170,7 +174,7 @@ describe('loadAlerts', () => { const result = await loadAlerts({ http, - tagsFilter: ['foo', 'baz'], + actionTypesFilter: ['foo', 'baz'], typesFilter: ['foo', 'bar'], page: { index: 0, size: 10 }, }); @@ -180,7 +184,8 @@ describe('loadAlerts', () => { "/api/alert/_find", Object { "query": Object { - "filter": "alert.attributes.tags:(foo and baz) and alert.attributes.alertTypeId:(foo or bar)", + "default_search_operator": "AND", + "filter": "alert.attributes.alertTypeId:(foo or bar) and (alert.attributes.actions:{ actionTypeId:foo } OR alert.attributes.actions:{ actionTypeId:baz })", "page": 1, "per_page": 10, "search": undefined, @@ -213,11 +218,12 @@ describe('loadAlerts', () => { "/api/alert/_find", Object { "query": Object { - "filter": "alert.attributes.tags:(foo and baz) and alert.attributes.alertTypeId:(foo or bar)", + "default_search_operator": "AND", + "filter": "alert.attributes.alertTypeId:(foo or bar)", "page": 1, "per_page": 10, "search": "apples", - "search_fields": "name", + "search_fields": "[\\"name\\",\\"tags\\"]", }, }, ] diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.ts index d30bff1ce35cdd..56819c5faeb9fa 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.ts @@ -17,11 +17,13 @@ export async function loadAlerts({ page, searchText, typesFilter, + actionTypesFilter, }: { http: HttpServiceBase; page: { index: number; size: number }; searchText?: string; typesFilter?: string[]; + actionTypesFilter?: string[]; }): Promise<{ page: number; perPage: number; @@ -32,6 +34,15 @@ export async function loadAlerts({ if (typesFilter && typesFilter.length) { filters.push(`alert.attributes.alertTypeId:(${typesFilter.join(' or ')})`); } + if (actionTypesFilter && actionTypesFilter.length) { + filters.push( + [ + '(', + actionTypesFilter.map(id => `alert.attributes.actions:{ actionTypeId:${id} }`).join(' OR '), + ')', + ].join('') + ); + } return await http.get(`${BASE_ALERT_API_PATH}/_find`, { query: { page: page.index + 1, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/action_type_filter.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/action_type_filter.tsx new file mode 100644 index 00000000000000..1e5b411b33ba4c --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/action_type_filter.tsx @@ -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 React, { useEffect, useState } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiFilterGroup, EuiPopover, EuiFilterButton, EuiFilterSelectItem } from '@elastic/eui'; +import { ActionType } from '../../../../types'; + +interface ActionTypeFilterProps { + actionTypes: ActionType[]; + onChange?: (selectedActionTypeIds: string[]) => void; +} + +export const ActionTypeFilter: React.FunctionComponent = ({ + actionTypes, + onChange, +}: ActionTypeFilterProps) => { + const [selectedValues, setSelectedValues] = useState([]); + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + useEffect(() => { + if (onChange) { + onChange(selectedValues); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [selectedValues]); + + return ( + + setIsPopoverOpen(false)} + button={ + 0} + numActiveFilters={selectedValues.length} + numFilters={selectedValues.length} + onClick={() => setIsPopoverOpen(!isPopoverOpen)} + > + + + } + > +
+ {actionTypes.map(item => ( + { + const isPreviouslyChecked = selectedValues.includes(item.id); + if (isPreviouslyChecked) { + setSelectedValues(selectedValues.filter(val => val !== item.id)); + } else { + setSelectedValues(selectedValues.concat(item.id)); + } + }} + checked={selectedValues.includes(item.id) ? 'on' : undefined} + > + {item.name} + + ))} +
+
+
+ ); +}; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 3b975e2a875828..0c1af9c6b260f0 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -8,16 +8,18 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { Fragment, useEffect, useState } from 'react'; // @ts-ignore: EuiSearchBar not exported in TypeScript -import { EuiBasicTable, EuiButton, EuiSearchBar, EuiSpacer } from '@elastic/eui'; +import { EuiBasicTable, EuiButton, EuiFilterButton, EuiSearchBar, EuiSpacer } from '@elastic/eui'; import { AlertsContext } from '../../../context/alerts_context'; import { useAppDependencies } from '../../../app_dependencies'; -import { Alert, AlertTableItem, AlertTypeIndex, Pagination } from '../../../../types'; +import { ActionType, Alert, AlertTableItem, AlertTypeIndex, Pagination } from '../../../../types'; import { AlertAdd } from '../../alert_add'; import { BulkActionPopover } from './bulk_action_popover'; import { CollapsedItemActions } from './collapsed_item_actions'; import { TypeFilter } from './type_filter'; +import { ActionTypeFilter } from './action_type_filter'; import { loadAlerts, loadAlertTypes } from '../../../lib/alert_api'; +import { loadActionTypes } from '../../../lib/action_connector_api'; export const AlertsList: React.FunctionComponent = () => { const { @@ -26,6 +28,7 @@ export const AlertsList: React.FunctionComponent = () => { } = useAppDependencies(); const canDelete = capabilities.get().alerting.delete; + const [actionTypes, setActionTypes] = useState([]); const [alertTypesIndex, setAlertTypesIndex] = useState(undefined); const [alerts, setAlerts] = useState([]); const [data, setData] = useState([]); @@ -37,12 +40,13 @@ export const AlertsList: React.FunctionComponent = () => { const [page, setPage] = useState({ index: 0, size: 10 }); const [searchText, setSearchText] = useState(undefined); const [typesFilter, setTypesFilter] = useState([]); + const [actionTypesFilter, setActionTypesFilter] = useState([]); const [alertFlyoutVisible, setAlertFlyoutVisibility] = useState(false); useEffect(() => { loadAlertsData(); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [page, searchText, typesFilter]); + }, [page, searchText, typesFilter, actionTypesFilter]); useEffect(() => { (async () => { @@ -68,6 +72,23 @@ export const AlertsList: React.FunctionComponent = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + useEffect(() => { + (async () => { + try { + const result = await loadActionTypes({ http }); + setActionTypes(result); + } catch (e) { + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.unableToLoadActionTypesMessage', + { defaultMessage: 'Unable to load action types' } + ), + }); + } + })(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + useEffect(() => { // Avoid flickering before alert types load if (typeof alertTypesIndex === 'undefined') { @@ -86,7 +107,13 @@ export const AlertsList: React.FunctionComponent = () => { async function loadAlertsData() { setIsLoadingAlerts(true); try { - const alertsResponse = await loadAlerts({ http, page, searchText, typesFilter }); + const alertsResponse = await loadAlerts({ + http, + page, + searchText, + typesFilter, + actionTypesFilter, + }); setAlerts(alertsResponse.data); setTotalItemCount(alertsResponse.total); } catch (e) { @@ -186,6 +213,10 @@ export const AlertsList: React.FunctionComponent = () => { })) .sort((a, b) => a.name.localeCompare(b.name))} />, + setActionTypesFilter(ids)} + />, = ({

- ) + ); }; From 072c1711d61ba014f91a02e02d4278574f9badd6 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 9 Dec 2019 19:57:17 -0500 Subject: [PATCH 187/297] Rename plugin name for translations --- x-pack/.i18nrc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index a3103944c8f048..ede0ff1a43c101 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -4,7 +4,7 @@ "xpack.actions": "legacy/plugins/actions", "xpack.advancedUiActions": "plugins/advanced_ui_actions", "xpack.alerting": "legacy/plugins/alerting", - "xpack.alertingUI": "legacy/plugins/triggers_actions_ui", + "xpack.triggersActionsUI": "legacy/plugins/triggers_actions_ui", "xpack.apm": "legacy/plugins/apm", "xpack.beatsManagement": "legacy/plugins/beats_management", "xpack.canvas": "legacy/plugins/canvas", From a142566a64ec77a164237ba177c834d3566ffbfb Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 9 Dec 2019 20:06:10 -0500 Subject: [PATCH 188/297] Rename default breadcrumb title to alerts and actions --- .../np_ready/public/application/lib/doc_title.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.ts index e0778db099f793..385ad49fc84f4a 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.ts @@ -28,7 +28,7 @@ class DocTitleService { break; default: updatedTitle = i18n.translate('xpack.triggersActionsUI.home.breadcrumbTitle', { - defaultMessage: 'Alerting', + defaultMessage: 'Alerts and actions', }); } From ac30692505c59523ae1b7a2cdbb8e758da8a2f7e Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 9 Dec 2019 16:34:37 -0800 Subject: [PATCH 189/297] Added unit tests for connectors empty prompt, fixed api tests --- .../public/application/lib/alert_api.test.ts | 127 +++++----- .../action_connector_form.tsx | 57 +++-- .../actions_connectors_list.test.tsx | 230 +++++++++++++++++- .../components/actions_connectors_list.tsx | 23 +- 4 files changed, 331 insertions(+), 106 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.test.ts index a5c68cebb2f918..858c90258247ec 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.test.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.test.ts @@ -83,19 +83,19 @@ describe('loadAlerts', () => { const result = await loadAlerts({ http, searchText: 'apples', page: { index: 0, size: 10 } }); expect(result).toEqual(resolvedValue); expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "/api/alert/_find", - Object { - "query": Object { - "default_search_operator": "AND", - "filter": undefined, - "page": 1, - "per_page": 10, - "search": "apples", - "search_fields": "[\\"name\\",\\"tags\\"]", - }, + Array [ + "/api/alert/_find", + Object { + "query": Object { + "default_search_operator": "AND", + "filter": undefined, + "page": 1, + "per_page": 10, + "search": "apples", + "search_fields": "[\\"name\\",\\"tags\\"]", }, - ] + }, + ] `); }); @@ -110,24 +110,24 @@ describe('loadAlerts', () => { const result = await loadAlerts({ http, - actionTypesFilter: ['foo', 'bar'], + searchText: 'foo', page: { index: 0, size: 10 }, }); expect(result).toEqual(resolvedValue); expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "/api/alert/_find", - Object { - "query": Object { - "default_search_operator": "AND", - "filter": "(alert.attributes.actions:{ actionTypeId:foo } OR alert.attributes.actions:{ actionTypeId:bar })", - "page": 1, - "per_page": 10, - "search": undefined, - "search_fields": undefined, - }, + Array [ + "/api/alert/_find", + Object { + "query": Object { + "default_search_operator": "AND", + "filter": undefined, + "page": 1, + "per_page": 10, + "search": "foo", + "search_fields": "[\\"name\\",\\"tags\\"]", }, - ] + }, + ] `); }); @@ -147,19 +147,19 @@ describe('loadAlerts', () => { }); expect(result).toEqual(resolvedValue); expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "/api/alert/_find", - Object { - "query": Object { - "default_search_operator": "AND", - "filter": "alert.attributes.alertTypeId:(foo or bar)", - "page": 1, - "per_page": 10, - "search": undefined, - "search_fields": undefined, - }, + Array [ + "/api/alert/_find", + Object { + "query": Object { + "default_search_operator": "AND", + "filter": "alert.attributes.alertTypeId:(foo or bar)", + "page": 1, + "per_page": 10, + "search": undefined, + "search_fields": undefined, }, - ] + }, + ] `); }); @@ -174,25 +174,25 @@ describe('loadAlerts', () => { const result = await loadAlerts({ http, - actionTypesFilter: ['foo', 'baz'], + searchText: 'baz', typesFilter: ['foo', 'bar'], page: { index: 0, size: 10 }, }); expect(result).toEqual(resolvedValue); expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "/api/alert/_find", - Object { - "query": Object { - "default_search_operator": "AND", - "filter": "alert.attributes.alertTypeId:(foo or bar) and (alert.attributes.actions:{ actionTypeId:foo } OR alert.attributes.actions:{ actionTypeId:baz })", - "page": 1, - "per_page": 10, - "search": undefined, - "search_fields": undefined, - }, + Array [ + "/api/alert/_find", + Object { + "query": Object { + "default_search_operator": "AND", + "filter": "alert.attributes.alertTypeId:(foo or bar)", + "page": 1, + "per_page": 10, + "search": "baz", + "search_fields": "[\\"name\\",\\"tags\\"]", }, - ] + }, + ] `); }); @@ -207,26 +207,25 @@ describe('loadAlerts', () => { const result = await loadAlerts({ http, - searchText: 'apples', - tagsFilter: ['foo', 'baz'], + searchText: 'apples, foo, baz', typesFilter: ['foo', 'bar'], page: { index: 0, size: 10 }, }); expect(result).toEqual(resolvedValue); expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` - Array [ - "/api/alert/_find", - Object { - "query": Object { - "default_search_operator": "AND", - "filter": "alert.attributes.alertTypeId:(foo or bar)", - "page": 1, - "per_page": 10, - "search": "apples", - "search_fields": "[\\"name\\",\\"tags\\"]", - }, + Array [ + "/api/alert/_find", + Object { + "query": Object { + "default_search_operator": "AND", + "filter": "alert.attributes.alertTypeId:(foo or bar)", + "page": 1, + "per_page": 10, + "search": "apples, foo, baz", + "search_fields": "[\\"name\\",\\"tags\\"]", }, - ] + }, + ] `); }); }); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index 7acd2c6274a766..df2d353195d4c2 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -40,11 +40,12 @@ export const ActionConnectorForm = ({ }: ActionConnectorProps) => { const { core: { http }, - plugins: { toastNotifications }, + plugins: { capabilities, toastNotifications }, actionTypeRegistry, } = useAppDependencies(); const { reloadConnectors } = useContext(ActionsConnectorsContext); + const canSave = capabilities.get().actions.save; // hooks const [{ connector }, dispatch] = useReducer(connectorReducer, { connector: initialAction }); @@ -241,32 +242,34 @@ export const ActionConnectorForm = ({ )} - - { - setIsSaving(true); - const savedAction = await onActionConnectorSave(); - setIsSaving(false); - if (savedAction && savedAction.error) { - return setServerError(savedAction.error); - } - setFlyoutVisibility(false); - reloadConnectors(); - }} - > - - - + {canSave ? ( + + { + setIsSaving(true); + const savedAction = await onActionConnectorSave(); + setIsSaving(false); + if (savedAction && savedAction.error) { + return setServerError(savedAction.error); + } + setFlyoutVisibility(false); + reloadConnectors(); + }} + > + + + + ) : null} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx index 095c4604a44364..8da748c53b7182 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx @@ -10,13 +10,87 @@ import { setAppDependencies } from '../../../app_dependencies'; import { coreMock } from '../../../../../../../../../../src/core/public/mocks'; import { ReactWrapper } from 'enzyme'; import { act } from 'react-dom/test-utils'; +import { actionTypeRegistryMock } from '../../../action_type_registry.mock'; jest.mock('../../../context/actions_connectors_context'); jest.mock('../../../lib/action_connector_api', () => ({ loadAllActions: jest.fn(), loadActionTypes: jest.fn(), })); -describe('actions_connectors_list', () => { +const actionTypeRegistry = actionTypeRegistryMock.create(); + +describe('actions_connectors_list component empty', () => { + let wrapper: ReactWrapper; + + beforeEach(async () => { + const { loadAllActions, loadActionTypes } = jest.requireMock( + '../../../lib/action_connector_api' + ); + loadAllActions.mockResolvedValueOnce({ + page: 1, + perPage: 10000, + total: 0, + data: [], + }); + loadActionTypes.mockResolvedValueOnce([ + { + id: 'test', + name: 'Test', + }, + { + id: 'test2', + name: 'Test2', + }, + ]); + const deps = { + core: coreMock.createStart(), + plugins: { + capabilities: { + get() { + return { + actions: { + delete: true, + save: true, + show: true, + }, + }; + }, + }, + } as any, + actionTypeRegistry: actionTypeRegistry as any, + alertTypeRegistry: {} as any, + }; + const AppDependenciesProvider = setAppDependencies(deps); + actionTypeRegistry.has.mockReturnValue(true); + + await act(async () => { + wrapper = mountWithIntl( + + + + ); + }); + + await waitForRender(wrapper); + }); + + it('renders empty prompt', () => { + expect(wrapper.find('EuiEmptyPrompt')).toHaveLength(1); + expect( + wrapper.find('[data-test-subj="createFirstActionButton"]').find('EuiButton') + ).toHaveLength(1); + }); + + test('if click create button should render ConnectorAddFlyout', () => { + wrapper + .find('[data-test-subj="createFirstActionButton"]') + .first() + .simulate('click'); + expect(wrapper.find('ConnectorAddFlyout')).toHaveLength(1); + }); +}); + +describe('actions_connectors_list component with items', () => { let wrapper: ReactWrapper; beforeEach(async () => { @@ -96,20 +170,160 @@ describe('actions_connectors_list', () => { expect(wrapper.find('EuiTableRow')).toHaveLength(2); }); - it('select item for edit should render ConnectorEditFlyout', () => { + test('if select item for edit should render ConnectorEditFlyout', () => { wrapper .find('[data-test-subj="edit1"]') .first() .simulate('click'); expect(wrapper.find('ConnectorEditFlyout')).toHaveLength(1); }); +}); - it('change capability', () => { - wrapper - .find('[data-test-subj="edit1"]') - .first() - .simulate('click'); - expect(wrapper.find('ConnectorEditFlyout')).toHaveLength(1); +describe('actions_connectors_list component empty with show only capability', () => { + let wrapper: ReactWrapper; + + beforeEach(async () => { + const { loadAllActions, loadActionTypes } = jest.requireMock( + '../../../lib/action_connector_api' + ); + loadAllActions.mockResolvedValueOnce({ + page: 1, + perPage: 10000, + total: 0, + data: [], + }); + loadActionTypes.mockResolvedValueOnce([ + { + id: 'test', + name: 'Test', + }, + { + id: 'test2', + name: 'Test2', + }, + ]); + const deps = { + core: coreMock.createStart(), + plugins: { + capabilities: { + get() { + return { + actions: { + delete: false, + save: false, + show: true, + }, + }; + }, + }, + } as any, + actionTypeRegistry: { + get() { + return null; + }, + } as any, + alertTypeRegistry: {} as any, + }; + const AppDependenciesProvider = setAppDependencies(deps); + + await act(async () => { + wrapper = mountWithIntl( + + + + ); + }); + + await waitForRender(wrapper); + }); + + it('renders no permissions to create connector', () => { + expect(wrapper.find('[defaultMessage="No permissions to create connector"]')).toHaveLength(1); + expect(wrapper.find('[data-test-subj="createActionButton"]')).toHaveLength(0); + }); +}); + +describe('actions_connectors_list with show only capability', () => { + let wrapper: ReactWrapper; + + beforeEach(async () => { + const { loadAllActions, loadActionTypes } = jest.requireMock( + '../../../lib/action_connector_api' + ); + loadAllActions.mockResolvedValueOnce({ + page: 1, + perPage: 10000, + total: 2, + data: [ + { + id: '1', + actionTypeId: 'test', + description: 'My test', + referencedByCount: 1, + config: {}, + }, + { + id: '2', + actionTypeId: 'test2', + description: 'My test 2', + referencedByCount: 1, + config: {}, + }, + ], + }); + loadActionTypes.mockResolvedValueOnce([ + { + id: 'test', + name: 'Test', + }, + { + id: 'test2', + name: 'Test2', + }, + ]); + const deps = { + core: coreMock.createStart(), + plugins: { + capabilities: { + get() { + return { + actions: { + delete: false, + save: false, + show: true, + }, + }; + }, + }, + } as any, + actionTypeRegistry: { + get() { + return null; + }, + } as any, + alertTypeRegistry: {} as any, + }; + const AppDependenciesProvider = setAppDependencies(deps); + + await act(async () => { + wrapper = mountWithIntl( + + + + ); + }); + + await waitForRender(wrapper); + }); + + it('renders table of connectors with delete button disabled', () => { + expect(wrapper.find('EuiInMemoryTable')).toHaveLength(1); + expect(wrapper.find('EuiTableRow')).toHaveLength(2); + wrapper.find('EuiTableRow').forEach(elem => { + const deleteButton = elem.find('[data-test-subj="deleteConnector"]').first(); + expect(deleteButton).toBeTruthy(); + expect(deleteButton.prop('isDisabled')).toBeTruthy(); + }); }); }); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index 15a3fd5f810d39..582bd5fb56742a 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -256,11 +256,13 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { data-test-subj="actionsTable" pagination={true} selection={ - canDelete && { - onSelectionChange(updatedSelectedItemsList: ActionConnectorTableItem[]) { - setSelectedItems(updatedSelectedItemsList); - }, - } + canDelete + ? { + onSelectionChange(updatedSelectedItemsList: ActionConnectorTableItem[]) { + setSelectedItems(updatedSelectedItemsList); + }, + } + : null } search={{ filters: [ @@ -320,7 +322,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { ], }} /> - ) : ( + ) : canSave ? ( @@ -348,7 +350,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { } actions={ { } /> + ) : ( +

+ +

)} {editedConnectorItem ? : null} From b1a398aa679aa3f56027f99d7db3d730b351d605 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 9 Dec 2019 18:33:29 -0800 Subject: [PATCH 190/297] Added unit test for select action type menu for create connector; Fixed update selected connector for edit form --- .../action_connector_form.tsx | 17 ++-- .../action_type_menu.test.tsx | 87 +++++++++++++++++++ .../action_type_menu.tsx | 7 +- .../connector_add_flyout.tsx | 10 ++- .../connector_edit_flyout.tsx | 2 +- 5 files changed, 110 insertions(+), 13 deletions(-) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.test.tsx diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index df2d353195d4c2..bd0f08c931c8f5 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -28,13 +28,13 @@ import { ActionsConnectorsContext } from '../../context/actions_connectors_conte import { ActionConnector, IErrorObject } from '../../../types'; interface ActionConnectorProps { - initialAction: any; + initialConnector: any; actionTypeName: string; setFlyoutVisibility: React.Dispatch>; } export const ActionConnectorForm = ({ - initialAction, + initialConnector, actionTypeName, setFlyoutVisibility, }: ActionConnectorProps) => { @@ -48,12 +48,16 @@ export const ActionConnectorForm = ({ const canSave = capabilities.get().actions.save; // hooks - const [{ connector }, dispatch] = useReducer(connectorReducer, { connector: initialAction }); + const [{ connector }, dispatch] = useReducer(connectorReducer, { connector: initialConnector }); const setActionProperty = (key: string, value: any) => { dispatch({ command: { type: 'setProperty' }, payload: { key, value } }); }; + const setConnector = (key: string, value: any) => { + dispatch({ command: { type: 'setConnector' }, payload: { key, value } }); + }; + const setActionConfigProperty = (key: string, value: any) => { dispatch({ command: { type: 'setConfigProperty' }, payload: { key, value } }); }; @@ -63,15 +67,16 @@ export const ActionConnectorForm = ({ }; useEffect(() => { + setConnector('connector', initialConnector); setServerError(null); - }, []); + }, [initialConnector]); const [isSaving, setIsSaving] = useState(false); const [serverError, setServerError] = useState<{ body: { message: string; error: string }; } | null>(null); - const actionTypeRegisterd = actionTypeRegistry.get(initialAction.actionTypeId); + const actionTypeRegisterd = actionTypeRegistry.get(initialConnector.actionTypeId); if (actionTypeRegisterd === null) return null; function validateBaseProperties(actionObject: ActionConnector) { @@ -191,7 +196,7 @@ export const ActionConnectorForm = ({ editActionSecrets={setActionSecretsProperty} hasErrors={hasErrors} > - {initialAction.actionTypeId === null ? ( + {initialConnector.actionTypeId === null ? ( { + let AppDependenciesProvider: React.ProviderExoticComponent>; + let deps: any; + + beforeEach(() => { + deps = { + core: coreMock.createStart(), + plugins: { + capabilities: { + get() { + return { + actions: { + delete: true, + save: true, + show: true, + }, + }; + }, + }, + } as any, + actionTypeRegistry: actionTypeRegistry as any, + alertTypeRegistry: {} as any, + }; + AppDependenciesProvider = setAppDependencies(deps); + }); + + it('renders action type menu with proper EuiCards for registered action types', () => { + const onActionTypeChange = jest.fn(); + + const wrapper = mountWithIntl( + + {}, + editFlyoutVisible: false, + setEditFlyoutVisibility: state => {}, + actionTypesIndex: { + 'first-action-type': { id: 'first-action-type', name: 'first' }, + 'second-action-type': { id: 'second-action-type', name: 'second' }, + }, + reloadConnectors: () => { + return new Promise(() => {}); + }, + }} + > + + + + ); + const actionType = { + id: 'my-action-type', + iconClass: 'test', + selectMessage: 'test', + validateConnector: (): ValidationResult => { + return { errors: {} }; + }, + validateParams: (): ValidationResult => { + const validationResult = { errors: {} }; + return validationResult; + }, + actionConnectorFields: null, + actionParamsFields: null, + }; + actionTypeRegistry.get.mockReturnValueOnce(actionType); + + expect(wrapper.find('[data-test-subj="first-action-type-card"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="second-action-type-card"]').exists()).toBeTruthy(); + }); +}); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx index b8b9f94bdb9ac7..2db9763394ed9c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx @@ -20,15 +20,16 @@ import { ActionsConnectorsContext } from '../../context/actions_connectors_conte import { useAppDependencies } from '../../app_dependencies'; interface Props { - setActionType: React.Dispatch>; + onActionTypeChange: (actionType: ActionType) => void; } -export const ActionTypeMenu = ({ setActionType }: Props) => { +export const ActionTypeMenu = ({ onActionTypeChange }: Props) => { const { actionTypeRegistry } = useAppDependencies(); const { actionTypesIndex, setAddFlyoutVisibility } = useContext(ActionsConnectorsContext); if (!actionTypesIndex) { return null; } + const actionTypes = Object.entries(actionTypesIndex) .filter(([index]) => actionTypeRegistry.has(index)) .map(([index, actionType]) => { @@ -50,7 +51,7 @@ export const ActionTypeMenu = ({ setActionType }: Props) => { icon={} title={item.name} description={item.selectMessage} - onClick={() => setActionType(item.actionType)} + onClick={() => onActionTypeChange(item.actionType)} /> ); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx index c9ea55ceed68a1..6158a0722b2c11 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx @@ -36,18 +36,22 @@ export const ConnectorAddFlyout = () => { return null; } + function onActionTypeChange(newActionType: ActionType) { + setActionType(newActionType); + } + let currentForm; let actionTypeModel; if (!actionType) { - currentForm = ; + currentForm = ; } else { actionTypeModel = actionTypeRegistry.get(actionType.id); - const initialAction = { actionTypeId: actionType.id, config: {}, secrets: {} }; + const initialConnector = { actionTypeId: actionType.id, config: {}, secrets: {} }; currentForm = ( ); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx index e58ba2f7bac360..80d240b40ebe13 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx @@ -55,7 +55,7 @@ export const ConnectorEditFlyout = ({ connector }: ConnectorEditProps) => {
Date: Mon, 9 Dec 2019 20:58:08 -0800 Subject: [PATCH 191/297] Added unit test for edit connector flyout --- .../action_connector_form.tsx | 2 +- .../connector_edit_flyout.test.tsx | 96 +++++++++++++++++++ 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index bd0f08c931c8f5..5330219dc44a40 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -77,7 +77,7 @@ export const ActionConnectorForm = ({ } | null>(null); const actionTypeRegisterd = actionTypeRegistry.get(initialConnector.actionTypeId); - if (actionTypeRegisterd === null) return null; + if (!actionTypeRegisterd) return null; function validateBaseProperties(actionObject: ActionConnector) { const validationResult = { errors: {} }; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx new file mode 100644 index 00000000000000..5f9d4f058496f3 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx @@ -0,0 +1,96 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import * as React from 'react'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { setAppDependencies } from '../../app_dependencies'; +import { coreMock } from '../../../../../../../../../src/core/public/mocks'; +import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; +import { actionTypeRegistryMock } from '../../action_type_registry.mock'; +import { ValidationResult } from '../../../types'; +import { AppDependencies } from '../../../../../public/shim'; +import { ConnectorEditFlyout } from './connector_edit_flyout'; +jest.mock('../../context/actions_connectors_context'); +const actionTypeRegistry = actionTypeRegistryMock.create(); +let AppDependenciesProvider: React.ProviderExoticComponent>; +let deps: any; + +describe('connector_edit_flyout', () => { + beforeEach(() => { + deps = { + core: coreMock.createStart(), + plugins: { + capabilities: { + get() { + return { + actions: { + delete: true, + save: true, + show: true, + }, + }; + }, + }, + } as any, + actionTypeRegistry: actionTypeRegistry as any, + alertTypeRegistry: {} as any, + }; + AppDependenciesProvider = setAppDependencies(deps); + }); + + test('if input connector render correct in the edit form', () => { + const connector = { + secrets: {}, + id: 'test', + actionTypeId: 'test-action-type-id', + actionType: 'test-action-type-name', + name: 'action-connector', + referencedByCount: 0, + config: {}, + }; + + const actionType = { + id: 'test-action-type-id', + iconClass: 'test', + selectMessage: 'test', + validateConnector: (): ValidationResult => { + return { errors: {} }; + }, + validateParams: (): ValidationResult => { + const validationResult = { errors: {} }; + return validationResult; + }, + actionConnectorFields: null, + actionParamsFields: null, + }; + actionTypeRegistry.get.mockReturnValue(actionType); + actionTypeRegistry.has.mockReturnValue(true); + + const wrapper = mountWithIntl( + + {}, + editFlyoutVisible: true, + setEditFlyoutVisibility: state => {}, + actionTypesIndex: { + 'test-action-type-id': { id: 'test-action-type-id', name: 'test' }, + }, + reloadConnectors: () => { + return new Promise(() => {}); + }, + }} + > + + + + ); + + const connectorNameField = wrapper.find('[data-test-subj="nameInput"]'); + expect(connectorNameField.exists()).toBeTruthy(); + expect(connectorNameField.first().prop('value')).toBe('action-connector'); + }); +}); From 4a7af57966f7c1eaf52352d11c01f07816db4588 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 9 Dec 2019 21:37:40 -0800 Subject: [PATCH 192/297] Added alerts list unit tests --- .../components/alerts_list.test.tsx | 313 ++++++++++++++++++ .../alerts_list/components/alerts_list.tsx | 12 +- 2 files changed, 320 insertions(+), 5 deletions(-) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx new file mode 100644 index 00000000000000..59f7a202285d12 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx @@ -0,0 +1,313 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under 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 React from 'react'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { setAppDependencies } from '../../../app_dependencies'; +import { coreMock } from '../../../../../../../../../../src/core/public/mocks'; +import { ReactWrapper } from 'enzyme'; +import { act } from 'react-dom/test-utils'; +import { actionTypeRegistryMock } from '../../../action_type_registry.mock'; +import { alertTypeRegistryMock } from '../../../alert_type_registry.mock'; +import { AlertsList } from './alerts_list'; +jest.mock('../../../context/actions_connectors_context'); +jest.mock('../../../lib/action_connector_api', () => ({ + loadAlerts: jest.fn(), + loadActionTypes: jest.fn(), +})); + +const actionTypeRegistry = actionTypeRegistryMock.create(); +const alertTypeRegistry = alertTypeRegistryMock.create(); + +describe('alerts_list component empty', () => { + let wrapper: ReactWrapper; + + beforeEach(async () => { + const { loadAlerts, loadActionTypes } = jest.requireMock('../../../lib/alert_api'); + loadAlerts.mockResolvedValueOnce({ + page: 1, + perPage: 10000, + total: 0, + data: [], + }); + loadActionTypes.mockResolvedValueOnce([ + { + id: 'test', + name: 'Test', + }, + { + id: 'test2', + name: 'Test2', + }, + ]); + const deps = { + core: coreMock.createStart(), + plugins: { + capabilities: { + get() { + return { + alerts: { + delete: true, + save: true, + show: true, + }, + }; + }, + }, + } as any, + actionTypeRegistry: actionTypeRegistry as any, + alertTypeRegistry: alertTypeRegistry as any, + }; + const AppDependenciesProvider = setAppDependencies(deps); + actionTypeRegistry.has.mockReturnValue(true); + + await act(async () => { + wrapper = mountWithIntl( + + + + ); + }); + + await waitForRender(wrapper); + }); + + it('renders empty list', () => { + expect(wrapper.find('[data-test-subj="createAlertButton"]').find('EuiButton')).toHaveLength(1); + }); + + test('if click create button should render AlertAdd', () => { + wrapper + .find('[data-test-subj="createAlertButton"]') + .first() + .simulate('click'); + expect(wrapper.find('AlertAdd')).toHaveLength(1); + }); +}); + +describe('alerts_list component with items', () => { + let wrapper: ReactWrapper; + + beforeEach(async () => { + const { loadAlerts, loadActionTypes } = jest.requireMock('../../../lib/alert_api'); + loadAlerts.mockResolvedValueOnce({ + page: 1, + perPage: 10000, + total: 2, + data: [ + { + id: '1', + actionTypeId: 'test', + description: 'My test', + referencedByCount: 1, + config: {}, + }, + { + id: '2', + actionTypeId: 'test2', + description: 'My test 2', + referencedByCount: 1, + config: {}, + }, + ], + }); + loadActionTypes.mockResolvedValueOnce([ + { + id: 'test', + name: 'Test', + }, + { + id: 'test2', + name: 'Test2', + }, + ]); + const deps = { + core: coreMock.createStart(), + plugins: { + capabilities: { + get() { + return { + actions: { + delete: true, + save: true, + show: true, + }, + }; + }, + }, + } as any, + actionTypeRegistry: { + get() { + return null; + }, + } as any, + alertTypeRegistry: {} as any, + }; + const AppDependenciesProvider = setAppDependencies(deps); + + await act(async () => { + wrapper = mountWithIntl( + + + + ); + }); + + await waitForRender(wrapper); + + expect(loadAlerts).toHaveBeenCalled(); + }); + + it('renders table of connectors', () => { + expect(wrapper.find('EuiInMemoryTable')).toHaveLength(1); + expect(wrapper.find('EuiTableRow')).toHaveLength(2); + }); +}); + +describe('alerts_list component empty with show only capability', () => { + let wrapper: ReactWrapper; + + beforeEach(async () => { + const { loadAlerts, loadActionTypes } = jest.requireMock('../../../lib/alert_api'); + loadAlerts.mockResolvedValueOnce({ + page: 1, + perPage: 10000, + total: 0, + data: [], + }); + loadActionTypes.mockResolvedValueOnce([ + { + id: 'test', + name: 'Test', + }, + { + id: 'test2', + name: 'Test2', + }, + ]); + const deps = { + core: coreMock.createStart(), + plugins: { + capabilities: { + get() { + return { + alerts: { + delete: false, + save: false, + show: true, + }, + }; + }, + }, + } as any, + actionTypeRegistry: { + get() { + return null; + }, + } as any, + alertTypeRegistry: {} as any, + }; + const AppDependenciesProvider = setAppDependencies(deps); + + await act(async () => { + wrapper = mountWithIntl( + + + + ); + }); + + await waitForRender(wrapper); + }); + + it('renders no permissions to create connector', () => { + expect(wrapper.find('[defaultMessage="No permissions to create connector"]')).toHaveLength(1); + expect(wrapper.find('[data-test-subj="createActionButton"]')).toHaveLength(0); + }); +}); + +describe('alerts_list with show only capability', () => { + let wrapper: ReactWrapper; + + beforeEach(async () => { + const { loadAlerts, loadActionTypes } = jest.requireMock('../../../lib/alert_api'); + loadAlerts.mockResolvedValueOnce({ + page: 1, + perPage: 10000, + total: 2, + data: [ + { + id: '1', + actionTypeId: 'test', + description: 'My test', + referencedByCount: 1, + config: {}, + }, + { + id: '2', + actionTypeId: 'test2', + description: 'My test 2', + referencedByCount: 1, + config: {}, + }, + ], + }); + loadActionTypes.mockResolvedValueOnce([ + { + id: 'test', + name: 'Test', + }, + { + id: 'test2', + name: 'Test2', + }, + ]); + const deps = { + core: coreMock.createStart(), + plugins: { + capabilities: { + get() { + return { + alerts: { + delete: false, + save: false, + show: true, + }, + }; + }, + }, + } as any, + actionTypeRegistry: actionTypeRegistry as any, + alertTypeRegistry: alertTypeRegistry as any, + }; + const AppDependenciesProvider = setAppDependencies(deps); + + await act(async () => { + wrapper = mountWithIntl( + + + + ); + }); + + await waitForRender(wrapper); + }); + + it('renders table of alerts with delete button disabled', () => { + expect(wrapper.find('EuiInMemoryTable')).toHaveLength(1); + expect(wrapper.find('EuiTableRow')).toHaveLength(2); + wrapper.find('EuiTableRow').forEach(elem => { + const deleteButton = elem.find('[data-test-subj="deleteAlert"]').first(); + expect(deleteButton).toBeTruthy(); + expect(deleteButton.prop('isDisabled')).toBeTruthy(); + }); + }); +}); + +async function waitForRender(wrapper: ReactWrapper) { + await Promise.resolve(); + await Promise.resolve(); + wrapper.update(); +} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 0c1af9c6b260f0..5c98d329e62a3b 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -254,11 +254,13 @@ export const AlertsList: React.FunctionComponent = () => { totalItemCount, }} selection={ - canDelete && { - onSelectionChange(updatedSelectedItemsList: AlertTableItem[]) { - setSelectedIds(updatedSelectedItemsList.map(item => item.id)); - }, - } + canDelete + ? { + onSelectionChange(updatedSelectedItemsList: AlertTableItem[]) { + setSelectedIds(updatedSelectedItemsList.map(item => item.id)); + }, + } + : null } onChange={({ page: changedPage }: { page: Pagination }) => { setPage(changedPage); From 0c4bbe8c2645549fde94cc43d3c2e090848054df Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 9 Dec 2019 21:39:59 -0800 Subject: [PATCH 193/297] Added connector form unit tests --- .../action_connector_form.test.tsx | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx new file mode 100644 index 00000000000000..1469b092fa37d9 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx @@ -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 * as React from 'react'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { setAppDependencies } from '../../app_dependencies'; +import { coreMock } from '../../../../../../../../../src/core/public/mocks'; +import { ReactWrapper } from 'enzyme'; +import { act } from 'react-dom/test-utils'; +import { ConnectorAddFlyout } from './connector_add_flyout'; +import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; +import { actionTypeRegistryMock } from '../../action_type_registry.mock'; +import { ValidationResult } from '../../../types'; +jest.mock('../../context/actions_connectors_context'); +const actionTypeRegistry = actionTypeRegistryMock.create(); + +describe('action_connector_form', () => { + let wrapper: ReactWrapper; + + beforeEach(async () => { + const deps = { + core: coreMock.createStart(), + plugins: { + capabilities: { + get() { + return { + actions: { + delete: true, + save: true, + show: true, + }, + }; + }, + }, + } as any, + actionTypeRegistry: actionTypeRegistry as any, + alertTypeRegistry: {} as any, + }; + const AppDependenciesProvider = setAppDependencies(deps); + + await act(async () => { + wrapper = mountWithIntl( + + {}, + editFlyoutVisible: false, + setEditFlyoutVisibility: state => {}, + actionTypesIndex: { 'my-action-type': { id: 'my-action-type', name: 'test' } }, + reloadConnectors: () => { + return new Promise(() => {}); + }, + }} + > + + + + ); + }); + + await waitForRender(wrapper); + }); + + it('renders action_connector_form', () => { + const actionType = { + id: 'my-action-type', + iconClass: 'test', + selectMessage: 'test', + validateConnector: (): ValidationResult => { + return { errors: {} }; + }, + validateParams: (): ValidationResult => { + const validationResult = { errors: {} }; + return validationResult; + }, + actionConnectorFields: null, + actionParamsFields: null, + }; + actionTypeRegistry.get.mockReturnValueOnce(actionType); + actionTypeRegistry.has.mockReturnValue(true); + + const connectorNameField = wrapper.find('[data-test-subj="nameInput"]'); + expect(connectorNameField.exists()).toBeTruthy(); + expect(connectorNameField.first().prop('value')).toBe('action-connector'); + }); +}); + +async function waitForRender(wrapper: ReactWrapper) { + await Promise.resolve(); + await Promise.resolve(); + wrapper.update(); +} From e4dfa1acf8b2a50f76ef8b4ad60b12b430aecf97 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 9 Dec 2019 21:49:35 -0800 Subject: [PATCH 194/297] Added connector reducer unit tests --- .../connector_reducer.test.ts | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_reducer.test.ts diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_reducer.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_reducer.test.ts new file mode 100644 index 00000000000000..6c8a13008ab8ff --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_reducer.test.ts @@ -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 { connectorReducer } from './connector_reducer'; + +describe('connector reducer', () => { + test('if property name was changed', () => { + const connector = { + secrets: {}, + id: 'test', + actionTypeId: 'test-action-type-id', + actionType: 'test-action-type-name', + name: 'action-connector', + referencedByCount: 0, + config: {}, + }; + + const updatedConnector = connectorReducer( + { connector }, + { + command: 'setProperty', + payload: { + key: 'name', + value: 'new name', + }, + } + ); + expect(updatedConnector.connector.name).toBe('new name'); + }); + + test('if property config property was added', () => { + const connector = { + secrets: {}, + id: 'test', + actionTypeId: 'test-action-type-id', + actionType: 'test-action-type-name', + name: 'action-connector', + referencedByCount: 0, + config: {}, + }; + + const updatedConnector = connectorReducer( + { connector }, + { + command: 'setConfigProperty', + payload: { + key: 'test', + value: 'new test property', + }, + } + ); + expect(updatedConnector.connector.test).toBe('new test property'); + }); +}); From 1e5918245f823286b1796e99ac3d37b56774143f Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 10 Dec 2019 13:07:30 -0800 Subject: [PATCH 195/297] Fixed some failing unit tests --- .../action_connector_form.test.tsx | 54 +++++++------ .../connector_reducer.test.ts | 75 ++++++++++++++----- 2 files changed, 86 insertions(+), 43 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx index 1469b092fa37d9..7ce9a822e2c62d 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx @@ -9,10 +9,10 @@ import { setAppDependencies } from '../../app_dependencies'; import { coreMock } from '../../../../../../../../../src/core/public/mocks'; import { ReactWrapper } from 'enzyme'; import { act } from 'react-dom/test-utils'; -import { ConnectorAddFlyout } from './connector_add_flyout'; import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; import { actionTypeRegistryMock } from '../../action_type_registry.mock'; import { ValidationResult } from '../../../types'; +import { ActionConnectorForm } from './action_connector_form'; jest.mock('../../context/actions_connectors_context'); const actionTypeRegistry = actionTypeRegistryMock.create(); @@ -40,22 +40,47 @@ describe('action_connector_form', () => { }; const AppDependenciesProvider = setAppDependencies(deps); + const actionType = { + id: 'my-action-type', + iconClass: 'test', + selectMessage: 'test', + validateConnector: (): ValidationResult => { + return { errors: {} }; + }, + validateParams: (): ValidationResult => { + const validationResult = { errors: {} }; + return validationResult; + }, + actionConnectorFields: null, + actionParamsFields: null, + }; + actionTypeRegistry.get.mockReturnValue(actionType); + actionTypeRegistry.has.mockReturnValue(true); + + const initialConnector = { actionTypeId: actionType.id, config: {}, secrets: {} }; + await act(async () => { wrapper = mountWithIntl( {}, + setAddFlyoutVisibility: () => {}, editFlyoutVisible: false, - setEditFlyoutVisibility: state => {}, - actionTypesIndex: { 'my-action-type': { id: 'my-action-type', name: 'test' } }, + setEditFlyoutVisibility: () => {}, + actionTypesIndex: { + 'my-action-type': { id: 'my-action-type', name: 'my-action-type-name' }, + }, reloadConnectors: () => { return new Promise(() => {}); }, }} > - + {}} + /> ); @@ -65,26 +90,9 @@ describe('action_connector_form', () => { }); it('renders action_connector_form', () => { - const actionType = { - id: 'my-action-type', - iconClass: 'test', - selectMessage: 'test', - validateConnector: (): ValidationResult => { - return { errors: {} }; - }, - validateParams: (): ValidationResult => { - const validationResult = { errors: {} }; - return validationResult; - }, - actionConnectorFields: null, - actionParamsFields: null, - }; - actionTypeRegistry.get.mockReturnValueOnce(actionType); - actionTypeRegistry.has.mockReturnValue(true); - const connectorNameField = wrapper.find('[data-test-subj="nameInput"]'); expect(connectorNameField.exists()).toBeTruthy(); - expect(connectorNameField.first().prop('value')).toBe('action-connector'); + expect(connectorNameField.first().prop('value')).toBe(''); }); }); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_reducer.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_reducer.test.ts index 6c8a13008ab8ff..de7f6a0b550f73 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_reducer.test.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_reducer.test.ts @@ -4,23 +4,26 @@ * you may not use this file except in compliance with the Elastic License. */ import { connectorReducer } from './connector_reducer'; +import { ActionConnector } from '../../../types'; describe('connector reducer', () => { - test('if property name was changed', () => { - const connector = { + let initialConnector: ActionConnector; + beforeEach(() => { + initialConnector = { secrets: {}, id: 'test', actionTypeId: 'test-action-type-id', - actionType: 'test-action-type-name', name: 'action-connector', referencedByCount: 0, config: {}, }; + }); + test('if property name was changed', () => { const updatedConnector = connectorReducer( - { connector }, + { connector: initialConnector }, { - command: 'setProperty', + command: { type: 'setProperty' }, payload: { key: 'name', value: 'new name', @@ -30,27 +33,59 @@ describe('connector reducer', () => { expect(updatedConnector.connector.name).toBe('new name'); }); - test('if property config property was added', () => { - const connector = { - secrets: {}, - id: 'test', - actionTypeId: 'test-action-type-id', - actionType: 'test-action-type-name', - name: 'action-connector', - referencedByCount: 0, - config: {}, - }; + test('if config property was added and updated', () => { + const updatedConnector = connectorReducer( + { connector: initialConnector }, + { + command: { type: 'setConfigProperty' }, + payload: { + key: 'testConfig', + value: 'new test config property', + }, + } + ); + expect(updatedConnector.connector.config.testConfig).toBe('new test config property'); + const updatedConnectorUpdatedProperty = connectorReducer( + { connector: updatedConnector.connector }, + { + command: { type: 'setConfigProperty' }, + payload: { + key: 'testConfig', + value: 'test config property updated', + }, + } + ); + expect(updatedConnectorUpdatedProperty.connector.config.testConfig).toBe( + 'test config property updated' + ); + }); + + test('if secrets property was added', () => { const updatedConnector = connectorReducer( - { connector }, + { connector: initialConnector }, { - command: 'setConfigProperty', + command: { type: 'setSecretsProperty' }, payload: { - key: 'test', - value: 'new test property', + key: 'testSecret', + value: 'new test secret property', }, } ); - expect(updatedConnector.connector.test).toBe('new test property'); + expect(updatedConnector.connector.secrets.testSecret).toBe('new test secret property'); + + const updatedConnectorUpdatedProperty = connectorReducer( + { connector: updatedConnector.connector }, + { + command: { type: 'setSecretsProperty' }, + payload: { + key: 'testSecret', + value: 'test secret property updated', + }, + } + ); + expect(updatedConnectorUpdatedProperty.connector.secrets.testSecret).toBe( + 'test secret property updated' + ); }); }); From b6d5f4e353f43a2dd1531cd5732cf4970bcc9aac Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 10 Dec 2019 15:44:16 -0800 Subject: [PATCH 196/297] Fixed alerts list unit tests --- .../action_type_menu.test.tsx | 30 +-- .../sections/alert_add/alert_add.tsx | 2 - .../components/alerts_list.test.tsx | 197 +++++++++++++----- .../alerts_list/components/alerts_list.tsx | 66 +++--- 4 files changed, 197 insertions(+), 98 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.test.tsx index 922339b1563688..9479022913df2e 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.test.tsx @@ -43,6 +43,21 @@ describe('connector_add_flyout', () => { it('renders action type menu with proper EuiCards for registered action types', () => { const onActionTypeChange = jest.fn(); + const actionType = { + id: 'my-action-type', + iconClass: 'test', + selectMessage: 'test', + validateConnector: (): ValidationResult => { + return { errors: {} }; + }, + validateParams: (): ValidationResult => { + const validationResult = { errors: {} }; + return validationResult; + }, + actionConnectorFields: null, + actionParamsFields: null, + }; + actionTypeRegistry.get.mockReturnValueOnce(actionType); const wrapper = mountWithIntl( @@ -65,21 +80,6 @@ describe('connector_add_flyout', () => { ); - const actionType = { - id: 'my-action-type', - iconClass: 'test', - selectMessage: 'test', - validateConnector: (): ValidationResult => { - return { errors: {} }; - }, - validateParams: (): ValidationResult => { - const validationResult = { errors: {} }; - return validationResult; - }, - actionConnectorFields: null, - actionParamsFields: null, - }; - actionTypeRegistry.get.mockReturnValueOnce(actionType); expect(wrapper.find('[data-test-subj="first-action-type-card"]').exists()).toBeTruthy(); expect(wrapper.find('[data-test-subj="second-action-type-card"]').exists()).toBeTruthy(); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 35be9e187ff41e..87af87fb845146 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -23,8 +23,6 @@ import { EuiFlexGrid, EuiFormRow, EuiComboBox, - EuiCard, - EuiKeyPadMenu, EuiKeyPadMenuItem, EuiTabs, EuiTab, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx index 59f7a202285d12..54fb06cc85efc6 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import * as React from 'react'; +import { Fragment } from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { setAppDependencies } from '../../../app_dependencies'; import { coreMock } from '../../../../../../../../../../src/core/public/mocks'; @@ -12,27 +13,52 @@ import { act } from 'react-dom/test-utils'; import { actionTypeRegistryMock } from '../../../action_type_registry.mock'; import { alertTypeRegistryMock } from '../../../alert_type_registry.mock'; import { AlertsList } from './alerts_list'; -jest.mock('../../../context/actions_connectors_context'); +import { ValidationResult } from '../../../../types'; +jest.mock('../../../context/alerts_context'); jest.mock('../../../lib/action_connector_api', () => ({ - loadAlerts: jest.fn(), loadActionTypes: jest.fn(), + loadAllActions: jest.fn(), +})); +jest.mock('../../../lib/alert_api', () => ({ + loadAlerts: jest.fn(), + loadAlertTypes: jest.fn(), })); const actionTypeRegistry = actionTypeRegistryMock.create(); const alertTypeRegistry = alertTypeRegistryMock.create(); +const alertType = { + id: 'test_alert_type', + name: 'some alert type', + iconClass: 'test', + alertType: { + id: 'test_alert_type', + name: 'some alert type', + iconClass: 'test', + validate: (): ValidationResult => { + return { errors: {} }; + }, + alertParamsExpression: () => null, + }, +}; +alertTypeRegistry.list.mockReturnValue([alertType]); +actionTypeRegistry.list.mockReturnValue([]); + describe('alerts_list component empty', () => { let wrapper: ReactWrapper; beforeEach(async () => { - const { loadAlerts, loadActionTypes } = jest.requireMock('../../../lib/alert_api'); - loadAlerts.mockResolvedValueOnce({ + const { loadAlerts, loadAlertTypes } = jest.requireMock('../../../lib/alert_api'); + const { loadActionTypes, loadAllActions } = jest.requireMock( + '../../../lib/action_connector_api' + ); + loadAlerts.mockResolvedValue({ page: 1, perPage: 10000, total: 0, data: [], }); - loadActionTypes.mockResolvedValueOnce([ + loadActionTypes.mockResolvedValue([ { id: 'test', name: 'Test', @@ -42,13 +68,20 @@ describe('alerts_list component empty', () => { name: 'Test2', }, ]); + loadAlertTypes.mockResolvedValue([{ id: 'test_alert_type', name: 'some alert type' }]); + loadAllActions.mockResolvedValue({ + page: 1, + perPage: 10000, + total: 0, + data: [], + }); const deps = { core: coreMock.createStart(), plugins: { capabilities: { get() { return { - alerts: { + alerting: { delete: true, save: true, show: true, @@ -61,8 +94,6 @@ describe('alerts_list component empty', () => { alertTypeRegistry: alertTypeRegistry as any, }; const AppDependenciesProvider = setAppDependencies(deps); - actionTypeRegistry.has.mockReturnValue(true); - await act(async () => { wrapper = mountWithIntl( @@ -91,29 +122,52 @@ describe('alerts_list component with items', () => { let wrapper: ReactWrapper; beforeEach(async () => { - const { loadAlerts, loadActionTypes } = jest.requireMock('../../../lib/alert_api'); - loadAlerts.mockResolvedValueOnce({ + const { loadAlerts, loadAlertTypes } = jest.requireMock('../../../lib/alert_api'); + const { loadActionTypes, loadAllActions } = jest.requireMock( + '../../../lib/action_connector_api' + ); + loadAlerts.mockResolvedValue({ page: 1, perPage: 10000, total: 2, data: [ { id: '1', - actionTypeId: 'test', - description: 'My test', - referencedByCount: 1, - config: {}, + name: 'test alert', + tags: ['tag1'], + enabled: true, + alertTypeId: 'test_alert_type', + interval: '5d', + actions: [], + params: { name: 'test alert type name' }, + scheduledTaskId: null, + createdBy: null, + updatedBy: null, + apiKeyOwner: null, + throttle: '1m', + muteAll: false, + mutedInstanceIds: [], }, { id: '2', - actionTypeId: 'test2', - description: 'My test 2', - referencedByCount: 1, - config: {}, + name: 'test alert 2', + tags: ['tag1'], + enabled: true, + alertTypeId: 'test_alert_type', + interval: '5d', + actions: [{ id: 'test', group: 'alert', params: { message: 'test' } }], + params: { name: 'test alert type name' }, + scheduledTaskId: null, + createdBy: null, + updatedBy: null, + apiKeyOwner: null, + throttle: '1m', + muteAll: false, + mutedInstanceIds: [], }, ], }); - loadActionTypes.mockResolvedValueOnce([ + loadActionTypes.mockResolvedValue([ { id: 'test', name: 'Test', @@ -123,13 +177,20 @@ describe('alerts_list component with items', () => { name: 'Test2', }, ]); + loadAlertTypes.mockResolvedValue([{ id: 'test_alert_type', name: 'some alert type' }]); + loadAllActions.mockResolvedValue({ + page: 1, + perPage: 10000, + total: 0, + data: [], + }); const deps = { core: coreMock.createStart(), plugins: { capabilities: { get() { return { - actions: { + alerting: { delete: true, save: true, show: true, @@ -138,12 +199,8 @@ describe('alerts_list component with items', () => { }, }, } as any, - actionTypeRegistry: { - get() { - return null; - }, - } as any, - alertTypeRegistry: {} as any, + actionTypeRegistry: actionTypeRegistry as any, + alertTypeRegistry: alertTypeRegistry as any, }; const AppDependenciesProvider = setAppDependencies(deps); @@ -158,10 +215,11 @@ describe('alerts_list component with items', () => { await waitForRender(wrapper); expect(loadAlerts).toHaveBeenCalled(); + expect(loadActionTypes).toHaveBeenCalled(); }); it('renders table of connectors', () => { - expect(wrapper.find('EuiInMemoryTable')).toHaveLength(1); + expect(wrapper.find('EuiBasicTable')).toHaveLength(1); expect(wrapper.find('EuiTableRow')).toHaveLength(2); }); }); @@ -170,14 +228,17 @@ describe('alerts_list component empty with show only capability', () => { let wrapper: ReactWrapper; beforeEach(async () => { - const { loadAlerts, loadActionTypes } = jest.requireMock('../../../lib/alert_api'); - loadAlerts.mockResolvedValueOnce({ + const { loadAlerts, loadAlertTypes } = jest.requireMock('../../../lib/alert_api'); + const { loadActionTypes, loadAllActions } = jest.requireMock( + '../../../lib/action_connector_api' + ); + loadAlerts.mockResolvedValue({ page: 1, perPage: 10000, total: 0, data: [], }); - loadActionTypes.mockResolvedValueOnce([ + loadActionTypes.mockResolvedValue([ { id: 'test', name: 'Test', @@ -187,13 +248,20 @@ describe('alerts_list component empty with show only capability', () => { name: 'Test2', }, ]); + loadAlertTypes.mockResolvedValue([{ id: 'test_alert_type', name: 'some alert type' }]); + loadAllActions.mockResolvedValue({ + page: 1, + perPage: 10000, + total: 0, + data: [], + }); const deps = { core: coreMock.createStart(), plugins: { capabilities: { get() { return { - alerts: { + alerting: { delete: false, save: false, show: true, @@ -222,9 +290,8 @@ describe('alerts_list component empty with show only capability', () => { await waitForRender(wrapper); }); - it('renders no permissions to create connector', () => { - expect(wrapper.find('[defaultMessage="No permissions to create connector"]')).toHaveLength(1); - expect(wrapper.find('[data-test-subj="createActionButton"]')).toHaveLength(0); + it('not renders create alert button', () => { + expect(wrapper.find('[data-test-subj="createAlertButton"]')).toHaveLength(0); }); }); @@ -232,29 +299,52 @@ describe('alerts_list with show only capability', () => { let wrapper: ReactWrapper; beforeEach(async () => { - const { loadAlerts, loadActionTypes } = jest.requireMock('../../../lib/alert_api'); - loadAlerts.mockResolvedValueOnce({ + const { loadAlerts, loadAlertTypes } = jest.requireMock('../../../lib/alert_api'); + const { loadActionTypes, loadAllActions } = jest.requireMock( + '../../../lib/action_connector_api' + ); + loadAlerts.mockResolvedValue({ page: 1, perPage: 10000, total: 2, data: [ { id: '1', - actionTypeId: 'test', - description: 'My test', - referencedByCount: 1, - config: {}, + name: 'test alert', + tags: ['tag1'], + enabled: true, + alertTypeId: 'test_alert_type', + interval: '5d', + actions: [], + params: { name: 'test alert type name' }, + scheduledTaskId: null, + createdBy: null, + updatedBy: null, + apiKeyOwner: null, + throttle: '1m', + muteAll: false, + mutedInstanceIds: [], }, { id: '2', - actionTypeId: 'test2', - description: 'My test 2', - referencedByCount: 1, - config: {}, + name: 'test alert 2', + tags: ['tag1'], + enabled: true, + alertTypeId: 'test_alert_type', + interval: '5d', + actions: [{ id: 'test', group: 'alert', params: { message: 'test' } }], + params: { name: 'test alert type name' }, + scheduledTaskId: null, + createdBy: null, + updatedBy: null, + apiKeyOwner: null, + throttle: '1m', + muteAll: false, + mutedInstanceIds: [], }, ], }); - loadActionTypes.mockResolvedValueOnce([ + loadActionTypes.mockResolvedValue([ { id: 'test', name: 'Test', @@ -264,13 +354,20 @@ describe('alerts_list with show only capability', () => { name: 'Test2', }, ]); + loadAlertTypes.mockResolvedValue([{ id: 'test_alert_type', name: 'some alert type' }]); + loadAllActions.mockResolvedValue({ + page: 1, + perPage: 10000, + total: 0, + data: [], + }); const deps = { core: coreMock.createStart(), plugins: { capabilities: { get() { return { - alerts: { + alerting: { delete: false, save: false, show: true, @@ -296,13 +393,9 @@ describe('alerts_list with show only capability', () => { }); it('renders table of alerts with delete button disabled', () => { - expect(wrapper.find('EuiInMemoryTable')).toHaveLength(1); + expect(wrapper.find('EuiBasicTable')).toHaveLength(1); expect(wrapper.find('EuiTableRow')).toHaveLength(2); - wrapper.find('EuiTableRow').forEach(elem => { - const deleteButton = elem.find('[data-test-subj="deleteAlert"]').first(); - expect(deleteButton).toBeTruthy(); - expect(deleteButton.prop('isDisabled')).toBeTruthy(); - }); + // TODO: check delete button }); }); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 5c98d329e62a3b..5533a0be0d408e 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -27,6 +27,7 @@ export const AlertsList: React.FunctionComponent = () => { plugins: { capabilities, toastNotifications }, } = useAppDependencies(); const canDelete = capabilities.get().alerting.delete; + const canSave = capabilities.get().alerting.save; const [actionTypes, setActionTypes] = useState([]); const [alertTypesIndex, setAlertTypesIndex] = useState(undefined); @@ -181,6 +182,41 @@ export const AlertsList: React.FunctionComponent = () => { }, ]; + const toolsRight = [ + setTypesFilter(types)} + options={Object.values(alertTypesIndex || {}) + .map(alertType => ({ + value: alertType.id, + name: alertType.name, + })) + .sort((a, b) => a.name.localeCompare(b.name))} + />, + setActionTypesFilter(ids)} + />, + ]; + + if (canSave) { + toolsRight.push( + setAlertFlyoutVisibility(true)} + > + + + ); + } + return (
@@ -202,35 +238,7 @@ export const AlertsList: React.FunctionComponent = () => { />, ] } - toolsRight={[ - setTypesFilter(types)} - options={Object.values(alertTypesIndex || {}) - .map(alertType => ({ - value: alertType.id, - name: alertType.name, - })) - .sort((a, b) => a.name.localeCompare(b.name))} - />, - setActionTypesFilter(ids)} - />, - setAlertFlyoutVisibility(true)} - > - - , - ]} + toolsRight={toolsRight} /> {/* Large to remain consistent with ActionsList table spacing */} From da11d0aa8c17a80bbba7e144a466fc36d71d6f63 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 10 Dec 2019 19:46:43 -0800 Subject: [PATCH 197/297] Set alert tab default if it is available --- .../np_ready/public/application/app.tsx | 30 ++++++++++++------- .../public/application/constants/index.ts | 1 - 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx index 299455a2837bc7..85371e805076fe 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx @@ -6,8 +6,9 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { Switch, Route, Redirect } from 'react-router-dom'; -import { BASE_PATH, Section, DEFAULT_SECTION } from './constants'; +import { BASE_PATH, Section } from './constants'; import { TriggersActionsUIHome } from './home'; +import { useAppDependencies } from './app_dependencies'; class ShareRouter extends Component { static contextTypes = { @@ -39,13 +40,20 @@ export const App = () => { ); }; -export const AppWithoutRouter = ({ sectionsRegex }: any) => ( - - - - -); +export const AppWithoutRouter = ({ sectionsRegex }: any) => { + const { + plugins: { capabilities }, + } = useAppDependencies(); + const canShowAlerts = capabilities.get().alerting.show; + const DEFAULT_SECTION = canShowAlerts ? 'alerts' : 'connectors'; + return ( + + + + + ); +}; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/index.ts index c337c847ef1f50..69ab29f4297aed 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/index.ts @@ -8,7 +8,6 @@ export const BASE_PATH = '/management/kibana/triggersActions'; export const BASE_ACTION_API_PATH = '/api/action'; export const BASE_ALERT_API_PATH = '/api/alert'; -export const DEFAULT_SECTION: Section = 'connectors'; export type Section = 'connectors' | 'alerts'; export const routeToHome = `${BASE_PATH}`; From 8ecccba6c055dae69e8c54674d6a4bea7b524b1f Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 11 Dec 2019 10:19:12 -0800 Subject: [PATCH 198/297] Added doc_title and get_time_units unit tests --- .../public/application/lib/doc_title.test.ts | 53 +++++++++++++++++++ .../public/application/lib/doc_title.ts | 6 +-- .../application/lib/get_time_options.test.ts | 48 +++++++++++++++++ 3 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.test.ts create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/get_time_options.test.ts diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.test.ts new file mode 100644 index 00000000000000..837fc207bae9cd --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.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 { docTitleService } from './doc_title'; +import { coreMock } from '../../../../../../../../src/core/public/mocks'; + +describe('doc_title', () => { + test('if change calls set proper breadcrumb title ', async () => { + const core = coreMock.createStart(); + const spy = jest.spyOn(core.chrome.docTitle, 'change'); + docTitleService.init(spy); + docTitleService.setTitle('home'); + docTitleService.setTitle('alerts'); + docTitleService.setTitle('connectors'); + expect(core.chrome.docTitle).toMatchInlineSnapshot(` + Object { + "__legacy": Object { + "setBaseTitle": [MockFunction], + }, + "change": [MockFunction] { + "calls": Array [ + Array [ + "Alerts and actions", + ], + Array [ + "Alerts", + ], + Array [ + "Connectors", + ], + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + Object { + "type": "return", + "value": undefined, + }, + Object { + "type": "return", + "value": undefined, + }, + ], + }, + "reset": [MockFunction], + } + `); + }); +}); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.ts index 385ad49fc84f4a..db48d64ad0fd81 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.ts @@ -16,9 +16,9 @@ class DocTitleService { let updatedTitle: string; switch (page) { - case 'actions': - updatedTitle = i18n.translate('xpack.triggersActionsUI.actions.breadcrumbTitle', { - defaultMessage: 'Actions', + case 'connectors': + updatedTitle = i18n.translate('xpack.triggersActionsUI.connectors.breadcrumbTitle', { + defaultMessage: 'Connectors', }); break; case 'alerts': diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/get_time_options.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/get_time_options.test.ts new file mode 100644 index 00000000000000..70b5999001ddf0 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/get_time_options.test.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { getTimeOptions, getTimeFieldOptions } from './get_time_options'; + +describe('get_time_options', () => { + test('if getTimeOptions return single unit time options', () => { + const timeUnitValue = getTimeOptions('1'); + expect(timeUnitValue).toMatchObject([ + { text: 'second', value: 's' }, + { text: 'minute', value: 'm' }, + { text: 'hour', value: 'h' }, + { text: 'day', value: 'd' }, + ]); + }); + + test('if getTimeOptions return multiple unit time options', () => { + const timeUnitValue = getTimeOptions('10'); + expect(timeUnitValue).toMatchObject([ + { text: 'seconds', value: 's' }, + { text: 'minutes', value: 'm' }, + { text: 'hours', value: 'h' }, + { text: 'days', value: 'd' }, + ]); + }); + + test('if ', () => { + const timeOnlyTypeFields = getTimeFieldOptions( + [ + { type: 'date', name: 'order_date' }, + { type: 'number', name: 'sum' }, + ], + { + text: 'select', + value: '', + } + ); + expect(timeOnlyTypeFields).toMatchObject([ + { + text: 'select', + value: '', + }, + { text: 'order_date', value: 'order_date' }, + ]); + }); +}); From 9d01113e3918c887c11d7a31122758ca98c21d89 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 11 Dec 2019 11:34:47 -0800 Subject: [PATCH 199/297] Added some test fixes --- .../action_connector_form/action_connector_form.test.tsx | 2 +- .../action_connector_form/action_type_menu.test.tsx | 2 +- .../action_connector_form/connector_add_flyout.test.tsx | 2 +- .../action_connector_form/connector_edit_flyout.test.tsx | 2 +- .../action_connector_form/connector_reducer.test.ts | 2 +- .../components/actions_connectors_list.test.tsx | 8 ++++---- .../alert_add/alert_types/threshold/expression.tsx | 4 +++- 7 files changed, 12 insertions(+), 10 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx index 7ce9a822e2c62d..353e36a64542a1 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx @@ -19,7 +19,7 @@ const actionTypeRegistry = actionTypeRegistryMock.create(); describe('action_connector_form', () => { let wrapper: ReactWrapper; - beforeEach(async () => { + beforeAll(async () => { const deps = { core: coreMock.createStart(), plugins: { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.test.tsx index 9479022913df2e..d6610de4ea9391 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.test.tsx @@ -19,7 +19,7 @@ describe('connector_add_flyout', () => { let AppDependenciesProvider: React.ProviderExoticComponent>; let deps: any; - beforeEach(() => { + beforeAll(() => { deps = { core: coreMock.createStart(), plugins: { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.test.tsx index 1f96250ee28f85..3aaa4aa5a5aeaa 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.test.tsx @@ -19,7 +19,7 @@ const actionTypeRegistry = actionTypeRegistryMock.create(); describe('connector_add_flyout', () => { let wrapper: ReactWrapper; - beforeEach(async () => { + beforeAll(async () => { const deps = { core: coreMock.createStart(), plugins: { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx index 5f9d4f058496f3..3be42e7109287b 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx @@ -18,7 +18,7 @@ let AppDependenciesProvider: React.ProviderExoticComponent { - beforeEach(() => { + beforeAll(() => { deps = { core: coreMock.createStart(), plugins: { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_reducer.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_reducer.test.ts index de7f6a0b550f73..df7e5d8fe9a78d 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_reducer.test.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_reducer.test.ts @@ -8,7 +8,7 @@ import { ActionConnector } from '../../../types'; describe('connector reducer', () => { let initialConnector: ActionConnector; - beforeEach(() => { + beforeAll(() => { initialConnector = { secrets: {}, id: 'test', diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx index 8da748c53b7182..c109d6b161fc21 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx @@ -22,7 +22,7 @@ const actionTypeRegistry = actionTypeRegistryMock.create(); describe('actions_connectors_list component empty', () => { let wrapper: ReactWrapper; - beforeEach(async () => { + beforeAll(async () => { const { loadAllActions, loadActionTypes } = jest.requireMock( '../../../lib/action_connector_api' ); @@ -93,7 +93,7 @@ describe('actions_connectors_list component empty', () => { describe('actions_connectors_list component with items', () => { let wrapper: ReactWrapper; - beforeEach(async () => { + beforeAll(async () => { const { loadAllActions, loadActionTypes } = jest.requireMock( '../../../lib/action_connector_api' ); @@ -182,7 +182,7 @@ describe('actions_connectors_list component with items', () => { describe('actions_connectors_list component empty with show only capability', () => { let wrapper: ReactWrapper; - beforeEach(async () => { + beforeAll(async () => { const { loadAllActions, loadActionTypes } = jest.requireMock( '../../../lib/action_connector_api' ); @@ -246,7 +246,7 @@ describe('actions_connectors_list component empty with show only capability', () describe('actions_connectors_list with show only capability', () => { let wrapper: ReactWrapper; - beforeEach(async () => { + beforeAll(async () => { const { loadAllActions, loadActionTypes } = jest.requireMock( '../../../lib/action_connector_api' ); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx index 549d9b66ad9fb3..d6ae8d6f4362ed 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx @@ -854,7 +854,9 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = { - setAlertParams('termSize', e.target.value); + const { value } = e.target; + const termSizeVal = value !== '' ? parseFloat(value) : value; + setAlertParams('termSize', termSizeVal); }} min={1} /> From bc39d5281e8c11116e901cce0ad0d93f43f2afc1 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 11 Dec 2019 11:58:28 -0800 Subject: [PATCH 200/297] Fixed index threshold expression to display only index and fields --- .../alert_types/threshold/expression.tsx | 81 ++----------------- 1 file changed, 7 insertions(+), 74 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx index d6ae8d6f4362ed..e0b857b04420f8 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx @@ -50,7 +50,6 @@ const DEFAULT_VALUES = { const expressionFieldsWithValidation = [ 'index', 'timeField', - 'triggerIntervalSize', 'aggField', 'termSize', 'termField', @@ -63,7 +62,6 @@ const validateAlertType = (alert: Alert): ValidationResult => { const { index, timeField, - triggerIntervalSize, aggType, aggField, groupBy, @@ -82,7 +80,6 @@ const validateAlertType = (alert: Alert): ValidationResult => { threshold1: new Array(), index: new Array(), timeField: new Array(), - triggerIntervalSize: new Array(), }; validationResult.errors = errors; if (!index) { @@ -99,16 +96,6 @@ const validateAlertType = (alert: Alert): ValidationResult => { }) ); } - if (!triggerIntervalSize) { - errors.triggerIntervalSize.push( - i18n.translate( - 'xpack.triggersActionsUI.sections.addAlert.error.requiredTriggerIntervalSizeText', - { - defaultMessage: 'Trigger interval size is required.', - } - ) - ); - } if (aggType && aggregationTypes[aggType].fieldRequired && !aggField) { errors.aggField.push( i18n.translate('xpack.triggersActionsUI.sections.addAlert.error.requiredAggFieldText', { @@ -297,8 +284,6 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = const { index, timeField, - triggerIntervalSize, - triggerIntervalUnit, aggType, aggField, groupBy, @@ -363,7 +348,6 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = thresholdComparator: DEFAULT_VALUES.THRESHOLD_COMPARATOR, timeWindowSize: DEFAULT_VALUES.TIME_WINDOW_SIZE, timeWindowUnit: DEFAULT_VALUES.TIME_WINDOW_UNIT, - triggerIntervalSize: DEFAULT_VALUES.TRIGGER_INTERVAL_SIZE, triggerIntervalUnit: DEFAULT_VALUES.TRIGGER_INTERVAL_UNIT, groupBy: DEFAULT_VALUES.GROUP_BY, threshold: DEFAULT_VALUES.THRESHOLD, @@ -540,58 +524,6 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = /> - - - } - errorKey="triggerIntervalSize" - isShowingErrors={hasErrors && triggerIntervalSize !== undefined} - errors={errors} - > - - - { - const { value } = e.target; - const triggerIntervalSizeVal = value !== '' ? parseInt(value, 10) : value; - setAlertParams('triggerIntervalSize', triggerIntervalSizeVal); - }} - onBlur={e => { - if (triggerIntervalSize === undefined) { - setAlertParams('triggerIntervalSize', ''); - } - }} - /> - - - { - setAlertParams('triggerIntervalUnit', e.target.value); - }} - options={getTimeOptions(triggerIntervalSize)} - /> - - - - @@ -609,13 +541,13 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = = anchorPosition="downLeft" zIndex={8000} > -
+
{i18n.translate( - 'xpack.triggersActionsUI.sections.alertAdd.threshold.insideButtonLabel', + 'xpack.triggersActionsUI.sections.alertAdd.threshold.indexButtonLabel', { - defaultMessage: 'inside', + defaultMessage: 'index', } )} @@ -689,6 +621,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = { setAlertParams('aggType', e.target.value); setAggTypePopoverOpen(false); From c839bd20cc5fba5131d2c4a60e6904bbb034b74c Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 11 Dec 2019 20:23:31 -0800 Subject: [PATCH 201/297] Added email building action unit tests --- .../builtin_action_types/email.test.tsx | 129 ++++++++++++++++++ .../components/builtin_action_types/email.tsx | 7 +- 2 files changed, 132 insertions(+), 4 deletions(-) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx new file mode 100644 index 00000000000000..a4f46d8ae24427 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx @@ -0,0 +1,129 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under 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 { ActionTypeRegistry } from '../../action_type_registry'; +import { registerBuiltInActionTypes } from './index'; +import { ActionTypeModel, ActionConnector } from '../../../types'; +const ACTION_TYPE_ID = '.email'; +let actionTypeModel: ActionTypeModel | undefined; + +beforeAll(() => { + const actionTypeRegistry = new ActionTypeRegistry(); + registerBuiltInActionTypes({ actionTypeRegistry }); + actionTypeModel = actionTypeRegistry.get(ACTION_TYPE_ID); +}); + +describe('actionTypeRegistry.get() works', () => { + test('action type static data is as expected', () => { + expect(actionTypeModel.id).toEqual(ACTION_TYPE_ID); + expect(actionTypeModel.iconClass).toEqual('email'); + }); +}); + +describe('connector validation', () => { + test('connector validation succeeds when connector config is valid', () => { + const actionConnector = { + secrets: { + user: 'user', + password: 'pass', + }, + id: 'test', + actionTypeId: '.email', + name: 'email', + config: { + from: 'test@test.com', + port: '2323', + host: 'localhost', + test: 'test', + }, + } as ActionConnector; + + expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ + errors: { + from: [], + port: [], + host: [], + user: [], + password: [], + }, + }); + + delete actionConnector.config.test; + actionConnector.config.host = 'elastic.co'; + actionConnector.config.port = 8080; + expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ + errors: { + from: [], + port: [], + host: [], + user: [], + password: [], + }, + }); + }); + + test('connector validation fails when connector config is not valid', () => { + const actionConnector = { + secrets: { + user: 'user', + password: 'pass', + }, + id: 'test', + actionTypeId: '.email', + name: 'email', + config: { + from: 'test@test.com', + }, + } as ActionConnector; + + expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ + errors: { + from: [], + port: ['Port is required.'], + host: ['Host is required.'], + user: [], + password: [], + }, + }); + }); +}); + +describe('action params validation', () => { + test('action params validation succeeds when action params is valid', () => { + const actionParams = { + to: 'test@test.com', + cc: 'test1@test.com', + message: 'message {test}', + subject: 'test', + }; + + expect(actionTypeModel.validateParams(actionParams)).toEqual({ + errors: { + to: [], + cc: [], + bcc: [], + message: [], + subject: [], + }, + }); + }); + + test('action params validation fails when action params is not valid', () => { + const actionParams = { + to: 'test@test.com', + subject: 'test', + }; + + expect(actionTypeModel.validateParams(actionParams)).toEqual({ + errors: { + to: [], + cc: [], + bcc: [], + message: ['Message is required.'], + subject: [], + }, + }); + }); +}); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx index 745aa19cdaecf7..59e582a0488f7d 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx @@ -106,10 +106,9 @@ export function getActionType(): ActionTypeModel { }; validationResult.errors = errors; if ( - ((!actionParams.to || actionParams.to.length === 0) && - (!actionParams.cc || actionParams.cc.length === 0)) || - !actionParams.bcc || - actionParams.bcc.length === 0 + (!actionParams.to || actionParams.to.length === 0) && + (!actionParams.cc || actionParams.cc.length === 0) && + (!actionParams.bcc || actionParams.bcc.length === 0) ) { const errorText = i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredEntryText', From 68f7f554d5d4a6f8901bc7d8c4050dd15d252e9f Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 12 Dec 2019 18:37:49 -0800 Subject: [PATCH 202/297] Added unit tests for builtin action types --- .../builtin_action_types/email.test.tsx | 87 ++++++++- .../components/builtin_action_types/email.tsx | 2 +- .../builtin_action_types/es_index.test.tsx | 140 ++++++++++++++ .../builtin_action_types/es_index.tsx | 3 +- .../builtin_action_types/pagerduty.test.tsx | 182 ++++++++++++++++++ .../builtin_action_types/server_log.test.tsx | 89 +++++++++ .../builtin_action_types/slack.test.tsx | 149 ++++++++++++++ .../components/builtin_action_types/slack.tsx | 2 +- .../builtin_action_types/webhook.test.tsx | 166 ++++++++++++++++ .../builtin_action_types/webhook.tsx | 5 +- 10 files changed, 817 insertions(+), 8 deletions(-) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.test.tsx create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.test.tsx create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.test.tsx create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.test.tsx create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx index a4f46d8ae24427..872065f8b540fd 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx @@ -3,16 +3,22 @@ * 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 { mountWithIntl } from 'test_utils/enzyme_helpers'; import { ActionTypeRegistry } from '../../action_type_registry'; import { registerBuiltInActionTypes } from './index'; import { ActionTypeModel, ActionConnector } from '../../../types'; + const ACTION_TYPE_ID = '.email'; -let actionTypeModel: ActionTypeModel | undefined; +let actionTypeModel: ActionTypeModel; beforeAll(() => { const actionTypeRegistry = new ActionTypeRegistry(); registerBuiltInActionTypes({ actionTypeRegistry }); - actionTypeModel = actionTypeRegistry.get(ACTION_TYPE_ID); + const getResult = actionTypeRegistry.get(ACTION_TYPE_ID); + if (getResult !== null) { + actionTypeModel = getResult; + } }); describe('actionTypeRegistry.get() works', () => { @@ -127,3 +133,80 @@ describe('action params validation', () => { }); }); }); + +describe('EmailActionConnectorFields renders', () => { + test('all connector fields is rendered', () => { + expect(actionTypeModel.actionConnectorFields).not.toBeNull(); + if (!actionTypeModel.actionConnectorFields) { + return; + } + const ConnectorFields = actionTypeModel.actionConnectorFields; + const actionConnector = { + secrets: { + user: 'user', + password: 'pass', + }, + id: 'test', + actionTypeId: '.email', + name: 'email', + config: { + from: 'test@test.com', + }, + } as ActionConnector; + const wrapper = mountWithIntl( + {}} + editActionSecrets={() => {}} + hasErrors={false} + /> + ); + expect(wrapper.find('[data-test-subj="emailFromInput"]').length > 0).toBeTruthy(); + expect( + wrapper + .find('[data-test-subj="emailFromInput"]') + .first() + .prop('value') + ).toBe('test@test.com'); + expect(wrapper.find('[data-test-subj="emailHostInput"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="emailPortInput"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="emailUserInput"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="emailPasswordInput"]').length > 0).toBeTruthy(); + }); +}); + +describe('EmailParamsFields renders', () => { + test('all params fields is rendered', () => { + expect(actionTypeModel.actionParamsFields).not.toBeNull(); + if (!actionTypeModel.actionParamsFields) { + return; + } + const ParamsFields = actionTypeModel.actionParamsFields; + const actionParams = { + to: ['test@test.com'], + subject: 'test', + message: 'test message', + }; + const wrapper = mountWithIntl( + {}} + index={0} + hasErrors={false} + /> + ); + expect(wrapper.find('[data-test-subj="toEmailAddressInput"]').length > 0).toBeTruthy(); + expect( + wrapper + .find('[data-test-subj="toEmailAddressInput"]') + .first() + .prop('selectedOptions') + ).toStrictEqual([{ label: 'test@test.com' }]); + expect(wrapper.find('[data-test-subj="ccEmailAddressInput"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="bccEmailAddressInput"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="emailSubjectInput"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="emailMessageInput"]').length > 0).toBeTruthy(); + }); +}); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx index 59e582a0488f7d..ea10f7a858d989 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx @@ -176,7 +176,7 @@ const EmailActionConnectorFields: React.FunctionComponent { editActionConfig('from', e.target.value); }} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.test.tsx new file mode 100644 index 00000000000000..709d64504e411a --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.test.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 from 'react'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { ActionTypeRegistry } from '../../action_type_registry'; +import { registerBuiltInActionTypes } from './index'; +import { ActionTypeModel, ActionConnector } from '../../../types'; + +const ACTION_TYPE_ID = '.index'; +let actionTypeModel: ActionTypeModel; + +beforeAll(() => { + const actionTypeRegistry = new ActionTypeRegistry(); + registerBuiltInActionTypes({ actionTypeRegistry }); + const getResult = actionTypeRegistry.get(ACTION_TYPE_ID); + if (getResult !== null) { + actionTypeModel = getResult; + } +}); + +describe('actionTypeRegistry.get() works', () => { + test('action type .index is registered', () => { + expect(actionTypeModel.id).toEqual(ACTION_TYPE_ID); + expect(actionTypeModel.iconClass).toEqual('indexOpen'); + }); +}); + +describe('index connector validation', () => { + test('connector validation succeeds when connector config is valid', () => { + const actionConnector = { + secrets: {}, + id: 'test', + actionTypeId: '.email', + name: 'email', + config: { + index: 'test_es_index', + }, + } as ActionConnector; + + expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ + errors: {}, + }); + + delete actionConnector.config.index; + expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ + errors: {}, + }); + }); +}); + +describe('action params validation', () => { + test('action params validation succeeds when action params is valid', () => { + const actionParams = { + index: 'test', + refresh: false, + executionTimeField: '1', + documents: ['test'], + }; + + expect(actionTypeModel.validateParams(actionParams)).toEqual({ + errors: {}, + }); + + const emptyActionParams = {}; + + expect(actionTypeModel.validateParams(emptyActionParams)).toEqual({ + errors: {}, + }); + }); +}); + +describe('IndexActionConnectorFields renders', () => { + test('all connector fields is rendered', () => { + expect(actionTypeModel.actionConnectorFields).not.toBeNull(); + if (!actionTypeModel.actionConnectorFields) { + return; + } + const ConnectorFields = actionTypeModel.actionConnectorFields; + const actionConnector = { + secrets: {}, + id: 'test', + actionTypeId: '.email', + name: 'email', + config: { + index: 'test', + }, + } as ActionConnector; + const wrapper = mountWithIntl( + {}} + editActionSecrets={() => {}} + hasErrors={false} + /> + ); + expect(wrapper.find('[data-test-subj="indexInput"]').length > 0).toBeTruthy(); + expect( + wrapper + .find('[data-test-subj="indexInput"]') + .first() + .prop('value') + ).toBe('test'); + }); +}); + +describe('IndexParamsFields renders', () => { + test('all params fields is rendered', () => { + expect(actionTypeModel.actionParamsFields).not.toBeNull(); + if (!actionTypeModel.actionParamsFields) { + return; + } + const ParamsFields = actionTypeModel.actionParamsFields; + const actionParams = { + index: 'test_index', + refresh: false, + documents: ['test'], + }; + const wrapper = mountWithIntl( + {}} + index={0} + hasErrors={false} + /> + ); + expect(wrapper.find('[data-test-subj="indexInput"]').length > 0).toBeTruthy(); + expect( + wrapper + .find('[data-test-subj="indexInput"]') + .first() + .prop('value') + ).toBe('test_index'); + expect(wrapper.find('[data-test-subj="indexRefreshCheckbox"]').length > 0).toBeTruthy(); + }); +}); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.tsx index 96ca6222f777db..82ffdfc74f53a4 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.tsx @@ -81,7 +81,6 @@ const IndexParamsFields: React.FunctionComponent = ({ return ( = ({ /> { editAction('refresh', e.target.checked, index); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.test.tsx new file mode 100644 index 00000000000000..e16684cfd925dc --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.test.tsx @@ -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 React from 'react'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { ActionTypeRegistry } from '../../action_type_registry'; +import { registerBuiltInActionTypes } from './index'; +import { ActionTypeModel, ActionConnector } from '../../../types'; + +const ACTION_TYPE_ID = '.pagerduty'; +let actionTypeModel: ActionTypeModel; + +beforeAll(() => { + const actionTypeRegistry = new ActionTypeRegistry(); + registerBuiltInActionTypes({ actionTypeRegistry }); + const getResult = actionTypeRegistry.get(ACTION_TYPE_ID); + if (getResult !== null) { + actionTypeModel = getResult; + } +}); + +describe('actionTypeRegistry.get() works', () => { + test('action type static data is as expected', () => { + expect(actionTypeModel.id).toEqual(ACTION_TYPE_ID); + expect(actionTypeModel.iconClass).toEqual('apps'); + }); +}); + +describe('pagerduty connector validation', () => { + test('connector validation succeeds when connector config is valid', () => { + const actionConnector = { + secrets: { + routingKey: 'test', + }, + id: 'test', + actionTypeId: '.email', + name: 'email', + config: { + apiUrl: 'http:\\test', + }, + } as ActionConnector; + + expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ + errors: { + routingKey: [], + apiUrl: [], + }, + }); + + delete actionConnector.config.test; + actionConnector.secrets.routingKey = 'test1'; + expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ + errors: { + routingKey: [], + apiUrl: [], + }, + }); + }); + + test('connector validation fails when connector config is not valid', () => { + const actionConnector = { + secrets: {}, + id: 'test', + actionTypeId: '.email', + name: 'email', + config: { + apiUrl: 'http:\\test', + }, + } as ActionConnector; + + expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ + errors: { + routingKey: ['Routing Key is required.'], + apiUrl: [], + }, + }); + }); +}); + +describe('pagerduty action params validation', () => { + test('action params validation succeeds when action params is valid', () => { + const actionParams = { + eventAction: 'trigger', + dedupKey: 'test', + summary: '2323', + source: 'source', + severity: 'critical', + timestamp: '234654564654', + component: 'test', + group: 'group', + class: 'test class', + }; + + expect(actionTypeModel.validateParams(actionParams)).toEqual({ + errors: {}, + }); + }); +}); + +describe('PagerDutyActionConnectorFields renders', () => { + test('all connector fields is rendered', () => { + expect(actionTypeModel.actionConnectorFields).not.toBeNull(); + if (!actionTypeModel.actionConnectorFields) { + return; + } + const ConnectorFields = actionTypeModel.actionConnectorFields; + const actionConnector = { + secrets: { + routingKey: 'test', + }, + id: 'test', + actionTypeId: '.email', + name: 'email', + config: { + apiUrl: 'http:\\test', + }, + } as ActionConnector; + const wrapper = mountWithIntl( + {}} + editActionSecrets={() => {}} + hasErrors={false} + /> + ); + expect(wrapper.find('[data-test-subj="pagerdutyApiUrlInput"]').length > 0).toBeTruthy(); + expect( + wrapper + .find('[data-test-subj="pagerdutyApiUrlInput"]') + .first() + .prop('value') + ).toBe('http:\\test'); + expect(wrapper.find('[data-test-subj="pagerdutyRoutingKeyInput"]').length > 0).toBeTruthy(); + }); +}); + +describe('PagerDutyParamsFields renders', () => { + test('all params fields is rendered', () => { + expect(actionTypeModel.actionParamsFields).not.toBeNull(); + if (!actionTypeModel.actionParamsFields) { + return; + } + const ParamsFields = actionTypeModel.actionParamsFields; + const actionParams = { + eventAction: 'trigger', + dedupKey: 'test', + summary: '2323', + source: 'source', + severity: 'critical', + timestamp: '234654564654', + component: 'test', + group: 'group', + class: 'test class', + }; + const wrapper = mountWithIntl( + {}} + index={0} + hasErrors={false} + /> + ); + expect(wrapper.find('[data-test-subj="severitySelect"]').length > 0).toBeTruthy(); + expect( + wrapper + .find('[data-test-subj="severitySelect"]') + .first() + .prop('value') + ).toStrictEqual('critical'); + expect(wrapper.find('[data-test-subj="eventActionSelect"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="dedupKeyInput"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="timestampInput"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="componentInput"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="groupInput"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="sourceInput"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="pagerdutyDescriptionInput"]').length > 0).toBeTruthy(); + }); +}); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.test.tsx new file mode 100644 index 00000000000000..04d3acbd30ee15 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.test.tsx @@ -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 React from 'react'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { ActionTypeRegistry } from '../../action_type_registry'; +import { registerBuiltInActionTypes } from './index'; +import { ActionTypeModel, ActionConnector } from '../../../types'; + +const ACTION_TYPE_ID = '.server-log'; +let actionTypeModel: ActionTypeModel; + +beforeAll(() => { + const actionTypeRegistry = new ActionTypeRegistry(); + registerBuiltInActionTypes({ actionTypeRegistry }); + const getResult = actionTypeRegistry.get(ACTION_TYPE_ID); + if (getResult !== null) { + actionTypeModel = getResult; + } +}); + +describe('actionTypeRegistry.get() works', () => { + test('action type static data is as expected', () => { + expect(actionTypeModel.id).toEqual(ACTION_TYPE_ID); + expect(actionTypeModel.iconClass).toEqual('logsApp'); + }); +}); + +describe('server-log connector validation', () => { + test('connector validation succeeds when connector config is valid', () => { + const actionConnector = { + secrets: {}, + id: 'test', + actionTypeId: '.email', + name: 'email', + config: {}, + } as ActionConnector; + + expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ + errors: {}, + }); + }); +}); + +describe('action params validation', () => { + test('action params validation succeeds when action params is valid', () => { + const actionParams = { + message: 'test message', + level: 'trace', + }; + + expect(actionTypeModel.validateParams(actionParams)).toEqual({ + errors: {}, + }); + }); +}); + +describe('ServerLogParamsFields renders', () => { + test('all params fields is rendered', () => { + expect(actionTypeModel.actionParamsFields).not.toBeNull(); + if (!actionTypeModel.actionParamsFields) { + return; + } + const ParamsFields = actionTypeModel.actionParamsFields; + const actionParams = { + message: 'test message', + level: 'trace', + }; + const wrapper = mountWithIntl( + {}} + index={0} + hasErrors={false} + /> + ); + expect(wrapper.find('[data-test-subj="loggingLevelSelect"]').length > 0).toBeTruthy(); + expect( + wrapper + .find('[data-test-subj="loggingLevelSelect"]') + .first() + .prop('value') + ).toStrictEqual('trace'); + expect(wrapper.find('[data-test-subj="loggingMessageInput"]').length > 0).toBeTruthy(); + }); +}); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.test.tsx new file mode 100644 index 00000000000000..81c3e59d883af7 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.test.tsx @@ -0,0 +1,149 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under 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 { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { ActionTypeRegistry } from '../../action_type_registry'; +import { registerBuiltInActionTypes } from './index'; +import { ActionTypeModel, ActionConnector } from '../../../types'; + +const ACTION_TYPE_ID = '.slack'; +let actionTypeModel: ActionTypeModel; + +beforeAll(() => { + const actionTypeRegistry = new ActionTypeRegistry(); + registerBuiltInActionTypes({ actionTypeRegistry }); + const getResult = actionTypeRegistry.get(ACTION_TYPE_ID); + if (getResult !== null) { + actionTypeModel = getResult; + } +}); + +describe('actionTypeRegistry.get() works', () => { + test('action type static data is as expected', () => { + expect(actionTypeModel.id).toEqual(ACTION_TYPE_ID); + expect(actionTypeModel.iconClass).toEqual('logoSlack'); + }); +}); + +describe('slack connector validation', () => { + test('connector validation succeeds when connector config is valid', () => { + const actionConnector = { + secrets: { + webhookUrl: 'http:\\test', + }, + id: 'test', + actionTypeId: '.email', + name: 'email', + config: {}, + } as ActionConnector; + + expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ + errors: { + webhookUrl: [], + }, + }); + }); + + test('connector validation fails when connector config is not valid', () => { + const actionConnector = { + secrets: {}, + id: 'test', + actionTypeId: '.email', + name: 'email', + config: {}, + } as ActionConnector; + + expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ + errors: { + webhookUrl: ['WebhookUrl is required.'], + }, + }); + }); +}); + +describe('slack action params validation', () => { + test('if action params validation succeeds when action params is valid', () => { + const actionParams = { + message: 'message {test}', + }; + + expect(actionTypeModel.validateParams(actionParams)).toEqual({ + errors: {}, + }); + }); + + test('if action params validation not fails when action params is empty', () => { + const actionParams = {}; + + expect(actionTypeModel.validateParams(actionParams)).toEqual({ + errors: {}, + }); + }); +}); + +describe('SlackActionFields renders', () => { + test('all connector fields is rendered', () => { + expect(actionTypeModel.actionConnectorFields).not.toBeNull(); + if (!actionTypeModel.actionConnectorFields) { + return; + } + const ConnectorFields = actionTypeModel.actionConnectorFields; + const actionConnector = { + secrets: { + webhookUrl: 'http:\\test', + }, + id: 'test', + actionTypeId: '.email', + name: 'email', + config: {}, + } as ActionConnector; + const wrapper = mountWithIntl( + {}} + editActionSecrets={() => {}} + hasErrors={false} + /> + ); + expect(wrapper.find('[data-test-subj="slackWebhookUrlInput"]').length > 0).toBeTruthy(); + expect( + wrapper + .find('[data-test-subj="slackWebhookUrlInput"]') + .first() + .prop('value') + ).toBe('http:\\test'); + }); +}); + +describe('SlackParamsFields renders', () => { + test('all params fields is rendered', () => { + expect(actionTypeModel.actionParamsFields).not.toBeNull(); + if (!actionTypeModel.actionParamsFields) { + return; + } + const ParamsFields = actionTypeModel.actionParamsFields; + const actionParams = { + message: 'test message', + }; + const wrapper = mountWithIntl( + {}} + index={0} + hasErrors={false} + /> + ); + expect(wrapper.find('[data-test-subj="slackMessageTextarea"]').length > 0).toBeTruthy(); + expect( + wrapper + .find('[data-test-subj="slackMessageTextarea"]') + .first() + .prop('value') + ).toStrictEqual('test message'); + }); +}); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx index 6797c61944ad2c..bb978722fb5d97 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx @@ -79,7 +79,7 @@ const SlackActionFields: React.FunctionComponent = ( fullWidth name="webhookUrl" value={webhookUrl || ''} - data-test-subj="slackWebhookUrlTextarea" + data-test-subj="slackWebhookUrlInput" onChange={e => { editActionSecrets('webhookUrl', e.target.value); }} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx new file mode 100644 index 00000000000000..e314039f93af16 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx @@ -0,0 +1,166 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under 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 { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { ActionTypeRegistry } from '../../action_type_registry'; +import { registerBuiltInActionTypes } from './index'; +import { ActionTypeModel, ActionConnector } from '../../../types'; + +const ACTION_TYPE_ID = '.webhook'; +let actionTypeModel: ActionTypeModel; + +beforeAll(() => { + const actionTypeRegistry = new ActionTypeRegistry(); + registerBuiltInActionTypes({ actionTypeRegistry }); + const getResult = actionTypeRegistry.get(ACTION_TYPE_ID); + if (getResult !== null) { + actionTypeModel = getResult; + } +}); + +describe('actionTypeRegistry.get() works', () => { + test('action type static data is as expected', () => { + expect(actionTypeModel.id).toEqual(ACTION_TYPE_ID); + expect(actionTypeModel.iconClass).toEqual('logoWebhook'); + }); +}); + +describe('webhook connector validation', () => { + test('connector validation succeeds when connector config is valid', () => { + const actionConnector = { + secrets: { + user: 'user', + password: 'pass', + }, + id: 'test', + actionTypeId: '.email', + name: 'email', + config: { + method: 'PUT', + url: 'http:\\test', + headers: ['content-type: text'], + }, + } as ActionConnector; + + expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ + errors: { + url: [], + method: [], + user: [], + password: [], + }, + }); + }); + + test('connector validation fails when connector config is not valid', () => { + const actionConnector = { + secrets: { + user: 'user', + }, + id: 'test', + actionTypeId: '.email', + name: 'email', + config: { + method: 'PUT', + }, + } as ActionConnector; + + expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ + errors: { + url: ['Url is required.'], + method: [], + user: [], + password: ['Password is required.'], + }, + }); + }); +}); + +describe('webhook action params validation', () => { + test('action params validation succeeds when action params is valid', () => { + const actionParams = { + body: 'message {test}', + }; + + expect(actionTypeModel.validateParams(actionParams)).toEqual({ + errors: {}, + }); + }); +}); + +describe('WebhookActionConnectorFields renders', () => { + test('all connector fields is rendered', () => { + expect(actionTypeModel.actionConnectorFields).not.toBeNull(); + if (!actionTypeModel.actionConnectorFields) { + return; + } + const ConnectorFields = actionTypeModel.actionConnectorFields; + const actionConnector = { + secrets: { + user: 'user', + password: 'pass', + }, + id: 'test', + actionTypeId: '.email', + name: 'email', + config: { + method: 'PUT', + url: 'http:\\test', + headers: ['content-type: text'], + }, + } as ActionConnector; + const wrapper = mountWithIntl( + {}} + editActionSecrets={() => {}} + hasErrors={false} + /> + ); + expect(wrapper.find('[data-test-subj="webhookAddHeaderButton"]').length > 0).toBeTruthy(); + wrapper + .find('[data-test-subj="webhookAddHeaderButton"]') + .first() + .simulate('click'); + expect(wrapper.find('[data-test-subj="webhookHeadersKeyInput"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="webhookHeaderText"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="webhookHeadersValueInput"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="webhookMethodSelect"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="webhookUrlText"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="webhookUserInput"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="webhookPasswordInput"]').length > 0).toBeTruthy(); + }); +}); + +describe('WebhookParamsFields renders', () => { + test('all params fields is rendered', () => { + expect(actionTypeModel.actionParamsFields).not.toBeNull(); + if (!actionTypeModel.actionParamsFields) { + return; + } + const ParamsFields = actionTypeModel.actionParamsFields; + const actionParams = { + body: 'test message', + }; + const wrapper = mountWithIntl( + {}} + index={0} + hasErrors={false} + /> + ); + expect(wrapper.find('[data-test-subj="webhookBodyEditor"]').length > 0).toBeTruthy(); + expect( + wrapper + .find('[data-test-subj="webhookBodyEditor"]') + .first() + .prop('value') + ).toStrictEqual('test message'); + }); +}); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx index 0a593694f5f759..5b03edb1e3a79e 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx @@ -269,7 +269,7 @@ const WebhookActionConnectorFields: React.FunctionComponent { editActionConfig('url', e.target.value); }} @@ -349,6 +349,7 @@ const WebhookActionConnectorFields: React.FunctionComponent addHeader()} > { return ( - + {key}: From 6e7423833d33176fbadd292671852eadde4b09e0 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 13 Dec 2019 09:18:03 -0500 Subject: [PATCH 203/297] Remove test alert type --- x-pack/legacy/plugins/alerting/server/plugin.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/x-pack/legacy/plugins/alerting/server/plugin.ts b/x-pack/legacy/plugins/alerting/server/plugin.ts index a114f9e4e110cc..9889e01e0ca19e 100644 --- a/x-pack/legacy/plugins/alerting/server/plugin.ts +++ b/x-pack/legacy/plugins/alerting/server/plugin.ts @@ -118,14 +118,6 @@ export class Plugin { core.http.route(muteAlertInstanceRoute); core.http.route(unmuteAlertInstanceRoute); - // TODO: Remove, this is only for dev purposes and should be removed before branch is merged - alertTypeRegistry.register({ - id: 'test', - name: 'Test', - actionGroups: ['default'], - executor(): any {}, - }); - return { registerType: alertTypeRegistry.register.bind(alertTypeRegistry), }; From e193caa217cf1a5e525eba0e0445f2a61adacdb9 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 13 Dec 2019 09:35:50 -0500 Subject: [PATCH 204/297] Move create alert UI behind feature flag 'createAlertUiEnabled' --- x-pack/legacy/plugins/triggers_actions_ui/index.ts | 7 +++++++ .../sections/alerts_list/components/alerts_list.tsx | 5 +++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/index.ts index 66c5981527900f..1c94a7dc6a64ca 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/index.ts @@ -24,6 +24,7 @@ export function triggersActionsUI(kibana: any) { return Joi.object() .keys({ enabled: Joi.boolean().default(true), + createAlertUiEnabled: Joi.boolean().default(false), }) .default(); }, @@ -31,6 +32,12 @@ export function triggersActionsUI(kibana: any) { hacks: ['plugins/triggers_actions_ui/hacks/register'], managementSections: ['plugins/triggers_actions_ui'], styleSheetPaths: resolve(__dirname, 'public/index.scss'), + injectDefaultVars(server: Legacy.Server) { + const serverConfig = server.config(); + return { + createAlertUiEnabled: serverConfig.get('xpack.triggers_actions_ui.createAlertUiEnabled'), + }; + }, }, }); } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 5533a0be0d408e..8a26daa55c7df5 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -23,11 +23,12 @@ import { loadActionTypes } from '../../../lib/action_connector_api'; export const AlertsList: React.FunctionComponent = () => { const { - core: { http }, + core: { http, injectedMetadata }, plugins: { capabilities, toastNotifications }, } = useAppDependencies(); const canDelete = capabilities.get().alerting.delete; const canSave = capabilities.get().alerting.save; + const createAlertUiEnabled = injectedMetadata.getInjectedVar('createAlertUiEnabled'); const [actionTypes, setActionTypes] = useState([]); const [alertTypesIndex, setAlertTypesIndex] = useState(undefined); @@ -199,7 +200,7 @@ export const AlertsList: React.FunctionComponent = () => { />, ]; - if (canSave) { + if (canSave && createAlertUiEnabled) { toolsRight.push( Date: Fri, 13 Dec 2019 11:49:40 -0500 Subject: [PATCH 205/297] Fix functional tests --- .../apps/triggers_actions_ui/alerts.ts | 6 ++--- .../apps/triggers_actions_ui/connectors.ts | 2 ++ .../apps/triggers_actions_ui/home_page.ts | 16 ++++++++++++- x-pack/test/functional_with_es_ssl/config.ts | 3 ++- .../fixtures/plugins/alerts/index.ts | 24 +++++++++++++++++++ .../fixtures/plugins/alerts/package.json | 7 ++++++ .../page_objects/triggers_actions_ui_page.ts | 7 +++++- 7 files changed, 59 insertions(+), 6 deletions(-) create mode 100644 x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/index.ts create mode 100644 x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/package.json diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts index 37fb68d8a1df3c..571e90af6c1aa9 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts @@ -26,7 +26,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { enabled: true, name: generateUniqueKey(), tags: ['foo', 'bar'], - alertTypeId: 'test', + alertTypeId: 'test.noop', interval: '1m', throttle: '1m', actions: [], @@ -53,7 +53,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { { name: createdAlert.name, tagsText: 'foo, bar', - alertType: 'Test', + alertType: 'Test: Noop', interval: '1m', }, ]); @@ -69,7 +69,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { { name: createdAlert.name, tagsText: 'foo, bar', - alertType: 'Test', + alertType: 'Test: Noop', interval: '1m', }, ]); diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts index 8ec366c109fc55..d43b0691a0dd26 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts @@ -20,6 +20,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('Connectors', function() { before(async () => { await pageObjects.common.navigateToApp('triggersActions'); + const alertsTab = await testSubjects.find('connectorsTab'); + await alertsTab.click(); }); it('should create a connector', async () => { diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts index 2addfe9339e03c..0193b3cd0c2e29 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts @@ -23,8 +23,22 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const headingText = await pageObjects.triggersActionsUI.getSectionHeadingText(); expect(headingText).to.be('Alerts and actions'); + }); + + describe('Connectors tab', () => { + it('renders the connectors tab', async () => { + // Navigate to the connectors tab + pageObjects.triggersActionsUI.changeTabs('connectorsTab'); - await testSubjects.existOrFail('createActionButton'); + await pageObjects.header.waitUntilLoadingHasFinished(); + + // Verify url + const url = await browser.getCurrentUrl(); + expect(url).to.contain(`/connectors`); + + // Verify content + await testSubjects.existOrFail('actionsList'); + }); }); describe('Alerts tab', () => { diff --git a/x-pack/test/functional_with_es_ssl/config.ts b/x-pack/test/functional_with_es_ssl/config.ts index 3c1a6a1cdedcb5..d22043dfa7e3a1 100644 --- a/x-pack/test/functional_with_es_ssl/config.ts +++ b/x-pack/test/functional_with_es_ssl/config.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { resolve } from 'path'; +import { resolve, join } from 'path'; import { CA_CERT_PATH } from '@kbn/dev-utils'; import { FtrConfigProviderContext } from '@kbn/test/types/ftr'; import { services } from './services'; @@ -46,6 +46,7 @@ export default async function({ readConfigFile }: FtrConfigProviderContext) { ...xpackFunctionalConfig.get('kbnTestServer.serverArgs'), `--elasticsearch.hosts=https://${servers.elasticsearch.hostname}:${servers.elasticsearch.port}`, `--elasticsearch.ssl.certificateAuthorities=${CA_CERT_PATH}`, + `--plugin-path=${join(__dirname, 'fixtures', 'plugins', 'alerts')}`, ], }, }; diff --git a/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/index.ts b/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/index.ts new file mode 100644 index 00000000000000..df651c67c2c281 --- /dev/null +++ b/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/index.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 { AlertType } from '../../../../../legacy/plugins/alerting'; + +// eslint-disable-next-line import/no-default-export +export default function(kibana: any) { + return new kibana.Plugin({ + require: ['alerting'], + name: 'alerts', + init(server: any) { + const noopAlertType: AlertType = { + id: 'test.noop', + name: 'Test: Noop', + actionGroups: ['default'], + async executor() {}, + }; + server.plugins.alerting.setup.registerType(noopAlertType); + }, + }); +} diff --git a/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/package.json b/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/package.json new file mode 100644 index 00000000000000..836fa09855d8fd --- /dev/null +++ b/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/package.json @@ -0,0 +1,7 @@ +{ + "name": "alerts", + "version": "0.0.0", + "kibana": { + "version": "kibana" + } +} diff --git a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts index fbcd57b8ef95f3..8e89dedffdfcc7 100644 --- a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts +++ b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts @@ -17,7 +17,10 @@ export function TriggersActionsPageProvider({ getService }: FtrProviderContext) return await testSubjects.getVisibleText('appTitle'); }, async clickCreateConnectorButton() { - await testSubjects.click('createActionButton'); + const createBtn = await find.byCssSelector( + '[data-test-subj="createActionButton"],[data-test-subj="createFirstActionButton"]' + ); + await createBtn.click(); }, async searchConnectors(searchText: string) { const searchBox = await find.byCssSelector('[data-test-subj="actionsList"] .euiFieldSearch'); @@ -25,6 +28,7 @@ export function TriggersActionsPageProvider({ getService }: FtrProviderContext) await searchBox.clearValue(); await searchBox.type(searchText); await searchBox.pressKeys(ENTER_KEY); + await find.byCssSelector('[data-test-subj="actionsList"]:not(.euiBasicTable-loading)'); }, async searchAlerts(searchText: string) { const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); @@ -32,6 +36,7 @@ export function TriggersActionsPageProvider({ getService }: FtrProviderContext) await searchBox.clearValue(); await searchBox.type(searchText); await searchBox.pressKeys(ENTER_KEY); + await find.byCssSelector('[data-test-subj="alertsList"]:not(.euiBasicTable-loading)'); }, async getConnectorsList() { const table = await find.byCssSelector('[data-test-subj="actionsList"] table'); From 5b3220370607b6da86badf77940d97d3c03263d8 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 13 Dec 2019 16:38:37 -0500 Subject: [PATCH 206/297] Update codeowners --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 36a2cda841fa8b..f9100286b00f84 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -110,6 +110,7 @@ /x-pack/legacy/plugins/alerting @elastic/kibana-alerting-services /x-pack/legacy/plugins/actions @elastic/kibana-alerting-services /x-pack/legacy/plugins/task_manager @elastic/kibana-alerting-services +/x-pack/legacy/plugins/triggers_actions_ui @elastic/kibana-alerting-services # Design **/*.scss @elastic/kibana-design From 800b2de02c6fe234c3cc94ed8fa73b81fd26e4c3 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 13 Dec 2019 16:47:33 -0500 Subject: [PATCH 207/297] Update codeowners for tests --- .github/CODEOWNERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f9100286b00f84..fe46384c5f7484 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -111,6 +111,8 @@ /x-pack/legacy/plugins/actions @elastic/kibana-alerting-services /x-pack/legacy/plugins/task_manager @elastic/kibana-alerting-services /x-pack/legacy/plugins/triggers_actions_ui @elastic/kibana-alerting-services +/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui @elastic/kibana-alerting-services +/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts @elastic/kibana-alerting-services # Design **/*.scss @elastic/kibana-design From 9afd07a71df56578d7fa274b219342112ce37e71 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 16 Dec 2019 09:31:07 -0500 Subject: [PATCH 208/297] Revert watcher changes --- .../public/np_ready/application/models/action/logging_action.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/watcher/public/np_ready/application/models/action/logging_action.js b/x-pack/legacy/plugins/watcher/public/np_ready/application/models/action/logging_action.js index 29afadcf46cb1c..bef094b57cc8e2 100644 --- a/x-pack/legacy/plugins/watcher/public/np_ready/application/models/action/logging_action.js +++ b/x-pack/legacy/plugins/watcher/public/np_ready/application/models/action/logging_action.js @@ -70,7 +70,7 @@ export class LoggingAction extends BaseAction { }); static iconClass = 'logsApp'; static selectMessage = i18n.translate('xpack.watcher.models.loggingAction.selectMessageText', { - defaultMessage: 'Adds a log line with a message you define', + defaultMessage: 'Add an item to the logs.', }); static simulatePrompt = i18n.translate('xpack.watcher.models.loggingAction.simulateButtonLabel', { defaultMessage: 'Log a sample message', From 283da53b4f0f20c3d9559df9083bc23362589f59 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 16 Dec 2019 09:50:21 -0500 Subject: [PATCH 209/297] Fix type check failure --- .../sections/alerts_list/components/alerts_list.test.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx index 54fb06cc85efc6..67ca929c6931bd 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ import * as React from 'react'; -import { Fragment } from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { setAppDependencies } from '../../../app_dependencies'; import { coreMock } from '../../../../../../../../../../src/core/public/mocks'; From cafd43a4a54ed1995bcbea78cabba85a0597dc4d Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Mon, 16 Dec 2019 10:12:29 -0500 Subject: [PATCH 210/297] Fix unit test failures --- .../actions_connectors_list.test.tsx | 32 ++++---- .../components/alerts_list.test.tsx | 76 ++++++++++++++----- 2 files changed, 72 insertions(+), 36 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx index c109d6b161fc21..78e4d8f87c6871 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx @@ -48,10 +48,10 @@ describe('actions_connectors_list component empty', () => { capabilities: { get() { return { - actions: { - delete: true, - save: true, - show: true, + siem: { + 'actions:show': true, + 'actions:save': true, + 'actions:delete': true, }, }; }, @@ -134,10 +134,10 @@ describe('actions_connectors_list component with items', () => { capabilities: { get() { return { - actions: { - delete: true, - save: true, - show: true, + siem: { + 'actions:show': true, + 'actions:save': true, + 'actions:delete': true, }, }; }, @@ -208,10 +208,10 @@ describe('actions_connectors_list component empty with show only capability', () capabilities: { get() { return { - actions: { - delete: false, - save: false, - show: true, + siem: { + 'actions:show': true, + 'actions:save': false, + 'actions:delete': false, }, }; }, @@ -287,10 +287,10 @@ describe('actions_connectors_list with show only capability', () => { capabilities: { get() { return { - actions: { - delete: false, - save: false, - show: true, + siem: { + 'actions:show': true, + 'actions:save': false, + 'actions:delete': false, }, }; }, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx index 67ca929c6931bd..9c01cea20bad11 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx @@ -75,15 +75,24 @@ describe('alerts_list component empty', () => { data: [], }); const deps = { - core: coreMock.createStart(), + core: { + ...coreMock.createStart(), + injectedMetadata: { + getInjectedVar(name: string) { + if (name === 'createAlertUiEnabled') { + return true; + } + }, + }, + }, plugins: { capabilities: { get() { return { - alerting: { - delete: true, - save: true, - show: true, + siem: { + 'alerting:show': true, + 'alerting:save': true, + 'alerting:delete': true, }, }; }, @@ -184,15 +193,24 @@ describe('alerts_list component with items', () => { data: [], }); const deps = { - core: coreMock.createStart(), + core: { + ...coreMock.createStart(), + injectedMetadata: { + getInjectedVar(name: string) { + if (name === 'createAlertUiEnabled') { + return true; + } + }, + }, + }, plugins: { capabilities: { get() { return { - alerting: { - delete: true, - save: true, - show: true, + siem: { + 'alerting:show': true, + 'alerting:save': true, + 'alerting:delete': true, }, }; }, @@ -255,15 +273,24 @@ describe('alerts_list component empty with show only capability', () => { data: [], }); const deps = { - core: coreMock.createStart(), + core: { + ...coreMock.createStart(), + injectedMetadata: { + getInjectedVar(name: string) { + if (name === 'createAlertUiEnabled') { + return true; + } + }, + }, + }, plugins: { capabilities: { get() { return { - alerting: { - delete: false, - save: false, - show: true, + siem: { + 'alerting:show': true, + 'alerting:save': false, + 'alerting:delete': false, }, }; }, @@ -361,15 +388,24 @@ describe('alerts_list with show only capability', () => { data: [], }); const deps = { - core: coreMock.createStart(), + core: { + ...coreMock.createStart(), + injectedMetadata: { + getInjectedVar(name: string) { + if (name === 'createAlertUiEnabled') { + return true; + } + }, + }, + }, plugins: { capabilities: { get() { return { - alerting: { - delete: false, - save: false, - show: true, + siem: { + 'alerting:show': true, + 'alerting:save': false, + 'alerting:delete': false, }, }; }, From 7a8f191656bbe8a4e0f161d8e15690945d707aad Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 16 Dec 2019 08:38:53 -0800 Subject: [PATCH 211/297] Fixed typecheck failures --- .../sections/alert_add/alert_add.tsx | 12 +++++- .../alert_types/threshold/visualization.tsx | 43 +++++++++++-------- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 87af87fb845146..871f46d9135de7 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -51,6 +51,7 @@ import { } from '../../../types'; import { ACTION_GROUPS } from '../../constants/action_groups'; import { getTimeOptions } from '../../lib/get_time_options'; +import { SectionLoading } from '../../components/section_loading'; interface Props { refreshList: () => Promise; @@ -763,7 +764,16 @@ export const AlertAdd = ({ refreshList }: Props) => { - {actionTypeNodes} + {isLoadingActionTypes ? ( + + + + ) : ( + actionTypeNodes + )} ) : null} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx index 8f8215fd401183..b8154c54ca961f 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx @@ -6,6 +6,7 @@ import React, { Fragment, useEffect, useState } from 'react'; import { IUiSettingsClient } from 'kibana/public'; +import { i18n } from '@kbn/i18n'; import { AnnotationDomainTypes, Axis, @@ -98,9 +99,9 @@ interface Props { export const ThresholdVisualization: React.FunctionComponent = ({ alert }) => { const { core: { http, uiSettings }, + plugins: { toastNotifications }, } = useAppDependencies(); const [isLoading, setIsLoading] = useState(false); - const [isInitialRequest, setIsInitialRequest] = useState(false); const [error, setError] = useState(undefined); const [visualizationData, setVisualizationData] = useState>([]); @@ -136,22 +137,28 @@ export const ThresholdVisualization: React.FunctionComponent = ({ alert } const alertWithoutActions = { ...alert.params, actions: [], type: 'threshold' }; useEffect(() => { - // Prevent sending a second request on initial render. - if (isInitialRequest) { - return; - } - - async function loadVisualizationData() { - setIsLoading(true); - setVisualizationData( - await getThresholdAlertVisualizationData({ - model: alertWithoutActions, - visualizeOptions, - http, - }) - ); - } - loadVisualizationData(); + (async () => { + try { + setIsLoading(true); + setVisualizationData( + await getThresholdAlertVisualizationData({ + model: alertWithoutActions, + visualizeOptions, + http, + }) + ); + } catch (e) { + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.triggersActionsUI.sections.alertAdd.unableToLoadVisualizationMessage', + { defaultMessage: 'Unable to load visualization' } + ), + }); + setError(e); + } finally { + setIsLoading(false); + } + })(); /* eslint-disable react-hooks/exhaustive-deps */ }, [ index, @@ -170,7 +177,7 @@ export const ThresholdVisualization: React.FunctionComponent = ({ alert } ]); /* eslint-enable react-hooks/exhaustive-deps */ - if (isInitialRequest && isLoading) { + if (isLoading) { return ( } From dfe9adf6a085557558d83bdf82574b53cb04802e Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 16 Dec 2019 09:57:16 -0800 Subject: [PATCH 212/297] Fixed language check errors --- .../components/builtin_action_types/webhook.tsx | 6 +++--- .../action_connector_form.tsx | 4 ++-- .../connector_add_flyout.tsx | 10 +++++----- .../connector_edit_flyout.tsx | 4 ++-- .../sections/alert_add/alert_add.tsx | 17 +++++++++-------- 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx index 5b03edb1e3a79e..b1511815be79c9 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx @@ -353,8 +353,8 @@ const WebhookActionConnectorFields: React.FunctionComponent addHeader()} > @@ -366,7 +366,7 @@ const WebhookActionConnectorFields: React.FunctionComponent
diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index 7540e7fdb2c651..74ddb011f59d1e 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -113,7 +113,7 @@ export const ActionConnectorForm = ({ if (connector.id === undefined) { savedConnector = await createActionConnector({ http, connector }); message = i18n.translate( - 'xpack.triggersActionsUI.sections.actionConnectorForm.saveSuccessNotificationText', + 'xpack.triggersActionsUI.sections.actionConnectorForm.createSuccessNotificationText', { defaultMessage: "Created '{connectorName}'", values: { @@ -124,7 +124,7 @@ export const ActionConnectorForm = ({ } else { savedConnector = await updateActionConnector({ http, connector, id: connector.id }); message = i18n.translate( - 'xpack.triggersActionsUI.sections.actionConnectorForm.saveSuccessNotificationText', + 'xpack.triggersActionsUI.sections.actionConnectorForm.updateSuccessNotificationText', { defaultMessage: "Updated '{connectorName}'", values: { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx index 6158a0722b2c11..d4a02b67d6ccf9 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx @@ -72,8 +72,8 @@ export const ConnectorAddFlyout = () => {

{actionType.name}

@@ -84,10 +84,10 @@ export const ConnectorAddFlyout = () => { ) : ( -

+

diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx index 80d240b40ebe13..46094fd59aac53 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx @@ -46,8 +46,8 @@ export const ConnectorEditFlyout = ({ connector }: ConnectorEditProps) => {

diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 871f46d9135de7..edb1a959967276 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -346,7 +346,7 @@ export const AlertAdd = ({ refreshList }: Props) => {
@@ -361,7 +361,7 @@ export const AlertAdd = ({ refreshList }: Props) => { }} > @@ -432,8 +432,9 @@ export const AlertAdd = ({ refreshList }: Props) => {
@@ -526,7 +527,7 @@ export const AlertAdd = ({ refreshList }: Props) => {
@@ -584,7 +585,7 @@ export const AlertAdd = ({ refreshList }: Props) => {

@@ -757,7 +758,7 @@ export const AlertAdd = ({ refreshList }: Props) => {
@@ -767,8 +768,8 @@ export const AlertAdd = ({ refreshList }: Props) => { {isLoadingActionTypes ? ( ) : ( From b7710c7efa2301c337f8039742b496cc5867e7bd Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 16 Dec 2019 13:11:02 -0800 Subject: [PATCH 213/297] Did some text/type fixes --- .../public/application/lib/get_time_options.test.ts | 2 +- .../action_connector_form/action_connector_form.tsx | 2 +- .../action_connector_form/connector_add_flyout.tsx | 8 ++++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/get_time_options.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/get_time_options.test.ts index 70b5999001ddf0..534e461d5b2346 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/get_time_options.test.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/get_time_options.test.ts @@ -26,7 +26,7 @@ describe('get_time_options', () => { ]); }); - test('if ', () => { + test('if getTimeFieldOptions return only date type fields', () => { const timeOnlyTypeFields = getTimeFieldOptions( [ { type: 'date', name: 'order_date' }, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index 74ddb011f59d1e..8c47a698d72ad4 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -29,7 +29,7 @@ import { ActionConnector, IErrorObject } from '../../../types'; import { hasSaveActionsCapability } from '../../lib/capabilities'; interface ActionConnectorProps { - initialConnector: any; + initialConnector: ActionConnector; actionTypeName: string; setFlyoutVisibility: React.Dispatch>; } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx index d4a02b67d6ccf9..0d49437d62284e 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx @@ -17,7 +17,7 @@ import { import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; import { ActionTypeMenu } from './action_type_menu'; import { ActionConnectorForm } from './action_connector_form'; -import { ActionType } from '../../../types'; +import { ActionType, ActionConnector } from '../../../types'; import { useAppDependencies } from '../../app_dependencies'; export const ConnectorAddFlyout = () => { @@ -46,7 +46,11 @@ export const ConnectorAddFlyout = () => { currentForm = ; } else { actionTypeModel = actionTypeRegistry.get(actionType.id); - const initialConnector = { actionTypeId: actionType.id, config: {}, secrets: {} }; + const initialConnector = { + actionTypeId: actionType.id, + config: {}, + secrets: {}, + } as ActionConnector; currentForm = ( Date: Mon, 16 Dec 2019 14:10:54 -0800 Subject: [PATCH 214/297] Fixed typecheck --- .../action_connector_form/action_connector_form.test.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx index 353e36a64542a1..9cf2913bf5e18a 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx @@ -11,7 +11,7 @@ import { ReactWrapper } from 'enzyme'; import { act } from 'react-dom/test-utils'; import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; import { actionTypeRegistryMock } from '../../action_type_registry.mock'; -import { ValidationResult } from '../../../types'; +import { ValidationResult, ActionConnector } from '../../../types'; import { ActionConnectorForm } from './action_connector_form'; jest.mock('../../context/actions_connectors_context'); const actionTypeRegistry = actionTypeRegistryMock.create(); @@ -57,7 +57,11 @@ describe('action_connector_form', () => { actionTypeRegistry.get.mockReturnValue(actionType); actionTypeRegistry.has.mockReturnValue(true); - const initialConnector = { actionTypeId: actionType.id, config: {}, secrets: {} }; + const initialConnector = { + actionTypeId: actionType.id, + config: {}, + secrets: {}, + } as ActionConnector; await act(async () => { wrapper = mountWithIntl( From 17500c02638b30e2820407d4120da3cf4bf80541 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 16 Dec 2019 14:18:45 -0800 Subject: [PATCH 215/297] Fixed unit tests warning --- .../components/builtin_action_types/webhook.tsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx index b1511815be79c9..ca70326d212f28 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx @@ -382,7 +382,17 @@ const WebhookActionConnectorFields: React.FunctionComponent{headers[key]} - removeHeader(key)} /> + removeHeader(key)} + /> ); From 62dd2bada09e34cab0bdf015f2e5bb9e58b6f83a Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 17 Dec 2019 11:16:56 -0500 Subject: [PATCH 216/297] Fix failing functional tests --- .../apps/triggers_actions_ui/connectors.ts | 4 ++-- .../page_objects/triggers_actions_ui_page.ts | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts index d43b0691a0dd26..dbc391ce8ce633 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts @@ -141,7 +141,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const deleteConnectorBtn = await testSubjects.find('deleteConnector'); await deleteConnectorBtn.click(); - await find.byCssSelector('[data-test-subj="actionsTable"]:not(.euiBasicTable-loading)'); + await pageObjects.triggersActionsUI.searchConnectors(connectorName); const searchResultsAfterDelete = await pageObjects.triggersActionsUI.getConnectorsList(); expect(searchResultsAfterDelete.length).to.eql(0); @@ -180,7 +180,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const bulkDeleteBtn = await testSubjects.find('bulkDelete'); await bulkDeleteBtn.click(); - await find.byCssSelector('[data-test-subj="actionsTable"]:not(.euiBasicTable-loading)'); + await pageObjects.triggersActionsUI.searchConnectors(connectorName); const searchResultsAfterDelete = await pageObjects.triggersActionsUI.getConnectorsList(); expect(searchResultsAfterDelete.length).to.eql(0); diff --git a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts index 8e89dedffdfcc7..44672228a372af 100644 --- a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts +++ b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts @@ -28,7 +28,9 @@ export function TriggersActionsPageProvider({ getService }: FtrProviderContext) await searchBox.clearValue(); await searchBox.type(searchText); await searchBox.pressKeys(ENTER_KEY); - await find.byCssSelector('[data-test-subj="actionsList"]:not(.euiBasicTable-loading)'); + await find.byCssSelector( + '.euiBasicTable[data-test-subj="actionsTable"]:not(.euiBasicTable-loading)' + ); }, async searchAlerts(searchText: string) { const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); @@ -36,7 +38,9 @@ export function TriggersActionsPageProvider({ getService }: FtrProviderContext) await searchBox.clearValue(); await searchBox.type(searchText); await searchBox.pressKeys(ENTER_KEY); - await find.byCssSelector('[data-test-subj="alertsList"]:not(.euiBasicTable-loading)'); + await find.byCssSelector( + '.euiBasicTable[data-test-subj="alertsList"]:not(.euiBasicTable-loading)' + ); }, async getConnectorsList() { const table = await find.byCssSelector('[data-test-subj="actionsList"] table'); From 871732403d781017db27f15441b91bd40a56d1ff Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 18 Dec 2019 10:29:53 -0500 Subject: [PATCH 217/297] Fix registry tests to have cleaner diff when it fails --- .../application/action_type_registry.test.ts | 26 +++++++++---------- .../application/alert_type_registry.test.ts | 21 +++++++-------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.test.ts index c8b74fb6b7de45..ef2dfae9d88c3a 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.test.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.test.ts @@ -73,22 +73,22 @@ describe('list()', () => { const actionTypeRegistry = new ActionTypeRegistry(); actionTypeRegistry.register(getTestActionType()); const actionTypes = actionTypeRegistry.list(); - expect(JSON.stringify(actionTypes)).toEqual( - JSON.stringify([ - { + expect(actionTypes).toEqual([ + { + id: 'my-action-type', + name: 'my-action-type', + iconClass: 'test', + actionType: { id: 'my-action-type', - name: 'my-action-type', iconClass: 'test', - actionType: { - id: 'my-action-type', - iconClass: 'test', - selectMessage: 'test', - actionConnectorFields: null, - actionParamsFields: null, - }, + selectMessage: 'test', + actionConnectorFields: null, + actionParamsFields: null, + validateConnector: actionTypes[0].actionType.validateConnector, + validateParams: actionTypes[0].actionType.validateParams, }, - ]) - ); + }, + ]); }); }); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.test.ts index e5613b88516ba1..a19ee937996f91 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.test.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.test.ts @@ -70,21 +70,20 @@ describe('list()', () => { const alertTypeRegistry = new AlertTypeRegistry(); alertTypeRegistry.register(getTestAlertType()); const alertTypes = alertTypeRegistry.list(); - expect(JSON.stringify(alertTypes)).toEqual( - JSON.stringify([ - { + expect(alertTypes).toEqual([ + { + id: 'test-alet-type', + name: 'Test alert type', + iconClass: 'icon', + alertType: { id: 'test-alet-type', name: 'Test alert type', iconClass: 'icon', - alertType: { - id: 'test-alet-type', - name: 'Test alert type', - iconClass: 'icon', - alertParamsExpression: ExpressionComponent, - }, + alertParamsExpression: ExpressionComponent, + validate: alertTypes[0].alertType.validate, }, - ]) - ); + }, + ]); }); }); From b47e464f6552e8b7b35559c662af1aa50ae01673 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 18 Dec 2019 10:30:49 -0500 Subject: [PATCH 218/297] Make DEFAULT_SECTION a Section type --- .../triggers_actions_ui/np_ready/public/application/app.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx index 2324978c8e75a6..06115180da732c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx @@ -46,7 +46,7 @@ export const AppWithoutRouter = ({ sectionsRegex }: any) => { plugins: { capabilities }, } = useAppDependencies(); const canShowAlerts = hasShowAlertsCapability(capabilities.get()); - const DEFAULT_SECTION = canShowAlerts ? 'alerts' : 'connectors'; + const DEFAULT_SECTION: Section = canShowAlerts ? 'alerts' : 'connectors'; return ( Date: Wed, 18 Dec 2019 10:31:25 -0500 Subject: [PATCH 219/297] Remove unused constructor --- .../triggers_actions_ui/np_ready/public/application/app.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx index 06115180da732c..e4bf534df4791d 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx @@ -20,9 +20,6 @@ class ShareRouter extends Component { }).isRequired, }).isRequired, }; - constructor(props: any, context?: any) { - super(props, context); - } render() { return this.props.children; From 731de1fd7fc964b1d1e41c7bd8932bb7345dc77d Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 18 Dec 2019 10:32:04 -0500 Subject: [PATCH 220/297] Make app dependency error string same line --- .../np_ready/public/application/app_dependencies.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app_dependencies.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app_dependencies.tsx index dd2746e115f4b0..76007867ecf81c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app_dependencies.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app_dependencies.tsx @@ -17,8 +17,9 @@ export const setAppDependencies = (deps: AppDependencies) => { export const useAppDependencies = () => { if (!DependenciesContext) { - throw new Error(`The app dependencies Context hasn't been set. - Use the "setAppDependencies()" method when bootstrapping the app.`); + throw new Error( + `The app dependencies Context hasn't been set. Use the "setAppDependencies()" method when bootstrapping the app.` + ); } return useContext(DependenciesContext); }; From 6b23551355885674a5cc09853a0514378d8e5cec Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 18 Dec 2019 10:38:39 -0500 Subject: [PATCH 221/297] Remove unused error pages --- .../components/page_error/index.ts | 1 - .../components/page_error/page_error.tsx | 35 ------------------ .../page_error/page_error_forbidden.tsx | 27 -------------- .../page_error/page_error_not_exist.tsx | 36 ------------------- 4 files changed, 99 deletions(-) delete mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/page_error.tsx delete mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx delete mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/index.ts index c9ed4d3f1d77e7..3464f73ceac067 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/index.ts @@ -4,6 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export { PageError } from './page_error'; export { SectionError } from './section_error'; export { ErrableFormRow } from './form_errors'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/page_error.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/page_error.tsx deleted file mode 100644 index 822e828e59de84..00000000000000 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/page_error.tsx +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; - -import { PageErrorNotExist } from './page_error_not_exist'; -import { PageErrorForbidden } from './page_error_forbidden'; - -export function getPageErrorCode(errorOrErrors: any) { - const errors = Array.isArray(errorOrErrors) ? errorOrErrors : [errorOrErrors]; - const firstError = errors.find((error: any) => { - if (error) { - return [403, 404].includes(error.status); - } - return false; - }); - - if (firstError) { - return firstError.status; - } -} - -export function PageError({ errorCode, id }: { errorCode?: any; id?: any }) { - switch (errorCode) { - case 404: - return ; - - case 403: - default: - return ; - } -} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx deleted file mode 100644 index bffce8746f5b60..00000000000000 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/page_error_forbidden.tsx +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; - -import { EuiEmptyPrompt } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; - -export function PageErrorForbidden() { - return ( - - -
- } - /> - ); -} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx deleted file mode 100644 index 0cd5759aff141c..00000000000000 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/page_error_not_exist.tsx +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; - -import { EuiEmptyPrompt } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; - -export function PageErrorNotExist({ id }: { id: any }) { - return ( - - - - } - body={ -

- -

- } - /> - ); -} From 79b0e3f016787ab982c9a4f4d32a7014134b3c3b Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 18 Dec 2019 10:46:22 -0500 Subject: [PATCH 222/297] Set interface to alerts context --- .../application/context/actions_connectors_context.tsx | 3 ++- .../public/application/context/alerts_context.tsx | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_connectors_context.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_connectors_context.tsx index ac49e9c2c77ece..95761b2b83248c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_connectors_context.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_connectors_context.tsx @@ -6,7 +6,6 @@ import React from 'react'; import { ActionType } from '../../types'; -export const ActionsConnectorsContext = React.createContext({} as IActionsConnectorsContext); export interface IActionsConnectorsContext { addFlyoutVisible: boolean; @@ -16,3 +15,5 @@ export interface IActionsConnectorsContext { actionTypesIndex: Record | undefined; reloadConnectors: () => Promise; } + +export const ActionsConnectorsContext = React.createContext({} as IActionsConnectorsContext); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/alerts_context.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/alerts_context.tsx index 3ec66dfe2bc81a..b31cf8ea5169ed 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/alerts_context.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/alerts_context.tsx @@ -5,4 +5,10 @@ */ import React from 'react'; -export const AlertsContext = React.createContext({} as any); + +export interface IAlertsContext { + alertFlyoutVisible: boolean; + setAlertFlyoutVisibility: React.Dispatch>; +} + +export const AlertsContext = React.createContext({} as IAlertsContext); From bd68e931a317006bc20abc7e83ec45f140ec0407 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 18 Dec 2019 10:50:22 -0500 Subject: [PATCH 223/297] Fix action_connector_form.tsx label --- .../sections/action_connector_form/action_connector_form.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index 8c47a698d72ad4..724242f844c9e4 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -91,7 +91,7 @@ export const ActionConnectorForm = ({ i18n.translate( 'xpack.triggersActionsUI.sections.actionConnectorForm.error.requiredNameText', { - defaultMessage: 'Description is required.', + defaultMessage: 'Name is required.', } ) ); @@ -152,7 +152,7 @@ export const ActionConnectorForm = ({ title={ } error={serverError} From 87e35e83515b3ac6a476b5cc13a55abfccf2577a Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 18 Dec 2019 10:52:27 -0500 Subject: [PATCH 224/297] Fix label in connector_add_flyout.tsx --- .../sections/action_connector_form/connector_add_flyout.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx index 0d49437d62284e..f29b056b4f559d 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx @@ -76,10 +76,12 @@ export const ConnectorAddFlyout = () => {

- {actionType.name}

From f484f39b4766f40ce985ca06c37b9da7bf2a6383 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 18 Dec 2019 10:53:09 -0500 Subject: [PATCH 225/297] Fix label in alert_add.tsx --- .../public/application/sections/alert_add/alert_add.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index edb1a959967276..5728eb39a87019 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -206,7 +206,7 @@ export const AlertAdd = ({ refreshList }: Props) => { title: i18n.translate( 'xpack.triggersActionsUI.sections.alertAdd.unableToLoadActionsMessage', { - defaultMessage: 'Unable to load actions', + defaultMessage: 'Unable to load connectors', } ), }); From 016442fefc3683fadfa7c3c7b16cc2218ea3566b Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 18 Dec 2019 11:09:45 -0500 Subject: [PATCH 226/297] Move alert_types to builtin_alert_types --- .../builtin_alert_types}/index.ts | 4 ++-- .../threshold/expression.tsx | 16 ++++++++-------- .../builtin_alert_types/threshold}/types.ts | 0 .../threshold/visualization.tsx | 8 ++++---- .../np_ready/public/plugin.ts | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/{sections/alert_add/alert_types => components/builtin_alert_types}/index.ts (80%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/{sections/alert_add/alert_types => components/builtin_alert_types}/threshold/expression.tsx (98%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/{sections/alert_add/alert_types => components/builtin_alert_types/threshold}/types.ts (100%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/{sections/alert_add/alert_types => components/builtin_alert_types}/threshold/visualization.tsx (97%) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/index.ts similarity index 80% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/index.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/index.ts index 17fdffb40d2c17..f5e6dd46df2bfb 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/index.ts @@ -5,9 +5,9 @@ */ import { getActionType as getThresholdAlertType } from './threshold/expression'; -import { AlertTypeRegistry } from '../../../alert_type_registry'; +import { AlertTypeRegistry } from '../../alert_type_registry'; -export function registerAlertTypes({ +export function registerBuiltInAlertTypes({ alertTypeRegistry, }: { alertTypeRegistry: AlertTypeRegistry; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx similarity index 98% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx index e0b857b04420f8..90f3db51ab93b0 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/expression.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx @@ -21,18 +21,18 @@ import { EuiText, EuiCallOut, } from '@elastic/eui'; -import { AlertTypeModel, Alert, ValidationResult } from '../../../../../types'; -import { Comparator, AggregationType, GroupByType } from '../types'; -import { COMPARATORS, AGGREGATION_TYPES } from '../../../../constants'; +import { AlertTypeModel, Alert, ValidationResult } from '../../../../types'; +import { Comparator, AggregationType, GroupByType } from './types'; +import { COMPARATORS, AGGREGATION_TYPES } from '../../../constants'; import { getMatchingIndicesForThresholdAlertType, getThresholdAlertTypeFields, loadIndexPatterns, -} from '../../../../lib/api'; -import { useAppDependencies } from '../../../../app_dependencies'; -import { ErrableFormRow } from '../../../../components/page_error'; -import { getTimeOptions, getTimeFieldOptions } from '../../../../lib/get_time_options'; -import { getTimeUnitLabel } from '../../../../lib/get_time_unit_label'; +} from '../../../lib/api'; +import { useAppDependencies } from '../../../app_dependencies'; +import { ErrableFormRow } from '../../../components/page_error'; +import { getTimeOptions, getTimeFieldOptions } from '../../../lib/get_time_options'; +import { getTimeUnitLabel } from '../../../lib/get_time_unit_label'; import { ThresholdVisualization } from './visualization'; const DEFAULT_VALUES = { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/types.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/types.ts similarity index 100% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/types.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/types.ts diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx similarity index 97% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx index b8154c54ca961f..3f272c9fa219e4 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_types/threshold/visualization.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx @@ -26,11 +26,11 @@ import moment from 'moment-timezone'; import { EuiCallOut, EuiLoadingChart, EuiSpacer, EuiEmptyPrompt, EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { npStart } from 'ui/new_platform'; -import { getThresholdAlertVisualizationData } from '../../../../lib/api'; +import { getThresholdAlertVisualizationData } from '../../../lib/api'; import { comparators, aggregationTypes } from './expression'; -import { useAppDependencies } from '../../../../app_dependencies'; -import { SectionError } from '../../../../components/page_error/section_error'; -import { Alert } from '../../../../../types'; +import { useAppDependencies } from '../../../app_dependencies'; +import { SectionError } from '../../../components/page_error/section_error'; +import { Alert } from '../../../../types'; const customTheme = () => { return { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts index 4d3f0212a98234..b4b740cefa8a0b 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts @@ -23,7 +23,7 @@ import { docTitleService } from './application/lib/doc_title'; import { ActionTypeRegistry } from './application/action_type_registry'; import { registerBuiltInActionTypes } from './application/components/builtin_action_types'; import { AlertTypeRegistry } from './application/alert_type_registry'; -import { registerAlertTypes } from './application/sections/alert_add/alert_types'; +import { registerBuiltInAlertTypes } from './application/components/builtin_alert_types'; import { setSavedObjectsClient } from './application/lib/api'; import { hasShowActionsCapability, hasShowAlertsCapability } from './application/lib/capabilities'; @@ -63,7 +63,7 @@ export class Plugin implements CorePlugin { actionTypeRegistry: this.actionTypeRegistry, }); - registerAlertTypes({ + registerBuiltInAlertTypes({ alertTypeRegistry: this.alertTypeRegistry, }); From 2a77efef4996797f74821928458a6f18f9da3be3 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 18 Dec 2019 11:26:45 -0500 Subject: [PATCH 227/297] Move some threshold constants into threshold folder --- .../threshold}/constants/aggregation_types.ts | 0 .../threshold}/constants/comparators.ts | 0 .../threshold/constants/index.ts} | 15 ++------------- .../builtin_alert_types/threshold/expression.tsx | 2 +- .../public/application/constants/index.ts | 3 --- 5 files changed, 3 insertions(+), 17 deletions(-) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/{ => components/builtin_alert_types/threshold}/constants/aggregation_types.ts (100%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/{ => components/builtin_alert_types/threshold}/constants/comparators.ts (100%) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/{constants/expression_fields.ts => components/builtin_alert_types/threshold/constants/index.ts} (50%) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/aggregation_types.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/constants/aggregation_types.ts similarity index 100% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/aggregation_types.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/constants/aggregation_types.ts diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/comparators.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/constants/comparators.ts similarity index 100% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/comparators.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/constants/comparators.ts diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/expression_fields.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/constants/index.ts similarity index 50% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/expression_fields.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/constants/index.ts index f4ddf3f1982ab6..f88ee5ee23f901 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/expression_fields.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/constants/index.ts @@ -4,16 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export const expressionFields = [ - 'aggType', - 'aggField', - 'termSize', - 'termField', - 'thresholdComparator', - 'timeWindowSize', - 'timeWindowUnit', - 'triggerIntervalSize', - 'triggerIntervalUnit', - 'threshold', - 'groupBy', -]; +export { COMPARATORS } from './comparators'; +export { AGGREGATION_TYPES } from './aggregation_types'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx index 90f3db51ab93b0..769501a0342c81 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx @@ -23,7 +23,7 @@ import { } from '@elastic/eui'; import { AlertTypeModel, Alert, ValidationResult } from '../../../../types'; import { Comparator, AggregationType, GroupByType } from './types'; -import { COMPARATORS, AGGREGATION_TYPES } from '../../../constants'; +import { AGGREGATION_TYPES, COMPARATORS } from './constants'; import { getMatchingIndicesForThresholdAlertType, getThresholdAlertTypeFields, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/index.ts index 69ab29f4297aed..4c9feaadd3c29c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/index.ts @@ -14,10 +14,7 @@ export const routeToHome = `${BASE_PATH}`; export const routeToConnectors = `${BASE_PATH}/connectors`; export const routeToAlerts = `${BASE_PATH}/alerts`; -export { COMPARATORS } from './comparators'; -export { AGGREGATION_TYPES } from './aggregation_types'; export { TIME_UNITS } from './time_units'; -export { expressionFields } from './expression_fields'; export const SORT_ORDERS: { [key: string]: string } = { ASCENDING: 'asc', DESCENDING: 'desc', From 391659d09975b599c0ce0bc28ea5bde069dfab22 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Wed, 18 Dec 2019 11:33:05 -0500 Subject: [PATCH 228/297] Move api.ts within threshold folder --- .../components/builtin_alert_types/threshold/expression.tsx | 2 +- .../{ => components/builtin_alert_types/threshold}/lib/api.ts | 0 .../components/builtin_alert_types/threshold/visualization.tsx | 2 +- .../plugins/triggers_actions_ui/np_ready/public/plugin.ts | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/{ => components/builtin_alert_types/threshold}/lib/api.ts (100%) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx index 769501a0342c81..c08dbdbef98dff 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx @@ -28,7 +28,7 @@ import { getMatchingIndicesForThresholdAlertType, getThresholdAlertTypeFields, loadIndexPatterns, -} from '../../../lib/api'; +} from './lib/api'; import { useAppDependencies } from '../../../app_dependencies'; import { ErrableFormRow } from '../../../components/page_error'; import { getTimeOptions, getTimeFieldOptions } from '../../../lib/get_time_options'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/lib/api.ts similarity index 100% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/api.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/lib/api.ts diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx index 3f272c9fa219e4..1f49c465832106 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx @@ -26,7 +26,7 @@ import moment from 'moment-timezone'; import { EuiCallOut, EuiLoadingChart, EuiSpacer, EuiEmptyPrompt, EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { npStart } from 'ui/new_platform'; -import { getThresholdAlertVisualizationData } from '../../../lib/api'; +import { getThresholdAlertVisualizationData } from './lib/api'; import { comparators, aggregationTypes } from './expression'; import { useAppDependencies } from '../../../app_dependencies'; import { SectionError } from '../../../components/page_error/section_error'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts index b4b740cefa8a0b..d53e4148699080 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts @@ -24,7 +24,7 @@ import { ActionTypeRegistry } from './application/action_type_registry'; import { registerBuiltInActionTypes } from './application/components/builtin_action_types'; import { AlertTypeRegistry } from './application/alert_type_registry'; import { registerBuiltInAlertTypes } from './application/components/builtin_alert_types'; -import { setSavedObjectsClient } from './application/lib/api'; +import { setSavedObjectsClient } from './application/components/builtin_alert_types/threshold/lib/api'; import { hasShowActionsCapability, hasShowAlertsCapability } from './application/lib/capabilities'; export type Setup = void; From 7e6c7ce9657e81835c43c37c5e196e17d65ff9bc Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 18 Dec 2019 10:55:27 -0800 Subject: [PATCH 229/297] Removed duplication logic from action type and alert type registry list --- .../application/action_type_registry.test.ts | 15 +++++---------- .../public/application/action_type_registry.ts | 7 +------ .../application/alert_type_registry.test.ts | 9 ++------- .../public/application/alert_type_registry.ts | 7 +------ .../application/sections/alert_add/alert_add.tsx | 6 +++--- .../alerts_list/components/alerts_list.test.tsx | 11 +++-------- 6 files changed, 15 insertions(+), 40 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.test.ts index ef2dfae9d88c3a..aa3116637bb634 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.test.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.test.ts @@ -76,17 +76,12 @@ describe('list()', () => { expect(actionTypes).toEqual([ { id: 'my-action-type', - name: 'my-action-type', iconClass: 'test', - actionType: { - id: 'my-action-type', - iconClass: 'test', - selectMessage: 'test', - actionConnectorFields: null, - actionParamsFields: null, - validateConnector: actionTypes[0].actionType.validateConnector, - validateParams: actionTypes[0].actionType.validateParams, - }, + selectMessage: 'test', + actionConnectorFields: null, + actionParamsFields: null, + validateConnector: actionTypes[0].validateConnector, + validateParams: actionTypes[0].validateParams, }, ]); }); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.ts index c9c8b30c60a49f..c886ada04db5eb 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.ts @@ -48,11 +48,6 @@ export class ActionTypeRegistry { } public list() { - return Array.from(this.actionTypes).map(([actionTypeId, actionType]) => ({ - id: actionTypeId, - name: actionType.id, - iconClass: actionType.iconClass, - actionType, - })); + return Array.from(this.actionTypes).map(([actionTypeId, actionType]) => actionType); } } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.test.ts index a19ee937996f91..c581136b80dbbf 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.test.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.test.ts @@ -75,13 +75,8 @@ describe('list()', () => { id: 'test-alet-type', name: 'Test alert type', iconClass: 'icon', - alertType: { - id: 'test-alet-type', - name: 'Test alert type', - iconClass: 'icon', - alertParamsExpression: ExpressionComponent, - validate: alertTypes[0].alertType.validate, - }, + alertParamsExpression: ExpressionComponent, + validate: alertTypes[0].validate, }, ]); }); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.ts index 62d0ab02de34e9..968145eac7895f 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.ts @@ -39,11 +39,6 @@ export class AlertTypeRegistry { } public list() { - return Array.from(this.alertTypes).map(([alertTypeId, alertType]) => ({ - id: alertTypeId, - name: alertType.name, - iconClass: alertType.iconClass, - alertType, - })); + return Array.from(this.alertTypes).map(([alertTypeId, alertType]) => alertType); } } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 5728eb39a87019..5307649bd1ef6f 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -299,7 +299,7 @@ export const AlertAdd = ({ refreshList }: Props) => { label={item.name} onClick={() => { setAlertProperty('alertTypeId', item.id); - setAlertType(item.alertType); + setAlertType(item); }} > @@ -311,8 +311,8 @@ export const AlertAdd = ({ refreshList }: Props) => { return ( addActionType(item.actionType)} + label={actionTypesIndex ? actionTypesIndex[item.id].name : item.id} + onClick={() => addActionType(item)} > diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx index 9c01cea20bad11..9fe274803ca75b 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx @@ -30,15 +30,10 @@ const alertType = { id: 'test_alert_type', name: 'some alert type', iconClass: 'test', - alertType: { - id: 'test_alert_type', - name: 'some alert type', - iconClass: 'test', - validate: (): ValidationResult => { - return { errors: {} }; - }, - alertParamsExpression: () => null, + validate: (): ValidationResult => { + return { errors: {} }; }, + alertParamsExpression: () => null, }; alertTypeRegistry.list.mockReturnValue([alertType]); actionTypeRegistry.list.mockReturnValue([]); From 8eadea7aa4d229d838c31aee08975f712bc5b168 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 18 Dec 2019 13:39:39 -0800 Subject: [PATCH 230/297] Fixed email action type test and adjusted validation to support arrays ony --- .../components/builtin_action_types/email.test.tsx | 6 +++--- .../application/components/builtin_action_types/email.tsx | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx index 872065f8b540fd..de0991b5810b5c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx @@ -99,8 +99,8 @@ describe('connector validation', () => { describe('action params validation', () => { test('action params validation succeeds when action params is valid', () => { const actionParams = { - to: 'test@test.com', - cc: 'test1@test.com', + to: [], + cc: ['test1@test.com'], message: 'message {test}', subject: 'test', }; @@ -118,7 +118,7 @@ describe('action params validation', () => { test('action params validation fails when action params is not valid', () => { const actionParams = { - to: 'test@test.com', + to: ['test@test.com'], subject: 'test', }; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx index ea10f7a858d989..2df214dba99598 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx @@ -106,9 +106,9 @@ export function getActionType(): ActionTypeModel { }; validationResult.errors = errors; if ( - (!actionParams.to || actionParams.to.length === 0) && - (!actionParams.cc || actionParams.cc.length === 0) && - (!actionParams.bcc || actionParams.bcc.length === 0) + (!actionParams.to || !(actionParams.to instanceof Array) || actionParams.to.length === 0) && + (!actionParams.cc || !(actionParams.cc instanceof Array) || actionParams.cc.length === 0) && + (!actionParams.bcc || !(actionParams.bcc instanceof Array) || actionParams.bcc.length === 0) ) { const errorText = i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredEntryText', From c505ec58725923fb341c713e809349dacc15491d Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 18 Dec 2019 14:45:54 -0800 Subject: [PATCH 231/297] Added missing connector fields for email action type --- .../builtin_action_types/email.test.tsx | 20 +++++- .../components/builtin_action_types/email.tsx | 66 +++++++++++++++++-- 2 files changed, 78 insertions(+), 8 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx index de0991b5810b5c..37bce8063ff8c2 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx @@ -49,6 +49,7 @@ describe('connector validation', () => { expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ errors: { from: [], + service: [], port: [], host: [], user: [], @@ -62,6 +63,20 @@ describe('connector validation', () => { expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ errors: { from: [], + service: [], + port: [], + host: [], + user: [], + password: [], + }, + }); + delete actionConnector.config.host; + delete actionConnector.config.port; + actionConnector.config.service = 'testService'; + expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ + errors: { + from: [], + service: [], port: [], host: [], user: [], @@ -87,8 +102,9 @@ describe('connector validation', () => { expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ errors: { from: [], - port: ['Port is required.'], - host: ['Host is required.'], + service: ['Service or host with port is required.'], + port: ['Port or Service is required.'], + host: ['Host or Service is required.'], user: [], password: [], }, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx index 2df214dba99598..1cfafb85257491 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx @@ -12,6 +12,7 @@ import { EuiFieldPassword, EuiComboBox, EuiTextArea, + EuiSwitch, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ErrableFormRow } from '../page_error'; @@ -30,13 +31,14 @@ export function getActionType(): ActionTypeModel { selectMessage: i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.emailAction.selectMessageText', { - defaultMessage: 'Configure SMTP settings to send email from your servers', + defaultMessage: 'Configure settings to send email through your mail server', } ), validateConnector: (action: ActionConnector): ValidationResult => { const validationResult = { errors: {} }; const errors = { from: new Array(), + service: new Array(), port: new Array(), host: new Array(), user: new Array(), @@ -53,22 +55,32 @@ export function getActionType(): ActionTypeModel { ) ); } - if (!action.config.port) { + if (!action.config.port && !action.config.service) { errors.port.push( i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredPortText', { - defaultMessage: 'Port is required.', + defaultMessage: 'Port or Service is required.', } ) ); } - if (!action.config.host) { + if (!action.config.service && (!action.config.port || !action.config.host)) { + errors.service.push( + i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredServiceText', + { + defaultMessage: 'Service or host with port is required.', + } + ) + ); + } + if (!action.config.host && !action.config.service) { errors.host.push( i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredHostText', { - defaultMessage: 'Host is required.', + defaultMessage: 'Host or Service is required.', } ) ); @@ -154,7 +166,7 @@ const EmailActionConnectorFields: React.FunctionComponent { - const { from, host, port } = action.config; + const { from, host, port, secure, service } = action.config; const { user, password } = action.secrets; return ( @@ -187,6 +199,34 @@ const EmailActionConnectorFields: React.FunctionComponent + + { + editActionConfig('service', e.target.value); + }} + onBlur={() => { + if (!service) { + editActionConfig('service', ''); + } + }} + /> + + + { + editActionConfig('secure', e.target.checked); + }} + /> + From 9c252ce436697d021c0ebc59c945cb4f259b6b30 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 18 Dec 2019 15:26:13 -0800 Subject: [PATCH 232/297] Fixed building action types issues due to comments --- .../builtin_action_types/es_index.test.tsx | 8 ++++---- .../builtin_action_types/pagerduty.test.tsx | 15 ++++++--------- .../builtin_action_types/pagerduty.tsx | 18 ++---------------- .../builtin_action_types/server_log.test.tsx | 4 ++-- .../builtin_action_types/webhook.test.tsx | 12 ++++++------ 5 files changed, 20 insertions(+), 37 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.test.tsx index 709d64504e411a..903f83ebe500a3 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.test.tsx @@ -33,8 +33,8 @@ describe('index connector validation', () => { const actionConnector = { secrets: {}, id: 'test', - actionTypeId: '.email', - name: 'email', + actionTypeId: '.index', + name: 'es_index', config: { index: 'test_es_index', }, @@ -82,8 +82,8 @@ describe('IndexActionConnectorFields renders', () => { const actionConnector = { secrets: {}, id: 'test', - actionTypeId: '.email', - name: 'email', + actionTypeId: '.index', + name: 'es_index', config: { index: 'test', }, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.test.tsx index e16684cfd925dc..77221a3f8b08d3 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.test.tsx @@ -35,8 +35,8 @@ describe('pagerduty connector validation', () => { routingKey: 'test', }, id: 'test', - actionTypeId: '.email', - name: 'email', + actionTypeId: '.pagerduty', + name: 'pagerduty', config: { apiUrl: 'http:\\test', }, @@ -45,7 +45,6 @@ describe('pagerduty connector validation', () => { expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ errors: { routingKey: [], - apiUrl: [], }, }); @@ -54,7 +53,6 @@ describe('pagerduty connector validation', () => { expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ errors: { routingKey: [], - apiUrl: [], }, }); }); @@ -63,8 +61,8 @@ describe('pagerduty connector validation', () => { const actionConnector = { secrets: {}, id: 'test', - actionTypeId: '.email', - name: 'email', + actionTypeId: '.pagerduty', + name: 'pagerduty', config: { apiUrl: 'http:\\test', }, @@ -73,7 +71,6 @@ describe('pagerduty connector validation', () => { expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ errors: { routingKey: ['Routing Key is required.'], - apiUrl: [], }, }); }); @@ -111,8 +108,8 @@ describe('PagerDutyActionConnectorFields renders', () => { routingKey: 'test', }, id: 'test', - actionTypeId: '.email', - name: 'email', + actionTypeId: '.pagerduty', + name: 'pagerduty', config: { apiUrl: 'http:\\test', }, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.tsx index 1ed59bbf7b19f7..e738530c4c5e68 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.tsx @@ -29,7 +29,6 @@ export function getActionType(): ActionTypeModel { const validationResult = { errors: {} }; const errors = { routingKey: new Array(), - apiUrl: new Array(), }; validationResult.errors = errors; if (!action.secrets.routingKey) { @@ -42,16 +41,6 @@ export function getActionType(): ActionTypeModel { ) ); } - if (!action.config.apiUrl) { - errors.apiUrl.push( - i18n.translate( - 'xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.error.requiredApiUrlText', - { - defaultMessage: 'ApiUrl is required.', - } - ) - ); - } return validationResult; }, validateParams: (actionParams: any): ValidationResult => { @@ -74,12 +63,9 @@ const PagerDutyActionConnectorFields: React.FunctionComponent - - + { const actionConnector = { secrets: {}, id: 'test', - actionTypeId: '.email', - name: 'email', + actionTypeId: '.server-log', + name: 'server-log', config: {}, } as ActionConnector; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx index e314039f93af16..2deb7418a8008a 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx @@ -36,8 +36,8 @@ describe('webhook connector validation', () => { password: 'pass', }, id: 'test', - actionTypeId: '.email', - name: 'email', + actionTypeId: '.webhook', + name: 'webhook', config: { method: 'PUT', url: 'http:\\test', @@ -61,8 +61,8 @@ describe('webhook connector validation', () => { user: 'user', }, id: 'test', - actionTypeId: '.email', - name: 'email', + actionTypeId: '.webhook', + name: 'webhook', config: { method: 'PUT', }, @@ -104,8 +104,8 @@ describe('WebhookActionConnectorFields renders', () => { password: 'pass', }, id: 'test', - actionTypeId: '.email', - name: 'email', + actionTypeId: '.webhook', + name: 'webhook', config: { method: 'PUT', url: 'http:\\test', From fe88d50ae2b9a98de23862702f5328d55a52491b Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 19 Dec 2019 22:18:31 -0800 Subject: [PATCH 233/297] Refactored with more new platform structure; fixed some comments from review --- .../plugins/triggers_actions_ui/index.ts | 2 +- .../np_ready/public/application/app.tsx | 40 ++++- .../public/application/app_context.tsx | 30 ++++ .../public/application/app_dependencies.tsx | 42 ----- .../np_ready/public/application/boot.tsx | 35 ++++ .../threshold/expression.tsx | 2 +- .../threshold/visualization.tsx | 2 +- .../application/constants/action_groups.ts | 12 +- .../public/application/constants/plugin.ts} | 9 +- .../np_ready/public/application/home.tsx | 11 +- .../np_ready/public/application/index.tsx | 22 --- .../public/application/lib/breadcrumb.ts | 69 ++------ .../action_connector_form.tsx | 7 +- .../action_type_menu.tsx | 2 +- .../connector_add_flyout.tsx | 2 +- .../connector_edit_flyout.tsx | 2 +- .../components/actions_connectors_list.tsx | 7 +- .../sections/alert_add/alert_add.tsx | 9 +- .../alerts_list/components/alerts_list.tsx | 8 +- .../components/bulk_action_popover.tsx | 7 +- .../components/collapsed_item_actions.tsx | 6 +- .../public/application/type_registry.ts | 56 +++++++ .../np_ready/public/legacy.ts | 13 -- .../np_ready/public/plugin.ts | 154 +++++++----------- .../np_ready/public/types.ts | 6 + .../triggers_actions_ui/public/index.html | 3 - .../triggers_actions_ui/public/legacy.ts | 89 ++++++++++ .../public/manage_angular_lifecycle.ts | 28 ++++ 28 files changed, 393 insertions(+), 282 deletions(-) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app_context.tsx delete mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app_dependencies.tsx create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/boot.tsx rename x-pack/legacy/plugins/triggers_actions_ui/{public/index.ts => np_ready/public/application/constants/plugin.ts} (52%) delete mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/index.tsx create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/type_registry.ts delete mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/legacy.ts delete mode 100644 x-pack/legacy/plugins/triggers_actions_ui/public/index.html create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/public/legacy.ts create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/public/manage_angular_lifecycle.ts diff --git a/x-pack/legacy/plugins/triggers_actions_ui/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/index.ts index 1c94a7dc6a64ca..aa2324d61c7c42 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/index.ts @@ -30,7 +30,7 @@ export function triggersActionsUI(kibana: any) { }, uiExports: { hacks: ['plugins/triggers_actions_ui/hacks/register'], - managementSections: ['plugins/triggers_actions_ui'], + managementSections: ['plugins/triggers_actions_ui/legacy'], styleSheetPaths: resolve(__dirname, 'public/index.scss'), injectDefaultVars(server: Legacy.Server) { const serverConfig = server.config(); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx index e4bf534df4791d..281a709342949c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx @@ -5,11 +5,33 @@ */ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import { Switch, Route, Redirect } from 'react-router-dom'; +import { Switch, Route, Redirect, HashRouter } from 'react-router-dom'; +import { + ChromeStart, + DocLinksStart, + ToastsSetup, + HttpSetup, + IUiSettingsClient, +} from 'kibana/public'; import { BASE_PATH, Section } from './constants'; import { TriggersActionsUIHome } from './home'; -import { useAppDependencies } from './app_dependencies'; +import { AppContextProvider, useAppDependencies } from './app_context'; import { hasShowAlertsCapability } from './lib/capabilities'; +import { ActionTypeRegistry } from './action_type_registry'; +import { AlertTypeRegistry } from './alert_type_registry'; +import { LegacyDependencies } from '../types'; + +export interface AppDeps { + chrome: ChromeStart; + docLinks: DocLinksStart; + toastNotifications: ToastsSetup; + injectedMetadata: any; + http: HttpSetup; + uiSettings: IUiSettingsClient; + legacy: LegacyDependencies; + actionTypeRegistry: ActionTypeRegistry; + alertTypeRegistry: AlertTypeRegistry; +} class ShareRouter extends Component { static contextTypes = { @@ -26,21 +48,25 @@ class ShareRouter extends Component { } } -export const App = () => { +export const App = (deps: AppDeps) => { const sections: Section[] = ['alerts', 'connectors']; const sectionsRegex = sections.join('|'); return ( - - - + + + + + + + ); }; export const AppWithoutRouter = ({ sectionsRegex }: any) => { const { - plugins: { capabilities }, + legacy: { capabilities }, } = useAppDependencies(); const canShowAlerts = hasShowAlertsCapability(capabilities.get()); const DEFAULT_SECTION: Section = canShowAlerts ? 'alerts' : 'connectors'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app_context.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app_context.tsx new file mode 100644 index 00000000000000..c04c5a1856feed --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app_context.tsx @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { createContext, useContext } from 'react'; +import { AppDeps } from './app'; + +const AppContext = createContext(null as any); + +export const AppContextProvider = ({ + children, + value, +}: { + value: AppDeps; + children: React.ReactNode; +}) => { + return {children}; +}; + +export const useAppDependencies = () => { + const ctx = useContext(AppContext); + if (!ctx) { + throw new Error( + 'The app dependencies Context has not been set. Use the "setAppDependencies()" method when bootstrapping the app.' + ); + } + return ctx; +}; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app_dependencies.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app_dependencies.tsx deleted file mode 100644 index 76007867ecf81c..00000000000000 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app_dependencies.tsx +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React, { createContext, useContext, ReactNode } from 'react'; -import { HashRouter } from 'react-router-dom'; -import { AppDependencies } from '../../../public/shim'; - -let DependenciesContext: React.Context; - -export const setAppDependencies = (deps: AppDependencies) => { - DependenciesContext = createContext(deps); - return DependenciesContext.Provider; -}; - -export const useAppDependencies = () => { - if (!DependenciesContext) { - throw new Error( - `The app dependencies Context hasn't been set. Use the "setAppDependencies()" method when bootstrapping the app.` - ); - } - return useContext(DependenciesContext); -}; - -export const getAppProviders = (deps: AppDependencies) => { - const { - i18n: { Context: I18nContext }, - } = deps.core; - - // Create App dependencies context and get its provider - const AppDependenciesProvider = setAppDependencies(deps); - - return ({ children }: { children: ReactNode }) => ( - - - {children} - - - ); -}; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/boot.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/boot.tsx new file mode 100644 index 00000000000000..e718147adb66fa --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/boot.tsx @@ -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 React from 'react'; +import { render, unmountComponentAtNode } from 'react-dom'; +import { SavedObjectsClientContract } from 'src/core/public'; + +import { App, AppDeps } from './app'; +import { setSavedObjectsClient } from '../application/components/builtin_alert_types/threshold/lib/api'; +import { LegacyDependencies } from '../types'; +// import { LegacyDependencies } from '../types'; + +interface BootDeps extends AppDeps { + element: HTMLElement; + savedObjects: SavedObjectsClientContract; + I18nContext: any; + legacy: LegacyDependencies; +} + +export const boot = (bootDeps: BootDeps) => { + const { I18nContext, element, legacy, savedObjects, ...appDeps } = bootDeps; + + setSavedObjectsClient(savedObjects); + + render( + + + , + element + ); + return () => unmountComponentAtNode(element); +}; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx index c08dbdbef98dff..b41c759f81dd33 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx @@ -29,7 +29,7 @@ import { getThresholdAlertTypeFields, loadIndexPatterns, } from './lib/api'; -import { useAppDependencies } from '../../../app_dependencies'; +import { useAppDependencies } from '../../../app_context'; import { ErrableFormRow } from '../../../components/page_error'; import { getTimeOptions, getTimeFieldOptions } from '../../../lib/get_time_options'; import { getTimeUnitLabel } from '../../../lib/get_time_unit_label'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx index 1f49c465832106..96b3325cbc0113 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx @@ -28,7 +28,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { npStart } from 'ui/new_platform'; import { getThresholdAlertVisualizationData } from './lib/api'; import { comparators, aggregationTypes } from './expression'; -import { useAppDependencies } from '../../../app_dependencies'; +import { useAppDependencies } from '../../../app_context'; import { SectionError } from '../../../components/page_error/section_error'; import { Alert } from '../../../../types'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/action_groups.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/action_groups.ts index e74d0577b577b0..83a03010d55ad6 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/action_groups.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/action_groups.ts @@ -4,10 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -export const ACTION_GROUPS: { [key: string]: string } = { - ALERT: 'alert', - - WARNING: 'warning', - - UNACKNOWLEDGED: 'unacknowledged', -}; +export enum ACTION_GROUPS { + ALERT = 'alert', + WARNING = 'warning', + UNACKNOWLEDGED = 'unacknowledged', +} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/public/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/plugin.ts similarity index 52% rename from x-pack/legacy/plugins/triggers_actions_ui/public/index.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/plugin.ts index 573578bfb1275a..12d9c06f87492d 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/public/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/plugin.ts @@ -4,4 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import '../np_ready/public/legacy'; +export const PLUGIN = { + ID: 'triggers_actions_ui', + getI18nName: (i18n: any): string => { + return i18n.translate('xpack.triggers_actions_ui.appName', { + defaultMessage: 'Alerts and actions', + }); + }, +}; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx index b904c1a8c33e54..e405345c0970ff 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx @@ -19,9 +19,9 @@ import { } from '@elastic/eui'; import { BASE_PATH, Section, routeToConnectors, routeToAlerts } from './constants'; -import { breadcrumbService } from './lib/breadcrumb'; +import { getCurrentBreadcrumb } from './lib/breadcrumb'; import { docTitleService } from './lib/doc_title'; -import { useAppDependencies } from './app_dependencies'; +import { useAppDependencies } from './app_context'; import { hasShowActionsCapability, hasShowAlertsCapability } from './lib/capabilities'; import { ActionsConnectorsList } from './sections/actions_connectors_list/components/actions_connectors_list'; @@ -38,7 +38,8 @@ export const TriggersActionsUIHome: React.FunctionComponent { const { - plugins: { capabilities }, + chrome, + legacy: { MANAGEMENT_BREADCRUMB, capabilities }, } = useAppDependencies(); const canShowActions = hasShowActionsCapability(capabilities.get()); @@ -78,9 +79,9 @@ export const TriggersActionsUIHome: React.FunctionComponent { - breadcrumbService.setBreadcrumbs(section || 'home'); + chrome.setBreadcrumbs([MANAGEMENT_BREADCRUMB, getCurrentBreadcrumb(section || 'home')]); docTitleService.setTitle(section || 'home'); - }, [section]); + }, [section, chrome, MANAGEMENT_BREADCRUMB]); return ( diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/index.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/index.tsx deleted file mode 100644 index fec6be07f16f35..00000000000000 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/index.tsx +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import { render } from 'react-dom'; -import { App } from './app'; -import { AppDependencies } from '../../../public/shim'; -import { getAppProviders } from './app_dependencies'; - -export const renderReact = async (elem: HTMLElement, appDependencies: AppDependencies) => { - const Providers = getAppProviders(appDependencies); - - render( - - - , - elem - ); -}; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.ts index de658d5aabc1e2..75af45f89e5fde 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.ts @@ -7,72 +7,29 @@ import { i18n } from '@kbn/i18n'; import { routeToHome, routeToConnectors, routeToAlerts } from '../constants'; -class BreadcrumbService { - private chrome: any; - private breadcrumbs: { - [key: string]: Array<{ - text: string; - href?: string; - }>; - } = { - management: [], - home: [], - actions: [], - }; - - public init(chrome: any, managementBreadcrumb: any): void { - this.chrome = chrome; - this.breadcrumbs.management = [managementBreadcrumb]; - - // Home and sections - this.breadcrumbs.home = [ - ...this.breadcrumbs.management, - { +export const getCurrentBreadcrumb = (type: string): any => { + // Home and sections + switch (type) { + case 'home': + return { text: i18n.translate('xpack.triggersActionsUI.home.breadcrumbTitle', { defaultMessage: 'Alerts and actions', }), href: `#${routeToHome}`, - }, - ]; - this.breadcrumbs.connectors = [ - ...this.breadcrumbs.home, - { + }; + case 'connectors': + return { text: i18n.translate('xpack.triggersActionsUI.connectors.breadcrumbTitle', { defaultMessage: 'Connectors', }), href: `#${routeToConnectors}`, - }, - ]; - this.breadcrumbs.alerts = [ - ...this.breadcrumbs.home, - { + }; + case 'alerts': + return { text: i18n.translate('xpack.triggersActionsUI.alerts.breadcrumbTitle', { defaultMessage: 'Alerts', }), href: `#${routeToAlerts}`, - }, - ]; - } - - public setBreadcrumbs(type: string): void { - const newBreadcrumbs = this.breadcrumbs[type] - ? [...this.breadcrumbs[type]] - : [...this.breadcrumbs.home]; - - // Pop off last breadcrumb - const lastBreadcrumb = newBreadcrumbs.pop() as { - text: string; - href?: string; - }; - - // Put last breadcrumb back without href - newBreadcrumbs.push({ - ...lastBreadcrumb, - href: undefined, - }); - - this.chrome.setBreadcrumbs(newBreadcrumbs); + }; } -} - -export const breadcrumbService = new BreadcrumbService(); +}; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index 724242f844c9e4..d4d7a0833d2575 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -22,7 +22,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { createActionConnector, updateActionConnector } from '../../lib/action_connector_api'; import { SectionError, ErrableFormRow } from '../../components/page_error'; -import { useAppDependencies } from '../../app_dependencies'; +import { useAppDependencies } from '../../app_context'; import { connectorReducer } from './connector_reducer'; import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; import { ActionConnector, IErrorObject } from '../../../types'; @@ -40,8 +40,9 @@ export const ActionConnectorForm = ({ setFlyoutVisibility, }: ActionConnectorProps) => { const { - core: { http }, - plugins: { capabilities, toastNotifications }, + http, + toastNotifications, + legacy: { capabilities }, actionTypeRegistry, } = useAppDependencies(); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx index 2db9763394ed9c..55ff4e1ff7016e 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx @@ -17,7 +17,7 @@ import { import { i18n } from '@kbn/i18n'; import { ActionType } from '../../../types'; import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; -import { useAppDependencies } from '../../app_dependencies'; +import { useAppDependencies } from '../../app_context'; interface Props { onActionTypeChange: (actionType: ActionType) => void; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx index f29b056b4f559d..19f658e97a40ab 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx @@ -18,7 +18,7 @@ import { ActionsConnectorsContext } from '../../context/actions_connectors_conte import { ActionTypeMenu } from './action_type_menu'; import { ActionConnectorForm } from './action_connector_form'; import { ActionType, ActionConnector } from '../../../types'; -import { useAppDependencies } from '../../app_dependencies'; +import { useAppDependencies } from '../../app_context'; export const ConnectorAddFlyout = () => { const { actionTypeRegistry } = useAppDependencies(); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx index 46094fd59aac53..54aa8ab5d69d82 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx @@ -15,7 +15,7 @@ import { } from '@elastic/eui'; import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; import { ActionConnectorForm } from './action_connector_form'; -import { useAppDependencies } from '../../app_dependencies'; +import { useAppDependencies } from '../../app_context'; import { ActionConnectorTableItem } from '../../../types'; export interface ConnectorEditProps { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index f4285cc99bed3a..0e2f288fbff0b7 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -18,7 +18,7 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { ActionsConnectorsContext } from '../../../context/actions_connectors_context'; -import { useAppDependencies } from '../../../app_dependencies'; +import { useAppDependencies } from '../../../app_context'; import { deleteActions, loadAllActions, loadActionTypes } from '../../../lib/action_connector_api'; import { ActionConnector, ActionConnectorTableItem, ActionTypeIndex } from '../../../../types'; import { ConnectorAddFlyout, ConnectorEditFlyout } from '../../action_connector_form'; @@ -26,8 +26,9 @@ import { hasDeleteActionsCapability, hasSaveActionsCapability } from '../../../l export const ActionsConnectorsList: React.FunctionComponent = () => { const { - core: { http }, - plugins: { capabilities, toastNotifications }, + http, + toastNotifications, + legacy: { capabilities }, } = useAppDependencies(); const canDelete = hasDeleteActionsCapability(capabilities.get()); const canSave = hasSaveActionsCapability(capabilities.get()); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 5307649bd1ef6f..2368a5675c9d1b 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -34,7 +34,7 @@ import { EuiAccordion, EuiButtonIcon, } from '@elastic/eui'; -import { useAppDependencies } from '../../app_dependencies'; +import { useAppDependencies } from '../../app_context'; import { createAlert } from '../../lib/alert_api'; import { loadActionTypes, loadAllActions } from '../../lib/action_connector_api'; import { AlertsContext } from '../../context/alerts_context'; @@ -91,12 +91,7 @@ function validateBaseProperties(alertObject: Alert) { } export const AlertAdd = ({ refreshList }: Props) => { - const { - core: { http }, - plugins: { toastNotifications }, - alertTypeRegistry, - actionTypeRegistry, - } = useAppDependencies(); + const { http, toastNotifications, alertTypeRegistry, actionTypeRegistry } = useAppDependencies(); const initialAlert = { params: {}, alertTypeId: null, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 51ca9b01e9ba44..33a28a6d57d7c5 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -11,7 +11,7 @@ import React, { Fragment, useEffect, useState } from 'react'; import { EuiBasicTable, EuiButton, EuiFilterButton, EuiSearchBar, EuiSpacer } from '@elastic/eui'; import { AlertsContext } from '../../../context/alerts_context'; -import { useAppDependencies } from '../../../app_dependencies'; +import { useAppDependencies } from '../../../app_context'; import { ActionType, Alert, AlertTableItem, AlertTypeIndex, Pagination } from '../../../../types'; import { AlertAdd } from '../../alert_add'; import { BulkActionPopover } from './bulk_action_popover'; @@ -24,8 +24,10 @@ import { hasDeleteAlertsCapability, hasSaveAlertsCapability } from '../../../lib export const AlertsList: React.FunctionComponent = () => { const { - core: { http, injectedMetadata }, - plugins: { capabilities, toastNotifications }, + http, + injectedMetadata, + toastNotifications, + legacy: { capabilities }, } = useAppDependencies(); const canDelete = hasDeleteAlertsCapability(capabilities.get()); const canSave = hasSaveAlertsCapability(capabilities.get()); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx index 806d2fda324fae..95d8e14e26f64d 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx @@ -10,7 +10,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { EuiButton, EuiButtonEmpty, EuiFormRow, EuiPopover } from '@elastic/eui'; import { AlertTableItem } from '../../../../types'; -import { useAppDependencies } from '../../../app_dependencies'; +import { useAppDependencies } from '../../../app_context'; import { deleteAlerts, disableAlerts, @@ -30,10 +30,7 @@ export const BulkActionPopover: React.FunctionComponent = ({ onPerformingAction, onActionPerformed, }: ComponentOpts) => { - const { - core: { http }, - plugins: { toastNotifications }, - } = useAppDependencies(); + const { http, toastNotifications } = useAppDependencies(); const [isPopoverOpen, setIsPopoverOpen] = useState(false); const [isMutingAlerts, setIsMutingAlerts] = useState(false); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx index 64d4edfff74784..718898c2d857f9 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx @@ -17,7 +17,7 @@ import { } from '@elastic/eui'; import { AlertTableItem } from '../../../../types'; -import { useAppDependencies } from '../../../app_dependencies'; +import { useAppDependencies } from '../../../app_context'; import { hasDeleteAlertsCapability, hasSaveAlertsCapability } from '../../../lib/capabilities'; import { deleteAlerts, @@ -37,8 +37,8 @@ export const CollapsedItemActions: React.FunctionComponent = ({ onAlertChanged, }: ComponentOpts) => { const { - core: { http }, - plugins: { capabilities }, + http, + legacy: { capabilities }, } = useAppDependencies(); const canDelete = hasDeleteAlertsCapability(capabilities.get()); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/type_registry.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/type_registry.ts new file mode 100644 index 00000000000000..3f23eb7d44efba --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/type_registry.ts @@ -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 { i18n } from '@kbn/i18n'; + +interface BaseObjectType { + id: string; +} + +export class TypeRegistry { + private readonly objectTypes: Map = new Map(); + + /** + * Returns if the action type registry has the given action type registered + */ + public has(id: string) { + return this.objectTypes.has(id); + } + + /** + * Registers an action type to the action type registry + */ + public register(objectType: T) { + if (this.has(objectType.id)) { + throw new Error( + i18n.translate( + 'xpack.triggersActionsUI.actionTypeRegistry.register.duplicateActionTypeErrorMessage', + { + defaultMessage: 'Action type "{id}" is already registered.', + values: { + id: objectType.id, + }, + } + ) + ); + } + this.objectTypes.set(objectType.id, objectType); + } + + /** + * Returns an action type, null if not registered + */ + public get(id: string): T | null { + if (!this.has(id)) { + return null; + } + return this.objectTypes.get(id)!; + } + + public list() { + return Array.from(this.objectTypes).map(([id, objectType]) => objectType); + } +} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/legacy.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/legacy.ts deleted file mode 100644 index 0afd9b35dc7a49..00000000000000 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/legacy.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import { npStart, npSetup } from 'ui/new_platform'; -import { createShim } from '../../public/shim'; -import { plugin } from '.'; - -const pluginInstance = plugin({} as any); -const { pluginsSetup, pluginsStart } = createShim(); -pluginInstance.setup(npSetup.core, pluginsSetup); -pluginInstance.start(npStart.core, pluginsStart); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts index d53e4148699080..59be83640ee905 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts @@ -4,10 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { unmountComponentAtNode } from 'react-dom'; -import { i18n } from '@kbn/i18n'; -import routes from 'ui/routes'; -import { SavedObjectsClientProvider } from 'ui/saved_objects'; import { CoreSetup, CoreStart, @@ -15,22 +11,21 @@ import { PluginInitializerContext, } from 'src/core/public'; -import template from '../../public/index.html'; -import { renderReact } from './application'; -import { BASE_PATH } from './application/constants'; -import { breadcrumbService } from './application/lib/breadcrumb'; -import { docTitleService } from './application/lib/doc_title'; +import { i18n } from '@kbn/i18n'; import { ActionTypeRegistry } from './application/action_type_registry'; import { registerBuiltInActionTypes } from './application/components/builtin_action_types'; import { AlertTypeRegistry } from './application/alert_type_registry'; import { registerBuiltInAlertTypes } from './application/components/builtin_alert_types'; -import { setSavedObjectsClient } from './application/components/builtin_alert_types/threshold/lib/api'; import { hasShowActionsCapability, hasShowAlertsCapability } from './application/lib/capabilities'; +import { PLUGIN } from './application/constants/plugin'; +import { LegacyDependencies } from './types'; export type Setup = void; export type Start = void; -const REACT_ROOT_ID = 'triggersActionsRoot'; +interface LegacyPlugins { + __LEGACY: LegacyDependencies; +} export class Plugin implements CorePlugin { private actionTypeRegistry: ActionTypeRegistry; @@ -44,102 +39,69 @@ export class Plugin implements CorePlugin { this.alertTypeRegistry = alertTypeRegistry; } - public setup(core: CoreSetup, plugins: any): Setup { - /* - The code below would be replacing for current: - uiExports: { - managementSections: ['myplugin/management'], - } - */ - const { - capabilities, - management: { getSection }, - } = plugins; - - const canShowActions = hasShowActionsCapability(capabilities.get()); - const canShowAlerts = hasShowAlertsCapability(capabilities.get()); - if (canShowActions || canShowAlerts) { - registerBuiltInActionTypes({ - actionTypeRegistry: this.actionTypeRegistry, - }); - - registerBuiltInAlertTypes({ - alertTypeRegistry: this.alertTypeRegistry, - }); + public setup( + { application, notifications, http, uiSettings, injectedMetadata }: CoreSetup, + { __LEGACY }: LegacyPlugins + ): Setup { + const canShowActions = hasShowActionsCapability(__LEGACY.capabilities.get()); + const canShowAlerts = hasShowAlertsCapability(__LEGACY.capabilities.get()); - const kbnSection = getSection('kibana'); - kbnSection.register('triggersActions', { - display: i18n.translate('xpack.triggersActionsUI.managementSection.displayName', { - defaultMessage: 'Alerts and actions', - }), - order: 7, - url: `#${BASE_PATH}`, - }); + if (!canShowActions && !canShowAlerts) { + return; } + registerBuiltInActionTypes({ + actionTypeRegistry: this.actionTypeRegistry, + }); + + registerBuiltInAlertTypes({ + alertTypeRegistry: this.alertTypeRegistry, + }); + application.register({ + id: PLUGIN.ID, + title: PLUGIN.getI18nName(i18n), + mount: async ( + { + core: { + docLinks, + chrome, + // Waiting for types to be updated. + // @ts-ignore + savedObjects, + i18n: { Context: I18nContext }, + }, + }, + { element } + ) => { + const { boot } = await import('./application/boot'); + return boot({ + element, + toastNotifications: notifications.toasts, + injectedMetadata, + http, + uiSettings, + docLinks, + chrome, + savedObjects: savedObjects.client, + I18nContext, + legacy: { + ...__LEGACY, + }, + actionTypeRegistry: this.actionTypeRegistry, + alertTypeRegistry: this.alertTypeRegistry, + }); + }, + }); } - public start(core: CoreStart, plugins: any) { - const { capabilities } = plugins; + public start(core: CoreStart, { __LEGACY }: LegacyPlugins) { + const { capabilities } = __LEGACY; const canShowActions = hasShowActionsCapability(capabilities.get()); const canShowAlerts = hasShowAlertsCapability(capabilities.get()); - // AppCore/AppPlugins to be passed on as React context - const AppDependencies = { - core, - plugins, - actionTypeRegistry: this.actionTypeRegistry, - alertTypeRegistry: this.alertTypeRegistry, - }; // Don't register routes when user doesn't have access to the application if (!canShowActions && !canShowAlerts) { return; } - - docTitleService.init(plugins.docTitle.change); - breadcrumbService.init(core.chrome, plugins.management.breadcrumb); - - const unmountReactApp = (): void => { - const elem = document.getElementById(REACT_ROOT_ID); - if (elem) { - unmountComponentAtNode(elem); - } - }; - - routes.when(`${BASE_PATH}/:section?/:subsection?/:view?/:id?`, { - template, - controller: (() => { - return ($route: any, $scope: any, Private: any) => { - const appRoute = $route.current; - setSavedObjectsClient(Private(SavedObjectsClientProvider)); - const stopListeningForLocationChange = $scope.$on('$locationChangeSuccess', () => { - const currentRoute = $route.current; - const isNavigationInApp = currentRoute.$$route.template === appRoute.$$route.template; - - // When we navigate within Transform, prevent Angular from re-matching the route and rebuild the app - if (isNavigationInApp) { - $route.current = appRoute; - } else { - // Any clean up when user leaves Transform - } - - $scope.$on('$destroy', () => { - if (stopListeningForLocationChange) { - stopListeningForLocationChange(); - } - unmountReactApp(); - }); - }); - - $scope.$$postDigest(() => { - unmountReactApp(); - const elReactRoot = document.getElementById(REACT_ROOT_ID); - if (elReactRoot) { - renderReact(elReactRoot, AppDependencies); - } - }); - }; - })(), - }); } public stop() {} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts index ed3be1376ceb6e..b07b2da570fcc4 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts @@ -3,6 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { capabilities } from 'ui/capabilities'; import { ActionTypeRegistry } from './application/action_type_registry'; import { AlertTypeRegistry } from './application/alert_type_registry'; @@ -113,3 +114,8 @@ export interface AlertTypeModel { export interface IErrorObject { [key: string]: string[]; } + +export interface LegacyDependencies { + MANAGEMENT_BREADCRUMB: { text: string; href?: string }; + capabilities: typeof capabilities; +} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/public/index.html b/x-pack/legacy/plugins/triggers_actions_ui/public/index.html deleted file mode 100644 index a982be5cbb8776..00000000000000 --- a/x-pack/legacy/plugins/triggers_actions_ui/public/index.html +++ /dev/null @@ -1,3 +0,0 @@ - -
-
diff --git a/x-pack/legacy/plugins/triggers_actions_ui/public/legacy.ts b/x-pack/legacy/plugins/triggers_actions_ui/public/legacy.ts new file mode 100644 index 00000000000000..966ab54381e649 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/public/legacy.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 { CoreSetup, App, AppUnmount } from 'src/core/public'; +import { capabilities } from 'ui/capabilities'; +import { i18n } from '@kbn/i18n'; + +/* Legacy UI imports */ +import { npSetup, npStart } from 'ui/new_platform'; +import routes from 'ui/routes'; +import { management, MANAGEMENT_BREADCRUMB } from 'ui/management'; +// @ts-ignore +import { xpackInfo } from 'plugins/xpack_main/services/xpack_info'; +/* Legacy UI imports */ + +import { plugin } from '../np_ready/public'; +import { manageAngularLifecycle } from './manage_angular_lifecycle'; +import { BASE_PATH } from '../np_ready/public/application/constants'; + +const REACT_ROOT_ID = 'triggersActionsRoot'; + +const template = ` +
+
`; + +let elem: HTMLElement; +let mountApp: () => AppUnmount | Promise; +let unmountApp: AppUnmount | Promise; +routes.when(`${BASE_PATH}:section?/:subsection?/:view?/:id?`, { + template, + controller: (() => { + return ($route: any, $scope: any) => { + const shimCore: CoreSetup = { + ...npSetup.core, + application: { + ...npSetup.core.application, + register(app: App): void { + mountApp = () => + app.mount(npStart as any, { + element: elem, + appBasePath: BASE_PATH, + }); + }, + }, + }; + + // clean up previously rendered React app if one exists + // this happens because of React Router redirects + if (elem) { + ((unmountApp as unknown) as AppUnmount)(); + } + + $scope.$$postDigest(() => { + elem = document.getElementById(REACT_ROOT_ID)!; + const instance = plugin({} as any); + instance.setup(shimCore, { + ...(npSetup.plugins as typeof npSetup.plugins), + __LEGACY: { + MANAGEMENT_BREADCRUMB, + capabilities, + }, + }); + + instance.start(npStart.core, { + ...(npSetup.plugins as typeof npSetup.plugins), + __LEGACY: { + MANAGEMENT_BREADCRUMB, + capabilities, + }, + }); + + (mountApp() as Promise).then(fn => (unmountApp = fn)); + + manageAngularLifecycle($scope, $route, elem); + }); + }; + })(), +}); + +management.getSection('kibana').register('triggersActions', { + display: i18n.translate('xpack.triggersActionsUI.managementSection.displayName', { + defaultMessage: 'Alerts and actions', + }), + order: 7, + url: `#${BASE_PATH}`, +}); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/public/manage_angular_lifecycle.ts b/x-pack/legacy/plugins/triggers_actions_ui/public/manage_angular_lifecycle.ts new file mode 100644 index 00000000000000..efd40eaf83daad --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/public/manage_angular_lifecycle.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 { unmountComponentAtNode } from 'react-dom'; + +export const manageAngularLifecycle = ($scope: any, $route: any, elem: HTMLElement) => { + const lastRoute = $route.current; + + const deregister = $scope.$on('$locationChangeSuccess', () => { + const currentRoute = $route.current; + if (lastRoute.$$route.template === currentRoute.$$route.template) { + $route.current = lastRoute; + } + }); + + $scope.$on('$destroy', () => { + if (deregister) { + deregister(); + } + + if (elem) { + unmountComponentAtNode(elem); + } + }); +}; From 44e10ab9d0ec15fd05a6b0ef1e3937aa8b76fd23 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 20 Dec 2019 09:13:49 -0500 Subject: [PATCH 234/297] Capitalize Actions in 'Alerts and Actions' labels --- .../np_ready/public/application/constants/plugin.ts | 2 +- .../triggers_actions_ui/np_ready/public/application/home.tsx | 2 +- .../np_ready/public/application/lib/breadcrumb.ts | 2 +- .../np_ready/public/application/lib/doc_title.test.ts | 2 +- .../np_ready/public/application/lib/doc_title.ts | 2 +- .../legacy/plugins/triggers_actions_ui/public/hacks/register.ts | 2 +- x-pack/legacy/plugins/triggers_actions_ui/public/legacy.ts | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/plugin.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/plugin.ts index 12d9c06f87492d..5eab6fc9c93ed5 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/plugin.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/plugin.ts @@ -8,7 +8,7 @@ export const PLUGIN = { ID: 'triggers_actions_ui', getI18nName: (i18n: any): string => { return i18n.translate('xpack.triggers_actions_ui.appName', { - defaultMessage: 'Alerts and actions', + defaultMessage: 'Alerts and Actions', }); }, }; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx index e405345c0970ff..d80150a0c0a22c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx @@ -92,7 +92,7 @@ export const TriggersActionsUIHome: React.FunctionComponent
diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.ts index 75af45f89e5fde..99a6234a523bfc 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.ts @@ -13,7 +13,7 @@ export const getCurrentBreadcrumb = (type: string): any => { case 'home': return { text: i18n.translate('xpack.triggersActionsUI.home.breadcrumbTitle', { - defaultMessage: 'Alerts and actions', + defaultMessage: 'Alerts and Actions', }), href: `#${routeToHome}`, }; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.test.ts index 837fc207bae9cd..2746abe4c82b86 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.test.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.test.ts @@ -22,7 +22,7 @@ describe('doc_title', () => { "change": [MockFunction] { "calls": Array [ Array [ - "Alerts and actions", + "Alerts and Actions", ], Array [ "Alerts", diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.ts index db48d64ad0fd81..bcca98f19a9e44 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.ts @@ -28,7 +28,7 @@ class DocTitleService { break; default: updatedTitle = i18n.translate('xpack.triggersActionsUI.home.breadcrumbTitle', { - defaultMessage: 'Alerts and actions', + defaultMessage: 'Alerts and Actions', }); } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/public/hacks/register.ts b/x-pack/legacy/plugins/triggers_actions_ui/public/hacks/register.ts index 897c956ec12327..7991604fcc6674 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/public/hacks/register.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/public/hacks/register.ts @@ -13,7 +13,7 @@ import { FeatureCatalogueRegistryProvider.register(() => { return { id: 'triggersActions', - title: 'Alerts and actions', // This is a product name so we don't translate it. + title: 'Alerts and Actions', // This is a product name so we don't translate it. description: i18n.translate('xpack.triggersActionsUI.triggersActionsDescription', { defaultMessage: 'Data by creating, managing, and monitoring triggers and actions.', }), diff --git a/x-pack/legacy/plugins/triggers_actions_ui/public/legacy.ts b/x-pack/legacy/plugins/triggers_actions_ui/public/legacy.ts index 966ab54381e649..8937da0cbb30c5 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/public/legacy.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/public/legacy.ts @@ -82,7 +82,7 @@ routes.when(`${BASE_PATH}:section?/:subsection?/:view?/:id?`, { management.getSection('kibana').register('triggersActions', { display: i18n.translate('xpack.triggersActionsUI.managementSection.displayName', { - defaultMessage: 'Alerts and actions', + defaultMessage: 'Alerts and Actions', }), order: 7, url: `#${BASE_PATH}`, From 680212173a31fd0b0da5ac4d537059f6765e58c3 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 20 Dec 2019 09:17:17 -0500 Subject: [PATCH 235/297] Skip flaky tests --- .../apps/triggers_actions_ui/alerts.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts index 571e90af6c1aa9..1b406adc6bcf78 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts @@ -75,7 +75,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ]); }); - it('should disable single alert', async () => { + // Flaky until https://github.com/elastic/eui/issues/2612 fixed + it.skip('should disable single alert', async () => { const createdAlert = await createAlert(); await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); @@ -96,7 +97,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(isChecked).to.eql('false'); }); - it('should re-enable single alert', async () => { + // Flaky until https://github.com/elastic/eui/issues/2612 fixed + it.skip('should re-enable single alert', async () => { const createdAlert = await createAlert(); await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); @@ -125,7 +127,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(isChecked).to.eql('true'); }); - it('should mute single alert', async () => { + // Flaky until https://github.com/elastic/eui/issues/2612 fixed + it.skip('should mute single alert', async () => { const createdAlert = await createAlert(); await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); @@ -146,7 +149,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(isChecked).to.eql('true'); }); - it('should unmute single alert', async () => { + // Flaky until https://github.com/elastic/eui/issues/2612 fixed + it.skip('should unmute single alert', async () => { const createdAlert = await createAlert(); await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); From 4827d42aa4b9ad03f99b8e3a2ee6b46f51f72988 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 20 Dec 2019 11:45:56 -0500 Subject: [PATCH 236/297] Fix failing functional test --- .../apps/triggers_actions_ui/home_page.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts index 0193b3cd0c2e29..13f50a505b0b6f 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts @@ -22,7 +22,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await log.debug('Checking for section heading to say Triggers and Actions.'); const headingText = await pageObjects.triggersActionsUI.getSectionHeadingText(); - expect(headingText).to.be('Alerts and actions'); + expect(headingText).to.be('Alerts and Actions'); }); describe('Connectors tab', () => { From e9e6a7291b378ce407e3bb434eff7d31ca62d401 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 20 Dec 2019 09:25:14 -0800 Subject: [PATCH 237/297] Fixed failing unit tests, added new deps --- .../threshold/expression.tsx | 4 +- .../builtin_alert_types/threshold/lib/api.ts | 8 +- .../threshold/visualization.tsx | 5 +- .../application/lib/action_connector_api.ts | 12 +- .../public/application/lib/alert_api.ts | 26 ++-- .../action_connector_form.test.tsx | 23 ++- .../action_type_menu.test.tsx | 27 ++-- .../connector_add_flyout.test.tsx | 23 ++- .../connector_edit_flyout.test.tsx | 27 ++-- .../actions_connectors_list.test.tsx | 87 +++++++---- .../components/alerts_list.test.tsx | 140 ++++++++++-------- .../triggers_actions_ui/public/shim.ts | 48 ------ 12 files changed, 221 insertions(+), 209 deletions(-) delete mode 100644 x-pack/legacy/plugins/triggers_actions_ui/public/shim.ts diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx index b41c759f81dd33..1b2cf96c2f0683 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx @@ -277,9 +277,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = errors, hasErrors, }) => { - const { - core: { http }, - } = useAppDependencies(); + const { http } = useAppDependencies(); const { index, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/lib/api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/lib/api.ts index 0012c2526d05a0..956007049a8216 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/lib/api.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/lib/api.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { HttpServiceBase } from 'kibana/public'; +import { HttpSetup } from 'kibana/public'; const WATCHER_API_ROOT = '/api/watcher'; @@ -14,7 +14,7 @@ export async function getMatchingIndicesForThresholdAlertType({ http, }: { pattern: string; - http: HttpServiceBase; + http: HttpSetup; }): Promise> { if (!pattern.startsWith('*')) { pattern = `*${pattern}`; @@ -33,7 +33,7 @@ export async function getThresholdAlertTypeFields({ http, }: { indexes: string[]; - http: HttpServiceBase; + http: HttpSetup; }): Promise> { const { fields } = await http.post(`${WATCHER_API_ROOT}/fields`, { body: JSON.stringify({ indexes }), @@ -67,7 +67,7 @@ export async function getThresholdAlertVisualizationData({ }: { model: any; visualizeOptions: any; - http: HttpServiceBase; + http: HttpSetup; }): Promise> { const { visualizeData } = await http.post(`${WATCHER_API_ROOT}/watch/visualize`, { body: JSON.stringify({ diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx index 96b3325cbc0113..2570e401dce600 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx @@ -97,10 +97,7 @@ interface Props { } export const ThresholdVisualization: React.FunctionComponent = ({ alert }) => { - const { - core: { http, uiSettings }, - plugins: { toastNotifications }, - } = useAppDependencies(); + const { http, uiSettings, toastNotifications } = useAppDependencies(); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(undefined); const [visualizationData, setVisualizationData] = useState>([]); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts index 72c66da3e6149e..8d13aeaa28ab0c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { HttpServiceBase } from 'kibana/public'; +import { HttpSetup } from 'kibana/public'; import { BASE_ACTION_API_PATH } from '../constants'; import { ActionConnector, ActionConnectorWithoutId, ActionType } from '../../types'; @@ -13,14 +13,14 @@ import { ActionConnector, ActionConnectorWithoutId, ActionType } from '../../typ // We'll set this max setting assuming it's never reached. const MAX_ACTIONS_RETURNED = 10000; -export async function loadActionTypes({ http }: { http: HttpServiceBase }): Promise { +export async function loadActionTypes({ http }: { http: HttpSetup }): Promise { return await http.get(`${BASE_ACTION_API_PATH}/types`); } export async function loadAllActions({ http, }: { - http: HttpServiceBase; + http: HttpSetup; }): Promise<{ page: number; perPage: number; @@ -38,7 +38,7 @@ export async function createActionConnector({ http, connector, }: { - http: HttpServiceBase; + http: HttpSetup; connector: Omit; }): Promise { return await http.post(`${BASE_ACTION_API_PATH}`, { @@ -51,7 +51,7 @@ export async function updateActionConnector({ connector, id, }: { - http: HttpServiceBase; + http: HttpSetup; connector: Pick; id: string; }): Promise { @@ -69,7 +69,7 @@ export async function deleteActions({ http, }: { ids: string[]; - http: HttpServiceBase; + http: HttpSetup; }): Promise { await Promise.all(ids.map(id => http.delete(`${BASE_ACTION_API_PATH}/${id}`))); } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.ts index 56819c5faeb9fa..9867acbd7a622a 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/alert_api.ts @@ -4,11 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { HttpServiceBase } from 'kibana/public'; +import { HttpSetup } from 'kibana/public'; import { BASE_ALERT_API_PATH } from '../constants'; import { Alert, AlertType, AlertWithoutId } from '../../types'; -export async function loadAlertTypes({ http }: { http: HttpServiceBase }): Promise { +export async function loadAlertTypes({ http }: { http: HttpSetup }): Promise { return await http.get(`${BASE_ALERT_API_PATH}/types`); } @@ -19,7 +19,7 @@ export async function loadAlerts({ typesFilter, actionTypesFilter, }: { - http: HttpServiceBase; + http: HttpSetup; page: { index: number; size: number }; searchText?: string; typesFilter?: string[]; @@ -60,7 +60,7 @@ export async function deleteAlerts({ http, }: { ids: string[]; - http: HttpServiceBase; + http: HttpSetup; }): Promise { await Promise.all(ids.map(id => http.delete(`${BASE_ALERT_API_PATH}/${id}`))); } @@ -69,7 +69,7 @@ export async function createAlert({ http, alert, }: { - http: HttpServiceBase; + http: HttpSetup; alert: Omit; }): Promise { return await http.post(`${BASE_ALERT_API_PATH}`, { @@ -82,7 +82,7 @@ export async function updateAlert({ alert, id, }: { - http: HttpServiceBase; + http: HttpSetup; alert: Pick; id: string; }): Promise { @@ -96,7 +96,7 @@ export async function enableAlerts({ http, }: { ids: string[]; - http: HttpServiceBase; + http: HttpSetup; }): Promise { await Promise.all(ids.map(id => http.post(`${BASE_ALERT_API_PATH}/${id}/_enable`))); } @@ -106,18 +106,12 @@ export async function disableAlerts({ http, }: { ids: string[]; - http: HttpServiceBase; + http: HttpSetup; }): Promise { await Promise.all(ids.map(id => http.post(`${BASE_ALERT_API_PATH}/${id}/_disable`))); } -export async function muteAlerts({ - ids, - http, -}: { - ids: string[]; - http: HttpServiceBase; -}): Promise { +export async function muteAlerts({ ids, http }: { ids: string[]; http: HttpSetup }): Promise { await Promise.all(ids.map(id => http.post(`${BASE_ALERT_API_PATH}/${id}/_mute_all`))); } @@ -126,7 +120,7 @@ export async function unmuteAlerts({ http, }: { ids: string[]; - http: HttpServiceBase; + http: HttpSetup; }): Promise { await Promise.all(ids.map(id => http.post(`${BASE_ALERT_API_PATH}/${id}/_unmute_all`))); } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx index 9cf2913bf5e18a..54c7c7cf1292df 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx @@ -5,7 +5,6 @@ */ import * as React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; -import { setAppDependencies } from '../../app_dependencies'; import { coreMock } from '../../../../../../../../../src/core/public/mocks'; import { ReactWrapper } from 'enzyme'; import { act } from 'react-dom/test-utils'; @@ -13,6 +12,7 @@ import { ActionsConnectorsContext } from '../../context/actions_connectors_conte import { actionTypeRegistryMock } from '../../action_type_registry.mock'; import { ValidationResult, ActionConnector } from '../../../types'; import { ActionConnectorForm } from './action_connector_form'; +import { AppContextProvider } from '../../app_context'; jest.mock('../../context/actions_connectors_context'); const actionTypeRegistry = actionTypeRegistryMock.create(); @@ -20,9 +20,16 @@ describe('action_connector_form', () => { let wrapper: ReactWrapper; beforeAll(async () => { + const mockes = coreMock.createSetup(); + const [{ chrome, docLinks }] = await mockes.getStartServices(); const deps = { - core: coreMock.createStart(), - plugins: { + chrome, + docLinks, + toastNotifications: mockes.notifications.toasts, + injectedMetadata: mockes.injectedMetadata, + http: mockes.http, + uiSettings: mockes.uiSettings, + legacy: { capabilities: { get() { return { @@ -33,12 +40,12 @@ describe('action_connector_form', () => { }, }; }, - }, - } as any, + } as any, + MANAGEMENT_BREADCRUMB: { set: () => {} } as any, + }, actionTypeRegistry: actionTypeRegistry as any, alertTypeRegistry: {} as any, }; - const AppDependenciesProvider = setAppDependencies(deps); const actionType = { id: 'my-action-type', @@ -65,7 +72,7 @@ describe('action_connector_form', () => { await act(async () => { wrapper = mountWithIntl( - + { setFlyoutVisibility={() => {}} /> - + ); }); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.test.tsx index d6610de4ea9391..568a4c6d57792e 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.test.tsx @@ -5,24 +5,29 @@ */ import * as React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; -import { setAppDependencies } from '../../app_dependencies'; import { coreMock } from '../../../../../../../../../src/core/public/mocks'; import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; import { actionTypeRegistryMock } from '../../action_type_registry.mock'; -import { AppDependencies } from '../../../../../public/shim'; import { ActionTypeMenu } from './action_type_menu'; import { ValidationResult } from '../../../types'; +import { AppContextProvider } from '../../app_context'; jest.mock('../../context/actions_connectors_context'); const actionTypeRegistry = actionTypeRegistryMock.create(); describe('connector_add_flyout', () => { - let AppDependenciesProvider: React.ProviderExoticComponent>; let deps: any; - beforeAll(() => { + beforeAll(async () => { + const mockes = coreMock.createSetup(); + const [{ chrome, docLinks }] = await mockes.getStartServices(); deps = { - core: coreMock.createStart(), - plugins: { + chrome, + docLinks, + toastNotifications: mockes.notifications.toasts, + injectedMetadata: mockes.injectedMetadata, + http: mockes.http, + uiSettings: mockes.uiSettings, + legacy: { capabilities: { get() { return { @@ -33,12 +38,12 @@ describe('connector_add_flyout', () => { }, }; }, - }, - } as any, + } as any, + MANAGEMENT_BREADCRUMB: { set: () => {} } as any, + }, actionTypeRegistry: actionTypeRegistry as any, alertTypeRegistry: {} as any, }; - AppDependenciesProvider = setAppDependencies(deps); }); it('renders action type menu with proper EuiCards for registered action types', () => { @@ -60,7 +65,7 @@ describe('connector_add_flyout', () => { actionTypeRegistry.get.mockReturnValueOnce(actionType); const wrapper = mountWithIntl( - + { > - + ); expect(wrapper.find('[data-test-subj="first-action-type-card"]').exists()).toBeTruthy(); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.test.tsx index 3aaa4aa5a5aeaa..1b69dc818c2ae8 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.test.tsx @@ -5,7 +5,6 @@ */ import * as React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; -import { setAppDependencies } from '../../app_dependencies'; import { coreMock } from '../../../../../../../../../src/core/public/mocks'; import { ReactWrapper } from 'enzyme'; import { act } from 'react-dom/test-utils'; @@ -13,6 +12,7 @@ import { ConnectorAddFlyout } from './connector_add_flyout'; import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; import { actionTypeRegistryMock } from '../../action_type_registry.mock'; import { ValidationResult } from '../../../types'; +import { AppContextProvider } from '../../app_context'; jest.mock('../../context/actions_connectors_context'); const actionTypeRegistry = actionTypeRegistryMock.create(); @@ -20,9 +20,16 @@ describe('connector_add_flyout', () => { let wrapper: ReactWrapper; beforeAll(async () => { + const mockes = coreMock.createSetup(); + const [{ chrome, docLinks }] = await mockes.getStartServices(); const deps = { - core: coreMock.createStart(), - plugins: { + chrome, + docLinks, + toastNotifications: mockes.notifications.toasts, + injectedMetadata: mockes.injectedMetadata, + http: mockes.http, + uiSettings: mockes.uiSettings, + legacy: { capabilities: { get() { return { @@ -33,16 +40,16 @@ describe('connector_add_flyout', () => { }, }; }, - }, - } as any, + } as any, + MANAGEMENT_BREADCRUMB: { set: () => {} } as any, + }, actionTypeRegistry: actionTypeRegistry as any, alertTypeRegistry: {} as any, }; - const AppDependenciesProvider = setAppDependencies(deps); await act(async () => { wrapper = mountWithIntl( - + { > - + ); }); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx index 3be42e7109287b..b58ac85dd58a7a 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx @@ -5,23 +5,28 @@ */ import * as React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; -import { setAppDependencies } from '../../app_dependencies'; import { coreMock } from '../../../../../../../../../src/core/public/mocks'; import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; import { actionTypeRegistryMock } from '../../action_type_registry.mock'; import { ValidationResult } from '../../../types'; -import { AppDependencies } from '../../../../../public/shim'; import { ConnectorEditFlyout } from './connector_edit_flyout'; +import { AppContextProvider } from '../../app_context'; jest.mock('../../context/actions_connectors_context'); const actionTypeRegistry = actionTypeRegistryMock.create(); -let AppDependenciesProvider: React.ProviderExoticComponent>; let deps: any; describe('connector_edit_flyout', () => { - beforeAll(() => { + beforeAll(async () => { + const mockes = coreMock.createSetup(); + const [{ chrome, docLinks }] = await mockes.getStartServices(); deps = { - core: coreMock.createStart(), - plugins: { + chrome, + docLinks, + toastNotifications: mockes.notifications.toasts, + injectedMetadata: mockes.injectedMetadata, + http: mockes.http, + uiSettings: mockes.uiSettings, + legacy: { capabilities: { get() { return { @@ -32,12 +37,12 @@ describe('connector_edit_flyout', () => { }, }; }, - }, - } as any, + } as any, + MANAGEMENT_BREADCRUMB: { set: () => {} } as any, + }, actionTypeRegistry: actionTypeRegistry as any, alertTypeRegistry: {} as any, }; - AppDependenciesProvider = setAppDependencies(deps); }); test('if input connector render correct in the edit form', () => { @@ -69,7 +74,7 @@ describe('connector_edit_flyout', () => { actionTypeRegistry.has.mockReturnValue(true); const wrapper = mountWithIntl( - + { > - + ); const connectorNameField = wrapper.find('[data-test-subj="nameInput"]'); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx index 78e4d8f87c6871..8f41b31c297593 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx @@ -6,11 +6,11 @@ import * as React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { ActionsConnectorsList } from './actions_connectors_list'; -import { setAppDependencies } from '../../../app_dependencies'; import { coreMock } from '../../../../../../../../../../src/core/public/mocks'; import { ReactWrapper } from 'enzyme'; import { act } from 'react-dom/test-utils'; import { actionTypeRegistryMock } from '../../../action_type_registry.mock'; +import { AppContextProvider } from '../../../app_context'; jest.mock('../../../context/actions_connectors_context'); jest.mock('../../../lib/action_connector_api', () => ({ loadAllActions: jest.fn(), @@ -42,9 +42,16 @@ describe('actions_connectors_list component empty', () => { name: 'Test2', }, ]); + const mockes = coreMock.createSetup(); + const [{ chrome, docLinks }] = await mockes.getStartServices(); const deps = { - core: coreMock.createStart(), - plugins: { + chrome, + docLinks, + toastNotifications: mockes.notifications.toasts, + injectedMetadata: mockes.injectedMetadata, + http: mockes.http, + uiSettings: mockes.uiSettings, + legacy: { capabilities: { get() { return { @@ -55,19 +62,19 @@ describe('actions_connectors_list component empty', () => { }, }; }, - }, - } as any, + } as any, + MANAGEMENT_BREADCRUMB: { set: () => {} } as any, + }, actionTypeRegistry: actionTypeRegistry as any, alertTypeRegistry: {} as any, }; - const AppDependenciesProvider = setAppDependencies(deps); actionTypeRegistry.has.mockReturnValue(true); await act(async () => { wrapper = mountWithIntl( - + - + ); }); @@ -128,9 +135,17 @@ describe('actions_connectors_list component with items', () => { name: 'Test2', }, ]); + + const mockes = coreMock.createSetup(); + const [{ chrome, docLinks }] = await mockes.getStartServices(); const deps = { - core: coreMock.createStart(), - plugins: { + chrome, + docLinks, + toastNotifications: mockes.notifications.toasts, + injectedMetadata: mockes.injectedMetadata, + http: mockes.http, + uiSettings: mockes.uiSettings, + legacy: { capabilities: { get() { return { @@ -141,8 +156,9 @@ describe('actions_connectors_list component with items', () => { }, }; }, - }, - } as any, + } as any, + MANAGEMENT_BREADCRUMB: { set: () => {} } as any, + }, actionTypeRegistry: { get() { return null; @@ -150,13 +166,12 @@ describe('actions_connectors_list component with items', () => { } as any, alertTypeRegistry: {} as any, }; - const AppDependenciesProvider = setAppDependencies(deps); await act(async () => { wrapper = mountWithIntl( - + - + ); }); @@ -202,9 +217,16 @@ describe('actions_connectors_list component empty with show only capability', () name: 'Test2', }, ]); + const mockes = coreMock.createSetup(); + const [{ chrome, docLinks }] = await mockes.getStartServices(); const deps = { - core: coreMock.createStart(), - plugins: { + chrome, + docLinks, + toastNotifications: mockes.notifications.toasts, + injectedMetadata: mockes.injectedMetadata, + http: mockes.http, + uiSettings: mockes.uiSettings, + legacy: { capabilities: { get() { return { @@ -215,8 +237,9 @@ describe('actions_connectors_list component empty with show only capability', () }, }; }, - }, - } as any, + } as any, + MANAGEMENT_BREADCRUMB: { set: () => {} } as any, + }, actionTypeRegistry: { get() { return null; @@ -224,13 +247,12 @@ describe('actions_connectors_list component empty with show only capability', () } as any, alertTypeRegistry: {} as any, }; - const AppDependenciesProvider = setAppDependencies(deps); await act(async () => { wrapper = mountWithIntl( - + - + ); }); @@ -281,9 +303,16 @@ describe('actions_connectors_list with show only capability', () => { name: 'Test2', }, ]); + const mockes = coreMock.createSetup(); + const [{ chrome, docLinks }] = await mockes.getStartServices(); const deps = { - core: coreMock.createStart(), - plugins: { + chrome, + docLinks, + toastNotifications: mockes.notifications.toasts, + injectedMetadata: mockes.injectedMetadata, + http: mockes.http, + uiSettings: mockes.uiSettings, + legacy: { capabilities: { get() { return { @@ -294,8 +323,9 @@ describe('actions_connectors_list with show only capability', () => { }, }; }, - }, - } as any, + } as any, + MANAGEMENT_BREADCRUMB: { set: () => {} } as any, + }, actionTypeRegistry: { get() { return null; @@ -303,13 +333,12 @@ describe('actions_connectors_list with show only capability', () => { } as any, alertTypeRegistry: {} as any, }; - const AppDependenciesProvider = setAppDependencies(deps); await act(async () => { wrapper = mountWithIntl( - + - + ); }); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx index 9fe274803ca75b..f34c18877ba745 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx @@ -5,7 +5,6 @@ */ import * as React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; -import { setAppDependencies } from '../../../app_dependencies'; import { coreMock } from '../../../../../../../../../../src/core/public/mocks'; import { ReactWrapper } from 'enzyme'; import { act } from 'react-dom/test-utils'; @@ -13,6 +12,7 @@ import { actionTypeRegistryMock } from '../../../action_type_registry.mock'; import { alertTypeRegistryMock } from '../../../alert_type_registry.mock'; import { AlertsList } from './alerts_list'; import { ValidationResult } from '../../../../types'; +import { AppContextProvider } from '../../../app_context'; jest.mock('../../../context/alerts_context'); jest.mock('../../../lib/action_connector_api', () => ({ loadActionTypes: jest.fn(), @@ -69,18 +69,23 @@ describe('alerts_list component empty', () => { total: 0, data: [], }); + + const mockes = coreMock.createSetup(); + const [{ chrome, docLinks }] = await mockes.getStartServices(); const deps = { - core: { - ...coreMock.createStart(), - injectedMetadata: { - getInjectedVar(name: string) { - if (name === 'createAlertUiEnabled') { - return true; - } - }, + chrome, + docLinks, + toastNotifications: mockes.notifications.toasts, + injectedMetadata: { + getInjectedVar(name: string) { + if (name === 'createAlertUiEnabled') { + return true; + } }, - }, - plugins: { + } as any, + http: mockes.http, + uiSettings: mockes.uiSettings, + legacy: { capabilities: { get() { return { @@ -91,17 +96,18 @@ describe('alerts_list component empty', () => { }, }; }, - }, - } as any, + } as any, + MANAGEMENT_BREADCRUMB: { set: () => {} } as any, + }, actionTypeRegistry: actionTypeRegistry as any, alertTypeRegistry: alertTypeRegistry as any, }; - const AppDependenciesProvider = setAppDependencies(deps); + await act(async () => { wrapper = mountWithIntl( - + - + ); }); @@ -187,18 +193,22 @@ describe('alerts_list component with items', () => { total: 0, data: [], }); + const mockes = coreMock.createSetup(); + const [{ chrome, docLinks }] = await mockes.getStartServices(); const deps = { - core: { - ...coreMock.createStart(), - injectedMetadata: { - getInjectedVar(name: string) { - if (name === 'createAlertUiEnabled') { - return true; - } - }, + chrome, + docLinks, + toastNotifications: mockes.notifications.toasts, + injectedMetadata: { + getInjectedVar(name: string) { + if (name === 'createAlertUiEnabled') { + return true; + } }, - }, - plugins: { + } as any, + http: mockes.http, + uiSettings: mockes.uiSettings, + legacy: { capabilities: { get() { return { @@ -209,18 +219,18 @@ describe('alerts_list component with items', () => { }, }; }, - }, - } as any, + } as any, + MANAGEMENT_BREADCRUMB: { set: () => {} } as any, + }, actionTypeRegistry: actionTypeRegistry as any, alertTypeRegistry: alertTypeRegistry as any, }; - const AppDependenciesProvider = setAppDependencies(deps); await act(async () => { wrapper = mountWithIntl( - + - + ); }); @@ -267,18 +277,22 @@ describe('alerts_list component empty with show only capability', () => { total: 0, data: [], }); + const mockes = coreMock.createSetup(); + const [{ chrome, docLinks }] = await mockes.getStartServices(); const deps = { - core: { - ...coreMock.createStart(), - injectedMetadata: { - getInjectedVar(name: string) { - if (name === 'createAlertUiEnabled') { - return true; - } - }, + chrome, + docLinks, + toastNotifications: mockes.notifications.toasts, + injectedMetadata: { + getInjectedVar(name: string) { + if (name === 'createAlertUiEnabled') { + return true; + } }, - }, - plugins: { + } as any, + http: mockes.http, + uiSettings: mockes.uiSettings, + legacy: { capabilities: { get() { return { @@ -289,8 +303,9 @@ describe('alerts_list component empty with show only capability', () => { }, }; }, - }, - } as any, + } as any, + MANAGEMENT_BREADCRUMB: { set: () => {} } as any, + }, actionTypeRegistry: { get() { return null; @@ -298,13 +313,12 @@ describe('alerts_list component empty with show only capability', () => { } as any, alertTypeRegistry: {} as any, }; - const AppDependenciesProvider = setAppDependencies(deps); await act(async () => { wrapper = mountWithIntl( - + - + ); }); @@ -382,18 +396,22 @@ describe('alerts_list with show only capability', () => { total: 0, data: [], }); + const mockes = coreMock.createSetup(); + const [{ chrome, docLinks }] = await mockes.getStartServices(); const deps = { - core: { - ...coreMock.createStart(), - injectedMetadata: { - getInjectedVar(name: string) { - if (name === 'createAlertUiEnabled') { - return true; - } - }, + chrome, + docLinks, + toastNotifications: mockes.notifications.toasts, + injectedMetadata: { + getInjectedVar(name: string) { + if (name === 'createAlertUiEnabled') { + return true; + } }, - }, - plugins: { + } as any, + http: mockes.http, + uiSettings: mockes.uiSettings, + legacy: { capabilities: { get() { return { @@ -404,18 +422,18 @@ describe('alerts_list with show only capability', () => { }, }; }, - }, - } as any, + } as any, + MANAGEMENT_BREADCRUMB: { set: () => {} } as any, + }, actionTypeRegistry: actionTypeRegistry as any, alertTypeRegistry: alertTypeRegistry as any, }; - const AppDependenciesProvider = setAppDependencies(deps); await act(async () => { wrapper = mountWithIntl( - + - + ); }); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/public/shim.ts b/x-pack/legacy/plugins/triggers_actions_ui/public/shim.ts deleted file mode 100644 index 1a655d5f9a74b3..00000000000000 --- a/x-pack/legacy/plugins/triggers_actions_ui/public/shim.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { management, MANAGEMENT_BREADCRUMB } from 'ui/management'; -import { capabilities } from 'ui/capabilities'; -import { CoreStart } from 'kibana/public'; -import { toastNotifications } from 'ui/notify'; -import { docTitle } from 'ui/doc_title/doc_title'; -import { ActionTypeRegistry } from '../np_ready/public/application/action_type_registry'; -import { AlertTypeRegistry } from '../np_ready/public/application/alert_type_registry'; - -export interface AppPlugins { - management: { - breadcrumb: typeof MANAGEMENT_BREADCRUMB; - }; - capabilities: typeof capabilities; - toastNotifications: typeof toastNotifications; - docTitle: typeof docTitle; -} - -export interface AppDependencies { - core: CoreStart; - plugins: AppPlugins; - actionTypeRegistry: ActionTypeRegistry; - alertTypeRegistry: AlertTypeRegistry; -} - -export function createShim() { - return { - pluginsSetup: { - capabilities, - management: { - getSection: management.getSection.bind(management), - }, - }, - pluginsStart: { - docTitle, - capabilities, - toastNotifications, - management: { - breadcrumb: MANAGEMENT_BREADCRUMB, - }, - }, - }; -} From 74ac9c7bb4c258a0b481b22708d87728cf2635f7 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 20 Dec 2019 09:35:20 -0800 Subject: [PATCH 238/297] Fixed type checks --- .../components/actions_connectors_list.tsx | 3 ++- .../sections/alerts_list/components/alerts_list.tsx | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index 0e2f288fbff0b7..80372d6e20118c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -202,6 +202,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { }, }, { + field: '', name: '', actions: [ { @@ -264,7 +265,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { setSelectedItems(updatedSelectedItemsList); }, } - : null + : undefined } search={{ filters: [ diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 33a28a6d57d7c5..cb653218d5c1d0 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -272,7 +272,7 @@ export const AlertsList: React.FunctionComponent = () => { setSelectedIds(updatedSelectedItemsList.map(item => item.id)); }, } - : null + : undefined } onChange={({ page: changedPage }: { page: Pagination }) => { setPage(changedPage); From db143438876ee3736f0baa00455507de68f1bd3f Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 20 Dec 2019 10:40:55 -0800 Subject: [PATCH 239/297] Fixed language check failing --- .../np_ready/public/application/constants/plugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/plugin.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/plugin.ts index 5eab6fc9c93ed5..63ba7df2556de3 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/plugin.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/plugin.ts @@ -7,7 +7,7 @@ export const PLUGIN = { ID: 'triggers_actions_ui', getI18nName: (i18n: any): string => { - return i18n.translate('xpack.triggers_actions_ui.appName', { + return i18n.translate('xpack.triggersActionsUI.appName', { defaultMessage: 'Alerts and Actions', }); }, From 7640f8f5a87cfbc34e47f592f03429f9707eaee8 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 20 Dec 2019 15:08:06 -0500 Subject: [PATCH 240/297] Fix broken functional tests --- .../sections/alerts_list/components/alerts_list.tsx | 2 +- .../functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 33a28a6d57d7c5..9e0aef64a1fa17 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -166,7 +166,7 @@ export const AlertsList: React.FunctionComponent = () => { 'data-test-subj': 'alertsTableCell-alertType', }, { - field: 'interval', + field: 'schedule.interval', name: i18n.translate( 'xpack.triggersActionsUI.sections.alertsList.alertsListTable.columns.intervalTitle', { defaultMessage: 'Runs every' } diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts index 1b406adc6bcf78..9ad3b6124dad13 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts @@ -27,7 +27,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { name: generateUniqueKey(), tags: ['foo', 'bar'], alertTypeId: 'test.noop', - interval: '1m', + consumer: 'test', + schedule: { interval: '1m' }, throttle: '1m', actions: [], params: {}, From bd2741187cb72048d723e3b4aab2dc5195fee1af Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 20 Dec 2019 12:38:39 -0800 Subject: [PATCH 241/297] Refactored actionConnectors and alerting context --- .../context/actions_connectors_context.tsx | 26 ++++++++++++++++--- .../application/context/alerts_context.tsx | 24 ++++++++++++++--- .../action_connector_form.test.tsx | 7 +++-- .../action_connector_form.tsx | 14 +++++----- .../action_type_menu.test.tsx | 7 +++-- .../action_type_menu.tsx | 6 ++--- .../connector_add_flyout.test.tsx | 7 +++-- .../connector_add_flyout.tsx | 6 ++--- .../connector_edit_flyout.test.tsx | 7 +++-- .../connector_edit_flyout.tsx | 6 ++--- .../actions_connectors_list.test.tsx | 1 - .../components/actions_connectors_list.tsx | 6 ++--- .../sections/alert_add/alert_add.tsx | 4 +-- .../components/alerts_list.test.tsx | 1 - .../alerts_list/components/alerts_list.tsx | 6 ++--- 15 files changed, 80 insertions(+), 48 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_connectors_context.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_connectors_context.tsx index 95761b2b83248c..11786950d0f263 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_connectors_context.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/actions_connectors_context.tsx @@ -4,10 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { createContext, useContext } from 'react'; import { ActionType } from '../../types'; -export interface IActionsConnectorsContext { +export interface ActionsConnectorsContextValue { addFlyoutVisible: boolean; editFlyoutVisible: boolean; setEditFlyoutVisibility: React.Dispatch>; @@ -16,4 +16,24 @@ export interface IActionsConnectorsContext { reloadConnectors: () => Promise; } -export const ActionsConnectorsContext = React.createContext({} as IActionsConnectorsContext); +const ActionsConnectorsContext = createContext(null as any); + +export const ActionsConnectorsContextProvider = ({ + children, + value, +}: { + value: ActionsConnectorsContextValue; + children: React.ReactNode; +}) => { + return ( + {children} + ); +}; + +export const useActionsConnectorsContext = () => { + const ctx = useContext(ActionsConnectorsContext); + if (!ctx) { + throw new Error('ActionsConnectorsContext has not been set.'); + } + return ctx; +}; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/alerts_context.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/alerts_context.tsx index b31cf8ea5169ed..06be1bb7c58516 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/alerts_context.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/context/alerts_context.tsx @@ -4,11 +4,29 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { useContext, createContext } from 'react'; -export interface IAlertsContext { +export interface AlertsContextValue { alertFlyoutVisible: boolean; setAlertFlyoutVisibility: React.Dispatch>; } -export const AlertsContext = React.createContext({} as IAlertsContext); +const AlertsContext = createContext(null as any); + +export const AlertsContextProvider = ({ + children, + value, +}: { + value: AlertsContextValue; + children: React.ReactNode; +}) => { + return {children}; +}; + +export const useAlertsContext = () => { + const ctx = useContext(AlertsContext); + if (!ctx) { + throw new Error('ActionsConnectorsContext has not been set.'); + } + return ctx; +}; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx index 54c7c7cf1292df..e53e05266519b4 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx @@ -8,12 +8,11 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { coreMock } from '../../../../../../../../../src/core/public/mocks'; import { ReactWrapper } from 'enzyme'; import { act } from 'react-dom/test-utils'; -import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; +import { ActionsConnectorsContextProvider } from '../../context/actions_connectors_context'; import { actionTypeRegistryMock } from '../../action_type_registry.mock'; import { ValidationResult, ActionConnector } from '../../../types'; import { ActionConnectorForm } from './action_connector_form'; import { AppContextProvider } from '../../app_context'; -jest.mock('../../context/actions_connectors_context'); const actionTypeRegistry = actionTypeRegistryMock.create(); describe('action_connector_form', () => { @@ -73,7 +72,7 @@ describe('action_connector_form', () => { await act(async () => { wrapper = mountWithIntl( - {}, @@ -92,7 +91,7 @@ describe('action_connector_form', () => { initialConnector={initialConnector} setFlyoutVisibility={() => {}} /> - + ); }); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index d4d7a0833d2575..bf386fee886a53 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, useContext, useState, useReducer, useEffect } from 'react'; +import React, { Fragment, useState, useReducer, useEffect } from 'react'; import { EuiButton, EuiFlexGroup, @@ -24,7 +24,7 @@ import { createActionConnector, updateActionConnector } from '../../lib/action_c import { SectionError, ErrableFormRow } from '../../components/page_error'; import { useAppDependencies } from '../../app_context'; import { connectorReducer } from './connector_reducer'; -import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; +import { useActionsConnectorsContext } from '../../context/actions_connectors_context'; import { ActionConnector, IErrorObject } from '../../../types'; import { hasSaveActionsCapability } from '../../lib/capabilities'; @@ -46,7 +46,7 @@ export const ActionConnectorForm = ({ actionTypeRegistry, } = useAppDependencies(); - const { reloadConnectors } = useContext(ActionsConnectorsContext); + const { reloadConnectors } = useActionsConnectorsContext(); const canSave = hasSaveActionsCapability(capabilities.get()); // hooks @@ -202,9 +202,9 @@ export const ActionConnectorForm = ({ { @@ -66,7 +65,7 @@ describe('connector_add_flyout', () => { const wrapper = mountWithIntl( - {}, @@ -82,7 +81,7 @@ describe('connector_add_flyout', () => { }} > - + ); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx index 55ff4e1ff7016e..4356bf7d512651 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, useContext } from 'react'; +import React, { Fragment } from 'react'; import { EuiFlexGroup, EuiFlexItem, @@ -16,7 +16,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ActionType } from '../../../types'; -import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; +import { useActionsConnectorsContext } from '../../context/actions_connectors_context'; import { useAppDependencies } from '../../app_context'; interface Props { @@ -25,7 +25,7 @@ interface Props { export const ActionTypeMenu = ({ onActionTypeChange }: Props) => { const { actionTypeRegistry } = useAppDependencies(); - const { actionTypesIndex, setAddFlyoutVisibility } = useContext(ActionsConnectorsContext); + const { actionTypesIndex, setAddFlyoutVisibility } = useActionsConnectorsContext(); if (!actionTypesIndex) { return null; } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.test.tsx index 1b69dc818c2ae8..84bd26c222b1f2 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.test.tsx @@ -9,11 +9,10 @@ import { coreMock } from '../../../../../../../../../src/core/public/mocks'; import { ReactWrapper } from 'enzyme'; import { act } from 'react-dom/test-utils'; import { ConnectorAddFlyout } from './connector_add_flyout'; -import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; +import { ActionsConnectorsContextProvider } from '../../context/actions_connectors_context'; import { actionTypeRegistryMock } from '../../action_type_registry.mock'; import { ValidationResult } from '../../../types'; import { AppContextProvider } from '../../app_context'; -jest.mock('../../context/actions_connectors_context'); const actionTypeRegistry = actionTypeRegistryMock.create(); describe('connector_add_flyout', () => { @@ -50,7 +49,7 @@ describe('connector_add_flyout', () => { await act(async () => { wrapper = mountWithIntl( - {}, @@ -63,7 +62,7 @@ describe('connector_add_flyout', () => { }} > - + ); }); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx index 19f658e97a40ab..b487b4fdaad89b 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { useContext, useCallback, useState, useEffect, Fragment } from 'react'; +import React, { useCallback, useState, useEffect, Fragment } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiTitle, @@ -14,7 +14,7 @@ import { EuiIcon, EuiText, } from '@elastic/eui'; -import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; +import { useActionsConnectorsContext } from '../../context/actions_connectors_context'; import { ActionTypeMenu } from './action_type_menu'; import { ActionConnectorForm } from './action_connector_form'; import { ActionType, ActionConnector } from '../../../types'; @@ -22,7 +22,7 @@ import { useAppDependencies } from '../../app_context'; export const ConnectorAddFlyout = () => { const { actionTypeRegistry } = useAppDependencies(); - const { addFlyoutVisible, setAddFlyoutVisibility } = useContext(ActionsConnectorsContext); + const { addFlyoutVisible, setAddFlyoutVisibility } = useActionsConnectorsContext(); const [actionType, setActionType] = useState(undefined); const closeFlyout = useCallback(() => setAddFlyoutVisibility(false), [setAddFlyoutVisibility]); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx index b58ac85dd58a7a..bdddd6aa5dea27 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.test.tsx @@ -6,12 +6,11 @@ import * as React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { coreMock } from '../../../../../../../../../src/core/public/mocks'; -import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; +import { ActionsConnectorsContextProvider } from '../../context/actions_connectors_context'; import { actionTypeRegistryMock } from '../../action_type_registry.mock'; import { ValidationResult } from '../../../types'; import { ConnectorEditFlyout } from './connector_edit_flyout'; import { AppContextProvider } from '../../app_context'; -jest.mock('../../context/actions_connectors_context'); const actionTypeRegistry = actionTypeRegistryMock.create(); let deps: any; @@ -75,7 +74,7 @@ describe('connector_edit_flyout', () => { const wrapper = mountWithIntl( - {}, @@ -90,7 +89,7 @@ describe('connector_edit_flyout', () => { }} > - + ); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx index 54aa8ab5d69d82..7bd921af17ee76 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { useContext, useCallback } from 'react'; +import React, { useCallback } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiTitle, @@ -13,7 +13,7 @@ import { EuiFlexItem, EuiIcon, } from '@elastic/eui'; -import { ActionsConnectorsContext } from '../../context/actions_connectors_context'; +import { useActionsConnectorsContext } from '../../context/actions_connectors_context'; import { ActionConnectorForm } from './action_connector_form'; import { useAppDependencies } from '../../app_context'; import { ActionConnectorTableItem } from '../../../types'; @@ -24,7 +24,7 @@ export interface ConnectorEditProps { export const ConnectorEditFlyout = ({ connector }: ConnectorEditProps) => { const { actionTypeRegistry } = useAppDependencies(); - const { editFlyoutVisible, setEditFlyoutVisibility } = useContext(ActionsConnectorsContext); + const { editFlyoutVisible, setEditFlyoutVisibility } = useActionsConnectorsContext(); const closeFlyout = useCallback(() => setEditFlyoutVisibility(false), [setEditFlyoutVisibility]); if (!editFlyoutVisible) { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx index 8f41b31c297593..b4c45238792ce2 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.test.tsx @@ -11,7 +11,6 @@ import { ReactWrapper } from 'enzyme'; import { act } from 'react-dom/test-utils'; import { actionTypeRegistryMock } from '../../../action_type_registry.mock'; import { AppContextProvider } from '../../../app_context'; -jest.mock('../../../context/actions_connectors_context'); jest.mock('../../../lib/action_connector_api', () => ({ loadAllActions: jest.fn(), loadActionTypes: jest.fn(), diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index 80372d6e20118c..55e967792c7cf4 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -17,7 +17,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { ActionsConnectorsContext } from '../../../context/actions_connectors_context'; +import { ActionsConnectorsContextProvider } from '../../../context/actions_connectors_context'; import { useAppDependencies } from '../../../app_context'; import { deleteActions, loadAllActions, loadActionTypes } from '../../../lib/action_connector_api'; import { ActionConnector, ActionConnectorTableItem, ActionTypeIndex } from '../../../../types'; @@ -233,7 +233,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => {
- { )} {editedConnectorItem ? : null} - +
); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 2368a5675c9d1b..03801360377d91 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -37,7 +37,7 @@ import { import { useAppDependencies } from '../../app_context'; import { createAlert } from '../../lib/alert_api'; import { loadActionTypes, loadAllActions } from '../../lib/action_connector_api'; -import { AlertsContext } from '../../context/alerts_context'; +import { useAlertsContext } from '../../context/alerts_context'; import { alertReducer } from './alert_reducer'; import { ErrableFormRow, SectionError } from '../../components/page_error'; import { @@ -100,7 +100,7 @@ export const AlertAdd = ({ refreshList }: Props) => { tags: [], }; - const { alertFlyoutVisible, setAlertFlyoutVisibility } = useContext(AlertsContext); + const { alertFlyoutVisible, setAlertFlyoutVisibility } = useAlertsContext(); // hooks const [alertType, setAlertType] = useState(undefined); const [{ alert }, dispatch] = useReducer(alertReducer, { alert: initialAlert }); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx index f34c18877ba745..0f896898c8d1d9 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx @@ -13,7 +13,6 @@ import { alertTypeRegistryMock } from '../../../alert_type_registry.mock'; import { AlertsList } from './alerts_list'; import { ValidationResult } from '../../../../types'; import { AppContextProvider } from '../../../app_context'; -jest.mock('../../../context/alerts_context'); jest.mock('../../../lib/action_connector_api', () => ({ loadActionTypes: jest.fn(), loadAllActions: jest.fn(), diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 6eb82c1852f0d8..9f8b063917f771 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -10,7 +10,7 @@ import React, { Fragment, useEffect, useState } from 'react'; // @ts-ignore: EuiSearchBar not exported in TypeScript import { EuiBasicTable, EuiButton, EuiFilterButton, EuiSearchBar, EuiSpacer } from '@elastic/eui'; -import { AlertsContext } from '../../../context/alerts_context'; +import { AlertsContextProvider } from '../../../context/alerts_context'; import { useAppDependencies } from '../../../app_context'; import { ActionType, Alert, AlertTableItem, AlertTypeIndex, Pagination } from '../../../../types'; import { AlertAdd } from '../../alert_add'; @@ -225,7 +225,7 @@ export const AlertsList: React.FunctionComponent = () => {
- + setSearchText(queryText)} toolsLeft={ @@ -279,7 +279,7 @@ export const AlertsList: React.FunctionComponent = () => { }} /> - +
); From 69da968bfa2cda20661c240c00675e1486cfba21 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 20 Dec 2019 13:12:49 -0800 Subject: [PATCH 242/297] Removed doc title service --- .../np_ready/public/application/home.tsx | 4 +- .../public/application/lib/breadcrumb.test.ts | 31 +++++++++++ .../public/application/lib/breadcrumb.ts | 16 +++--- .../public/application/lib/doc_title.test.ts | 51 +++---------------- .../public/application/lib/doc_title.ts | 49 +++++++----------- 5 files changed, 66 insertions(+), 85 deletions(-) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.test.ts diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx index d80150a0c0a22c..3312f1a103b29a 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/home.tsx @@ -20,7 +20,7 @@ import { import { BASE_PATH, Section, routeToConnectors, routeToAlerts } from './constants'; import { getCurrentBreadcrumb } from './lib/breadcrumb'; -import { docTitleService } from './lib/doc_title'; +import { getCurrentDocTitle } from './lib/doc_title'; import { useAppDependencies } from './app_context'; import { hasShowActionsCapability, hasShowAlertsCapability } from './lib/capabilities'; @@ -80,7 +80,7 @@ export const TriggersActionsUIHome: React.FunctionComponent { chrome.setBreadcrumbs([MANAGEMENT_BREADCRUMB, getCurrentBreadcrumb(section || 'home')]); - docTitleService.setTitle(section || 'home'); + chrome.docTitle.change(getCurrentDocTitle(section || 'home')); }, [section, chrome, MANAGEMENT_BREADCRUMB]); return ( diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.test.ts new file mode 100644 index 00000000000000..b75e014640d722 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.test.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { getCurrentBreadcrumb } from './breadcrumb'; +import { i18n } from '@kbn/i18n'; +import { routeToConnectors, routeToAlerts, routeToHome } from '../constants'; + +describe('getCurrentBreadcrumb', () => { + test('if change calls return proper breadcrumb title ', async () => { + expect(getCurrentBreadcrumb('connectors')).toMatchObject({ + text: i18n.translate('xpack.triggersActionsUI.connectors.breadcrumbTitle', { + defaultMessage: 'Connectors', + }), + href: `#${routeToConnectors}`, + }); + expect(getCurrentBreadcrumb('alerts')).toMatchObject({ + text: i18n.translate('xpack.triggersActionsUI.alerts.breadcrumbTitle', { + defaultMessage: 'Alerts', + }), + href: `#${routeToAlerts}`, + }); + expect(getCurrentBreadcrumb('home')).toMatchObject({ + text: i18n.translate('xpack.triggersActionsUI.home.breadcrumbTitle', { + defaultMessage: 'Alerts and Actions', + }), + href: `#${routeToHome}`, + }); + }); +}); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.ts index 99a6234a523bfc..f833ae9eb39ac0 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/breadcrumb.ts @@ -7,16 +7,9 @@ import { i18n } from '@kbn/i18n'; import { routeToHome, routeToConnectors, routeToAlerts } from '../constants'; -export const getCurrentBreadcrumb = (type: string): any => { +export const getCurrentBreadcrumb = (type: string): { text: string; href: string } => { // Home and sections switch (type) { - case 'home': - return { - text: i18n.translate('xpack.triggersActionsUI.home.breadcrumbTitle', { - defaultMessage: 'Alerts and Actions', - }), - href: `#${routeToHome}`, - }; case 'connectors': return { text: i18n.translate('xpack.triggersActionsUI.connectors.breadcrumbTitle', { @@ -31,5 +24,12 @@ export const getCurrentBreadcrumb = (type: string): any => { }), href: `#${routeToAlerts}`, }; + default: + return { + text: i18n.translate('xpack.triggersActionsUI.home.breadcrumbTitle', { + defaultMessage: 'Alerts and Actions', + }), + href: `#${routeToHome}`, + }; } }; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.test.ts index 2746abe4c82b86..f351adf79eb2c1 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.test.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.test.ts @@ -3,51 +3,12 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { docTitleService } from './doc_title'; -import { coreMock } from '../../../../../../../../src/core/public/mocks'; +import { getCurrentDocTitle } from './doc_title'; -describe('doc_title', () => { - test('if change calls set proper breadcrumb title ', async () => { - const core = coreMock.createStart(); - const spy = jest.spyOn(core.chrome.docTitle, 'change'); - docTitleService.init(spy); - docTitleService.setTitle('home'); - docTitleService.setTitle('alerts'); - docTitleService.setTitle('connectors'); - expect(core.chrome.docTitle).toMatchInlineSnapshot(` - Object { - "__legacy": Object { - "setBaseTitle": [MockFunction], - }, - "change": [MockFunction] { - "calls": Array [ - Array [ - "Alerts and Actions", - ], - Array [ - "Alerts", - ], - Array [ - "Connectors", - ], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - Object { - "type": "return", - "value": undefined, - }, - Object { - "type": "return", - "value": undefined, - }, - ], - }, - "reset": [MockFunction], - } - `); +describe('getCurrentDocTitle', () => { + test('if change calls return the proper doc title ', async () => { + expect(getCurrentDocTitle('home') === 'Alerts and Actions').toBeTruthy(); + expect(getCurrentDocTitle('connectors') === 'Connectors').toBeTruthy(); + expect(getCurrentDocTitle('alerts') === 'Alerts').toBeTruthy(); }); }); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.ts index bcca98f19a9e44..15bd6bc77b1328 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/doc_title.ts @@ -5,35 +5,24 @@ */ import { i18n } from '@kbn/i18n'; -class DocTitleService { - private changeDocTitle: any = () => {}; +export const getCurrentDocTitle = (page: string): string => { + let updatedTitle: string; - public init(changeDocTitle: any): void { - this.changeDocTitle = changeDocTitle; + switch (page) { + case 'connectors': + updatedTitle = i18n.translate('xpack.triggersActionsUI.connectors.breadcrumbTitle', { + defaultMessage: 'Connectors', + }); + break; + case 'alerts': + updatedTitle = i18n.translate('xpack.triggersActionsUI.alerts.breadcrumbTitle', { + defaultMessage: 'Alerts', + }); + break; + default: + updatedTitle = i18n.translate('xpack.triggersActionsUI.home.breadcrumbTitle', { + defaultMessage: 'Alerts and Actions', + }); } - - public setTitle(page?: string): void { - let updatedTitle: string; - - switch (page) { - case 'connectors': - updatedTitle = i18n.translate('xpack.triggersActionsUI.connectors.breadcrumbTitle', { - defaultMessage: 'Connectors', - }); - break; - case 'alerts': - updatedTitle = i18n.translate('xpack.triggersActionsUI.alerts.breadcrumbTitle', { - defaultMessage: 'Alerts', - }); - break; - default: - updatedTitle = i18n.translate('xpack.triggersActionsUI.home.breadcrumbTitle', { - defaultMessage: 'Alerts and Actions', - }); - } - - this.changeDocTitle(updatedTitle); - } -} - -export const docTitleService = new DocTitleService(); + return updatedTitle; +}; From f67df65264ffef00ea0e4127f5d5cb559af4a23f Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 20 Dec 2019 13:33:57 -0800 Subject: [PATCH 243/297] added get time options type definitions --- .../threshold/expression.tsx | 6 +++--- .../application/lib/get_time_options.test.ts | 20 ++++--------------- .../application/lib/get_time_options.ts | 13 +++++++++--- 3 files changed, 17 insertions(+), 22 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx index 1b2cf96c2f0683..b14afba657613d 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx @@ -465,18 +465,18 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = // reset time field and expression fields if indices are deleted if (indices.length === 0) { - setTimeFieldOptions(getTimeFieldOptions([], firstFieldOption)); + setTimeFieldOptions([firstFieldOption]); setAlertParams('timeFields', []); setDefaultExpressionValues(); return; } const currentEsFields = await getFields(indices); - const timeFields = getTimeFieldOptions(currentEsFields, firstFieldOption); + const timeFields = getTimeFieldOptions(currentEsFields as any); setEsFields(currentEsFields); setAlertParams('timeFields', timeFields); - setTimeFieldOptions(timeFields); + setTimeFieldOptions([firstFieldOption, ...timeFields]); }} onSearchChange={async search => { setIsIndiciesLoading(true); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/get_time_options.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/get_time_options.test.ts index 534e461d5b2346..3ed7eea026db48 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/get_time_options.test.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/get_time_options.test.ts @@ -27,22 +27,10 @@ describe('get_time_options', () => { }); test('if getTimeFieldOptions return only date type fields', () => { - const timeOnlyTypeFields = getTimeFieldOptions( - [ - { type: 'date', name: 'order_date' }, - { type: 'number', name: 'sum' }, - ], - { - text: 'select', - value: '', - } - ); - expect(timeOnlyTypeFields).toMatchObject([ - { - text: 'select', - value: '', - }, - { text: 'order_date', value: 'order_date' }, + const timeOnlyTypeFields = getTimeFieldOptions([ + { type: 'date', name: 'order_date' }, + { type: 'number', name: 'sum' }, ]); + expect(timeOnlyTypeFields).toMatchObject([{ text: 'order_date', value: 'order_date' }]); }); }); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/get_time_options.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/get_time_options.ts index 5df6b83a07a276..d24f20a4fc289d 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/get_time_options.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/get_time_options.ts @@ -15,10 +15,17 @@ export const getTimeOptions = (unitSize: string) => }; }); -export const getTimeFieldOptions = (fields: any, firstFieldOption: any) => { - const options = [firstFieldOption]; +interface TimeFieldOptions { + text: string; + value: string; +} - fields.forEach((field: any) => { +export const getTimeFieldOptions = ( + fields: Array<{ type: string; name: string }> +): TimeFieldOptions[] => { + const options: TimeFieldOptions[] = []; + + fields.forEach((field: { type: string; name: string }) => { if (field.type === 'date') { options.push({ text: field.name, From 007bdcd0e16cd0c18c253b304bf35fd65a19796d Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 20 Dec 2019 13:37:42 -0800 Subject: [PATCH 244/297] removed obsolete code --- .../application/components/builtin_action_types/email.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx index 1cfafb85257491..7b483ee8fbcba8 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx @@ -118,9 +118,9 @@ export function getActionType(): ActionTypeModel { }; validationResult.errors = errors; if ( - (!actionParams.to || !(actionParams.to instanceof Array) || actionParams.to.length === 0) && - (!actionParams.cc || !(actionParams.cc instanceof Array) || actionParams.cc.length === 0) && - (!actionParams.bcc || !(actionParams.bcc instanceof Array) || actionParams.bcc.length === 0) + (!(actionParams.to instanceof Array) || actionParams.to.length === 0) && + (!(actionParams.cc instanceof Array) || actionParams.cc.length === 0) && + (!(actionParams.bcc instanceof Array) || actionParams.bcc.length === 0) ) { const errorText = i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredEntryText', From 95488ea89505a25af32350908ee155fcda066dce Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 20 Dec 2019 13:57:28 -0800 Subject: [PATCH 245/297] Made generic registry type for actionTypes and alert types --- .../application/action_type_registry.ts | 53 ---------- .../application/alert_type_registry.test.ts | 96 ------------------- .../public/application/alert_type_registry.ts | 44 --------- .../np_ready/public/application/app.tsx | 9 +- .../builtin_action_types/email.test.tsx | 4 +- .../builtin_action_types/es_index.test.tsx | 4 +- .../components/builtin_action_types/index.ts | 5 +- .../builtin_action_types/pagerduty.test.tsx | 4 +- .../builtin_action_types/server_log.test.tsx | 4 +- .../builtin_action_types/slack.test.tsx | 4 +- .../builtin_action_types/webhook.test.tsx | 4 +- .../components/builtin_alert_types/index.ts | 5 +- ...registry.test.ts => type_registry.test.ts} | 58 +++++++---- .../public/application/type_registry.ts | 10 +- .../np_ready/public/plugin.ts | 13 ++- .../np_ready/public/types.ts | 7 +- 16 files changed, 73 insertions(+), 251 deletions(-) delete mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.ts delete mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.test.ts delete mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.ts rename x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/{action_type_registry.test.ts => type_registry.test.ts} (55%) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.ts deleted file mode 100644 index c886ada04db5eb..00000000000000 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.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 { i18n } from '@kbn/i18n'; -import { ActionTypeModel } from '../types'; - -export class ActionTypeRegistry { - private readonly actionTypes: Map = new Map(); - - /** - * Returns if the action type registry has the given action type registered - */ - public has(id: string) { - return this.actionTypes.has(id); - } - - /** - * Registers an action type to the action type registry - */ - public register(actionType: ActionTypeModel) { - if (this.has(actionType.id)) { - throw new Error( - i18n.translate( - 'xpack.triggersActionsUI.actionTypeRegistry.register.duplicateActionTypeErrorMessage', - { - defaultMessage: 'Action type "{id}" is already registered.', - values: { - id: actionType.id, - }, - } - ) - ); - } - this.actionTypes.set(actionType.id, actionType); - } - - /** - * Returns an action type, null if not registered - */ - public get(id: string): ActionTypeModel | null { - if (!this.has(id)) { - return null; - } - return this.actionTypes.get(id)!; - } - - public list() { - return Array.from(this.actionTypes).map(([actionTypeId, actionType]) => actionType); - } -} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.test.ts deleted file mode 100644 index c581136b80dbbf..00000000000000 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.test.ts +++ /dev/null @@ -1,96 +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 { AlertTypeRegistry } from './alert_type_registry'; -import { ValidationResult } from '../types'; - -export const ExpressionComponent: React.FunctionComponent = () => { - return null; -}; - -const getTestAlertType = (id?: string, name?: string, iconClass?: string) => { - return { - id: id || 'test-alet-type', - name: name || 'Test alert type', - iconClass: iconClass || 'icon', - validate: (): ValidationResult => { - return { errors: {} }; - }, - alertParamsExpression: ExpressionComponent, - }; -}; - -beforeEach(() => jest.resetAllMocks()); - -describe('register()', () => { - test('able to register alert types', () => { - const alertTypeRegistry = new AlertTypeRegistry(); - alertTypeRegistry.register(getTestAlertType()); - expect(alertTypeRegistry.has('test-alet-type')).toEqual(true); - }); - - test('throws error if alert type already registered', () => { - const alertTypeRegistry = new AlertTypeRegistry(); - alertTypeRegistry.register(getTestAlertType('my-test-alert-type-1')); - expect(() => - alertTypeRegistry.register(getTestAlertType('my-test-alert-type-1')) - ).toThrowErrorMatchingInlineSnapshot( - `"Alert type \\"my-test-alert-type-1\\" is already registered."` - ); - }); -}); - -describe('get()', () => { - test('returns alert type', () => { - const alertTypeRegistry = new AlertTypeRegistry(); - alertTypeRegistry.register(getTestAlertType('my-alert-type-snapshot')); - const alertType = alertTypeRegistry.get('my-alert-type-snapshot'); - expect(alertType).toMatchInlineSnapshot(` - Object { - "alertParamsExpression": [Function], - "iconClass": "icon", - "id": "my-alert-type-snapshot", - "name": "Test alert type", - "validate": [Function], - } - `); - }); - - test(`return null when alert type doesn't exist`, () => { - const alertTypeRegistry = new AlertTypeRegistry(); - expect(alertTypeRegistry.get('not-exist-alert-type')).toBeNull(); - }); -}); - -describe('list()', () => { - test('returns list of alert types', () => { - const alertTypeRegistry = new AlertTypeRegistry(); - alertTypeRegistry.register(getTestAlertType()); - const alertTypes = alertTypeRegistry.list(); - expect(alertTypes).toEqual([ - { - id: 'test-alet-type', - name: 'Test alert type', - iconClass: 'icon', - alertParamsExpression: ExpressionComponent, - validate: alertTypes[0].validate, - }, - ]); - }); -}); - -describe('has()', () => { - test('returns false for unregistered alert types', () => { - const alertTypeRegistry = new AlertTypeRegistry(); - expect(alertTypeRegistry.has('my-alert-type')).toEqual(false); - }); - - test('returns true after registering an alert type', () => { - const alertTypeRegistry = new AlertTypeRegistry(); - alertTypeRegistry.register(getTestAlertType()); - expect(alertTypeRegistry.has('test-alet-type')); - }); -}); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.ts deleted file mode 100644 index 968145eac7895f..00000000000000 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/alert_type_registry.ts +++ /dev/null @@ -1,44 +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 { i18n } from '@kbn/i18n'; -import { AlertTypeModel } from '../types'; - -export class AlertTypeRegistry { - private readonly alertTypes: Map = new Map(); - - public has(id: string) { - return this.alertTypes.has(id); - } - - public register(alertType: AlertTypeModel) { - if (this.has(alertType.id)) { - throw new Error( - i18n.translate( - 'xpack.triggersActionsUI.alertTypeRegistry.register.duplicateAlertTypeError', - { - defaultMessage: 'Alert type "{id}" is already registered.', - values: { - id: alertType.id, - }, - } - ) - ); - } - this.alertTypes.set(alertType.id, alertType); - } - - public get(id: string): AlertTypeModel | null { - if (!this.has(id)) { - return null; - } - return this.alertTypes.get(id)!; - } - - public list() { - return Array.from(this.alertTypes).map(([alertTypeId, alertType]) => alertType); - } -} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx index 281a709342949c..ee958e9e3ce6b7 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx @@ -17,9 +17,8 @@ import { BASE_PATH, Section } from './constants'; import { TriggersActionsUIHome } from './home'; import { AppContextProvider, useAppDependencies } from './app_context'; import { hasShowAlertsCapability } from './lib/capabilities'; -import { ActionTypeRegistry } from './action_type_registry'; -import { AlertTypeRegistry } from './alert_type_registry'; -import { LegacyDependencies } from '../types'; +import { LegacyDependencies, ActionTypeModel, AlertTypeModel } from '../types'; +import { TypeRegistry } from './type_registry'; export interface AppDeps { chrome: ChromeStart; @@ -29,8 +28,8 @@ export interface AppDeps { http: HttpSetup; uiSettings: IUiSettingsClient; legacy: LegacyDependencies; - actionTypeRegistry: ActionTypeRegistry; - alertTypeRegistry: AlertTypeRegistry; + actionTypeRegistry: TypeRegistry; + alertTypeRegistry: TypeRegistry; } class ShareRouter extends Component { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx index 37bce8063ff8c2..f79bff058805f6 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx @@ -5,7 +5,7 @@ */ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; -import { ActionTypeRegistry } from '../../action_type_registry'; +import { TypeRegistry } from '../../type_registry'; import { registerBuiltInActionTypes } from './index'; import { ActionTypeModel, ActionConnector } from '../../../types'; @@ -13,7 +13,7 @@ const ACTION_TYPE_ID = '.email'; let actionTypeModel: ActionTypeModel; beforeAll(() => { - const actionTypeRegistry = new ActionTypeRegistry(); + const actionTypeRegistry = new TypeRegistry(); registerBuiltInActionTypes({ actionTypeRegistry }); const getResult = actionTypeRegistry.get(ACTION_TYPE_ID); if (getResult !== null) { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.test.tsx index 903f83ebe500a3..b6a7c4d82aca44 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.test.tsx @@ -5,7 +5,7 @@ */ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; -import { ActionTypeRegistry } from '../../action_type_registry'; +import { TypeRegistry } from '../../type_registry'; import { registerBuiltInActionTypes } from './index'; import { ActionTypeModel, ActionConnector } from '../../../types'; @@ -13,7 +13,7 @@ const ACTION_TYPE_ID = '.index'; let actionTypeModel: ActionTypeModel; beforeAll(() => { - const actionTypeRegistry = new ActionTypeRegistry(); + const actionTypeRegistry = new TypeRegistry(); registerBuiltInActionTypes({ actionTypeRegistry }); const getResult = actionTypeRegistry.get(ACTION_TYPE_ID); if (getResult !== null) { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/index.ts index adab604330486e..6ffd9b2c9ffde8 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/index.ts @@ -10,12 +10,13 @@ import { getActionType as getEmailActionType } from './email'; import { getActionType as getIndexActionType } from './es_index'; import { getActionType as getPagerDutyActionType } from './pagerduty'; import { getActionType as getWebhookActionType } from './webhook'; -import { ActionTypeRegistry } from '../../action_type_registry'; +import { TypeRegistry } from '../../type_registry'; +import { ActionTypeModel } from '../../../types'; export function registerBuiltInActionTypes({ actionTypeRegistry, }: { - actionTypeRegistry: ActionTypeRegistry; + actionTypeRegistry: TypeRegistry; }) { actionTypeRegistry.register(getServerLogActionType()); actionTypeRegistry.register(getSlackActionType()); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.test.tsx index 77221a3f8b08d3..35dfe94d009eeb 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.test.tsx @@ -5,7 +5,7 @@ */ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; -import { ActionTypeRegistry } from '../../action_type_registry'; +import { TypeRegistry } from '../../type_registry'; import { registerBuiltInActionTypes } from './index'; import { ActionTypeModel, ActionConnector } from '../../../types'; @@ -13,7 +13,7 @@ const ACTION_TYPE_ID = '.pagerduty'; let actionTypeModel: ActionTypeModel; beforeAll(() => { - const actionTypeRegistry = new ActionTypeRegistry(); + const actionTypeRegistry = new TypeRegistry(); registerBuiltInActionTypes({ actionTypeRegistry }); const getResult = actionTypeRegistry.get(ACTION_TYPE_ID); if (getResult !== null) { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.test.tsx index 73b2560efba97e..94898da7e46e46 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.test.tsx @@ -5,7 +5,7 @@ */ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; -import { ActionTypeRegistry } from '../../action_type_registry'; +import { TypeRegistry } from '../../type_registry'; import { registerBuiltInActionTypes } from './index'; import { ActionTypeModel, ActionConnector } from '../../../types'; @@ -13,7 +13,7 @@ const ACTION_TYPE_ID = '.server-log'; let actionTypeModel: ActionTypeModel; beforeAll(() => { - const actionTypeRegistry = new ActionTypeRegistry(); + const actionTypeRegistry = new TypeRegistry(); registerBuiltInActionTypes({ actionTypeRegistry }); const getResult = actionTypeRegistry.get(ACTION_TYPE_ID); if (getResult !== null) { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.test.tsx index 81c3e59d883af7..8db445c89abfeb 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.test.tsx @@ -5,7 +5,7 @@ */ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; -import { ActionTypeRegistry } from '../../action_type_registry'; +import { TypeRegistry } from '../../type_registry'; import { registerBuiltInActionTypes } from './index'; import { ActionTypeModel, ActionConnector } from '../../../types'; @@ -13,7 +13,7 @@ const ACTION_TYPE_ID = '.slack'; let actionTypeModel: ActionTypeModel; beforeAll(() => { - const actionTypeRegistry = new ActionTypeRegistry(); + const actionTypeRegistry = new TypeRegistry(); registerBuiltInActionTypes({ actionTypeRegistry }); const getResult = actionTypeRegistry.get(ACTION_TYPE_ID); if (getResult !== null) { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx index 2deb7418a8008a..881ceeb24e5bac 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx @@ -5,7 +5,7 @@ */ import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; -import { ActionTypeRegistry } from '../../action_type_registry'; +import { TypeRegistry } from '../../type_registry'; import { registerBuiltInActionTypes } from './index'; import { ActionTypeModel, ActionConnector } from '../../../types'; @@ -13,7 +13,7 @@ const ACTION_TYPE_ID = '.webhook'; let actionTypeModel: ActionTypeModel; beforeAll(() => { - const actionTypeRegistry = new ActionTypeRegistry(); + const actionTypeRegistry = new TypeRegistry(); registerBuiltInActionTypes({ actionTypeRegistry }); const getResult = actionTypeRegistry.get(ACTION_TYPE_ID); if (getResult !== null) { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/index.ts index f5e6dd46df2bfb..6c5d440e47888f 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/index.ts @@ -5,12 +5,13 @@ */ import { getActionType as getThresholdAlertType } from './threshold/expression'; -import { AlertTypeRegistry } from '../../alert_type_registry'; +import { TypeRegistry } from '../../type_registry'; +import { AlertTypeModel } from '../../../types'; export function registerBuiltInAlertTypes({ alertTypeRegistry, }: { - alertTypeRegistry: AlertTypeRegistry; + alertTypeRegistry: TypeRegistry; }) { alertTypeRegistry.register(getThresholdAlertType()); } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/type_registry.test.ts similarity index 55% rename from x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.test.ts rename to x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/type_registry.test.ts index aa3116637bb634..efe58aedb8353c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/action_type_registry.test.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/type_registry.test.ts @@ -4,8 +4,24 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ActionTypeRegistry } from './action_type_registry'; -import { ValidationResult } from '../types'; +import { TypeRegistry } from './type_registry'; +import { ValidationResult, AlertTypeModel, ActionTypeModel } from '../types'; + +export const ExpressionComponent: React.FunctionComponent = () => { + return null; +}; + +const getTestAlertType = (id?: string, name?: string, iconClass?: string) => { + return { + id: id || 'test-alet-type', + name: name || 'Test alert type', + iconClass: iconClass || 'icon', + validate: (): ValidationResult => { + return { errors: {} }; + }, + alertParamsExpression: ExpressionComponent, + }; +}; const getTestActionType = (id?: string, iconClass?: string, selectedMessage?: string) => { return { @@ -27,26 +43,26 @@ const getTestActionType = (id?: string, iconClass?: string, selectedMessage?: st beforeEach(() => jest.resetAllMocks()); describe('register()', () => { - test('able to register action types', () => { - const actionTypeRegistry = new ActionTypeRegistry(); - actionTypeRegistry.register(getTestActionType()); - expect(actionTypeRegistry.has('my-action-type')).toEqual(true); + test('able to register alert types', () => { + const alertTypeRegistry = new TypeRegistry(); + alertTypeRegistry.register(getTestAlertType()); + expect(alertTypeRegistry.has('test-alet-type')).toEqual(true); }); - test('throws error if action type already registered', () => { - const actionTypeRegistry = new ActionTypeRegistry(); - actionTypeRegistry.register(getTestActionType('my-test-action-type-1')); + test('throws error if alert type already registered', () => { + const alertTypeRegistry = new TypeRegistry(); + alertTypeRegistry.register(getTestAlertType('my-test-alert-type-1')); expect(() => - actionTypeRegistry.register(getTestActionType('my-test-action-type-1')) + alertTypeRegistry.register(getTestAlertType('my-test-alert-type-1')) ).toThrowErrorMatchingInlineSnapshot( - `"Action type \\"my-test-action-type-1\\" is already registered."` + `"Object type \\"my-test-alert-type-1\\" is already registered."` ); }); }); describe('get()', () => { test('returns action type', () => { - const actionTypeRegistry = new ActionTypeRegistry(); + const actionTypeRegistry = new TypeRegistry(); actionTypeRegistry.register(getTestActionType('my-action-type-snapshot')); const actionType = actionTypeRegistry.get('my-action-type-snapshot'); expect(actionType).toMatchInlineSnapshot(` @@ -63,14 +79,14 @@ describe('get()', () => { }); test(`return null when action type doesn't exist`, () => { - const actionTypeRegistry = new ActionTypeRegistry(); + const actionTypeRegistry = new TypeRegistry(); expect(actionTypeRegistry.get('not-exist-action-type')).toBeNull(); }); }); describe('list()', () => { test('returns list of action types', () => { - const actionTypeRegistry = new ActionTypeRegistry(); + const actionTypeRegistry = new TypeRegistry(); actionTypeRegistry.register(getTestActionType()); const actionTypes = actionTypeRegistry.list(); expect(actionTypes).toEqual([ @@ -88,14 +104,14 @@ describe('list()', () => { }); describe('has()', () => { - test('returns false for unregistered action types', () => { - const actionTypeRegistry = new ActionTypeRegistry(); - expect(actionTypeRegistry.has('my-action-type')).toEqual(false); + test('returns false for unregistered alert types', () => { + const alertTypeRegistry = new TypeRegistry(); + expect(alertTypeRegistry.has('my-alert-type')).toEqual(false); }); - test('returns true after registering an action type', () => { - const actionTypeRegistry = new ActionTypeRegistry(); - actionTypeRegistry.register(getTestActionType()); - expect(actionTypeRegistry.has('my-action-type')); + test('returns true after registering an alert type', () => { + const alertTypeRegistry = new TypeRegistry(); + alertTypeRegistry.register(getTestAlertType()); + expect(alertTypeRegistry.has('test-alet-type')); }); }); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/type_registry.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/type_registry.ts index 3f23eb7d44efba..3390d8910a45fa 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/type_registry.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/type_registry.ts @@ -14,22 +14,22 @@ export class TypeRegistry { private readonly objectTypes: Map = new Map(); /** - * Returns if the action type registry has the given action type registered + * Returns if the object type registry has the given type registered */ public has(id: string) { return this.objectTypes.has(id); } /** - * Registers an action type to the action type registry + * Registers an object type to the type registry */ public register(objectType: T) { if (this.has(objectType.id)) { throw new Error( i18n.translate( - 'xpack.triggersActionsUI.actionTypeRegistry.register.duplicateActionTypeErrorMessage', + 'xpack.triggersActionsUI.typeRegistry.register.duplicateObjectTypeErrorMessage', { - defaultMessage: 'Action type "{id}" is already registered.', + defaultMessage: 'Object type "{id}" is already registered.', values: { id: objectType.id, }, @@ -41,7 +41,7 @@ export class TypeRegistry { } /** - * Returns an action type, null if not registered + * Returns an object type, null if not registered */ public get(id: string): T | null { if (!this.has(id)) { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts index 59be83640ee905..0b0f8a4ee67907 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts @@ -12,13 +12,12 @@ import { } from 'src/core/public'; import { i18n } from '@kbn/i18n'; -import { ActionTypeRegistry } from './application/action_type_registry'; import { registerBuiltInActionTypes } from './application/components/builtin_action_types'; -import { AlertTypeRegistry } from './application/alert_type_registry'; import { registerBuiltInAlertTypes } from './application/components/builtin_alert_types'; import { hasShowActionsCapability, hasShowAlertsCapability } from './application/lib/capabilities'; import { PLUGIN } from './application/constants/plugin'; -import { LegacyDependencies } from './types'; +import { LegacyDependencies, ActionTypeModel, AlertTypeModel } from './types'; +import { TypeRegistry } from './application/type_registry'; export type Setup = void; export type Start = void; @@ -28,14 +27,14 @@ interface LegacyPlugins { } export class Plugin implements CorePlugin { - private actionTypeRegistry: ActionTypeRegistry; - private alertTypeRegistry: AlertTypeRegistry; + private actionTypeRegistry: TypeRegistry; + private alertTypeRegistry: TypeRegistry; constructor(initializerContext: PluginInitializerContext) { - const actionTypeRegistry = new ActionTypeRegistry(); + const actionTypeRegistry = new TypeRegistry(); this.actionTypeRegistry = actionTypeRegistry; - const alertTypeRegistry = new AlertTypeRegistry(); + const alertTypeRegistry = new TypeRegistry(); this.alertTypeRegistry = alertTypeRegistry; } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts index b07b2da570fcc4..4cf28d3bbd06fc 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/types.ts @@ -4,13 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ import { capabilities } from 'ui/capabilities'; -import { ActionTypeRegistry } from './application/action_type_registry'; -import { AlertTypeRegistry } from './application/alert_type_registry'; +import { TypeRegistry } from './application/type_registry'; export type ActionTypeIndex = Record; export type AlertTypeIndex = Record; -export type ActionTypeRegistryContract = PublicMethodsOf; -export type AlertTypeRegistryContract = PublicMethodsOf; +export type ActionTypeRegistryContract = PublicMethodsOf>; +export type AlertTypeRegistryContract = PublicMethodsOf>; export interface ActionConnectorFieldsProps { action: ActionConnector; From 6aafd1bcb2fd1c8ff0eb6784c11e8b7562a9ab97 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 20 Dec 2019 14:04:13 -0800 Subject: [PATCH 246/297] Fixed some enum types --- .../np_ready/public/application/constants/index.ts | 8 ++++---- .../public/application/constants/time_units.ts | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/index.ts index 4c9feaadd3c29c..a8364ffe21019d 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/index.ts @@ -15,7 +15,7 @@ export const routeToConnectors = `${BASE_PATH}/connectors`; export const routeToAlerts = `${BASE_PATH}/alerts`; export { TIME_UNITS } from './time_units'; -export const SORT_ORDERS: { [key: string]: string } = { - ASCENDING: 'asc', - DESCENDING: 'desc', -}; +export enum SORT_ORDERS { + ASCENDING = 'asc', + DESCENDING = 'desc', +} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/time_units.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/time_units.ts index c861d47416a804..2a4f8fbd421ed6 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/time_units.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/constants/time_units.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -export const TIME_UNITS: { [key: string]: string } = { - SECOND: 's', - MINUTE: 'm', - HOUR: 'h', - DAY: 'd', -}; +export enum TIME_UNITS { + SECOND = 's', + MINUTE = 'm', + HOUR = 'h', + DAY = 'd', +} From 23e222602aee42ca9632e99d4335070d7b87ddd1 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 20 Dec 2019 14:43:18 -0800 Subject: [PATCH 247/297] fixed type check CI --- .../public/application/sections/alert_add/alert_add.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx index 03801360377d91..b1c15d26c1748c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alert_add/alert_add.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, useContext, useState, useCallback, useReducer, useEffect } from 'react'; +import React, { Fragment, useState, useCallback, useReducer, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { From 0b48b654a320f0143903e5a7bd9c2c3cc9e40b57 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 31 Dec 2019 12:35:23 -0500 Subject: [PATCH 248/297] Convert EuiSearchBar to normal text field --- .../alerts_list/components/alerts_list.tsx | 61 +++++++++++++------ 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 9f8b063917f771..f2bb8fa58543b9 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -7,8 +7,15 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { Fragment, useEffect, useState } from 'react'; -// @ts-ignore: EuiSearchBar not exported in TypeScript -import { EuiBasicTable, EuiButton, EuiFilterButton, EuiSearchBar, EuiSpacer } from '@elastic/eui'; +import { + EuiBasicTable, + EuiButton, + EuiFieldText, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiSpacer, +} from '@elastic/eui'; import { AlertsContextProvider } from '../../../context/alerts_context'; import { useAppDependencies } from '../../../app_context'; @@ -226,24 +233,38 @@ export const AlertsList: React.FunctionComponent = () => { - setSearchText(queryText)} - toolsLeft={ - selectedIds.length === 0 || !canDelete - ? [] - : [ - setIsPerformingAction(true)} - onActionPerformed={() => { - loadAlertsData(); - setIsPerformingAction(false); - }} - />, - ] - } - toolsRight={toolsRight} - /> + + {selectedIds.length > 0 && canDelete && ( + + setIsPerformingAction(true)} + onActionPerformed={() => { + loadAlertsData(); + setIsPerformingAction(false); + }} + /> + + )} + + } + onChange={e => setSearchText(e.target.value)} + placeholder={i18n.translate( + 'xpack.triggersActionsUI.sections.alertsList.searchPlaceholderTitle', + { defaultMessage: 'Search...' } + )} + /> + + + + {toolsRight.map(tool => ( + {tool} + ))} + + + {/* Large to remain consistent with ActionsList table spacing */} From e61c5b91b1e1ec53515cd11c3bf3c97ac49891ff Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 31 Dec 2019 12:37:14 -0500 Subject: [PATCH 249/297] Fix typo --- .../action_connector_form/action_connector_form.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index bf386fee886a53..da75275aa931e7 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -78,8 +78,8 @@ export const ActionConnectorForm = ({ body: { message: string; error: string }; } | null>(null); - const actionTypeRegisterd = actionTypeRegistry.get(initialConnector.actionTypeId); - if (!actionTypeRegisterd) return null; + const actionTypeRegistered = actionTypeRegistry.get(initialConnector.actionTypeId); + if (!actionTypeRegistered) return null; function validateBaseProperties(actionObject: ActionConnector) { const validationResult = { errors: {} }; @@ -100,9 +100,9 @@ export const ActionConnectorForm = ({ return validationResult; } - const FieldsComponent = actionTypeRegisterd.actionConnectorFields; + const FieldsComponent = actionTypeRegistered.actionConnectorFields; const errors = { - ...actionTypeRegisterd.validateConnector(connector).errors, + ...actionTypeRegistered.validateConnector(connector).errors, ...validateBaseProperties(connector).errors, } as IErrorObject; const hasErrors = !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); From 3f4bdc5244b80ca809a8e5a499c1d5386a17f2d2 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 31 Dec 2019 12:44:21 -0500 Subject: [PATCH 250/297] Fix conditional rendering --- .../components/actions_connectors_list.tsx | 273 +++++++++--------- 1 file changed, 141 insertions(+), 132 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index 55e967792c7cf4..a5ab483e7e26e8 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -229,6 +229,143 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { }, ]; + const table = ( + ({ + 'data-test-subj': 'connectors-row', + })} + cellProps={() => ({ + 'data-test-subj': 'cell', + })} + data-test-subj="actionsTable" + pagination={true} + selection={ + canDelete + ? { + onSelectionChange(updatedSelectedItemsList: ActionConnectorTableItem[]) { + setSelectedItems(updatedSelectedItemsList); + }, + } + : undefined + } + search={{ + filters: [ + { + type: 'field_value_selection', + field: 'actionTypeId', + name: i18n.translate( + 'xpack.triggersActionsUI.sections.actionsConnectorsList.filters.actionTypeIdName', + { defaultMessage: 'Type' } + ), + multiSelect: 'or', + options: actionTypesList, + }, + ], + toolsLeft: + selectedItems.length === 0 || !canDelete + ? [] + : [ + + + , + ], + toolsRight: [ + setAddFlyoutVisibility(true)} + > + + , + ], + }} + /> + ); + + const emptyPrompt = ( + + + + + + +

+ +

+
+
+ } + body={ +

+ +

+ } + actions={ + setAddFlyoutVisibility(true)} + > + + + } + /> + ); + + const noPermissionPrompt = ( +

+ +

+ ); + return (
@@ -243,138 +380,10 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { reloadConnectors: loadActions, }} > - {data.length > 0 ? ( - ({ - 'data-test-subj': 'connectors-row', - })} - cellProps={() => ({ - 'data-test-subj': 'cell', - })} - data-test-subj="actionsTable" - pagination={true} - selection={ - canDelete - ? { - onSelectionChange(updatedSelectedItemsList: ActionConnectorTableItem[]) { - setSelectedItems(updatedSelectedItemsList); - }, - } - : undefined - } - search={{ - filters: [ - { - type: 'field_value_selection', - field: 'actionTypeId', - name: i18n.translate( - 'xpack.triggersActionsUI.sections.actionsConnectorsList.filters.actionTypeIdName', - { defaultMessage: 'Type' } - ), - multiSelect: 'or', - options: actionTypesList, - }, - ], - toolsLeft: - selectedItems.length === 0 || !canDelete - ? [] - : [ - - - , - ], - toolsRight: [ - setAddFlyoutVisibility(true)} - > - - , - ], - }} - /> - ) : canSave ? ( - - - - - - -

- -

-
-
- } - body={ -

- -

- } - actions={ - setAddFlyoutVisibility(true)} - > - - - } - /> - ) : ( -

- -

- )} + {/* Render the view based on if there's data or if they can save */} + {data.length !== 0 && table} + {data.length === 0 && canSave && emptyPrompt} + {data.length === 0 && !canSave && noPermissionPrompt} {editedConnectorItem ? : null} From 0b4fc6a8e09b756b440590eb0a79f2abdc0020c6 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 31 Dec 2019 12:46:44 -0500 Subject: [PATCH 251/297] Fix bug where selection doesn't reset --- .../components/actions_connectors_list.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index a5ab483e7e26e8..593038de039862 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -150,6 +150,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { async function deleteSelectedItems() { await deleteItems(selectedItems); + setSelectedItems([]); } const actionsTableColumns = [ From a1ef419bad56362d3f2c2bf76de5a338cdacbb89 Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 31 Dec 2019 13:16:29 -0500 Subject: [PATCH 252/297] Fix broken functional test, wait for ENTER key to search alerts --- .../sections/alerts_list/components/alerts_list.tsx | 13 +++++++++++-- .../page_objects/triggers_actions_ui_page.ts | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index f2bb8fa58543b9..b4c05e676f8252 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -29,6 +29,8 @@ import { loadAlerts, loadAlertTypes } from '../../../lib/alert_api'; import { loadActionTypes } from '../../../lib/action_connector_api'; import { hasDeleteAlertsCapability, hasSaveAlertsCapability } from '../../../lib/capabilities'; +const ENTER_KEY = 13; + export const AlertsList: React.FunctionComponent = () => { const { http, @@ -50,7 +52,8 @@ export const AlertsList: React.FunctionComponent = () => { const [isPerformingAction, setIsPerformingAction] = useState(false); const [totalItemCount, setTotalItemCount] = useState(0); const [page, setPage] = useState({ index: 0, size: 10 }); - const [searchText, setSearchText] = useState(undefined); + const [searchText, setSearchText] = useState(); + const [inputText, setInputText] = useState(); const [typesFilter, setTypesFilter] = useState([]); const [actionTypesFilter, setActionTypesFilter] = useState([]); const [alertFlyoutVisible, setAlertFlyoutVisibility] = useState(false); @@ -249,8 +252,14 @@ export const AlertsList: React.FunctionComponent = () => { } - onChange={e => setSearchText(e.target.value)} + onChange={e => setInputText(e.target.value)} + onKeyUp={e => { + if (e.keyCode === ENTER_KEY) { + setSearchText(inputText); + } + }} placeholder={i18n.translate( 'xpack.triggersActionsUI.sections.alertsList.searchPlaceholderTitle', { defaultMessage: 'Search...' } diff --git a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts index 44672228a372af..ce68109771487b 100644 --- a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts +++ b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts @@ -33,7 +33,7 @@ export function TriggersActionsPageProvider({ getService }: FtrProviderContext) ); }, async searchAlerts(searchText: string) { - const searchBox = await find.byCssSelector('[data-test-subj="alertsList"] .euiFieldSearch'); + const searchBox = await testSubjects.find('alertSearchField'); await searchBox.click(); await searchBox.clearValue(); await searchBox.type(searchText); From 986b6bee84dac5d1cb6d45afa92791f3fef9d3bb Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Tue, 31 Dec 2019 13:33:48 -0500 Subject: [PATCH 253/297] Make app section hide from menu when user doesn't have access --- .../triggers_actions_ui/public/legacy.ts | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/public/legacy.ts b/x-pack/legacy/plugins/triggers_actions_ui/public/legacy.ts index 8937da0cbb30c5..f6f9a33bd13665 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/public/legacy.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/public/legacy.ts @@ -19,8 +19,14 @@ import { xpackInfo } from 'plugins/xpack_main/services/xpack_info'; import { plugin } from '../np_ready/public'; import { manageAngularLifecycle } from './manage_angular_lifecycle'; import { BASE_PATH } from '../np_ready/public/application/constants'; +import { + hasShowActionsCapability, + hasShowAlertsCapability, +} from '../np_ready/public/application/lib/capabilities'; const REACT_ROOT_ID = 'triggersActionsRoot'; +const canShowActions = hasShowActionsCapability(capabilities.get()); +const canShowAlerts = hasShowAlertsCapability(capabilities.get()); const template = `
@@ -80,10 +86,12 @@ routes.when(`${BASE_PATH}:section?/:subsection?/:view?/:id?`, { })(), }); -management.getSection('kibana').register('triggersActions', { - display: i18n.translate('xpack.triggersActionsUI.managementSection.displayName', { - defaultMessage: 'Alerts and Actions', - }), - order: 7, - url: `#${BASE_PATH}`, -}); +if (canShowActions || canShowAlerts) { + management.getSection('kibana').register('triggersActions', { + display: i18n.translate('xpack.triggersActionsUI.managementSection.displayName', { + defaultMessage: 'Alerts and Actions', + }), + order: 7, + url: `#${BASE_PATH}`, + }); +} From 84bd6179d93f3206fb57dfcd2ab4c645b76b7e51 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 2 Jan 2020 09:52:40 -0800 Subject: [PATCH 254/297] Fixed connector name validation (error due to renaming from description) --- .../sections/action_connector_form/action_connector_form.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index da75275aa931e7..5ea537e20cf5f8 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -84,11 +84,11 @@ export const ActionConnectorForm = ({ function validateBaseProperties(actionObject: ActionConnector) { const validationResult = { errors: {} }; const errors = { - description: new Array(), + name: new Array(), }; validationResult.errors = errors; if (!actionObject.name) { - errors.description.push( + errors.name.push( i18n.translate( 'xpack.triggersActionsUI.sections.actionConnectorForm.error.requiredNameText', { From 7eb158badc708c679af22fc756307cc8c5f5af35 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 2 Jan 2020 11:39:57 -0800 Subject: [PATCH 255/297] Removed obsolete useEffect --- .../action_connector_form/connector_add_flyout.tsx | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx index b487b4fdaad89b..a1c6e58ab5c533 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx @@ -24,13 +24,10 @@ export const ConnectorAddFlyout = () => { const { actionTypeRegistry } = useAppDependencies(); const { addFlyoutVisible, setAddFlyoutVisibility } = useActionsConnectorsContext(); const [actionType, setActionType] = useState(undefined); - const closeFlyout = useCallback(() => setAddFlyoutVisibility(false), [setAddFlyoutVisibility]); - - useEffect(() => { - if (addFlyoutVisible) { - setActionType(undefined); - } - }, [addFlyoutVisible]); + const closeFlyout = useCallback(() => { + setAddFlyoutVisibility(false); + setActionType(undefined); + }, [setAddFlyoutVisibility, setActionType]); if (!addFlyoutVisible) { return null; @@ -56,7 +53,7 @@ export const ConnectorAddFlyout = () => { ); } From efde3411a8345bdbd2848025b472df8f6862d016 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 2 Jan 2020 12:07:13 -0800 Subject: [PATCH 256/297] Removed unused ShareRouter --- .../np_ready/public/application/app.tsx | 26 +++---------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx index ee958e9e3ce6b7..bdc898da1adf13 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx @@ -3,8 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; +import React from 'react'; import { Switch, Route, Redirect, HashRouter } from 'react-router-dom'; import { ChromeStart, @@ -32,21 +31,6 @@ export interface AppDeps { alertTypeRegistry: TypeRegistry; } -class ShareRouter extends Component { - static contextTypes = { - router: PropTypes.shape({ - history: PropTypes.shape({ - push: PropTypes.func.isRequired, - createHref: PropTypes.func.isRequired, - }).isRequired, - }).isRequired, - }; - - render() { - return this.props.children; - } -} - export const App = (deps: AppDeps) => { const sections: Section[] = ['alerts', 'connectors']; @@ -54,11 +38,9 @@ export const App = (deps: AppDeps) => { return ( - - - - - + + + ); }; From 60ff7f707e3ae1a11bb58a35a405d3182109ee7a Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 2 Jan 2020 12:57:23 -0800 Subject: [PATCH 257/297] Fixed key validation error --- .../sections/alerts_list/components/alerts_list.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index b4c05e676f8252..64f06521c0f9d9 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -208,6 +208,7 @@ export const AlertsList: React.FunctionComponent = () => { .sort((a, b) => a.name.localeCompare(b.name))} />, setActionTypesFilter(ids)} />, @@ -268,8 +269,10 @@ export const AlertsList: React.FunctionComponent = () => {
- {toolsRight.map(tool => ( - {tool} + {toolsRight.map((tool, index: number) => ( + + {tool} + ))} From 62f3fceaaea77291d5eca4e85d076e1ecd818d5e Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 2 Jan 2020 14:04:40 -0800 Subject: [PATCH 258/297] Mobed wrongly wrapped objects --- .../components/actions_connectors_list.tsx | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index 593038de039862..4bd433dfee7f13 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -369,26 +369,24 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { return (
- - - - {/* Render the view based on if there's data or if they can save */} - {data.length !== 0 && table} - {data.length === 0 && canSave && emptyPrompt} - {data.length === 0 && !canSave && noPermissionPrompt} - - {editedConnectorItem ? : null} - - + + {/* Render the view based on if there's data or if they can save */} + {data.length !== 0 && table} + {data.length === 0 && canSave && emptyPrompt} + {data.length === 0 && !canSave && noPermissionPrompt} + + + {editedConnectorItem ? : null} +
); }; From 54d44e74d088433831f090315ae13ed87f6a98fc Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 2 Jan 2020 14:23:12 -0800 Subject: [PATCH 259/297] Removed useEffect from connectors form --- .../action_connector_form/action_connector_form.tsx | 9 --------- .../action_connector_form/connector_edit_flyout.tsx | 1 + .../action_connector_form/connector_reducer.ts | 13 +------------ 3 files changed, 2 insertions(+), 21 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index 5ea537e20cf5f8..912b9f27fbd0ce 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -56,10 +56,6 @@ export const ActionConnectorForm = ({ dispatch({ command: { type: 'setProperty' }, payload: { key, value } }); }; - const setConnector = (key: string, value: any) => { - dispatch({ command: { type: 'setConnector' }, payload: { key, value } }); - }; - const setActionConfigProperty = (key: string, value: any) => { dispatch({ command: { type: 'setConfigProperty' }, payload: { key, value } }); }; @@ -68,11 +64,6 @@ export const ActionConnectorForm = ({ dispatch({ command: { type: 'setSecretsProperty' }, payload: { key, value } }); }; - useEffect(() => { - setConnector('connector', initialConnector); - setServerError(null); - }, [initialConnector]); - const [isSaving, setIsSaving] = useState(false); const [serverError, setServerError] = useState<{ body: { message: string; error: string }; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx index 7bd921af17ee76..408989609d2ec5 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_edit_flyout.tsx @@ -55,6 +55,7 @@ export const ConnectorEditFlyout = ({ connector }: ConnectorEditProps) => { { const { connector } = state; switch (command.type) { - case 'setConnector': { - const { key, value } = payload; - if (key === 'connector') { - return { - ...state, - connector: value, - }; - } else { - return state; - } - } case 'setProperty': { const { key, value } = payload; if (isEqual(connector[key], value)) { From db0aa95344781255e073304ab75a2d46898a0128 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 2 Jan 2020 15:45:32 -0800 Subject: [PATCH 260/297] Replaced error forms with eui controls props --- .../components/builtin_action_types/email.tsx | 112 +++++++++--------- .../builtin_action_types/es_index.tsx | 11 +- .../builtin_action_types/pagerduty.tsx | 21 ++-- .../builtin_action_types/server_log.tsx | 23 ++-- .../components/builtin_action_types/slack.tsx | 32 +++-- .../builtin_action_types/webhook.tsx | 61 +++++----- .../threshold/expression.tsx | 69 +++++------ .../threshold/visualization.tsx | 11 +- .../components/page_error/form_errors.tsx | 31 ----- .../components/page_error/index.ts | 8 -- .../components/page_error/section_error.tsx | 45 ------- .../action_connector_form.tsx | 30 ++--- .../connector_add_flyout.tsx | 2 +- .../sections/alert_add/alert_add.tsx | 27 +---- 14 files changed, 183 insertions(+), 300 deletions(-) delete mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/form_errors.tsx delete mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/index.ts delete mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/section_error.tsx diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx index 7b483ee8fbcba8..d4769d15b332ca 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx @@ -13,9 +13,9 @@ import { EuiComboBox, EuiTextArea, EuiSwitch, + EuiFormRow, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ErrableFormRow } from '../page_error'; import { ActionTypeModel, ActionConnectorFieldsProps, @@ -171,12 +171,11 @@ const EmailActionConnectorFields: React.FunctionComponent - - - + { @@ -226,15 +226,14 @@ const EmailActionConnectorFields: React.FunctionComponent - + - - + - - + - - + - - + @@ -384,11 +384,10 @@ const EmailParamsFields: React.FunctionComponent = ({ return ( - = ({ > = ({ } }} /> - - + = ({ > = ({ } }} /> - - + = ({ > = ({ } }} /> - - + = ({ > = ({ editAction('subject', e.target.value, index); }} /> - - + = ({ > = ({ editAction('message', e.target.value, index); }} /> - + ); }; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.tsx index 82ffdfc74f53a4..aa15195cdc2867 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/es_index.tsx @@ -13,7 +13,6 @@ import { ValidationResult, ActionParamsProps, } from '../../../types'; -import { ErrableFormRow } from '../page_error'; export function getActionType(): ActionTypeModel { return { @@ -80,11 +79,10 @@ const IndexParamsFields: React.FunctionComponent = ({ const { refresh } = action; return ( - = ({ > = ({ } }} /> - + - - + ); }; @@ -311,12 +310,11 @@ const PagerDutyParamsFields: React.FunctionComponent = ({ }} /> - = ({ > = ({ } }} /> - + ); }; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.tsx index 69ee4e2f433d85..66a5915d4d27ba 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.tsx @@ -5,9 +5,8 @@ */ import React, { Fragment } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiSelect, EuiTextArea } from '@elastic/eui'; +import { EuiSelect, EuiTextArea, EuiFormRow } from '@elastic/eui'; import { ActionTypeModel, ValidationResult, ActionParamsProps } from '../../../types'; -import { ErrableFormRow } from '../page_error'; export function getActionType(): ActionTypeModel { return { @@ -50,12 +49,11 @@ export const ServerLogParamsFields: React.FunctionComponent = return ( - = > = editAction('level', e.target.value, index); }} /> - - + = > = editAction('message', e.target.value, index); }} /> - + ); }; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx index bb978722fb5d97..b69e84960a7932 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx @@ -4,9 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ import React, { Fragment } from 'react'; -import { EuiFieldText, EuiTextArea, EuiFlexGroup, EuiFlexItem, EuiButtonIcon } from '@elastic/eui'; +import { + EuiFieldText, + EuiTextArea, + EuiFlexGroup, + EuiFlexItem, + EuiButtonIcon, + EuiFormRow, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ErrableFormRow } from '../page_error'; import { ActionTypeModel, ActionConnectorFieldsProps, @@ -62,21 +68,21 @@ const SlackActionFields: React.FunctionComponent = ( return ( - = ( } }} /> - + ); }; @@ -114,12 +120,11 @@ const SlackParamsFields: React.FunctionComponent = ({ /> - = ({ > = ({ editAction('message', e.target.value, index); }} /> - + ); }; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx index ca70326d212f28..8280e5ce25da75 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx @@ -21,7 +21,6 @@ import { EuiCodeEditor, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ErrableFormRow } from '../page_error'; import { ActionTypeModel, ActionConnectorFieldsProps, @@ -175,12 +174,11 @@ const WebhookActionConnectorFields: React.FunctionComponent - - + - - + ); @@ -252,12 +251,11 @@ const WebhookActionConnectorFields: React.FunctionComponent - - + - - + - { @@ -341,7 +340,7 @@ const WebhookActionConnectorFields: React.FunctionComponent - + @@ -413,7 +412,7 @@ const WebhookParamsFields: React.FunctionComponent = ({ return ( - = ({ defaultMessage: 'Body', } )} - errorKey="body" - isShowingErrors={hasErrors === true} + isInvalid={hasErrors === true} fullWidth - errors={errors} + error={errors.body} > = ({ editAction('body', json, index); }} /> - + ); }; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx index b14afba657613d..907a61677b2631 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/expression.tsx @@ -19,6 +19,7 @@ import { EuiFieldNumber, EuiComboBoxOptionProps, EuiText, + EuiFormRow, EuiCallOut, } from '@elastic/eui'; import { AlertTypeModel, Alert, ValidationResult } from '../../../../types'; @@ -30,7 +31,6 @@ import { loadIndexPatterns, } from './lib/api'; import { useAppDependencies } from '../../../app_context'; -import { ErrableFormRow } from '../../../components/page_error'; import { getTimeOptions, getTimeFieldOptions } from '../../../lib/get_time_options'; import { getTimeUnitLabel } from '../../../lib/get_time_unit_label'; import { ThresholdVisualization } from './visualization'; @@ -424,7 +424,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = - = defaultMessage="Indices to query" /> } - errorKey="index" - isShowingErrors={hasErrors && index !== undefined} - errors={errors} + isInvalid={hasErrors && index !== undefined} + error={errors.index} helpText={ = fullWidth async isLoading={isIndiciesLoading} + isInvalid={hasErrors && index !== undefined} noSuggestions={!indexOptions.length} options={indexOptions} data-test-subj="thresholdIndexesComboBox" @@ -489,10 +489,10 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = } }} /> - + - = defaultMessage="Time field" /> } - errorKey="timeField" - isShowingErrors={hasErrors && timeField !== undefined} - errors={errors} + isInvalid={hasErrors && timeField !== undefined} + error={errors.timeField} > = } }} /> - + @@ -671,13 +671,13 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = - { if ( @@ -700,7 +700,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = setAggFieldPopoverOpen(false); }} /> - +
@@ -777,12 +777,9 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = {groupByTypes[groupBy || DEFAULT_VALUES.GROUP_BY].sizeRequired ? ( - + { const { value } = e.target; @@ -791,16 +788,16 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = }} min={1} /> - + - { setAlertParams('termField', e.target.value); }} @@ -821,7 +818,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = [firstFieldOption] )} /> - + ) : null} @@ -903,13 +900,10 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = ) : null} - + = setAlertParams('threshold', newThreshold); }} /> - + ); @@ -969,12 +963,9 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = - + { @@ -983,7 +974,7 @@ export const IndexThresholdAlertTypeExpression: React.FunctionComponent = setAlertParams('timeWindowSize', timeWindowSizeVal); }} /> - + { @@ -194,15 +193,19 @@ export const ThresholdVisualization: React.FunctionComponent = ({ alert } return ( - } - error={error} - /> + color="danger" + iconType="alert" + > + {error} + ); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/form_errors.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/form_errors.tsx deleted file mode 100644 index 68a8a5601c584c..00000000000000 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/form_errors.tsx +++ /dev/null @@ -1,31 +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 { EuiFormRow } from '@elastic/eui'; -import React, { Children, cloneElement, Fragment, ReactElement } from 'react'; -export const ErrableFormRow = ({ - errorKey, - isShowingErrors, - errors, - children, - ...rest -}: { - errorKey: string; - isShowingErrors?: boolean; - errors: { [key: string]: string[] }; - children: ReactElement; - [key: string]: any; -}) => { - return ( - 0} - error={errors[errorKey]} - {...rest} - > - {Children.map(children, child => cloneElement(child))} - - ); -}; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/index.ts deleted file mode 100644 index 3464f73ceac067..00000000000000 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/index.ts +++ /dev/null @@ -1,8 +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 { SectionError } from './section_error'; -export { ErrableFormRow } from './form_errors'; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/section_error.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/section_error.tsx deleted file mode 100644 index c13f792e719883..00000000000000 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/page_error/section_error.tsx +++ /dev/null @@ -1,45 +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 { EuiCallOut, EuiSpacer } from '@elastic/eui'; -import React, { Fragment } from 'react'; - -export interface Error { - body: { - error: string; - cause?: string[]; - message?: string; - }; -} - -interface Props { - title: React.ReactNode; - error: Error; -} - -export const SectionError: React.FunctionComponent = ({ title, error, ...rest }) => { - const { - error: errorString, - cause, // wrapEsError() on the server adds a "cause" array - message, - } = error.body; - - return ( - -
{message || errorString}
- {cause && ( - - -
    - {cause.map((causeMsg, i) => ( -
  • {causeMsg}
  • - ))} -
-
- )} -
- ); -}; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index 912b9f27fbd0ce..d1d46262c3ffcc 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment, useState, useReducer, useEffect } from 'react'; +import React, { Fragment, useState, useReducer } from 'react'; import { EuiButton, EuiFlexGroup, @@ -17,11 +17,11 @@ import { EuiFlyoutFooter, EuiFieldText, EuiFlyoutBody, + EuiFormRow, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { createActionConnector, updateActionConnector } from '../../lib/action_connector_api'; -import { SectionError, ErrableFormRow } from '../../components/page_error'; import { useAppDependencies } from '../../app_context'; import { connectorReducer } from './connector_reducer'; import { useActionsConnectorsContext } from '../../context/actions_connectors_context'; @@ -137,22 +137,8 @@ export const ActionConnectorForm = ({ return ( - - {serverError && ( - - - } - error={serverError} - /> - - - )} - + } - errorKey="name" - isShowingErrors={hasErrors && connector.name !== undefined} - errors={errors} + isInvalid={hasErrors && connector.name !== undefined} + error={errors.name} > - + {FieldsComponent !== null ? ( { - - {serverError && ( - - - } - error={serverError} - /> - - - )} + - { defaultMessage="Name" /> } - errorKey="name" - isShowingErrors={hasErrors && alert.name !== undefined} - errors={errors} + isInvalid={hasErrors && alert.name !== undefined} + error={errors.name} > { } }} /> - + Date: Thu, 2 Jan 2020 18:27:02 -0800 Subject: [PATCH 261/297] Added delete confirmation dialog for connectors list --- .../components/delete_connectors_modal.tsx | 91 +++++++++++++++++++ .../application/lib/action_connector_api.ts | 12 ++- .../components/actions_connectors_list.tsx | 60 ++++++------ 3 files changed, 132 insertions(+), 31 deletions(-) create mode 100644 x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/delete_connectors_modal.tsx diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/delete_connectors_modal.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/delete_connectors_modal.tsx new file mode 100644 index 00000000000000..b7d1a4ffe29664 --- /dev/null +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/delete_connectors_modal.tsx @@ -0,0 +1,91 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under 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 { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { useAppDependencies } from '../app_context'; +import { deleteActions } from '../lib/action_connector_api'; + +export const DeleteConnectorsModal = ({ + connectorsToDelete, + callback, +}: { + connectorsToDelete: string[]; + callback: (deleted?: string[]) => void; +}) => { + const { http, toastNotifications } = useAppDependencies(); + const numConnectorsToDelete = connectorsToDelete.length; + if (!numConnectorsToDelete) { + return null; + } + const confirmModalText = i18n.translate( + 'xpack.triggersActionsUI.deleteSelectedConnectorsConfirmModal.descriptionText', + { + defaultMessage: + "You can't recover {numConnectorsToDelete, plural, one {a deleted connector} other {deleted connectors}}.", + values: { numConnectorsToDelete }, + } + ); + const confirmButtonText = i18n.translate( + 'xpack.triggersActionsUI.deleteSelectedConnectorsConfirmModal.deleteButtonLabel', + { + defaultMessage: + 'Delete {numConnectorsToDelete, plural, one {connector} other {# connectors}} ', + values: { numConnectorsToDelete }, + } + ); + const cancelButtonText = i18n.translate( + 'xpack.triggersActionsUI.deleteSelectedConnectorsConfirmModal.cancelButtonLabel', + { + defaultMessage: 'Cancel', + } + ); + return ( + + callback()} + onConfirm={async () => { + const { successes, errors } = await deleteActions({ ids: connectorsToDelete, http }); + const numSuccesses = successes.length; + const numErrors = errors.length; + callback(successes); + if (numSuccesses > 0) { + toastNotifications.addSuccess( + i18n.translate( + 'xpack.triggersActionsUI.sections.connectorsList.deleteSelectedConnectorsSuccessNotification.descriptionText', + { + defaultMessage: + 'Deleted {numSuccesses, number} {numSuccesses, plural, one {connector} other {connectors}}', + values: { numSuccesses }, + } + ) + ); + } + + if (numErrors > 0) { + toastNotifications.addDanger( + i18n.translate( + 'xpack.triggersActionsUI.sections.connectorsList.deleteSelectedConnectorsErrorNotification.descriptionText', + { + defaultMessage: + 'Failed to delete {numErrors, number} {numErrors, plural, one {connector} other {connectors}}', + values: { numErrors }, + } + ) + ); + } + }} + cancelButtonText={cancelButtonText} + confirmButtonText={confirmButtonText} + > + {confirmModalText} + + + ); +}; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts index 8d13aeaa28ab0c..cd543a24099a07 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts @@ -70,6 +70,14 @@ export async function deleteActions({ }: { ids: string[]; http: HttpSetup; -}): Promise { - await Promise.all(ids.map(id => http.delete(`${BASE_ACTION_API_PATH}/${id}`))); +}): Promise<{ successes: string[]; errors: string[] }> { + const successes: string[] = []; + const errors: string[] = []; + await Promise.all(ids.map(id => http.delete(`${BASE_ACTION_API_PATH}/${id}`))).then(function( + values + ) { + errors.push(...values.filter(v => v.state === 'rejected')); + successes.push(...values.filter(v => v.state === 'fulfilled')); + }); + return { successes, errors }; } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index 4bd433dfee7f13..a393a8a585d338 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -19,10 +19,11 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { ActionsConnectorsContextProvider } from '../../../context/actions_connectors_context'; import { useAppDependencies } from '../../../app_context'; -import { deleteActions, loadAllActions, loadActionTypes } from '../../../lib/action_connector_api'; +import { loadAllActions, loadActionTypes } from '../../../lib/action_connector_api'; import { ActionConnector, ActionConnectorTableItem, ActionTypeIndex } from '../../../../types'; import { ConnectorAddFlyout, ConnectorEditFlyout } from '../../action_connector_form'; import { hasDeleteActionsCapability, hasSaveActionsCapability } from '../../../lib/capabilities'; +import { DeleteConnectorsModal } from '../../../components/delete_connectors_modal'; export const ActionsConnectorsList: React.FunctionComponent = () => { const { @@ -48,6 +49,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { const [editedConnectorItem, setEditedConnectorItem] = useState< ActionConnectorTableItem | undefined >(undefined); + const [connectorsToDelete, setConnectorsToDelete] = useState([]); useEffect(() => { loadActions(); @@ -122,37 +124,11 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { } } - async function deleteItems(items: ActionConnectorTableItem[]) { - setIsDeletingActions(true); - const ids = items.map(item => (item.id ? item.id : '')); - try { - await deleteActions({ http, ids }); - const updatedActions = actions.filter(action => action.id && !ids.includes(action.id)); - setActions(updatedActions); - } catch (e) { - toastNotifications.addDanger({ - title: i18n.translate( - 'xpack.triggersActionsUI.sections.actionsConnectorsList.failedToDeleteActionsMessage', - { defaultMessage: 'Failed to delete action(s)' } - ), - }); - // Refresh the actions from the server, some actions may have beend deleted - loadActions(); - } finally { - setIsDeletingActions(false); - } - } - async function editItem(connectorTableItem: ActionConnectorTableItem) { setEditedConnectorItem(connectorTableItem); setEditFlyoutVisibility(true); } - async function deleteSelectedItems() { - await deleteItems(selectedItems); - setSelectedItems([]); - } - const actionsTableColumns = [ { field: 'name', @@ -224,7 +200,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { ), type: 'icon', icon: 'trash', - onClick: (item: ActionConnectorTableItem) => deleteItems([item]), + onClick: (item: ActionConnectorTableItem) => setConnectorsToDelete([item.id]), }, ], }, @@ -276,7 +252,9 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { iconType="trash" color="danger" data-test-subj="bulkDelete" - onClick={deleteSelectedItems} + onClick={() => { + setConnectorsToDelete(selectedItems.map((selected: any) => selected.id)); + }} title={ canDelete ? undefined @@ -369,6 +347,30 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { return (
+ { + if (deleted) { + if (selectedItems.length === deleted.length) { + const updatedActions = actions.filter( + action => action.id && !connectorsToDelete.includes(action.id) + ); + setActions(updatedActions); + setSelectedItems([]); + } else { + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.triggersActionsUI.sections.actionsConnectorsList.failedToDeleteActionsMessage', + { defaultMessage: 'Failed to delete action(s)' } + ), + }); + // Refresh the actions from the server, some actions may have beend deleted + loadActions(); + } + } + setConnectorsToDelete([]); + }} + connectorsToDelete={connectorsToDelete} + /> {/* Render the view based on if there's data or if they can save */} {data.length !== 0 && table} From fcb6369af7631d5ad7d9b49388ca0f04d1624cd7 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 2 Jan 2020 20:08:55 -0800 Subject: [PATCH 262/297] Fixed build errors --- .../server/builtin_action_types/server_log.test.ts | 2 +- .../server/builtin_action_types/server_log.ts | 2 +- .../public/application/lib/action_connector_api.ts | 14 ++++++++------ .../components/actions_connectors_list.tsx | 5 ++--- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.test.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.test.ts index 32da12603f05ba..a4cb156b5fc1c1 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.test.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.test.ts @@ -98,6 +98,6 @@ describe('execute()', () => { config: {}, secrets: {}, }); - expect(mockedLogger.info).toHaveBeenCalledWith('server-log: message text here'); + expect(mockedLogger.info).toHaveBeenCalledWith('Server Log: message text here'); }); }); diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.ts index 0edf409e4d46c6..0811ae20eea837 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.ts @@ -12,7 +12,7 @@ import { Logger } from '../../../../../../src/core/server'; import { ActionType, ActionTypeExecutorOptions, ActionTypeExecutorResult } from '../types'; import { withoutControlCharacters } from './lib/string_utils'; -const ACTION_NAME = 'server-log'; +const ACTION_NAME = 'Server Log'; // params definition diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts index cd543a24099a07..5b2b59603d281d 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.ts @@ -73,11 +73,13 @@ export async function deleteActions({ }): Promise<{ successes: string[]; errors: string[] }> { const successes: string[] = []; const errors: string[] = []; - await Promise.all(ids.map(id => http.delete(`${BASE_ACTION_API_PATH}/${id}`))).then(function( - values - ) { - errors.push(...values.filter(v => v.state === 'rejected')); - successes.push(...values.filter(v => v.state === 'fulfilled')); - }); + await Promise.all(ids.map(id => http.delete(`${BASE_ACTION_API_PATH}/${id}`))).then( + function(fulfilled) { + successes.push(...fulfilled); + }, + function(rejected) { + errors.push(...rejected); + } + ); return { successes, errors }; } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index a393a8a585d338..32db4367bc90fc 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -40,7 +40,6 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { const [selectedItems, setSelectedItems] = useState([]); const [isLoadingActionTypes, setIsLoadingActionTypes] = useState(false); const [isLoadingActions, setIsLoadingActions] = useState(false); - const [isDeletingActions, setIsDeletingActions] = useState(false); const [editFlyoutVisible, setEditFlyoutVisibility] = useState(false); const [addFlyoutVisible, setAddFlyoutVisibility] = useState(false); const [actionTypesList, setActionTypesList] = useState>( @@ -208,7 +207,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { const table = ( { { if (deleted) { - if (selectedItems.length === deleted.length) { + if (selectedItems.length === 0 || selectedItems.length === deleted.length) { const updatedActions = actions.filter( action => action.id && !connectorsToDelete.includes(action.id) ); From f16b6d5a5a16d09fd547b33d9562ce0b452fe2ca Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 2 Jan 2020 21:00:00 -0800 Subject: [PATCH 263/297] Fixed failing test --- .../public/application/lib/action_connector_api.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.test.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.test.ts index ad5a75d577515b..bc2949917edea7 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.test.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/lib/action_connector_api.test.ts @@ -117,7 +117,7 @@ describe('deleteActions', () => { const ids = ['1', '2', '3']; const result = await deleteActions({ ids, http }); - expect(result).toEqual(undefined); + expect(result).toEqual({ errors: [], successes: [undefined, undefined, undefined] }); expect(http.delete.mock.calls).toMatchInlineSnapshot(` Array [ Array [ From 8a1e52c68ebcdfb0f0b81f4cbf6e7e9a499d4c0a Mon Sep 17 00:00:00 2001 From: Mike Cote Date: Fri, 3 Jan 2020 12:24:18 -0500 Subject: [PATCH 264/297] Skip flaky tests --- .../apps/triggers_actions_ui/alerts.ts | 18 ++++++++++++------ .../apps/triggers_actions_ui/connectors.ts | 6 ++++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts index 9ad3b6124dad13..4fdfe0d32ace3d 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts.ts @@ -180,7 +180,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(isChecked).to.eql('false'); }); - it('should delete single alert', async () => { + // Flaky, will be fixed with https://github.com/elastic/kibana/issues/53956 + it.skip('should delete single alert', async () => { const createdAlert = await createAlert(); await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); @@ -199,7 +200,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }); - it('should mute all selection', async () => { + // Flaky, will be fixed with https://github.com/elastic/kibana/issues/49830 + it.skip('should mute all selection', async () => { const createdAlert = await createAlert(); await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); @@ -226,7 +228,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(isChecked).to.eql('true'); }); - it('should unmute all selection', async () => { + // Flaky, will be fixed with https://github.com/elastic/kibana/issues/49830 + it.skip('should unmute all selection', async () => { const createdAlert = await createAlert(); await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); @@ -256,7 +259,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(isChecked).to.eql('false'); }); - it('should disable all selection', async () => { + // Flaky, will be fixed with https://github.com/elastic/kibana/issues/49830 + it.skip('should disable all selection', async () => { const createdAlert = await createAlert(); await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); @@ -283,7 +287,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(isChecked).to.eql('false'); }); - it('should enable all selection', async () => { + // Flaky, will be fixed with https://github.com/elastic/kibana/issues/49830 + it.skip('should enable all selection', async () => { const createdAlert = await createAlert(); await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); @@ -313,7 +318,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(isChecked).to.eql('true'); }); - it('should delete all selection', async () => { + // Flaky, will be fixed with https://github.com/elastic/kibana/issues/53956 + it.skip('should delete all selection', async () => { const createdAlert = await createAlert(); await pageObjects.triggersActionsUI.searchAlerts(createdAlert.name); diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts index dbc391ce8ce633..eb6720207e78f0 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts @@ -113,7 +113,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ]); }); - it('should delete a connector', async () => { + // Flaky, will be fixed with https://github.com/elastic/kibana/issues/53956 + it.skip('should delete a connector', async () => { const connectorName = generateUniqueKey(); await pageObjects.triggersActionsUI.clickCreateConnectorButton(); @@ -147,7 +148,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(searchResultsAfterDelete.length).to.eql(0); }); - it('should bulk delete connectors', async () => { + // Flaky, will be fixed with https://github.com/elastic/kibana/issues/53956 + it.skip('should bulk delete connectors', async () => { const connectorName = generateUniqueKey(); await pageObjects.triggersActionsUI.clickCreateConnectorButton(); From 95006d5701c3b0705b4504120045e4118a2deb0d Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 6 Jan 2020 09:58:48 -0800 Subject: [PATCH 265/297] Added null check for app context - render components tree only if it isn't null --- .../np_ready/public/application/app.tsx | 4 ++-- .../np_ready/public/application/app_context.tsx | 10 +++++----- .../np_ready/public/application/boot.tsx | 1 - .../action_connector_form.test.tsx | 2 +- .../action_connector_form/action_type_menu.test.tsx | 2 +- .../connector_add_flyout.test.tsx | 2 +- .../connector_edit_flyout.test.tsx | 2 +- .../components/actions_connectors_list.test.tsx | 8 ++++---- .../alerts_list/components/alerts_list.test.tsx | 8 ++++---- 9 files changed, 19 insertions(+), 20 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx index bdc898da1adf13..3ad6b5b7c697de 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app.tsx @@ -31,14 +31,14 @@ export interface AppDeps { alertTypeRegistry: TypeRegistry; } -export const App = (deps: AppDeps) => { +export const App = (appDeps: AppDeps) => { const sections: Section[] = ['alerts', 'connectors']; const sectionsRegex = sections.join('|'); return ( - + diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app_context.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app_context.tsx index c04c5a1856feed..bf2e0c7274e7b6 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app_context.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/app_context.tsx @@ -7,19 +7,19 @@ import React, { createContext, useContext } from 'react'; import { AppDeps } from './app'; -const AppContext = createContext(null as any); +const AppContext = createContext(null); export const AppContextProvider = ({ children, - value, + appDeps, }: { - value: AppDeps; + appDeps: AppDeps | null; children: React.ReactNode; }) => { - return {children}; + return appDeps ? {children} : null; }; -export const useAppDependencies = () => { +export const useAppDependencies = (): AppDeps => { const ctx = useContext(AppContext); if (!ctx) { throw new Error( diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/boot.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/boot.tsx index e718147adb66fa..a37bedbfbdda88 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/boot.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/boot.tsx @@ -11,7 +11,6 @@ import { SavedObjectsClientContract } from 'src/core/public'; import { App, AppDeps } from './app'; import { setSavedObjectsClient } from '../application/components/builtin_alert_types/threshold/lib/api'; import { LegacyDependencies } from '../types'; -// import { LegacyDependencies } from '../types'; interface BootDeps extends AppDeps { element: HTMLElement; diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx index e53e05266519b4..c129ce73c7176e 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.test.tsx @@ -71,7 +71,7 @@ describe('action_connector_form', () => { await act(async () => { wrapper = mountWithIntl( - + { actionTypeRegistry.get.mockReturnValueOnce(actionType); const wrapper = mountWithIntl( - + { await act(async () => { wrapper = mountWithIntl( - + { actionTypeRegistry.has.mockReturnValue(true); const wrapper = mountWithIntl( - + { await act(async () => { wrapper = mountWithIntl( - + ); @@ -168,7 +168,7 @@ describe('actions_connectors_list component with items', () => { await act(async () => { wrapper = mountWithIntl( - + ); @@ -249,7 +249,7 @@ describe('actions_connectors_list component empty with show only capability', () await act(async () => { wrapper = mountWithIntl( - + ); @@ -335,7 +335,7 @@ describe('actions_connectors_list with show only capability', () => { await act(async () => { wrapper = mountWithIntl( - + ); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx index 0f896898c8d1d9..8f8aef5a16bd5f 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.test.tsx @@ -104,7 +104,7 @@ describe('alerts_list component empty', () => { await act(async () => { wrapper = mountWithIntl( - + ); @@ -227,7 +227,7 @@ describe('alerts_list component with items', () => { await act(async () => { wrapper = mountWithIntl( - + ); @@ -315,7 +315,7 @@ describe('alerts_list component empty with show only capability', () => { await act(async () => { wrapper = mountWithIntl( - + ); @@ -430,7 +430,7 @@ describe('alerts_list with show only capability', () => { await act(async () => { wrapper = mountWithIntl( - + ); From 072ec10a3f42d379d0500316992446a476cd7635 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 6 Jan 2020 10:31:35 -0800 Subject: [PATCH 266/297] Fixed type check eror --- .../components/builtin_alert_types/threshold/visualization.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx index 159fa4c54d6f4d..9048cfcb40a48e 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx @@ -272,7 +272,7 @@ export const ThresholdVisualization: React.FunctionComponent = ({ alert } return ( From 1d2a59a005b0bbf77c2eccef43eff3427f89e02d Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 6 Jan 2020 15:47:57 -0800 Subject: [PATCH 267/297] Did changes on the UX and text/labels commnets --- .../builtin_action_types/server_log.test.ts | 4 +- .../server/builtin_action_types/server_log.ts | 2 +- .../components/builtin_action_types/email.tsx | 80 ++++++++----------- .../builtin_action_types/pagerduty.tsx | 34 ++++++-- .../builtin_action_types/server_log.tsx | 2 +- .../builtin_action_types/slack.test.tsx | 3 +- .../components/builtin_action_types/slack.tsx | 23 ++++-- .../builtin_action_types/webhook.test.tsx | 1 - .../builtin_action_types/webhook.tsx | 31 ++++--- .../threshold/visualization.tsx | 1 - .../action_connector_form.tsx | 4 +- .../action_type_menu.tsx | 28 ++++--- .../connector_add_flyout.tsx | 4 +- .../components/actions_connectors_list.tsx | 8 +- .../components/action_type_filter.tsx | 2 +- .../components/bulk_action_popover.tsx | 12 +-- .../apps/triggers_actions_ui/connectors.ts | 4 +- 17 files changed, 128 insertions(+), 115 deletions(-) diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.test.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.test.ts index a4cb156b5fc1c1..8f28b9e8f51254 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.test.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.test.ts @@ -25,7 +25,7 @@ beforeAll(() => { describe('get()', () => { test('returns action type', () => { expect(actionType.id).toEqual(ACTION_TYPE_ID); - expect(actionType.name).toEqual('Server Log'); + expect(actionType.name).toEqual('Server log'); }); }); @@ -98,6 +98,6 @@ describe('execute()', () => { config: {}, secrets: {}, }); - expect(mockedLogger.info).toHaveBeenCalledWith('Server Log: message text here'); + expect(mockedLogger.info).toHaveBeenCalledWith('Server log: message text here'); }); }); diff --git a/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.ts b/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.ts index 0811ae20eea837..34b8602eeba368 100644 --- a/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.ts +++ b/x-pack/legacy/plugins/actions/server/builtin_action_types/server_log.ts @@ -12,7 +12,7 @@ import { Logger } from '../../../../../../src/core/server'; import { ActionType, ActionTypeExecutorOptions, ActionTypeExecutorResult } from '../types'; import { withoutControlCharacters } from './lib/string_utils'; -const ACTION_NAME = 'Server Log'; +const ACTION_NAME = 'Server log'; // params definition diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx index d4769d15b332ca..1a75ebcb11a7e9 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx @@ -25,13 +25,14 @@ import { } from '../../../types'; export function getActionType(): ActionTypeModel { + const mailformat = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/; return { id: '.email', iconClass: 'email', selectMessage: i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.emailAction.selectMessageText', { - defaultMessage: 'Configure settings to send email through your mail server', + defaultMessage: 'Send email from your server.', } ), validateConnector: (action: ActionConnector): ValidationResult => { @@ -50,7 +51,17 @@ export function getActionType(): ActionTypeModel { i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredFromText', { - defaultMessage: 'From is required.', + defaultMessage: 'Sender is required.', + } + ) + ); + } + if (action.config.from && !action.config.from.match(mailformat)) { + errors.from.push( + i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.error.formatFromText', + { + defaultMessage: 'Sender is not a valid email address.', } ) ); @@ -60,7 +71,7 @@ export function getActionType(): ActionTypeModel { i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredPortText', { - defaultMessage: 'Port or Service is required.', + defaultMessage: 'Port is required.', } ) ); @@ -70,7 +81,7 @@ export function getActionType(): ActionTypeModel { i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredServiceText', { - defaultMessage: 'Service or host with port is required.', + defaultMessage: 'Service is required.', } ) ); @@ -80,7 +91,7 @@ export function getActionType(): ActionTypeModel { i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredHostText', { - defaultMessage: 'Host or Service is required.', + defaultMessage: 'Host is required.', } ) ); @@ -90,7 +101,7 @@ export function getActionType(): ActionTypeModel { i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredUserText', { - defaultMessage: 'User is required.', + defaultMessage: 'Username is required.', } ) ); @@ -164,9 +175,8 @@ const EmailActionConnectorFields: React.FunctionComponent { - const { from, host, port, secure, service } = action.config; + const { from, host, port, secure } = action.config; const { user, password } = action.secrets; return ( @@ -175,17 +185,17 @@ const EmailActionConnectorFields: React.FunctionComponent 0 && from !== undefined} label={i18n.translate( 'xpack.triggersActionsUI.sections.builtinActionTypes.emailAction.fromTextFieldLabel', { - defaultMessage: 'From', + defaultMessage: 'Sender', } )} > 0 && from !== undefined} name="from" value={from || ''} data-test-subj="emailFromInput" @@ -199,41 +209,13 @@ const EmailActionConnectorFields: React.FunctionComponent - - { - editActionConfig('service', e.target.value); - }} - onBlur={() => { - if (!service) { - editActionConfig('service', ''); - } - }} - /> - 0 && host !== undefined} label={i18n.translate( 'xpack.triggersActionsUI.sections.builtinActionTypes.emailAction.hostTextFieldLabel', { @@ -243,8 +225,9 @@ const EmailActionConnectorFields: React.FunctionComponent 0 && host !== undefined} name="host" + placeholder="localhost" value={host || ''} data-test-subj="emailHostInput" onChange={e => { @@ -262,8 +245,9 @@ const EmailActionConnectorFields: React.FunctionComponent 0 && port !== undefined} label={i18n.translate( 'xpack.triggersActionsUI.sections.builtinActionTypes.emailAction.portTextFieldLabel', { @@ -273,7 +257,7 @@ const EmailActionConnectorFields: React.FunctionComponent 0 && port !== undefined} fullWidth name="port" value={port || ''} @@ -310,17 +294,17 @@ const EmailActionConnectorFields: React.FunctionComponent 0 && user !== undefined} label={i18n.translate( 'xpack.triggersActionsUI.sections.builtinActionTypes.emailAction.userTextFieldLabel', { - defaultMessage: 'User', + defaultMessage: 'Username', } )} > 0 && user !== undefined} name="user" value={user || ''} data-test-subj="emailUserInput" @@ -340,7 +324,7 @@ const EmailActionConnectorFields: React.FunctionComponent 0 && password !== undefined} label={i18n.translate( 'xpack.triggersActionsUI.sections.builtinActionTypes.emailAction.passwordFieldLabel', { @@ -350,7 +334,7 @@ const EmailActionConnectorFields: React.FunctionComponent 0 && password !== undefined} name="password" value={password || ''} data-test-subj="emailPasswordInput" diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.tsx index 3dfd050baac23a..679e9c7a451838 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.tsx @@ -4,8 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ import React, { Fragment } from 'react'; -import { EuiFieldText, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiSelect } from '@elastic/eui'; +import { + EuiFieldText, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiSelect, + EuiLink, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { ActionTypeModel, ActionConnectorFieldsProps, @@ -21,7 +29,7 @@ export function getActionType(): ActionTypeModel { selectMessage: i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.selectMessageText', { - defaultMessage: 'Configure PageDuty API details to send events to their system', + defaultMessage: 'Send an event in PagerDuty.', } ), validateConnector: (action: ActionConnector): ValidationResult => { @@ -35,7 +43,7 @@ export function getActionType(): ActionTypeModel { i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.error.requiredRoutingKeyText', { - defaultMessage: 'Routing Key is required.', + defaultMessage: 'A routing key is required.', } ) ); @@ -53,7 +61,6 @@ export function getActionType(): ActionTypeModel { const PagerDutyActionConnectorFields: React.FunctionComponent = ({ errors, - hasErrors, action, editActionConfig, editActionSecrets, @@ -68,7 +75,7 @@ const PagerDutyActionConnectorFields: React.FunctionComponent @@ -90,18 +97,29 @@ const PagerDutyActionConnectorFields: React.FunctionComponent + + + } error={errors.routingKey} - isInvalid={hasErrors === true && routingKey !== undefined} + isInvalid={errors.routingKey.length > 0 && routingKey !== undefined} label={i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.pagerDutyAction.routingKeyTextFieldLabel', { - defaultMessage: 'RoutingKey', + defaultMessage: 'Routing key', } )} > 0 && routingKey !== undefined} name="routingKey" value={routingKey || ''} data-test-subj="pagerdutyRoutingKeyInput" diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.tsx index 66a5915d4d27ba..da9271bb82a9bb 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.tsx @@ -15,7 +15,7 @@ export function getActionType(): ActionTypeModel { selectMessage: i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.serverLogAction.selectMessageText', { - defaultMessage: 'Adds a log line with a message you define', + defaultMessage: 'Add a message to a Kibana log.', } ), validateConnector: (): ValidationResult => { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.test.tsx index 8db445c89abfeb..50451aebf4fb10 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.test.tsx @@ -58,7 +58,7 @@ describe('slack connector validation', () => { expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ errors: { - webhookUrl: ['WebhookUrl is required.'], + webhookUrl: ['Webhook URL is required.'], }, }); }); @@ -106,7 +106,6 @@ describe('SlackActionFields renders', () => { errors={{}} editActionConfig={() => {}} editActionSecrets={() => {}} - hasErrors={false} /> ); expect(wrapper.find('[data-test-subj="slackWebhookUrlInput"]').length > 0).toBeTruthy(); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx index b69e84960a7932..671272f0aa341f 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx @@ -11,8 +11,10 @@ import { EuiFlexItem, EuiButtonIcon, EuiFormRow, + EuiLink, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import { ActionTypeModel, ActionConnectorFieldsProps, @@ -28,7 +30,7 @@ export function getActionType(): ActionTypeModel { selectMessage: i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.slackAction.selectMessageText', { - defaultMessage: 'Configure Slack using a webhook url they provide', + defaultMessage: 'Send a message to a Slack channel or user.', } ), validateConnector: (action: ActionConnector): ValidationResult => { @@ -42,7 +44,7 @@ export function getActionType(): ActionTypeModel { i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.slackAction.error.requiredWebhookUrlText', { - defaultMessage: 'WebhookUrl is required.', + defaultMessage: 'Webhook URL is required.', } ) ); @@ -62,7 +64,6 @@ const SlackActionFields: React.FunctionComponent = ( action, editActionSecrets, errors, - hasErrors, }) => { const { webhookUrl } = action.secrets; @@ -71,8 +72,19 @@ const SlackActionFields: React.FunctionComponent = ( + + + } error={errors.webhookUrl} - isInvalid={hasErrors === true && webhookUrl !== undefined} + isInvalid={errors.webhookUrl.length > 0 && webhookUrl !== undefined} label={i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.slackAction.webhookUrlTextFieldLabel', { @@ -82,8 +94,9 @@ const SlackActionFields: React.FunctionComponent = ( > 0 && webhookUrl !== undefined} name="webhookUrl" + placeholder="URL like https://hooks.slack.com/services" value={webhookUrl || ''} data-test-subj="slackWebhookUrlInput" onChange={e => { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx index 881ceeb24e5bac..3f782dfc705d1d 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx @@ -118,7 +118,6 @@ describe('WebhookActionConnectorFields renders', () => { errors={{}} editActionConfig={() => {}} editActionSecrets={() => {}} - hasErrors={false} /> ); expect(wrapper.find('[data-test-subj="webhookAddHeaderButton"]').length > 0).toBeTruthy(); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx index 8280e5ce25da75..3e8d34c681ebe7 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx @@ -55,7 +55,7 @@ export function getActionType(): ActionTypeModel { i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.error.requiredUrlText', { - defaultMessage: 'Url is required.', + defaultMessage: 'URL is required.', } ) ); @@ -75,7 +75,7 @@ export function getActionType(): ActionTypeModel { i18n.translate( 'xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredHostText', { - defaultMessage: 'User is required.', + defaultMessage: 'Username is required.', } ) ); @@ -106,7 +106,6 @@ const WebhookActionConnectorFields: React.FunctionComponent { const [headerKey, setHeaderKey] = useState(''); const [headerValue, setHeaderValue] = useState(''); @@ -126,7 +125,7 @@ const WebhookActionConnectorFields: React.FunctionComponent @@ -207,7 +206,7 @@ const WebhookActionConnectorFields: React.FunctionComponent @@ -255,17 +254,17 @@ const WebhookActionConnectorFields: React.FunctionComponent 0 && url !== undefined} label={i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.urlTextFieldLabel', { - defaultMessage: 'Url', + defaultMessage: 'URL', } )} > 0 && url !== undefined} fullWidth value={url || ''} data-test-subj="webhookUrlText" @@ -287,17 +286,17 @@ const WebhookActionConnectorFields: React.FunctionComponent 0 && user !== undefined} label={i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.userTextFieldLabel', { - defaultMessage: 'User', + defaultMessage: 'Username', } )} > 0 && user !== undefined} name="user" value={user || ''} data-test-subj="webhookUserInput" @@ -317,7 +316,7 @@ const WebhookActionConnectorFields: React.FunctionComponent 0 && password !== undefined} label={i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.passwordTextFieldLabel', { @@ -328,7 +327,7 @@ const WebhookActionConnectorFields: React.FunctionComponent 0 && password !== undefined} value={password || ''} data-test-subj="webhookPasswordInput" onChange={e => { @@ -365,7 +364,7 @@ const WebhookActionConnectorFields: React.FunctionComponent
diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx index 9048cfcb40a48e..8433c585ef3e5b 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_alert_types/threshold/visualization.tsx @@ -10,7 +10,6 @@ import { i18n } from '@kbn/i18n'; import { AnnotationDomainTypes, Axis, - getAnnotationId, getAxisId, getSpecId, Chart, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index d1d46262c3ffcc..5bb2ec62002ddd 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -147,12 +147,12 @@ export const ActionConnectorForm = ({ defaultMessage="Name" /> } - isInvalid={hasErrors && connector.name !== undefined} + isInvalid={errors.name.length > 0 && connector.name !== undefined} error={errors.name} > 0 && connector.name !== undefined} name="name" data-test-subj="nameInput" value={connector.name || ''} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx index 4356bf7d512651..19373fda79b9e7 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_type_menu.tsx @@ -43,19 +43,21 @@ export const ActionTypeMenu = ({ onActionTypeChange }: Props) => { }; }); - const cardNodes = actionTypes.map((item, index): any => { - return ( - - } - title={item.name} - description={item.selectMessage} - onClick={() => onActionTypeChange(item.actionType)} - /> - - ); - }); + const cardNodes = actionTypes + .sort((a, b) => a.name.localeCompare(b.name)) + .map((item, index): any => { + return ( + + } + title={item.name} + description={item.selectMessage} + onClick={() => onActionTypeChange(item.actionType)} + /> + + ); + }); return ( diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx index 91d78847ebdb9e..a3ec7ab4b3ab96 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/connector_add_flyout.tsx @@ -73,7 +73,7 @@ export const ConnectorAddFlyout = () => {

{

diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index 32db4367bc90fc..0943924623f0fd 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -165,7 +165,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { 'data-test-subj': 'connectorsTableCell-referencedByCount', name: i18n.translate( 'xpack.triggersActionsUI.sections.actionsConnectorsList.connectorsListTable.columns.referencedByCountTitle', - { defaultMessage: 'Attached actions' } + { defaultMessage: 'Actions' } ), sortable: false, truncateText: true, @@ -283,7 +283,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { > , ], @@ -313,7 +313,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => {

} @@ -328,7 +328,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { > } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/action_type_filter.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/action_type_filter.tsx index 1e5b411b33ba4c..7a25a241b0162c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/action_type_filter.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/action_type_filter.tsx @@ -43,7 +43,7 @@ export const ActionTypeFilter: React.FunctionComponent = > } diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx index 95d8e14e26f64d..59ec52ac83a6c5 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/bulk_action_popover.tsx @@ -162,7 +162,7 @@ export const BulkActionPopover: React.FunctionComponent = ({ > } @@ -177,7 +177,7 @@ export const BulkActionPopover: React.FunctionComponent = ({ > @@ -192,7 +192,7 @@ export const BulkActionPopover: React.FunctionComponent = ({ > @@ -207,7 +207,7 @@ export const BulkActionPopover: React.FunctionComponent = ({ > @@ -222,7 +222,7 @@ export const BulkActionPopover: React.FunctionComponent = ({ > @@ -236,7 +236,7 @@ export const BulkActionPopover: React.FunctionComponent = ({ > diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts index eb6720207e78f0..16c5516291cf8e 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts @@ -51,7 +51,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(searchResults).to.eql([ { name: connectorName, - actionType: 'Server Log', + actionType: 'Server log', referencedByCount: '0', }, ]); @@ -107,7 +107,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(searchResultsAfterEdit).to.eql([ { name: updatedConnectorName, - actionType: 'Server Log', + actionType: 'Server log', referencedByCount: '0', }, ]); From 3618cf1e432e4ba2bc539d76eb25e921d9672a31 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 6 Jan 2020 16:54:40 -0800 Subject: [PATCH 268/297] Fixed failing tests --- .../components/builtin_action_types/email.test.tsx | 8 ++++---- .../components/builtin_action_types/pagerduty.test.tsx | 4 ++-- .../components/builtin_action_types/pagerduty.tsx | 2 +- .../components/builtin_action_types/slack.test.tsx | 2 +- .../application/components/builtin_action_types/slack.tsx | 2 +- .../components/builtin_action_types/webhook.test.tsx | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx index f79bff058805f6..5c924982c3536a 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.test.tsx @@ -102,9 +102,9 @@ describe('connector validation', () => { expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ errors: { from: [], - service: ['Service or host with port is required.'], - port: ['Port or Service is required.'], - host: ['Host or Service is required.'], + service: ['Service is required.'], + port: ['Port is required.'], + host: ['Host is required.'], user: [], password: [], }, @@ -172,7 +172,7 @@ describe('EmailActionConnectorFields renders', () => { const wrapper = mountWithIntl( {}} editActionSecrets={() => {}} hasErrors={false} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.test.tsx index 35dfe94d009eeb..52bfa021125cc0 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.test.tsx @@ -70,7 +70,7 @@ describe('pagerduty connector validation', () => { expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ errors: { - routingKey: ['Routing Key is required.'], + routingKey: ['A routing key is required.'], }, }); }); @@ -117,7 +117,7 @@ describe('PagerDutyActionConnectorFields renders', () => { const wrapper = mountWithIntl( {}} editActionSecrets={() => {}} hasErrors={false} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.tsx index 679e9c7a451838..69c7ec166df60e 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.tsx @@ -103,7 +103,7 @@ const PagerDutyActionConnectorFields: React.FunctionComponent diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.test.tsx index 50451aebf4fb10..f41d25808693f7 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.test.tsx @@ -103,7 +103,7 @@ describe('SlackActionFields renders', () => { const wrapper = mountWithIntl( {}} editActionSecrets={() => {}} /> diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx index 671272f0aa341f..72f39a4a13a36c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx @@ -78,7 +78,7 @@ const SlackActionFields: React.FunctionComponent = ( target="_blank" > diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx index 3f782dfc705d1d..633aca40907500 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx @@ -70,7 +70,7 @@ describe('webhook connector validation', () => { expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ errors: { - url: ['Url is required.'], + url: ['URL is required.'], method: [], user: [], password: ['Password is required.'], @@ -115,7 +115,7 @@ describe('WebhookActionConnectorFields renders', () => { const wrapper = mountWithIntl( {}} editActionSecrets={() => {}} /> From 3004376d1e4a775a189e2c430caebb012b980e96 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 7 Jan 2020 11:54:12 -0800 Subject: [PATCH 269/297] Fixed error handling --- .../action_connector_form.tsx | 65 ++++++++++--------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index 5bb2ec62002ddd..6b4b892bdd4587 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -99,39 +99,46 @@ export const ActionConnectorForm = ({ const hasErrors = !!Object.keys(errors).find(errorKey => errors[errorKey].length >= 1); async function onActionConnectorSave(): Promise { - try { - let message; - let savedConnector; - if (connector.id === undefined) { - savedConnector = await createActionConnector({ http, connector }); - message = i18n.translate( - 'xpack.triggersActionsUI.sections.actionConnectorForm.createSuccessNotificationText', - { - defaultMessage: "Created '{connectorName}'", - values: { - connectorName: savedConnector.name, - }, - } - ); - } else { - savedConnector = await updateActionConnector({ http, connector, id: connector.id }); - message = i18n.translate( - 'xpack.triggersActionsUI.sections.actionConnectorForm.updateSuccessNotificationText', - { - defaultMessage: "Updated '{connectorName}'", - values: { - connectorName: savedConnector.name, - }, - } - ); - } - toastNotifications.addSuccess(message); - return savedConnector; - } catch (error) { + let message: string; + let savedConnector: ActionConnector | undefined; + let error; + if (connector.id === undefined) { + await createActionConnector({ http, connector }) + .then(res => { + savedConnector = res; + }) + .catch(errorRes => { + error = errorRes; + }); + + message = "Created '{connectorName}'"; + } else { + await updateActionConnector({ http, connector, id: connector.id }) + .then(res => { + savedConnector = res; + }) + .catch(errorRes => { + error = errorRes; + }); + message = "Updated '{connectorName}'"; + } + if (error) { return { error, }; } + toastNotifications.addSuccess( + i18n.translate( + 'xpack.triggersActionsUI.sections.actionConnectorForm.updateSuccessNotificationText', + { + defaultMessage: message, + values: { + connectorName: savedConnector ? savedConnector.name : '', + }, + } + ) + ); + return savedConnector; } return ( From 91728dba9e7baefb98eae4749b27fa63bd610e51 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 7 Jan 2020 16:51:09 -0800 Subject: [PATCH 270/297] Refactored Webhook form http headers due to the mockup --- .../builtin_action_types/webhook.tsx | 125 ++++++++++-------- .../action_connector_form.tsx | 10 +- 2 files changed, 79 insertions(+), 56 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx index 3e8d34c681ebe7..6564c130fadab2 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx @@ -19,6 +19,8 @@ import { EuiText, EuiTitle, EuiCodeEditor, + EuiSwitch, + EuiButtonEmpty, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { @@ -143,10 +145,6 @@ const WebhookActionConnectorFields: React.FunctionComponent 0 || headerErrors.valueHeader.length > 0; function addHeader() { - if (!hasHeaders) { - setHasHeaders(true); - return; - } if (headers && !!Object.keys(headers).find(key => key === headerKey)) { return; } @@ -158,6 +156,13 @@ const WebhookActionConnectorFields: React.FunctionComponent key !== keyToRemove) @@ -171,7 +176,7 @@ const WebhookActionConnectorFields: React.FunctionComponent + @@ -206,7 +211,7 @@ const WebhookActionConnectorFields: React.FunctionComponent @@ -222,10 +227,48 @@ const WebhookActionConnectorFields: React.FunctionComponent + + addHeader()} + > + + + ); } + const headersList = Object.keys(headers || {}).map((key: string) => { + return ( + + + removeHeader(key)} + /> + + + {key}: + + + {headers[key]} + + + ); + }); + return ( @@ -343,58 +386,36 @@ const WebhookActionConnectorFields: React.FunctionComponent - - + addHeader()} - > - - + label={i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.addHeaderButton', + { + defaultMessage: 'Add HTTP header', + } + )} + checked={hasHeaders} + onChange={() => viewHeaders()} + /> - + {headerControl} {hasHeaders ? ( - -
- -
-
- ) : null} - {Object.keys(headers || {}).map((key: string) => { - return ( - - - {key}: - - - {headers[key]} - - - removeHeader(key)} + + +
+ - - - ); - })} +
+
+ {headersList} +
+ ) : null}
); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index 6b4b892bdd4587..c73e4654843352 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -111,7 +111,7 @@ export const ActionConnectorForm = ({ error = errorRes; }); - message = "Created '{connectorName}'"; + message = 'Created'; } else { await updateActionConnector({ http, connector, id: connector.id }) .then(res => { @@ -120,7 +120,7 @@ export const ActionConnectorForm = ({ .catch(errorRes => { error = errorRes; }); - message = "Updated '{connectorName}'"; + message = 'Updated'; } if (error) { return { @@ -131,8 +131,9 @@ export const ActionConnectorForm = ({ i18n.translate( 'xpack.triggersActionsUI.sections.actionConnectorForm.updateSuccessNotificationText', { - defaultMessage: message, + defaultMessage: "'{message}' '{connectorName}", values: { + message, connectorName: savedConnector ? savedConnector.name : '', }, } @@ -151,7 +152,7 @@ export const ActionConnectorForm = ({ label={ } isInvalid={errors.name.length > 0 && connector.name !== undefined} @@ -161,6 +162,7 @@ export const ActionConnectorForm = ({ fullWidth isInvalid={errors.name.length > 0 && connector.name !== undefined} name="name" + placeholder="untitled" data-test-subj="nameInput" value={connector.name || ''} onChange={e => { From 5f776323217ffeb437db737e7bd3ac06f6b92896 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Tue, 7 Jan 2020 20:16:31 -0800 Subject: [PATCH 271/297] Fixed build --- .../components/builtin_action_types/webhook.test.tsx | 7 ++----- .../components/builtin_action_types/webhook.tsx | 3 +-- .../action_connector_form/action_connector_form.tsx | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx index 633aca40907500..b290a7381bf4ce 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx @@ -120,14 +120,11 @@ describe('WebhookActionConnectorFields renders', () => { editActionSecrets={() => {}} /> ); - expect(wrapper.find('[data-test-subj="webhookAddHeaderButton"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="webhookViewHeadersButton"]').length > 0).toBeTruthy(); wrapper - .find('[data-test-subj="webhookAddHeaderButton"]') + .find('[data-test-subj="webhookViewHeadersButton"]') .first() .simulate('click'); - expect(wrapper.find('[data-test-subj="webhookHeadersKeyInput"]').length > 0).toBeTruthy(); - expect(wrapper.find('[data-test-subj="webhookHeaderText"]').length > 0).toBeTruthy(); - expect(wrapper.find('[data-test-subj="webhookHeadersValueInput"]').length > 0).toBeTruthy(); expect(wrapper.find('[data-test-subj="webhookMethodSelect"]').length > 0).toBeTruthy(); expect(wrapper.find('[data-test-subj="webhookUrlText"]').length > 0).toBeTruthy(); expect(wrapper.find('[data-test-subj="webhookUserInput"]').length > 0).toBeTruthy(); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx index 6564c130fadab2..718ac10cbe195a 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx @@ -14,7 +14,6 @@ import { EuiFlexGroup, EuiFlexItem, EuiSpacer, - EuiButton, EuiButtonIcon, EuiText, EuiTitle, @@ -388,7 +387,7 @@ const WebhookActionConnectorFields: React.FunctionComponent Date: Wed, 8 Jan 2020 07:23:38 -0800 Subject: [PATCH 272/297] Fix labels issue --- .../components/builtin_action_types/webhook.test.tsx | 4 ++-- .../application/components/builtin_action_types/webhook.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx index b290a7381bf4ce..339b347fc925fe 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx @@ -120,9 +120,9 @@ describe('WebhookActionConnectorFields renders', () => { editActionSecrets={() => {}} /> ); - expect(wrapper.find('[data-test-subj="webhookViewHeadersButton"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="webhookViewHeadersSwitch"]').length > 0).toBeTruthy(); wrapper - .find('[data-test-subj="webhookViewHeadersButton"]') + .find('[data-test-subj="webhookViewHeadersSwitch"]') .first() .simulate('click'); expect(wrapper.find('[data-test-subj="webhookMethodSelect"]').length > 0).toBeTruthy(); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx index 718ac10cbe195a..6bbba0a55d3a8a 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx @@ -387,9 +387,9 @@ const WebhookActionConnectorFields: React.FunctionComponent Date: Wed, 8 Jan 2020 12:58:08 -0500 Subject: [PATCH 273/297] Fix spacing and form row alignment --- .../components/builtin_action_types/email.tsx | 86 ++++++++++--------- .../builtin_action_types/webhook.tsx | 25 +++--- .../action_connector_form.tsx | 4 +- .../alerts_list/components/alerts_list.tsx | 4 +- 4 files changed, 64 insertions(+), 55 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx index 1a75ebcb11a7e9..677b15fe022771 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx @@ -181,34 +181,38 @@ const EmailActionConnectorFields: React.FunctionComponent - 0 && from !== undefined} - label={i18n.translate( - 'xpack.triggersActionsUI.sections.builtinActionTypes.emailAction.fromTextFieldLabel', - { - defaultMessage: 'Sender', - } - )} - > - 0 && from !== undefined} - name="from" - value={from || ''} - data-test-subj="emailFromInput" - onChange={e => { - editActionConfig('from', e.target.value); - }} - onBlur={() => { - if (!from) { - editActionConfig('from', ''); - } - }} - /> - + + + 0 && from !== undefined} + label={i18n.translate( + 'xpack.triggersActionsUI.sections.builtinActionTypes.emailAction.fromTextFieldLabel', + { + defaultMessage: 'Sender', + } + )} + > + 0 && from !== undefined} + name="from" + value={from || ''} + data-test-subj="emailFromInput" + onChange={e => { + editActionConfig('from', e.target.value); + }} + onBlur={() => { + if (!from) { + editActionConfig('from', ''); + } + }} + /> + + + - { - editActionConfig('secure', e.target.checked); - }} - /> + + { + editActionConfig('secure', e.target.checked); + }} + /> + diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx index 718ac10cbe195a..a97c08c70f6b60 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx @@ -175,7 +175,7 @@ const WebhookActionConnectorFields: React.FunctionComponent + - addHeader()} - > - - + + addHeader()} + > + + + ); @@ -255,6 +257,7 @@ const WebhookActionConnectorFields: React.FunctionComponent removeHeader(key)} /> diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index 0374c60a34adfb..e4ded573780453 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -162,7 +162,7 @@ export const ActionConnectorForm = ({ fullWidth isInvalid={errors.name.length > 0 && connector.name !== undefined} name="name" - placeholder="untitled" + placeholder="Untitled" data-test-subj="nameInput" value={connector.name || ''} onChange={e => { @@ -175,7 +175,7 @@ export const ActionConnectorForm = ({ }} /> - + {FieldsComponent !== null ? ( { )} - } From b77fe1f3f1e80ae3f5cbbb93b75b904fefe08734 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Wed, 8 Jan 2020 13:17:22 -0800 Subject: [PATCH 274/297] Fixed failing type check --- .../sections/alerts_list/components/alerts_list.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx index 83f9ed83ddc5a8..64f06521c0f9d9 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/alerts_list.tsx @@ -10,7 +10,7 @@ import React, { Fragment, useEffect, useState } from 'react'; import { EuiBasicTable, EuiButton, - EuiFieldSearch, + EuiFieldText, EuiFlexGroup, EuiFlexItem, EuiIcon, @@ -251,7 +251,7 @@ export const AlertsList: React.FunctionComponent = () => { )} - } From 5acaa1af6efea72bed706ea8817c134f7f4833bd Mon Sep 17 00:00:00 2001 From: Dave Snider Date: Fri, 6 Dec 2019 12:47:07 -0800 Subject: [PATCH 275/297] put ownfocus on popover in actions list --- .../sections/alerts_list/components/collapsed_item_actions.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx index 718898c2d857f9..f063ab4f7cde3c 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/alerts_list/components/collapsed_item_actions.tsx @@ -65,6 +65,7 @@ export const CollapsedItemActions: React.FunctionComponent = ({ button={button} isOpen={isPopoverOpen} closePopover={() => setIsPopoverOpen(false)} + ownFocus data-test-subj="collapsedItemActions" > From 3b9fdc69ac74db8c708d68b959ccd8d21135f42d Mon Sep 17 00:00:00 2001 From: Dave Snider Date: Thu, 9 Jan 2020 13:02:24 -0800 Subject: [PATCH 276/297] fix spacing and flex --- .../components/builtin_action_types/email.tsx | 98 ++++++++++--------- .../action_connector_form.tsx | 2 +- 2 files changed, 53 insertions(+), 47 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx index 677b15fe022771..663f7dc59b627e 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx @@ -246,52 +246,58 @@ const EmailActionConnectorFields: React.FunctionComponent - 0 && port !== undefined} - label={i18n.translate( - 'xpack.triggersActionsUI.sections.builtinActionTypes.emailAction.portTextFieldLabel', - { - defaultMessage: 'Port', - } - )} - > - 0 && port !== undefined} - fullWidth - name="port" - value={port || ''} - data-test-subj="emailPortInput" - onChange={e => { - editActionConfig('port', parseInt(e.target.value, 10)); - }} - onBlur={() => { - if (!port) { - editActionConfig('port', ''); - } - }} - /> - - - - - { - editActionConfig('secure', e.target.checked); - }} - /> - + + + 0 && port !== undefined} + label={i18n.translate( + 'xpack.triggersActionsUI.sections.builtinActionTypes.emailAction.portTextFieldLabel', + { + defaultMessage: 'Port', + } + )} + > + 0 && port !== undefined} + fullWidth + name="port" + value={port || ''} + data-test-subj="emailPortInput" + onChange={e => { + editActionConfig('port', parseInt(e.target.value, 10)); + }} + onBlur={() => { + if (!port) { + editActionConfig('port', ''); + } + }} + /> + + + + + + { + editActionConfig('secure', e.target.checked); + }} + /> + + + + diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx index e4ded573780453..682c1fbb54b67e 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/action_connector_form/action_connector_form.tsx @@ -175,7 +175,7 @@ export const ActionConnectorForm = ({ }} /> - + {FieldsComponent !== null ? ( Date: Thu, 9 Jan 2020 13:09:05 -0800 Subject: [PATCH 277/297] fix color on conectors list --- .../components/actions_connectors_list.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index 0943924623f0fd..3d01688e57bb91 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -199,6 +199,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { ), type: 'icon', icon: 'trash', + color: 'danger', onClick: (item: ActionConnectorTableItem) => setConnectorsToDelete([item.id]), }, ], From 45c4349891bec912ca6dd61c432c7337b91b2eb9 Mon Sep 17 00:00:00 2001 From: Dave Snider Date: Thu, 9 Jan 2020 13:43:07 -0800 Subject: [PATCH 278/297] clean up webhook headers form --- .../builtin_action_types/webhook.tsx | 164 ++++++++++-------- 1 file changed, 90 insertions(+), 74 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx index 2d3f3f089d9193..6738ae4965aaff 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx @@ -15,7 +15,9 @@ import { EuiFlexItem, EuiSpacer, EuiButtonIcon, - EuiText, + EuiDescriptionList, + EuiDescriptionListDescription, + EuiDescriptionListTitle, EuiTitle, EuiCodeEditor, EuiSwitch, @@ -175,78 +177,89 @@ const WebhookActionConnectorFields: React.FunctionComponent - - - + +
+ +
+
+ + + + { - setHeaderKey(e.target.value); - }} - /> - - - - - + { + setHeaderKey(e.target.value); + }} + /> + + + + { - setHeaderValue(e.target.value); - }} - /> - - - - - addHeader()} + label={i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.webhookAction.valueTextFieldLabel', + { + defaultMessage: 'Value', + } + )} > - { + setHeaderValue(e.target.value); + }} /> - - - - +
+
+ + + addHeader()} + > + + + + +
+ ); } const headersList = Object.keys(headers || {}).map((key: string) => { return ( - + removeHeader(key)} /> - {key}: - - - {headers[key]} + + {key} + {headers[key]} + ); @@ -402,23 +415,26 @@ const WebhookActionConnectorFields: React.FunctionComponent - {headerControl} - - - {hasHeaders ? ( +
+ {Object.keys(headers || {}).length > 0 ? ( - + +
+ {headersList}
) : null} - + + {headerControl} + +
); }; From 9f9a178f374b8aba5fab5f8b7c46827ed30ed522 Mon Sep 17 00:00:00 2001 From: Dave Snider Date: Thu, 9 Jan 2020 13:45:22 -0800 Subject: [PATCH 279/297] fix logic check for headers --- .../application/components/builtin_action_types/webhook.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx index 6738ae4965aaff..329f15140e2855 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx @@ -416,7 +416,7 @@ const WebhookActionConnectorFields: React.FunctionComponent
- {Object.keys(headers || {}).length > 0 ? ( + {hasHeaders && Object.keys(headers || {}).length > 0 ? ( From e4242857e417de48e9f4e162c94df567ee5d626e Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Thu, 9 Jan 2020 17:08:54 -0800 Subject: [PATCH 280/297] Made changes due to review comments --- .github/CODEOWNERS | 6 +-- .../components/builtin_action_types/email.tsx | 7 ++- .../builtin_action_types/pagerduty.test.tsx | 2 +- .../builtin_action_types/server_log.test.tsx | 45 ++++++++++++++++- .../builtin_action_types/server_log.tsx | 21 ++++++-- .../builtin_action_types/slack.test.tsx | 24 +++++---- .../components/builtin_action_types/slack.tsx | 14 ++++++ .../builtin_action_types/webhook.test.tsx | 16 +++++- .../builtin_action_types/webhook.tsx | 50 ++++++++++++------- 9 files changed, 142 insertions(+), 43 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 9e58a611d8c9e6..99241c5e2dda34 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -131,9 +131,9 @@ /x-pack/test/alerting_api_integration @elastic/kibana-alerting-services /x-pack/test/plugin_api_integration/plugins/task_manager @elastic/kibana-alerting-services /x-pack/test/plugin_api_integration/test_suites/task_manager @elastic/kibana-alerting-services -/x-pack/legacy/plugins/triggers_actions_ui @elastic/kibana-alerting-services -/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui @elastic/kibana-alerting-services -/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts @elastic/kibana-alerting-services +/x-pack/legacy/plugins/triggers_actions_ui/ @elastic/kibana-alerting-services +/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/ @elastic/kibana-alerting-services +/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/ @elastic/kibana-alerting-services # Design **/*.scss @elastic/kibana-design diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx index 663f7dc59b627e..a6750ccf96debc 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/email.tsx @@ -25,7 +25,7 @@ import { } from '../../../types'; export function getActionType(): ActionTypeModel { - const mailformat = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/; + const mailformat = /^[^@\s]+@[^@\s]+$/; return { id: '.email', iconClass: 'email', @@ -56,7 +56,7 @@ export function getActionType(): ActionTypeModel { ) ); } - if (action.config.from && !action.config.from.match(mailformat)) { + if (action.config.from && !action.config.from.trim().match(mailformat)) { errors.from.push( i18n.translate( 'xpack.triggersActionsUI.components.builtinActionTypes.error.formatFromText', @@ -231,7 +231,6 @@ const EmailActionConnectorFields: React.FunctionComponent 0 && host !== undefined} name="host" - placeholder="localhost" value={host || ''} data-test-subj="emailHostInput" onChange={e => { @@ -251,7 +250,7 @@ const EmailActionConnectorFields: React.FunctionComponent 0 && port !== undefined} label={i18n.translate( diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.test.tsx index 52bfa021125cc0..582315c95812a4 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/pagerduty.test.tsx @@ -48,7 +48,7 @@ describe('pagerduty connector validation', () => { }, }); - delete actionConnector.config.test; + delete actionConnector.config.apiUrl; actionConnector.secrets.routingKey = 'test1'; expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ errors: { diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.test.tsx index 94898da7e46e46..b79be4eef523bc 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.test.tsx @@ -52,7 +52,7 @@ describe('action params validation', () => { }; expect(actionTypeModel.validateParams(actionParams)).toEqual({ - errors: {}, + errors: { message: [] }, }); }); }); @@ -71,7 +71,7 @@ describe('ServerLogParamsFields renders', () => { const wrapper = mountWithIntl( {}} index={0} hasErrors={false} @@ -86,4 +86,45 @@ describe('ServerLogParamsFields renders', () => { ).toStrictEqual('trace'); expect(wrapper.find('[data-test-subj="loggingMessageInput"]').length > 0).toBeTruthy(); }); + + test('level param field is rendered with default value if not selected', () => { + expect(actionTypeModel.actionParamsFields).not.toBeNull(); + if (!actionTypeModel.actionParamsFields) { + return; + } + const ParamsFields = actionTypeModel.actionParamsFields; + const actionParams = { + message: 'test message', + level: 'info', + }; + const wrapper = mountWithIntl( + {}} + index={0} + hasErrors={false} + /> + ); + expect(wrapper.find('[data-test-subj="loggingLevelSelect"]').length > 0).toBeTruthy(); + expect( + wrapper + .find('[data-test-subj="loggingLevelSelect"]') + .first() + .prop('value') + ).toStrictEqual('info'); + expect(wrapper.find('[data-test-subj="loggingMessageInput"]').length > 0).toBeTruthy(); + }); + + test('params validation fails when message is not valid', () => { + const actionParams = { + message: '', + }; + + expect(actionTypeModel.validateParams(actionParams)).toEqual({ + errors: { + message: ['Message is required.'], + }, + }); + }); }); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.tsx index da9271bb82a9bb..885061aa819243 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/server_log.tsx @@ -23,6 +23,20 @@ export function getActionType(): ActionTypeModel { }, validateParams: (actionParams: any): ValidationResult => { const validationResult = { errors: {} }; + const errors = { + message: new Array(), + }; + validationResult.errors = errors; + if (!actionParams.message || actionParams.message.length === 0) { + errors.message.push( + i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredServerLogMessageText', + { + defaultMessage: 'Message is required.', + } + ) + ); + } return validationResult; }, actionConnectorFields: null, @@ -47,13 +61,14 @@ export const ServerLogParamsFields: React.FunctionComponent = { value: 'fatal', text: 'Fatal' }, ]; + // Set default value 'info' for level param + editAction('level', 'info', index); + return ( = > { editAction('level', e.target.value, index); }} diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.test.tsx index f41d25808693f7..36beea4d2f2be2 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.test.tsx @@ -71,15 +71,7 @@ describe('slack action params validation', () => { }; expect(actionTypeModel.validateParams(actionParams)).toEqual({ - errors: {}, - }); - }); - - test('if action params validation not fails when action params is empty', () => { - const actionParams = {}; - - expect(actionTypeModel.validateParams(actionParams)).toEqual({ - errors: {}, + errors: { message: [] }, }); }); }); @@ -131,7 +123,7 @@ describe('SlackParamsFields renders', () => { const wrapper = mountWithIntl( {}} index={0} hasErrors={false} @@ -145,4 +137,16 @@ describe('SlackParamsFields renders', () => { .prop('value') ).toStrictEqual('test message'); }); + + test('params validation fails when message is not valid', () => { + const actionParams = { + message: '', + }; + + expect(actionTypeModel.validateParams(actionParams)).toEqual({ + errors: { + message: ['Message is required.'], + }, + }); + }); }); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx index 72f39a4a13a36c..0ae51725169bf1 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/slack.tsx @@ -53,6 +53,20 @@ export function getActionType(): ActionTypeModel { }, validateParams: (actionParams: any): ValidationResult => { const validationResult = { errors: {} }; + const errors = { + message: new Array(), + }; + validationResult.errors = errors; + if (!actionParams.message || actionParams.message.length === 0) { + errors.message.push( + i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredSlackMessageText', + { + defaultMessage: 'Message is required.', + } + ) + ); + } return validationResult; }, actionConnectorFields: SlackActionFields, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx index 339b347fc925fe..cd342f2e199693 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.test.tsx @@ -86,7 +86,7 @@ describe('webhook action params validation', () => { }; expect(actionTypeModel.validateParams(actionParams)).toEqual({ - errors: {}, + errors: { body: [] }, }); }); }); @@ -145,7 +145,7 @@ describe('WebhookParamsFields renders', () => { const wrapper = mountWithIntl( {}} index={0} hasErrors={false} @@ -159,4 +159,16 @@ describe('WebhookParamsFields renders', () => { .prop('value') ).toStrictEqual('test message'); }); + + test('params validation fails when body is not valid', () => { + const actionParams = { + body: '', + }; + + expect(actionTypeModel.validateParams(actionParams)).toEqual({ + errors: { + body: ['Body is required.'], + }, + }); + }); }); diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx index 329f15140e2855..70a9a6f3d75b3a 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/components/builtin_action_types/webhook.tsx @@ -97,6 +97,20 @@ export function getActionType(): ActionTypeModel { }, validateParams: (actionParams: any): ValidationResult => { const validationResult = { errors: {} }; + const errors = { + body: new Array(), + }; + validationResult.errors = errors; + if (!actionParams.body || actionParams.body.length === 0) { + errors.body.push( + i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.error.requiredWebhookBodyText', + { + defaultMessage: 'Body is required.', + } + ) + ); + } return validationResult; }, actionConnectorFields: WebhookActionConnectorFields, @@ -110,8 +124,8 @@ const WebhookActionConnectorFields: React.FunctionComponent { - const [headerKey, setHeaderKey] = useState(''); - const [headerValue, setHeaderValue] = useState(''); + const [httpHeaderKey, setHttpHeaderKey] = useState(''); + const [httpHeaderValue, setHttpHeaderValue] = useState(''); const [hasHeaders, setHasHeaders] = useState(false); const { user, password } = action.secrets; @@ -123,7 +137,7 @@ const WebhookActionConnectorFields: React.FunctionComponent(), valueHeader: new Array(), }; - if (!headerKey && headerValue) { + if (!httpHeaderKey && httpHeaderValue) { headerErrors.keyHeader.push( i18n.translate( 'xpack.triggersActionsUI.sections.addAction.webhookAction.error.requiredHeaderKeyText', @@ -133,7 +147,7 @@ const WebhookActionConnectorFields: React.FunctionComponent 0 || headerErrors.valueHeader.length > 0; function addHeader() { - if (headers && !!Object.keys(headers).find(key => key === headerKey)) { + if (headers && !!Object.keys(headers).find(key => key === httpHeaderKey)) { return; } const updatedHeaders = headers - ? { ...headers, [headerKey]: headerValue } - : { [headerKey]: headerValue }; + ? { ...headers, [httpHeaderKey]: httpHeaderValue } + : { [httpHeaderKey]: httpHeaderValue }; editActionConfig('headers', updatedHeaders); - setHeaderKey(''); - setHeaderValue(''); + setHttpHeaderKey(''); + setHttpHeaderValue(''); } function viewHeaders() { @@ -193,7 +207,7 @@ const WebhookActionConnectorFields: React.FunctionComponent { - setHeaderKey(e.target.value); + setHttpHeaderKey(e.target.value); }} /> @@ -218,7 +232,7 @@ const WebhookActionConnectorFields: React.FunctionComponent { - setHeaderValue(e.target.value); + setHttpHeaderValue(e.target.value); }} /> @@ -241,7 +255,7 @@ const WebhookActionConnectorFields: React.FunctionComponent addHeader()} > From dd816acec17c4eb2b28754c1536bd7ce8fd9f81b Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 10 Jan 2020 08:34:20 -0800 Subject: [PATCH 281/297] Fixed delete connector test --- .../apps/triggers_actions_ui/connectors.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts index 16c5516291cf8e..0e68ec7ad3c0ad 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts @@ -114,7 +114,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); // Flaky, will be fixed with https://github.com/elastic/kibana/issues/53956 - it.skip('should delete a connector', async () => { + it('should delete a connector', async () => { const connectorName = generateUniqueKey(); await pageObjects.triggersActionsUI.clickCreateConnectorButton(); @@ -141,6 +141,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const deleteConnectorBtn = await testSubjects.find('deleteConnector'); await deleteConnectorBtn.click(); + await testSubjects.existOrFail('deleteConnectorsConfirmation'); + await testSubjects.click('deleteConnectorsConfirmation > confirmModalConfirmButton'); + await testSubjects.missingOrFail('deleteConnectorsConfirmation', { timeout: 30 * 1000 }); + await pageObjects.header.waitUntilLoadingHasFinished(); await pageObjects.triggersActionsUI.searchConnectors(connectorName); From 982e84089d26ee3a5d4d85e492eb8093a99c6555 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 10 Jan 2020 09:03:36 -0800 Subject: [PATCH 282/297] Fixed all flaky test for delete connectors 53956 --- .../components/actions_connectors_list.tsx | 1 + .../apps/triggers_actions_ui/connectors.ts | 73 ++++++++++--------- 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx index 3d01688e57bb91..1990ffefdf84e2 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/application/sections/actions_connectors_list/components/actions_connectors_list.tsx @@ -294,6 +294,7 @@ export const ActionsConnectorsList: React.FunctionComponent = () => { const emptyPrompt = ( diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts index 0e68ec7ad3c0ad..7e905972034c14 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts @@ -113,26 +113,28 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { ]); }); - // Flaky, will be fixed with https://github.com/elastic/kibana/issues/53956 it('should delete a connector', async () => { + async function createConnector(connectorName: string) { + await pageObjects.triggersActionsUI.clickCreateConnectorButton(); + + const serverLogCard = await testSubjects.find('.server-log-card'); + await serverLogCard.click(); + + const nameInput = await testSubjects.find('nameInput'); + await nameInput.click(); + await nameInput.clearValue(); + await nameInput.type(connectorName); + + const saveButton = await find.byCssSelector( + '[data-test-subj="saveActionButton"]:not(disabled)' + ); + await saveButton.click(); + await pageObjects.common.closeToast(); + } const connectorName = generateUniqueKey(); + await createConnector(connectorName); - await pageObjects.triggersActionsUI.clickCreateConnectorButton(); - - const serverLogCard = await testSubjects.find('.server-log-card'); - await serverLogCard.click(); - - const nameInput = await testSubjects.find('nameInput'); - await nameInput.click(); - await nameInput.clearValue(); - await nameInput.type(connectorName); - - const saveButton = await find.byCssSelector( - '[data-test-subj="saveActionButton"]:not(disabled)' - ); - await saveButton.click(); - - await pageObjects.common.closeToast(); + await createConnector(generateUniqueKey()); await pageObjects.triggersActionsUI.searchConnectors(connectorName); @@ -144,7 +146,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.existOrFail('deleteConnectorsConfirmation'); await testSubjects.click('deleteConnectorsConfirmation > confirmModalConfirmButton'); await testSubjects.missingOrFail('deleteConnectorsConfirmation', { timeout: 30 * 1000 }); - await pageObjects.header.waitUntilLoadingHasFinished(); await pageObjects.triggersActionsUI.searchConnectors(connectorName); @@ -152,26 +153,29 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(searchResultsAfterDelete.length).to.eql(0); }); - // Flaky, will be fixed with https://github.com/elastic/kibana/issues/53956 - it.skip('should bulk delete connectors', async () => { - const connectorName = generateUniqueKey(); + it('should bulk delete connectors', async () => { + async function createConnector(connectorName: string) { + await pageObjects.triggersActionsUI.clickCreateConnectorButton(); - await pageObjects.triggersActionsUI.clickCreateConnectorButton(); + const serverLogCard = await testSubjects.find('.server-log-card'); + await serverLogCard.click(); - const serverLogCard = await testSubjects.find('.server-log-card'); - await serverLogCard.click(); + const nameInput = await testSubjects.find('nameInput'); + await nameInput.click(); + await nameInput.clearValue(); + await nameInput.type(connectorName); - const nameInput = await testSubjects.find('nameInput'); - await nameInput.click(); - await nameInput.clearValue(); - await nameInput.type(connectorName); + const saveButton = await find.byCssSelector( + '[data-test-subj="saveActionButton"]:not(disabled)' + ); + await saveButton.click(); + await pageObjects.common.closeToast(); + } - const saveButton = await find.byCssSelector( - '[data-test-subj="saveActionButton"]:not(disabled)' - ); - await saveButton.click(); + const connectorName = generateUniqueKey(); + await createConnector(connectorName); - await pageObjects.common.closeToast(); + await createConnector(generateUniqueKey()); await pageObjects.triggersActionsUI.searchConnectors(connectorName); @@ -185,6 +189,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const bulkDeleteBtn = await testSubjects.find('bulkDelete'); await bulkDeleteBtn.click(); + await testSubjects.existOrFail('deleteConnectorsConfirmation'); + await testSubjects.click('deleteConnectorsConfirmation > confirmModalConfirmButton'); + await testSubjects.missingOrFail('deleteConnectorsConfirmation', { timeout: 30 * 1000 }); await pageObjects.triggersActionsUI.searchConnectors(connectorName); From 440f5de1e7fef02ced4a8c91eceba74e9c56c187 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 10 Jan 2020 12:21:36 -0800 Subject: [PATCH 283/297] Fixed type check due to NP changes --- x-pack/legacy/plugins/triggers_actions_ui/public/legacy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/public/legacy.ts b/x-pack/legacy/plugins/triggers_actions_ui/public/legacy.ts index f6f9a33bd13665..bae91040812671 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/public/legacy.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/public/legacy.ts @@ -48,6 +48,7 @@ routes.when(`${BASE_PATH}:section?/:subsection?/:view?/:id?`, { app.mount(npStart as any, { element: elem, appBasePath: BASE_PATH, + onAppLeave: () => undefined, }); }, }, From 61751391dd4695d4055a76646f6245ac7916c6b6 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 10 Jan 2020 14:44:14 -0800 Subject: [PATCH 284/297] Disable plugin by default --- x-pack/legacy/plugins/triggers_actions_ui/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/index.ts index aa2324d61c7c42..012415e9ebd3c2 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/index.ts @@ -23,7 +23,7 @@ export function triggersActionsUI(kibana: any) { config(Joi: Root) { return Joi.object() .keys({ - enabled: Joi.boolean().default(true), + enabled: Joi.boolean().default(false), createAlertUiEnabled: Joi.boolean().default(false), }) .default(); From fd464ef7b6192f1f4a8d9a1ab3e52f558c812ae0 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 10 Jan 2020 16:40:54 -0800 Subject: [PATCH 285/297] Added configuration props for functional tests to enable triggers and actions ui --- x-pack/test/functional_with_es_ssl/config.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/test/functional_with_es_ssl/config.ts b/x-pack/test/functional_with_es_ssl/config.ts index d22043dfa7e3a1..2a687a2d87cd6e 100644 --- a/x-pack/test/functional_with_es_ssl/config.ts +++ b/x-pack/test/functional_with_es_ssl/config.ts @@ -47,6 +47,8 @@ export default async function({ readConfigFile }: FtrConfigProviderContext) { `--elasticsearch.hosts=https://${servers.elasticsearch.hostname}:${servers.elasticsearch.port}`, `--elasticsearch.ssl.certificateAuthorities=${CA_CERT_PATH}`, `--plugin-path=${join(__dirname, 'fixtures', 'plugins', 'alerts')}`, + '--xpack.triggers_actions_ui.enabled=true', + '--xpack.triggers_actions_ui.createAlertUiEnabled=true', ], }, }; From bc68537c1ae5e29a8738291a451545123e759275 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 10 Jan 2020 19:03:14 -0800 Subject: [PATCH 286/297] removed timeout from test --- .../apps/triggers_actions_ui/connectors.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts index 7e905972034c14..7b60685225ac6c 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors.ts @@ -145,7 +145,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await deleteConnectorBtn.click(); await testSubjects.existOrFail('deleteConnectorsConfirmation'); await testSubjects.click('deleteConnectorsConfirmation > confirmModalConfirmButton'); - await testSubjects.missingOrFail('deleteConnectorsConfirmation', { timeout: 30 * 1000 }); + await testSubjects.missingOrFail('deleteConnectorsConfirmation'); await pageObjects.triggersActionsUI.searchConnectors(connectorName); @@ -191,7 +191,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await bulkDeleteBtn.click(); await testSubjects.existOrFail('deleteConnectorsConfirmation'); await testSubjects.click('deleteConnectorsConfirmation > confirmModalConfirmButton'); - await testSubjects.missingOrFail('deleteConnectorsConfirmation', { timeout: 30 * 1000 }); + await testSubjects.missingOrFail('deleteConnectorsConfirmation'); await pageObjects.triggersActionsUI.searchConnectors(connectorName); From aa3cadfd1f285e37b0c853c02dc2534be46134bb Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 10 Jan 2020 20:34:59 -0800 Subject: [PATCH 287/297] added enable triggers and actions to functional/config.js --- x-pack/test/functional/config.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/test/functional/config.js b/x-pack/test/functional/config.js index 17235c61c7d8ce..787d7a8e9df503 100644 --- a/x-pack/test/functional/config.js +++ b/x-pack/test/functional/config.js @@ -88,6 +88,8 @@ export default async function({ readConfigFile }) { '--telemetry.banner=false', '--timelion.ui.enabled=true', '--xpack.endpoint.enabled=true', + '--xpack.triggers_actions_ui.enabled=true', + '--xpack.triggers_actions_ui.createAlertUiEnabled=true', ], }, uiSettings: { From efc01b2c796e66c6ad71f35c8558ec06ce6e6671 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Fri, 10 Jan 2020 21:16:42 -0800 Subject: [PATCH 288/297] fix the build --- x-pack/legacy/plugins/triggers_actions_ui/index.ts | 2 +- x-pack/test/functional/config.js | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/index.ts index 012415e9ebd3c2..aa2324d61c7c42 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/index.ts @@ -23,7 +23,7 @@ export function triggersActionsUI(kibana: any) { config(Joi: Root) { return Joi.object() .keys({ - enabled: Joi.boolean().default(false), + enabled: Joi.boolean().default(true), createAlertUiEnabled: Joi.boolean().default(false), }) .default(); diff --git a/x-pack/test/functional/config.js b/x-pack/test/functional/config.js index 787d7a8e9df503..17235c61c7d8ce 100644 --- a/x-pack/test/functional/config.js +++ b/x-pack/test/functional/config.js @@ -88,8 +88,6 @@ export default async function({ readConfigFile }) { '--telemetry.banner=false', '--timelion.ui.enabled=true', '--xpack.endpoint.enabled=true', - '--xpack.triggers_actions_ui.enabled=true', - '--xpack.triggers_actions_ui.createAlertUiEnabled=true', ], }, uiSettings: { From a78ebcdfc28b44c4b68263d9daa92136108dc40a Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Sat, 11 Jan 2020 20:14:31 -0800 Subject: [PATCH 289/297] Changed ci group and disabled plugin --- x-pack/legacy/plugins/triggers_actions_ui/index.ts | 2 +- .../functional_with_es_ssl/apps/triggers_actions_ui/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/index.ts index aa2324d61c7c42..012415e9ebd3c2 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/index.ts @@ -23,7 +23,7 @@ export function triggersActionsUI(kibana: any) { config(Joi: Root) { return Joi.object() .keys({ - enabled: Joi.boolean().default(true), + enabled: Joi.boolean().default(false), createAlertUiEnabled: Joi.boolean().default(false), }) .default(); diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts index c76f477c8cfbef..a4a372d81992c3 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default ({ loadTestFile, getService }: FtrProviderContext) => { describe('Actions and Triggers app', function() { - this.tags('ciGroup3'); + this.tags(['ciGroup2', 'skipFirefox']); loadTestFile(require.resolve('./home_page')); loadTestFile(require.resolve('./connectors')); loadTestFile(require.resolve('./alerts')); From 7352c2091a7e7a1e99081f033fe7ce2f3f654da6 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Sat, 11 Jan 2020 21:34:15 -0800 Subject: [PATCH 290/297] changed config setting to root --- x-pack/test/functional/config.js | 2 ++ .../functional_with_es_ssl/apps/triggers_actions_ui/index.ts | 2 +- x-pack/test/functional_with_es_ssl/config.ts | 2 -- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/test/functional/config.js b/x-pack/test/functional/config.js index 664bfdf8d2a746..c156c5b24c51a3 100644 --- a/x-pack/test/functional/config.js +++ b/x-pack/test/functional/config.js @@ -88,6 +88,8 @@ export default async function({ readConfigFile }) { '--telemetry.banner=false', '--timelion.ui.enabled=true', '--xpack.endpoint.enabled=true', + '--xpack.triggers_actions_ui.enabled=true', + '--xpack.triggers_actions_ui.createAlertUiEnabled=true', ], }, uiSettings: { diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts index a4a372d81992c3..8f3f584bdbc56e 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default ({ loadTestFile, getService }: FtrProviderContext) => { describe('Actions and Triggers app', function() { - this.tags(['ciGroup2', 'skipFirefox']); + this.tags(['ciGroup3', 'skipFirefox']); loadTestFile(require.resolve('./home_page')); loadTestFile(require.resolve('./connectors')); loadTestFile(require.resolve('./alerts')); diff --git a/x-pack/test/functional_with_es_ssl/config.ts b/x-pack/test/functional_with_es_ssl/config.ts index 2a687a2d87cd6e..d22043dfa7e3a1 100644 --- a/x-pack/test/functional_with_es_ssl/config.ts +++ b/x-pack/test/functional_with_es_ssl/config.ts @@ -47,8 +47,6 @@ export default async function({ readConfigFile }: FtrConfigProviderContext) { `--elasticsearch.hosts=https://${servers.elasticsearch.hostname}:${servers.elasticsearch.port}`, `--elasticsearch.ssl.certificateAuthorities=${CA_CERT_PATH}`, `--plugin-path=${join(__dirname, 'fixtures', 'plugins', 'alerts')}`, - '--xpack.triggers_actions_ui.enabled=true', - '--xpack.triggers_actions_ui.createAlertUiEnabled=true', ], }, }; From 6f3066121464fb7f605175d5dc87f275197d5dc9 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Sun, 12 Jan 2020 10:40:26 -0800 Subject: [PATCH 291/297] Changed disable approach --- x-pack/legacy/plugins/triggers_actions_ui/index.ts | 9 ++------- .../triggers_actions_ui/np_ready/public/plugin.ts | 6 ++++++ x-pack/test/functional/config.js | 2 -- x-pack/test/functional_with_es_ssl/config.ts | 2 ++ 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/x-pack/legacy/plugins/triggers_actions_ui/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/index.ts index 012415e9ebd3c2..d0667a217a2120 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/index.ts @@ -14,12 +14,6 @@ export function triggersActionsUI(kibana: any) { configPrefix: 'xpack.triggers_actions_ui', publicDir: resolve(__dirname, 'public'), require: ['kibana'], - isEnabled(config: Legacy.KibanaConfig) { - return ( - config.get('xpack.triggers_actions_ui.enabled') && - (config.get('xpack.actions.enabled') || config.get('xpack.alerting.enabled')) - ); - }, config(Joi: Root) { return Joi.object() .keys({ @@ -29,13 +23,14 @@ export function triggersActionsUI(kibana: any) { .default(); }, uiExports: { - hacks: ['plugins/triggers_actions_ui/hacks/register'], + home: ['plugins/triggers_actions_ui/hacks/register'], managementSections: ['plugins/triggers_actions_ui/legacy'], styleSheetPaths: resolve(__dirname, 'public/index.scss'), injectDefaultVars(server: Legacy.Server) { const serverConfig = server.config(); return { createAlertUiEnabled: serverConfig.get('xpack.triggers_actions_ui.createAlertUiEnabled'), + uiEnabled: serverConfig.get('xpack.triggers_actions_ui.enabled'), }; }, }, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts index 0b0f8a4ee67907..ebd23aa796bdbe 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts @@ -93,6 +93,12 @@ export class Plugin implements CorePlugin { } public start(core: CoreStart, { __LEGACY }: LegacyPlugins) { + const uiEnabled = core.injectedMetadata.getInjectedVar('uiEnabled'); + + if (uiEnabled === false) { + return; + } + const { capabilities } = __LEGACY; const canShowActions = hasShowActionsCapability(capabilities.get()); const canShowAlerts = hasShowAlertsCapability(capabilities.get()); diff --git a/x-pack/test/functional/config.js b/x-pack/test/functional/config.js index c156c5b24c51a3..664bfdf8d2a746 100644 --- a/x-pack/test/functional/config.js +++ b/x-pack/test/functional/config.js @@ -88,8 +88,6 @@ export default async function({ readConfigFile }) { '--telemetry.banner=false', '--timelion.ui.enabled=true', '--xpack.endpoint.enabled=true', - '--xpack.triggers_actions_ui.enabled=true', - '--xpack.triggers_actions_ui.createAlertUiEnabled=true', ], }, uiSettings: { diff --git a/x-pack/test/functional_with_es_ssl/config.ts b/x-pack/test/functional_with_es_ssl/config.ts index d22043dfa7e3a1..2a687a2d87cd6e 100644 --- a/x-pack/test/functional_with_es_ssl/config.ts +++ b/x-pack/test/functional_with_es_ssl/config.ts @@ -47,6 +47,8 @@ export default async function({ readConfigFile }: FtrConfigProviderContext) { `--elasticsearch.hosts=https://${servers.elasticsearch.hostname}:${servers.elasticsearch.port}`, `--elasticsearch.ssl.certificateAuthorities=${CA_CERT_PATH}`, `--plugin-path=${join(__dirname, 'fixtures', 'plugins', 'alerts')}`, + '--xpack.triggers_actions_ui.enabled=true', + '--xpack.triggers_actions_ui.createAlertUiEnabled=true', ], }, }; From be1e127866a040e83a64b8f208f396865027f2a2 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Sun, 12 Jan 2020 14:53:51 -0800 Subject: [PATCH 292/297] Experiment with index managment --- x-pack/legacy/plugins/index_management/index.ts | 12 +++++++++++- x-pack/legacy/plugins/triggers_actions_ui/index.ts | 7 ++++++- .../triggers_actions_ui/np_ready/public/plugin.ts | 6 ------ x-pack/test/functional/config.js | 1 + .../apps/triggers_actions_ui/home_page.ts | 4 +++- .../apps/triggers_actions_ui/index.ts | 2 +- x-pack/test/functional_with_es_ssl/config.ts | 2 ++ 7 files changed, 24 insertions(+), 10 deletions(-) diff --git a/x-pack/legacy/plugins/index_management/index.ts b/x-pack/legacy/plugins/index_management/index.ts index f2a543337199f4..df3e33b477edfa 100644 --- a/x-pack/legacy/plugins/index_management/index.ts +++ b/x-pack/legacy/plugins/index_management/index.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { Root } from 'joi'; import { resolve } from 'path'; import { i18n } from '@kbn/i18n'; import { Legacy } from 'kibana'; @@ -21,7 +22,16 @@ export function indexManagement(kibana: any) { configPrefix: 'xpack.index_management', publicDir: resolve(__dirname, 'public'), require: ['kibana', 'elasticsearch', 'xpack_main'], - + isEnabled(config: Legacy.KibanaConfig) { + return config.get('xpack.index_management.enabled'); + }, + config(Joi: Root) { + return Joi.object() + .keys({ + enabled: Joi.boolean().default(false), + }) + .default(); + }, uiExports: { styleSheetPaths: resolve(__dirname, 'public/index.scss'), managementSections: ['plugins/index_management'], diff --git a/x-pack/legacy/plugins/triggers_actions_ui/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/index.ts index d0667a217a2120..c6ac3649a14775 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/index.ts @@ -12,6 +12,12 @@ export function triggersActionsUI(kibana: any) { return new kibana.Plugin({ id: 'triggers_actions_ui', configPrefix: 'xpack.triggers_actions_ui', + isEnabled(config: Legacy.KibanaConfig) { + return ( + config.get('xpack.triggers_actions_ui.enabled') && + (config.get('xpack.actions.enabled') || config.get('xpack.alerting.enabled')) + ); + }, publicDir: resolve(__dirname, 'public'), require: ['kibana'], config(Joi: Root) { @@ -30,7 +36,6 @@ export function triggersActionsUI(kibana: any) { const serverConfig = server.config(); return { createAlertUiEnabled: serverConfig.get('xpack.triggers_actions_ui.createAlertUiEnabled'), - uiEnabled: serverConfig.get('xpack.triggers_actions_ui.enabled'), }; }, }, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts index ebd23aa796bdbe..0b0f8a4ee67907 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/np_ready/public/plugin.ts @@ -93,12 +93,6 @@ export class Plugin implements CorePlugin { } public start(core: CoreStart, { __LEGACY }: LegacyPlugins) { - const uiEnabled = core.injectedMetadata.getInjectedVar('uiEnabled'); - - if (uiEnabled === false) { - return; - } - const { capabilities } = __LEGACY; const canShowActions = hasShowActionsCapability(capabilities.get()); const canShowAlerts = hasShowAlertsCapability(capabilities.get()); diff --git a/x-pack/test/functional/config.js b/x-pack/test/functional/config.js index 664bfdf8d2a746..cea68cf0e33995 100644 --- a/x-pack/test/functional/config.js +++ b/x-pack/test/functional/config.js @@ -88,6 +88,7 @@ export default async function({ readConfigFile }) { '--telemetry.banner=false', '--timelion.ui.enabled=true', '--xpack.endpoint.enabled=true', + '--xpack.index_management.enabled=true', ], }, uiSettings: { diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts index 13f50a505b0b6f..2ba09559094917 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts @@ -15,7 +15,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('Home page', function() { before(async () => { - await pageObjects.common.navigateToApp('triggersActions'); + await browser.refresh(); + await pageObjects.header.awaitKibanaChrome(); + await pageObjects.common.navigateToActualUrl('kibana', 'management/kibana/triggersActions'); }); it('Loads the app', async () => { diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts index 8f3f584bdbc56e..3c03a3585f0b68 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default ({ loadTestFile, getService }: FtrProviderContext) => { describe('Actions and Triggers app', function() { - this.tags(['ciGroup3', 'skipFirefox']); + this.tags(['ciGroup4']); loadTestFile(require.resolve('./home_page')); loadTestFile(require.resolve('./connectors')); loadTestFile(require.resolve('./alerts')); diff --git a/x-pack/test/functional_with_es_ssl/config.ts b/x-pack/test/functional_with_es_ssl/config.ts index 2a687a2d87cd6e..1a9736b0b47736 100644 --- a/x-pack/test/functional_with_es_ssl/config.ts +++ b/x-pack/test/functional_with_es_ssl/config.ts @@ -47,6 +47,8 @@ export default async function({ readConfigFile }: FtrConfigProviderContext) { `--elasticsearch.hosts=https://${servers.elasticsearch.hostname}:${servers.elasticsearch.port}`, `--elasticsearch.ssl.certificateAuthorities=${CA_CERT_PATH}`, `--plugin-path=${join(__dirname, 'fixtures', 'plugins', 'alerts')}`, + '--xpack.actions.enabled=true', + '--xpack.alerting.enabled=true', '--xpack.triggers_actions_ui.enabled=true', '--xpack.triggers_actions_ui.createAlertUiEnabled=true', ], From 87165bea3841eb24b9b0cd3888fb684f178203c7 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Sun, 12 Jan 2020 19:42:32 -0800 Subject: [PATCH 293/297] Set back configuration settings for triggers and actions --- .../apps/triggers_actions_ui/home_page.ts | 4 +--- .../functional_with_es_ssl/apps/triggers_actions_ui/index.ts | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts index 2ba09559094917..13f50a505b0b6f 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts @@ -15,9 +15,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('Home page', function() { before(async () => { - await browser.refresh(); - await pageObjects.header.awaitKibanaChrome(); - await pageObjects.common.navigateToActualUrl('kibana', 'management/kibana/triggersActions'); + await pageObjects.common.navigateToApp('triggersActions'); }); it('Loads the app', async () => { diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts index 3c03a3585f0b68..c76f477c8cfbef 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/index.ts @@ -8,7 +8,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default ({ loadTestFile, getService }: FtrProviderContext) => { describe('Actions and Triggers app', function() { - this.tags(['ciGroup4']); + this.tags('ciGroup3'); loadTestFile(require.resolve('./home_page')); loadTestFile(require.resolve('./connectors')); loadTestFile(require.resolve('./alerts')); From 3b9d9b829a9a0207ce09784b6b8ef92c7fa6aa9e Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Sun, 12 Jan 2020 20:30:04 -0800 Subject: [PATCH 294/297] Enable plugins --- x-pack/legacy/plugins/index_management/index.ts | 2 +- x-pack/legacy/plugins/triggers_actions_ui/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/index_management/index.ts b/x-pack/legacy/plugins/index_management/index.ts index df3e33b477edfa..dce0afd1f80330 100644 --- a/x-pack/legacy/plugins/index_management/index.ts +++ b/x-pack/legacy/plugins/index_management/index.ts @@ -28,7 +28,7 @@ export function indexManagement(kibana: any) { config(Joi: Root) { return Joi.object() .keys({ - enabled: Joi.boolean().default(false), + enabled: Joi.boolean().default(true), }) .default(); }, diff --git a/x-pack/legacy/plugins/triggers_actions_ui/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/index.ts index c6ac3649a14775..a3a62c3c444a04 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/index.ts @@ -23,7 +23,7 @@ export function triggersActionsUI(kibana: any) { config(Joi: Root) { return Joi.object() .keys({ - enabled: Joi.boolean().default(false), + enabled: Joi.boolean().default(true), createAlertUiEnabled: Joi.boolean().default(false), }) .default(); From 8690d2260705e40ca7290f2c1244663277b321e6 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 13 Jan 2020 08:03:58 -0800 Subject: [PATCH 295/297] Set index management to disabled to see the failing issue --- x-pack/legacy/plugins/index_management/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/index_management/index.ts b/x-pack/legacy/plugins/index_management/index.ts index dce0afd1f80330..df3e33b477edfa 100644 --- a/x-pack/legacy/plugins/index_management/index.ts +++ b/x-pack/legacy/plugins/index_management/index.ts @@ -28,7 +28,7 @@ export function indexManagement(kibana: any) { config(Joi: Root) { return Joi.object() .keys({ - enabled: Joi.boolean().default(true), + enabled: Joi.boolean().default(false), }) .default(); }, From 7431dcac0e482bebf531f3615f20b39c28f4a1e0 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 13 Jan 2020 14:41:39 -0800 Subject: [PATCH 296/297] Revert experimental back for index_managment --- x-pack/legacy/plugins/index_management/index.ts | 10 ---------- x-pack/legacy/plugins/triggers_actions_ui/index.ts | 2 +- x-pack/test/functional/config.js | 1 - 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/x-pack/legacy/plugins/index_management/index.ts b/x-pack/legacy/plugins/index_management/index.ts index df3e33b477edfa..c8d16accadb467 100644 --- a/x-pack/legacy/plugins/index_management/index.ts +++ b/x-pack/legacy/plugins/index_management/index.ts @@ -22,16 +22,6 @@ export function indexManagement(kibana: any) { configPrefix: 'xpack.index_management', publicDir: resolve(__dirname, 'public'), require: ['kibana', 'elasticsearch', 'xpack_main'], - isEnabled(config: Legacy.KibanaConfig) { - return config.get('xpack.index_management.enabled'); - }, - config(Joi: Root) { - return Joi.object() - .keys({ - enabled: Joi.boolean().default(false), - }) - .default(); - }, uiExports: { styleSheetPaths: resolve(__dirname, 'public/index.scss'), managementSections: ['plugins/index_management'], diff --git a/x-pack/legacy/plugins/triggers_actions_ui/index.ts b/x-pack/legacy/plugins/triggers_actions_ui/index.ts index a3a62c3c444a04..c6ac3649a14775 100644 --- a/x-pack/legacy/plugins/triggers_actions_ui/index.ts +++ b/x-pack/legacy/plugins/triggers_actions_ui/index.ts @@ -23,7 +23,7 @@ export function triggersActionsUI(kibana: any) { config(Joi: Root) { return Joi.object() .keys({ - enabled: Joi.boolean().default(true), + enabled: Joi.boolean().default(false), createAlertUiEnabled: Joi.boolean().default(false), }) .default(); diff --git a/x-pack/test/functional/config.js b/x-pack/test/functional/config.js index cea68cf0e33995..664bfdf8d2a746 100644 --- a/x-pack/test/functional/config.js +++ b/x-pack/test/functional/config.js @@ -88,7 +88,6 @@ export default async function({ readConfigFile }) { '--telemetry.banner=false', '--timelion.ui.enabled=true', '--xpack.endpoint.enabled=true', - '--xpack.index_management.enabled=true', ], }, uiSettings: { From 14f5ab5f7ca0147e19a89dfbef8283364dd45690 Mon Sep 17 00:00:00 2001 From: Yuliia Naumenko Date: Mon, 13 Jan 2020 15:03:32 -0800 Subject: [PATCH 297/297] Fixed type check --- x-pack/legacy/plugins/index_management/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/index_management/index.ts b/x-pack/legacy/plugins/index_management/index.ts index c8d16accadb467..f2a543337199f4 100644 --- a/x-pack/legacy/plugins/index_management/index.ts +++ b/x-pack/legacy/plugins/index_management/index.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Root } from 'joi'; import { resolve } from 'path'; import { i18n } from '@kbn/i18n'; import { Legacy } from 'kibana'; @@ -22,6 +21,7 @@ export function indexManagement(kibana: any) { configPrefix: 'xpack.index_management', publicDir: resolve(__dirname, 'public'), require: ['kibana', 'elasticsearch', 'xpack_main'], + uiExports: { styleSheetPaths: resolve(__dirname, 'public/index.scss'), managementSections: ['plugins/index_management'],