Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Backport 2.17] Register alerts card with analytics workspace use case #1070

Merged
merged 1 commit into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cypress/integration/composite_level_monitor_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ describe('CompositeLevelMonitor', () => {
.type('{backspace}')
.type('Composite trigger');

cy.intercept('api/alerting/workflows?*').as('createMonitorRequest');
cy.intercept('api/alerting/workflows*').as('createMonitorRequest');
cy.intercept(`api/alerting/monitors?*`).as('getMonitorsRequest');
cy.get('button').contains('Create').click({ force: true });

Expand Down
3 changes: 2 additions & 1 deletion opensearch_dashboards.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"expressions",
"data",
"visAugmenter",
"opensearchDashboardsUtils"
"opensearchDashboardsUtils",
"contentManagement"
],
"server": true,
"ui": true,
Expand Down
144 changes: 144 additions & 0 deletions public/components/DataSourceAlertsCard/DataSourceAlertsCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import React, { useCallback, useEffect, useState } from "react";
import { EuiBadge, EuiDescriptionList, EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiLink, EuiLoadingContent, EuiPanel, EuiSmallButtonEmpty, EuiText, EuiTitle } from "@elastic/eui";
import { DataSourceManagementPluginSetup, DataSourceOption } from "../../../../../src/plugins/data_source_management/public";
import { getApplication, getClient, getNotifications, getSavedObjectsClient } from "../../services";
import { dataSourceFilterFn, getSeverityColor, getSeverityBadgeText, getTruncatedText } from "../../utils/helpers";
import { renderTime } from "../../pages/Dashboard/utils/tableUtils";
import { ALERTS_NAV_ID } from "../../../utils/constants";
import { DEFAULT_EMPTY_DATA } from "../../utils/constants";

export interface DataSourceAlertsCardProps {
getDataSourceMenu: DataSourceManagementPluginSetup['ui']['getDataSourceMenu'];
}

export const DataSourceAlertsCard: React.FC<DataSourceAlertsCardProps> = ({ getDataSourceMenu }) => {
const DataSourceSelector = getDataSourceMenu();
const [loading, setLoading] = useState(false);
const [dataSource, setDataSource] = useState<DataSourceOption>({
label: 'Local cluster',
id: '',
});
const [alerts, setAlerts] = useState<any[]>([]);

useEffect(() => {
setLoading(true);
getClient().get('../api/alerting/alerts', {
query: {
size: 25,
sortField: 'start_time',
dataSourceId: dataSource?.id || '',
sortDirection: 'desc'
}
}).then(res => {
if (res.ok) {
setAlerts(res.alerts);
}
setLoading(false);
}).catch(() => {
setLoading(false);
})
}, [dataSource]);

const onDataSourceSelected = useCallback((options: any[]) => {
if (dataSource?.id !== undefined && dataSource?.id !== options[0]?.id) {
setDataSource(options[0]);
}
}, [dataSource]);

const createAlertDetailsHeader = useCallback((alert) => {
const severityColor = getSeverityColor(alert.severity);
const triggerName = alert.trigger_name ?? DEFAULT_EMPTY_DATA;

return (
<EuiFlexGroup gutterSize="s" justifyContent="spaceBetween" alignItems="center">
<EuiFlexItem grow={false}>
<div>
<EuiBadge color={severityColor?.background} style={{ padding: '1px 4px', color: severityColor?.text }}>{getSeverityBadgeText(alert.severity)}</EuiBadge>
&nbsp;&nbsp;
<span style={{ color: "#006BB4" }} className="eui-textTruncate">{getTruncatedText(triggerName)}</span>
</div>
</EuiFlexItem>
<EuiFlexItem grow={false} >
<EuiText color="subdued" size="s">{renderTime(alert.start_time, { showFromNow: true })}</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
)
}, []);

const createAlertDetailsDescription = useCallback((alert) => {
const monitorName = alert.monitor_name ?? DEFAULT_EMPTY_DATA;

return (
<>
<EuiFlexGroup gutterSize="s" justifyContent="flexStart" alignItems="center">
<EuiFlexItem grow={false}>
<EuiText size="s" color="subdued">Monitor:</EuiText>
</EuiFlexItem>
<EuiFlexItem grow={false} >
<EuiText size="m">{getTruncatedText(monitorName)}</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
<EuiHorizontalRule margin="xs" />
</>
)
}, []);

const alertsListItems = alerts.map((alert) => {
return {
title: createAlertDetailsHeader(alert),
description: createAlertDetailsDescription(alert)
}
});

return (
<EuiPanel hasBorder={false} hasShadow={false}>
<EuiFlexGroup style={{ height: '100%' }} direction="column" justifyContent="spaceBetween" alignItems="flexStart" gutterSize="xs">
<EuiFlexItem grow={false} style={{ width: '100%', height: '90%' }}>
<EuiFlexGroup direction="column" style={{ height: '100%' }}>
<EuiFlexItem grow={false}>
<EuiFlexGroup gutterSize="s" justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<EuiTitle size="s">
<h3>
Recent alerts
</h3>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<DataSourceSelector
componentType={"DataSourceSelectable"}
componentConfig={{
savedObjects: getSavedObjectsClient(),
notifications: getNotifications(),
onSelectedDataSources: onDataSourceSelected,
fullWidth: false,
dataSourceFilter: dataSourceFilterFn,
activeOption: dataSource ? [{ id: dataSource.id }] : undefined
}}
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem style={{ overflow: 'scroll' }}>
{loading ? (
<EuiLoadingContent />
) : (
<EuiDescriptionList
listItems={alertsListItems}
/>
)}
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiLink href={getApplication().getUrlForApp(ALERTS_NAV_ID, { path: '#/dasboard' })} target="_blank"><EuiText size="s" className="eui-displayInline">View all</EuiText></EuiLink>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
)
};
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ import { queryColumns } from '../../../../pages/Dashboard/utils/tableUtils';
import { DEFAULT_PAGE_SIZE_OPTIONS } from '../../../../pages/Monitors/containers/Monitors/utils/constants';
import queryString from 'query-string';
import { MAX_ALERT_COUNT } from '../../../../pages/Dashboard/utils/constants';
import { SEVERITY_OPTIONS } from '../../../../pages/CreateTrigger/utils/constants';
import {
getAlertsFindingColumn,
TABLE_TAB_IDS,
Expand All @@ -62,6 +61,7 @@ import {
getDataSourceId,
getIsCommentsEnabled,
} from '../../../../pages/utils/helpers';
import { getSeverityText } from '../../../../utils/helpers';

export const DEFAULT_NUM_FLYOUT_ROWS = 10;

Expand Down Expand Up @@ -172,10 +172,6 @@ export default class AlertsDashboardFlyoutComponent extends Component {
});
};

