From d8442fd2d06396a139125d56ed5bf781f607c81f Mon Sep 17 00:00:00 2001 From: Mihir Soni Date: Mon, 6 May 2019 20:37:22 -0700 Subject: [PATCH 1/6] Initial config change and updated hits.total to hits.total.value --- package.json | 4 ++-- .../MonitorTimeField/MonitorTimeField.js | 1 + .../QueryPerformance/QueryPerformance.js | 2 +- .../DefineMonitor/utils/mappings.js | 9 +------- .../DefineMonitor/utils/mappings.test.js | 22 +++++++++---------- .../CreateTrigger/utils/constants.js | 2 +- .../utils/formikToTrigger.test.js | 2 +- .../CreateDestination/utils/validations.js | 2 +- .../DestinationsList/DestinationsList.js | 2 +- public/utils/validate.js | 2 +- server/clusters/alerting/alertingPlugin.js | 2 +- server/services/AlertService.js | 2 +- server/services/DestinationsService.js | 3 +-- server/services/MonitorService.js | 2 +- 14 files changed, 24 insertions(+), 33 deletions(-) diff --git a/package.json b/package.json index c9bd24c7..8a7f3353 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "opendistro-alerting", - "version": "0.9.0.0", + "version": "0.1.0.0", "description": "Kibana Alerting Plugin", "main": "index.js", "license": "Apache-2.0", "homepage": "https://github.com/opendistro-for-elasticsearch/alerting-kibana-plugin", "kibana": { - "version": "6.7.1", + "version": "7.0.0", "templateVersion": "6.3.3" }, "repository": { diff --git a/public/pages/CreateMonitor/components/MonitorTimeField/MonitorTimeField.js b/public/pages/CreateMonitor/components/MonitorTimeField/MonitorTimeField.js index 9af26f13..0778db24 100644 --- a/public/pages/CreateMonitor/components/MonitorTimeField/MonitorTimeField.js +++ b/public/pages/CreateMonitor/components/MonitorTimeField/MonitorTimeField.js @@ -21,6 +21,7 @@ import { validateTimeField } from './utils/validation'; const MonitorTimeField = ({ dataTypes }) => { // Default empty option + options from index mappings mapped to ui select form + console.log('dataTypes', dataTypes); const dateFields = Array.from(dataTypes.date || []); const options = [''].concat(dateFields).map(option => ({ value: option, text: option })); return ( diff --git a/public/pages/CreateMonitor/components/QueryPerformance/QueryPerformance.js b/public/pages/CreateMonitor/components/QueryPerformance/QueryPerformance.js index 69a0fcc0..91cf45d8 100644 --- a/public/pages/CreateMonitor/components/QueryPerformance/QueryPerformance.js +++ b/public/pages/CreateMonitor/components/QueryPerformance/QueryPerformance.js @@ -59,7 +59,7 @@ const QueryPerformance = ({ response }) => ( Hits - {_.get(response, 'hits.total', DEFAULT_EMPTY_DATA)} + {_.get(response, 'hits.total.value', DEFAULT_EMPTY_DATA)} diff --git a/public/pages/CreateMonitor/containers/DefineMonitor/utils/mappings.js b/public/pages/CreateMonitor/containers/DefineMonitor/utils/mappings.js index 8b1a8274..aa9d80fc 100644 --- a/public/pages/CreateMonitor/containers/DefineMonitor/utils/mappings.js +++ b/public/pages/CreateMonitor/containers/DefineMonitor/utils/mappings.js @@ -13,11 +13,6 @@ * permissions and limitations under the License. */ -export function getDocMappings([index, { mappings }]) { - const [docType, docMappings] = Object.entries(mappings).pop(); - return docMappings; -} - export function shouldSkip(mapping) { const isDisabled = mapping.enabled === false; const hasIndexDisabled = mapping.index === false; @@ -38,7 +33,6 @@ export function getFieldsFromProperties(properties, dataTypes, path) { export function getTypeFromMappings(mappings, dataTypes, path = '') { if (shouldSkip(mappings)) return dataTypes; - // if there are properties then type is inherently an object if (mappings.properties) { getFieldsFromProperties(mappings.properties, dataTypes, path); @@ -55,7 +49,6 @@ export function getTypeFromMappings(mappings, dataTypes, path = '') { export function getPathsPerDataType(mappings) { const dataTypes = {}; Object.entries(mappings) - .map(getDocMappings) - .forEach(docMappings => getTypeFromMappings(docMappings, dataTypes)); + .forEach(([index, { mappings: docMappings }]) => getTypeFromMappings(docMappings, dataTypes)); return dataTypes; } diff --git a/public/pages/CreateMonitor/containers/DefineMonitor/utils/mappings.test.js b/public/pages/CreateMonitor/containers/DefineMonitor/utils/mappings.test.js index 1d19bd74..5e544d58 100644 --- a/public/pages/CreateMonitor/containers/DefineMonitor/utils/mappings.test.js +++ b/public/pages/CreateMonitor/containers/DefineMonitor/utils/mappings.test.js @@ -20,18 +20,16 @@ describe('getPathsPerDataType', () => { const mappings = { random_index: { mappings: { - _doc: { - properties: { - '@message': { type: 'text' }, - '@timestamp': { type: 'date' }, - username: { type: 'keyword' }, - memory: { type: 'double' }, - phpmemory: { type: 'long' }, - bytes: { type: 'long' }, - clientip: { type: 'ip' }, - id: { type: 'integer' }, - ip: { type: 'ip' }, - }, + properties: { + '@message': { type: 'text' }, + '@timestamp': { type: 'date' }, + username: { type: 'keyword' }, + memory: { type: 'double' }, + phpmemory: { type: 'long' }, + bytes: { type: 'long' }, + clientip: { type: 'ip' }, + id: { type: 'integer' }, + ip: { type: 'ip' }, }, }, }, diff --git a/public/pages/CreateTrigger/containers/CreateTrigger/utils/constants.js b/public/pages/CreateTrigger/containers/CreateTrigger/utils/constants.js index 5edc2ef5..a7402692 100644 --- a/public/pages/CreateTrigger/containers/CreateTrigger/utils/constants.js +++ b/public/pages/CreateTrigger/containers/CreateTrigger/utils/constants.js @@ -20,7 +20,7 @@ export const FORMIK_INITIAL_VALUES = { rollingWindowSize: null, script: { lang: 'painless', - source: `ctx.results[0].hits.total > 0`, + source: `ctx.results[0].hits.total.value > 0`, }, thresholdValue: 10000, thresholdEnum: 'ABOVE', diff --git a/public/pages/CreateTrigger/containers/CreateTrigger/utils/formikToTrigger.test.js b/public/pages/CreateTrigger/containers/CreateTrigger/utils/formikToTrigger.test.js index 428ded63..80f6e648 100644 --- a/public/pages/CreateTrigger/containers/CreateTrigger/utils/formikToTrigger.test.js +++ b/public/pages/CreateTrigger/containers/CreateTrigger/utils/formikToTrigger.test.js @@ -58,7 +58,7 @@ describe('formikToCondition', () => { const formikValues = _.cloneDeep(FORMIK_INITIAL_VALUES); expect( formikToCondition(formikValues, { search: { searchType: 'graph', aggregationType: 'count' } }) - ).toEqual({ script: { lang: 'painless', source: `ctx.results[0].hits.total > 10000` } }); + ).toEqual({ script: { lang: 'painless', source: `ctx.results[0].hits.total.value > 10000` } }); }); test('can return condition for other aggregations', () => { diff --git a/public/pages/Destinations/containers/CreateDestination/utils/validations.js b/public/pages/Destinations/containers/CreateDestination/utils/validations.js index a6f48b2d..cbb3b98d 100644 --- a/public/pages/Destinations/containers/CreateDestination/utils/validations.js +++ b/public/pages/Destinations/containers/CreateDestination/utils/validations.js @@ -24,7 +24,7 @@ export const validateDestinationName = (httpClient, destinationToEdit) => async query: { query: { term: { 'destination.name.keyword': value } } }, }; const response = await httpClient.post('../api/alerting/_search', options); - if (_.get(response, 'data.resp.hits.total', 0)) { + if (_.get(response, 'data.resp.hits.total.value', 0)) { if (!destinationToEdit) throw 'Destination name is already used'; if (destinationToEdit && destinationToEdit.name !== value) { throw 'Destination name is already used'; diff --git a/public/pages/Destinations/containers/DestinationsList/DestinationsList.js b/public/pages/Destinations/containers/DestinationsList/DestinationsList.js index 97c9e484..b850eab9 100644 --- a/public/pages/Destinations/containers/DestinationsList/DestinationsList.js +++ b/public/pages/Destinations/containers/DestinationsList/DestinationsList.js @@ -95,7 +95,7 @@ class DestinationsList extends React.Component { query: isDeleteAllowedQuery(type, id), index: INDEX.SCHEDULED_JOBS, }); - const total = _.get(resp, 'data.resp.hits.total'); + const total = _.get(resp, 'data.resp.hits.total.value'); return total === 0; }; diff --git a/public/utils/validate.js b/public/utils/validate.js index ec096f8c..44d994fb 100644 --- a/public/utils/validate.js +++ b/public/utils/validate.js @@ -42,7 +42,7 @@ export const validateMonitorName = (httpClient, monitorToEdit) => async value => query: { query: { term: { 'monitor.name.keyword': value } } }, }; const response = await httpClient.post('../api/alerting/_search', options); - if (_.get(response, 'data.resp.hits.total', 0)) { + if (_.get(response, 'data.resp.hits.total.value', 0)) { if (!monitorToEdit) throw 'Monitor name is already used'; if (monitorToEdit && monitorToEdit.name !== value) { throw 'Monitor name is already used'; diff --git a/server/clusters/alerting/alertingPlugin.js b/server/clusters/alerting/alertingPlugin.js index c523c2a9..968bf579 100644 --- a/server/clusters/alerting/alertingPlugin.js +++ b/server/clusters/alerting/alertingPlugin.js @@ -57,7 +57,7 @@ export default function alertingPlugin(Client, config, components) { alerting.updateMonitor = ca({ url: { - fmt: `${MONITOR_BASE_API}/<%=monitorId%>?version=<%=version%>&refresh=wait_for`, + fmt: `${MONITOR_BASE_API}/<%=monitorId%>?if_seq_no=<%=if_seq_no%>&if_primary_term=<%=if_primary_term%>&refresh=wait_for`, req: { monitorId: { type: 'string', diff --git a/server/services/AlertService.js b/server/services/AlertService.js index e293dfb7..24703b57 100644 --- a/server/services/AlertService.js +++ b/server/services/AlertService.js @@ -114,7 +114,7 @@ export default class AlertService { const { callWithRequest } = this.esDriver.getCluster(CLUSTER.DATA); try { const resp = await callWithRequest(req, 'search', params); - const totalAlerts = resp.hits.total; + const totalAlerts = resp.hits.total.value; const alerts = resp.hits.hits.map(hit => { const { _source: alert, _id: id, _version: version } = hit; return { id, ...alert, version }; diff --git a/server/services/DestinationsService.js b/server/services/DestinationsService.js index 07396994..ecc6eefd 100644 --- a/server/services/DestinationsService.js +++ b/server/services/DestinationsService.js @@ -75,7 +75,6 @@ export default class DestinationsService { try { const resp = await callWithRequest(req, 'get', { index: INDEX.SCHEDULED_JOBS, - type: '_doc', id: destinationId, }); return { ok: true, destination: resp._source.destination, version: resp._version }; @@ -150,7 +149,7 @@ export default class DestinationsService { const { callWithRequest } = this.esDriver.getCluster(CLUSTER.DATA); try { const resp = await callWithRequest(req, 'search', params); - const totalDestinations = resp.hits.total; + const totalDestinations = resp.hits.total.value; const destinations = resp.hits.hits.map(hit => { const { _source: destination, _id: id, _version: version } = hit; return { id, ...destination.destination, version }; diff --git a/server/services/MonitorService.js b/server/services/MonitorService.js index 24835573..13619b9c 100644 --- a/server/services/MonitorService.js +++ b/server/services/MonitorService.js @@ -172,7 +172,7 @@ export default class MonitorService { const { callWithRequest: alertingCallWithRequest } = await this.esDriver.getCluster(CLUSTER.ALERTING); const getResponse = await alertingCallWithRequest(req, 'alerting.getMonitors', params); - const totalMonitors = _.get(getResponse, 'hits.total', 0); + const totalMonitors = _.get(getResponse, 'hits.total.value', 0); const monitorKeyValueTuples = _.get(getResponse, 'hits.hits', []).map(result => { const { _id: id, _version: version, _source: monitor } = result; const { name, enabled } = monitor; From ce7a18cc0792298d78f5c77b47d7c9933d0c8286 Mon Sep 17 00:00:00 2001 From: Mihir Soni Date: Tue, 7 May 2019 15:25:28 -0700 Subject: [PATCH 2/6] Fixes babel setup, broken setup, prettier fixes --- .babelrc | 4 -- babel.config.js | 12 ++++ package.json | 2 +- public/components/Breadcrumbs/Breadcrumbs.js | 16 +++-- .../Breadcrumbs/Breadcrumbs.test.js | 53 ++++++++++----- public/components/Flyout/Flyout.test.js | 14 ++-- .../components/Flyout/flyouts/flyouts.test.js | 2 +- public/components/Flyout/flyouts/message.js | 5 +- .../expressions/ForExpression.js | 7 +- .../expressions/OverExpression.js | 13 +--- .../QueryPerformance/QueryPerformance.test.js | 4 +- .../Schedule/Frequencies/CustomCron.js | 5 +- .../VisualGraph/utils/helpers.test.js | 5 +- .../containers/CreateMonitor/CreateMonitor.js | 4 +- .../CreateMonitor/CreateMonitor.test.js | 2 +- .../CreateMonitor/utils/formikToMonitor.js | 8 +-- .../utils/formikToMonitor.test.js | 8 ++- .../DefineMonitor/DefineMonitor.test.js | 58 +++++++++++++---- .../DefineMonitor/utils/mappings.js | 5 +- .../DefineMonitor/utils/searchRequests.js | 6 +- .../containers/MonitorIndex/MonitorIndex.js | 4 +- .../MonitorIndex/MonitorIndex.test.js | 64 +++++++++++++++---- .../CreateTrigger/components/Action/Action.js | 4 +- .../TriggerExpressions.test.js | 25 ++++++-- .../components/TriggerExpressions/index.js | 2 +- .../TriggerQuery/TriggerQuery.test.js | 22 +++++-- .../components/TriggerQuery/index.js | 2 +- .../ConfigureActions/ConfigureActions.js | 12 ++-- .../CreateTrigger/utils/constants.js | 2 +- .../EmptyDestinations/EmptyDestinations.js | 1 - .../EmptyDestinations.test.js | 4 +- .../utils/__tests__/validation.test.js | 12 +++- .../DestinationsList/DestinationsList.js | 6 +- .../containers/MonitorDetails.js | 10 ++- .../containers/Triggers/Triggers.test.js | 20 +++--- .../containers/Triggers/index.js | 2 +- .../containers/Monitors/Monitors.test.js | 38 ++++++++--- 37 files changed, 314 insertions(+), 149 deletions(-) delete mode 100644 .babelrc create mode 100644 babel.config.js diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 0832dac6..00000000 --- a/.babelrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "presets": ["env", "react"], - "plugins": ["transform-class-properties", "transform-define", "transform-object-rest-spread"] -} diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 00000000..41350cfa --- /dev/null +++ b/babel.config.js @@ -0,0 +1,12 @@ +// babelrc doesn't respect NODE_PATH anymore but using require does. +// Alternative to install them locally in node_modules +module.exports = { + presets: [ + require('@babel/preset-env'), + require('@babel/preset-react'), + ], + plugins: [ + require('@babel/plugin-proposal-class-properties'), + require('@babel/plugin-proposal-object-rest-spread'), + ] +} \ No newline at end of file diff --git a/package.json b/package.json index 8a7f3353..3ed7a5fd 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "license": "Apache-2.0", "homepage": "https://github.com/opendistro-for-elasticsearch/alerting-kibana-plugin", "kibana": { - "version": "7.0.0", + "version": "7.0.1", "templateVersion": "6.3.3" }, "repository": { diff --git a/public/components/Breadcrumbs/Breadcrumbs.js b/public/components/Breadcrumbs/Breadcrumbs.js index 5a90cff1..86dbc43f 100644 --- a/public/components/Breadcrumbs/Breadcrumbs.js +++ b/public/components/Breadcrumbs/Breadcrumbs.js @@ -18,7 +18,12 @@ import PropTypes from 'prop-types'; import _ from 'lodash'; import queryString from 'query-string'; import { EuiBreadcrumbs } from '@elastic/eui'; -import { APP_PATH, DESTINATION_ACTIONS, MONITOR_ACTIONS, TRIGGER_ACTIONS } from '../../utils/constants'; +import { + APP_PATH, + DESTINATION_ACTIONS, + MONITOR_ACTIONS, + TRIGGER_ACTIONS, +} from '../../utils/constants'; const propTypes = { history: PropTypes.object.isRequired, @@ -130,9 +135,12 @@ export async function getBreadcrumb(route, routeState, httpClient) { console.error(err); } const breadcrumbs = [{ text: monitorName, href: `/monitors/${base}` }]; - if (action === MONITOR_ACTIONS.UPDATE_MONITOR) breadcrumbs.push({ text: 'Update monitor', href: '/' }); - if (action === TRIGGER_ACTIONS.CREATE_TRIGGER) breadcrumbs.push({ text: 'Create trigger', href: '/' }); - if (action === TRIGGER_ACTIONS.UPDATE_TRIGGER) breadcrumbs.push({ text: 'Update trigger', href: '/' }); + if (action === MONITOR_ACTIONS.UPDATE_MONITOR) + breadcrumbs.push({ text: 'Update monitor', href: '/' }); + if (action === TRIGGER_ACTIONS.CREATE_TRIGGER) + breadcrumbs.push({ text: 'Create trigger', href: '/' }); + if (action === TRIGGER_ACTIONS.UPDATE_TRIGGER) + breadcrumbs.push({ text: 'Update trigger', href: '/' }); return breadcrumbs; } } diff --git a/public/components/Breadcrumbs/Breadcrumbs.test.js b/public/components/Breadcrumbs/Breadcrumbs.test.js index b983b040..1670a40b 100644 --- a/public/components/Breadcrumbs/Breadcrumbs.test.js +++ b/public/components/Breadcrumbs/Breadcrumbs.test.js @@ -17,7 +17,12 @@ import React from 'react'; import { mount, shallow } from 'enzyme'; import { EuiBreadcrumbs } from '@elastic/eui'; -import Breadcrumbs, { createEuiBreadcrumb, getBreadcrumbs, parseLocationHash, getBreadcrumb } from './Breadcrumbs'; +import Breadcrumbs, { + createEuiBreadcrumb, + getBreadcrumbs, + parseLocationHash, + getBreadcrumb, +} from './Breadcrumbs'; import { historyMock, httpClientMock } from '../../../test/mocks'; import { MONITOR_ACTIONS, TRIGGER_ACTIONS } from '../../utils/constants'; @@ -26,7 +31,7 @@ const location = { hash: '', pathname: '/monitors/random_id_20_chars__', search: '', - state: undefined + state: undefined, }; beforeEach(() => { @@ -35,7 +40,9 @@ beforeEach(() => { describe('Breadcrumbs', () => { const title = 'Alerting'; - httpClientMock.get = jest.fn().mockResolvedValue({ data: { ok: true, resp: { name: 'random monitor' } } }); + httpClientMock.get = jest + .fn() + .mockResolvedValue({ data: { ok: true, resp: { name: 'random monitor' } } }); delete global.window.location; global.window.location = { hash: '' }; @@ -92,7 +99,9 @@ describe('getBreadcrumb', () => { const routeState = { destinationToEdit: { name: 'unique_name' } }; test('returns null if falsy base value', async () => { expect(await getBreadcrumb('', {}, httpClientMock)).toBe(null); - expect(await getBreadcrumb(`?action=${TRIGGER_ACTIONS.CREATE_TRIGGER}`, {}, httpClientMock)).toBe(null); + expect( + await getBreadcrumb(`?action=${TRIGGER_ACTIONS.CREATE_TRIGGER}`, {}, httpClientMock) + ).toBe(null); }); test('returns correct constant breadcrumbs', async () => { @@ -114,30 +123,42 @@ describe('getBreadcrumb', () => { test('returns monitor name', async () => { httpClientMock.get.mockResolvedValue({ data: { ok: true, resp: { name: 'random_name' } } }); - expect(await getBreadcrumb(monitorId, {}, httpClientMock)) - .toMatchSnapshot(); + expect(await getBreadcrumb(monitorId, {}, httpClientMock)).toMatchSnapshot(); }); test('uses monitor id as name if request fails', async () => { httpClientMock.get.mockRejectedValue({ data: { ok: true, resp: { name: 'random_name' } } }); - expect(await getBreadcrumb(monitorId, {}, httpClientMock)) - .toMatchSnapshot(); + expect(await getBreadcrumb(monitorId, {}, httpClientMock)).toMatchSnapshot(); }); test('uses monitor id as name if ok=false', async () => { httpClientMock.get.mockResolvedValue({ data: { ok: false, resp: { name: 'random_name' } } }); - expect(await getBreadcrumb(monitorId, {}, httpClientMock)) - .toMatchSnapshot(); + expect(await getBreadcrumb(monitorId, {}, httpClientMock)).toMatchSnapshot(); }); test('adds appropriate action breadcrumb', async () => { httpClientMock.get.mockResolvedValue({ data: { ok: true, resp: { name: 'random_name' } } }); - expect(await getBreadcrumb(`${monitorId}?action=${MONITOR_ACTIONS.UPDATE_MONITOR}`, {}, httpClientMock)) - .toMatchSnapshot(); - expect(await getBreadcrumb(`${monitorId}?action=${TRIGGER_ACTIONS.CREATE_TRIGGER}`, {}, httpClientMock)) - .toMatchSnapshot(); - expect(await getBreadcrumb(`${monitorId}?action=${TRIGGER_ACTIONS.UPDATE_TRIGGER}`, {}, httpClientMock)) - .toMatchSnapshot(); + expect( + await getBreadcrumb( + `${monitorId}?action=${MONITOR_ACTIONS.UPDATE_MONITOR}`, + {}, + httpClientMock + ) + ).toMatchSnapshot(); + expect( + await getBreadcrumb( + `${monitorId}?action=${TRIGGER_ACTIONS.CREATE_TRIGGER}`, + {}, + httpClientMock + ) + ).toMatchSnapshot(); + expect( + await getBreadcrumb( + `${monitorId}?action=${TRIGGER_ACTIONS.UPDATE_TRIGGER}`, + {}, + httpClientMock + ) + ).toMatchSnapshot(); }); }); }); diff --git a/public/components/Flyout/Flyout.test.js b/public/components/Flyout/Flyout.test.js index 7efbf416..e9e32104 100644 --- a/public/components/Flyout/Flyout.test.js +++ b/public/components/Flyout/Flyout.test.js @@ -22,18 +22,24 @@ jest.unmock('./flyouts'); describe('Flyout', () => { test('renders', () => { - const wrapper = shallow(); + const wrapper = shallow( + + ); expect(wrapper).toMatchSnapshot(); }); test('renders null if no flyout', () => { - const wrapper = shallow(); + const wrapper = shallow( + + ); expect(wrapper).toMatchSnapshot(); }); test('defaults if bad flyout data', () => { Flyouts.message = jest.fn(() => ({})); - const wrapper = shallow(); + const wrapper = shallow( + + ); expect(wrapper).toMatchSnapshot(); }); -}); \ No newline at end of file +}); diff --git a/public/components/Flyout/flyouts/flyouts.test.js b/public/components/Flyout/flyouts/flyouts.test.js index 9a2b47d7..9f54a553 100644 --- a/public/components/Flyout/flyouts/flyouts.test.js +++ b/public/components/Flyout/flyouts/flyouts.test.js @@ -35,4 +35,4 @@ describe('Flyouts.triggerCondition', () => { const json = Flyouts.triggerCondition({}); expect(json).toMatchSnapshot(); }); -}); \ No newline at end of file +}); diff --git a/public/components/Flyout/flyouts/message.js b/public/components/Flyout/flyouts/message.js index 88d14dce..d9804176 100644 --- a/public/components/Flyout/flyouts/message.js +++ b/public/components/Flyout/flyouts/message.js @@ -39,10 +39,7 @@ const message = () => ({

Learn More

  • - + HTML Templates with Mustache.js
  • diff --git a/public/pages/CreateMonitor/components/MonitorExpressions/expressions/ForExpression.js b/public/pages/CreateMonitor/components/MonitorExpressions/expressions/ForExpression.js index 646a2035..e614efb9 100644 --- a/public/pages/CreateMonitor/components/MonitorExpressions/expressions/ForExpression.js +++ b/public/pages/CreateMonitor/components/MonitorExpressions/expressions/ForExpression.js @@ -16,12 +16,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'formik'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiPopover, - EuiExpression, -} from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiPopover, EuiExpression } from '@elastic/eui'; import { Expressions, POPOVER_STYLE, UNITS_OF_TIME, EXPRESSION_STYLE } from './utils/constants'; import { selectOptionValueToText } from './utils/helpers'; import { FormikFieldNumber, FormikSelect } from '../../../../../components/FormControls'; diff --git a/public/pages/CreateMonitor/components/MonitorExpressions/expressions/OverExpression.js b/public/pages/CreateMonitor/components/MonitorExpressions/expressions/OverExpression.js index e7f68f8d..3f080408 100644 --- a/public/pages/CreateMonitor/components/MonitorExpressions/expressions/OverExpression.js +++ b/public/pages/CreateMonitor/components/MonitorExpressions/expressions/OverExpression.js @@ -15,12 +15,7 @@ import React, { Component } from 'react'; import { connect } from 'formik'; -import { - EuiPopover, - EuiExpression, - EuiFlexGroup, - EuiFlexItem, -} from '@elastic/eui'; +import { EuiPopover, EuiExpression, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { POPOVER_STYLE, Expressions, OVER_TYPES, EXPRESSION_STYLE } from './utils/constants'; import { FormikSelect, FormikFieldNumber } from '../../../../../components/FormControls'; @@ -50,9 +45,7 @@ class OverExpression extends Component { ); renderOverPopover = () => ( -
    - {this.renderTypeSelect()} -
    +
    {this.renderTypeSelect()}
    ); renderGroupedPopover = () => ( @@ -61,7 +54,7 @@ class OverExpression extends Component { style={{ maxWidth: 600, width: Math.max(expressionWidth, 180), - ...EXPRESSION_STYLE + ...EXPRESSION_STYLE, }} > diff --git a/public/pages/CreateMonitor/components/QueryPerformance/QueryPerformance.test.js b/public/pages/CreateMonitor/components/QueryPerformance/QueryPerformance.test.js index 6b1d04b9..39bd2856 100644 --- a/public/pages/CreateMonitor/components/QueryPerformance/QueryPerformance.test.js +++ b/public/pages/CreateMonitor/components/QueryPerformance/QueryPerformance.test.js @@ -20,7 +20,9 @@ import QueryPerformance from './QueryPerformance'; describe('QueryPerformance', () => { test('renders', () => { - const component = ; + const component = ( + + ); expect(render(component)).toMatchSnapshot(); }); diff --git a/public/pages/CreateMonitor/components/Schedule/Frequencies/CustomCron.js b/public/pages/CreateMonitor/components/Schedule/Frequencies/CustomCron.js index 3688d697..a68e743a 100644 --- a/public/pages/CreateMonitor/components/Schedule/Frequencies/CustomCron.js +++ b/public/pages/CreateMonitor/components/Schedule/Frequencies/CustomCron.js @@ -22,10 +22,7 @@ import { isInvalid, hasError } from '../../../../../utils/validate'; import { URL } from '../../../../../../utils/constants'; const cronHelpLink = ( - + cron expressions ); diff --git a/public/pages/CreateMonitor/components/VisualGraph/utils/helpers.test.js b/public/pages/CreateMonitor/components/VisualGraph/utils/helpers.test.js index c63d7377..3c748045 100644 --- a/public/pages/CreateMonitor/components/VisualGraph/utils/helpers.test.js +++ b/public/pages/CreateMonitor/components/VisualGraph/utils/helpers.test.js @@ -58,7 +58,10 @@ describe('getLeftPadding', () => { describe('getXDomain', () => { test('gets x domains', () => { - const data = [{ y: 440, x: '2019-01-30T07:00:00.000-08:00' }, { y: 440, x: '2019-01-30T08:00:00.000-08:00' }]; + const data = [ + { y: 440, x: '2019-01-30T07:00:00.000-08:00' }, + { y: 440, x: '2019-01-30T08:00:00.000-08:00' }, + ]; const xDomain = getXDomain(data); const expectedXDomain = [data[0].x, data[data.length - 1].x]; expect(xDomain).toEqual(expectedXDomain); diff --git a/public/pages/CreateMonitor/containers/CreateMonitor/CreateMonitor.js b/public/pages/CreateMonitor/containers/CreateMonitor/CreateMonitor.js index 15eff14d..44a0c684 100644 --- a/public/pages/CreateMonitor/containers/CreateMonitor/CreateMonitor.js +++ b/public/pages/CreateMonitor/containers/CreateMonitor/CreateMonitor.js @@ -73,7 +73,9 @@ export default class CreateMonitor extends Component { }, } = resp; if (ok) { - this.props.history.push(`/monitors/${_id}?action=${TRIGGER_ACTIONS.CREATE_TRIGGER}&success=true`); + this.props.history.push( + `/monitors/${_id}?action=${TRIGGER_ACTIONS.CREATE_TRIGGER}&success=true` + ); } else { console.log('Failed to create:', resp.data); } diff --git a/public/pages/CreateMonitor/containers/CreateMonitor/CreateMonitor.test.js b/public/pages/CreateMonitor/containers/CreateMonitor/CreateMonitor.test.js index af912129..be65794a 100644 --- a/public/pages/CreateMonitor/containers/CreateMonitor/CreateMonitor.test.js +++ b/public/pages/CreateMonitor/containers/CreateMonitor/CreateMonitor.test.js @@ -33,7 +33,7 @@ const match = { isExact: true, params: {}, path: '/create-monitor', - url: '/create-monitor' + url: '/create-monitor', }; const location = { hash: '', diff --git a/public/pages/CreateMonitor/containers/CreateMonitor/utils/formikToMonitor.js b/public/pages/CreateMonitor/containers/CreateMonitor/utils/formikToMonitor.js index 5e574d94..a09b640e 100644 --- a/public/pages/CreateMonitor/containers/CreateMonitor/utils/formikToMonitor.js +++ b/public/pages/CreateMonitor/containers/CreateMonitor/utils/formikToMonitor.js @@ -143,11 +143,11 @@ export function formikToUiOverAggregation(values) { min_doc_count: 0, extended_bounds: { min: `now-${bucketValue * BUCKET_COUNT}${bucketUnitOfTime}`, - max: 'now' - } + max: 'now', + }, }, - aggregations: whenAggregation - } + aggregations: whenAggregation, + }, }; } diff --git a/public/pages/CreateMonitor/containers/CreateMonitor/utils/formikToMonitor.test.js b/public/pages/CreateMonitor/containers/CreateMonitor/utils/formikToMonitor.test.js index efaecd20..b5a8b4e0 100644 --- a/public/pages/CreateMonitor/containers/CreateMonitor/utils/formikToMonitor.test.js +++ b/public/pages/CreateMonitor/containers/CreateMonitor/utils/formikToMonitor.test.js @@ -86,13 +86,17 @@ describe('formikToExtractionQuery', () => { describe('formikToGraphQuery', () => { test('can build graph query', () => { - expect(formikToGraphQuery({ ...FORMIK_INITIAL_VALUES, timeField: '@timestamp' })).toMatchSnapshot(); + expect( + formikToGraphQuery({ ...FORMIK_INITIAL_VALUES, timeField: '@timestamp' }) + ).toMatchSnapshot(); }); }); describe('formikToUiGraphQuery', () => { test('can build ui graph query', () => { - expect(formikToUiGraphQuery({ ...FORMIK_INITIAL_VALUES, timeField: '@timestamp' })).toMatchSnapshot(); + expect( + formikToUiGraphQuery({ ...FORMIK_INITIAL_VALUES, timeField: '@timestamp' }) + ).toMatchSnapshot(); }); }); diff --git a/public/pages/CreateMonitor/containers/DefineMonitor/DefineMonitor.test.js b/public/pages/CreateMonitor/containers/DefineMonitor/DefineMonitor.test.js index 6c66036d..839d09f2 100644 --- a/public/pages/CreateMonitor/containers/DefineMonitor/DefineMonitor.test.js +++ b/public/pages/CreateMonitor/containers/DefineMonitor/DefineMonitor.test.js @@ -22,11 +22,7 @@ import { httpClientMock } from '../../../../../test/mocks'; function getShallowWrapper(customProps = {}) { return shallow( - + ); } @@ -53,7 +49,12 @@ describe('DefineMonitor', () => { test('mounting should not call onQueryMappings or onRunQuery if no indices selected', () => { const onQueryMappings = jest.spyOn(DefineMonitor.prototype, 'onQueryMappings'); const onRunQuery = jest.spyOn(DefineMonitor.prototype, 'onRunQuery'); - const values = { ...FORMIK_INITIAL_VALUES, searchType: 'graph', timeField: '@timestamp', index: [] }; + const values = { + ...FORMIK_INITIAL_VALUES, + searchType: 'graph', + timeField: '@timestamp', + index: [], + }; const wrapper = getShallowWrapper({ values }); expect(onQueryMappings).not.toHaveBeenCalled(); expect(onRunQuery).not.toHaveBeenCalled(); @@ -62,7 +63,12 @@ describe('DefineMonitor', () => { test('mounting should only call onQueryMappings if graph type and indices are selected, but no timefield', () => { const onQueryMappings = jest.spyOn(DefineMonitor.prototype, 'onQueryMappings'); const onRunQuery = jest.spyOn(DefineMonitor.prototype, 'onRunQuery'); - const values = { ...FORMIK_INITIAL_VALUES, searchType: 'graph', timeField: '', index: [{ label: 'some_index' }] }; + const values = { + ...FORMIK_INITIAL_VALUES, + searchType: 'graph', + timeField: '', + index: [{ label: 'some_index' }], + }; const wrapper = getShallowWrapper({ values }); expect(onQueryMappings).toHaveBeenCalled(); expect(onRunQuery).not.toHaveBeenCalled(); @@ -71,7 +77,12 @@ describe('DefineMonitor', () => { test('mounting should call onQueryMappings and onRunQuery if graph type, indices are selected, and timefield exists', () => { const onQueryMappings = jest.spyOn(DefineMonitor.prototype, 'onQueryMappings'); const onRunQuery = jest.spyOn(DefineMonitor.prototype, 'onRunQuery'); - const values = { ...FORMIK_INITIAL_VALUES, searchType: 'graph', timeField: '@timestamp', index: [{ label: 'some_index' }] }; + const values = { + ...FORMIK_INITIAL_VALUES, + searchType: 'graph', + timeField: '@timestamp', + index: [{ label: 'some_index' }], + }; const wrapper = getShallowWrapper({ values }); expect(onQueryMappings).toHaveBeenCalled(); expect(onRunQuery).toHaveBeenCalled(); @@ -80,7 +91,12 @@ describe('DefineMonitor', () => { test('should call onQueryMappings and onRunQuery when switching from query type to graph type', () => { const onQueryMappings = jest.spyOn(DefineMonitor.prototype, 'onQueryMappings'); const onRunQuery = jest.spyOn(DefineMonitor.prototype, 'onRunQuery'); - const values = { ...FORMIK_INITIAL_VALUES, searchType: 'query', timeField: '@timestamp', index: [{ label: 'some_index' }] }; + const values = { + ...FORMIK_INITIAL_VALUES, + searchType: 'query', + timeField: '@timestamp', + index: [{ label: 'some_index' }], + }; const wrapper = getShallowWrapper({ values }); expect(onQueryMappings).not.toHaveBeenCalled(); expect(onRunQuery).not.toHaveBeenCalled(); @@ -93,11 +109,19 @@ describe('DefineMonitor', () => { test('should call onQueryMappings and onRunQuery when changing indices', () => { const onQueryMappings = jest.spyOn(DefineMonitor.prototype, 'onQueryMappings'); const onRunQuery = jest.spyOn(DefineMonitor.prototype, 'onRunQuery'); - const values = { ...FORMIK_INITIAL_VALUES, searchType: 'graph', timeField: '@timestamp', index: [] }; + const values = { + ...FORMIK_INITIAL_VALUES, + searchType: 'graph', + timeField: '@timestamp', + index: [], + }; const wrapper = getShallowWrapper({ values }); expect(onQueryMappings).not.toHaveBeenCalled(); expect(onRunQuery).not.toHaveBeenCalled(); - wrapper.setProps({ httpClient: httpClientMock, values: { ...values, index: [{ label: 'some_index' }] } }); + wrapper.setProps({ + httpClient: httpClientMock, + values: { ...values, index: [{ label: 'some_index' }] }, + }); wrapper.update(); expect(onQueryMappings).toHaveBeenCalled(); expect(onRunQuery).toHaveBeenCalled(); @@ -105,10 +129,18 @@ describe('DefineMonitor', () => { test('should call onRunQuery when changing timefield', () => { const onRunQuery = jest.spyOn(DefineMonitor.prototype, 'onRunQuery'); - const values = { ...FORMIK_INITIAL_VALUES, searchType: 'graph', timeField: '@timestamp', index: [{ label: 'some_index' }] }; + const values = { + ...FORMIK_INITIAL_VALUES, + searchType: 'graph', + timeField: '@timestamp', + index: [{ label: 'some_index' }], + }; const wrapper = getShallowWrapper({ values }); expect(onRunQuery).toHaveBeenCalledTimes(1); // on mount - wrapper.setProps({ httpClient: httpClientMock, values: { ...values, timeField: 'different_time_field' } }); + wrapper.setProps({ + httpClient: httpClientMock, + values: { ...values, timeField: 'different_time_field' }, + }); wrapper.update(); expect(onRunQuery).toHaveBeenCalledTimes(2); // on update }); diff --git a/public/pages/CreateMonitor/containers/DefineMonitor/utils/mappings.js b/public/pages/CreateMonitor/containers/DefineMonitor/utils/mappings.js index aa9d80fc..d55fc21b 100644 --- a/public/pages/CreateMonitor/containers/DefineMonitor/utils/mappings.js +++ b/public/pages/CreateMonitor/containers/DefineMonitor/utils/mappings.js @@ -48,7 +48,8 @@ export function getTypeFromMappings(mappings, dataTypes, path = '') { export function getPathsPerDataType(mappings) { const dataTypes = {}; - Object.entries(mappings) - .forEach(([index, { mappings: docMappings }]) => getTypeFromMappings(docMappings, dataTypes)); + Object.entries(mappings).forEach(([index, { mappings: docMappings }]) => + getTypeFromMappings(docMappings, dataTypes) + ); return dataTypes; } diff --git a/public/pages/CreateMonitor/containers/DefineMonitor/utils/searchRequests.js b/public/pages/CreateMonitor/containers/DefineMonitor/utils/searchRequests.js index a4e46c25..e8bf692a 100644 --- a/public/pages/CreateMonitor/containers/DefineMonitor/utils/searchRequests.js +++ b/public/pages/CreateMonitor/containers/DefineMonitor/utils/searchRequests.js @@ -13,7 +13,11 @@ * permissions and limitations under the License. */ -import { formikToGraphQuery, formikToUiGraphQuery, formikToIndices } from '../../CreateMonitor/utils/formikToMonitor'; +import { + formikToGraphQuery, + formikToUiGraphQuery, + formikToIndices, +} from '../../CreateMonitor/utils/formikToMonitor'; import { SEARCH_TYPE } from '../../../../../utils/constants'; export const buildSearchRequest = (values, uiGraphQuery = true) => diff --git a/public/pages/CreateMonitor/containers/MonitorIndex/MonitorIndex.js b/public/pages/CreateMonitor/containers/MonitorIndex/MonitorIndex.js index ac415e5d..dbbafa2d 100644 --- a/public/pages/CreateMonitor/containers/MonitorIndex/MonitorIndex.js +++ b/public/pages/CreateMonitor/containers/MonitorIndex/MonitorIndex.js @@ -195,7 +195,9 @@ class MonitorIndex extends React.Component { } renderOption(option, searchValue, contentClassName) { - return ; + return ( + + ); } render() { diff --git a/public/pages/CreateMonitor/containers/MonitorIndex/MonitorIndex.test.js b/public/pages/CreateMonitor/containers/MonitorIndex/MonitorIndex.test.js index 091bf100..867df217 100644 --- a/public/pages/CreateMonitor/containers/MonitorIndex/MonitorIndex.test.js +++ b/public/pages/CreateMonitor/containers/MonitorIndex/MonitorIndex.test.js @@ -67,7 +67,7 @@ describe('MonitorIndex', () => { .simulate('change', { target: { value: 'r' } }); expect(wrapper.find(MonitorIndex).instance().state.appendedWildcard).toBe(true); - expect(wrapper.find(MonitorIndex).instance().lastQuery = 'r*'); + expect((wrapper.find(MonitorIndex).instance().lastQuery = 'r*')); }); test('searches space normalizes value', () => { @@ -91,7 +91,7 @@ describe('MonitorIndex', () => { .simulate('change', { target: { value: 'r' } }); expect(wrapper.find(MonitorIndex).instance().state.appendedWildcard).toBe(true); - expect(wrapper.find(MonitorIndex).instance().lastQuery = 'r*'); + expect((wrapper.find(MonitorIndex).instance().lastQuery = 'r*')); wrapper .find('[data-test-subj="comboBoxSearchInput"]') @@ -99,38 +99,73 @@ describe('MonitorIndex', () => { .simulate('change', { target: { value: '*' } }); expect(wrapper.find(MonitorIndex).instance().state.appendedWildcard).toBe(false); - expect(wrapper.find(MonitorIndex).instance().lastQuery = ''); + expect((wrapper.find(MonitorIndex).instance().lastQuery = '')); }); test('returns empty alias/index array for *:', async () => { const wrapper = getMountWrapper(); - expect(await wrapper.find(MonitorIndex).instance().handleQueryAliases('*:')).toEqual([]); - expect(await wrapper.find(MonitorIndex).instance().handleQueryIndices('*:')).toEqual([]); + expect( + await wrapper + .find(MonitorIndex) + .instance() + .handleQueryAliases('*:') + ).toEqual([]); + expect( + await wrapper + .find(MonitorIndex) + .instance() + .handleQueryIndices('*:') + ).toEqual([]); }); test('returns empty array for data.ok = false', async () => { httpClientMock.post.mockResolvedValue({ data: { ok: false } }); const wrapper = getMountWrapper(); - expect(await wrapper.find(MonitorIndex).instance().handleQueryAliases('random')).toEqual([]); - expect(await wrapper.find(MonitorIndex).instance().handleQueryIndices('random')).toEqual([]); + expect( + await wrapper + .find(MonitorIndex) + .instance() + .handleQueryAliases('random') + ).toEqual([]); + expect( + await wrapper + .find(MonitorIndex) + .instance() + .handleQueryIndices('random') + ).toEqual([]); }); // test('returns indices/aliases', async () => { - httpClientMock.post.mockResolvedValue({ data: { ok: true, resp: [{ health: 'green', status: 'open', index: 'logstash-0', alias: 'logstash' }] } }); + httpClientMock.post.mockResolvedValue({ + data: { + ok: true, + resp: [{ health: 'green', status: 'open', index: 'logstash-0', alias: 'logstash' }], + }, + }); const wrapper = getMountWrapper(); - expect(await wrapper.find(MonitorIndex).instance().handleQueryAliases('l')).toEqual([{ label: 'logstash', index: 'logstash-0' }]); - expect(await wrapper.find(MonitorIndex).instance().handleQueryIndices('l')).toEqual([{ health: 'green', status: 'open', label: 'logstash-0' }]); + expect( + await wrapper + .find(MonitorIndex) + .instance() + .handleQueryAliases('l') + ).toEqual([{ label: 'logstash', index: 'logstash-0' }]); + expect( + await wrapper + .find(MonitorIndex) + .instance() + .handleQueryIndices('l') + ).toEqual([{ health: 'green', status: 'open', label: 'logstash-0' }]); }); test('onBlur sets index to touched', () => { httpClientMock.post.mockResolvedValue({ data: { ok: true, - resp: [{ health: 'green', status: 'open', index: 'logstash-0', alias: 'logstash' }] - } + resp: [{ health: 'green', status: 'open', index: 'logstash-0', alias: 'logstash' }], + }, }); const wrapper = getMountWrapper(); @@ -146,8 +181,9 @@ describe('MonitorIndex', () => { test('sets option when calling onCreateOption', () => { httpClientMock.post.mockResolvedValue({ data: { - ok: true, resp: [{ health: 'green', status: 'open', index: 'logstash-0', alias: 'logstash' }] - } + ok: true, + resp: [{ health: 'green', status: 'open', index: 'logstash-0', alias: 'logstash' }], + }, }); const wrapper = getMountWrapper(); diff --git a/public/pages/CreateTrigger/components/Action/Action.js b/public/pages/CreateTrigger/components/Action/Action.js index fb5385ae..a3fcb054 100644 --- a/public/pages/CreateTrigger/components/Action/Action.js +++ b/public/pages/CreateTrigger/components/Action/Action.js @@ -44,8 +44,8 @@ const Action = ({ className="accordion-action" buttonContent={ !_.get(selectedDestination, '0.type', undefined) - ? 'Notification' - : `${actionLabel}: ${name}` + ? 'Notification' + : `${actionLabel}: ${name}` } extraAction={
    diff --git a/public/pages/CreateTrigger/components/TriggerExpressions/TriggerExpressions.test.js b/public/pages/CreateTrigger/components/TriggerExpressions/TriggerExpressions.test.js index 93f98db8..3f5c82b8 100644 --- a/public/pages/CreateTrigger/components/TriggerExpressions/TriggerExpressions.test.js +++ b/public/pages/CreateTrigger/components/TriggerExpressions/TriggerExpressions.test.js @@ -33,9 +33,14 @@ describe('TriggerExpressions', () => { test('calls openExpression when clicking expression', () => { const wrapper = mount( } />); - const openExpression = jest.spyOn(wrapper.find(TriggerExpressions).instance(), 'openExpression'); + const openExpression = jest.spyOn( + wrapper.find(TriggerExpressions).instance(), + 'openExpression' + ); const button = wrapper.find(EuiExpression); - expect(wrapper.find(TriggerExpressions).state().openedStates[Expressions.THRESHOLD]).toBe(false); + expect(wrapper.find(TriggerExpressions).state().openedStates[Expressions.THRESHOLD]).toBe( + false + ); button.simulate('click'); wrapper.update(); expect(openExpression).toHaveBeenCalled(); @@ -44,8 +49,14 @@ describe('TriggerExpressions', () => { test('calls closeExpression when closing popover', () => { const wrapper = mount( } />); - const openExpression = jest.spyOn(wrapper.find(TriggerExpressions).instance(), 'openExpression'); - const closeExpression = jest.spyOn(wrapper.find(TriggerExpressions).instance(), 'closeExpression'); + const openExpression = jest.spyOn( + wrapper.find(TriggerExpressions).instance(), + 'openExpression' + ); + const closeExpression = jest.spyOn( + wrapper.find(TriggerExpressions).instance(), + 'closeExpression' + ); const button = wrapper.find(EuiExpression); button.simulate('click'); wrapper.update(); @@ -54,6 +65,8 @@ describe('TriggerExpressions', () => { button.simulate('keyDown', { keyCode: 27 }); wrapper.update(); expect(closeExpression).toHaveBeenCalled(); - expect(wrapper.find(TriggerExpressions).state().openedStates[Expressions.THRESHOLD]).toBe(false); + expect(wrapper.find(TriggerExpressions).state().openedStates[Expressions.THRESHOLD]).toBe( + false + ); }); -}); \ No newline at end of file +}); diff --git a/public/pages/CreateTrigger/components/TriggerExpressions/index.js b/public/pages/CreateTrigger/components/TriggerExpressions/index.js index 6c36a36a..73340457 100644 --- a/public/pages/CreateTrigger/components/TriggerExpressions/index.js +++ b/public/pages/CreateTrigger/components/TriggerExpressions/index.js @@ -15,4 +15,4 @@ import TriggerExpressions from './TriggerExpressions'; -export default TriggerExpressions; \ No newline at end of file +export default TriggerExpressions; diff --git a/public/pages/CreateTrigger/components/TriggerQuery/TriggerQuery.test.js b/public/pages/CreateTrigger/components/TriggerQuery/TriggerQuery.test.js index 4e0e179e..53c8719a 100644 --- a/public/pages/CreateTrigger/components/TriggerQuery/TriggerQuery.test.js +++ b/public/pages/CreateTrigger/components/TriggerQuery/TriggerQuery.test.js @@ -41,7 +41,9 @@ describe('TriggerQuery', () => { const button = wrapper.find(EuiButton); button.simulate('click'); expect(props.onRun).toHaveBeenCalled(); - expect(props.onRun).toHaveBeenCalledWith([{ ...formikToTrigger(props.triggerValues), actions: [] }]); + expect(props.onRun).toHaveBeenCalledWith([ + { ...formikToTrigger(props.triggerValues), actions: [] }, + ]); }); }); @@ -65,15 +67,23 @@ describe('getExecuteMessage', () => { test('returns No execute results for fasly trigger value on trigger_results', () => { const noTriggerResults = 'No execute results'; - expect(getExecuteMessage({ trigger_results: { 'trig_id': null } })).toBe(noTriggerResults); + expect(getExecuteMessage({ trigger_results: { trig_id: null } })).toBe(noTriggerResults); }); test('returns triggered value', () => { - expect(getExecuteMessage({ trigger_results: { 'trig_id': { triggered: true, error: null } } })).toBe('true'); - expect(getExecuteMessage({ trigger_results: { 'trig_id': { triggered: false, error: null } } })).toBe('false'); + expect( + getExecuteMessage({ trigger_results: { trig_id: { triggered: true, error: null } } }) + ).toBe('true'); + expect( + getExecuteMessage({ trigger_results: { trig_id: { triggered: false, error: null } } }) + ).toBe('false'); }); test('returns error message', () => { - expect(getExecuteMessage({ trigger_results: { 'trig_id': { triggered: true, error: 'RANDOM ERROR' } } })).toBe('ERROR: RANDOM ERROR'); + expect( + getExecuteMessage({ + trigger_results: { trig_id: { triggered: true, error: 'RANDOM ERROR' } }, + }) + ).toBe('ERROR: RANDOM ERROR'); }); -}); \ No newline at end of file +}); diff --git a/public/pages/CreateTrigger/components/TriggerQuery/index.js b/public/pages/CreateTrigger/components/TriggerQuery/index.js index bc9d3b3b..7178dcf3 100644 --- a/public/pages/CreateTrigger/components/TriggerQuery/index.js +++ b/public/pages/CreateTrigger/components/TriggerQuery/index.js @@ -15,4 +15,4 @@ import TriggerQuery from './TriggerQuery'; -export default TriggerQuery; \ No newline at end of file +export default TriggerQuery; diff --git a/public/pages/CreateTrigger/containers/ConfigureActions/ConfigureActions.js b/public/pages/CreateTrigger/containers/ConfigureActions/ConfigureActions.js index 41f8dcef..271e0b0a 100644 --- a/public/pages/CreateTrigger/containers/ConfigureActions/ConfigureActions.js +++ b/public/pages/CreateTrigger/containers/ConfigureActions/ConfigureActions.js @@ -56,11 +56,13 @@ class ConfigureActions extends React.Component { const response = await httpClient.get( `../api/alerting/destinations?search${searchText}size=200` ); - const destinations = response.data.destinations.map(destination => ({ - label: `${destination.name} - (${getDestinationLabel(destination)})`, - value: destination.id, - type: destination.type, - })).filter(({ type }) => Object.values(DESTINATION_TYPE).includes(type)); + const destinations = response.data.destinations + .map(destination => ({ + label: `${destination.name} - (${getDestinationLabel(destination)})`, + value: destination.id, + type: destination.type, + })) + .filter(({ type }) => Object.values(DESTINATION_TYPE).includes(type)); this.setState({ destinations, loadingDestinations: false }); // If actions is not defined If user choose to delete actions, it will not override customer's preferences. if (destinations.length > 0 && !values.actions && !actionDeleted) { diff --git a/public/pages/CreateTrigger/containers/CreateTrigger/utils/constants.js b/public/pages/CreateTrigger/containers/CreateTrigger/utils/constants.js index a7402692..68a4c331 100644 --- a/public/pages/CreateTrigger/containers/CreateTrigger/utils/constants.js +++ b/public/pages/CreateTrigger/containers/CreateTrigger/utils/constants.js @@ -27,5 +27,5 @@ export const FORMIK_INITIAL_VALUES = { actions: undefined, }; -export const HITS_TOTAL_RESULTS_PATH = 'ctx.results[0].hits.total'; +export const HITS_TOTAL_RESULTS_PATH = 'ctx.results[0].hits.total.value'; export const AGGREGATION_RESULTS_PATH = 'ctx.results[0].aggregations.when.value'; diff --git a/public/pages/Destinations/components/DestinationsList/EmptyDestinations/EmptyDestinations.js b/public/pages/Destinations/components/DestinationsList/EmptyDestinations/EmptyDestinations.js index 15f95c83..806461cc 100644 --- a/public/pages/Destinations/components/DestinationsList/EmptyDestinations/EmptyDestinations.js +++ b/public/pages/Destinations/components/DestinationsList/EmptyDestinations/EmptyDestinations.js @@ -40,7 +40,6 @@ const propTypes = { onResetFilters: PropTypes.func.isRequired, }; - const EmptyDestinations = ({ isFilterApplied, onResetFilters }) => ( ', () => { test('should render empty destinations message', () => { - const wrapper = render(); + const wrapper = render( + + ); expect(wrapper).toMatchSnapshot(); }); diff --git a/public/pages/Destinations/containers/CreateDestination/utils/__tests__/validation.test.js b/public/pages/Destinations/containers/CreateDestination/utils/__tests__/validation.test.js index c613c648..b70fa5a5 100644 --- a/public/pages/Destinations/containers/CreateDestination/utils/__tests__/validation.test.js +++ b/public/pages/Destinations/containers/CreateDestination/utils/__tests__/validation.test.js @@ -23,7 +23,9 @@ describe('destinations Validations', () => { jest.resetAllMocks(); }); describe('validateDestinationName', () => { - httpClient.post.mockResolvedValue({ data: { resp: { hits: { total: 0 } } } }); + httpClient.post.mockResolvedValue({ + data: { resp: { hits: { total: { value: 0, relation: 'eq' } } } }, + }); test('should be undefined if name is valid', () => { return expect( validateDestinationName(httpClient, null)('Valid Name') @@ -33,13 +35,17 @@ describe('destinations Validations', () => { return expect(validateDestinationName(httpClient, null)('')).rejects.toEqual('Required'); }); test('should reject if name already is being in used', () => { - httpClient.post.mockResolvedValue({ data: { resp: { hits: { total: 1 } } } }); + httpClient.post.mockResolvedValue({ + data: { resp: { hits: { total: { value: 1, relation: 'eq' } } } }, + }); return expect(validateDestinationName(httpClient, null)('destinationName')).rejects.toEqual( 'Destination name is already used' ); }); test('should reject if name already is being in used while editing destination', () => { - httpClient.post.mockResolvedValue({ data: { resp: { hits: { total: 1 } } } }); + httpClient.post.mockResolvedValue({ + data: { resp: { hits: { total: { value: 1, relation: 'eq' } } } }, + }); return expect( validateDestinationName(httpClient, { name: 'destinationName' })('destinationName Existing') ).rejects.toEqual('Destination name is already used'); diff --git a/public/pages/Destinations/containers/DestinationsList/DestinationsList.js b/public/pages/Destinations/containers/DestinationsList/DestinationsList.js index b850eab9..1f969727 100644 --- a/public/pages/Destinations/containers/DestinationsList/DestinationsList.js +++ b/public/pages/Destinations/containers/DestinationsList/DestinationsList.js @@ -178,9 +178,7 @@ class DestinationsList extends React.Component { ...this.props.location, search: queryParms, }); - const resp = await httpClient.get( - `../api/alerting/destinations?${queryParms}` - ); + const resp = await httpClient.get(`../api/alerting/destinations?${queryParms}`); if (resp.data.ok) { this.setState({ isDestinationLoading: false, @@ -189,7 +187,7 @@ class DestinationsList extends React.Component { }); } else { this.setState({ - isDestinationLoading: false + isDestinationLoading: false, }); } }, diff --git a/public/pages/MonitorDetails/containers/MonitorDetails.js b/public/pages/MonitorDetails/containers/MonitorDetails.js index 0bb11206..bd80914f 100644 --- a/public/pages/MonitorDetails/containers/MonitorDetails.js +++ b/public/pages/MonitorDetails/containers/MonitorDetails.js @@ -110,7 +110,10 @@ export default class MonitorDetails extends Component { }; onCreateTrigger = () => { - this.props.history.push({ ...this.props.location, search: `?action=${TRIGGER_ACTIONS.CREATE_TRIGGER}` }); + this.props.history.push({ + ...this.props.location, + search: `?action=${TRIGGER_ACTIONS.CREATE_TRIGGER}`, + }); }; onCloseTrigger = () => { @@ -120,7 +123,10 @@ export default class MonitorDetails extends Component { onEditTrigger = trigger => { this.setState({ triggerToEdit: trigger }); - this.props.history.push({ ...this.props.location, search: `?action=${TRIGGER_ACTIONS.UPDATE_TRIGGER}` }); + this.props.history.push({ + ...this.props.location, + search: `?action=${TRIGGER_ACTIONS.UPDATE_TRIGGER}`, + }); }; renderNoTriggersCallOut = () => { diff --git a/public/pages/MonitorDetails/containers/Triggers/Triggers.test.js b/public/pages/MonitorDetails/containers/Triggers/Triggers.test.js index 2ebd5d96..0c293b90 100644 --- a/public/pages/MonitorDetails/containers/Triggers/Triggers.test.js +++ b/public/pages/MonitorDetails/containers/Triggers/Triggers.test.js @@ -19,21 +19,21 @@ import { shallow } from 'enzyme'; import Triggers from './Triggers'; const props = { - monitor: { triggers: [{ name: 'Random Trigger', severity: 1, actions: [{ name: 'Random Action' }] }] }, + monitor: { + triggers: [{ name: 'Random Trigger', severity: 1, actions: [{ name: 'Random Action' }] }], + }, updateMonitor: jest.fn(), onEditTrigger: jest.fn(), onCreateTrigger: jest.fn(), }; -jest.mock("uuid/v4", () => { let value = 0; return () => value++; }); +jest.mock('uuid/v4', () => { + let value = 0; + return () => value++; +}); function getShallowWrapper(customProps = {}) { - return shallow( - - ); + return shallow(); } describe('Triggers', () => { @@ -70,8 +70,8 @@ describe('Triggers', () => { const monitor = { triggers: [ { name: 'one', severity: 1, actions: [{ name: 'one action' }] }, - { name: 'two', severity: 2, actions: [{ name: 'two action' }] } - ] + { name: 'two', severity: 2, actions: [{ name: 'two action' }] }, + ], }; const wrapper = getShallowWrapper({ monitor }); wrapper.setState({ selectedItems: [monitor.triggers[0]] }); diff --git a/public/pages/MonitorDetails/containers/Triggers/index.js b/public/pages/MonitorDetails/containers/Triggers/index.js index 23302ae5..464d56af 100644 --- a/public/pages/MonitorDetails/containers/Triggers/index.js +++ b/public/pages/MonitorDetails/containers/Triggers/index.js @@ -15,4 +15,4 @@ import Triggers from './Triggers'; -export default Triggers; \ No newline at end of file +export default Triggers; diff --git a/public/pages/Monitors/containers/Monitors/Monitors.test.js b/public/pages/Monitors/containers/Monitors/Monitors.test.js index 9d868b8d..3e3cf663 100644 --- a/public/pages/Monitors/containers/Monitors/Monitors.test.js +++ b/public/pages/Monitors/containers/Monitors/Monitors.test.js @@ -24,7 +24,7 @@ import AlertingFakes from '../../../../../test/utils/helpers'; const alertingFakes = new AlertingFakes('random seed'); jest.unmock('lodash'); -_.debounce = jest.fn((fn) => fn); +_.debounce = jest.fn(fn => fn); const match = { isExact: true, @@ -89,7 +89,12 @@ describe('Monitors', () => { expect(mountWrapper.instance().state.size).not.toBe(17); expect(mountWrapper.instance().state.sortField).not.toBe('testing_sort_field'); expect(mountWrapper.instance().state.sortDirection).not.toBe('asc'); - mountWrapper.instance().onTableChange({ page: { index: 17, size: 17 }, sort: { field: 'testing_sort_field', direction: 'desc' } }); + mountWrapper + .instance() + .onTableChange({ + page: { index: 17, size: 17 }, + sort: { field: 'testing_sort_field', direction: 'desc' }, + }); mountWrapper.update(); expect(onTableChange).toHaveBeenCalled(); @@ -141,26 +146,35 @@ describe('Monitors', () => { test('updateMonitor calls put with update', async () => { const updateMonitor = jest.spyOn(Monitors.prototype, 'updateMonitor'); - httpClientMock.put = jest.fn() + httpClientMock.put = jest + .fn() .mockResolvedValueOnce({ data: { ok: true } }) .mockRejectedValueOnce(new Error('random error')); const mountWrapper = getMountWrapper(); const monitor = alertingFakes.randomMonitor(); - const response = await mountWrapper.instance().updateMonitor({ id: 'random_id', version: 17, monitor }, { name: 'UNIQUE_NAME' }); + const response = await mountWrapper + .instance() + .updateMonitor({ id: 'random_id', version: 17, monitor }, { name: 'UNIQUE_NAME' }); mountWrapper.update(); expect(updateMonitor).toHaveBeenCalled(); expect(httpClientMock.put).toHaveBeenCalled(); - expect(httpClientMock.put).toHaveBeenCalledWith(`../api/alerting/monitors/random_id?version=17`, { ...monitor, name: 'UNIQUE_NAME' }); + expect(httpClientMock.put).toHaveBeenCalledWith( + `../api/alerting/monitors/random_id?version=17`, + { ...monitor, name: 'UNIQUE_NAME' } + ); expect(response).toEqual({ data: { ok: true } }); - const error = await mountWrapper.instance().updateMonitor({ id: 'random_id', version: 17, monitor }, { name: 'UNIQUE_NAME' }); + const error = await mountWrapper + .instance() + .updateMonitor({ id: 'random_id', version: 17, monitor }, { name: 'UNIQUE_NAME' }); expect(httpClientMock.put).toHaveBeenCalledTimes(2); expect(error.message).toBe('random error'); }); test('deleteMonitor calls delete', async () => { const deleteMonitor = jest.spyOn(Monitors.prototype, 'deleteMonitor'); - httpClientMock.delete = jest.fn() + httpClientMock.delete = jest + .fn() .mockResolvedValueOnce({ data: { ok: true } }) .mockRejectedValueOnce(new Error('random delete error')); const mountWrapper = getMountWrapper(); @@ -169,7 +183,9 @@ describe('Monitors', () => { expect(deleteMonitor).toHaveBeenCalled(); expect(httpClientMock.delete).toHaveBeenCalled(); - expect(httpClientMock.delete).toHaveBeenCalledWith(`../api/alerting/monitors/delete_id?version=15`); + expect(httpClientMock.delete).toHaveBeenCalledWith( + `../api/alerting/monitors/delete_id?version=15` + ); expect(response).toEqual({ data: { ok: true } }); const error = await mountWrapper.instance().deleteMonitor({ id: 'delete_id', version: 15 }); expect(httpClientMock.delete).toHaveBeenCalledTimes(2); @@ -194,7 +210,7 @@ describe('Monitors', () => { const alerts = [ { id: 'alert_1', monitor_id: 'monitor_1' }, { id: 'alert_2', monitor_id: 'monitor_1' }, - { id: 'alert_1', monitor_id: 'monitor_2' } + { id: 'alert_1', monitor_id: 'monitor_2' }, ]; await mountWrapper.instance().onClickAcknowledgeModal(alerts); @@ -381,7 +397,9 @@ describe('Monitors', () => { test('getItemId returns formatted id for table', () => { const getItemId = jest.spyOn(Monitors.prototype, 'getItemId'); const mountWrapper = getMountWrapper(); - const response = mountWrapper.instance().getItemId({ id: 'item_id', currentTime: 143534534345 }); + const response = mountWrapper + .instance() + .getItemId({ id: 'item_id', currentTime: 143534534345 }); expect(getItemId).toHaveBeenCalled(); expect(response).toBe('item_id-143534534345'); From 0b69438b9682fda1c8cdd2a385fd5caa94a17195 Mon Sep 17 00:00:00 2001 From: Mihir Soni Date: Wed, 8 May 2019 14:37:19 -0700 Subject: [PATCH 3/6] use seq_no and primary_term for updates --- package.json | 2 +- .../MonitorTimeField/MonitorTimeField.js | 1 - .../CreateDestination/CreateDestination.js | 11 +++-- .../containers/MonitorDetails.js | 40 ++++++++++++++----- .../containers/Monitors/Monitors.test.js | 10 ++--- server/clusters/alerting/alertingPlugin.js | 26 +++++++----- server/services/DestinationsService.js | 19 ++++++--- server/services/MonitorService.js | 15 ++++--- 8 files changed, 83 insertions(+), 41 deletions(-) diff --git a/package.json b/package.json index 3ed7a5fd..a303e5a9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "opendistro-alerting", - "version": "0.1.0.0", + "version": "1.0.0", "description": "Kibana Alerting Plugin", "main": "index.js", "license": "Apache-2.0", diff --git a/public/pages/CreateMonitor/components/MonitorTimeField/MonitorTimeField.js b/public/pages/CreateMonitor/components/MonitorTimeField/MonitorTimeField.js index 0778db24..9af26f13 100644 --- a/public/pages/CreateMonitor/components/MonitorTimeField/MonitorTimeField.js +++ b/public/pages/CreateMonitor/components/MonitorTimeField/MonitorTimeField.js @@ -21,7 +21,6 @@ import { validateTimeField } from './utils/validation'; const MonitorTimeField = ({ dataTypes }) => { // Default empty option + options from index mappings mapped to ui select form - console.log('dataTypes', dataTypes); const dateFields = Array.from(dataTypes.date || []); const options = [''].concat(dateFields).map(option => ({ value: option, text: option })); return ( diff --git a/public/pages/Destinations/containers/CreateDestination/CreateDestination.js b/public/pages/Destinations/containers/CreateDestination/CreateDestination.js index f498fd2b..df07f04d 100644 --- a/public/pages/Destinations/containers/CreateDestination/CreateDestination.js +++ b/public/pages/Destinations/containers/CreateDestination/CreateDestination.js @@ -49,6 +49,7 @@ class CreateDestination extends React.Component { const { location, edit, history } = this.props; let destinationVersion; + let ifSeqNo, ifPrimaryTerm; if (edit) { // In case user is refreshing in edit mode , redirect them to the destination page. // TODO:: Ideally this should fetch the destination from ElasticSearch and fill in value @@ -56,6 +57,8 @@ class CreateDestination extends React.Component { if (destinationToEdit) { initialValues = { ...destinationToFormik(destinationToEdit) }; destinationVersion = destinationToEdit.version; + ifSeqNo = destinationToEdit.ifSeqNo; + ifPrimaryTerm = destinationToEdit.ifPrimaryTerm; } else { history.push('/destinations'); } @@ -63,6 +66,8 @@ class CreateDestination extends React.Component { this.state = { initialValues, destinationVersion, + ifSeqNo, + ifPrimaryTerm, }; } @@ -92,14 +97,14 @@ class CreateDestination extends React.Component { }, history, } = this.props; - const { destinationVersion } = this.state; + const { destinationVersion, ifSeqNo, ifPrimaryTerm } = this.state; try { const resp = await httpClient.put( - `../api/alerting/destinations/${destinationId}?version=${destinationVersion}`, + `../api/alerting/destinations/${destinationId}?version=${destinationVersion}&ifSeqNo=${ifSeqNo}&ifPrimaryTerm=${ifPrimaryTerm}`, requestData ); const { - data: { ok, version }, + data: { ok }, } = resp; if (ok) { history.push(`/destinations`); diff --git a/public/pages/MonitorDetails/containers/MonitorDetails.js b/public/pages/MonitorDetails/containers/MonitorDetails.js index bd80914f..685c2969 100644 --- a/public/pages/MonitorDetails/containers/MonitorDetails.js +++ b/public/pages/MonitorDetails/containers/MonitorDetails.js @@ -40,6 +40,8 @@ export default class MonitorDetails extends Component { this.state = { monitor: null, monitorVersion: 0, + ifSeqNo: 0, + ifPrimaryTerm: 0, dayCount: 0, activeCount: 0, loading: true, @@ -71,9 +73,19 @@ export default class MonitorDetails extends Component { httpClient .get(`../api/alerting/monitors/${id}`) .then(resp => { - const { ok, resp: monitor, version: monitorVersion, dayCount, activeCount } = resp.data; + const { + ok, + resp: monitor, + version: monitorVersion, + dayCount, + activeCount, + ifSeqNo, + ifPrimaryTerm, + } = resp.data; if (ok) { this.setState({ + ifSeqNo, + ifPrimaryTerm, monitor, monitorVersion, dayCount, @@ -91,12 +103,20 @@ export default class MonitorDetails extends Component { }); }; - updateMonitor = (id, version, update) => { - const { httpClient } = this.props; - const { monitor } = this.state; + updateMonitor = update => { + const { + match: { + params: { monitorId }, + }, + httpClient, + } = this.props; + const { monitor, monitorVersion, ifSeqNo, ifPrimaryTerm } = this.state; this.setState({ updating: true }); return httpClient - .put(`../api/alerting/monitors/${id}?version=${version}`, { ...monitor, ...update }) + .put( + `../api/alerting/monitors/${monitorId}?version=${monitorVersion}&ifSeqNo=${ifSeqNo}&ifPrimaryTerm=${ifPrimaryTerm}`, + { ...monitor, ...update } + ) .then(resp => { const { version: monitorVersion } = resp.data; this.setState({ monitorVersion, updating: false }); @@ -184,7 +204,7 @@ export default class MonitorDetails extends Component { return ( this.updateMonitor(monitorId, monitorVersion, update)} + updateMonitor={this.updateMonitor} monitorToEdit={monitor} {...this.props} /> @@ -202,7 +222,7 @@ export default class MonitorDetails extends Component { setFlyout={this.props.setFlyout} onCloseTrigger={this.onCloseTrigger} onMonitorFieldChange={() => {}} - updateMonitor={update => this.updateMonitor(monitorId, monitorVersion, update)} + updateMonitor={this.updateMonitor} /> ); } @@ -241,9 +261,7 @@ export default class MonitorDetails extends Component { - this.updateMonitor(monitorId, monitorVersion, { enabled: !monitor.enabled }) - } + onClick={() => this.updateMonitor({ enabled: !monitor.enabled })} > {monitor.enabled ? 'Disable' : 'Enable'} @@ -259,7 +277,7 @@ export default class MonitorDetails extends Component { this.updateMonitor(monitorId, monitorVersion, update)} + updateMonitor={this.updateMonitor} onEditTrigger={this.onEditTrigger} onCreateTrigger={this.onCreateTrigger} /> diff --git a/public/pages/Monitors/containers/Monitors/Monitors.test.js b/public/pages/Monitors/containers/Monitors/Monitors.test.js index 3e3cf663..30f34d92 100644 --- a/public/pages/Monitors/containers/Monitors/Monitors.test.js +++ b/public/pages/Monitors/containers/Monitors/Monitors.test.js @@ -89,12 +89,10 @@ describe('Monitors', () => { expect(mountWrapper.instance().state.size).not.toBe(17); expect(mountWrapper.instance().state.sortField).not.toBe('testing_sort_field'); expect(mountWrapper.instance().state.sortDirection).not.toBe('asc'); - mountWrapper - .instance() - .onTableChange({ - page: { index: 17, size: 17 }, - sort: { field: 'testing_sort_field', direction: 'desc' }, - }); + mountWrapper.instance().onTableChange({ + page: { index: 17, size: 17 }, + sort: { field: 'testing_sort_field', direction: 'desc' }, + }); mountWrapper.update(); expect(onTableChange).toHaveBeenCalled(); diff --git a/server/clusters/alerting/alertingPlugin.js b/server/clusters/alerting/alertingPlugin.js index 968bf579..e098aa80 100644 --- a/server/clusters/alerting/alertingPlugin.js +++ b/server/clusters/alerting/alertingPlugin.js @@ -57,13 +57,17 @@ export default function alertingPlugin(Client, config, components) { alerting.updateMonitor = ca({ url: { - fmt: `${MONITOR_BASE_API}/<%=monitorId%>?if_seq_no=<%=if_seq_no%>&if_primary_term=<%=if_primary_term%>&refresh=wait_for`, + fmt: `${MONITOR_BASE_API}/<%=monitorId%>?if_seq_no=<%=ifSeqNo%>&if_primary_term=<%=ifPrimaryTerm%>&refresh=wait_for`, req: { monitorId: { type: 'string', required: true, }, - version: { + ifSeqNo: { + type: 'string', + required: true, + }, + ifPrimaryTerm: { type: 'string', required: true, }, @@ -88,8 +92,8 @@ export default function alertingPlugin(Client, config, components) { monitorId: { type: 'string', required: true, - } - } + }, + }, }, needBody: true, method: 'POST', @@ -102,7 +106,7 @@ export default function alertingPlugin(Client, config, components) { dryrun: { type: 'string', required: true, - } + }, }, }, needBody: true, @@ -119,13 +123,17 @@ export default function alertingPlugin(Client, config, components) { alerting.updateDestination = ca({ url: { - fmt: `${DESTINATION_BASE_API}/<%=destinationId%>?version=<%=version%>&refresh=wait_for`, + fmt: `${DESTINATION_BASE_API}/<%=destinationId%>?if_seq_no=<%=ifSeqNo%>&if_primary_term=<%=ifPrimaryTerm%>&refresh=wait_for`, req: { destinationId: { type: 'string', required: true, }, - version: { + ifSeqNo: { + type: 'string', + required: true, + }, + ifPrimaryTerm: { type: 'string', required: true, }, @@ -142,9 +150,9 @@ export default function alertingPlugin(Client, config, components) { destinationId: { type: 'string', required: true, - } + }, }, }, method: 'DELETE', }); -} \ No newline at end of file +} diff --git a/server/services/DestinationsService.js b/server/services/DestinationsService.js index ecc6eefd..ce3fded1 100644 --- a/server/services/DestinationsService.js +++ b/server/services/DestinationsService.js @@ -36,11 +36,12 @@ export default class DestinationsService { updateDestination = async (req, h) => { try { const { destinationId } = req.params; - const { version } = req.query; + const { version, ifSeqNo, ifPrimaryTerm } = req.query; const params = { body: JSON.stringify(req.payload), destinationId, - version, + ifSeqNo, + ifPrimaryTerm, }; const { callWithRequest } = await this.esDriver.getCluster(CLUSTER.ALERTING); const updateResponse = await callWithRequest(req, 'alerting.updateDestination', params); @@ -77,7 +78,8 @@ export default class DestinationsService { index: INDEX.SCHEDULED_JOBS, id: destinationId, }); - return { ok: true, destination: resp._source.destination, version: resp._version }; + const { _source, _seq_no: ifSeqNo, _primary_term: ifPrimaryTerm, _version: version } = resp; + return { ok: true, destination: _source.destination, version, ifSeqNo, ifPrimaryTerm }; } catch (err) { console.error('Alerting - DestinationService - getDestination:', err); return { ok: false, resp: err.message }; @@ -133,6 +135,7 @@ export default class DestinationsService { const params = { index: INDEX.SCHEDULED_JOBS, version: true, + seq_no_primary_term: true, body: { sort, size, @@ -151,8 +154,14 @@ export default class DestinationsService { const resp = await callWithRequest(req, 'search', params); const totalDestinations = resp.hits.total.value; const destinations = resp.hits.hits.map(hit => { - const { _source: destination, _id: id, _version: version } = hit; - return { id, ...destination.destination, version }; + const { + _source: destination, + _id: id, + _version: version, + _seq_no: ifSeqNo, + _primary_term: ifPrimaryTerm, + } = hit; + return { id, ...destination.destination, version, ifSeqNo, ifPrimaryTerm }; }); return { ok: true, destinations, totalDestinations }; } catch (err) { diff --git a/server/services/MonitorService.js b/server/services/MonitorService.js index 13619b9c..d3c7bb60 100644 --- a/server/services/MonitorService.js +++ b/server/services/MonitorService.js @@ -54,8 +54,11 @@ export default class MonitorService { const params = { monitorId: id }; const { callWithRequest } = await this.esDriver.getCluster(CLUSTER.ALERTING); const getResponse = await callWithRequest(req, 'alerting.getMonitor', params); + console.log('getResponse', JSON.stringify(getResponse)); const monitor = _.get(getResponse, 'monitor', null); const version = _.get(getResponse, '_version', null); + const ifSeqNo = _.get(getResponse, '_seq_no', null); + const ifPrimaryTerm = _.get(getResponse, '_primary_term', null); if (monitor) { const { callWithRequest } = this.esDriver.getCluster(CLUSTER.DATA); const searchResponse = await callWithRequest(req, 'search', { @@ -89,10 +92,10 @@ export default class MonitorService { const dayCount = _.get(searchResponse, 'aggregations.24_hour_count.buckets.0.doc_count', 0); const activeBuckets = _.get(searchResponse, 'aggregations.active_count.buckets', []); const activeCount = activeBuckets.reduce( - (accu, curr) => (curr.key === 'ACTIVE' ? curr.doc_count : accu), + (acc, curr) => (curr.key === 'ACTIVE' ? curr.doc_count : acc), 0 ); - return { ok: true, resp: monitor, activeCount, dayCount, version }; + return { ok: true, resp: monitor, activeCount, dayCount, version, ifSeqNo, ifPrimaryTerm }; } else { return { ok: false }; } @@ -105,8 +108,8 @@ export default class MonitorService { updateMonitor = async (req, h) => { try { const { id } = req.params; - const { version } = req.query; - const params = { monitorId: id, version, body: JSON.stringify(req.payload) }; + const { version, ifSeqNo, ifPrimaryTerm } = req.query; + const params = { monitorId: id, ifSeqNo, ifPrimaryTerm, body: JSON.stringify(req.payload) }; const { callWithRequest } = await this.esDriver.getCluster(CLUSTER.ALERTING); const updateResponse = await callWithRequest(req, 'alerting.updateMonitor', params); const { _version, _id } = updateResponse; @@ -169,7 +172,9 @@ export default class MonitorService { }), }; - const { callWithRequest: alertingCallWithRequest } = await this.esDriver.getCluster(CLUSTER.ALERTING); + const { callWithRequest: alertingCallWithRequest } = await this.esDriver.getCluster( + CLUSTER.ALERTING + ); const getResponse = await alertingCallWithRequest(req, 'alerting.getMonitors', params); const totalMonitors = _.get(getResponse, 'hits.total.value', 0); From 4431201b28e9beabd6bad1248717d4ac5f80e26c Mon Sep 17 00:00:00 2001 From: Mihir Soni Date: Wed, 8 May 2019 19:38:38 -0700 Subject: [PATCH 4/6] enabled dark mode support --- public/app.js | 3 +- .../components/Charts/Highlight/Highlight.js | 19 +++++-- public/less/main.less | 54 ------------------- .../ConfigureActions/ConfigureActions.js | 2 +- .../MonitorHistory/POIChart/POIChart.js | 5 +- .../MonitorHistory/MonitorHistory.js | 12 ++--- .../MonitorHistory/__mocks__/ui/chrome.js | 4 ++ server/services/MonitorService.js | 1 - 8 files changed, 29 insertions(+), 71 deletions(-) create mode 100644 public/pages/MonitorDetails/containers/MonitorHistory/__mocks__/ui/chrome.js diff --git a/public/app.js b/public/app.js index c602dd73..8eba90bb 100644 --- a/public/app.js +++ b/public/app.js @@ -18,9 +18,8 @@ import chrome from 'ui/chrome'; import { render, unmountComponentAtNode } from 'react-dom'; import { uiModules } from 'ui/modules'; import { HashRouter as Router, Route } from 'react-router-dom'; -import '@elastic/eui/dist/eui_theme_light.css'; -import 'react-vis/dist/style.css'; +import 'react-vis/dist/style.css'; import 'ui/autoload/styles'; import './less/main.less'; diff --git a/public/components/Charts/Highlight/Highlight.js b/public/components/Charts/Highlight/Highlight.js index 0ba1e838..baa97e73 100644 --- a/public/components/Charts/Highlight/Highlight.js +++ b/public/components/Charts/Highlight/Highlight.js @@ -287,6 +287,19 @@ class Highlight extends AbstractSeries { } } + getHighlighterStyles() { + const { isDarkMode } = this.props; + if (isDarkMode) { + return { + fill: 'black', + opacity: 0.1, + }; + } + return { + fill: 'white', + opacity: 0.8, + }; + } render() { const { color, @@ -360,13 +373,12 @@ class Highlight extends AbstractSeries { e.preventDefault()} + {...this.getHighlighterStyles()} /> {/* A Center Highlighter */} e.preventDefault()} + {...this.getHighlighterStyles()} /> {/* Draws border lines on Highlighted area */} diff --git a/public/less/main.less b/public/less/main.less index cf3aa7be..094ab029 100644 --- a/public/less/main.less +++ b/public/less/main.less @@ -50,55 +50,6 @@ * .euiSwitch .euiSwitch__thumb has a width/height set at 24px in older version which breaks the styling of the newer version. * */ -.euiSwitch .euiSwitch__thumb { - width: 20px; - height: 20px; -} - -.euiRadio .euiRadio__circle { - width: 16px; - height: 16px; -} - -.euiCheckbox { - min-height: initial; - - .euiCheckbox__input { - opacity: initial; - z-index: initial; - margin: initial; - cursor: initial; - } - - .euiCheckbox__square { - height: initial; - width: initial; - z-index: initial; - } - - .euiCheckbox__label { - font-weight: initial; - } -} - -.euiRadio .euiRadio__input:checked ~ .euiRadio__circle { - background-repeat-x: no-repeat; - background-repeat-y: no-repeat; - background-position-x: center; - background-position-y: center; -} - -.euiCheckbox .euiCheckbox__input:checked ~ .euiCheckbox__square { - background-position-x: center; - background-position-y: center; - background-repeat-x: no-repeat; - background-repeat-y: no-repeat; -} - -.euiAccordion__button:focus { - background-color: initial; -} - .euiFormRow.euiFormRow--hasEmptyLabelSpace { padding-top: initial; } @@ -123,8 +74,3 @@ .euiPaginationButton-isActive:focus { color: #0079a5 !important; } - -.euiComboBox .euiComboBox__input > input { - // Fixes blue rectangle border around cursor text - box-shadow: initial; -} diff --git a/public/pages/CreateTrigger/containers/ConfigureActions/ConfigureActions.js b/public/pages/CreateTrigger/containers/ConfigureActions/ConfigureActions.js index 271e0b0a..a6d4f8ac 100644 --- a/public/pages/CreateTrigger/containers/ConfigureActions/ConfigureActions.js +++ b/public/pages/CreateTrigger/containers/ConfigureActions/ConfigureActions.js @@ -131,7 +131,7 @@ class ConfigureActions extends React.Component { title="Configure Actions" titleSize="s" panelStyles={{ paddingBottom: '0px' }} - bodyStyles={{ backgroundColor: '#F6F6F6', padding: '10px' }} + bodyStyles={{ padding: '10px' }} horizontalRuleClassName="accordion-horizontal-rule" actions={} > diff --git a/public/pages/MonitorDetails/components/MonitorHistory/POIChart/POIChart.js b/public/pages/MonitorDetails/components/MonitorHistory/POIChart/POIChart.js index bd56266d..88895c86 100644 --- a/public/pages/MonitorDetails/components/MonitorHistory/POIChart/POIChart.js +++ b/public/pages/MonitorDetails/components/MonitorHistory/POIChart/POIChart.js @@ -27,6 +27,7 @@ const POIChart = ({ yDomain, highlightedArea, isLoading, + isDarkMode, }) => ( diff --git a/public/pages/MonitorDetails/containers/MonitorHistory/__mocks__/ui/chrome.js b/public/pages/MonitorDetails/containers/MonitorHistory/__mocks__/ui/chrome.js new file mode 100644 index 00000000..e71d5448 --- /dev/null +++ b/public/pages/MonitorDetails/containers/MonitorHistory/__mocks__/ui/chrome.js @@ -0,0 +1,4 @@ +const chrome = { + getUiSettingsClient: () => ({ get: () => false }), +}; +module.exports = chrome; diff --git a/server/services/MonitorService.js b/server/services/MonitorService.js index d3c7bb60..59ba4f4b 100644 --- a/server/services/MonitorService.js +++ b/server/services/MonitorService.js @@ -54,7 +54,6 @@ export default class MonitorService { const params = { monitorId: id }; const { callWithRequest } = await this.esDriver.getCluster(CLUSTER.ALERTING); const getResponse = await callWithRequest(req, 'alerting.getMonitor', params); - console.log('getResponse', JSON.stringify(getResponse)); const monitor = _.get(getResponse, 'monitor', null); const version = _.get(getResponse, '_version', null); const ifSeqNo = _.get(getResponse, '_seq_no', null); From 84ebb01e1262dc666449b8fd17827b6ce6772632 Mon Sep 17 00:00:00 2001 From: Mihir Soni Date: Thu, 9 May 2019 11:34:03 -0700 Subject: [PATCH 5/6] fixed code-edtior in dark mode --- public/less/main.less | 3 --- .../components/ExtractionQuery/ExtractionQuery.js | 7 +++---- .../containers/DefineMonitor/DefineMonitor.js | 9 ++++++++- .../components/TriggerQuery/TriggerQuery.js | 6 +++--- .../containers/CreateTrigger/CreateTrigger.js | 3 +++ .../containers/DefineTrigger/DefineTrigger.js | 3 +++ 6 files changed, 20 insertions(+), 11 deletions(-) diff --git a/public/less/main.less b/public/less/main.less index 094ab029..0436c4c2 100644 --- a/public/less/main.less +++ b/public/less/main.less @@ -22,8 +22,6 @@ } .accordion-action { - background-color: white; - border: 1px solid #d9d9d9; padding: 10px 0px; margin-bottom: 10px; .euiAccordion__button { @@ -36,7 +34,6 @@ } .euiTextArea.read-only-text-area { - background-color: #fbfbfb; padding-left: 12px; border-color: initial; box-shadow: 0 1px 1px -1px rgba(153, 153, 153, 0.2), 0 3px 2px -2px rgba(153, 153, 153, 0.2), diff --git a/public/pages/CreateMonitor/components/ExtractionQuery/ExtractionQuery.js b/public/pages/CreateMonitor/components/ExtractionQuery/ExtractionQuery.js index 6876cdd2..6579d060 100644 --- a/public/pages/CreateMonitor/components/ExtractionQuery/ExtractionQuery.js +++ b/public/pages/CreateMonitor/components/ExtractionQuery/ExtractionQuery.js @@ -15,7 +15,6 @@ import React from 'react'; import { EuiCodeEditor, EuiFlexGroup, EuiFlexItem, EuiFormRow } from '@elastic/eui'; -import 'brace/theme/github'; import 'brace/mode/json'; import 'brace/mode/plain_text'; import 'brace/snippets/javascript'; @@ -24,7 +23,7 @@ import 'brace/ext/language_tools'; import { FormikCodeEditor } from '../../../../components/FormControls'; import { isInvalid, hasError, validateExtractionQuery } from '../../../../utils/validate'; -const ExtractionQuery = ({ response }) => ( +const ExtractionQuery = ({ isDarkMode, response }) => ( ( mode: 'json', width: '100%', height: '500px', - theme: 'github', + theme: isDarkMode ? 'sense-dark' : 'github', onChange: (query, field, form) => { form.setFieldValue('query', query); }, @@ -55,7 +54,7 @@ const ExtractionQuery = ({ response }) => ( ; + content = ( + + ); } } diff --git a/public/pages/CreateTrigger/components/TriggerQuery/TriggerQuery.js b/public/pages/CreateTrigger/components/TriggerQuery/TriggerQuery.js index e2e6b1db..538cadb6 100644 --- a/public/pages/CreateTrigger/components/TriggerQuery/TriggerQuery.js +++ b/public/pages/CreateTrigger/components/TriggerQuery/TriggerQuery.js @@ -26,7 +26,6 @@ import { EuiSpacer, EuiText, } from '@elastic/eui'; -import 'brace/theme/github'; import 'brace/mode/json'; import 'brace/mode/plain_text'; import 'brace/snippets/javascript'; @@ -54,6 +53,7 @@ const TriggerQuery = ({ response, triggerValues, setFlyout, + isDarkMode, }) => { const trigger = { ...formikToTrigger(triggerValues), actions: [] }; const formattedResponse = JSON.stringify(response, null, 4); @@ -64,7 +64,7 @@ const TriggerQuery = ({ { diff --git a/public/pages/CreateTrigger/containers/CreateTrigger/CreateTrigger.js b/public/pages/CreateTrigger/containers/CreateTrigger/CreateTrigger.js index 4481ff42..4db20e37 100644 --- a/public/pages/CreateTrigger/containers/CreateTrigger/CreateTrigger.js +++ b/public/pages/CreateTrigger/containers/CreateTrigger/CreateTrigger.js @@ -15,6 +15,7 @@ import React, { Component, Fragment } from 'react'; import _ from 'lodash'; +import chrome from 'ui/chrome'; import moment from 'moment'; import { Formik, FieldArray } from 'formik'; import { @@ -54,6 +55,7 @@ export default class CreateTrigger extends Component { executeResponse: null, initialValues, }; + this.isDarkMode = chrome.getUiSettingsClient().get('theme:darkMode') || false; } componentDidMount() { @@ -206,6 +208,7 @@ export default class CreateTrigger extends Component { setFlyout={setFlyout} triggers={monitor.triggers} triggerValues={values} + isDarkMode={this.isDarkMode} /> { const isGraph = _.get(monitorValues, 'searchType') === SEARCH_TYPE.GRAPH; const response = _.get(executeResponse, 'input_results.results[0]'); @@ -109,6 +111,7 @@ const DefineTrigger = ({ response={response} setFlyout={setFlyout} triggerValues={triggerValues} + isDarkMode={isDarkMode} /> )} From d46444c37bc5cbc3b677a5a33d738e32d6483cbc Mon Sep 17 00:00:00 2001 From: Mihir Soni Date: Fri, 10 May 2019 18:52:44 -0700 Subject: [PATCH 6/6] removed unused versions --- .../CreateDestination/CreateDestination.js | 13 ++++++------- .../MonitorDetails/containers/MonitorDetails.js | 4 ++-- server/services/DestinationsService.js | 8 ++------ server/services/MonitorService.js | 8 ++------ test/jest.config.js | 2 +- 5 files changed, 13 insertions(+), 22 deletions(-) diff --git a/public/pages/Destinations/containers/CreateDestination/CreateDestination.js b/public/pages/Destinations/containers/CreateDestination/CreateDestination.js index df07f04d..66da8471 100644 --- a/public/pages/Destinations/containers/CreateDestination/CreateDestination.js +++ b/public/pages/Destinations/containers/CreateDestination/CreateDestination.js @@ -48,7 +48,6 @@ class CreateDestination extends React.Component { let initialValues = formikInitialValues; const { location, edit, history } = this.props; - let destinationVersion; let ifSeqNo, ifPrimaryTerm; if (edit) { // In case user is refreshing in edit mode , redirect them to the destination page. @@ -56,7 +55,6 @@ class CreateDestination extends React.Component { const destinationToEdit = _.get(location, 'state.destinationToEdit', null); if (destinationToEdit) { initialValues = { ...destinationToFormik(destinationToEdit) }; - destinationVersion = destinationToEdit.version; ifSeqNo = destinationToEdit.ifSeqNo; ifPrimaryTerm = destinationToEdit.ifPrimaryTerm; } else { @@ -65,7 +63,6 @@ class CreateDestination extends React.Component { } this.state = { initialValues, - destinationVersion, ifSeqNo, ifPrimaryTerm, }; @@ -76,9 +73,11 @@ class CreateDestination extends React.Component { try { const resp = await httpClient.get(`../api/alerting/destinations/${destinationId}`); if (resp.data.ok) { - const destinationVersion = _.get(resp, 'data.version'); + const ifSeqNo = _.get(resp, 'data.ifSeqNo'); + const ifPrimaryTerm = _.get(resp, 'data.ifPrimaryTerm'); this.setState({ - destinationVersion, + ifSeqNo, + ifPrimaryTerm, }); } else { // Handle error, show message in case of 404 @@ -97,10 +96,10 @@ class CreateDestination extends React.Component { }, history, } = this.props; - const { destinationVersion, ifSeqNo, ifPrimaryTerm } = this.state; + const { ifSeqNo, ifPrimaryTerm } = this.state; try { const resp = await httpClient.put( - `../api/alerting/destinations/${destinationId}?version=${destinationVersion}&ifSeqNo=${ifSeqNo}&ifPrimaryTerm=${ifPrimaryTerm}`, + `../api/alerting/destinations/${destinationId}?ifSeqNo=${ifSeqNo}&ifPrimaryTerm=${ifPrimaryTerm}`, requestData ); const { diff --git a/public/pages/MonitorDetails/containers/MonitorDetails.js b/public/pages/MonitorDetails/containers/MonitorDetails.js index 685c2969..1898b100 100644 --- a/public/pages/MonitorDetails/containers/MonitorDetails.js +++ b/public/pages/MonitorDetails/containers/MonitorDetails.js @@ -110,11 +110,11 @@ export default class MonitorDetails extends Component { }, httpClient, } = this.props; - const { monitor, monitorVersion, ifSeqNo, ifPrimaryTerm } = this.state; + const { monitor, ifSeqNo, ifPrimaryTerm } = this.state; this.setState({ updating: true }); return httpClient .put( - `../api/alerting/monitors/${monitorId}?version=${monitorVersion}&ifSeqNo=${ifSeqNo}&ifPrimaryTerm=${ifPrimaryTerm}`, + `../api/alerting/monitors/${monitorId}?ifSeqNo=${ifSeqNo}&ifPrimaryTerm=${ifPrimaryTerm}`, { ...monitor, ...update } ) .then(resp => { diff --git a/server/services/DestinationsService.js b/server/services/DestinationsService.js index ce3fded1..d6ac4e9e 100644 --- a/server/services/DestinationsService.js +++ b/server/services/DestinationsService.js @@ -36,7 +36,7 @@ export default class DestinationsService { updateDestination = async (req, h) => { try { const { destinationId } = req.params; - const { version, ifSeqNo, ifPrimaryTerm } = req.query; + const { ifSeqNo, ifPrimaryTerm } = req.query; const params = { body: JSON.stringify(req.payload), destinationId, @@ -46,11 +46,7 @@ export default class DestinationsService { const { callWithRequest } = await this.esDriver.getCluster(CLUSTER.ALERTING); const updateResponse = await callWithRequest(req, 'alerting.updateDestination', params); const { _version, _id } = updateResponse; - if (_version === parseInt(version, 10) + 1) { - return { ok: true, version: _version, id: _id }; - } else { - return { ok: false, resp: updateResponse }; - } + return { ok: true, version: _version, id: _id }; } catch (err) { console.error('Alerting - DestinationService - updateDestination:', err); return { ok: false, resp: err.message }; diff --git a/server/services/MonitorService.js b/server/services/MonitorService.js index 59ba4f4b..d179d2df 100644 --- a/server/services/MonitorService.js +++ b/server/services/MonitorService.js @@ -107,16 +107,12 @@ export default class MonitorService { updateMonitor = async (req, h) => { try { const { id } = req.params; - const { version, ifSeqNo, ifPrimaryTerm } = req.query; + const { ifSeqNo, ifPrimaryTerm } = req.query; const params = { monitorId: id, ifSeqNo, ifPrimaryTerm, body: JSON.stringify(req.payload) }; const { callWithRequest } = await this.esDriver.getCluster(CLUSTER.ALERTING); const updateResponse = await callWithRequest(req, 'alerting.updateMonitor', params); const { _version, _id } = updateResponse; - if (_version === parseInt(version, 10) + 1) { - return { ok: true, version: _version, id: _id }; - } else { - return { ok: false }; - } + return { ok: true, version: _version, id: _id }; } catch (err) { console.error('Alerting - MonitorService - updateMonitor:', err); return { ok: false, resp: err.message }; diff --git a/test/jest.config.js b/test/jest.config.js index 0f81f21c..1d51d90b 100644 --- a/test/jest.config.js +++ b/test/jest.config.js @@ -29,7 +29,7 @@ module.exports = { coverageReporters: ['lcov', 'text', 'cobertura'], testMatch: ['**/*.test.js'], collectCoverageFrom: [ - '**/*.{js}', + '**/*.js', '!**/node_modules/**', '!**/index.js', '!/public/actions/**',