From c094dd98620dd73ed98bebdb84144e5652d017d5 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Fri, 8 May 2020 14:50:49 -0400 Subject: [PATCH 01/35] Extract store creation to plugin start, add redux providers to alert registration. --- x-pack/plugins/uptime/public/apps/plugin.ts | 37 +++++++++++++++++-- .../contexts/uptime_refresh_context.tsx | 25 ++++++++----- .../framework/new_platform_adapter.tsx | 19 +++------- .../uptime/public/lib/alert_types/index.ts | 6 ++- .../public/lib/alert_types/monitor_status.tsx | 12 +++++- .../uptime/public/lib/alert_types/tls.tsx | 9 ++++- x-pack/plugins/uptime/public/state/index.ts | 14 ++++--- x-pack/plugins/uptime/public/uptime_app.tsx | 9 ++--- 8 files changed, 89 insertions(+), 42 deletions(-) diff --git a/x-pack/plugins/uptime/public/apps/plugin.ts b/x-pack/plugins/uptime/public/apps/plugin.ts index b589bd64591fc..812108d4c6c2a 100644 --- a/x-pack/plugins/uptime/public/apps/plugin.ts +++ b/x-pack/plugins/uptime/public/apps/plugin.ts @@ -3,6 +3,8 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ + +import { Store } from 'redux'; import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'kibana/public'; import { AppMountParameters, DEFAULT_APP_CATEGORIES } from '../../../../../src/core/public'; import { UMFrontendLibs } from '../lib/lib'; @@ -12,6 +14,9 @@ import { HomePublicPluginSetup } from '../../../../../src/plugins/home/public'; import { EmbeddableStart } from '../../../../../src/plugins/embeddable/public'; import { TriggersAndActionsUIPublicPluginSetup } from '../../../triggers_actions_ui/public'; import { DataPublicPluginSetup } from '../../../../../src/plugins/data/public'; +import { alertTypeInitializers } from '../lib/alert_types'; +import { initializeStore } from '../state'; +import { kibanaService } from '../state/kibana_service'; export interface ClientPluginsSetup { data: DataPublicPluginSetup; @@ -24,12 +29,21 @@ export interface ClientPluginsStart { } export class UptimePlugin implements Plugin { - constructor(_context: PluginInitializerContext) {} + private _store: Store; + private _data: DataPublicPluginSetup | undefined; + private _triggersActionsUI: TriggersAndActionsUIPublicPluginSetup | undefined; + + constructor(_context: PluginInitializerContext) { + this._store = initializeStore(); + } public async setup( core: CoreSetup, plugins: ClientPluginsSetup ): Promise { + this._data = plugins.data; + this._triggersActionsUI = plugins.triggers_actions_ui; + if (plugins.home) { plugins.home.featureCatalogue.register({ id: PLUGIN.ID, @@ -42,6 +56,7 @@ export class UptimePlugin implements Plugin {}; @@ -65,7 +81,22 @@ export class UptimePlugin implements Plugin { + const alertInitializer = init({ + autocomplete: this._data!.autocomplete, + store: this._store, + }); + if ( + this._triggersActionsUI && + !this._triggersActionsUI.alertTypeRegistry.has(alertInitializer.id) + ) { + this._triggersActionsUI.alertTypeRegistry.register(alertInitializer); + } + }); + } public stop(): void {} } diff --git a/x-pack/plugins/uptime/public/contexts/uptime_refresh_context.tsx b/x-pack/plugins/uptime/public/contexts/uptime_refresh_context.tsx index 8e406f621f648..e06038ac6cde7 100644 --- a/x-pack/plugins/uptime/public/contexts/uptime_refresh_context.tsx +++ b/x-pack/plugins/uptime/public/contexts/uptime_refresh_context.tsx @@ -5,7 +5,7 @@ */ import React, { createContext, useMemo, useState } from 'react'; -import { store } from '../state'; +import { Store } from 'redux'; import { triggerAppRefresh } from '../state/actions'; interface UptimeRefreshContext { @@ -13,6 +13,10 @@ interface UptimeRefreshContext { refreshApp: () => void; } +interface RefreshContextProps { + store: Store; +} + const defaultContext: UptimeRefreshContext = { lastRefresh: 0, refreshApp: () => { @@ -22,19 +26,20 @@ const defaultContext: UptimeRefreshContext = { export const UptimeRefreshContext = createContext(defaultContext); -export const UptimeRefreshContextProvider: React.FC = ({ children }) => { +export const UptimeRefreshContextProvider: React.FC = ({ + children, + store, +}) => { const [lastRefresh, setLastRefresh] = useState(Date.now()); - const refreshApp = () => { - const refreshTime = Date.now(); - setLastRefresh(refreshTime); - // @ts-ignore - store.dispatch(triggerAppRefresh(refreshTime)); - }; - const value = useMemo(() => { + const refreshApp = () => { + const refreshTime = Date.now(); + setLastRefresh(refreshTime); + store.dispatch(triggerAppRefresh(refreshTime)); + }; return { lastRefresh, refreshApp }; - }, [lastRefresh]); + }, [lastRefresh, store]); return ; }; diff --git a/x-pack/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx b/x-pack/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx index f7f9e056f41af..ee13a48b82e99 100644 --- a/x-pack/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx +++ b/x-pack/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx @@ -9,7 +9,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { get } from 'lodash'; import { i18n as i18nFormatter } from '@kbn/i18n'; -import { alertTypeInitializers } from '../../alert_types'; +import { Store } from 'redux'; import { UptimeApp, UptimeAppProps } from '../../../uptime_app'; import { getIntegratedAppAvailability } from './capabilities_adapter'; import { @@ -20,11 +20,13 @@ import { } from '../../../../common/constants'; import { UMFrameworkAdapter } from '../../lib'; import { ClientPluginsStart, ClientPluginsSetup } from '../../../apps/plugin'; +import { AppState } from '../../../state'; export const getKibanaFrameworkAdapter = ( core: CoreStart, plugins: ClientPluginsSetup, - startPlugins: ClientPluginsStart + startPlugins: ClientPluginsStart, + store: Store ): UMFrameworkAdapter => { const { application: { capabilities }, @@ -34,18 +36,6 @@ export const getKibanaFrameworkAdapter = ( i18n, } = core; - const { - data: { autocomplete }, - triggers_actions_ui, - } = plugins; - - alertTypeInitializers.forEach(init => { - const alertInitializer = init({ autocomplete }); - if (!triggers_actions_ui.alertTypeRegistry.has(alertInitializer.id)) { - triggers_actions_ui.alertTypeRegistry.register(init({ autocomplete })); - } - }); - let breadcrumbs: ChromeBreadcrumb[] = []; core.chrome.getBreadcrumbs$().subscribe((nextBreadcrumbs?: ChromeBreadcrumb[]) => { breadcrumbs = nextBreadcrumbs || []; @@ -90,6 +80,7 @@ export const getKibanaFrameworkAdapter = ( routerBasename: basePath.prepend(PLUGIN.ROUTER_BASE_NAME), setBadge, setBreadcrumbs: core.chrome.setBreadcrumbs, + store, }; return { diff --git a/x-pack/plugins/uptime/public/lib/alert_types/index.ts b/x-pack/plugins/uptime/public/lib/alert_types/index.ts index 9a0151e95748c..dee96f557e808 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/index.ts +++ b/x-pack/plugins/uptime/public/lib/alert_types/index.ts @@ -4,11 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ +import { Store } from 'redux'; import { AlertTypeModel } from '../../../../triggers_actions_ui/public'; import { initMonitorStatusAlertType } from './monitor_status'; import { initTlsAlertType } from './tls'; -export type AlertTypeInitializer = (dependenies: { autocomplete: any }) => AlertTypeModel; +export type AlertTypeInitializer = (dependenies: { + autocomplete: any; + store: Store; +}) => AlertTypeModel; export const alertTypeInitializers: AlertTypeInitializer[] = [ initMonitorStatusAlertType, diff --git a/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx index bba7907d79c5d..74bdbebab7185 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx +++ b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx @@ -5,6 +5,7 @@ */ import { PathReporter } from 'io-ts/lib/PathReporter'; +import { Provider as ReduxProvider } from 'react-redux'; import React from 'react'; import DateMath from '@elastic/datemath'; import { isRight } from 'fp-ts/lib/Either'; @@ -59,12 +60,19 @@ const { defaultActionMessage } = MonitorStatusTranslations; export const initMonitorStatusAlertType: AlertTypeInitializer = ({ autocomplete, + store, }): AlertTypeModel => ({ id: CLIENT_ALERT_TYPES.MONITOR_STATUS, - name: , + name: ( + + + + ), iconClass: 'uptimeApp', alertParamsExpression: (params: any) => ( - + + + ), validate, defaultActionMessage, diff --git a/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx b/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx index 5e1b8cf233d70..0676b6cfa17f2 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx +++ b/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx @@ -5,6 +5,7 @@ */ import React from 'react'; +import { Provider as ReduxProvider } from 'react-redux'; import { AlertTypeModel } from '../../../../triggers_actions_ui/public'; import { CLIENT_ALERT_TYPES } from '../../../common/constants'; import { TlsTranslations } from './translations'; @@ -13,10 +14,14 @@ import { AlertTls } from '../../components/overview/alerts/alerts_containers/ale const { name, defaultActionMessage } = TlsTranslations; -export const initTlsAlertType: AlertTypeInitializer = (): AlertTypeModel => ({ +export const initTlsAlertType: AlertTypeInitializer = ({ store }): AlertTypeModel => ({ id: CLIENT_ALERT_TYPES.TLS, iconClass: 'uptimeApp', - alertParamsExpression: () => , + alertParamsExpression: () => ( + + + + ), name, validate: () => ({ errors: {} }), defaultActionMessage, diff --git a/x-pack/plugins/uptime/public/state/index.ts b/x-pack/plugins/uptime/public/state/index.ts index e3563c74294d2..fa9979d7436bb 100644 --- a/x-pack/plugins/uptime/public/state/index.ts +++ b/x-pack/plugins/uptime/public/state/index.ts @@ -9,12 +9,16 @@ import createSagaMiddleware from 'redux-saga'; import { rootEffect } from './effects'; import { rootReducer } from './reducers'; -const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; +export type AppState = ReturnType; -const sagaMW = createSagaMiddleware(); +export const initializeStore = () => { + const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; -export const store = createStore(rootReducer, composeEnhancers(applyMiddleware(sagaMW))); + const sagaMW = createSagaMiddleware(); -export type AppState = ReturnType; + const store = createStore(rootReducer, composeEnhancers(applyMiddleware(sagaMW))); + + sagaMW.run(rootEffect); -sagaMW.run(rootEffect); + return store; +}; diff --git a/x-pack/plugins/uptime/public/uptime_app.tsx b/x-pack/plugins/uptime/public/uptime_app.tsx index 2891a15510f31..81db62aa45df7 100644 --- a/x-pack/plugins/uptime/public/uptime_app.tsx +++ b/x-pack/plugins/uptime/public/uptime_app.tsx @@ -10,6 +10,7 @@ import React, { useEffect } from 'react'; import { Provider as ReduxProvider } from 'react-redux'; import { BrowserRouter as Router } from 'react-router-dom'; import { I18nStart, ChromeBreadcrumb, CoreStart } from 'src/core/public'; +import { Store } from 'redux'; import { KibanaContextProvider } from '../../../../src/plugins/kibana_react/public'; import { ClientPluginsSetup, ClientPluginsStart } from './apps/plugin'; import { UMUpdateBadge } from './lib/lib'; @@ -20,14 +21,12 @@ import { UptimeStartupPluginsContextProvider, } from './contexts'; import { CommonlyUsedRange } from './components/common/uptime_date_picker'; -import { store } from './state'; import { setBasePath } from './state/actions'; import { PageRouter } from './routes'; import { UptimeAlertsContextProvider, UptimeAlertsFlyoutWrapper, } from './components/overview/alerts'; -import { kibanaService } from './state/kibana_service'; export interface UptimeAppColors { danger: string; @@ -55,6 +54,7 @@ export interface UptimeAppProps { renderGlobalHelpControls(): void; commonlyUsedRanges: CommonlyUsedRange[]; setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => void; + store: Store; } const Application = (props: UptimeAppProps) => { @@ -69,6 +69,7 @@ const Application = (props: UptimeAppProps) => { routerBasename, setBadge, startPlugins, + store, } = props; useEffect(() => { @@ -88,8 +89,6 @@ const Application = (props: UptimeAppProps) => { ); }, [canSave, renderGlobalHelpControls, setBadge]); - kibanaService.core = core; - store.dispatch(setBasePath(basePath)); return ( @@ -98,7 +97,7 @@ const Application = (props: UptimeAppProps) => { - + From 6bb55191bbd57d68a85576416fe57332e2b8f812 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Wed, 13 May 2020 17:11:28 -0400 Subject: [PATCH 02/35] Update unit test. --- .../__tests__/monitor_status.test.ts | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts b/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts index b06a7cc93f628..e9162a0e609c8 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts +++ b/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts @@ -166,7 +166,18 @@ describe('monitor status alert type', () => { }); describe('initMonitorStatusAlertType', () => { - expect(initMonitorStatusAlertType({ autocomplete: {} })).toMatchInlineSnapshot(` + expect( + initMonitorStatusAlertType({ + autocomplete: {}, + store: { + dispatch: jest.fn(), + getState: jest.fn(), + replaceReducer: jest.fn(), + subscribe: jest.fn(), + [Symbol.observable]: jest.fn(), + }, + }) + ).toMatchInlineSnapshot(` Object { "alertParamsExpression": [Function], "defaultActionMessage": "{{context.message}} @@ -174,7 +185,19 @@ describe('monitor status alert type', () => { {{context.downMonitorsWithGeo}}", "iconClass": "uptimeApp", "id": "xpack.uptime.alerts.monitorStatus", - "name": , + "name": + + , "requiresAppContext": true, "validate": [Function], } From e5a1eb31c868ecf4d06e05f3442d4a5091ceedc2 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Thu, 14 May 2020 12:43:41 -0400 Subject: [PATCH 03/35] Move alert registration to `setup` function. --- x-pack/plugins/uptime/public/apps/plugin.ts | 31 +++++++++------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/x-pack/plugins/uptime/public/apps/plugin.ts b/x-pack/plugins/uptime/public/apps/plugin.ts index 812108d4c6c2a..78f3dd1623a81 100644 --- a/x-pack/plugins/uptime/public/apps/plugin.ts +++ b/x-pack/plugins/uptime/public/apps/plugin.ts @@ -30,8 +30,6 @@ export interface ClientPluginsStart { export class UptimePlugin implements Plugin { private _store: Store; - private _data: DataPublicPluginSetup | undefined; - private _triggersActionsUI: TriggersAndActionsUIPublicPluginSetup | undefined; constructor(_context: PluginInitializerContext) { this._store = initializeStore(); @@ -41,9 +39,6 @@ export class UptimePlugin implements Plugin, plugins: ClientPluginsSetup ): Promise { - this._data = plugins.data; - this._triggersActionsUI = plugins.triggers_actions_ui; - if (plugins.home) { plugins.home.featureCatalogue.register({ id: PLUGIN.ID, @@ -56,6 +51,19 @@ export class UptimePlugin implements Plugin { + const alertInitializer = init({ + autocomplete: plugins.data.autocomplete, + store: this._store, + }); + if ( + plugins.triggers_actions_ui && + !plugins.triggers_actions_ui.alertTypeRegistry.has(alertInitializer.id) + ) { + plugins.triggers_actions_ui.alertTypeRegistry.register(alertInitializer); + } + }); + const self = this; core.application.register({ appRoute: '/app/uptime#/', @@ -83,19 +91,6 @@ export class UptimePlugin implements Plugin { - const alertInitializer = init({ - autocomplete: this._data!.autocomplete, - store: this._store, - }); - if ( - this._triggersActionsUI && - !this._triggersActionsUI.alertTypeRegistry.has(alertInitializer.id) - ) { - this._triggersActionsUI.alertTypeRegistry.register(alertInitializer); - } - }); } public stop(): void {} From 03ec2995cd114e0359a00cc681a5e5f903603b02 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Thu, 14 May 2020 12:55:50 -0400 Subject: [PATCH 04/35] Allow external editing of uptime client alert types. --- x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx | 2 +- x-pack/plugins/uptime/public/lib/alert_types/tls.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx index 74bdbebab7185..17e6c06db03d3 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx +++ b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx @@ -76,5 +76,5 @@ export const initMonitorStatusAlertType: AlertTypeInitializer = ({ ), validate, defaultActionMessage, - requiresAppContext: true, + requiresAppContext: false, }); diff --git a/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx b/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx index 0676b6cfa17f2..7648d567b5315 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx +++ b/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx @@ -25,5 +25,5 @@ export const initTlsAlertType: AlertTypeInitializer = ({ store }): AlertTypeMode name, validate: () => ({ errors: {} }), defaultActionMessage, - requiresAppContext: true, + requiresAppContext: false, }); From bf16f6ad9cad517cfe2d5cd6e3eb978faa3b8dc1 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Thu, 14 May 2020 14:57:34 -0400 Subject: [PATCH 05/35] Move alert initialization back to `start`. --- x-pack/plugins/uptime/public/apps/plugin.ts | 29 +++++++++++---------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/x-pack/plugins/uptime/public/apps/plugin.ts b/x-pack/plugins/uptime/public/apps/plugin.ts index 78f3dd1623a81..313c5c3f41ce6 100644 --- a/x-pack/plugins/uptime/public/apps/plugin.ts +++ b/x-pack/plugins/uptime/public/apps/plugin.ts @@ -51,19 +51,6 @@ export class UptimePlugin implements Plugin { - const alertInitializer = init({ - autocomplete: plugins.data.autocomplete, - store: this._store, - }); - if ( - plugins.triggers_actions_ui && - !plugins.triggers_actions_ui.alertTypeRegistry.has(alertInitializer.id) - ) { - plugins.triggers_actions_ui.alertTypeRegistry.register(alertInitializer); - } - }); - const self = this; core.application.register({ appRoute: '/app/uptime#/', @@ -89,8 +76,22 @@ export class UptimePlugin implements Plugin { + const alertInitializer = init({ + autocomplete: plugins.data.autocomplete, + store: this._store, + core: start, + plugins, + }); + if ( + plugins.triggers_actions_ui && + !plugins.triggers_actions_ui.alertTypeRegistry.has(alertInitializer.id) + ) { + plugins.triggers_actions_ui.alertTypeRegistry.register(alertInitializer); + } + }); } public stop(): void {} From c2ad6d02725df7a7985dc421f0462773cf503deb Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Fri, 15 May 2020 10:41:20 -0400 Subject: [PATCH 06/35] Clean up interfaces for alert types. --- x-pack/plugins/uptime/public/apps/plugin.ts | 15 +++++++++++---- .../uptime/public/lib/alert_types/index.ts | 5 ++++- .../public/lib/alert_types/monitor_status.tsx | 18 ++++++++++++------ .../uptime/public/lib/alert_types/tls.tsx | 11 +++++++++-- 4 files changed, 36 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/uptime/public/apps/plugin.ts b/x-pack/plugins/uptime/public/apps/plugin.ts index 313c5c3f41ce6..58467cb311d1f 100644 --- a/x-pack/plugins/uptime/public/apps/plugin.ts +++ b/x-pack/plugins/uptime/public/apps/plugin.ts @@ -12,8 +12,14 @@ import { PLUGIN } from '../../common/constants'; import { FeatureCatalogueCategory } from '../../../../../src/plugins/home/public'; import { HomePublicPluginSetup } from '../../../../../src/plugins/home/public'; import { EmbeddableStart } from '../../../../../src/plugins/embeddable/public'; -import { TriggersAndActionsUIPublicPluginSetup } from '../../../triggers_actions_ui/public'; -import { DataPublicPluginSetup } from '../../../../../src/plugins/data/public'; +import { + TriggersAndActionsUIPublicPluginSetup, + TriggersAndActionsUIPublicPluginStart, +} from '../../../triggers_actions_ui/public'; +import { + DataPublicPluginSetup, + DataPublicPluginStart, +} from '../../../../../src/plugins/data/public'; import { alertTypeInitializers } from '../lib/alert_types'; import { initializeStore } from '../state'; import { kibanaService } from '../state/kibana_service'; @@ -26,6 +32,8 @@ export interface ClientPluginsSetup { export interface ClientPluginsStart { embeddable: EmbeddableStart; + data: DataPublicPluginStart; + triggers_actions_ui: TriggersAndActionsUIPublicPluginStart; } export class UptimePlugin implements Plugin { @@ -76,11 +84,10 @@ export class UptimePlugin implements Plugin { const alertInitializer = init({ - autocomplete: plugins.data.autocomplete, store: this._store, core: start, plugins, diff --git a/x-pack/plugins/uptime/public/lib/alert_types/index.ts b/x-pack/plugins/uptime/public/lib/alert_types/index.ts index dee96f557e808..4c62b24fa2b0e 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/index.ts +++ b/x-pack/plugins/uptime/public/lib/alert_types/index.ts @@ -5,13 +5,16 @@ */ import { Store } from 'redux'; +import { CoreStart } from 'kibana/public'; import { AlertTypeModel } from '../../../../triggers_actions_ui/public'; import { initMonitorStatusAlertType } from './monitor_status'; import { initTlsAlertType } from './tls'; +import { ClientPluginsStart } from '../../apps/plugin'; export type AlertTypeInitializer = (dependenies: { - autocomplete: any; store: Store; + core: CoreStart; + plugins: ClientPluginsStart; }) => AlertTypeModel; export const alertTypeInitializers: AlertTypeInitializer[] = [ diff --git a/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx index 17e6c06db03d3..5b17a94d7f32b 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx +++ b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx @@ -16,6 +16,7 @@ import { AlertMonitorStatus } from '../../components/overview/alerts/alerts_cont import { MonitorStatusTitle } from './monitor_status_title'; import { CLIENT_ALERT_TYPES } from '../../../common/constants'; import { MonitorStatusTranslations } from './translations'; +import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; export const validate = (alertParams: any) => { const errors: Record = {}; @@ -59,8 +60,9 @@ export const validate = (alertParams: any) => { const { defaultActionMessage } = MonitorStatusTranslations; export const initMonitorStatusAlertType: AlertTypeInitializer = ({ - autocomplete, store, + core, + plugins, }): AlertTypeModel => ({ id: CLIENT_ALERT_TYPES.MONITOR_STATUS, name: ( @@ -69,11 +71,15 @@ export const initMonitorStatusAlertType: AlertTypeInitializer = ({ ), iconClass: 'uptimeApp', - alertParamsExpression: (params: any) => ( - - - - ), + alertParamsExpression: (params: any) => { + return ( + + + + + + ); + }, validate, defaultActionMessage, requiresAppContext: false, diff --git a/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx b/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx index 7648d567b5315..e35a6727c0085 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx +++ b/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx @@ -11,15 +11,22 @@ import { CLIENT_ALERT_TYPES } from '../../../common/constants'; import { TlsTranslations } from './translations'; import { AlertTypeInitializer } from '.'; import { AlertTls } from '../../components/overview/alerts/alerts_containers/alert_tls'; +import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; const { name, defaultActionMessage } = TlsTranslations; -export const initTlsAlertType: AlertTypeInitializer = ({ store }): AlertTypeModel => ({ +export const initTlsAlertType: AlertTypeInitializer = ({ + store, + core, + plugins, +}): AlertTypeModel => ({ id: CLIENT_ALERT_TYPES.TLS, iconClass: 'uptimeApp', alertParamsExpression: () => ( - + + + ), name, From f8e3c7e26735c5f9827e8888bd404fb82ca873de Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Fri, 15 May 2020 17:11:33 -0400 Subject: [PATCH 07/35] Add code that will work for settings link even outside uptime app. --- .../alerts/settings_message_expression_popover.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/settings_message_expression_popover.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/settings_message_expression_popover.tsx index 8d9de08751eee..fe65b5fa75766 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/settings_message_expression_popover.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/settings_message_expression_popover.tsx @@ -4,11 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ +import { EuiLink } from '@elastic/eui'; import { EuiExpression, EuiPopover } from '@elastic/eui'; -import { Link } from 'react-router-dom'; import React, { useState } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { SETTINGS_ROUTE } from '../../../../common/constants'; +import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; interface SettingsMessageExpressionPopoverProps { 'aria-label': string; @@ -25,6 +25,8 @@ export const SettingsMessageExpressionPopover: React.FC { + const kibana = useKibana(); + const path = kibana.services?.application?.getUrlForApp('uptime', { path: 'settings' }); const [isOpen, setIsOpen] = useState(false); return ( + { setAlertFlyoutVisible(false); @@ -63,7 +65,7 @@ export const SettingsMessageExpressionPopover: React.FC settings page - + ), }} /> From 47fe9cccad615f2b7060464482645d62dc335056 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Thu, 28 May 2020 10:30:37 -0400 Subject: [PATCH 08/35] Create new atomic params type for status alerts. --- .../stringify_kueries.test.ts.snap | 0 .../combine_filters_and_user_search.test.ts | 0 .../lib}/__tests__/stringify_kueries.test.ts | 0 .../lib}/combine_filters_and_user_search.ts | 0 x-pack/plugins/uptime/common/lib/index.ts | 8 ++ .../lib}/stringify_kueries.ts | 0 .../runtime_types/alerts/status_check.ts | 27 ++++- .../overview/alerts/alert_monitor_status.tsx | 6 +- .../alert_monitor_status.tsx | 10 +- .../filters_expression_select.tsx | 22 +++-- .../time_expression_select.tsx | 3 +- .../overview/kuery_bar/kuery_bar.tsx | 11 ++- x-pack/plugins/uptime/public/hooks/index.ts | 1 + .../public/hooks/update_kuery_string.ts | 2 +- .../uptime/public/hooks/use_search_text.ts | 22 +++++ .../public/lib/alert_types/monitor_status.tsx | 41 +++----- .../plugins/uptime/public/lib/helper/index.ts | 2 - .../plugins/uptime/public/state/actions/ui.ts | 2 + .../uptime/public/state/reducers/ui.ts | 8 ++ .../uptime/public/state/selectors/index.ts | 2 + .../lib/adapters/framework/adapter_types.ts | 2 +- .../uptime/server/lib/alerts/status_check.ts | 99 ++++++++++++++++--- .../server/lib/requests/get_index_pattern.ts | 2 +- .../server/lib/requests/uptime_requests.ts | 3 +- 24 files changed, 203 insertions(+), 70 deletions(-) rename x-pack/plugins/uptime/{public/lib/helper => common/lib}/__tests__/__snapshots__/stringify_kueries.test.ts.snap (100%) rename x-pack/plugins/uptime/{public/lib/helper => common/lib}/__tests__/combine_filters_and_user_search.test.ts (100%) rename x-pack/plugins/uptime/{public/lib/helper => common/lib}/__tests__/stringify_kueries.test.ts (100%) rename x-pack/plugins/uptime/{public/lib/helper => common/lib}/combine_filters_and_user_search.ts (100%) create mode 100644 x-pack/plugins/uptime/common/lib/index.ts rename x-pack/plugins/uptime/{public/lib/helper => common/lib}/stringify_kueries.ts (100%) create mode 100644 x-pack/plugins/uptime/public/hooks/use_search_text.ts diff --git a/x-pack/plugins/uptime/public/lib/helper/__tests__/__snapshots__/stringify_kueries.test.ts.snap b/x-pack/plugins/uptime/common/lib/__tests__/__snapshots__/stringify_kueries.test.ts.snap similarity index 100% rename from x-pack/plugins/uptime/public/lib/helper/__tests__/__snapshots__/stringify_kueries.test.ts.snap rename to x-pack/plugins/uptime/common/lib/__tests__/__snapshots__/stringify_kueries.test.ts.snap diff --git a/x-pack/plugins/uptime/public/lib/helper/__tests__/combine_filters_and_user_search.test.ts b/x-pack/plugins/uptime/common/lib/__tests__/combine_filters_and_user_search.test.ts similarity index 100% rename from x-pack/plugins/uptime/public/lib/helper/__tests__/combine_filters_and_user_search.test.ts rename to x-pack/plugins/uptime/common/lib/__tests__/combine_filters_and_user_search.test.ts diff --git a/x-pack/plugins/uptime/public/lib/helper/__tests__/stringify_kueries.test.ts b/x-pack/plugins/uptime/common/lib/__tests__/stringify_kueries.test.ts similarity index 100% rename from x-pack/plugins/uptime/public/lib/helper/__tests__/stringify_kueries.test.ts rename to x-pack/plugins/uptime/common/lib/__tests__/stringify_kueries.test.ts diff --git a/x-pack/plugins/uptime/public/lib/helper/combine_filters_and_user_search.ts b/x-pack/plugins/uptime/common/lib/combine_filters_and_user_search.ts similarity index 100% rename from x-pack/plugins/uptime/public/lib/helper/combine_filters_and_user_search.ts rename to x-pack/plugins/uptime/common/lib/combine_filters_and_user_search.ts diff --git a/x-pack/plugins/uptime/common/lib/index.ts b/x-pack/plugins/uptime/common/lib/index.ts new file mode 100644 index 0000000000000..2daec0adf87e4 --- /dev/null +++ b/x-pack/plugins/uptime/common/lib/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 * from './combine_filters_and_user_search'; +export * from './stringify_kueries'; diff --git a/x-pack/plugins/uptime/public/lib/helper/stringify_kueries.ts b/x-pack/plugins/uptime/common/lib/stringify_kueries.ts similarity index 100% rename from x-pack/plugins/uptime/public/lib/helper/stringify_kueries.ts rename to x-pack/plugins/uptime/common/lib/stringify_kueries.ts diff --git a/x-pack/plugins/uptime/common/runtime_types/alerts/status_check.ts b/x-pack/plugins/uptime/common/runtime_types/alerts/status_check.ts index 909669bb5d3eb..74d5337256601 100644 --- a/x-pack/plugins/uptime/common/runtime_types/alerts/status_check.ts +++ b/x-pack/plugins/uptime/common/runtime_types/alerts/status_check.ts @@ -6,7 +6,30 @@ import * as t from 'io-ts'; -export const StatusCheckExecutorParamsType = t.intersection([ +export const StatusCheckFiltersType = t.type({ + 'monitor.type': t.array(t.string), + 'observer.geo.name': t.array(t.string), + tags: t.array(t.string), + 'url.port': t.array(t.string), +}); + +export type StatusCheckFilters = t.TypeOf; + +export const AtomicStatusCheckParamsType = t.intersection([ + t.type({ + numTimes: t.number, + timerangeCount: t.number, + timerangeUnit: t.string, + }), + t.partial({ + search: t.string, + filters: StatusCheckFiltersType, + }), +]); + +export type AtomicStatusCheckParams = t.TypeOf; + +export const StatusCheckParamsType = t.intersection([ t.partial({ filters: t.string, }), @@ -20,4 +43,4 @@ export const StatusCheckExecutorParamsType = t.intersection([ }), ]); -export type StatusCheckExecutorParams = t.TypeOf; +export type StatusCheckParams = t.TypeOf; diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx index 62f92fe8a5142..e2e44124ec659 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useEffect, useState } from 'react'; +import React, { useState } from 'react'; import { EuiSpacer } from '@elastic/eui'; import { DataPublicPluginSetup } from 'src/plugins/data/public'; import * as labels from './translations'; @@ -35,10 +35,6 @@ export const AlertMonitorStatusComponent: React.FC = (p const [newFilters, setNewFilters] = useState([]); - useEffect(() => { - setAlertParams('filters', filters); - }, [filters, setAlertParams]); - return ( <> diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx index 77e0c98c0260d..d5d207344b6f2 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx @@ -4,10 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { useEffect } from 'react'; import { useSelector } from 'react-redux'; import { DataPublicPluginSetup } from 'src/plugins/data/public'; -import { selectMonitorStatusAlert } from '../../../../state/selectors'; +import { selectMonitorStatusAlert, selectSearchText } from '../../../../state/selectors'; import { AlertMonitorStatusComponent } from '../index'; interface Props { @@ -29,6 +29,12 @@ export const AlertMonitorStatus: React.FC = ({ timerange, }) => { const { filters, locations } = useSelector(selectMonitorStatusAlert); + const searchText = useSelector(selectSearchText); + + useEffect(() => { + setAlertParams('search', searchText); + }, [setAlertParams, searchText]); + return ( = ({ updatedFieldValues.values ); - useEffect(() => { - if (updatedFieldValues.fieldName === 'observer.geo.name') { - setAlertParams('locations', updatedFieldValues.values); - } - }, [setAlertParams, updatedFieldValues]); + const [filters, setFilters] = useState({ + 'observer.geo.name': selectedLocations, + 'url.port': selectedPorts, + tags: selectedTags, + 'monitor.type': selectedSchemes, + }); useEffect(() => { - setAlertParams('locations', []); - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + setAlertParams('filters', filters); + }, [filters, setAlertParams]); const onFilterFieldChange = (fieldName: string, values: string[]) => { + setFilters({ + ...filters, + [fieldName]: values, + }); setUpdatedFieldValues({ fieldName, values }); }; diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/time_expression_select.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/time_expression_select.tsx index aabc6fd6e6623..e3893845862fb 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/time_expression_select.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/time_expression_select.tsx @@ -51,7 +51,8 @@ export const TimeExpressionSelect: React.FC = ({ setAlertParams }) => { useEffect(() => { const timerangeUnit = timerangeUnitOptions.find(({ checked }) => checked === 'on')?.key ?? 'm'; - setAlertParams('timerange', { from: `now-${numUnits}${timerangeUnit}`, to: 'now' }); + setAlertParams('timerangeUnit', timerangeUnit); + setAlertParams('timerangeCount', numUnits); }, [numUnits, timerangeUnitOptions, setAlertParams]); return ( diff --git a/x-pack/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx b/x-pack/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx index a63dbfdecef42..5c0ee632a2bda 100644 --- a/x-pack/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx +++ b/x-pack/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx @@ -4,13 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { uniqueId, startsWith } from 'lodash'; import { EuiCallOut } from '@elastic/eui'; import styled from 'styled-components'; import { FormattedMessage } from '@kbn/i18n/react'; import { Typeahead } from './typeahead'; -import { useUrlParams } from '../../../hooks'; +import { useSearchText, useUrlParams } from '../../../hooks'; import { esKuery, IIndexPattern, @@ -45,6 +45,7 @@ export function KueryBar({ 'data-test-subj': dataTestSubj, }: Props) { const { loading, index_pattern: indexPattern } = useIndexPattern(); + const { updateSearchText } = useSearchText(); const [state, setState] = useState({ suggestions: [], @@ -56,6 +57,10 @@ export function KueryBar({ const [getUrlParams, updateUrlParams] = useUrlParams(); const { search: kuery } = getUrlParams(); + useEffect(() => { + updateSearchText(kuery); + }, [kuery, updateSearchText]); + const indexPatternMissing = loading && !indexPattern; async function onChange(inputValue: string, selectionStart: number) { @@ -63,6 +68,8 @@ export function KueryBar({ return; } + updateSearchText(inputValue); + setIsLoadingSuggestions(true); setState({ ...state, suggestions: [] }); diff --git a/x-pack/plugins/uptime/public/hooks/index.ts b/x-pack/plugins/uptime/public/hooks/index.ts index b92d2d4cf7df5..14264710f7a0d 100644 --- a/x-pack/plugins/uptime/public/hooks/index.ts +++ b/x-pack/plugins/uptime/public/hooks/index.ts @@ -9,3 +9,4 @@ export * from './use_url_params'; export * from './use_telemetry'; export * from './update_kuery_string'; export * from './use_cert_status'; +export * from './use_search_text'; diff --git a/x-pack/plugins/uptime/public/hooks/update_kuery_string.ts b/x-pack/plugins/uptime/public/hooks/update_kuery_string.ts index 492d2bab5bb80..8a9e134e98bfd 100644 --- a/x-pack/plugins/uptime/public/hooks/update_kuery_string.ts +++ b/x-pack/plugins/uptime/public/hooks/update_kuery_string.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { combineFiltersAndUserSearch, stringifyKueries } from '../lib/helper'; import { esKuery, IIndexPattern } from '../../../../../src/plugins/data/public'; +import { combineFiltersAndUserSearch, stringifyKueries } from '../../common/lib'; const getKueryString = (urlFilters: string): string => { let kueryString = ''; diff --git a/x-pack/plugins/uptime/public/hooks/use_search_text.ts b/x-pack/plugins/uptime/public/hooks/use_search_text.ts new file mode 100644 index 0000000000000..8bf2b7c82fdeb --- /dev/null +++ b/x-pack/plugins/uptime/public/hooks/use_search_text.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { useCallback } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { setSearchText } from '../state/actions'; +import { selectSearchText } from '../state/selectors'; + +export const useSearchText = () => { + const dispatch = useDispatch(); + const searchText = useSelector(selectSearchText); + + const updateSearchText = useCallback( + (nextSearchText: string) => dispatch(setSearchText(nextSearchText)), + [dispatch] + ); + + return { searchText, updateSearchText }; +}; diff --git a/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx index 08fc044bee201..274e61c11b86c 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx +++ b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx @@ -4,51 +4,32 @@ * you may not use this file except in compliance with the Elastic License. */ -import { PathReporter } from 'io-ts/lib/PathReporter'; import React from 'react'; -import DateMath from '@elastic/datemath'; import { isRight } from 'fp-ts/lib/Either'; import { AlertTypeModel } from '../../../../triggers_actions_ui/public'; import { AlertTypeInitializer } from '.'; -import { StatusCheckExecutorParamsType } from '../../../common/runtime_types'; +import { AtomicStatusCheckParamsType } from '../../../common/runtime_types'; import { MonitorStatusTitle } from './monitor_status_title'; import { CLIENT_ALERT_TYPES } from '../../../common/constants'; import { MonitorStatusTranslations } from './translations'; export const validate = (alertParams: any) => { const errors: Record = {}; - const decoded = StatusCheckExecutorParamsType.decode(alertParams); + const newDecoded = AtomicStatusCheckParamsType.decode(alertParams); - /* - * When the UI initially loads, this validate function is called with an - * empty set of params, we don't want to type check against that. - */ - if (!isRight(decoded)) { + if (!isRight(newDecoded)) { errors.typeCheckFailure = 'Provided parameters do not conform to the expected type.'; - errors.typeCheckParsingMessage = PathReporter.report(decoded); - } - - if (isRight(decoded)) { - const { numTimes, timerange } = decoded.right; - const { from, to } = timerange; - const fromAbs = DateMath.parse(from)?.valueOf(); - const toAbs = DateMath.parse(to)?.valueOf(); - if (!fromAbs || isNaN(fromAbs)) { - errors.timeRangeStartValueNaN = 'Specified time range `from` is an invalid value'; - } - if (!toAbs || isNaN(toAbs)) { - errors.timeRangeEndValueNaN = 'Specified time range `to` is an invalid value'; - } - - // the default values for this test will pass, we only want to specify an error - // in the case that `from` is more recent than `to` - if ((fromAbs ?? 0) > (toAbs ?? 1)) { - errors.invalidTimeRange = 'Time range start cannot exceed time range end'; - } - + } else { + const { numTimes, timerangeCount } = newDecoded.right; if (numTimes < 1) { errors.invalidNumTimes = 'Number of alert check down times must be an integer greater than 0'; } + if (isNaN(timerangeCount)) { + errors.timeRangeStartValueNaN = 'Specified time range value must be a number'; + } + if (timerangeCount <= 0) { + errors.invalidTimeRangeValue = 'Time range value must be greater than 0'; + } } return { errors }; diff --git a/x-pack/plugins/uptime/public/lib/helper/index.ts b/x-pack/plugins/uptime/public/lib/helper/index.ts index e2aa4a2b3d429..cf49328141b83 100644 --- a/x-pack/plugins/uptime/public/lib/helper/index.ts +++ b/x-pack/plugins/uptime/public/lib/helper/index.ts @@ -4,10 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -export { combineFiltersAndUserSearch } from './combine_filters_and_user_search'; export { convertMicrosecondsToMilliseconds } from './convert_measurements'; export * from './observability_integration'; export { getChartDateLabel } from './charts'; export { seriesHasDownValues } from './series_has_down_values'; -export { stringifyKueries } from './stringify_kueries'; export { UptimeUrlParams, getSupportedUrlParams } from './url_params'; diff --git a/x-pack/plugins/uptime/public/state/actions/ui.ts b/x-pack/plugins/uptime/public/state/actions/ui.ts index 0d21e177d3e40..2b834b08d0918 100644 --- a/x-pack/plugins/uptime/public/state/actions/ui.ts +++ b/x-pack/plugins/uptime/public/state/actions/ui.ts @@ -20,6 +20,8 @@ export const setBasePath = createAction('SET BASE PATH'); export const setEsKueryString = createAction('SET ES KUERY STRING'); +export const setSearchText = createAction('SET SEARCH'); + export const toggleIntegrationsPopover = createAction( 'TOGGLE INTEGRATION POPOVER STATE' ); diff --git a/x-pack/plugins/uptime/public/state/reducers/ui.ts b/x-pack/plugins/uptime/public/state/reducers/ui.ts index 9e7bc2ad02723..7084d69958ded 100644 --- a/x-pack/plugins/uptime/public/state/reducers/ui.ts +++ b/x-pack/plugins/uptime/public/state/reducers/ui.ts @@ -13,6 +13,7 @@ import { UiPayload, setAlertFlyoutType, setAlertFlyoutVisible, + setSearchText, } from '../actions'; export interface UiState { @@ -20,6 +21,7 @@ export interface UiState { alertFlyoutType?: string; basePath: string; esKuery: string; + searchText: string; integrationsPopoverOpen: PopoverState | null; } @@ -27,6 +29,7 @@ const initialState: UiState = { alertFlyoutVisible: false, basePath: '', esKuery: '', + searchText: '', integrationsPopoverOpen: null, }; @@ -56,6 +59,11 @@ export const uiReducer = handleActions( ...state, alertFlyoutType: action.payload, }), + + [String(setSearchText)]: (state, action: Action) => ({ + ...state, + searchText: action.payload, + }), }, initialState ); diff --git a/x-pack/plugins/uptime/public/state/selectors/index.ts b/x-pack/plugins/uptime/public/state/selectors/index.ts index ce295faaf5763..7dee4e3bc567e 100644 --- a/x-pack/plugins/uptime/public/state/selectors/index.ts +++ b/x-pack/plugins/uptime/public/state/selectors/index.ts @@ -84,3 +84,5 @@ export const monitorListSelector = ({ monitorList }: AppState) => monitorList; export const overviewFiltersSelector = ({ overviewFilters }: AppState) => overviewFilters; export const esKuerySelector = ({ ui: { esKuery } }: AppState) => esKuery; + +export const selectSearchText = ({ ui: { searchText } }: AppState) => searchText; diff --git a/x-pack/plugins/uptime/server/lib/adapters/framework/adapter_types.ts b/x-pack/plugins/uptime/server/lib/adapters/framework/adapter_types.ts index f4d1c72770494..69065a96cb560 100644 --- a/x-pack/plugins/uptime/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/plugins/uptime/server/lib/adapters/framework/adapter_types.ts @@ -23,7 +23,7 @@ export type APICaller = ( export type UMElasticsearchQueryFn = ( params: { callES: APICaller; dynamicSettings: DynamicSettings } & P -) => Promise | R; +) => Promise; export type UMSavedObjectsQueryFn = ( client: SavedObjectsClientContract | ISavedObjectsRepository, diff --git a/x-pack/plugins/uptime/server/lib/alerts/status_check.ts b/x-pack/plugins/uptime/server/lib/alerts/status_check.ts index 17479bb451b18..01feaa485155d 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/status_check.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/status_check.ts @@ -11,11 +11,18 @@ import { i18n } from '@kbn/i18n'; import { AlertExecutorOptions } from '../../../../alerting/server'; import { UptimeAlertTypeFactory } from './types'; import { GetMonitorStatusResult } from '../requests'; -import { StatusCheckExecutorParamsType } from '../../../common/runtime_types'; +import { esKuery, IIndexPattern } from '../../../../../../src/plugins/data/server'; +import { + StatusCheckParamsType, + StatusCheckParams, + StatusCheckFilters, + AtomicStatusCheckParamsType, +} from '../../../common/runtime_types'; import { ACTION_GROUP_DEFINITIONS } from '../../../common/constants'; import { savedObjectsAdapter } from '../saved_objects'; import { updateState } from './common'; import { commonStateTranslations } from './translations'; +import { stringifyKueries, combineFiltersAndUserSearch } from '../../../common/lib'; const { MONITOR_STATUS } = ACTION_GROUP_DEFINITIONS; @@ -124,6 +131,46 @@ export const fullListByIdAndLocation = ( // we might want to make this a parameter in the future const DEFAULT_MAX_MESSAGE_ROWS = 3; +const hasFilters = (filters?: StatusCheckFilters) => { + if (!filters) return false; + for (const list of Object.values(filters)) { + if (list.length > 0) { + return true; + } + } + return false; +}; + +const genFilterString = async ( + getIndexPattern: () => Promise, + filters?: StatusCheckFilters, + search?: string +): Promise => { + const filtersExist = hasFilters(filters); + if (!filtersExist && !search) return undefined; + + let filterString: string | undefined; + if (filtersExist) { + filterString = stringifyKueries(new Map(Object.entries(filters ?? {}))); + } + + let combinedString: string | undefined; + if (filterString && search) { + combinedString = combineFiltersAndUserSearch(filterString, search); + } else if (filterString) { + combinedString = filterString; + } else if (search) { + combinedString = search; + } + + return JSON.stringify( + esKuery.toElasticsearchQuery( + esKuery.fromKueryExpression(combinedString ?? ''), + await getIndexPattern() + ) + ); +}; + export const statusCheckAlertFactory: UptimeAlertTypeFactory = (_server, libs) => ({ id: 'xpack.uptime.alerts.monitorStatus', name: i18n.translate('xpack.uptime.alerts.monitorStatus', { @@ -131,13 +178,18 @@ export const statusCheckAlertFactory: UptimeAlertTypeFactory = (_server, libs) = }), validate: { params: schema.object({ - filters: schema.maybe(schema.string()), + filters: schema.maybe( + schema.object({ + 'monitor.type': schema.arrayOf(schema.string()), + 'observer.geo.name': schema.arrayOf(schema.string()), + tags: schema.arrayOf(schema.string()), + 'url.port': schema.arrayOf(schema.string()), + }) + ), numTimes: schema.number(), - timerange: schema.object({ - from: schema.string(), - to: schema.string(), - }), - locations: schema.arrayOf(schema.string()), + search: schema.maybe(schema.string()), + timerangeCount: schema.number(), + timerangeUnit: schema.string(), }), }, defaultActionGroupId: MONITOR_STATUS.id, @@ -174,18 +226,39 @@ export const statusCheckAlertFactory: UptimeAlertTypeFactory = (_server, libs) = producer: 'uptime', async executor(options: AlertExecutorOptions) { const { params: rawParams } = options; - const decoded = StatusCheckExecutorParamsType.decode(rawParams); - if (!isRight(decoded)) { + const dynamicSettings = await savedObjectsAdapter.getUptimeDynamicSettings( + options.services.savedObjectsClient + ); + const atomicDecoded = AtomicStatusCheckParamsType.decode(rawParams); + const decoded = StatusCheckParamsType.decode(rawParams); + let params: StatusCheckParams; + if (isRight(atomicDecoded)) { + const { filters, search, numTimes, timerangeCount, timerangeUnit } = atomicDecoded.right; + const timerange = { from: `now-${String(timerangeCount) + timerangeUnit}`, to: 'now' }; + + params = { + timerange, + numTimes, + locations: [], + filters: await genFilterString( + () => + libs.requests.getIndexPattern({ + callES: options.services.callCluster, + dynamicSettings, + }), + filters, + search + ), + }; + } else if (isRight(decoded)) { + params = decoded.right; + } else { ThrowReporter.report(decoded); return { error: 'Alert param types do not conform to required shape.', }; } - const params = decoded.right; - const dynamicSettings = await savedObjectsAdapter.getUptimeDynamicSettings( - options.services.savedObjectsClient - ); /* This is called `monitorsByLocation` but it's really * monitors by location by status. The query we run to generate this * filters on the status field, so effectively there should be one and only one diff --git a/x-pack/plugins/uptime/server/lib/requests/get_index_pattern.ts b/x-pack/plugins/uptime/server/lib/requests/get_index_pattern.ts index 7902d9a5c8536..7b08752f12249 100644 --- a/x-pack/plugins/uptime/server/lib/requests/get_index_pattern.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_index_pattern.ts @@ -8,7 +8,7 @@ import { APICaller, CallAPIOptions } from 'src/core/server'; import { UMElasticsearchQueryFn } from '../adapters'; import { IndexPatternsFetcher, IIndexPattern } from '../../../../../../src/plugins/data/server'; -export const getUptimeIndexPattern: UMElasticsearchQueryFn<{}, {}> = async ({ +export const getUptimeIndexPattern: UMElasticsearchQueryFn<{}, IIndexPattern | undefined> = async ({ callES, dynamicSettings, }) => { diff --git a/x-pack/plugins/uptime/server/lib/requests/uptime_requests.ts b/x-pack/plugins/uptime/server/lib/requests/uptime_requests.ts index 367db924cf1c6..85fc2c3ef9771 100644 --- a/x-pack/plugins/uptime/server/lib/requests/uptime_requests.ts +++ b/x-pack/plugins/uptime/server/lib/requests/uptime_requests.ts @@ -33,13 +33,14 @@ import { } from '.'; import { GetMonitorStatesResult } from './get_monitor_states'; import { GetSnapshotCountParams } from './get_snapshot_counts'; +import { IIndexPattern } from '../../../../../../src/plugins/data/server'; type ESQ = UMElasticsearchQueryFn; export interface UptimeRequests { getCerts: ESQ; getFilterBar: ESQ; - getIndexPattern: ESQ<{}, {}>; + getIndexPattern: ESQ<{}, IIndexPattern | undefined>; getLatestMonitor: ESQ; getMonitorDurationChart: ESQ; getMonitorDetails: ESQ; From f5cf3b54e3690f70ce2bc9c004b90684d7d2f67d Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Fri, 29 May 2020 12:19:29 -0400 Subject: [PATCH 09/35] Update executor params typing to support both alert params types. --- .../uptime/server/lib/alerts/status_check.ts | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/uptime/server/lib/alerts/status_check.ts b/x-pack/plugins/uptime/server/lib/alerts/status_check.ts index 01feaa485155d..d4768ab004947 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/status_check.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/status_check.ts @@ -179,17 +179,27 @@ export const statusCheckAlertFactory: UptimeAlertTypeFactory = (_server, libs) = validate: { params: schema.object({ filters: schema.maybe( - schema.object({ - 'monitor.type': schema.arrayOf(schema.string()), - 'observer.geo.name': schema.arrayOf(schema.string()), - tags: schema.arrayOf(schema.string()), - 'url.port': schema.arrayOf(schema.string()), - }) + schema.oneOf([ + schema.object({ + 'monitor.type': schema.maybe(schema.arrayOf(schema.string())), + 'observer.geo.name': schema.maybe(schema.arrayOf(schema.string())), + tags: schema.maybe(schema.arrayOf(schema.string())), + 'url.port': schema.maybe(schema.arrayOf(schema.string())), + }), + schema.string(), + ]) ), + locations: schema.maybe(schema.arrayOf(schema.string())), numTimes: schema.number(), search: schema.maybe(schema.string()), - timerangeCount: schema.number(), - timerangeUnit: schema.string(), + timerangeCount: schema.maybe(schema.number()), + timerangeUnit: schema.maybe(schema.string()), + timerange: schema.maybe( + schema.object({ + from: schema.string(), + to: schema.string(), + }) + ), }), }, defaultActionGroupId: MONITOR_STATUS.id, From e4141809cd2011442d295b39b0956b42aec5c67e Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Fri, 29 May 2020 12:36:15 -0400 Subject: [PATCH 10/35] Update snapshot for alert factory function. --- .../uptime/server/lib/alerts/__tests__/status_check.test.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/uptime/server/lib/alerts/__tests__/status_check.test.ts b/x-pack/plugins/uptime/server/lib/alerts/__tests__/status_check.test.ts index 73d104c1d21ae..fd60a623c3408 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/__tests__/status_check.test.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/__tests__/status_check.test.ts @@ -310,9 +310,12 @@ describe('status check alert', () => { expect(Object.keys(alert.validate?.params?.props ?? {})).toMatchInlineSnapshot(` Array [ "filters", + "locations", "numTimes", + "search", + "timerangeCount", + "timerangeUnit", "timerange", - "locations", ] `); }); From 68dec305046839c980b1c10de97fa9a9c9ec9ce8 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Fri, 29 May 2020 13:32:26 -0400 Subject: [PATCH 11/35] Fix broken types and refresh snapshots. --- .../__tests__/monitor_status.test.ts | 96 +++---------------- .../public/lib/alert_types/monitor_status.tsx | 10 +- .../__tests__/__snapshots__/ui.test.ts.snap | 2 + .../state/reducers/__tests__/ui.test.ts | 4 + .../state/selectors/__tests__/index.test.ts | 1 + 5 files changed, 26 insertions(+), 87 deletions(-) diff --git a/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts b/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts index b06a7cc93f628..098a999b0d89c 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts +++ b/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts @@ -12,12 +12,9 @@ describe('monitor status alert type', () => { beforeEach(() => { params = { - locations: [], numTimes: 5, - timerange: { - from: 'now-15m', - to: 'now', - }, + timerangeCount: 15, + timerangeUnit: 'm', }; }); @@ -27,9 +24,9 @@ describe('monitor status alert type', () => { "errors": Object { "typeCheckFailure": "Provided parameters do not conform to the expected type.", "typeCheckParsingMessage": Array [ - "Invalid value undefined supplied to : (Partial<{ filters: string }> & { locations: Array, numTimes: number, timerange: { from: string, to: string } })/1: { locations: Array, numTimes: number, timerange: { from: string, to: string } }/locations: Array", - "Invalid value undefined supplied to : (Partial<{ filters: string }> & { locations: Array, numTimes: number, timerange: { from: string, to: string } })/1: { locations: Array, numTimes: number, timerange: { from: string, to: string } }/numTimes: number", - "Invalid value undefined supplied to : (Partial<{ filters: string }> & { locations: Array, numTimes: number, timerange: { from: string, to: string } })/1: { locations: Array, numTimes: number, timerange: { from: string, to: string } }/timerange: { from: string, to: string }", + "Invalid value undefined supplied to : ({ numTimes: number, timerangeCount: number, timerangeUnit: string } & Partial<{ search: string, filters: { monitor.type: Array, observer.geo.name: Array, tags: Array, url.port: Array } }>)/0: { numTimes: number, timerangeCount: number, timerangeUnit: string }/numTimes: number", + "Invalid value undefined supplied to : ({ numTimes: number, timerangeCount: number, timerangeUnit: string } & Partial<{ search: string, filters: { monitor.type: Array, observer.geo.name: Array, tags: Array, url.port: Array } }>)/0: { numTimes: number, timerangeCount: number, timerangeUnit: string }/timerangeCount: number", + "Invalid value undefined supplied to : ({ numTimes: number, timerangeCount: number, timerangeUnit: string } & Partial<{ search: string, filters: { monitor.type: Array, observer.geo.name: Array, tags: Array, url.port: Array } }>)/0: { numTimes: number, timerangeCount: number, timerangeUnit: string }/timerangeUnit: string", ], }, } @@ -37,88 +34,21 @@ describe('monitor status alert type', () => { }); describe('timerange', () => { - it('is undefined', () => { - delete params.timerange; - expect(validate(params)).toMatchInlineSnapshot(` - Object { - "errors": Object { - "typeCheckFailure": "Provided parameters do not conform to the expected type.", - "typeCheckParsingMessage": Array [ - "Invalid value undefined supplied to : (Partial<{ filters: string }> & { locations: Array, numTimes: number, timerange: { from: string, to: string } })/1: { locations: Array, numTimes: number, timerange: { from: string, to: string } }/timerange: { from: string, to: string }", - ], - }, - } - `); - }); - - it('is missing `from` or `to` value', () => { - expect( - validate({ - ...params, - timerange: {}, - }) - ).toMatchInlineSnapshot(` - Object { - "errors": Object { - "typeCheckFailure": "Provided parameters do not conform to the expected type.", - "typeCheckParsingMessage": Array [ - "Invalid value undefined supplied to : (Partial<{ filters: string }> & { locations: Array, numTimes: number, timerange: { from: string, to: string } })/1: { locations: Array, numTimes: number, timerange: { from: string, to: string } }/timerange: { from: string, to: string }/from: string", - "Invalid value undefined supplied to : (Partial<{ filters: string }> & { locations: Array, numTimes: number, timerange: { from: string, to: string } })/1: { locations: Array, numTimes: number, timerange: { from: string, to: string } }/timerange: { from: string, to: string }/to: string", - ], - }, - } - `); - }); - - it('is invalid timespan', () => { - expect( - validate({ - ...params, - timerange: { - from: 'now', - to: 'now-15m', - }, - }) - ).toMatchInlineSnapshot(` - Object { - "errors": Object { - "invalidTimeRange": "Time range start cannot exceed time range end", - }, - } - `); - }); - - it('has unparseable `from` value', () => { - expect( - validate({ - ...params, - timerange: { - from: 'cannot parse this to a date', - to: 'now', - }, - }) - ).toMatchInlineSnapshot(` + it('has invalid timerangeCount value', () => { + expect(validate({ ...params, timerangeCount: 0 })).toMatchInlineSnapshot(` Object { "errors": Object { - "timeRangeStartValueNaN": "Specified time range \`from\` is an invalid value", + "invalidTimeRangeValue": "Time range value must be greater than 0", }, } `); }); - it('has unparseable `to` value', () => { - expect( - validate({ - ...params, - timerange: { - from: 'now-15m', - to: 'cannot parse this to a date', - }, - }) - ).toMatchInlineSnapshot(` + it('has NaN timerangeCount value', () => { + expect(validate({ ...params, timerangeCount: NaN })).toMatchInlineSnapshot(` Object { "errors": Object { - "timeRangeEndValueNaN": "Specified time range \`to\` is an invalid value", + "timeRangeStartValueNaN": "Specified time range value must be a number", }, } `); @@ -133,7 +63,7 @@ describe('monitor status alert type', () => { "errors": Object { "typeCheckFailure": "Provided parameters do not conform to the expected type.", "typeCheckParsingMessage": Array [ - "Invalid value undefined supplied to : (Partial<{ filters: string }> & { locations: Array, numTimes: number, timerange: { from: string, to: string } })/1: { locations: Array, numTimes: number, timerange: { from: string, to: string } }/numTimes: number", + "Invalid value undefined supplied to : ({ numTimes: number, timerangeCount: number, timerangeUnit: string } & Partial<{ search: string, filters: { monitor.type: Array, observer.geo.name: Array, tags: Array, url.port: Array } }>)/0: { numTimes: number, timerangeCount: number, timerangeUnit: string }/numTimes: number", ], }, } @@ -146,7 +76,7 @@ describe('monitor status alert type', () => { "errors": Object { "typeCheckFailure": "Provided parameters do not conform to the expected type.", "typeCheckParsingMessage": Array [ - "Invalid value \\"this isn't a number\\" supplied to : (Partial<{ filters: string }> & { locations: Array, numTimes: number, timerange: { from: string, to: string } })/1: { locations: Array, numTimes: number, timerange: { from: string, to: string } }/numTimes: number", + "Invalid value \\"this isn't a number\\" supplied to : ({ numTimes: number, timerangeCount: number, timerangeUnit: string } & Partial<{ search: string, filters: { monitor.type: Array, observer.geo.name: Array, tags: Array, url.port: Array } }>)/0: { numTimes: number, timerangeCount: number, timerangeUnit: string }/numTimes: number", ], }, } diff --git a/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx index 274e61c11b86c..a39317f8db1ed 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx +++ b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx @@ -6,6 +6,7 @@ import React from 'react'; import { isRight } from 'fp-ts/lib/Either'; +import { PathReporter } from 'io-ts/lib/PathReporter'; import { AlertTypeModel } from '../../../../triggers_actions_ui/public'; import { AlertTypeInitializer } from '.'; import { AtomicStatusCheckParamsType } from '../../../common/runtime_types'; @@ -13,14 +14,15 @@ import { MonitorStatusTitle } from './monitor_status_title'; import { CLIENT_ALERT_TYPES } from '../../../common/constants'; import { MonitorStatusTranslations } from './translations'; -export const validate = (alertParams: any) => { +export const validate = (alertParams: unknown) => { const errors: Record = {}; - const newDecoded = AtomicStatusCheckParamsType.decode(alertParams); + const decoded = AtomicStatusCheckParamsType.decode(alertParams); - if (!isRight(newDecoded)) { + if (!isRight(decoded)) { errors.typeCheckFailure = 'Provided parameters do not conform to the expected type.'; + errors.typeCheckParsingMessage = PathReporter.report(decoded); } else { - const { numTimes, timerangeCount } = newDecoded.right; + const { numTimes, timerangeCount } = decoded.right; if (numTimes < 1) { errors.invalidNumTimes = 'Number of alert check down times must be an integer greater than 0'; } diff --git a/x-pack/plugins/uptime/public/state/reducers/__tests__/__snapshots__/ui.test.ts.snap b/x-pack/plugins/uptime/public/state/reducers/__tests__/__snapshots__/ui.test.ts.snap index f8faf78fbc504..c11b146101d35 100644 --- a/x-pack/plugins/uptime/public/state/reducers/__tests__/__snapshots__/ui.test.ts.snap +++ b/x-pack/plugins/uptime/public/state/reducers/__tests__/__snapshots__/ui.test.ts.snap @@ -9,6 +9,7 @@ Object { "id": "popover-2", "open": true, }, + "searchText": "", } `; @@ -18,5 +19,6 @@ Object { "basePath": "yyz", "esKuery": "", "integrationsPopoverOpen": null, + "searchText": "", } `; diff --git a/x-pack/plugins/uptime/public/state/reducers/__tests__/ui.test.ts b/x-pack/plugins/uptime/public/state/reducers/__tests__/ui.test.ts index 94bc626088c84..3b8447ec2d713 100644 --- a/x-pack/plugins/uptime/public/state/reducers/__tests__/ui.test.ts +++ b/x-pack/plugins/uptime/public/state/reducers/__tests__/ui.test.ts @@ -18,6 +18,7 @@ describe('ui reducer', () => { basePath: 'abc', esKuery: '', integrationsPopoverOpen: null, + searchText: '', }, action ) @@ -36,6 +37,7 @@ describe('ui reducer', () => { basePath: '', esKuery: '', integrationsPopoverOpen: null, + searchText: '', }, action ) @@ -51,6 +53,7 @@ describe('ui reducer', () => { basePath: '', esKuery: '', integrationsPopoverOpen: null, + searchText: '', }, action ) @@ -60,6 +63,7 @@ describe('ui reducer', () => { "basePath": "", "esKuery": "", "integrationsPopoverOpen": null, + "searchText": "", } `); }); diff --git a/x-pack/plugins/uptime/public/state/selectors/__tests__/index.test.ts b/x-pack/plugins/uptime/public/state/selectors/__tests__/index.test.ts index d8121e29d0cae..2eb0f1e8cb0ee 100644 --- a/x-pack/plugins/uptime/public/state/selectors/__tests__/index.test.ts +++ b/x-pack/plugins/uptime/public/state/selectors/__tests__/index.test.ts @@ -44,6 +44,7 @@ describe('state selectors', () => { basePath: 'yyz', esKuery: '', integrationsPopoverOpen: null, + searchText: '', }, monitorStatus: { status: null, From ccea1f047c0e698635627a4213c55fd313ed9052 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Tue, 2 Jun 2020 09:42:14 -0400 Subject: [PATCH 12/35] Allow edits of filters for monitor alerts. --- .../overview/alerts/alert_monitor_status.tsx | 12 ++++-- .../alert_monitor_status.tsx | 41 ++++++++++++++++--- .../filters_expression_select.tsx | 36 ++++++---------- .../uptime/public/hooks/use_filter_update.ts | 11 +++-- .../public/state/actions/overview_filters.ts | 14 ++++++- .../public/state/reducers/overview_filters.ts | 6 +++ 6 files changed, 84 insertions(+), 36 deletions(-) diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx index e2e44124ec659..1541fa464cfbc 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { EuiSpacer } from '@elastic/eui'; import { DataPublicPluginSetup } from 'src/plugins/data/public'; import * as labels from './translations'; @@ -31,9 +31,12 @@ interface AlertMonitorStatusProps { } export const AlertMonitorStatusComponent: React.FC = (props) => { - const { filters, setAlertParams } = props; + const { alertParams, filters, setFilters, setAlertParams } = props; - const [newFilters, setNewFilters] = useState([]); + const alertFilters = alertParams?.filters ?? {}; + const [newFilters, setNewFilters] = useState( + Object.keys(alertFilters).filter((f) => alertFilters[f].length) + ); return ( <> @@ -56,6 +59,9 @@ export const AlertMonitorStatusComponent: React.FC = (p { if (newFilters.includes(removeFiler)) { diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx index d5d207344b6f2..e21aee4abe2e0 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx @@ -4,11 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useEffect } from 'react'; -import { useSelector } from 'react-redux'; +import React, { useEffect, useCallback } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; import { DataPublicPluginSetup } from 'src/plugins/data/public'; -import { selectMonitorStatusAlert, selectSearchText } from '../../../../state/selectors'; +import { + selectMonitorStatusAlert, + selectSearchText, + overviewFiltersSelector, +} from '../../../../state/selectors'; import { AlertMonitorStatusComponent } from '../index'; +import { setOverviewFilters, fetchOverviewFilters } from '../../../../state/actions'; interface Props { autocomplete: DataPublicPluginSetup['autocomplete']; @@ -27,10 +32,34 @@ export const AlertMonitorStatus: React.FC = ({ numTimes, setAlertParams, timerange, + alertParams, }) => { + const dispatch = useDispatch(); + useEffect(() => { + dispatch( + fetchOverviewFilters({ + dateRangeStart: `now-${alertParams?.timerangeCount ?? 15}${ + alertParams?.timerangeUnit ?? 'd' + }`, + dateRangeEnd: 'now', + locations: alertParams?.filters['observer.geo.name'] ?? [], + ports: alertParams?.filters['url.port'] ?? [], + tags: alertParams?.filters.tags ?? [], + schemes: alertParams?.filters['monitor.type'] ?? [], + }) + ); + }, [alertParams, dispatch]); + + const setFilters = useCallback( + (filters: any) => { + dispatch(setOverviewFilters(filters)); + }, + [dispatch] + ); + + const overviewFilters = useSelector(overviewFiltersSelector); const { filters, locations } = useSelector(selectMonitorStatusAlert); const searchText = useSelector(selectSearchText); - useEffect(() => { setAlertParams('search', searchText); }, [setAlertParams, searchText]); @@ -39,7 +68,9 @@ export const AlertMonitorStatus: React.FC = ({ = ({ setAlertParams, newFilters, onRemoveFilter, + filters, + setFilters, + alertParams, }) => { const { filters: { tags, ports, schemes, locations }, } = useSelector(overviewFiltersSelector); - const [updatedFieldValues, setUpdatedFieldValues] = useState<{ - fieldName: string; - values: string[]; - }>({ fieldName: '', values: [] }); - - const { selectedLocations, selectedPorts, selectedSchemes, selectedTags } = useFilterUpdate( - updatedFieldValues.fieldName, - updatedFieldValues.values - ); - - const [filters, setFilters] = useState({ - 'observer.geo.name': selectedLocations, - 'url.port': selectedPorts, - tags: selectedTags, - 'monitor.type': selectedSchemes, - }); - - useEffect(() => { - setAlertParams('filters', filters); - }, [filters, setAlertParams]); + const selectedPorts = alertParams?.filters['url.port'] ?? []; + const selectedLocations = alertParams?.filters['observer.geo.name'] ?? []; + const selectedSchemes = alertParams?.filters['monitor.type'] ?? []; + const selectedTags = alertParams?.filters?.tags ?? []; const onFilterFieldChange = (fieldName: string, values: string[]) => { setFilters({ ...filters, [fieldName]: values, }); - setUpdatedFieldValues({ fieldName, values }); + + if (alertParams.filters) { + setAlertParams('filters', { ...alertParams.filters, [fieldName]: values }); + } }; const monitorFilters = [ diff --git a/x-pack/plugins/uptime/public/hooks/use_filter_update.ts b/x-pack/plugins/uptime/public/hooks/use_filter_update.ts index 550de134c49bc..54b94b8c98843 100644 --- a/x-pack/plugins/uptime/public/hooks/use_filter_update.ts +++ b/x-pack/plugins/uptime/public/hooks/use_filter_update.ts @@ -20,14 +20,19 @@ interface SelectedFilters { selectedFilters: Map; } -export const useFilterUpdate = (fieldName?: string, values?: string[]): SelectedFilters => { +export const useFilterUpdate = ( + fieldName?: string, + values?: string[], + shouldUpdateUrl?: boolean, + alertParamFilters?: any +): SelectedFilters => { const [getUrlParams, updateUrl] = useUrlParams(); const { filters: currentFilters } = getUrlParams(); // update filters in the URL from filter group const onFilterUpdate = (filtersKuery: string) => { - if (currentFilters !== filtersKuery) { + if (currentFilters !== filtersKuery && shouldUpdateUrl) { updateUrl({ filters: filtersKuery, pagination: '' }); } }; @@ -57,7 +62,7 @@ export const useFilterUpdate = (fieldName?: string, values?: string[]): Selected } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [fieldName, values]); + }, [alertParamFilters, fieldName, values]); return { selectedTags: filterKueries.get('tags') || [], diff --git a/x-pack/plugins/uptime/public/state/actions/overview_filters.ts b/x-pack/plugins/uptime/public/state/actions/overview_filters.ts index dbbd01e34b4d4..8eefa701a240a 100644 --- a/x-pack/plugins/uptime/public/state/actions/overview_filters.ts +++ b/x-pack/plugins/uptime/public/state/actions/overview_filters.ts @@ -9,6 +9,7 @@ import { OverviewFilters } from '../../../common/runtime_types'; export const FETCH_OVERVIEW_FILTERS = 'FETCH_OVERVIEW_FILTERS'; export const FETCH_OVERVIEW_FILTERS_FAIL = 'FETCH_OVERVIEW_FILTERS_FAIL'; export const FETCH_OVERVIEW_FILTERS_SUCCESS = 'FETCH_OVERVIEW_FILTERS_SUCCESS'; +export const SET_OVERVIEW_FILTERS = 'SET_OVERVIEW_FILTERS'; export interface GetOverviewFiltersPayload { dateRangeStart: string; @@ -36,10 +37,16 @@ interface GetOverviewFiltersFailAction { payload: Error; } +interface SetOverviewFiltersAction { + type: typeof SET_OVERVIEW_FILTERS; + payload: OverviewFilters; +} + export type OverviewFiltersAction = | GetOverviewFiltersFetchAction | GetOverviewFiltersSuccessAction - | GetOverviewFiltersFailAction; + | GetOverviewFiltersFailAction + | SetOverviewFiltersAction; export const fetchOverviewFilters = ( payload: GetOverviewFiltersPayload @@ -59,3 +66,8 @@ export const fetchOverviewFiltersSuccess = ( type: FETCH_OVERVIEW_FILTERS_SUCCESS, payload: filters, }); + +export const setOverviewFilters = (filters: OverviewFilters): SetOverviewFiltersAction => ({ + type: SET_OVERVIEW_FILTERS, + payload: filters, +}); diff --git a/x-pack/plugins/uptime/public/state/reducers/overview_filters.ts b/x-pack/plugins/uptime/public/state/reducers/overview_filters.ts index 0b67d8b0e7689..4548627d9dcb8 100644 --- a/x-pack/plugins/uptime/public/state/reducers/overview_filters.ts +++ b/x-pack/plugins/uptime/public/state/reducers/overview_filters.ts @@ -10,6 +10,7 @@ import { FETCH_OVERVIEW_FILTERS_FAIL, FETCH_OVERVIEW_FILTERS_SUCCESS, OverviewFiltersAction, + SET_OVERVIEW_FILTERS, } from '../actions'; export interface OverviewFiltersState { @@ -51,6 +52,11 @@ export function overviewFiltersReducer( errors: [...state.errors, action.payload], loading: false, }; + case SET_OVERVIEW_FILTERS: + return { + ...state, + filters: action.payload, + }; default: return state; } From 4caaeca5c236c7b806e797ace22f2718bdf444de Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Tue, 2 Jun 2020 10:19:11 -0400 Subject: [PATCH 13/35] Support default parameter value for numTimes. --- .../components/overview/alerts/alert_monitor_status.tsx | 6 +++++- .../alerts/monitor_expressions/down_number_select.tsx | 9 +++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx index 1541fa464cfbc..e21e0feb59108 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx @@ -49,7 +49,11 @@ export const AlertMonitorStatusComponent: React.FC = (p - + diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/down_number_select.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/down_number_select.tsx index 7f68aef8e179c..61ff128409900 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/down_number_select.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/down_number_select.tsx @@ -12,10 +12,15 @@ import { AlertFieldNumber } from '../alert_field_number'; interface Props { setAlertParams: (key: string, value: any) => void; filters: string; + defaultNumTimes?: number; } -export const DownNoExpressionSelect: React.FC = ({ filters, setAlertParams }) => { - const [numTimes, setNumTimes] = useState(5); +export const DownNoExpressionSelect: React.FC = ({ + defaultNumTimes, + filters, + setAlertParams, +}) => { + const [numTimes, setNumTimes] = useState(defaultNumTimes ?? 5); useEffect(() => { setAlertParams('numTimes', numTimes); From 93739f5147ed426811a73c35fe149164bbbcf8c8 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Tue, 2 Jun 2020 10:31:38 -0400 Subject: [PATCH 14/35] Support default parameter values for timerange. --- .../overview/alerts/alert_monitor_status.tsx | 6 +++++- .../time_expression_select.tsx | 17 +++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx index e21e0feb59108..1ce5f87794044 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx @@ -57,7 +57,11 @@ export const AlertMonitorStatusComponent: React.FC = (p - + diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/time_expression_select.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/time_expression_select.tsx index e3893845862fb..2a338a93597a2 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/time_expression_select.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/time_expression_select.tsx @@ -13,6 +13,8 @@ import { AlertFieldNumber } from '../alert_field_number'; import { timeExpLabels } from './translations'; interface Props { + defaultTimerangeCount?: number; + defaultTimerangeUnit?: string; setAlertParams: (key: string, value: any) => void; } @@ -26,7 +28,6 @@ const TimeRangeOptions = [ { 'aria-label': labels.MINUTES_TIME_RANGE, 'data-test-subj': 'xpack.uptime.alerts.monitorStatus.timerangeUnitSelectable.minutesOption', - checked: 'on', key: 'm', label: labels.MINUTES, }, @@ -44,10 +45,18 @@ const TimeRangeOptions = [ }, ]; -export const TimeExpressionSelect: React.FC = ({ setAlertParams }) => { - const [numUnits, setNumUnits] = useState(15); +export const TimeExpressionSelect: React.FC = ({ + defaultTimerangeCount, + defaultTimerangeUnit, + setAlertParams, +}) => { + const [numUnits, setNumUnits] = useState(defaultTimerangeCount ?? 15); - const [timerangeUnitOptions, setTimerangeUnitOptions] = useState(TimeRangeOptions); + const [timerangeUnitOptions, setTimerangeUnitOptions] = useState( + TimeRangeOptions.map((opt) => + opt.key === defaultTimerangeUnit ?? 'm' ? { ...opt, checked: 'on' } : opt + ) + ); useEffect(() => { const timerangeUnit = timerangeUnitOptions.find(({ checked }) => checked === 'on')?.key ?? 'm'; From c93037ea6fafb9be2ee1cda00b96f9ddd8f8d08b Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Tue, 2 Jun 2020 13:20:48 -0400 Subject: [PATCH 15/35] Modify kuery bar to work for alert edits, fix some filter issues. --- .../overview/alerts/alert_monitor_status.tsx | 5 +++- .../alert_monitor_status.tsx | 16 ++++++------ .../filters_expression_select.tsx | 25 +++++++++++++------ .../time_expression_select.tsx | 4 ++- .../overview/kuery_bar/kuery_bar.tsx | 16 ++++++++++-- 5 files changed, 47 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx index 1ce5f87794044..c3a16d5d6da08 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useEffect, useState } from 'react'; +import React, { useState } from 'react'; import { EuiSpacer } from '@elastic/eui'; import { DataPublicPluginSetup } from 'src/plugins/data/public'; import * as labels from './translations'; @@ -44,6 +44,9 @@ export const AlertMonitorStatusComponent: React.FC = (p setAlertParams('search', value)} data-test-subj="xpack.uptime.alerts.monitorStatus.filterBar" /> diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx index e21aee4abe2e0..0e09e68cc55c0 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx @@ -13,7 +13,7 @@ import { overviewFiltersSelector, } from '../../../../state/selectors'; import { AlertMonitorStatusComponent } from '../index'; -import { setOverviewFilters, fetchOverviewFilters } from '../../../../state/actions'; +import { setOverviewFilters, fetchOverviewFilters, setSearchText } from '../../../../state/actions'; interface Props { autocomplete: DataPublicPluginSetup['autocomplete']; @@ -42,10 +42,10 @@ export const AlertMonitorStatus: React.FC = ({ alertParams?.timerangeUnit ?? 'd' }`, dateRangeEnd: 'now', - locations: alertParams?.filters['observer.geo.name'] ?? [], - ports: alertParams?.filters['url.port'] ?? [], - tags: alertParams?.filters.tags ?? [], - schemes: alertParams?.filters['monitor.type'] ?? [], + locations: alertParams.filters?.['observer.geo.name'] ?? [], + ports: alertParams.filters?.['url.port'] ?? [], + tags: alertParams.filters?.tags ?? [], + schemes: alertParams.filters?.['monitor.type'] ?? [], }) ); }, [alertParams, dispatch]); @@ -61,8 +61,10 @@ export const AlertMonitorStatus: React.FC = ({ const { filters, locations } = useSelector(selectMonitorStatusAlert); const searchText = useSelector(selectSearchText); useEffect(() => { - setAlertParams('search', searchText); - }, [setAlertParams, searchText]); + if (alertParams.search) { + dispatch(setSearchText(alertParams.search)); + } + }, [alertParams, dispatch]); return ( = ({ filters: { tags, ports, schemes, locations }, } = useSelector(overviewFiltersSelector); - const selectedPorts = alertParams?.filters['url.port'] ?? []; - const selectedLocations = alertParams?.filters['observer.geo.name'] ?? []; - const selectedSchemes = alertParams?.filters['monitor.type'] ?? []; + const selectedPorts = alertParams?.filters?.['url.port'] ?? []; + const selectedLocations = alertParams?.filters?.['observer.geo.name'] ?? []; + const selectedSchemes = alertParams?.filters?.['monitor.type'] ?? []; const selectedTags = alertParams?.filters?.tags ?? []; const onFilterFieldChange = (fieldName: string, values: string[]) => { - setFilters({ - ...filters, - [fieldName]: values, - }); - if (alertParams.filters) { setAlertParams('filters', { ...alertParams.filters, [fieldName]: values }); + } else { + setAlertParams( + 'filters', + Object.assign( + {}, + { + tags: [], + 'url.port': [], + 'observer.geo.name': [], + 'monitor.type': [], + }, + { [fieldName]: values } + ) + ); } }; diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/time_expression_select.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/time_expression_select.tsx index 2a338a93597a2..44bfbff6817c4 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/time_expression_select.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/time_expression_select.tsx @@ -18,6 +18,8 @@ interface Props { setAlertParams: (key: string, value: any) => void; } +const DEFAULT_TIMERANGE_UNIT = 'm'; + const TimeRangeOptions = [ { 'aria-label': labels.SECONDS_TIME_RANGE, @@ -54,7 +56,7 @@ export const TimeExpressionSelect: React.FC = ({ const [timerangeUnitOptions, setTimerangeUnitOptions] = useState( TimeRangeOptions.map((opt) => - opt.key === defaultTimerangeUnit ?? 'm' ? { ...opt, checked: 'on' } : opt + opt.key === (defaultTimerangeUnit ?? DEFAULT_TIMERANGE_UNIT) ? { ...opt, checked: 'on' } : opt ) ); diff --git a/x-pack/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx b/x-pack/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx index 5c0ee632a2bda..8949614c53b6b 100644 --- a/x-pack/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx +++ b/x-pack/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx @@ -36,13 +36,19 @@ function convertKueryToEsQuery(kuery: string, indexPattern: IIndexPattern) { interface Props { 'aria-label': string; autocomplete: DataPublicPluginSetup['autocomplete']; + updateDefaultKuery?: (value: string) => void; + defaultKuery?: string; 'data-test-subj': string; + shouldUpdateUrl?: boolean; } export function KueryBar({ 'aria-label': ariaLabel, autocomplete: autocompleteService, + defaultKuery, + updateDefaultKuery, 'data-test-subj': dataTestSubj, + shouldUpdateUrl, }: Props) { const { loading, index_pattern: indexPattern } = useIndexPattern(); const { updateSearchText } = useSearchText(); @@ -73,6 +79,10 @@ export function KueryBar({ setIsLoadingSuggestions(true); setState({ ...state, suggestions: [] }); + if (updateDefaultKuery) { + updateDefaultKuery(inputValue); + } + const currentRequest = uniqueId(); currentRequestCheck = currentRequest; @@ -112,7 +122,9 @@ export function KueryBar({ return; } - updateUrlParams({ search: inputValue.trim() }); + if (shouldUpdateUrl !== false) { + updateUrlParams({ search: inputValue.trim() }); + } } catch (e) { console.log('Invalid kuery syntax'); // eslint-disable-line no-console } @@ -125,7 +137,7 @@ export function KueryBar({ data-test-subj={dataTestSubj} disabled={indexPatternMissing} isLoading={isLoadingSuggestions || loading} - initialValue={kuery} + initialValue={defaultKuery || kuery} onChange={onChange} onSubmit={onSubmit} suggestions={state.suggestions} From 87df991d6717d85d36f63c00a60d83275658f546 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Tue, 2 Jun 2020 14:53:44 -0400 Subject: [PATCH 16/35] Clean up tests and fix types. --- .../overview/alerts/alert_monitor_status.tsx | 9 ++++--- .../alert_monitor_status.tsx | 24 +++++-------------- .../__tests__/down_number_select.test.tsx | 8 ++----- .../down_number_select.tsx | 6 ++--- .../filters_expression_select.tsx | 3 +-- .../framework/new_platform_adapter.tsx | 5 ---- .../__tests__/monitor_status.test.ts | 8 +++++-- .../uptime/public/lib/alert_types/tls.tsx | 13 ++++++---- 8 files changed, 31 insertions(+), 45 deletions(-) diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx index c3a16d5d6da08..de3481cadbb0e 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx @@ -18,9 +18,10 @@ import { AddFilterButton } from './add_filter_btn'; import { KueryBar } from '..'; interface AlertMonitorStatusProps { + alertParams: { [key: string]: any }; autocomplete: DataPublicPluginSetup['autocomplete']; enabled: boolean; - filters: string; + hasFilters: boolean; locations: string[]; numTimes: number; setAlertParams: (key: string, value: any) => void; @@ -31,7 +32,7 @@ interface AlertMonitorStatusProps { } export const AlertMonitorStatusComponent: React.FC = (props) => { - const { alertParams, filters, setFilters, setAlertParams } = props; + const { alertParams, hasFilters, setAlertParams } = props; const alertFilters = alertParams?.filters ?? {}; const [newFilters, setNewFilters] = useState( @@ -54,7 +55,7 @@ export const AlertMonitorStatusComponent: React.FC = (p @@ -70,8 +71,6 @@ export const AlertMonitorStatusComponent: React.FC = (p { diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx index 0e09e68cc55c0..70ea2acce1f8a 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx @@ -4,18 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useEffect, useCallback } from 'react'; +import React, { useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { DataPublicPluginSetup } from 'src/plugins/data/public'; -import { - selectMonitorStatusAlert, - selectSearchText, - overviewFiltersSelector, -} from '../../../../state/selectors'; +import { selectMonitorStatusAlert, overviewFiltersSelector } from '../../../../state/selectors'; import { AlertMonitorStatusComponent } from '../index'; -import { setOverviewFilters, fetchOverviewFilters, setSearchText } from '../../../../state/actions'; +import { fetchOverviewFilters, setSearchText } from '../../../../state/actions'; interface Props { + alertParams: { [key: string]: any }; autocomplete: DataPublicPluginSetup['autocomplete']; enabled: boolean; numTimes: number; @@ -50,16 +47,8 @@ export const AlertMonitorStatus: React.FC = ({ ); }, [alertParams, dispatch]); - const setFilters = useCallback( - (filters: any) => { - dispatch(setOverviewFilters(filters)); - }, - [dispatch] - ); - const overviewFilters = useSelector(overviewFiltersSelector); - const { filters, locations } = useSelector(selectMonitorStatusAlert); - const searchText = useSelector(selectSearchText); + const { locations } = useSelector(selectMonitorStatusAlert); useEffect(() => { if (alertParams.search) { dispatch(setSearchText(alertParams.search)); @@ -70,9 +59,8 @@ export const AlertMonitorStatus: React.FC = ({ { - const filters = - '"{"bool":{"filter":[{"bool":{"should":[{"match":{"observer.geo.name":"US-West"}}],"minimum_should_match":1}},' + - '{"bool":{"should":[{"match":{"url.port":443}}],"minimum_should_match":1}}]}}"'; - it('should shallow renders against props', function () { const component = shallowWithIntl( - + ); expect(component).toMatchSnapshot(); }); it('should renders against props', function () { const component = renderWithIntl( - + ); expect(component).toMatchSnapshot(); }); diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/down_number_select.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/down_number_select.tsx index 61ff128409900..352ed8ac45613 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/down_number_select.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/down_number_select.tsx @@ -11,13 +11,13 @@ import { AlertFieldNumber } from '../alert_field_number'; interface Props { setAlertParams: (key: string, value: any) => void; - filters: string; + hasFilters: boolean; defaultNumTimes?: number; } export const DownNoExpressionSelect: React.FC = ({ defaultNumTimes, - filters, + hasFilters, setAlertParams, }) => { const [numTimes, setNumTimes] = useState(defaultNumTimes ?? 5); @@ -39,7 +39,7 @@ export const DownNoExpressionSelect: React.FC = ({ /> } data-test-subj="xpack.uptime.alerts.monitorStatus.numTimesExpression" - description={filters ? labels.MATCHING_MONITORS_DOWN : labels.ANY_MONITOR_DOWN} + description={hasFilters ? labels.MATCHING_MONITORS_DOWN : labels.ANY_MONITOR_DOWN} id="ping-count" value={`${numTimes} times`} /> diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select.tsx index e0a87bdacc119..a559e730a9757 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select.tsx @@ -13,6 +13,7 @@ import { filterLabels } from '../../filter_group/translations'; import { alertFilterLabels } from './translations'; interface Props { + alertParams: { [key: string]: any }; newFilters: string[]; onRemoveFilter: (val: string) => void; setAlertParams: (key: string, value: any) => void; @@ -22,8 +23,6 @@ export const FiltersExpressionsSelect: React.FC = ({ setAlertParams, newFilters, onRemoveFilter, - filters, - setFilters, alertParams, }) => { const { diff --git a/x-pack/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx b/x-pack/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx index 8fa202dd4cb0c..329b33e60fead 100644 --- a/x-pack/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx +++ b/x-pack/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx @@ -36,11 +36,6 @@ export const getKibanaFrameworkAdapter = ( i18n, } = core; - let breadcrumbs: ChromeBreadcrumb[] = []; - core.chrome.getBreadcrumbs$().subscribe((nextBreadcrumbs?: ChromeBreadcrumb[]) => { - breadcrumbs = nextBreadcrumbs || []; - }); - const { apm, infrastructure, logs } = getIntegratedAppAvailability( capabilities, INTEGRATED_SOLUTIONS diff --git a/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts b/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts index 7a0b4e5a38c8c..a5645e3925479 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts +++ b/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts @@ -98,7 +98,6 @@ describe('monitor status alert type', () => { describe('initMonitorStatusAlertType', () => { expect( initMonitorStatusAlertType({ - autocomplete: {}, store: { dispatch: jest.fn(), getState: jest.fn(), @@ -106,6 +105,11 @@ describe('monitor status alert type', () => { subscribe: jest.fn(), [Symbol.observable]: jest.fn(), }, + // @ts-ignore we don't need to test this functionality here because + // it's not used by the code this file tests + core: {}, + // @ts-ignore + plugins: {}, }) ).toMatchInlineSnapshot(` Object { @@ -128,7 +132,7 @@ describe('monitor status alert type', () => { > , - "requiresAppContext": true, + "requiresAppContext": false, "validate": [Function], } `); diff --git a/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx b/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx index 6fe563dd8ee87..a3c629bb6f31c 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx +++ b/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx @@ -10,11 +10,12 @@ import { AlertTypeModel } from '../../../../triggers_actions_ui/public'; import { CLIENT_ALERT_TYPES } from '../../../common/constants'; import { TlsTranslations } from './translations'; import { AlertTypeInitializer } from '.'; -import { AlertTls } from '../../components/overview/alerts/alerts_containers/alert_tls'; import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; const { name, defaultActionMessage } = TlsTranslations; - +const TlsAlertExpression = React.lazy(() => + import('../../components/overview/alerts/alerts_containers/alert_tls') +); export const initTlsAlertType: AlertTypeInitializer = ({ store, core, @@ -22,8 +23,12 @@ export const initTlsAlertType: AlertTypeInitializer = ({ }): AlertTypeModel => ({ id: CLIENT_ALERT_TYPES.TLS, iconClass: 'uptimeApp', - alertParamsExpression: React.lazy(() => - import('../../components/overview/alerts/alerts_containers/alert_tls') + alertParamsExpression: (_params: any) => ( + + + + + ), name, validate: () => ({ errors: {} }), From af77c7a98c850a83885ad77c9eb79a720542b9e1 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Tue, 2 Jun 2020 23:06:52 -0400 Subject: [PATCH 17/35] Fix types and add a test. --- .../alert_monitor_status.tsx | 8 +++-- .../down_number_select.tsx | 4 +-- .../overview/kuery_bar/kuery_bar.tsx | 4 +-- .../contexts/uptime_refresh_context.tsx | 23 +++++--------- .../framework/new_platform_adapter.tsx | 2 +- .../state/reducers/__tests__/ui.test.ts | 31 ++++++++++++++++++- x-pack/plugins/uptime/public/uptime_app.tsx | 2 +- 7 files changed, 48 insertions(+), 26 deletions(-) diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx index 70ea2acce1f8a..cbfb6944ea532 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx @@ -33,11 +33,13 @@ export const AlertMonitorStatus: React.FC = ({ }) => { const dispatch = useDispatch(); useEffect(() => { + // example output: `now-13h` + const dateRangeStart = `now-${alertParams?.timerangeCount ?? 15}${ + alertParams?.timerangeUnit ?? 'd' + }`; dispatch( fetchOverviewFilters({ - dateRangeStart: `now-${alertParams?.timerangeCount ?? 15}${ - alertParams?.timerangeUnit ?? 'd' - }`, + dateRangeStart, dateRangeEnd: 'now', locations: alertParams.filters?.['observer.geo.name'] ?? [], ports: alertParams.filters?.['url.port'] ?? [], diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/down_number_select.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/down_number_select.tsx index 352ed8ac45613..0eb53eb044bc5 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/down_number_select.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/down_number_select.tsx @@ -10,9 +10,9 @@ import * as labels from '../translations'; import { AlertFieldNumber } from '../alert_field_number'; interface Props { - setAlertParams: (key: string, value: any) => void; - hasFilters: boolean; defaultNumTimes?: number; + hasFilters: boolean; + setAlertParams: (key: string, value: any) => void; } export const DownNoExpressionSelect: React.FC = ({ diff --git a/x-pack/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx b/x-pack/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx index 8949614c53b6b..15d8db97f7c4a 100644 --- a/x-pack/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx +++ b/x-pack/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx @@ -36,19 +36,19 @@ function convertKueryToEsQuery(kuery: string, indexPattern: IIndexPattern) { interface Props { 'aria-label': string; autocomplete: DataPublicPluginSetup['autocomplete']; - updateDefaultKuery?: (value: string) => void; defaultKuery?: string; 'data-test-subj': string; shouldUpdateUrl?: boolean; + updateDefaultKuery?: (value: string) => void; } export function KueryBar({ 'aria-label': ariaLabel, autocomplete: autocompleteService, defaultKuery, - updateDefaultKuery, 'data-test-subj': dataTestSubj, shouldUpdateUrl, + updateDefaultKuery, }: Props) { const { loading, index_pattern: indexPattern } = useIndexPattern(); const { updateSearchText } = useSearchText(); diff --git a/x-pack/plugins/uptime/public/contexts/uptime_refresh_context.tsx b/x-pack/plugins/uptime/public/contexts/uptime_refresh_context.tsx index e06038ac6cde7..b78a6492e2dcd 100644 --- a/x-pack/plugins/uptime/public/contexts/uptime_refresh_context.tsx +++ b/x-pack/plugins/uptime/public/contexts/uptime_refresh_context.tsx @@ -5,18 +5,12 @@ */ import React, { createContext, useMemo, useState } from 'react'; -import { Store } from 'redux'; -import { triggerAppRefresh } from '../state/actions'; interface UptimeRefreshContext { lastRefresh: number; refreshApp: () => void; } -interface RefreshContextProps { - store: Store; -} - const defaultContext: UptimeRefreshContext = { lastRefresh: 0, refreshApp: () => { @@ -26,20 +20,17 @@ const defaultContext: UptimeRefreshContext = { export const UptimeRefreshContext = createContext(defaultContext); -export const UptimeRefreshContextProvider: React.FC = ({ - children, - store, -}) => { +export const UptimeRefreshContextProvider: React.FC = ({ children }) => { const [lastRefresh, setLastRefresh] = useState(Date.now()); + const refreshApp = () => { + const refreshTime = Date.now(); + setLastRefresh(refreshTime); + }; + const value = useMemo(() => { - const refreshApp = () => { - const refreshTime = Date.now(); - setLastRefresh(refreshTime); - store.dispatch(triggerAppRefresh(refreshTime)); - }; return { lastRefresh, refreshApp }; - }, [lastRefresh, store]); + }, [lastRefresh]); return ; }; diff --git a/x-pack/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx b/x-pack/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx index 329b33e60fead..f1c06daa1dc69 100644 --- a/x-pack/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx +++ b/x-pack/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { CoreStart, ChromeBreadcrumb } from 'src/core/public'; +import { CoreStart } from 'src/core/public'; import React from 'react'; import ReactDOM from 'react-dom'; import { get } from 'lodash'; diff --git a/x-pack/plugins/uptime/public/state/reducers/__tests__/ui.test.ts b/x-pack/plugins/uptime/public/state/reducers/__tests__/ui.test.ts index 3b8447ec2d713..91b840079a22f 100644 --- a/x-pack/plugins/uptime/public/state/reducers/__tests__/ui.test.ts +++ b/x-pack/plugins/uptime/public/state/reducers/__tests__/ui.test.ts @@ -4,7 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { setBasePath, toggleIntegrationsPopover, setAlertFlyoutVisible } from '../../actions'; +import { + setBasePath, + toggleIntegrationsPopover, + setAlertFlyoutVisible, + setSearchText, +} from '../../actions'; import { uiReducer } from '../ui'; import { Action } from 'redux-actions'; @@ -67,4 +72,28 @@ describe('ui reducer', () => { } `); }); + + it('sets the search text', () => { + const action = setSearchText('lorem ipsum') as Action; + expect( + uiReducer( + { + alertFlyoutVisible: false, + basePath: '', + esKuery: '', + integrationsPopoverOpen: null, + searchText: '', + }, + action + ) + ).toMatchInlineSnapshot(` + Object { + "alertFlyoutVisible": false, + "basePath": "", + "esKuery": "", + "integrationsPopoverOpen": null, + "searchText": "lorem ipsum", + } + `); + }); }); diff --git a/x-pack/plugins/uptime/public/uptime_app.tsx b/x-pack/plugins/uptime/public/uptime_app.tsx index 88f33acaf583d..470e3018a50e6 100644 --- a/x-pack/plugins/uptime/public/uptime_app.tsx +++ b/x-pack/plugins/uptime/public/uptime_app.tsx @@ -96,7 +96,7 @@ const Application = (props: UptimeAppProps) => { - + From 604c889e9358e348dfd053a5e51242fac313f343 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Thu, 4 Jun 2020 10:43:59 -0400 Subject: [PATCH 18/35] Add callout and validation handling for old alerts while editing. --- .../overview/alerts/alert_monitor_status.tsx | 22 +++++++++++++++++-- .../alert_monitor_status.tsx | 9 +++++++- .../filters_expression_select.tsx | 3 ++- .../public/lib/alert_types/monitor_status.tsx | 16 +++++++++----- 4 files changed, 41 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx index de3481cadbb0e..dfc6a046186c5 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx @@ -5,7 +5,8 @@ */ import React, { useState } from 'react'; -import { EuiSpacer } from '@elastic/eui'; +import { EuiCallOut, EuiSpacer } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; import { DataPublicPluginSetup } from 'src/plugins/data/public'; import * as labels from './translations'; import { @@ -22,6 +23,7 @@ interface AlertMonitorStatusProps { autocomplete: DataPublicPluginSetup['autocomplete']; enabled: boolean; hasFilters: boolean; + isOldAlert: boolean; locations: string[]; numTimes: number; setAlertParams: (key: string, value: any) => void; @@ -32,7 +34,7 @@ interface AlertMonitorStatusProps { } export const AlertMonitorStatusComponent: React.FC = (props) => { - const { alertParams, hasFilters, setAlertParams } = props; + const { alertParams, hasFilters, isOldAlert, setAlertParams } = props; const alertFilters = alertParams?.filters ?? {}; const [newFilters, setNewFilters] = useState( @@ -42,6 +44,22 @@ export const AlertMonitorStatusComponent: React.FC = (p return ( <> + + {isOldAlert && ( + + } + iconType="alert" + /> + )} + + + = ({ dispatch(setSearchTextAction(alertParams.search)); } }, [alertParams, dispatch]); + const isOldAlert = React.useMemo( + () => !isRight(AtomicStatusCheckParamsType.decode(alertParams)), + [alertParams] + ); return ( = ({ const selectedTags = alertParams?.filters?.tags ?? []; const onFilterFieldChange = (fieldName: string, values: string[]) => { - if (alertParams.filters) { + // the `filters` field is no longer a string + if (alertParams.filters && typeof alertParams.filters !== 'string') { setAlertParams('filters', { ...alertParams.filters, [fieldName]: values }); } else { setAlertParams( diff --git a/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx index fc0d86670dd13..d4b14768fc9e4 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx +++ b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx @@ -10,7 +10,7 @@ import { isRight } from 'fp-ts/lib/Either'; import { PathReporter } from 'io-ts/lib/PathReporter'; import { AlertTypeModel } from '../../../../triggers_actions_ui/public'; import { AlertTypeInitializer } from '.'; -import { AtomicStatusCheckParamsType } from '../../../common/runtime_types'; +import { AtomicStatusCheckParamsType, StatusCheckParamsType } from '../../../common/runtime_types'; import { MonitorStatusTitle } from './monitor_status_title'; import { CLIENT_ALERT_TYPES } from '../../../common/constants'; import { MonitorStatusTranslations } from './translations'; @@ -19,11 +19,17 @@ import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_reac export const validate = (alertParams: unknown) => { const errors: Record = {}; const decoded = AtomicStatusCheckParamsType.decode(alertParams); + const oldDecoded = StatusCheckParamsType.decode(alertParams); - if (!isRight(decoded)) { - errors.typeCheckFailure = 'Provided parameters do not conform to the expected type.'; - errors.typeCheckParsingMessage = PathReporter.report(decoded); - } else { + if (!isRight(decoded) && !isRight(oldDecoded)) { + return { + errors: { + typeCheckFailure: 'Provided parameters do not conform to the expected type.', + typeCheckParsingMessage: PathReporter.report(decoded), + }, + }; + } + if (isRight(decoded)) { const { numTimes, timerangeCount } = decoded.right; if (numTimes < 1) { errors.invalidNumTimes = 'Number of alert check down times must be an integer greater than 0'; From 7f0f95f19c9246df51045b784c4f0ce964aac662 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Thu, 4 Jun 2020 10:57:46 -0400 Subject: [PATCH 19/35] Add a test for updated validation function. --- .../__tests__/monitor_status.test.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts b/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts index a5645e3925479..2d3a4c305576c 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts +++ b/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts @@ -33,6 +33,24 @@ describe('monitor status alert type', () => { `); }); + it('accepts original alert params', () => { + expect( + validate({ + locations: ['fairbanks'], + numTimes: 3, + timerange: { + from: 'now-15m', + to: 'now', + }, + filters: '{foo: "bar"}', + }) + ).toMatchInlineSnapshot(` + Object { + "errors": Object {}, + } + `); + }); + describe('timerange', () => { it('has invalid timerangeCount value', () => { expect(validate({ ...params, timerangeCount: 0 })).toMatchInlineSnapshot(` From e59dc77cc3bbd63117edbd0e354bbdc8f6d3872d Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Thu, 4 Jun 2020 11:16:42 -0400 Subject: [PATCH 20/35] Define window for overview filters fetch action. --- .../alerts/alerts_containers/alert_monitor_status.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx index d8149c001d27b..b69f3dd9209a9 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx @@ -35,13 +35,9 @@ export const AlertMonitorStatus: React.FC = ({ }) => { const dispatch = useDispatch(); useEffect(() => { - // example output: `now-13h` - const dateRangeStart = `now-${alertParams?.timerangeCount ?? 15}${ - alertParams?.timerangeUnit ?? 'd' - }`; dispatch( fetchOverviewFilters({ - dateRangeStart, + dateRangeStart: 'now-15m', dateRangeEnd: 'now', locations: alertParams.filters?.['observer.geo.name'] ?? [], ports: alertParams.filters?.['url.port'] ?? [], From 86baf2c3662dff3282986a726796c8798cd8d2ba Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Thu, 4 Jun 2020 12:07:24 -0400 Subject: [PATCH 21/35] Revert store initialization. --- x-pack/plugins/uptime/public/apps/plugin.ts | 11 ++--------- .../lib/adapters/framework/new_platform_adapter.tsx | 6 +----- .../plugins/uptime/public/lib/alert_types/index.ts | 2 -- .../uptime/public/lib/alert_types/monitor_status.tsx | 2 +- x-pack/plugins/uptime/public/lib/alert_types/tls.tsx | 7 ++----- x-pack/plugins/uptime/public/state/index.ts | 12 ++++-------- x-pack/plugins/uptime/public/uptime_app.tsx | 4 +--- 7 files changed, 11 insertions(+), 33 deletions(-) diff --git a/x-pack/plugins/uptime/public/apps/plugin.ts b/x-pack/plugins/uptime/public/apps/plugin.ts index 4da716cfcfdf4..3903733c4ba62 100644 --- a/x-pack/plugins/uptime/public/apps/plugin.ts +++ b/x-pack/plugins/uptime/public/apps/plugin.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Store } from 'redux'; import { CoreSetup, CoreStart, @@ -27,7 +26,6 @@ import { DataPublicPluginStart, } from '../../../../../src/plugins/data/public'; import { alertTypeInitializers } from '../lib/alert_types'; -import { initializeStore } from '../state'; import { kibanaService } from '../state/kibana_service'; export interface ClientPluginsSetup { @@ -47,10 +45,7 @@ export type ClientStart = void; export class UptimePlugin implements Plugin { - private _store: Store; - constructor(_context: PluginInitializerContext) { - this._store = initializeStore(); - } + constructor(_context: PluginInitializerContext) {} public async setup( core: CoreSetup, @@ -68,7 +63,6 @@ export class UptimePlugin }); } - const self = this; core.application.register({ appRoute: '/app/uptime#/', id: PLUGIN.ID, @@ -85,7 +79,7 @@ export class UptimePlugin const { element } = params; const libs: UMFrontendLibs = { - framework: getKibanaFrameworkAdapter(coreStart, plugins, corePlugins, self._store), + framework: getKibanaFrameworkAdapter(coreStart, plugins, corePlugins), }; return libs.framework.render(element); }, @@ -96,7 +90,6 @@ export class UptimePlugin kibanaService.core = start; alertTypeInitializers.forEach((init) => { const alertInitializer = init({ - store: this._store, core: start, plugins, }); diff --git a/x-pack/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx b/x-pack/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx index f1c06daa1dc69..0b4e2ce95cbe4 100644 --- a/x-pack/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx +++ b/x-pack/plugins/uptime/public/lib/adapters/framework/new_platform_adapter.tsx @@ -9,7 +9,6 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { get } from 'lodash'; import { i18n as i18nFormatter } from '@kbn/i18n'; -import { Store } from 'redux'; import { UptimeApp, UptimeAppProps } from '../../../uptime_app'; import { getIntegratedAppAvailability } from './capabilities_adapter'; import { @@ -20,13 +19,11 @@ import { } from '../../../../common/constants'; import { UMFrameworkAdapter } from '../../lib'; import { ClientPluginsStart, ClientPluginsSetup } from '../../../apps/plugin'; -import { AppState } from '../../../state'; export const getKibanaFrameworkAdapter = ( core: CoreStart, plugins: ClientPluginsSetup, - startPlugins: ClientPluginsStart, - store: Store + startPlugins: ClientPluginsStart ): UMFrameworkAdapter => { const { application: { capabilities }, @@ -74,7 +71,6 @@ export const getKibanaFrameworkAdapter = ( routerBasename: basePath.prepend(PLUGIN.ROUTER_BASE_NAME), setBadge, setBreadcrumbs: core.chrome.setBreadcrumbs, - store, }; return { diff --git a/x-pack/plugins/uptime/public/lib/alert_types/index.ts b/x-pack/plugins/uptime/public/lib/alert_types/index.ts index 4c62b24fa2b0e..f2f72311d2262 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/index.ts +++ b/x-pack/plugins/uptime/public/lib/alert_types/index.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Store } from 'redux'; import { CoreStart } from 'kibana/public'; import { AlertTypeModel } from '../../../../triggers_actions_ui/public'; import { initMonitorStatusAlertType } from './monitor_status'; @@ -12,7 +11,6 @@ import { initTlsAlertType } from './tls'; import { ClientPluginsStart } from '../../apps/plugin'; export type AlertTypeInitializer = (dependenies: { - store: Store; core: CoreStart; plugins: ClientPluginsStart; }) => AlertTypeModel; diff --git a/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx index d4b14768fc9e4..9906519865bdc 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx +++ b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx @@ -15,6 +15,7 @@ import { MonitorStatusTitle } from './monitor_status_title'; import { CLIENT_ALERT_TYPES } from '../../../common/constants'; import { MonitorStatusTranslations } from './translations'; import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; +import { store } from '../../state'; export const validate = (alertParams: unknown) => { const errors: Record = {}; @@ -52,7 +53,6 @@ const AlertMonitorStatus = React.lazy(() => ); export const initMonitorStatusAlertType: AlertTypeInitializer = ({ - store, core, plugins, }): AlertTypeModel => ({ diff --git a/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx b/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx index a3c629bb6f31c..c541ea4ae1331 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx +++ b/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx @@ -11,16 +11,13 @@ import { CLIENT_ALERT_TYPES } from '../../../common/constants'; import { TlsTranslations } from './translations'; import { AlertTypeInitializer } from '.'; import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; +import { store } from '../../state'; const { name, defaultActionMessage } = TlsTranslations; const TlsAlertExpression = React.lazy(() => import('../../components/overview/alerts/alerts_containers/alert_tls') ); -export const initTlsAlertType: AlertTypeInitializer = ({ - store, - core, - plugins, -}): AlertTypeModel => ({ +export const initTlsAlertType: AlertTypeInitializer = ({ core, plugins }): AlertTypeModel => ({ id: CLIENT_ALERT_TYPES.TLS, iconClass: 'uptimeApp', alertParamsExpression: (_params: any) => ( diff --git a/x-pack/plugins/uptime/public/state/index.ts b/x-pack/plugins/uptime/public/state/index.ts index fa9979d7436bb..1f4ce7103afbc 100644 --- a/x-pack/plugins/uptime/public/state/index.ts +++ b/x-pack/plugins/uptime/public/state/index.ts @@ -11,14 +11,10 @@ import { rootReducer } from './reducers'; export type AppState = ReturnType; -export const initializeStore = () => { - const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; +const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; - const sagaMW = createSagaMiddleware(); +const sagaMW = createSagaMiddleware(); - const store = createStore(rootReducer, composeEnhancers(applyMiddleware(sagaMW))); +export const store = createStore(rootReducer, composeEnhancers(applyMiddleware(sagaMW))); - sagaMW.run(rootEffect); - - return store; -}; +sagaMW.run(rootEffect); diff --git a/x-pack/plugins/uptime/public/uptime_app.tsx b/x-pack/plugins/uptime/public/uptime_app.tsx index 470e3018a50e6..4208d79e761ed 100644 --- a/x-pack/plugins/uptime/public/uptime_app.tsx +++ b/x-pack/plugins/uptime/public/uptime_app.tsx @@ -10,7 +10,6 @@ import React, { useEffect } from 'react'; import { Provider as ReduxProvider } from 'react-redux'; import { BrowserRouter as Router } from 'react-router-dom'; import { I18nStart, ChromeBreadcrumb, CoreStart } from 'src/core/public'; -import { Store } from 'redux'; import { KibanaContextProvider } from '../../../../src/plugins/kibana_react/public'; import { ClientPluginsSetup, ClientPluginsStart } from './apps/plugin'; import { UMUpdateBadge } from './lib/lib'; @@ -27,6 +26,7 @@ import { UptimeAlertsContextProvider, UptimeAlertsFlyoutWrapper, } from './components/overview/alerts'; +import { store } from './state'; export interface UptimeAppColors { danger: string; @@ -53,7 +53,6 @@ export interface UptimeAppProps { renderGlobalHelpControls(): void; commonlyUsedRanges: CommonlyUsedRange[]; setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => void; - store: Store; } const Application = (props: UptimeAppProps) => { @@ -68,7 +67,6 @@ const Application = (props: UptimeAppProps) => { routerBasename, setBadge, startPlugins, - store, } = props; useEffect(() => { From dcce253f4bdd151341aaa9543d30ac9df1e5d1f1 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Thu, 4 Jun 2020 14:22:29 -0400 Subject: [PATCH 22/35] Make monitor counter function while editing alerts. --- .../alert_monitor_status.tsx | 20 ++++++++++++++++++- .../overview/kuery_bar/kuery_bar.tsx | 10 ++++------ .../lib/alert_types/monitor_status_title.tsx | 15 +++++++++++--- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx index b69f3dd9209a9..64d15dc01b445 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx @@ -10,8 +10,14 @@ import { DataPublicPluginSetup } from 'src/plugins/data/public'; import { isRight } from 'fp-ts/lib/Either'; import { selectMonitorStatusAlert, overviewFiltersSelector } from '../../../../state/selectors'; import { AlertMonitorStatusComponent } from '../index'; -import { fetchOverviewFilters, setSearchTextAction } from '../../../../state/actions'; +import { + fetchOverviewFilters, + setSearchTextAction, + setEsKueryString, +} from '../../../../state/actions'; import { AtomicStatusCheckParamsType } from '../../../../../common/runtime_types'; +import { useIndexPattern } from '../../kuery_bar/use_index_pattern'; +import { useUpdateKueryString } from '../../../../hooks'; interface Props { alertParams: { [key: string]: any }; @@ -54,6 +60,18 @@ export const AlertMonitorStatus: React.FC = ({ dispatch(setSearchTextAction(alertParams.search)); } }, [alertParams, dispatch]); + + const { index_pattern: indexPattern } = useIndexPattern(); + const [esFilters] = useUpdateKueryString( + indexPattern, + alertParams.search, + typeof alertParams.filters === 'string' ? {} : alertParams.filters + ); + + useEffect(() => { + dispatch(setEsKueryString(esFilters ?? '')); + }, [dispatch, esFilters]); + const isOldAlert = React.useMemo( () => !isRight(AtomicStatusCheckParamsType.decode(alertParams)), [alertParams] diff --git a/x-pack/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx b/x-pack/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx index 15d8db97f7c4a..03c8e919ebbf1 100644 --- a/x-pack/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx +++ b/x-pack/plugins/uptime/public/components/overview/kuery_bar/kuery_bar.tsx @@ -74,15 +74,9 @@ export function KueryBar({ return; } - updateSearchText(inputValue); - setIsLoadingSuggestions(true); setState({ ...state, suggestions: [] }); - if (updateDefaultKuery) { - updateDefaultKuery(inputValue); - } - const currentRequest = uniqueId(); currentRequestCheck = currentRequest; @@ -125,6 +119,10 @@ export function KueryBar({ if (shouldUpdateUrl !== false) { updateUrlParams({ search: inputValue.trim() }); } + updateSearchText(inputValue); + if (updateDefaultKuery) { + updateDefaultKuery(inputValue); + } } catch (e) { console.log('Invalid kuery syntax'); // eslint-disable-line no-console } diff --git a/x-pack/plugins/uptime/public/lib/alert_types/monitor_status_title.tsx b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status_title.tsx index 3fe497f9e88bc..f259b815d70ac 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/monitor_status_title.tsx +++ b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status_title.tsx @@ -4,14 +4,23 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; -import { useSelector } from 'react-redux'; +import React, { useEffect } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiText } from '@elastic/eui'; -import { snapshotDataSelector } from '../../state/selectors'; +import { snapshotDataSelector, esKuerySelector } from '../../state/selectors'; +import { getSnapshotCountAction } from '../../state/actions'; export const MonitorStatusTitle = () => { const { count, loading } = useSelector(snapshotDataSelector); + const esKuery = useSelector(esKuerySelector); + const dispatch = useDispatch(); + useEffect(() => { + dispatch( + getSnapshotCountAction({ dateRangeStart: 'now-15m', dateRangeEnd: 'now', filters: esKuery }) + ); + }, [dispatch, esKuery]); + return ( From 4af3d19da69b08a7068e8de62a8fa156f2e126fb Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Thu, 4 Jun 2020 14:33:54 -0400 Subject: [PATCH 23/35] Refresh snapshot. --- .../lib/alert_types/__tests__/monitor_status.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts b/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts index 2d3a4c305576c..7ca5e7438d28a 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts +++ b/x-pack/plugins/uptime/public/lib/alert_types/__tests__/monitor_status.test.ts @@ -140,11 +140,11 @@ describe('monitor status alert type', () => { "name": From abc7e07ea8b0cffaca786c6be0ee28243d4f36c6 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Fri, 5 Jun 2020 12:49:18 -0400 Subject: [PATCH 24/35] Move snapshot count in monitor status alert to callout. --- .../overview/alerts/alert_monitor_status.tsx | 33 +++++++++++++++-- .../alert_monitor_status.tsx | 25 ++++++++++--- .../lib/alert_types/monitor_status_title.tsx | 36 +++---------------- 3 files changed, 56 insertions(+), 38 deletions(-) diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx index dfc6a046186c5..fdaa18c36d601 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx @@ -5,7 +5,7 @@ */ import React, { useState } from 'react'; -import { EuiCallOut, EuiSpacer } from '@elastic/eui'; +import { EuiCallOut, EuiLoadingSpinner, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { DataPublicPluginSetup } from 'src/plugins/data/public'; import * as labels from './translations'; @@ -25,6 +25,8 @@ interface AlertMonitorStatusProps { hasFilters: boolean; isOldAlert: boolean; locations: string[]; + snapshotCount: number; + snapshotLoading: boolean; numTimes: number; setAlertParams: (key: string, value: any) => void; timerange: { @@ -34,7 +36,14 @@ interface AlertMonitorStatusProps { } export const AlertMonitorStatusComponent: React.FC = (props) => { - const { alertParams, hasFilters, isOldAlert, setAlertParams } = props; + const { + alertParams, + hasFilters, + isOldAlert, + setAlertParams, + snapshotCount, + snapshotLoading, + } = props; const alertFilters = alertParams?.filters ?? {}; const [newFilters, setNewFilters] = useState( @@ -50,7 +59,7 @@ export const AlertMonitorStatusComponent: React.FC = (p size="s" title={ } @@ -108,6 +117,24 @@ export const AlertMonitorStatusComponent: React.FC = (p /> + + {!snapshotLoading ? ( + + } + iconType="iInCircle" + /> + ) : ( + + )} + + ); }; diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx index 64d15dc01b445..d665c98c434e0 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx @@ -8,12 +8,18 @@ import React, { useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { DataPublicPluginSetup } from 'src/plugins/data/public'; import { isRight } from 'fp-ts/lib/Either'; -import { selectMonitorStatusAlert, overviewFiltersSelector } from '../../../../state/selectors'; +import { + selectMonitorStatusAlert, + overviewFiltersSelector, + snapshotDataSelector, + esKuerySelector, +} from '../../../../state/selectors'; import { AlertMonitorStatusComponent } from '../index'; import { fetchOverviewFilters, setSearchTextAction, setEsKueryString, + getSnapshotCountAction, } from '../../../../state/actions'; import { AtomicStatusCheckParamsType } from '../../../../../common/runtime_types'; import { useIndexPattern } from '../../kuery_bar/use_index_pattern'; @@ -43,7 +49,7 @@ export const AlertMonitorStatus: React.FC = ({ useEffect(() => { dispatch( fetchOverviewFilters({ - dateRangeStart: 'now-15m', + dateRangeStart: 'now-24h', dateRangeEnd: 'now', locations: alertParams.filters?.['observer.geo.name'] ?? [], ports: alertParams.filters?.['url.port'] ?? [], @@ -62,12 +68,16 @@ export const AlertMonitorStatus: React.FC = ({ }, [alertParams, dispatch]); const { index_pattern: indexPattern } = useIndexPattern(); + + const { count, loading } = useSelector(snapshotDataSelector); + const esKuery = useSelector(esKuerySelector); const [esFilters] = useUpdateKueryString( indexPattern, alertParams.search, - typeof alertParams.filters === 'string' ? {} : alertParams.filters + alertParams.filters === undefined || typeof alertParams.filters === 'string' + ? '' + : JSON.stringify(Array.from(Object.entries(alertParams.filters))) ); - useEffect(() => { dispatch(setEsKueryString(esFilters ?? '')); }, [dispatch, esFilters]); @@ -76,6 +86,11 @@ export const AlertMonitorStatus: React.FC = ({ () => !isRight(AtomicStatusCheckParamsType.decode(alertParams)), [alertParams] ); + useEffect(() => { + dispatch( + getSnapshotCountAction({ dateRangeStart: 'now-24h', dateRangeEnd: 'now', filters: esKuery }) + ); + }, [dispatch, esKuery]); return ( = ({ locations={locations} numTimes={numTimes} setAlertParams={setAlertParams} + snapshotCount={count.total} + snapshotLoading={loading} timerange={timerange} /> ); diff --git a/x-pack/plugins/uptime/public/lib/alert_types/monitor_status_title.tsx b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status_title.tsx index f259b815d70ac..1e2751a4ac388 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/monitor_status_title.tsx +++ b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status_title.tsx @@ -4,40 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useEffect } from 'react'; -import { useSelector, useDispatch } from 'react-redux'; +import React from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiText } from '@elastic/eui'; -import { snapshotDataSelector, esKuerySelector } from '../../state/selectors'; -import { getSnapshotCountAction } from '../../state/actions'; export const MonitorStatusTitle = () => { - const { count, loading } = useSelector(snapshotDataSelector); - const esKuery = useSelector(esKuerySelector); - const dispatch = useDispatch(); - useEffect(() => { - dispatch( - getSnapshotCountAction({ dateRangeStart: 'now-15m', dateRangeEnd: 'now', filters: esKuery }) - ); - }, [dispatch, esKuery]); - return ( - - - {' '} - - - {!loading ? ( - - {count.total} monitors - - ) : ( - - )} - - + ); }; From 68c6e13fdfb36dd3a4ed7dfd4de090e4b40c34e9 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Fri, 5 Jun 2020 16:10:38 -0400 Subject: [PATCH 25/35] Add new state for selected filters. --- .../overview/alerts/add_filter_btn.tsx | 8 ++--- .../overview/alerts/alert_monitor_status.tsx | 29 +++++++-------- .../alert_monitor_status.tsx | 17 +++++++++ .../uptime/public/hooks/use_url_params.ts | 36 +++++++++++++++++++ .../public/state/actions/selected_filters.ts | 21 +++++++++++ .../uptime/public/state/reducers/index.ts | 2 ++ .../public/state/reducers/selected_filters.ts | 32 +++++++++++++++++ .../uptime/public/state/selectors/index.ts | 2 ++ 8 files changed, 126 insertions(+), 21 deletions(-) create mode 100644 x-pack/plugins/uptime/public/state/actions/selected_filters.ts create mode 100644 x-pack/plugins/uptime/public/state/reducers/selected_filters.ts diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/add_filter_btn.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/add_filter_btn.tsx index f633727a0af37..d9011c896ffdc 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/add_filter_btn.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/add_filter_btn.tsx @@ -6,20 +6,18 @@ import React, { useState } from 'react'; import { EuiButtonEmpty, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui'; -import { useFilterUpdate } from '../../../hooks/use_filter_update'; import * as labels from './translations'; interface Props { newFilters: string[]; onNewFilter: (val: string) => void; + alertFilters: { [key: string]: string[] }; } -export const AddFilterButton: React.FC = ({ newFilters, onNewFilter }) => { +export const AddFilterButton: React.FC = ({ newFilters, onNewFilter, alertFilters }) => { const [isPopoverOpen, setPopover] = useState(false); - const { selectedFilters } = useFilterUpdate(); - - const getSelectedItems = (fieldName: string) => selectedFilters.get(fieldName) || []; + const getSelectedItems = (fieldName: string) => alertFilters?.[fieldName] ?? []; const onButtonClick = () => { setPopover(!isPopoverOpen); diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx index fdaa18c36d601..cd055d4cb72d8 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx @@ -5,7 +5,7 @@ */ import React, { useState } from 'react'; -import { EuiCallOut, EuiLoadingSpinner, EuiSpacer } from '@elastic/eui'; +import { EuiCallOut, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { DataPublicPluginSetup } from 'src/plugins/data/public'; import * as labels from './translations'; @@ -110,6 +110,7 @@ export const AlertMonitorStatusComponent: React.FC = (p { setNewFilters([...newFilters, newFilter]); @@ -118,21 +119,17 @@ export const AlertMonitorStatusComponent: React.FC = (p - {!snapshotLoading ? ( - - } - iconType="iInCircle" - /> - ) : ( - - )} + + } + iconType="iInCircle" + /> diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx index d665c98c434e0..b570572ba79da 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx @@ -13,6 +13,7 @@ import { overviewFiltersSelector, snapshotDataSelector, esKuerySelector, + selectedFiltersSelector, } from '../../../../state/selectors'; import { AlertMonitorStatusComponent } from '../index'; import { @@ -92,6 +93,22 @@ export const AlertMonitorStatus: React.FC = ({ ); }, [dispatch, esKuery]); + const selectedFilters = useSelector(selectedFiltersSelector); + useEffect(() => { + if (!alertParams.filters && selectedFilters !== null) { + setAlertParams('filters', { + // @ts-ignore + 'url.port': selectedFilters?.ports ?? [], + // @ts-ignore + 'observer.geo.name': selectedFilters?.locations ?? [], + // @ts-ignore + 'monitor.type': selectedFilters?.schemes ?? [], + // @ts-ignore + tags: selectedFilters?.tags ?? [], + }); + } + }, [alertParams, setAlertParams, selectedFilters]); + return ( UptimeUrlParams; export type UpdateUrlParams = (updatedParams: { @@ -27,9 +31,35 @@ export const useGetUrlParams: GetUrlParams = () => { return getSupportedUrlParams(params); }; +const getMapFromFilters = (value: any): Map | undefined => { + try { + return new Map(JSON.parse(value)); + } catch { + return undefined; + } +}; + +const mapMapToObject = (map: Map) => ({ + locations: map.get('observer.geo.name') ?? [], + ports: map.get('url.port') ?? [], + schemes: map.get('monitor.type') ?? [], + tags: map.get('tags') ?? [], +}); + export const useUrlParams: UptimeUrlParamsHook = () => { const location = useLocation(); const history = useHistory(); + const dispatch = useDispatch(); + const selectedFilters = useSelector(selectedFiltersSelector); + const { filters } = useGetUrlParams(); + useEffect(() => { + if (selectedFilters === null) { + const filterMap = getMapFromFilters(filters); + if (filterMap) { + dispatch(setSelectedFilters(mapMapToObject(filterMap))); + } + } + }, [dispatch, filters, selectedFilters]); const updateUrlParams: UpdateUrlParams = (updatedParams) => { if (!history || !location) return; @@ -57,6 +87,12 @@ export const useUrlParams: UptimeUrlParamsHook = () => { { sort: false } ), }); + const filterMap = getMapFromFilters(mergedParams.filters); + if (!filterMap) { + dispatch(setSelectedFilters(null)); + } else { + dispatch(setSelectedFilters(mapMapToObject(filterMap))); + } }; return [useGetUrlParams, updateUrlParams]; diff --git a/x-pack/plugins/uptime/public/state/actions/selected_filters.ts b/x-pack/plugins/uptime/public/state/actions/selected_filters.ts new file mode 100644 index 0000000000000..11c159b09a157 --- /dev/null +++ b/x-pack/plugins/uptime/public/state/actions/selected_filters.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 { createAction } from 'redux-actions'; + +export interface SelectedFilters { + locations: string[]; + ports: number[]; + schemes: string[]; + tags: string[]; +} + +export type SelectedFiltersPayload = SelectedFilters; + +export const getSelectedFilters = createAction('GET SELECTED FILTERS'); +export const setSelectedFilters = createAction( + 'SET_SELECTED_FILTERS' +); diff --git a/x-pack/plugins/uptime/public/state/reducers/index.ts b/x-pack/plugins/uptime/public/state/reducers/index.ts index ead7f5b46431b..c05c740ab8ebf 100644 --- a/x-pack/plugins/uptime/public/state/reducers/index.ts +++ b/x-pack/plugins/uptime/public/state/reducers/index.ts @@ -19,6 +19,7 @@ import { monitorDurationReducer } from './monitor_duration'; import { indexStatusReducer } from './index_status'; import { mlJobsReducer } from './ml_anomaly'; import { certificatesReducer } from '../certificates/certificates'; +import { selectedFiltersReducer } from './selected_filters'; export const rootReducer = combineReducers({ monitor: monitorReducer, @@ -35,4 +36,5 @@ export const rootReducer = combineReducers({ monitorDuration: monitorDurationReducer, indexStatus: indexStatusReducer, certificates: certificatesReducer, + selectedFilters: selectedFiltersReducer, }); diff --git a/x-pack/plugins/uptime/public/state/reducers/selected_filters.ts b/x-pack/plugins/uptime/public/state/reducers/selected_filters.ts new file mode 100644 index 0000000000000..108d516d17ab1 --- /dev/null +++ b/x-pack/plugins/uptime/public/state/reducers/selected_filters.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Action } from 'redux-actions'; +import { + getSelectedFilters, + setSelectedFilters, + SelectedFilters, +} from '../actions/selected_filters'; + +const initialState = null; + +export function selectedFiltersReducer( + state = initialState, + action: Action +): SelectedFilters | null { + switch (action.type) { + case String(getSelectedFilters): + return state; + case String(setSelectedFilters): + if (state === null) return { ...action.payload }; + return { + ...(state || {}), + ...action.payload, + }; + default: + return state; + } +} diff --git a/x-pack/plugins/uptime/public/state/selectors/index.ts b/x-pack/plugins/uptime/public/state/selectors/index.ts index b088c346ad811..d08db2ccf5f2d 100644 --- a/x-pack/plugins/uptime/public/state/selectors/index.ts +++ b/x-pack/plugins/uptime/public/state/selectors/index.ts @@ -86,3 +86,5 @@ export const overviewFiltersSelector = ({ overviewFilters }: AppState) => overvi export const esKuerySelector = ({ ui: { esKuery } }: AppState) => esKuery; export const searchTextSelector = ({ ui: { searchText } }: AppState) => searchText; + +export const selectedFiltersSelector = ({ selectedFilters }: AppState) => selectedFilters; From 9eb7de4e31931743a93091d49abfb4799c55771b Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Fri, 5 Jun 2020 17:05:23 -0400 Subject: [PATCH 26/35] Add basic functional tests for uptime alert flyouts. --- .../settings_message_expression_popover.tsx | 1 + .../functional/page_objects/uptime_page.ts | 4 +++ .../test/functional/services/uptime/alerts.ts | 10 ++++++ .../apps/uptime/flyout_loads.ts | 32 +++++++++++++++++++ .../apps/uptime/index.ts | 1 + 5 files changed, 48 insertions(+) create mode 100644 x-pack/test/functional_with_es_ssl/apps/uptime/flyout_loads.ts diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/settings_message_expression_popover.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/settings_message_expression_popover.tsx index 27a353c31a6a9..cf6d2547d9c0c 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/settings_message_expression_popover.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/settings_message_expression_popover.tsx @@ -30,6 +30,7 @@ export const SettingsMessageExpressionPopover: React.FC { + describe('uptime alert flyout', () => { + const pageObjects = getPageObjects(['common', 'uptime']); + const uptimeService = getService('uptime'); + const browserService = getService('browser'); + + afterEach(async () => browserService.refresh()); + + it('can open status flyout', async () => { + await pageObjects.uptime.goToUptimeOverview(); + await uptimeService.alerts.openFlyout('monitorStatus'); + await uptimeService.alerts.assertMonitorStatusFlyoutSearchBarExists(); + }); + + it('can open tls flyout', async () => { + await pageObjects.uptime.goToUptimeOverview(); + await uptimeService.alerts.openFlyout('tls'); + await Promise.all([ + uptimeService.alerts.assertTlsFieldExists('expiration'), + uptimeService.alerts.assertTlsFieldExists('age'), + ]); + }); + }); +}; diff --git a/x-pack/test/functional_with_es_ssl/apps/uptime/index.ts b/x-pack/test/functional_with_es_ssl/apps/uptime/index.ts index ce91a2a26ce91..616b154da9c33 100644 --- a/x-pack/test/functional_with_es_ssl/apps/uptime/index.ts +++ b/x-pack/test/functional_with_es_ssl/apps/uptime/index.ts @@ -22,6 +22,7 @@ export default ({ getService, loadTestFile }: FtrProviderContext) => { after(async () => await esArchiver.unload(ARCHIVE)); loadTestFile(require.resolve('./alert_flyout')); + loadTestFile(require.resolve('./flyout_loads')); }); }); }; From 63bf9ec5e4a146bd8f669a5a27716ba4aca9406a Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Fri, 5 Jun 2020 17:44:01 -0400 Subject: [PATCH 27/35] Fix broken types. --- x-pack/plugins/uptime/public/state/reducers/selected_filters.ts | 2 +- .../uptime/public/state/selectors/__tests__/index.test.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/uptime/public/state/reducers/selected_filters.ts b/x-pack/plugins/uptime/public/state/reducers/selected_filters.ts index 108d516d17ab1..921754c93078a 100644 --- a/x-pack/plugins/uptime/public/state/reducers/selected_filters.ts +++ b/x-pack/plugins/uptime/public/state/reducers/selected_filters.ts @@ -11,7 +11,7 @@ import { SelectedFilters, } from '../actions/selected_filters'; -const initialState = null; +const initialState: SelectedFilters | null = null; export function selectedFiltersReducer( state = initialState, diff --git a/x-pack/plugins/uptime/public/state/selectors/__tests__/index.test.ts b/x-pack/plugins/uptime/public/state/selectors/__tests__/index.test.ts index 2eb0f1e8cb0ee..b1885ddeeba3f 100644 --- a/x-pack/plugins/uptime/public/state/selectors/__tests__/index.test.ts +++ b/x-pack/plugins/uptime/public/state/selectors/__tests__/index.test.ts @@ -107,6 +107,7 @@ describe('state selectors', () => { loading: false, }, }, + selectedFilters: null, }; it('selects base path from state', () => { From b6c5e046bc56ac33de437cd680510b153c44c991 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Fri, 5 Jun 2020 18:44:58 -0400 Subject: [PATCH 28/35] Update unit tests with mock provider. --- .../__tests__/uptime_date_picker.test.tsx | 8 +- .../__tests__/monitor_bar_series.test.tsx | 8 +- .../charts/__tests__/ping_histogram.test.tsx | 9 +- .../__tests__/filter_status_button.test.tsx | 8 +- .../__tests__/status_filter.test.tsx | 20 +- .../use_url_params.test.tsx.snap | 210 ++++++++++++++---- .../hooks/__tests__/use_breadcrumbs.test.tsx | 14 +- .../hooks/__tests__/use_url_params.test.tsx | 46 ++-- .../public/lib/helper/helper_with_redux.tsx | 21 ++ .../plugins/uptime/public/lib/helper/index.ts | 1 + x-pack/plugins/uptime/public/lib/index.ts | 1 + .../pages/__tests__/page_header.test.tsx | 28 +-- 12 files changed, 276 insertions(+), 98 deletions(-) create mode 100644 x-pack/plugins/uptime/public/lib/helper/helper_with_redux.tsx diff --git a/x-pack/plugins/uptime/public/components/common/__tests__/uptime_date_picker.test.tsx b/x-pack/plugins/uptime/public/components/common/__tests__/uptime_date_picker.test.tsx index 445d9302e3a9d..16853211433ca 100644 --- a/x-pack/plugins/uptime/public/components/common/__tests__/uptime_date_picker.test.tsx +++ b/x-pack/plugins/uptime/public/components/common/__tests__/uptime_date_picker.test.tsx @@ -6,7 +6,7 @@ import React from 'react'; import { UptimeDatePicker } from '../uptime_date_picker'; -import { renderWithRouter, shallowWithRouter } from '../../../lib'; +import { renderWithRouter, shallowWithRouter, MountWithReduxProvider } from '../../../lib'; describe('UptimeDatePicker component', () => { it('validates props with shallow render', () => { @@ -15,7 +15,11 @@ describe('UptimeDatePicker component', () => { }); it('renders properly with mock data', () => { - const component = renderWithRouter(); + const component = renderWithRouter( + + + + ); expect(component).toMatchSnapshot(); }); }); diff --git a/x-pack/plugins/uptime/public/components/common/charts/__tests__/monitor_bar_series.test.tsx b/x-pack/plugins/uptime/public/components/common/charts/__tests__/monitor_bar_series.test.tsx index 4522f8d633fa6..5e49d303c5c66 100644 --- a/x-pack/plugins/uptime/public/components/common/charts/__tests__/monitor_bar_series.test.tsx +++ b/x-pack/plugins/uptime/public/components/common/charts/__tests__/monitor_bar_series.test.tsx @@ -6,7 +6,7 @@ import React from 'react'; import { MonitorBarSeries, MonitorBarSeriesProps } from '../monitor_bar_series'; -import { renderWithRouter, shallowWithRouter } from '../../../../lib'; +import { renderWithRouter, shallowWithRouter, MountWithReduxProvider } from '../../../../lib'; import { HistogramPoint } from '../../../../../common/runtime_types'; describe('MonitorBarSeries component', () => { @@ -197,7 +197,11 @@ describe('MonitorBarSeries component', () => { }); it('renders if the data series is present', () => { - const component = renderWithRouter(); + const component = renderWithRouter( + + + + ); expect(component).toMatchSnapshot(); }); }); diff --git a/x-pack/plugins/uptime/public/components/common/charts/__tests__/ping_histogram.test.tsx b/x-pack/plugins/uptime/public/components/common/charts/__tests__/ping_histogram.test.tsx index 21c1fa86eeee4..57a38f2a949e7 100644 --- a/x-pack/plugins/uptime/public/components/common/charts/__tests__/ping_histogram.test.tsx +++ b/x-pack/plugins/uptime/public/components/common/charts/__tests__/ping_histogram.test.tsx @@ -6,7 +6,7 @@ import React from 'react'; import { PingHistogramComponent, PingHistogramComponentProps } from '../ping_histogram'; -import { renderWithRouter, shallowWithRouter } from '../../../../lib'; +import { renderWithRouter, shallowWithRouter, MountWithReduxProvider } from '../../../../lib'; describe('PingHistogram component', () => { const props: PingHistogramComponentProps = { @@ -49,7 +49,12 @@ describe('PingHistogram component', () => { }); it('renders the component without errors', () => { - const component = renderWithRouter(); + const component = renderWithRouter( + + + + ); + expect(component).toMatchSnapshot(); }); }); diff --git a/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/filter_status_button.test.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/filter_status_button.test.tsx index 58c305f0d15a0..612ede2c556e7 100644 --- a/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/filter_status_button.test.tsx +++ b/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/filter_status_button.test.tsx @@ -6,7 +6,7 @@ import React from 'react'; import { FilterStatusButton, FilterStatusButtonProps } from '../filter_status_button'; -import { renderWithRouter, shallowWithRouter } from '../../../../lib'; +import { renderWithRouter, shallowWithRouter, MountWithReduxProvider } from '../../../../lib'; describe('FilterStatusButton', () => { let props: FilterStatusButtonProps; @@ -26,7 +26,11 @@ describe('FilterStatusButton', () => { }); it('renders without errors for valid props', () => { - const wrapper = renderWithRouter(); + const wrapper = renderWithRouter( + + + + ); expect(wrapper).toMatchSnapshot(); }); }); diff --git a/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/status_filter.test.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/status_filter.test.tsx index a1288513eb785..d09bbad5cb9e0 100644 --- a/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/status_filter.test.tsx +++ b/x-pack/plugins/uptime/public/components/overview/monitor_list/__tests__/status_filter.test.tsx @@ -5,7 +5,12 @@ */ import React from 'react'; -import { mountWithRouter, renderWithRouter, shallowWithRouter } from '../../../../lib'; +import { + mountWithRouter, + renderWithRouter, + shallowWithRouter, + MountWithReduxProvider, +} from '../../../../lib'; import { createMemoryHistory } from 'history'; import { StatusFilter } from '../status_filter'; import { FilterStatusButton } from '../filter_status_button'; @@ -18,7 +23,12 @@ describe('StatusFilterComponent', () => { initialEntries: [`/?g=%22%22&statusFilter=${status}`], }); - const wrapper = mountWithRouter(, history); + const wrapper = mountWithRouter( + + + , + history + ); const filterBtns = wrapper.find(FilterStatusButton); const allBtn = filterBtns.at(0); @@ -34,7 +44,11 @@ describe('StatusFilterComponent', () => { }); it('renders without errors for valid props', () => { - const wrapper = renderWithRouter(); + const wrapper = renderWithRouter( + + + + ); expect(wrapper).toMatchSnapshot(); }); diff --git a/x-pack/plugins/uptime/public/hooks/__tests__/__snapshots__/use_url_params.test.tsx.snap b/x-pack/plugins/uptime/public/hooks/__tests__/__snapshots__/use_url_params.test.tsx.snap index 827c9257893ad..5d2565b7210da 100644 --- a/x-pack/plugins/uptime/public/hooks/__tests__/__snapshots__/use_url_params.test.tsx.snap +++ b/x-pack/plugins/uptime/public/hooks/__tests__/__snapshots__/use_url_params.test.tsx.snap @@ -137,30 +137,95 @@ exports[`useUrlParams deletes keys that do not have truthy values 1`] = ` } } > - + -
- {"absoluteDateRangeStart":20,"absoluteDateRangeEnd":20,"autorefreshInterval":60000,"autorefreshIsPaused":false,"dateRangeStart":"now-12","dateRangeEnd":"now","filters":"","search":"","selectedPingStatus":"","statusFilter":"","pagination":"foo"} -
- - -
+ +
+ {"absoluteDateRangeStart":20,"absoluteDateRangeEnd":20,"autorefreshInterval":60000,"autorefreshIsPaused":false,"dateRangeStart":"now-12","dateRangeEnd":"now","filters":"","search":"","selectedPingStatus":"","statusFilter":"","pagination":"foo"} +
+ + +
+
+
`; @@ -301,24 +366,89 @@ exports[`useUrlParams gets the expected values using the context 1`] = ` } } > - -
- {"absoluteDateRangeStart":20,"absoluteDateRangeEnd":20,"autorefreshInterval":60000,"autorefreshIsPaused":false,"dateRangeStart":"now-15m","dateRangeEnd":"now","filters":"","search":"","selectedPingStatus":"","statusFilter":""} -
- - -
+ +
+ {"absoluteDateRangeStart":20,"absoluteDateRangeEnd":20,"autorefreshInterval":60000,"autorefreshIsPaused":false,"dateRangeStart":"now-15m","dateRangeEnd":"now","filters":"","search":"","selectedPingStatus":"","statusFilter":""} +
+ + +
+ + `; diff --git a/x-pack/plugins/uptime/public/hooks/__tests__/use_breadcrumbs.test.tsx b/x-pack/plugins/uptime/public/hooks/__tests__/use_breadcrumbs.test.tsx index 306919015fcb1..d688660f564ca 100644 --- a/x-pack/plugins/uptime/public/hooks/__tests__/use_breadcrumbs.test.tsx +++ b/x-pack/plugins/uptime/public/hooks/__tests__/use_breadcrumbs.test.tsx @@ -10,7 +10,7 @@ import { Route } from 'react-router-dom'; import { mountWithRouter } from '../../lib'; import { OVERVIEW_ROUTE } from '../../../common/constants'; import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; -import { UptimeUrlParams, getSupportedUrlParams } from '../../lib/helper'; +import { UptimeUrlParams, getSupportedUrlParams, MountWithReduxProvider } from '../../lib/helper'; import { makeBaseBreadcrumb, useBreadcrumbs } from '../use_breadcrumbs'; describe('useBreadcrumbs', () => { @@ -34,11 +34,13 @@ describe('useBreadcrumbs', () => { }; mountWithRouter( - - - - - + + + + + + + ); const urlParams: UptimeUrlParams = getSupportedUrlParams({}); diff --git a/x-pack/plugins/uptime/public/hooks/__tests__/use_url_params.test.tsx b/x-pack/plugins/uptime/public/hooks/__tests__/use_url_params.test.tsx index deb1f163c1326..af5c113a02834 100644 --- a/x-pack/plugins/uptime/public/hooks/__tests__/use_url_params.test.tsx +++ b/x-pack/plugins/uptime/public/hooks/__tests__/use_url_params.test.tsx @@ -8,7 +8,7 @@ import DateMath from '@elastic/datemath'; import React, { useState, Fragment } from 'react'; import { useUrlParams, UptimeUrlParamsHook } from '../use_url_params'; import { UptimeRefreshContext } from '../../contexts'; -import { mountWithRouter } from '../../lib'; +import { mountWithRouter, MountWithReduxProvider } from '../../lib'; import { createMemoryHistory } from 'history'; interface MockUrlParamsComponentProps { @@ -52,9 +52,11 @@ describe('useUrlParams', () => { jest.spyOn(history, 'push'); const component = mountWithRouter( - - - , + + + + + , history ); @@ -68,14 +70,16 @@ describe('useUrlParams', () => { it('gets the expected values using the context', () => { const component = mountWithRouter( - - - + + + + + ); const getUrlParamsButton = component.find('#getUrlParams'); @@ -92,14 +96,16 @@ describe('useUrlParams', () => { jest.spyOn(history, 'push'); const component = mountWithRouter( - - - , + + + + + , history ); diff --git a/x-pack/plugins/uptime/public/lib/helper/helper_with_redux.tsx b/x-pack/plugins/uptime/public/lib/helper/helper_with_redux.tsx new file mode 100644 index 0000000000000..a68184dbdff97 --- /dev/null +++ b/x-pack/plugins/uptime/public/lib/helper/helper_with_redux.tsx @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { Provider as ReduxProvider } from 'react-redux'; + +export const MountWithReduxProvider: React.FC = ({ children }) => ( + + {children} + +); diff --git a/x-pack/plugins/uptime/public/lib/helper/index.ts b/x-pack/plugins/uptime/public/lib/helper/index.ts index cf49328141b83..10663163e8fda 100644 --- a/x-pack/plugins/uptime/public/lib/helper/index.ts +++ b/x-pack/plugins/uptime/public/lib/helper/index.ts @@ -9,3 +9,4 @@ export * from './observability_integration'; export { getChartDateLabel } from './charts'; export { seriesHasDownValues } from './series_has_down_values'; export { UptimeUrlParams, getSupportedUrlParams } from './url_params'; +export { MountWithReduxProvider } from './helper_with_redux'; diff --git a/x-pack/plugins/uptime/public/lib/index.ts b/x-pack/plugins/uptime/public/lib/index.ts index 06ac06e647adc..92787737d579f 100644 --- a/x-pack/plugins/uptime/public/lib/index.ts +++ b/x-pack/plugins/uptime/public/lib/index.ts @@ -4,4 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ +export { MountWithReduxProvider } from './helper'; export { renderWithRouter, shallowWithRouter, mountWithRouter } from './helper/helper_with_router'; diff --git a/x-pack/plugins/uptime/public/pages/__tests__/page_header.test.tsx b/x-pack/plugins/uptime/public/pages/__tests__/page_header.test.tsx index c9e4eef386764..63d4c24f965d9 100644 --- a/x-pack/plugins/uptime/public/pages/__tests__/page_header.test.tsx +++ b/x-pack/plugins/uptime/public/pages/__tests__/page_header.test.tsx @@ -6,47 +6,33 @@ import React from 'react'; import { PageHeader } from '../page_header'; -import { renderWithRouter } from '../../lib'; -import { Provider } from 'react-redux'; +import { renderWithRouter, MountWithReduxProvider } from '../../lib'; describe('PageHeader', () => { it('shallow renders with the date picker', () => { const component = renderWithRouter( - + - + ); expect(component).toMatchSnapshot('page_header_with_date_picker'); }); it('shallow renders without the date picker', () => { const component = renderWithRouter( - + - + ); expect(component).toMatchSnapshot('page_header_no_date_picker'); }); it('shallow renders extra links', () => { const component = renderWithRouter( - + - + ); expect(component).toMatchSnapshot('page_header_with_extra_links'); }); }); - -const MockReduxProvider = ({ children }: { children: React.ReactElement }) => ( - - {children} - -); From 518410d53f3c4c42c25b6eb63cc82a690d7199ee Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Fri, 5 Jun 2020 19:13:15 -0400 Subject: [PATCH 29/35] Remove unneeded params from hook. --- .../plugins/uptime/public/hooks/use_filter_update.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/uptime/public/hooks/use_filter_update.ts b/x-pack/plugins/uptime/public/hooks/use_filter_update.ts index 54b94b8c98843..550de134c49bc 100644 --- a/x-pack/plugins/uptime/public/hooks/use_filter_update.ts +++ b/x-pack/plugins/uptime/public/hooks/use_filter_update.ts @@ -20,19 +20,14 @@ interface SelectedFilters { selectedFilters: Map; } -export const useFilterUpdate = ( - fieldName?: string, - values?: string[], - shouldUpdateUrl?: boolean, - alertParamFilters?: any -): SelectedFilters => { +export const useFilterUpdate = (fieldName?: string, values?: string[]): SelectedFilters => { const [getUrlParams, updateUrl] = useUrlParams(); const { filters: currentFilters } = getUrlParams(); // update filters in the URL from filter group const onFilterUpdate = (filtersKuery: string) => { - if (currentFilters !== filtersKuery && shouldUpdateUrl) { + if (currentFilters !== filtersKuery) { updateUrl({ filters: filtersKuery, pagination: '' }); } }; @@ -62,7 +57,7 @@ export const useFilterUpdate = ( } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [alertParamFilters, fieldName, values]); + }, [fieldName, values]); return { selectedTags: filterKueries.get('tags') || [], From ba2b18e82ca3c9be3755edf6fb807034ce841165 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Sat, 6 Jun 2020 16:08:08 -0400 Subject: [PATCH 30/35] Add more unit tests. --- .../alerts/__tests__/add_filter_btn.test.tsx | 180 +++++++++++++ .../__tests__/alert_field_number.test.tsx | 145 +++++++++++ .../__tests__/alert_monitor_status.test.tsx | 239 ++++++++---------- .../__tests__/old_alert_callout.test.tsx | 36 +++ .../overview/alerts/alert_monitor_status.tsx | 29 +-- .../filters_expression_select.test.tsx | 170 +++++++++++++ .../filters_expression_select.tsx | 19 +- .../filters_expression_select_container.tsx | 23 ++ .../alerts/monitor_expressions/index.ts | 1 + .../overview/alerts/old_alert_call_out.tsx | 33 +++ 10 files changed, 710 insertions(+), 165 deletions(-) create mode 100644 x-pack/plugins/uptime/public/components/overview/alerts/__tests__/add_filter_btn.test.tsx create mode 100644 x-pack/plugins/uptime/public/components/overview/alerts/__tests__/alert_field_number.test.tsx create mode 100644 x-pack/plugins/uptime/public/components/overview/alerts/__tests__/old_alert_callout.test.tsx create mode 100644 x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/__tests__/filters_expression_select.test.tsx create mode 100644 x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select_container.tsx create mode 100644 x-pack/plugins/uptime/public/components/overview/alerts/old_alert_call_out.tsx diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/add_filter_btn.test.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/add_filter_btn.test.tsx new file mode 100644 index 0000000000000..ac465eca4c5e5 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/add_filter_btn.test.tsx @@ -0,0 +1,180 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 { shallowWithIntl, mountWithIntl } from 'test_utils/enzyme_helpers'; +import { AddFilterButton } from '../add_filter_btn'; +import { EuiButtonEmpty, EuiContextMenuItem } from '@elastic/eui'; + +describe('AddFilterButton component', () => { + it('provides all filter choices', () => { + const component = shallowWithIntl( + + ); + expect(component).toMatchInlineSnapshot(` + + Add filter + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + id="singlePanel" + isOpen={false} + ownFocus={false} + panelPaddingSize="none" + > + + Location + , + + Tag + , + + Port + , + + Type + , + ] + } + /> + + `); + }); + + it('excludes filters that already have selected values', () => { + const component = shallowWithIntl( + + ); + expect(component).toMatchInlineSnapshot(` + + Add filter + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + id="singlePanel" + isOpen={false} + ownFocus={false} + panelPaddingSize="none" + > + + Type + , + ] + } + /> + + `); + }); + + it('popover is disabled if no values are available', () => { + const component = shallowWithIntl( + + ); + expect(component).toMatchInlineSnapshot(` + + Add filter + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + id="singlePanel" + isOpen={false} + ownFocus={false} + panelPaddingSize="none" + > + + + `); + }); + + it('filter select', () => { + const mockOnNewFilter = jest.fn(); + const component = mountWithIntl( + + ); + component.find(EuiButtonEmpty).simulate('click', { target: { value: '0' } }); + component + .find(EuiContextMenuItem) + .first() + .simulate('click', { target: { value: '0' } }); + expect(mockOnNewFilter).toHaveBeenCalled(); + expect(mockOnNewFilter.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "observer.geo.name", + ], + ] + `); + }); +}); diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/alert_field_number.test.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/alert_field_number.test.tsx new file mode 100644 index 0000000000000..e2564992c76d2 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/alert_field_number.test.tsx @@ -0,0 +1,145 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 { AlertFieldNumber, handleAlertFieldNumberChange } from '../alert_field_number'; + +describe('AlertFieldNumber', () => { + describe('handleAlertFieldNumberChange', () => { + let mockSetIsInvalid: jest.Mock; + let mockSetFieldValue: jest.Mock; + + beforeEach(() => { + mockSetIsInvalid = jest.fn(); + mockSetFieldValue = jest.fn(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('sets a valid number', () => { + handleAlertFieldNumberChange( + // @ts-ignore no need to implement this entire type here + { target: { value: '23' } }, + false, + mockSetIsInvalid, + mockSetFieldValue + ); + expect(mockSetIsInvalid).not.toHaveBeenCalled(); + expect(mockSetFieldValue).toHaveBeenCalledTimes(1); + expect(mockSetFieldValue.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + 23, + ], + ] + `); + }); + + it('sets invalid for NaN value', () => { + handleAlertFieldNumberChange( + // @ts-ignore no need to implement this entire type here + { target: { value: 'foo' } }, + false, + mockSetIsInvalid, + mockSetFieldValue + ); + expect(mockSetIsInvalid).toHaveBeenCalledTimes(1); + expect(mockSetIsInvalid.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + true, + ], + ] + `); + expect(mockSetFieldValue).not.toHaveBeenCalled(); + }); + + it('sets invalid to false when a valid value is received and invalid is true', () => { + handleAlertFieldNumberChange( + // @ts-ignore no need to implement this entire type here + { target: { value: '23' } }, + true, + mockSetIsInvalid, + mockSetFieldValue + ); + expect(mockSetIsInvalid).toHaveBeenCalledTimes(1); + expect(mockSetIsInvalid.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + false, + ], + ] + `); + expect(mockSetFieldValue).toHaveBeenCalledTimes(1); + expect(mockSetFieldValue.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + 23, + ], + ] + `); + }); + }); + + describe('AlertFieldNumber', () => { + it('responds with correct number value when a valid number is specified', () => { + const mockValueHandler = jest.fn(); + const component = mountWithIntl( + + ); + component.find('input').simulate('change', { target: { value: '45' } }); + expect(mockValueHandler).toHaveBeenCalled(); + expect(mockValueHandler.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + 45, + ], + ] + `); + }); + + it('does not set an invalid number value', () => { + const mockValueHandler = jest.fn(); + const component = mountWithIntl( + + ); + component.find('input').simulate('change', { target: { value: 'not a number' } }); + expect(mockValueHandler).not.toHaveBeenCalled(); + expect(mockValueHandler.mock.calls).toEqual([]); + }); + + it('does not set a number value less than 1', () => { + const mockValueHandler = jest.fn(); + const component = mountWithIntl( + + ); + component.find('input').simulate('change', { target: { value: '0' } }); + expect(mockValueHandler).not.toHaveBeenCalled(); + expect(mockValueHandler.mock.calls).toEqual([]); + }); + }); +}); diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/alert_monitor_status.test.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/alert_monitor_status.test.tsx index aa17086f49034..430f91ff46f15 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/alert_monitor_status.test.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/alert_monitor_status.test.tsx @@ -5,141 +5,118 @@ */ import React from 'react'; -import { mountWithIntl } from 'test_utils/enzyme_helpers'; -import { AlertFieldNumber, handleAlertFieldNumberChange } from '../alert_field_number'; +import { shallowWithIntl } from 'test_utils/enzyme_helpers'; +import { AlertMonitorStatusComponent, AlertMonitorStatusProps } from '../alert_monitor_status'; describe('alert monitor status component', () => { - describe('handleAlertFieldNumberChange', () => { - let mockSetIsInvalid: jest.Mock; - let mockSetFieldValue: jest.Mock; + describe('AlertMonitorStatus', () => { + const defaultProps: AlertMonitorStatusProps = { + alertParams: { + numTimes: 3, + search: 'monitor.id: foo', + timerangeUnit: 'h', + timerangeCount: 21, + }, + autocomplete: { + addQuerySuggestionProvider: jest.fn(), + getQuerySuggestions: jest.fn(), + }, + enabled: true, + hasFilters: false, + isOldAlert: true, + locations: [], + snapshotCount: 0, + snapshotLoading: false, + numTimes: 14, + setAlertParams: jest.fn(), + timerange: { from: 'now-12h', to: 'now' }, + }; - beforeEach(() => { - mockSetIsInvalid = jest.fn(); - mockSetFieldValue = jest.fn(); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - it('sets a valid number', () => { - handleAlertFieldNumberChange( - // @ts-ignore no need to implement this entire type here - { target: { value: '23' } }, - false, - mockSetIsInvalid, - mockSetFieldValue - ); - expect(mockSetIsInvalid).not.toHaveBeenCalled(); - expect(mockSetFieldValue).toHaveBeenCalledTimes(1); - expect(mockSetFieldValue.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - 23, - ], - ] - `); - }); - - it('sets invalid for NaN value', () => { - handleAlertFieldNumberChange( - // @ts-ignore no need to implement this entire type here - { target: { value: 'foo' } }, - false, - mockSetIsInvalid, - mockSetFieldValue - ); - expect(mockSetIsInvalid).toHaveBeenCalledTimes(1); - expect(mockSetIsInvalid.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - true, - ], - ] - `); - expect(mockSetFieldValue).not.toHaveBeenCalled(); - }); - - it('sets invalid to false when a valid value is received and invalid is true', () => { - handleAlertFieldNumberChange( - // @ts-ignore no need to implement this entire type here - { target: { value: '23' } }, - true, - mockSetIsInvalid, - mockSetFieldValue - ); - expect(mockSetIsInvalid).toHaveBeenCalledTimes(1); - expect(mockSetIsInvalid.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - false, - ], - ] + it('passes default props to children', () => { + const component = shallowWithIntl(); + expect(component).toMatchInlineSnapshot(` + + + + + + + + + + + + + + + } + /> + + `); - expect(mockSetFieldValue).toHaveBeenCalledTimes(1); - expect(mockSetFieldValue.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - 23, - ], - ] - `); - }); - }); - - describe('AlertFieldNumber', () => { - it('responds with correct number value when a valid number is specified', () => { - const mockValueHandler = jest.fn(); - const component = mountWithIntl( - - ); - component.find('input').simulate('change', { target: { value: '45' } }); - expect(mockValueHandler).toHaveBeenCalled(); - expect(mockValueHandler.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - 45, - ], - ] - `); - }); - - it('does not set an invalid number value', () => { - const mockValueHandler = jest.fn(); - const component = mountWithIntl( - - ); - component.find('input').simulate('change', { target: { value: 'not a number' } }); - expect(mockValueHandler).not.toHaveBeenCalled(); - expect(mockValueHandler.mock.calls).toEqual([]); - }); - - it('does not set a number value less than 1', () => { - const mockValueHandler = jest.fn(); - const component = mountWithIntl( - - ); - component.find('input').simulate('change', { target: { value: '0' } }); - expect(mockValueHandler).not.toHaveBeenCalled(); - expect(mockValueHandler.mock.calls).toEqual([]); }); }); }); diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/old_alert_callout.test.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/old_alert_callout.test.tsx new file mode 100644 index 0000000000000..e324b213548d8 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/old_alert_callout.test.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { shallowWithIntl } from 'test_utils/enzyme_helpers'; +import { OldAlertCallOut } from '../old_alert_call_out'; + +describe('OldAlertCallOut', () => { + it('returns null for new alert type', () => { + expect(shallowWithIntl()).toEqual({}); + }); + + it('renders the call out for old alerts', () => { + expect(shallowWithIntl()).toMatchInlineSnapshot(` + + + + } + /> + + `); + }); +}); diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx index cd055d4cb72d8..be8401fa108f2 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx @@ -12,13 +12,13 @@ import * as labels from './translations'; import { DownNoExpressionSelect, TimeExpressionSelect, - FiltersExpressionsSelect, + FiltersExpressionSelectContainer, } from './monitor_expressions'; - import { AddFilterButton } from './add_filter_btn'; +import { OldAlertCallOut } from './old_alert_call_out'; import { KueryBar } from '..'; -interface AlertMonitorStatusProps { +export interface AlertMonitorStatusProps { alertParams: { [key: string]: any }; autocomplete: DataPublicPluginSetup['autocomplete']; enabled: boolean; @@ -52,20 +52,7 @@ export const AlertMonitorStatusComponent: React.FC = (p return ( <> - - - {isOldAlert && ( - - } - iconType="alert" - /> - )} + @@ -96,13 +83,13 @@ export const AlertMonitorStatusComponent: React.FC = (p - { - if (newFilters.includes(removeFiler)) { - setNewFilters(newFilters.filter((item) => item !== removeFiler)); + onRemoveFilter={(removeFilter: string) => { + if (newFilters.includes(removeFilter)) { + setNewFilters(newFilters.filter((item) => item !== removeFilter)); } }} /> diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/__tests__/filters_expression_select.test.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/__tests__/filters_expression_select.test.tsx new file mode 100644 index 0000000000000..d23496222f80e --- /dev/null +++ b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/__tests__/filters_expression_select.test.tsx @@ -0,0 +1,170 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { shallowWithIntl } from 'test_utils/enzyme_helpers'; +import { FiltersExpressionsSelect } from '../filters_expression_select'; + +describe('filters expression select component', () => { + it('is empty when no filters available', () => { + const component = shallowWithIntl( + + ); + expect(component).toMatchInlineSnapshot(` + + + + `); + }); + + it('contains provided new filter values', () => { + const component = shallowWithIntl( + + ); + expect(component).toMatchInlineSnapshot(` + + + + + } + disabled={true} + fieldName="observer.geo.name" + forceOpen={false} + id="filter_location" + items={Array []} + loading={false} + onFilterFieldChange={[Function]} + selectedItems={Array []} + setForceOpen={[Function]} + title="Scheme" + /> + + + + + + + + + `); + }); + + it('contains provided selected filter values', () => { + const component = shallowWithIntl( + + ); + expect(component).toMatchInlineSnapshot(` + + + + + } + disabled={false} + fieldName="tags" + forceOpen={false} + id="filter_tags" + items={ + Array [ + "foo", + "bar", + ] + } + loading={false} + onFilterFieldChange={[Function]} + selectedItems={Array []} + setForceOpen={[Function]} + title="Tags" + /> + + + + + + + + + `); + }); +}); diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select.tsx index 744dcaaaf8376..41f8df22a906c 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select.tsx @@ -5,30 +5,23 @@ */ import React, { useState } from 'react'; -import { useSelector } from 'react-redux'; import { EuiButtonIcon, EuiExpression, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import { FilterPopover } from '../../filter_group/filter_popover'; -import { overviewFiltersSelector } from '../../../../state/selectors'; import { filterLabels } from '../../filter_group/translations'; import { alertFilterLabels } from './translations'; +import { FilterExpressionsSelectProps } from './filters_expression_select_container'; +import { OverviewFiltersState } from '../../../../state/reducers/overview_filters'; -interface Props { - alertParams: { [key: string]: any }; - newFilters: string[]; - onRemoveFilter: (val: string) => void; - setAlertParams: (key: string, value: any) => void; -} +type Props = FilterExpressionsSelectProps & Pick; export const FiltersExpressionsSelect: React.FC = ({ + alertParams, setAlertParams, newFilters, onRemoveFilter, - alertParams, + filters: overviewFilters, }) => { - const { - filters: { tags, ports, schemes, locations }, - } = useSelector(overviewFiltersSelector); - + const { tags, ports, schemes, locations } = overviewFilters; const selectedPorts = alertParams?.filters?.['url.port'] ?? []; const selectedLocations = alertParams?.filters?.['observer.geo.name'] ?? []; const selectedSchemes = alertParams?.filters?.['monitor.type'] ?? []; diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select_container.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select_container.tsx new file mode 100644 index 0000000000000..f5c1bac6cc7a1 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select_container.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 { useSelector } from 'react-redux'; +import { FiltersExpressionsSelect } from './filters_expression_select'; +import { overviewFiltersSelector } from '../../../../state/selectors'; + +export interface FilterExpressionsSelectProps { + alertParams: { [key: string]: any }; + newFilters: string[]; + onRemoveFilter: (val: string) => void; + setAlertParams: (key: string, value: any) => void; +} + +export const FiltersExpressionSelectContainer: React.FC = (props) => { + const overviewFilters = useSelector(overviewFiltersSelector); + + return ; +}; diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/index.ts b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/index.ts index acc19dfbc8f8b..e6f47e744f5ea 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/index.ts +++ b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/index.ts @@ -6,4 +6,5 @@ export { DownNoExpressionSelect } from './down_number_select'; export { FiltersExpressionsSelect } from './filters_expression_select'; +export { FiltersExpressionSelectContainer } from './filters_expression_select_container'; export { TimeExpressionSelect } from './time_expression_select'; diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/old_alert_call_out.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/old_alert_call_out.tsx new file mode 100644 index 0000000000000..eba66f7bfd570 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/overview/alerts/old_alert_call_out.tsx @@ -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 { EuiSpacer, EuiCallOut } from '@elastic/eui'; +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; + +interface Props { + isOldAlert: boolean; +} + +export const OldAlertCallOut: React.FC = ({ isOldAlert }) => { + if (!isOldAlert) return null; + return ( + <> + + + + } + iconType="alert" + /> + + ); +}; From 290905ebff34b0e5fd27ade7fdee60a0d17e92e8 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Sat, 6 Jun 2020 17:53:34 -0400 Subject: [PATCH 31/35] Reducing functional test flakiness. --- .../test/functional/services/uptime/alerts.ts | 23 +++++++++++----- .../apps/uptime/flyout_loads.ts | 26 +++++++++++-------- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/x-pack/test/functional/services/uptime/alerts.ts b/x-pack/test/functional/services/uptime/alerts.ts index 1128f1dd00fe3..94d1150f32690 100644 --- a/x-pack/test/functional/services/uptime/alerts.ts +++ b/x-pack/test/functional/services/uptime/alerts.ts @@ -9,16 +9,25 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export function UptimeAlertsProvider({ getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const browser = getService('browser'); + const retry = getService('retry'); return { async openFlyout(alertType: 'monitorStatus' | 'tls') { - await testSubjects.click('xpack.uptime.alertsPopover.toggleButton', 5000); - await testSubjects.click('xpack.uptime.openAlertContextPanel', 5000); - if (alertType === 'monitorStatus') { - await testSubjects.click('xpack.uptime.toggleAlertFlyout', 5000); - } else if (alertType === 'tls') { - await testSubjects.click('xpack.uptime.toggleTlsAlertFlyout'); - } + await retry.try( + async () => { + await testSubjects.click('xpack.uptime.alertsPopover.toggleButton'); + await testSubjects.click('xpack.uptime.openAlertContextPanel'); + if (alertType === 'monitorStatus') { + await testSubjects.existOrFail('xpack.uptime.toggleAlertFlyout'); + await testSubjects.click('xpack.uptime.toggleAlertFlyout'); + } else if (alertType === 'tls') { + await testSubjects.click('xpack.uptime.toggleTlsAlertFlyout'); + } + }, + async () => { + await browser.refresh(); + } + ); }, async openMonitorStatusAlertType(alertType: string) { return testSubjects.click(`xpack.uptime.alerts.${alertType}-SelectOption`, 5000); diff --git a/x-pack/test/functional_with_es_ssl/apps/uptime/flyout_loads.ts b/x-pack/test/functional_with_es_ssl/apps/uptime/flyout_loads.ts index 59931cf4c6e84..c55a3b7423868 100644 --- a/x-pack/test/functional_with_es_ssl/apps/uptime/flyout_loads.ts +++ b/x-pack/test/functional_with_es_ssl/apps/uptime/flyout_loads.ts @@ -8,25 +8,29 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('uptime alert flyout', () => { - const pageObjects = getPageObjects(['common', 'uptime']); const uptimeService = getService('uptime'); const browserService = getService('browser'); + const retry = getService('retry'); - afterEach(async () => browserService.refresh()); + afterEach(async () => await browserService.refresh()); it('can open status flyout', async () => { - await pageObjects.uptime.goToUptimeOverview(); - await uptimeService.alerts.openFlyout('monitorStatus'); - await uptimeService.alerts.assertMonitorStatusFlyoutSearchBarExists(); + await retry.tryForTime(15000, async () => { + await uptimeService.navigation.goToUptime(); + await uptimeService.alerts.openFlyout('monitorStatus'); + await uptimeService.alerts.assertMonitorStatusFlyoutSearchBarExists(); + }); }); it('can open tls flyout', async () => { - await pageObjects.uptime.goToUptimeOverview(); - await uptimeService.alerts.openFlyout('tls'); - await Promise.all([ - uptimeService.alerts.assertTlsFieldExists('expiration'), - uptimeService.alerts.assertTlsFieldExists('age'), - ]); + await retry.tryForTime(15000, async () => { + await uptimeService.navigation.goToUptime(); + await uptimeService.alerts.openFlyout('tls'); + await Promise.all([ + uptimeService.alerts.assertTlsFieldExists('expiration'), + uptimeService.alerts.assertTlsFieldExists('age'), + ]); + }); }); }); }; From b761ea41ddc24eb8defe6d17a50a847261d7abea Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Mon, 8 Jun 2020 11:38:17 -0400 Subject: [PATCH 32/35] Alert flyout controls update url only within Uptime app. --- .../overview/alerts/alert_monitor_status.tsx | 7 +++++-- .../alerts_containers/alert_monitor_status.tsx | 7 ++++++- .../filters_expression_select.tsx | 14 ++++++++++++-- .../filters_expression_select_container.tsx | 1 + .../uptime/public/hooks/use_filter_update.ts | 8 ++++++-- 5 files changed, 30 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx index be8401fa108f2..a1b4762627e7c 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alert_monitor_status.tsx @@ -29,6 +29,7 @@ export interface AlertMonitorStatusProps { snapshotLoading: boolean; numTimes: number; setAlertParams: (key: string, value: any) => void; + shouldUpdateUrl: boolean; timerange: { from: string; to: string; @@ -41,6 +42,7 @@ export const AlertMonitorStatusComponent: React.FC = (p hasFilters, isOldAlert, setAlertParams, + shouldUpdateUrl, snapshotCount, snapshotLoading, } = props; @@ -60,7 +62,7 @@ export const AlertMonitorStatusComponent: React.FC = (p aria-label={labels.ALERT_KUERY_BAR_ARIA} autocomplete={props.autocomplete} defaultKuery={alertParams.search} - shouldUpdateUrl={false} + shouldUpdateUrl={shouldUpdateUrl} updateDefaultKuery={(value: string) => setAlertParams('search', value)} data-test-subj="xpack.uptime.alerts.monitorStatus.filterBar" /> @@ -84,7 +86,6 @@ export const AlertMonitorStatusComponent: React.FC = (p { @@ -92,6 +93,8 @@ export const AlertMonitorStatusComponent: React.FC = (p setNewFilters(newFilters.filter((item) => item !== removeFilter)); } }} + setAlertParams={setAlertParams} + shouldUpdateUrl={shouldUpdateUrl} /> diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx index b570572ba79da..ac87dbfcd13aa 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/alerts_containers/alert_monitor_status.tsx @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useEffect } from 'react'; +import React, { useMemo, useEffect } from 'react'; +import { useLocation } from 'react-router-dom'; import { useSelector, useDispatch } from 'react-redux'; import { DataPublicPluginSetup } from 'src/plugins/data/public'; import { isRight } from 'fp-ts/lib/Either'; @@ -109,6 +110,9 @@ export const AlertMonitorStatus: React.FC = ({ } }, [alertParams, setAlertParams, selectedFilters]); + const { pathname } = useLocation(); + const shouldUpdateUrl = useMemo(() => pathname.indexOf('app/uptime') !== -1, [pathname]); + return ( = ({ locations={locations} numTimes={numTimes} setAlertParams={setAlertParams} + shouldUpdateUrl={shouldUpdateUrl} snapshotCount={count.total} snapshotLoading={loading} timerange={timerange} diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select.tsx index 41f8df22a906c..b06b733711651 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select.tsx @@ -11,15 +11,17 @@ import { filterLabels } from '../../filter_group/translations'; import { alertFilterLabels } from './translations'; import { FilterExpressionsSelectProps } from './filters_expression_select_container'; import { OverviewFiltersState } from '../../../../state/reducers/overview_filters'; +import { useFilterUpdate } from '../../../../hooks/use_filter_update'; type Props = FilterExpressionsSelectProps & Pick; export const FiltersExpressionsSelect: React.FC = ({ alertParams, - setAlertParams, + filters: overviewFilters, newFilters, onRemoveFilter, - filters: overviewFilters, + setAlertParams, + shouldUpdateUrl, }) => { const { tags, ports, schemes, locations } = overviewFilters; const selectedPorts = alertParams?.filters?.['url.port'] ?? []; @@ -27,6 +29,13 @@ export const FiltersExpressionsSelect: React.FC = ({ const selectedSchemes = alertParams?.filters?.['monitor.type'] ?? []; const selectedTags = alertParams?.filters?.tags ?? []; + const [updatedFieldValues, setUpdatedFieldValues] = useState<{ + fieldName: string; + values: string[]; + }>({ fieldName: '', values: [] }); + + useFilterUpdate(updatedFieldValues.fieldName, updatedFieldValues.values, shouldUpdateUrl); + const onFilterFieldChange = (fieldName: string, values: string[]) => { // the `filters` field is no longer a string if (alertParams.filters && typeof alertParams.filters !== 'string') { @@ -46,6 +55,7 @@ export const FiltersExpressionsSelect: React.FC = ({ ) ); } + setUpdatedFieldValues({ fieldName, values }); }; const monitorFilters = [ diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select_container.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select_container.tsx index f5c1bac6cc7a1..45f77e018b257 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select_container.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select_container.tsx @@ -14,6 +14,7 @@ export interface FilterExpressionsSelectProps { newFilters: string[]; onRemoveFilter: (val: string) => void; setAlertParams: (key: string, value: any) => void; + shouldUpdateUrl: boolean; } export const FiltersExpressionSelectContainer: React.FC = (props) => { diff --git a/x-pack/plugins/uptime/public/hooks/use_filter_update.ts b/x-pack/plugins/uptime/public/hooks/use_filter_update.ts index 550de134c49bc..fefb676e6e2b5 100644 --- a/x-pack/plugins/uptime/public/hooks/use_filter_update.ts +++ b/x-pack/plugins/uptime/public/hooks/use_filter_update.ts @@ -20,14 +20,18 @@ interface SelectedFilters { selectedFilters: Map; } -export const useFilterUpdate = (fieldName?: string, values?: string[]): SelectedFilters => { +export const useFilterUpdate = ( + fieldName?: string, + values?: string[], + shouldUpdateUrl: boolean = true +): SelectedFilters => { const [getUrlParams, updateUrl] = useUrlParams(); const { filters: currentFilters } = getUrlParams(); // update filters in the URL from filter group const onFilterUpdate = (filtersKuery: string) => { - if (currentFilters !== filtersKuery) { + if (currentFilters !== filtersKuery && shouldUpdateUrl) { updateUrl({ filters: filtersKuery, pagination: '' }); } }; From ce725fb5ac846cbae916e90b61bd8a6f5c61c5ea Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Mon, 8 Jun 2020 12:06:52 -0400 Subject: [PATCH 33/35] Extract context interaction to container component, update snapshots. --- .../__tests__/alert_monitor_status.test.tsx | 1 - .../filters_expression_select.test.tsx | 6 ++++++ .../filters_expression_select.tsx | 18 ++++++++---------- .../filters_expression_select_container.tsx | 18 ++++++++++++++++-- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/alert_monitor_status.test.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/alert_monitor_status.test.tsx index 430f91ff46f15..99f0c27f666d5 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/alert_monitor_status.test.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/alert_monitor_status.test.tsx @@ -52,7 +52,6 @@ describe('alert monitor status component', () => { } data-test-subj="xpack.uptime.alerts.monitorStatus.filterBar" defaultKuery="monitor.id: foo" - shouldUpdateUrl={false} updateDefaultKuery={[Function]} /> { tags: [], }} setAlertParams={jest.fn()} + setUpdatedFieldValues={jest.fn()} + shouldUpdateUrl={false} /> ); expect(component).toMatchInlineSnapshot(` @@ -46,6 +48,8 @@ describe('filters expression select component', () => { locations: [], }} setAlertParams={jest.fn()} + setUpdatedFieldValues={jest.fn()} + shouldUpdateUrl={false} /> ); expect(component).toMatchInlineSnapshot(` @@ -111,6 +115,8 @@ describe('filters expression select component', () => { locations: [], }} setAlertParams={jest.fn()} + setUpdatedFieldValues={jest.fn()} + shouldUpdateUrl={false} /> ); expect(component).toMatchInlineSnapshot(` diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select.tsx index b06b733711651..64862a8b748d8 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select.tsx @@ -11,9 +11,14 @@ import { filterLabels } from '../../filter_group/translations'; import { alertFilterLabels } from './translations'; import { FilterExpressionsSelectProps } from './filters_expression_select_container'; import { OverviewFiltersState } from '../../../../state/reducers/overview_filters'; -import { useFilterUpdate } from '../../../../hooks/use_filter_update'; -type Props = FilterExpressionsSelectProps & Pick; +type FilterFieldUpdate = (updateTarget: { fieldName: string; values: string[] }) => void; + +interface OwnProps { + setUpdatedFieldValues: FilterFieldUpdate; +} + +type Props = FilterExpressionsSelectProps & Pick & OwnProps; export const FiltersExpressionsSelect: React.FC = ({ alertParams, @@ -21,7 +26,7 @@ export const FiltersExpressionsSelect: React.FC = ({ newFilters, onRemoveFilter, setAlertParams, - shouldUpdateUrl, + setUpdatedFieldValues, }) => { const { tags, ports, schemes, locations } = overviewFilters; const selectedPorts = alertParams?.filters?.['url.port'] ?? []; @@ -29,13 +34,6 @@ export const FiltersExpressionsSelect: React.FC = ({ const selectedSchemes = alertParams?.filters?.['monitor.type'] ?? []; const selectedTags = alertParams?.filters?.tags ?? []; - const [updatedFieldValues, setUpdatedFieldValues] = useState<{ - fieldName: string; - values: string[]; - }>({ fieldName: '', values: [] }); - - useFilterUpdate(updatedFieldValues.fieldName, updatedFieldValues.values, shouldUpdateUrl); - const onFilterFieldChange = (fieldName: string, values: string[]) => { // the `filters` field is no longer a string if (alertParams.filters && typeof alertParams.filters !== 'string') { diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select_container.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select_container.tsx index 45f77e018b257..6605f653d7f5c 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select_container.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/monitor_expressions/filters_expression_select_container.tsx @@ -4,10 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { useState } from 'react'; import { useSelector } from 'react-redux'; import { FiltersExpressionsSelect } from './filters_expression_select'; import { overviewFiltersSelector } from '../../../../state/selectors'; +import { useFilterUpdate } from '../../../../hooks/use_filter_update'; export interface FilterExpressionsSelectProps { alertParams: { [key: string]: any }; @@ -18,7 +19,20 @@ export interface FilterExpressionsSelectProps { } export const FiltersExpressionSelectContainer: React.FC = (props) => { + const [updatedFieldValues, setUpdatedFieldValues] = useState<{ + fieldName: string; + values: string[]; + }>({ fieldName: '', values: [] }); + + useFilterUpdate(updatedFieldValues.fieldName, updatedFieldValues.values, props.shouldUpdateUrl); + const overviewFilters = useSelector(overviewFiltersSelector); - return ; + return ( + + ); }; From 0eea5fd9d04b76ebd230a8469ea9d26826afc554 Mon Sep 17 00:00:00 2001 From: Justin Kambic Date: Mon, 8 Jun 2020 12:47:20 -0400 Subject: [PATCH 34/35] Add missing parameter to test file. --- .../overview/alerts/__tests__/alert_monitor_status.test.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/alert_monitor_status.test.tsx b/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/alert_monitor_status.test.tsx index 99f0c27f666d5..b955667ea7400 100644 --- a/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/alert_monitor_status.test.tsx +++ b/x-pack/plugins/uptime/public/components/overview/alerts/__tests__/alert_monitor_status.test.tsx @@ -25,6 +25,7 @@ describe('alert monitor status component', () => { hasFilters: false, isOldAlert: true, locations: [], + shouldUpdateUrl: false, snapshotCount: 0, snapshotLoading: false, numTimes: 14, @@ -52,6 +53,7 @@ describe('alert monitor status component', () => { } data-test-subj="xpack.uptime.alerts.monitorStatus.filterBar" defaultKuery="monitor.id: foo" + shouldUpdateUrl={false} updateDefaultKuery={[Function]} /> { newFilters={Array []} onRemoveFilter={[Function]} setAlertParams={[MockFunction]} + shouldUpdateUrl={false} /> Date: Mon, 8 Jun 2020 12:56:58 -0400 Subject: [PATCH 35/35] Remove flaky functional test. --- .../functional/page_objects/uptime_page.ts | 4 --- .../test/functional/services/uptime/alerts.ts | 33 ++++------------- .../apps/uptime/flyout_loads.ts | 36 ------------------- .../apps/uptime/index.ts | 1 - 4 files changed, 7 insertions(+), 67 deletions(-) delete mode 100644 x-pack/test/functional_with_es_ssl/apps/uptime/flyout_loads.ts diff --git a/x-pack/test/functional/page_objects/uptime_page.ts b/x-pack/test/functional/page_objects/uptime_page.ts index cc8494f4ad31c..074a2d598be8a 100644 --- a/x-pack/test/functional/page_objects/uptime_page.ts +++ b/x-pack/test/functional/page_objects/uptime_page.ts @@ -29,10 +29,6 @@ export function UptimePageProvider({ getPageObjects, getService }: FtrProviderCo } } - public async goToUptimeOverview() { - return navigation.goToUptime(); - } - public async goToUptimeOverviewAndLoadData( dateStart: string, dateEnd: string, diff --git a/x-pack/test/functional/services/uptime/alerts.ts b/x-pack/test/functional/services/uptime/alerts.ts index 94d1150f32690..c4f75b843d781 100644 --- a/x-pack/test/functional/services/uptime/alerts.ts +++ b/x-pack/test/functional/services/uptime/alerts.ts @@ -9,39 +9,20 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export function UptimeAlertsProvider({ getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const browser = getService('browser'); - const retry = getService('retry'); return { async openFlyout(alertType: 'monitorStatus' | 'tls') { - await retry.try( - async () => { - await testSubjects.click('xpack.uptime.alertsPopover.toggleButton'); - await testSubjects.click('xpack.uptime.openAlertContextPanel'); - if (alertType === 'monitorStatus') { - await testSubjects.existOrFail('xpack.uptime.toggleAlertFlyout'); - await testSubjects.click('xpack.uptime.toggleAlertFlyout'); - } else if (alertType === 'tls') { - await testSubjects.click('xpack.uptime.toggleTlsAlertFlyout'); - } - }, - async () => { - await browser.refresh(); - } - ); + await testSubjects.click('xpack.uptime.alertsPopover.toggleButton', 5000); + await testSubjects.click('xpack.uptime.openAlertContextPanel', 5000); + if (alertType === 'monitorStatus') { + await testSubjects.click('xpack.uptime.toggleAlertFlyout', 5000); + } else if (alertType === 'tls') { + await testSubjects.click('xpack.uptime.toggleTlsAlertFlyout'); + } }, async openMonitorStatusAlertType(alertType: string) { return testSubjects.click(`xpack.uptime.alerts.${alertType}-SelectOption`, 5000); }, - async assertTlsFieldExists(id: string) { - return testSubjects.existOrFail(`xpack.uptime.alerts.tls.expressionPopover.${id}`, { - timeout: 15 * 1000, - }); - }, - async assertMonitorStatusFlyoutSearchBarExists() { - return testSubjects.existOrFail('xpack.uptime.alerts.monitorStatus.filterBar', { - timeout: 15 * 1000, - }); - }, async setAlertTags(tags: string[]) { for (let i = 0; i < tags.length; i += 1) { await testSubjects.click('comboBoxSearchInput', 5000); diff --git a/x-pack/test/functional_with_es_ssl/apps/uptime/flyout_loads.ts b/x-pack/test/functional_with_es_ssl/apps/uptime/flyout_loads.ts deleted file mode 100644 index c55a3b7423868..0000000000000 --- a/x-pack/test/functional_with_es_ssl/apps/uptime/flyout_loads.ts +++ /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 { FtrProviderContext } from '../../ftr_provider_context'; - -export default ({ getPageObjects, getService }: FtrProviderContext) => { - describe('uptime alert flyout', () => { - const uptimeService = getService('uptime'); - const browserService = getService('browser'); - const retry = getService('retry'); - - afterEach(async () => await browserService.refresh()); - - it('can open status flyout', async () => { - await retry.tryForTime(15000, async () => { - await uptimeService.navigation.goToUptime(); - await uptimeService.alerts.openFlyout('monitorStatus'); - await uptimeService.alerts.assertMonitorStatusFlyoutSearchBarExists(); - }); - }); - - it('can open tls flyout', async () => { - await retry.tryForTime(15000, async () => { - await uptimeService.navigation.goToUptime(); - await uptimeService.alerts.openFlyout('tls'); - await Promise.all([ - uptimeService.alerts.assertTlsFieldExists('expiration'), - uptimeService.alerts.assertTlsFieldExists('age'), - ]); - }); - }); - }); -}; diff --git a/x-pack/test/functional_with_es_ssl/apps/uptime/index.ts b/x-pack/test/functional_with_es_ssl/apps/uptime/index.ts index 616b154da9c33..ce91a2a26ce91 100644 --- a/x-pack/test/functional_with_es_ssl/apps/uptime/index.ts +++ b/x-pack/test/functional_with_es_ssl/apps/uptime/index.ts @@ -22,7 +22,6 @@ export default ({ getService, loadTestFile }: FtrProviderContext) => { after(async () => await esArchiver.unload(ARCHIVE)); loadTestFile(require.resolve('./alert_flyout')); - loadTestFile(require.resolve('./flyout_loads')); }); }); };