getSeverityText = (severity) => {
return _.get(_.find(SEVERITY_OPTIONS, { value: severity }), 'text');
};

getBucketLevelGraphFilter = (trigger) => {
const compositeAggFilter = _.get(trigger, 'condition.composite_agg_filter');
if (_.isEmpty(compositeAggFilter)) return DEFAULT_WHERE_EXPRESSION_TEXT;
Expand Down Expand Up @@ -601,7 +597,7 @@ export default class AlertsDashboardFlyoutComponent extends Component {
<EuiFlexItem>
<EuiText size="s" data-test-subj={`alertsDashboardFlyout_severity_${trigger_name}`}>
<strong>Severity</strong>
<p>{this.getSeverityText(severity) || severity || DEFAULT_EMPTY_DATA}</p>
<p>{getSeverityText(severity) || severity || DEFAULT_EMPTY_DATA}</p>
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { EuiAccordion, EuiButton, EuiSpacer, EuiText, EuiTitle } from '@elastic/
import 'brace/mode/plain_text';
import { FormikFieldText, FormikSelect } from '../../../../components/FormControls';
import { hasError, isInvalid } from '../../../../utils/validate';
import { SEARCH_TYPE } from '../../../../utils/constants';
import { SEARCH_TYPE, SEVERITY_OPTIONS } from '../../../../utils/constants';
import { FORMIK_INITIAL_TRIGGER_CONDITION_VALUES } from '../CreateTrigger/utils/constants';
import AddTriggerConditionButton from '../../components/AddTriggerConditionButton';
import BucketLevelTriggerGraph from '../../components/BucketLevelTriggerGraph';
Expand All @@ -20,7 +20,7 @@ import WhereExpression from '../../../CreateMonitor/components/MonitorExpression
import { FieldArray } from 'formik';
import ConfigureActions from '../ConfigureActions';
import { inputLimitText } from '../../../../utils/helpers';
import { DEFAULT_TRIGGER_NAME, SEVERITY_OPTIONS } from '../../utils/constants';
import { DEFAULT_TRIGGER_NAME } from '../../utils/constants';
import { getTriggerContext } from '../../utils/helper';

const defaultRowProps = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ import PropTypes from 'prop-types';
import _ from 'lodash';
import { EuiSpacer, EuiTitle, EuiAccordion, EuiButton } from '@elastic/eui';
import { FormikFieldText, FormikSelect } from '../../../../components/FormControls';
import { hasError, isInvalid, required } from '../../../../utils/validate';
import { DEFAULT_TRIGGER_NAME, SEVERITY_OPTIONS } from '../../utils/constants';
import { hasError, isInvalid } from '../../../../utils/validate';
import { DEFAULT_TRIGGER_NAME } from '../../utils/constants';
import CompositeTriggerCondition from '../../components/CompositeTriggerCondition/CompositeTriggerCondition';
import TriggerNotifications from './TriggerNotifications';
import { FORMIK_COMPOSITE_INITIAL_TRIGGER_VALUES } from '../CreateTrigger/utils/constants';
import { titleTemplate } from '../../../../utils/helpers';
import { SEVERITY_OPTIONS } from '../../../../utils/constants';

const defaultRowProps = {
label: titleTemplate('Trigger name'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,26 +241,36 @@ exports[`DefineCompositeLevelTrigger renders 1`] = `
name="triggerDefinitions[undefined].severity"
>
<option
badgetext="Highest"
color="[object Object]"
value="1"
>
1 (Highest)
</option>
<option
badgetext="High"
color="[object Object]"
value="2"
>
2 (High)
</option>
<option
badgetext="Medium"
color="[object Object]"
value="3"
>
3 (Medium)
</option>
<option
badgetext="Low"
color="[object Object]"
value="4"
>
4 (Low)
</option>
<option
badgetext="Lowest"
color="[object Object]"
value="5"
>
5 (Lowest)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import {
} from '@elastic/eui';
import { FormikFieldText, FormikSelect } from '../../../../components/FormControls';
import { hasError, isInvalid } from '../../../../utils/validate';
import { SEARCH_TYPE } from '../../../../utils/constants';
import { DEFAULT_TRIGGER_NAME, SEVERITY_OPTIONS } from '../../utils/constants';
import { SEARCH_TYPE, SEVERITY_OPTIONS } from '../../../../utils/constants';
import { DEFAULT_TRIGGER_NAME } from '../../utils/constants';
import { validateTriggerName } from '../DefineTrigger/utils/validation';
import ConfigureActions from '../ConfigureActions';
import TriggerQuery from '../../components/TriggerQuery';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { isInvalid, hasError } from '../../../../utils/validate';
import TriggerQuery from '../../components/TriggerQuery';
import TriggerGraph from '../../components/TriggerGraph';
import { validateTriggerName } from './utils/validation';
import { OS_NOTIFICATION_PLUGIN, SEARCH_TYPE } from '../../../../utils/constants';
import { OS_NOTIFICATION_PLUGIN, SEARCH_TYPE, SEVERITY_OPTIONS } from '../../../../utils/constants';
import { AnomalyDetectorTrigger } from './AnomalyDetectorTrigger';
import { TRIGGER_TYPE } from '../CreateTrigger/utils/constants';
import { FieldArray } from 'formik';
Expand All @@ -34,7 +34,7 @@ import {
buildClusterMetricsRequest,
canExecuteClusterMetricsMonitor,
} from '../../../CreateMonitor/components/ClusterMetricsMonitor/utils/clusterMetricsMonitorHelpers';
import { DEFAULT_TRIGGER_NAME, SEVERITY_OPTIONS } from '../../utils/constants';
import { DEFAULT_TRIGGER_NAME } from '../../utils/constants';
import MinimalAccordion from '../../../../components/FeatureAnywhereContextMenu/MinimalAccordion';
import { getTriggerContext } from '../../utils/helper';
import { getDataSourceQueryObj } from '../../../utils/helpers';
Expand Down
8 changes: 0 additions & 8 deletions public/pages/CreateTrigger/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,6 @@ export const FORMIK_INITIAL_ACTION_VALUES = {
},
};

export const SEVERITY_OPTIONS = [
{ value: '1', text: '1 (Highest)' },
{ value: '2', text: '2 (High)' },
{ value: '3', text: '3 (Medium)' },
{ value: '4', text: '4 (Low)' },
{ value: '5', text: '5 (Lowest)' },
];

export const THRESHOLD_ENUM_OPTIONS = [
{ value: 'ABOVE', text: 'IS ABOVE' },
{ value: 'BELOW', text: 'IS BELOW' },
Expand Down
Loading
Loading