diff --git a/public/components/Flyout/flyouts/components/AlertsDashboardFlyoutComponent.js b/public/components/Flyout/flyouts/components/AlertsDashboardFlyoutComponent.js index cc695f837..bafddddac 100644 --- a/public/components/Flyout/flyouts/components/AlertsDashboardFlyoutComponent.js +++ b/public/components/Flyout/flyouts/components/AlertsDashboardFlyoutComponent.js @@ -148,7 +148,7 @@ export default class AlertsDashboardFlyoutComponent extends Component { this.setState({ tabContent: this.renderAlertsTable() }); } - getBucketLevelGraphConditions = (trigger) => { + getMultipleGraphConditions = (trigger) => { let conditions = _.get(trigger, 'condition.script.source'); if (_.isEmpty(conditions)) { return '-'; @@ -514,11 +514,21 @@ export default class AlertsDashboardFlyoutComponent extends Component { const groupBy = _.get(monitor, MONITOR_GROUP_BY); const condition = - (searchType === SEARCH_TYPE.GRAPH && monitorType === MONITOR_TYPE.BUCKET_LEVEL) || - MONITOR_TYPE.DOC_LEVEL - ? this.getBucketLevelGraphConditions(trigger) + searchType === SEARCH_TYPE.GRAPH && + (monitorType === MONITOR_TYPE.BUCKET_LEVEL || monitorType === MONITOR_TYPE.DOC_LEVEL) + ? this.getMultipleGraphConditions(trigger) : _.get(trigger, 'condition.script.source', '-'); + let displayMultipleConditions; + switch (monitorType) { + case MONITOR_TYPE.BUCKET_LEVEL: + case MONITOR_TYPE.DOC_LEVEL: + displayMultipleConditions = true; + break; + default: + displayMultipleConditions = false; + } + const filters = monitorType === MONITOR_TYPE.BUCKET_LEVEL && searchType === SEARCH_TYPE.GRAPH ? this.getBucketLevelGraphFilter(trigger) @@ -534,7 +544,15 @@ export default class AlertsDashboardFlyoutComponent extends Component { ? `${bucketValue} ${bucketUnitOfTime}` : '-'; - const displayTableTabs = monitorType === MONITOR_TYPE.DOC_LEVEL; + let displayTableTabs; + switch (monitorType) { + case MONITOR_TYPE.DOC_LEVEL: + displayTableTabs = true; + break; + default: + displayTableTabs = false; + break; + } return (
@@ -590,9 +608,7 @@ export default class AlertsDashboardFlyoutComponent extends Component { - - {monitorType === MONITOR_TYPE.BUCKET_LEVEL ? 'Conditions' : 'Condition'} - + {displayMultipleConditions ? 'Conditions' : 'Condition'}

{loadingMonitors || loading ? 'Loading conditions...' : condition}

diff --git a/public/pages/CreateMonitor/components/DocumentLevelMonitorQueries/ConfigureDocumentLevelQueries.js b/public/pages/CreateMonitor/components/DocumentLevelMonitorQueries/ConfigureDocumentLevelQueries.js index 499b42fe5..c4965de37 100644 --- a/public/pages/CreateMonitor/components/DocumentLevelMonitorQueries/ConfigureDocumentLevelQueries.js +++ b/public/pages/CreateMonitor/components/DocumentLevelMonitorQueries/ConfigureDocumentLevelQueries.js @@ -8,7 +8,8 @@ import _ from 'lodash'; import { connect, FieldArray } from 'formik'; import { EuiButton, EuiSpacer } from '@elastic/eui'; import { inputLimitText } from '../../../../utils/helpers'; -import DocumentLevelQuery, { getInitialQueryValues } from './DocumentLevelQuery'; +import DocumentLevelQuery from './DocumentLevelQuery'; +import { FORMIK_INITIAL_DOCUMENT_LEVEL_QUERY_VALUES } from '../../containers/CreateMonitor/utils/constants'; export const MAX_QUERIES = 10; // TODO DRAFT: Placeholder limit @@ -23,7 +24,8 @@ class ConfigureDocumentLevelQueries extends Component { dataTypes, formik: { values }, } = this.props; - if (_.isEmpty(values.queries)) arrayHelpers.push(_.cloneDeep(getInitialQueryValues())); + if (_.isEmpty(values.queries)) + arrayHelpers.push(_.cloneDeep(FORMIK_INITIAL_DOCUMENT_LEVEL_QUERY_VALUES)); const numOfQueries = values.queries.length; return (
@@ -44,7 +46,9 @@ class ConfigureDocumentLevelQueries extends Component { arrayHelpers.push(_.cloneDeep(getInitialQueryValues(numOfQueries)))} + onClick={() => + arrayHelpers.push(_.cloneDeep(FORMIK_INITIAL_DOCUMENT_LEVEL_QUERY_VALUES)) + } disabled={numOfQueries >= MAX_QUERIES} > {numOfQueries === 0 ? 'Add query' : 'Add another query'} diff --git a/public/pages/CreateMonitor/components/DocumentLevelMonitorQueries/ConfigureDocumentLevelQueryTags.js b/public/pages/CreateMonitor/components/DocumentLevelMonitorQueries/ConfigureDocumentLevelQueryTags.js index ddca82962..176883f73 100644 --- a/public/pages/CreateMonitor/components/DocumentLevelMonitorQueries/ConfigureDocumentLevelQueryTags.js +++ b/public/pages/CreateMonitor/components/DocumentLevelMonitorQueries/ConfigureDocumentLevelQueryTags.js @@ -5,9 +5,13 @@ import React, { Component } from 'react'; import { connect, FieldArray } from 'formik'; -import { EuiButtonEmpty } from '@elastic/eui'; +import { EuiButtonEmpty, EuiSpacer, EuiText } from '@elastic/eui'; import { inputLimitText } from '../../../../utils/helpers'; -import DocumentLevelQueryTag from './DocumentLevelQueryTag'; +import DocumentLevelQueryTag, { DOC_LEVEL_TAG_TOOLTIP } from './DocumentLevelQueryTag'; +import IconToolTip from '../../../../components/IconToolTip'; +import _ from 'lodash'; +import { FormikFormRow } from '../../../../components/FormControls'; +import { hasError, isInvalid } from '../../../../utils/validate'; export const MAX_TAGS = 10; // TODO DRAFT: Placeholder limit @@ -19,37 +23,59 @@ class ConfigureDocumentLevelQueryTags extends Component { renderTags(arrayHelpers) { const { - formik: { values }, + formik: { errors, values }, formFieldName = '', query, queryIndex, } = this.props; const numOfTags = query.tags.length; + const tagsErrors = _.get(errors, `${formFieldName}.tags`, []); + const containsErrors = !_.isEmpty(tagsErrors); return (
- {values.queries[queryIndex].tags.map((tag, index) => { - return ( - - - - ); - })} -
- arrayHelpers.push('')} - disabled={numOfTags >= MAX_TAGS} - style={{ paddingTop: '5px' }} - > - + Add tag - - {inputLimitText(numOfTags, MAX_TAGS, 'tag', 'tags')} -
+ + Tags + - optional + + + + + {_.isEmpty(query.tags) && ( +
+ No tags defined. +
+ )} + + +
+ {values.queries[queryIndex].tags.map((tag, index) => { + return ( + + + + ); + })} +
+
+ + arrayHelpers.push('')} + disabled={numOfTags >= MAX_TAGS} + style={{ paddingTop: '5px' }} + > + + Add tag + + {inputLimitText(numOfTags, MAX_TAGS, 'tag', 'tags')}
); } @@ -57,7 +83,7 @@ class ConfigureDocumentLevelQueryTags extends Component { render() { const { formFieldName } = this.props; return ( - + {(arrayHelpers) => this.renderTags(arrayHelpers)} ); diff --git a/public/pages/CreateMonitor/components/DocumentLevelMonitorQueries/DocumentLevelQuery.js b/public/pages/CreateMonitor/components/DocumentLevelMonitorQueries/DocumentLevelQuery.js index 0bed64e16..2b9eeb434 100644 --- a/public/pages/CreateMonitor/components/DocumentLevelMonitorQueries/DocumentLevelQuery.js +++ b/public/pages/CreateMonitor/components/DocumentLevelMonitorQueries/DocumentLevelQuery.js @@ -4,32 +4,23 @@ */ import React, { Component } from 'react'; -import _ from 'lodash'; import { connect } from 'formik'; -import { - EuiButton, - EuiFlexGroup, - EuiFlexItem, - EuiHorizontalRule, - EuiSpacer, - EuiText, -} from '@elastic/eui'; +import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiSpacer } from '@elastic/eui'; import { FormikComboBox, FormikFieldText, FormikSelect } from '../../../../components/FormControls'; -import { hasError, isInvalid, required } from '../../../../utils/validate'; -import { FORMIK_INITIAL_DOCUMENT_LEVEL_QUERY_VALUES } from '../../containers/CreateMonitor/utils/constants'; -import { DOC_LEVEL_TAG_TOOLTIP } from './DocumentLevelQueryTag'; -import IconToolTip from '../../../../components/IconToolTip'; +import { + hasError, + isInvalid, + required, + validateIllegalCharacters, +} from '../../../../utils/validate'; import ConfigureDocumentLevelQueryTags from './ConfigureDocumentLevelQueryTags'; import { getIndexFields } from '../MonitorExpressions/expressions/utils/dataTypes'; import { QUERY_OPERATORS } from '../../../Dashboard/components/FindingsDashboard/utils'; const ALLOWED_DATA_TYPES = ['number', 'text', 'keyword', 'boolean']; -export const getInitialQueryValues = (queryIndexNum = 0) => - _.cloneDeep({ - ...FORMIK_INITIAL_DOCUMENT_LEVEL_QUERY_VALUES, - queryName: `Query ${queryIndexNum + 1}`, - }); +// TODO DRAFT: implement validation +export const ILLEGAL_QUERY_NAME_CHARACTERS = [' ']; class DocumentLevelQuery extends Component { constructor(props) { @@ -46,14 +37,19 @@ class DocumentLevelQuery extends Component { @@ -124,19 +120,6 @@ class DocumentLevelQuery extends Component { - - Tags - - optional - - - - - {_.isEmpty(query.tags) && ( -
- No tags defined. -
- )} - { const MonitorDefinitionCard = ({ values, plugins }) => { const hasADPlugin = plugins.indexOf(OS_AD_PLUGIN) !== -1; - const isBucketLevelMonitor = values.monitor_type === MONITOR_TYPE.BUCKET_LEVEL; - + let supportsADOption; + switch (values.monitor_type) { + case MONITOR_TYPE.QUERY_LEVEL: + supportsADOption = true; + break; + default: + supportsADOption = false; + } return (
@@ -68,8 +74,8 @@ const MonitorDefinitionCard = ({ values, plugins }) => { }} /> - {/*// Only show the anomaly detector option when anomaly detection plugin is present, but not for bucket-level monitors.*/} - {hasADPlugin && !isBucketLevelMonitor && ( + {/*// Only show the anomaly detector option when anomaly detection plugin is present, and for supporting monitors.*/} + {hasADPlugin && supportsADOption && (
-
-
-
-
-
- -
-
-
- -
-
-
`; diff --git a/public/pages/CreateMonitor/containers/CreateMonitor/CreateMonitor.js b/public/pages/CreateMonitor/containers/CreateMonitor/CreateMonitor.js index 4741501a3..36dbe7468 100644 --- a/public/pages/CreateMonitor/containers/CreateMonitor/CreateMonitor.js +++ b/public/pages/CreateMonitor/containers/CreateMonitor/CreateMonitor.js @@ -170,13 +170,15 @@ export default class CreateMonitor extends Component { let triggerType; switch (monitor_type) { - case MONITOR_TYPE.QUERY_LEVEL: - case MONITOR_TYPE.CLUSTER_METRICS: - triggerType = TRIGGER_TYPE.QUERY_LEVEL; - break; case MONITOR_TYPE.BUCKET_LEVEL: triggerType = TRIGGER_TYPE.BUCKET_LEVEL; break; + case MONITOR_TYPE.DOC_LEVEL: + triggerType = TRIGGER_TYPE.DOC_LEVEL; + break; + default: + triggerType = TRIGGER_TYPE.QUERY_LEVEL; + break; } if (_.isArray(triggerToEdit)) { diff --git a/public/pages/CreateMonitor/containers/CreateMonitor/utils/constants.js b/public/pages/CreateMonitor/containers/CreateMonitor/utils/constants.js index 52acb4ff2..1197e06c9 100644 --- a/public/pages/CreateMonitor/containers/CreateMonitor/utils/constants.js +++ b/public/pages/CreateMonitor/containers/CreateMonitor/utils/constants.js @@ -64,7 +64,7 @@ export const FORMIK_INITIAL_AGG_VALUES = { export const FORMIK_INITIAL_DOCUMENT_LEVEL_QUERY_VALUES = { id: undefined, - queryName: 'Query name', + queryName: '', field: '', operator: QUERY_OPERATORS[0].value, query: '', diff --git a/public/pages/CreateTrigger/components/Action/__snapshots__/Action.test.js.snap b/public/pages/CreateTrigger/components/Action/__snapshots__/Action.test.js.snap index fd01e21ee..e5ec21cde 100644 --- a/public/pages/CreateTrigger/components/Action/__snapshots__/Action.test.js.snap +++ b/public/pages/CreateTrigger/components/Action/__snapshots__/Action.test.js.snap @@ -389,19 +389,24 @@ exports[`Action renders with Notifications plugin installed 1`] = `
-
+
- - Perform action - -
- Per monitor execution +
+ + Perform action + +
+ Per monitor execution +
+
-
+
- - Perform action - -
- Per monitor execution +
+ + Perform action + +
+ Per monitor execution +
+
) : ( - +
+ + +
)} {actionExecutionScopeId !== NOTIFY_OPTIONS_VALUES.PER_EXECUTION ? ( diff --git a/public/pages/CreateTrigger/components/Action/actions/__snapshots__/Message.test.js.snap b/public/pages/CreateTrigger/components/Action/actions/__snapshots__/Message.test.js.snap index 1fb13b85c..2f7ddbbc7 100644 --- a/public/pages/CreateTrigger/components/Action/actions/__snapshots__/Message.test.js.snap +++ b/public/pages/CreateTrigger/components/Action/actions/__snapshots__/Message.test.js.snap @@ -165,19 +165,24 @@ exports[`Message renders 1`] = `
-
+
- - Perform action - -
- Per monitor execution +
+ + Perform action + +
+ Per monitor execution +
+
{ + const triggerConditions = _.get(triggerValues, `${fieldPath}triggerConditions`, []); + const selectedQueriesAndTags = triggerConditions.map((condition) => + _.get(condition, 'query.queryName') + ); const queries = _.get(monitorValues, 'queries', []); + const tagSelectOptions = []; const querySelectOptions = queries.map((query) => { query.tags.forEach((tag) => { const tagOption = { label: tag, value: { queryName: tag, operator: '==', expression: `${QUERY_IDENTIFIERS.TAG}${tag}` }, + disabled: _.includes(selectedQueriesAndTags, tag), }; if (!_.includes(tagSelectOptions, tagOption)) tagSelectOptions.push(tagOption); }); return { label: query.queryName, value: { ...query, expression: `${QUERY_IDENTIFIERS.NAME}${query.queryName}` }, + disabled: _.includes(selectedQueriesAndTags, query.queryName), }; }); - const triggerConditions = _.get(triggerValues, `${fieldPath}triggerConditions`, []); - if (_.isEmpty(triggerConditions)) { + if (_.isEmpty(triggerConditions)) arrayHelpers.push(_.cloneDeep(FORMIK_INITIAL_TRIGGER_CONDITION_VALUES)); - } return triggerConditions.map((triggerCondition, index) => (
diff --git a/public/pages/Dashboard/components/AcknowledgeAlertsModal/AcknowledgeAlertsModal.js b/public/pages/Dashboard/components/AcknowledgeAlertsModal/AcknowledgeAlertsModal.js index 03ce1c9a6..24fc10261 100644 --- a/public/pages/Dashboard/components/AcknowledgeAlertsModal/AcknowledgeAlertsModal.js +++ b/public/pages/Dashboard/components/AcknowledgeAlertsModal/AcknowledgeAlertsModal.js @@ -177,6 +177,7 @@ export default class AcknowledgeAlertsModal extends Component { }; acknowledgeAlerts = async () => { + this.setState({ loading: true }); const { selectedItems } = this.state; const { httpClient, notifications } = this.props; @@ -227,7 +228,7 @@ export default class AcknowledgeAlertsModal extends Component { alertState, monitorIds ); - this.setState({ ...this.state, selectedItems: [] }); + this.setState({ ...this.state, loading: false, selectedItems: [] }); }; onSeverityLevelChange = (e) => { @@ -305,6 +306,7 @@ export default class AcknowledgeAlertsModal extends Component { switch (monitorType) { case MONITOR_TYPE.QUERY_LEVEL: case MONITOR_TYPE.CLUSTER_METRICS: + case MONITOR_TYPE.DOC_LEVEL: return `${item.id}-${item.version}`; case MONITOR_TYPE.BUCKET_LEVEL: return item.id; diff --git a/public/pages/Dashboard/containers/Dashboard.js b/public/pages/Dashboard/containers/Dashboard.js index c85b20093..3c2202fa5 100644 --- a/public/pages/Dashboard/containers/Dashboard.js +++ b/public/pages/Dashboard/containers/Dashboard.js @@ -18,6 +18,8 @@ import { } from '../../../utils/constants'; import { backendErrorNotification } from '../../../utils/helpers'; import { + displayAcknowledgedAlertsToast, + filterActiveAlerts, getInitialSize, getQueryObjectFromState, getURLQueryParams, @@ -190,6 +192,63 @@ export default class Dashboard extends Component { this.setState({ ...this.state, loadingMonitors: false, monitors: monitors }); } + // TODO: exists in both Dashboard and Monitors, should be moved to redux when implemented + acknowledgeAlert = async () => { + const { selectedItems } = this.state; + const { httpClient, notifications, perAlertView } = this.props; + + if (!selectedItems.length) return; + + let selectedAlerts = perAlertView ? selectedItems : _.get(selectedItems, '0.alerts', []); + selectedAlerts = filterActiveAlerts(selectedAlerts); + + const monitorAlerts = selectedAlerts.reduce((monitorAlerts, alert) => { + const { id, monitor_id: monitorId } = alert; + if (monitorAlerts[monitorId]) monitorAlerts[monitorId].push(id); + else monitorAlerts[monitorId] = [id]; + return monitorAlerts; + }, {}); + + Object.entries(monitorAlerts).map(([monitorId, alerts]) => + httpClient + .post(`../api/alerting/monitors/${monitorId}/_acknowledge/alerts`, { + body: JSON.stringify({ alerts }), + }) + .then((resp) => { + if (!resp.ok) { + backendErrorNotification(notifications, 'acknowledge', 'alert', resp.resp); + } else { + const successfulCount = _.get(resp, 'resp.success', []).length; + displayAcknowledgedAlertsToast(notifications, successfulCount); + } + }) + .catch((error) => error) + ); + + this.setState({ selectedItems: [] }); + const { + page, + size, + search, + sortField, + sortDirection, + severityLevel, + alertState, + monitorIds, + } = this.state; + this.getAlerts( + page * size, + size, + search, + sortField, + sortDirection, + severityLevel, + alertState, + monitorIds + ); + this.refreshDashboard(); + }; + onTableChange = ({ page: tablePage = {}, sort = {} }) => { const { index: page, size } = tablePage; const { field: sortField, direction: sortDirection } = sort; @@ -373,7 +432,7 @@ export default class Dashboard extends Component { // The acknowledge button is disabled when viewing by per alerts, and no item selected or per trigger view and item selected is not 1. const actions = [ diff --git a/public/pages/MonitorDetails/containers/MonitorDetails.js b/public/pages/MonitorDetails/containers/MonitorDetails.js index c999df5f7..dc9c897c7 100644 --- a/public/pages/MonitorDetails/containers/MonitorDetails.js +++ b/public/pages/MonitorDetails/containers/MonitorDetails.js @@ -158,10 +158,18 @@ export default class MonitorDetails extends Component { notifications, } = this.props; const { monitor, ifSeqNo, ifPrimaryTerm } = this.state; + + let query = { ifSeqNo, ifPrimaryTerm }; + switch (monitor.monitor_type) { + case MONITOR_TYPE.DOC_LEVEL: + query = {}; + break; + } + this.setState({ updating: true }); return httpClient .put(`../api/alerting/monitors/${monitorId}`, { - query: { ifSeqNo, ifPrimaryTerm }, + query: { ...query }, body: JSON.stringify({ ...monitor, ...update }), }) .then((resp) => { diff --git a/public/utils/validate.js b/public/utils/validate.js index 6b03a0d09..6e7ee63fa 100644 --- a/public/utils/validate.js +++ b/public/utils/validate.js @@ -31,6 +31,9 @@ export const validateActionName = (monitor, trigger) => (value) => { case MONITOR_TYPE.BUCKET_LEVEL: actions = _.get(trigger, `${TRIGGER_TYPE.BUCKET_LEVEL}.actions`, []); break; + case MONITOR_TYPE.DOC_LEVEL: + actions = _.get(trigger, `${TRIGGER_TYPE.DOC_LEVEL}.actions`, []); + break; } const matches = actions.filter((action) => action.name === value); if (matches.length > 1) return 'Action name is already used.'; @@ -56,6 +59,26 @@ export const required = (value) => { if (!value) return 'Required.'; }; +export const validateIllegalCharacters = (illegalCharacters = ILLEGAL_CHARACTERS) => (value) => { + if (_.isEmpty(value)) return required(value); + + const illegalCharactersString = illegalCharacters.join(' '); + let errorText = `Contains invalid characters. Cannot contain: ${illegalCharactersString}`; + + if (_.includes(illegalCharacters, ' ')) { + errorText = + illegalCharacters.length === 1 + ? 'Cannot contain spaces.' + : `Contains invalid characters or spaces. Cannot contain: ${illegalCharactersString}`; + } + + let includesIllegalCharacter = false; + illegalCharacters.forEach((character) => { + if (_.includes(value, character)) includesIllegalCharacter = true; + }); + if (includesIllegalCharacter) return errorText; +}; + export const validateRequiredNumber = (value) => { if (value === undefined || typeof value === 'string') return 'Provide a value.'; }; diff --git a/release-notes/opensearch-alerting-dashboards-plugin.release-notes-2.0.0.0-rc1.md b/release-notes/opensearch-alerting-dashboards-plugin.release-notes-2.0.0.0-rc1.md new file mode 100644 index 000000000..2c0854774 --- /dev/null +++ b/release-notes/opensearch-alerting-dashboards-plugin.release-notes-2.0.0.0-rc1.md @@ -0,0 +1,29 @@ +## Version 2.0.0.0-rc1 2022-04-25 +Compatible with OpenSearch Dashboards 2.0.0-rc1 + +### Enhancements +* Implemented UX support for configuring doc level monitors. ([#218](https://github.com/opensearch-project/alerting-dashboards-plugin/pull/218)) +* Integrate Alerting Dashboards with Notifications Plugin ([#220](https://github.com/opensearch-project/alerting-dashboards-plugin/pull/220)) +* Added document column to alerts dashboard for doc level monitors. Adjusted alerts dashboard configuration to remove unused alert states for doc level monitors. Refactored style of alerts flyout based on UX feedback. ([#223](https://github.com/opensearch-project/alerting-dashboards-plugin/pull/223)) + +### Maintenance +* Bumped main branch version to 2.0 to align with OpenSearch-Dashboards. Added alpha1 qualifier to align with backend snapshot version. ([#202](https://github.com/opensearch-project/alerting-dashboards-plugin/pull/202)) +* [Build] bump plugin version to 2.0.0.0-rc1 ([#213](https://github.com/opensearch-project/alerting-dashboards-plugin/pull/213)) +* Incremented version to 2.0-rc1. ([#216](https://github.com/opensearch-project/alerting-dashboards-plugin/pull/216)) + +### Refactor +* Temporarily disabled destination use in some cypress tests to resolve flakiness. ([#214](https://github.com/opensearch-project/alerting-dashboards-plugin/pull/214)) +* Remove disabled buttons and update Destination flows to reflect read-only state ([#221](https://github.com/opensearch-project/alerting-dashboards-plugin/pull/221)) + +### Bug Fixes +* Fixed a bug that was causing the UX to reset visual editor trigger conditions to their default values when a trigger name contained periods. ([#204](https://github.com/opensearch-project/alerting-dashboards-plugin/pull/204)) +* Fixed a bug that was preventing the configured schedule from displaying when editing a monitor that was created through backend commands. ([#197](https://github.com/opensearch-project/alerting-dashboards-plugin/pull/197)) +* Fixed bugs associated with alerts table, and addressed UX review feedback. ([#222](https://github.com/opensearch-project/alerting-dashboards-plugin/pull/222)) +* Document level monitor UX bug fixes ([#226](https://github.com/opensearch-project/alerting-dashboards-plugin/pull/226)) + +### Infrastructure +* Removed the Beta label from the bug report template. ([#196](https://github.com/opensearch-project/alerting-dashboards-plugin/pull/196)) +* Updated issue templates from .github. ([#205](https://github.com/opensearch-project/alerting-dashboards-plugin/pull/205)) + +### Documentation +* Add release notes for version 2.0.0-rc1 ([#227](https://github.com/opensearch-project/alerting-dashboards-plugin/pull/227)) diff --git a/server/clusters/alerting/alertingPlugin.js b/server/clusters/alerting/alertingPlugin.js index 6a056fed4..8564d0020 100644 --- a/server/clusters/alerting/alertingPlugin.js +++ b/server/clusters/alerting/alertingPlugin.js @@ -59,22 +59,15 @@ export default function alertingPlugin(Client, config, components) { method: 'DELETE', }); + // TODO DRAFT: May need to add 'refresh' assignment here again. alerting.updateMonitor = ca({ url: { - fmt: `${MONITOR_BASE_API}/<%=monitorId%>?if_seq_no=<%=ifSeqNo%>&if_primary_term=<%=ifPrimaryTerm%>&refresh=wait_for`, + fmt: `${MONITOR_BASE_API}/<%=monitorId%>`, req: { monitorId: { type: 'string', required: true, }, - ifSeqNo: { - type: 'string', - required: true, - }, - ifPrimaryTerm: { - type: 'string', - required: true, - }, }, }, needBody: true, diff --git a/server/routes/monitors.js b/server/routes/monitors.js index 520c95c73..6cc4967c0 100644 --- a/server/routes/monitors.js +++ b/server/routes/monitors.js @@ -78,8 +78,8 @@ export default function (services, router) { id: schema.string(), }), query: schema.object({ - ifSeqNo: schema.number(), - ifPrimaryTerm: schema.number(), + ifSeqNo: schema.maybe(schema.number()), + ifPrimaryTerm: schema.maybe(schema.number()), }), body: schema.any(), }, diff --git a/server/services/MonitorService.js b/server/services/MonitorService.js index 6c0646e12..81d788520 100644 --- a/server/services/MonitorService.js +++ b/server/services/MonitorService.js @@ -127,8 +127,15 @@ export default class MonitorService { updateMonitor = async (context, req, res) => { try { const { id } = req.params; + const params = { monitorId: id, body: req.body, refresh: 'wait_for' }; + + // TODO DRAFT: Are we sure we need to include ifSeqNo and ifPrimaryTerm from the UI side when updating monitors? const { ifSeqNo, ifPrimaryTerm } = req.query; - const params = { monitorId: id, ifSeqNo, ifPrimaryTerm, body: req.body }; + if (ifSeqNo && ifPrimaryTerm) { + params.if_seq_no = ifSeqNo; + params.if_primary_term = ifPrimaryTerm; + } + const { callAsCurrentUser } = await this.esDriver.asScoped(req); const updateResponse = await callAsCurrentUser('alerting.updateMonitor', params); const { _version, _id } = updateResponse;