Skip to content

Commit

Permalink
Implemented a toast to display successful attempts to acknowledge ale…
Browse files Browse the repository at this point in the history
…rts. Refactored alerts dashboard flyout to refresh its alerts table when alerts are acknowledged. (opensearch-project#160)

* Implemented unit and integ tests for the alerts dashboard flyout. Refactored AlertsDashboardFlyoutComponent::getBucketLevelGraphConditions to return a string with line breaks instead of an array of HTML elements. Signed-off-by: AWSHurneyt <[email protected]>

Signed-off-by: AWSHurneyt <[email protected]>

* Removed an unused test variable.

Signed-off-by: AWSHurneyt <[email protected]>

* Removed debug logs.

Signed-off-by: AWSHurneyt <[email protected]>

* Implemented unit test. Refactored integration tests to use fewer wait periods.

Signed-off-by: AWSHurneyt <[email protected]>

* Examining flakiness in cypress test.

Signed-off-by: AWSHurneyt <[email protected]>

* Added short wait period to flyout cypress tests to alleviate flakiness.

Signed-off-by: AWSHurneyt <[email protected]>

* Refactored flyout cypress tests to use aliases.

Signed-off-by: AWSHurneyt <[email protected]>
  • Loading branch information
AWSHurneyt authored and Annie Lee committed Jan 27, 2022
1 parent 232e98f commit 5e357a5
Showing 1 changed file with 81 additions and 97 deletions.
178 changes: 81 additions & 97 deletions public/pages/Dashboard/containers/Dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,24 +32,31 @@ import ContentPanel from '../../../components/ContentPanel';
import DashboardEmptyPrompt from '../components/DashboardEmptyPrompt';
import DashboardControls from '../components/DashboardControls';
import { alertColumns, queryColumns } from '../utils/tableUtils';
import { MONITOR_TYPE, OPENSEARCH_DASHBOARDS_AD_PLUGIN } from '../../../utils/constants';
import {
ALERT_STATE,
MONITOR_TYPE,
OPENSEARCH_DASHBOARDS_AD_PLUGIN,
} from '../../../utils/constants';
import { backendErrorNotification } from '../../../utils/helpers';
import {
displayAcknowledgedAlertsToast,
filterActiveAlerts,
getInitialSize,
getQueryObjectFromState,
getURLQueryParams,
groupAlertsByTrigger,
insertGroupByColumn,
removeColumns,
} from '../utils/helpers';
import { DEFAULT_PAGE_SIZE_OPTIONS } from '../../Monitors/containers/Monitors/utils/constants';
import { MAX_ALERT_COUNT, DEFAULT_GET_ALERTS_QUERY_PARAMS } from '../utils/constants';
import { MAX_ALERT_COUNT } from '../utils/constants';

// TODO: Abstract out a Table component to be used in both Dashboard and Monitors

export default class Dashboard extends Component {
constructor(props) {
super(props);

const { flyoutAlerts, isAlertsFlyout = false, perAlertView } = props;
const { location, perAlertView } = props;

const {
alertState,
Expand All @@ -59,25 +66,25 @@ export default class Dashboard extends Component {
size,
sortDirection,
sortField,
} = this.getURLQueryParams();
} = getURLQueryParams(location);

this.state = {
alerts: [],
alertsByTriggers: [],
alertState,
flyoutIsOpen: false,
loadingMonitors: true,
monitors: [],
monitorIds: this.props.monitorIds,
page: Math.floor(from / size),
search,
selectedItems: [],
severityLevel,
size: getInitialSize(isAlertsFlyout, perAlertView, size),
size: getInitialSize(perAlertView, size),
sortDirection,
sortField,
totalAlerts: 0,
totalTriggers: 0,
trimmedFlyoutAlerts: flyoutAlerts ? flyoutAlerts.slice(0, 10) : [],
};
}

Expand Down Expand Up @@ -110,8 +117,8 @@ export default class Dashboard extends Component {
}

componentDidUpdate(prevProps, prevState) {
const prevQuery = this.getQueryObjectFromState(prevState);
const currQuery = this.getQueryObjectFromState(this.state);
const prevQuery = getQueryObjectFromState(prevState);
const currQuery = getQueryObjectFromState(this.state);
if (!_.isEqual(prevQuery, currQuery)) {
const {
page,
Expand All @@ -136,50 +143,6 @@ export default class Dashboard extends Component {
}
}

getQueryObjectFromState = ({
page,
size,
search,
sortField,
sortDirection,
severityLevel,
alertState,
monitorIds,
}) => ({
page,
size,
search,
sortField,
sortDirection,
severityLevel,
alertState,
monitorIds,
});

getURLQueryParams = () => {
const {
from = DEFAULT_GET_ALERTS_QUERY_PARAMS.from,
size = DEFAULT_GET_ALERTS_QUERY_PARAMS.size,
search = DEFAULT_GET_ALERTS_QUERY_PARAMS.search,
sortField = DEFAULT_GET_ALERTS_QUERY_PARAMS.sortField,
sortDirection = DEFAULT_GET_ALERTS_QUERY_PARAMS.sortDirection,
severityLevel = DEFAULT_GET_ALERTS_QUERY_PARAMS.severityLevel,
alertState = DEFAULT_GET_ALERTS_QUERY_PARAMS.alertState,
monitorIds = this.props.monitorIds,
} = queryString.parse(this.props.location.search);

return {
from: isNaN(parseInt(from, 10)) ? DEFAULT_GET_ALERTS_QUERY_PARAMS.from : parseInt(from, 10),
size: isNaN(parseInt(size, 10)) ? DEFAULT_GET_ALERTS_QUERY_PARAMS.size : parseInt(size, 10),
search,
sortField,
sortDirection,
severityLevel,
alertState,
monitorIds,
};
};

getAlerts = _.debounce(
(from, size, search, sortField, sortDirection, severityLevel, alertState, monitorIds) => {
const params = {
Expand Down Expand Up @@ -259,7 +222,8 @@ export default class Dashboard extends Component {

if (!selectedItems.length) return;

const selectedAlerts = perAlertView ? selectedItems : _.get(selectedItems, '0.alerts', []);
let selectedAlerts = perAlertView ? selectedItems : _.get(selectedItems, '0.alerts', []);
selectedAlerts = filterActiveAlerts(selectedAlerts);

const monitorAlerts = selectedAlerts.reduce((monitorAlerts, alert) => {
const { id, monitor_id: monitorId } = alert;
Expand All @@ -268,22 +232,22 @@ export default class Dashboard extends Component {
return monitorAlerts;
}, {});

const promises = Object.entries(monitorAlerts).map(([monitorId, alerts]) =>
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)
);

const values = await Promise.all(promises);
console.log('values:', values);
// // TODO: Show which values failed, succeeded, etc.
const {
page,
size,
Expand All @@ -308,23 +272,9 @@ export default class Dashboard extends Component {
};

onTableChange = ({ page: tablePage = {}, sort = {} }) => {
const { isAlertsFlyout } = this.props;
const { index: page, size } = tablePage;

const { field: sortField, direction: sortDirection } = sort;
this.setState({
page,
size,
sortField,
sortDirection,
});

// If the table is in flyout, return the trimmed array of alerts.
if (isAlertsFlyout) {
const { flyoutAlerts } = this.props;
const trimmedFlyoutAlerts = flyoutAlerts.slice(page * size, page * size + size);
this.setState({ trimmedFlyoutAlerts });
}
this.setState({ page, size, sortField, sortDirection });
};

onSeverityLevelChange = (e) => {
Expand All @@ -347,6 +297,42 @@ export default class Dashboard extends Component {
this.setState({ page });
};

openFlyout = (payload) => {
this.setState({ ...this.state, flyoutIsOpen: true });
this.props.setFlyout({
type: 'alertsDashboard',
payload: { ...payload },
});
};

closeFlyout = () => {
this.props.setFlyout(null);
this.setState({ ...this.state, flyoutIsOpen: false });
};

refreshDashboard = () => {
const {
page,
size,
search,
sortField,
sortDirection,
severityLevel,
alertState,
monitorIds,
} = this.state;
this.getAlerts(
page * size,
size,
search,
sortField,
sortDirection,
severityLevel,
alertState,
monitorIds
);
};

render() {
const {
alerts,
Expand All @@ -363,7 +349,6 @@ export default class Dashboard extends Component {
sortField,
totalAlerts,
totalTriggers,
trimmedFlyoutAlerts,
} = this.state;
const {
monitorIds,
Expand Down Expand Up @@ -393,14 +378,12 @@ export default class Dashboard extends Component {
location,
monitors,
notifications,
setFlyout
setFlyout,
this.openFlyout,
this.closeFlyout,
this.refreshDashboard
);

if (isAlertsFlyout) {
totalItems = this.props.flyoutAlerts.length;
columnType = removeColumns(['severity', 'trigger_name'], columnType);
}

const pagination = {
pageIndex: page,
pageSize: size,
Expand All @@ -417,11 +400,13 @@ export default class Dashboard extends Component {

const selection = {
onSelectionChange: this.onSelectionChange,
selectable: perAlertView ? (item) => item.state === 'ACTIVE' : (item) => item.ACTIVE > 0,
selectable: perAlertView
? (item) => item.state === ALERT_STATE.ACTIVE
: (item) => item.ACTIVE > 0,
selectableMessage: perAlertView
? (selectable) => (selectable ? undefined : 'Only Active Alerts are Acknowledgeable')
? (selectable) => (selectable ? undefined : 'Only active alerts can be acknowledged.')
: (selectable) =>
selectable ? undefined : 'Only Triggers with Active Alerts are Acknowledgeable',
selectable ? undefined : 'Only triggers with active alerts can be acknowledged.',
};

const actions = () => {
Expand All @@ -430,7 +415,7 @@ export default class Dashboard extends Component {
<EuiButton
onClick={this.acknowledgeAlert}
disabled={perAlertView ? !selectedItems.length : selectedItems.length !== 1}
data-test-subj="acknowledgeButton"
data-test-subj={'acknowledgeAlertsButton'}
>
Acknowledge
</EuiButton>,
Expand All @@ -441,18 +426,17 @@ export default class Dashboard extends Component {
actions.unshift(
<EuiButton
onClick={() => {
setFlyout({
type: 'alertsDashboard',
payload: {
...alert,
history,
httpClient,
loadingMonitors,
location,
monitors,
notifications,
setFlyout,
},
this.openFlyout({
...alert,
history,
httpClient,
loadingMonitors,
location,
monitors,
notifications,
setFlyout,
closeFlyout: this.closeFlyout,
refreshDashboard: this.refreshDashboard,
});
}}
disabled={selectedItems.length !== 1}
Expand Down Expand Up @@ -503,7 +487,7 @@ export default class Dashboard extends Component {
<EuiHorizontalRule margin="xs" />

<EuiBasicTable
items={perAlertView ? (isAlertsFlyout ? trimmedFlyoutAlerts : alerts) : alertsByTriggers}
items={perAlertView ? alerts : alertsByTriggers}
/*
* If using just ID, doesn't update selectedItems when doing acknowledge
* because the next getAlerts have the same id
Expand Down

0 comments on commit 5e357a5

Please sign in to comment.