Skip to content

Commit

Permalink
[Metrics UI] Add full custom metric UI to inventory alerts (#81929)
Browse files Browse the repository at this point in the history
Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
Zacqary and kibanamachine authored Nov 5, 2020
1 parent 074ef6f commit 250fe67
Show file tree
Hide file tree
Showing 4 changed files with 282 additions and 94 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { AlertsContextValue } from '../../../../../triggers_actions_ui/public/ap
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { InventoryMetricConditions } from '../../../../server/lib/alerting/inventory_metric_threshold/types';
import React from 'react';
import { Expressions, AlertContextMeta, ExpressionRow } from './expression';
import { Expressions, AlertContextMeta, ExpressionRow, defaultExpression } from './expression';
import { act } from 'react-dom/test-utils';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { Comparator } from '../../../../server/lib/alerting/metric_threshold/types';
Expand Down Expand Up @@ -105,6 +105,7 @@ describe('Expression', () => {
threshold: [],
timeSize: 1,
timeUnit: 'm',
customMetric: defaultExpression.customMetric,
},
]);
});
Expand Down Expand Up @@ -155,6 +156,7 @@ describe('ExpressionRow', () => {
alertsContextMetadata={{
customMetrics: [],
}}
fields={[{ name: 'some.system.field', type: 'bzzz' }]}
/>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { set } from '@elastic/safer-lodash-set';
import { debounce, pick, uniqBy, isEqual } from 'lodash';
import { debounce, pick } from 'lodash';
import { Unit } from '@elastic/datemath';
import React, { useCallback, useMemo, useEffect, useState, ChangeEvent } from 'react';
import { IFieldType } from 'src/plugins/data/public';
import {
EuiFlexGroup,
EuiFlexItem,
Expand All @@ -23,7 +23,6 @@ import {
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { getCustomMetricLabel } from '../../../../common/formatters/get_custom_metric_label';
import { toMetricOpt } from '../../../../common/snapshot_metric_i18n';
import { AlertPreview } from '../../common';
import { METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID } from '../../../../common/alerting/metrics';
Expand Down Expand Up @@ -95,13 +94,18 @@ interface Props {
setAlertProperty(key: string, value: any): void;
}

const defaultExpression = {
export const defaultExpression = {
metric: 'cpu' as SnapshotMetricType,
comparator: Comparator.GT,
threshold: [],
timeSize: 1,
timeUnit: 'm',
customMetric: undefined,
customMetric: {
type: 'custom',
id: 'alert-custom-metric',
field: '',
aggregation: 'avg',
},
} as InventoryMetricConditions;

export const Expressions: React.FC<Props> = (props) => {
Expand Down Expand Up @@ -226,7 +230,7 @@ export const Expressions: React.FC<Props> = (props) => {
metric: md.options.metric!.type,
customMetric: SnapshotCustomMetricInputRT.is(md.options.metric)
? md.options.metric
: undefined,
: defaultExpression.customMetric,
} as InventoryMetricConditions,
]);
} else {
Expand Down Expand Up @@ -306,6 +310,7 @@ export const Expressions: React.FC<Props> = (props) => {
errors={errors[idx] || emptyError}
expression={e || {}}
alertsContextMetadata={alertsContext.metadata}
fields={derivedIndexPattern.fields}
/>
);
})}
Expand Down Expand Up @@ -415,6 +420,7 @@ interface ExpressionRowProps {
remove(id: number): void;
setAlertParams(id: number, params: Partial<InventoryMetricConditions>): void;
alertsContextMetadata: AlertsContextValue<AlertContextMeta>['metadata'];
fields: IFieldType[];
}

const StyledExpressionRow = euiStyled(EuiFlexGroup)`
Expand All @@ -428,48 +434,25 @@ const StyledExpression = euiStyled.div`
`;

export const ExpressionRow: React.FC<ExpressionRowProps> = (props) => {
const {
setAlertParams,
expression,
errors,
expressionId,
remove,
canDelete,
alertsContextMetadata,
} = props;
const { setAlertParams, expression, errors, expressionId, remove, canDelete, fields } = props;
const { metric, comparator = Comparator.GT, threshold = [], customMetric } = expression;
const [customMetrics, updateCustomMetrics] = useState<SnapshotCustomMetricInput[]>([]);

// Create and uniquify a list of custom metrics including:
// - The alert metadata context (which only gives us custom metrics on the inventory page)
// - The custom metric stored in the expression (necessary when editing this alert without having
// access to the metadata context)
// - Whatever custom metrics were previously stored in this list (to preserve the custom metric in the dropdown
// if the user edits the alert and switches away from the custom metric)
useEffect(() => {
const ctxCustomMetrics = alertsContextMetadata?.customMetrics ?? [];
const expressionCustomMetrics = customMetric ? [customMetric] : [];
const newCustomMetrics = uniqBy(
[...customMetrics, ...ctxCustomMetrics, ...expressionCustomMetrics],
(cm: SnapshotCustomMetricInput) => cm.id
);
if (!isEqual(customMetrics, newCustomMetrics)) updateCustomMetrics(newCustomMetrics);
}, [alertsContextMetadata, customMetric, customMetrics, updateCustomMetrics]);

const updateMetric = useCallback(
(m?: SnapshotMetricType | string) => {
const newMetric = SnapshotMetricTypeRT.is(m) ? m : 'custom';
const newMetric = SnapshotMetricTypeRT.is(m) ? m : Boolean(m) ? 'custom' : undefined;
const newAlertParams = { ...expression, metric: newMetric };
if (newMetric === 'custom' && customMetrics) {
set(
newAlertParams,
'customMetric',
customMetrics.find((cm) => cm.id === m)
);
}
setAlertParams(expressionId, newAlertParams);
},
[expressionId, expression, setAlertParams, customMetrics]
[expressionId, expression, setAlertParams]
);

const updateCustomMetric = useCallback(
(cm?: SnapshotCustomMetricInput) => {
if (SnapshotCustomMetricInputRT.is(cm)) {
setAlertParams(expressionId, { ...expression, customMetric: cm });
}
},
[expressionId, expression, setAlertParams]
);

const updateComparator = useCallback(
Expand Down Expand Up @@ -515,17 +498,8 @@ export const ExpressionRow: React.FC<ExpressionRowProps> = (props) => {
myMetrics = containerMetricTypes;
break;
}
const baseMetricOpts = myMetrics.map(toMetricOpt);
const customMetricOpts = customMetrics
? customMetrics.map((m, i) => ({
text: getCustomMetricLabel(m),
value: m.id,
}))
: [];
return [...baseMetricOpts, ...customMetricOpts];
}, [props.nodeType, customMetrics]);

const selectedMetricValue = metric === 'custom' && customMetric ? customMetric.id : metric!;
return myMetrics.map(toMetricOpt);
}, [props.nodeType]);

return (
<>
Expand All @@ -535,8 +509,8 @@ export const ExpressionRow: React.FC<ExpressionRowProps> = (props) => {
<StyledExpression>
<MetricExpression
metric={{
value: selectedMetricValue,
text: ofFields.find((v) => v?.value === selectedMetricValue)?.text || '',
value: metric!,
text: ofFields.find((v) => v?.value === metric)?.text || '',
}}
metrics={
ofFields.filter((m) => m !== undefined && m.value !== undefined) as Array<{
Expand All @@ -545,7 +519,10 @@ export const ExpressionRow: React.FC<ExpressionRowProps> = (props) => {
}>
}
onChange={updateMetric}
onChangeCustom={updateCustomMetric}
errors={errors}
customMetric={customMetric}
fields={fields}
/>
</StyledExpression>
<StyledExpression>
Expand Down
Loading

0 comments on commit 250fe67

Please sign in to comment.