mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 01:13:23 -04:00
[ML] Explain log rate spikes: Fix brush issues. (#138113)
- Fixes overlapping brush badges. - Adds missing tooltips to brush badges.
This commit is contained in:
parent
fb3e7185df
commit
9512635a7d
3 changed files with 116 additions and 38 deletions
|
@ -100,10 +100,10 @@ export function DualBrush({
|
|||
const xMax = x(max) ?? 0;
|
||||
const minExtentPx = Math.round((xMax - xMin) / 100);
|
||||
|
||||
const baselineBrush = d3.select('#brush-baseline');
|
||||
const baselineBrush = d3.select('#aiops-brush-baseline');
|
||||
const baselineSelection = d3.brushSelection(baselineBrush.node() as SVGGElement);
|
||||
|
||||
const deviationBrush = d3.select('#brush-deviation');
|
||||
const deviationBrush = d3.select('#aiops-brush-deviation');
|
||||
const deviationSelection = d3.brushSelection(deviationBrush.node() as SVGGElement);
|
||||
|
||||
if (!isBrushXSelection(deviationSelection) || !isBrushXSelection(baselineSelection)) {
|
||||
|
@ -221,7 +221,7 @@ export function DualBrush({
|
|||
.insert('g', '.brush')
|
||||
.attr('class', 'brush')
|
||||
.attr('id', (b: DualBrush) => {
|
||||
return 'brush-' + b.id;
|
||||
return 'aiops-brush-' + b.id;
|
||||
})
|
||||
.each((brushObject: DualBrush, i, n) => {
|
||||
const x = d3.scaleLinear().domain([min, max]).rangeRound([0, widthRef.current]);
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { FC } from 'react';
|
||||
|
||||
import { EuiBadge, EuiText, EuiToolTip } from '@elastic/eui';
|
||||
// @ts-ignore
|
||||
import { formatDate } from '@elastic/eui/lib/services/format';
|
||||
|
||||
const DATE_FORMAT = 'YYYY-MM-DD';
|
||||
const TIME_FORMAT = 'HH:mm:ss';
|
||||
|
||||
interface BrushBadgeProps {
|
||||
label: string;
|
||||
marginLeft: number;
|
||||
timestampFrom: number;
|
||||
timestampTo: number;
|
||||
width: number;
|
||||
}
|
||||
|
||||
export const BrushBadge: FC<BrushBadgeProps> = ({
|
||||
label,
|
||||
marginLeft,
|
||||
timestampFrom,
|
||||
timestampTo,
|
||||
width,
|
||||
}) => {
|
||||
// If "from" and "to" are on the same day, we skip displaying the date twice.
|
||||
const dateFrom = formatDate(timestampFrom, DATE_FORMAT);
|
||||
const dateTo = formatDate(timestampTo, DATE_FORMAT);
|
||||
const timeFrom = formatDate(timestampFrom, TIME_FORMAT);
|
||||
const timeTo = formatDate(timestampTo, TIME_FORMAT);
|
||||
|
||||
return (
|
||||
<div
|
||||
css={{
|
||||
position: 'absolute',
|
||||
'margin-left': `${marginLeft}px`,
|
||||
}}
|
||||
>
|
||||
<EuiToolTip
|
||||
content={
|
||||
<EuiText size="xs">
|
||||
{dateFrom} {timeFrom} -{' '}
|
||||
{dateFrom !== dateTo && (
|
||||
<>
|
||||
<br />
|
||||
{dateTo}{' '}
|
||||
</>
|
||||
)}
|
||||
{timeTo}
|
||||
</EuiText>
|
||||
}
|
||||
position="top"
|
||||
>
|
||||
<EuiBadge css={{ width, 'text-align': 'center' }}>{label}</EuiBadge>
|
||||
</EuiToolTip>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -20,10 +20,8 @@ import {
|
|||
XYChartElementEvent,
|
||||
XYBrushEvent,
|
||||
} from '@elastic/charts';
|
||||
import { EuiBadge } from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { IUiSettingsClient } from '@kbn/core/public';
|
||||
import { DualBrush, DualBrushAnnotation } from '@kbn/aiops-components';
|
||||
import { getSnappedWindowParameters, getWindowParameters } from '@kbn/aiops-utils';
|
||||
|
@ -33,6 +31,8 @@ import type { ChangePoint } from '@kbn/ml-agg-utils';
|
|||
|
||||
import { useAiOpsKibana } from '../../../kibana_context';
|
||||
|
||||
import { BrushBadge } from './brush_badge';
|
||||
|
||||
export interface DocumentCountChartPoint {
|
||||
time: number | string;
|
||||
value: number;
|
||||
|
@ -52,6 +52,9 @@ interface DocumentCountChartProps {
|
|||
|
||||
const SPEC_ID = 'document_count';
|
||||
|
||||
const BADGE_HEIGHT = 20;
|
||||
const BADGE_WIDTH = 75;
|
||||
|
||||
enum VIEW_MODE {
|
||||
ZOOM = 'zoom',
|
||||
BRUSH = 'brush',
|
||||
|
@ -67,6 +70,19 @@ function getTimezone(uiSettings: IUiSettingsClient) {
|
|||
}
|
||||
}
|
||||
|
||||
function getBaselineBadgeOverflow(
|
||||
windowParametersAsPixels: WindowParameters,
|
||||
baselineBadgeWidth: number
|
||||
) {
|
||||
const { baselineMin, baselineMax, deviationMin } = windowParametersAsPixels;
|
||||
|
||||
const baselineBrushWidth = baselineMax - baselineMin;
|
||||
const baselineBadgeActualMax = baselineMin + baselineBadgeWidth;
|
||||
return deviationMin < baselineBadgeActualMax
|
||||
? Math.max(0, baselineBadgeWidth - baselineBrushWidth)
|
||||
: 0;
|
||||
}
|
||||
|
||||
export const DocumentCountChart: FC<DocumentCountChartProps> = ({
|
||||
brushSelectionUpdateHandler,
|
||||
width,
|
||||
|
@ -239,47 +255,45 @@ export const DocumentCountChart: FC<DocumentCountChartProps> = ({
|
|||
}, [viewMode]);
|
||||
|
||||
const isBrushVisible =
|
||||
originalWindowParameters && mlBrushMarginLeft && mlBrushWidth && mlBrushWidth > 0;
|
||||
originalWindowParameters &&
|
||||
windowParameters &&
|
||||
mlBrushMarginLeft &&
|
||||
mlBrushWidth &&
|
||||
mlBrushWidth > 0;
|
||||
|
||||
// Avoid overlap of brush badges when the brushes are quite narrow.
|
||||
const baselineBadgeOverflow = windowParametersAsPixels
|
||||
? getBaselineBadgeOverflow(windowParametersAsPixels, BADGE_WIDTH)
|
||||
: 0;
|
||||
const baselineBadgeMarginLeft =
|
||||
(mlBrushMarginLeft ?? 0) + (windowParametersAsPixels?.baselineMin ?? 0);
|
||||
|
||||
return (
|
||||
<>
|
||||
{isBrushVisible && (
|
||||
<div className="aiopsHistogramBrushes">
|
||||
<div
|
||||
css={{
|
||||
position: 'absolute',
|
||||
'margin-left': `${
|
||||
mlBrushMarginLeft + (windowParametersAsPixels?.baselineMin ?? 0)
|
||||
}px`,
|
||||
}}
|
||||
>
|
||||
<EuiBadge>
|
||||
<FormattedMessage
|
||||
id="xpack.aiops.documentCountChart.baselineBadgeContent"
|
||||
defaultMessage="Baseline"
|
||||
/>
|
||||
</EuiBadge>
|
||||
<div css={{ height: BADGE_HEIGHT }}>
|
||||
<BrushBadge
|
||||
label={i18n.translate('xpack.aiops.documentCountChart.baselineBadgeLabel', {
|
||||
defaultMessage: 'Baseline',
|
||||
})}
|
||||
marginLeft={baselineBadgeMarginLeft - baselineBadgeOverflow}
|
||||
timestampFrom={windowParameters.baselineMin}
|
||||
timestampTo={windowParameters.baselineMax}
|
||||
width={BADGE_WIDTH}
|
||||
/>
|
||||
<BrushBadge
|
||||
label={i18n.translate('xpack.aiops.documentCountChart.deviationBadgeLabel', {
|
||||
defaultMessage: 'Deviation',
|
||||
})}
|
||||
marginLeft={mlBrushMarginLeft + (windowParametersAsPixels?.deviationMin ?? 0)}
|
||||
timestampFrom={windowParameters.deviationMin}
|
||||
timestampTo={windowParameters.deviationMax}
|
||||
width={BADGE_WIDTH}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
css={{
|
||||
position: 'absolute',
|
||||
'margin-left': `${
|
||||
mlBrushMarginLeft + (windowParametersAsPixels?.deviationMin ?? 0)
|
||||
}px`,
|
||||
}}
|
||||
>
|
||||
<EuiBadge>
|
||||
<FormattedMessage
|
||||
id="xpack.aiops.documentCountChart.deviationBadgeContent"
|
||||
defaultMessage="Deviation"
|
||||
/>
|
||||
</EuiBadge>
|
||||
</div>
|
||||
<div
|
||||
css={{
|
||||
position: 'relative',
|
||||
clear: 'both',
|
||||
'padding-top': '20px',
|
||||
'margin-bottom': '-4px',
|
||||
}}
|
||||
>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue