Skip to content

Commit

Permalink
fix: [Obs AI Ops > Anomaly Detection][KEYBOARD]: Anomalies table rows…
Browse files Browse the repository at this point in the history
… have a number of tooltips that cannot receive keyboard focus (#183807)

Closes: elastic/observability-dev#3398

## Description

The Obs Anomaly Detection Single Metric Viewer has an Anomalies table
with at least three tooltips that cannot be reached by keyboard focus.
Screenshot attached below.

### Steps to recreate
1. Open the [Obs Anomaly
Detection](https://issue-serverless-alpbx-pr180406-c06b1b.kb.eu-west-1.aws.qa.elastic.cloud/app/ml/jobs)
view
2. Create a new anomaly detection job
3. From the Anomaly Detection Jobs table, click the Single Metric Viewer
icon
4. Tab through the page, to the Anomalies table underneath the chart
5. Expand a row in the table using the arrow icon at the beginning of a
row
6. Keep tabbing, and verify the tooltips in the expanded row never
receive focus or become visible

### What was changed: 
1. `EuiToolTip` was replaced to `EuiIconTip`
  • Loading branch information
alexwizp authored May 22, 2024
1 parent 51f9eed commit f023c2c
Showing 1 changed file with 168 additions and 142 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@ import React from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import {
EuiToolTip,
EuiIcon,
EuiFlexGroup,
EuiFlexItem,
useEuiTheme,
EuiText,
EuiSpacer,
EuiLink,
EuiIconTip,
} from '@elastic/eui';
import {
getAnomalyScoreExplanationImpactValue,
Expand Down Expand Up @@ -231,43 +230,49 @@ export const DetailsItems: FC<{

items.push({
title: (
<EuiToolTip
position="left"
content={i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.recordScoreTooltip', {
defaultMessage:
'A normalized score between 0-100, which indicates the relative significance of the anomaly record result. This value might change as new data is analyzed.',
<span>
{i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.recordScoreTitle', {
defaultMessage: 'Record score',
})}
>
<span>
{i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.recordScoreTitle', {
defaultMessage: 'Record score',
&nbsp;
<EuiIconTip
size="s"
color="subdued"
type="questionInCircle"
className="eui-alignTop"
position="left"
content={i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.recordScoreTooltip', {
defaultMessage:
'A normalized score between 0-100, which indicates the relative significance of the anomaly record result. This value might change as new data is analyzed.',
})}
<EuiIcon size="s" color="subdued" type="questionInCircle" className="eui-alignTop" />
</span>
</EuiToolTip>
/>
</span>
),
description: Math.floor(1000 * source.record_score) / 1000,
});

items.push({
title: (
<EuiToolTip
position="left"
content={i18n.translate(
'xpack.ml.anomaliesTable.anomalyDetails.initialRecordScoreTooltip',
{
defaultMessage:
'A normalized score between 0-100, which indicates the relative significance of the anomaly record when the bucket was initially processed.',
}
)}
>
<span>
{i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.initialRecordScoreTitle', {
defaultMessage: 'Initial record score',
})}
<EuiIcon size="s" color="subdued" type="questionInCircle" className="eui-alignTop" />
</span>
</EuiToolTip>
<span>
{i18n.translate('xpack.ml.anomaliesTable.anomalyDetails.initialRecordScoreTitle', {
defaultMessage: 'Initial record score',
})}
&nbsp;
<EuiIconTip
size="s"
color="subdued"
type="questionInCircle"
className="eui-alignTop"
position="left"
content={i18n.translate(
'xpack.ml.anomaliesTable.anomalyDetails.initialRecordScoreTooltip',
{
defaultMessage:
'A normalized score between 0-100, which indicates the relative significance of the anomaly record when the bucket was initially processed.',
}
)}
/>
</span>
),
description: Math.floor(1000 * source.initial_record_score) / 1000,
});
Expand Down Expand Up @@ -368,24 +373,27 @@ export const AnomalyExplanationDetails: FC<{ anomaly: MlAnomaliesTableRecord }>
if (scoreDifference > ACCEPTABLE_NORMALIZATION) {
explanationDetails.push({
title: (
<EuiToolTip
position="left"
content={i18n.translate(
'xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.recordScoreTooltip',
{
defaultMessage:
'The initial record score has been reduced based on the analysis of subsequent data.',
}
)}
>
<span>
<FormattedMessage
id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.recordScore"
defaultMessage="Record score reduction"
/>
<EuiIcon size="s" color="subdued" type="questionInCircle" className="eui-alignTop" />
</span>
</EuiToolTip>
<span>
<FormattedMessage
id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.recordScore"
defaultMessage="Record score reduction"
/>
&nbsp;
<EuiIconTip
size="s"
color="subdued"
type="questionInCircle"
className="eui-alignTop"
position="left"
content={i18n.translate(
'xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.recordScoreTooltip',
{
defaultMessage:
'The initial record score has been reduced based on the analysis of subsequent data.',
}
)}
/>
</span>
),
description: (
<EuiFlexGroup gutterSize="xs">
Expand All @@ -406,21 +414,24 @@ export const AnomalyExplanationDetails: FC<{ anomaly: MlAnomaliesTableRecord }>
if (explanation.anomaly_characteristics_impact !== undefined) {
impactDetails.push({
title: (
<EuiToolTip
position="left"
content={getImpactTooltip(
explanation.anomaly_characteristics_impact,
'anomaly_characteristics'
)}
>
<span>
<FormattedMessage
id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.anomalyCharacteristics"
defaultMessage="Anomaly characteristics impact"
/>
<EuiIcon size="s" color="subdued" type="questionInCircle" className="eui-alignTop" />
</span>
</EuiToolTip>
<span>
<FormattedMessage
id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.anomalyCharacteristics"
defaultMessage="Anomaly characteristics impact"
/>
&nbsp;
<EuiIconTip
size="s"
color="subdued"
type="questionInCircle"
className="eui-alignTop"
position="left"
content={getImpactTooltip(
explanation.anomaly_characteristics_impact,
'anomaly_characteristics'
)}
/>
</span>
),
description: <ImpactVisual score={explanation.anomaly_characteristics_impact} />,
});
Expand All @@ -429,112 +440,127 @@ export const AnomalyExplanationDetails: FC<{ anomaly: MlAnomaliesTableRecord }>
if (explanation.single_bucket_impact !== undefined) {
impactDetails.push({
title: (
<EuiToolTip
position="left"
content={getImpactTooltip(explanation.single_bucket_impact, 'single_bucket')}
>
<span>
<FormattedMessage
id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.singleBucket"
defaultMessage="Single bucket impact"
/>
<EuiIcon size="s" color="subdued" type="questionInCircle" className="eui-alignTop" />
</span>
</EuiToolTip>
<span>
<FormattedMessage
id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.singleBucket"
defaultMessage="Single bucket impact"
/>
&nbsp;
<EuiIconTip
size="s"
color="subdued"
type="questionInCircle"
className="eui-alignTop"
position="left"
content={getImpactTooltip(explanation.single_bucket_impact, 'single_bucket')}
/>
</span>
),
description: <ImpactVisual score={explanation.single_bucket_impact} />,
});
}
if (explanation.multi_bucket_impact !== undefined) {
impactDetails.push({
title: (
<EuiToolTip
position="left"
content={getImpactTooltip(explanation.multi_bucket_impact, 'multi_bucket')}
>
<span>
<FormattedMessage
id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.multiBucket"
defaultMessage="Multi bucket impact"
/>
<EuiIcon size="s" color="subdued" type="questionInCircle" className="eui-alignTop" />
</span>
</EuiToolTip>
<span>
<FormattedMessage
id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.multiBucket"
defaultMessage="Multi bucket impact"
/>
&nbsp;
<EuiIconTip
size="s"
color="subdued"
type="questionInCircle"
className="eui-alignTop"
position="left"
content={getImpactTooltip(explanation.multi_bucket_impact, 'multi_bucket')}
/>
</span>
),
description: <ImpactVisual score={explanation.multi_bucket_impact} />,
});
}
if (explanation.high_variance_penalty !== undefined) {
impactDetails.push({
title: (
<EuiToolTip
position="left"
content={i18n.translate(
'xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.highVarianceTooltip',
{
defaultMessage:
'Indicates reduction of anomaly score for the bucket with large confidence intervals. If a bucket has large confidence intervals, the score is reduced.',
}
)}
>
<span>
<FormattedMessage
id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.highVariance"
defaultMessage="High variance interval"
/>
<EuiIcon size="s" color="subdued" type="questionInCircle" className="eui-alignTop" />
</span>
</EuiToolTip>
<span>
<FormattedMessage
id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.highVariance"
defaultMessage="High variance interval"
/>
&nbsp;
<EuiIconTip
size="s"
color="subdued"
type="questionInCircle"
className="eui-alignTop"
position="left"
content={i18n.translate(
'xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.highVarianceTooltip',
{
defaultMessage:
'Indicates reduction of anomaly score for the bucket with large confidence intervals. If a bucket has large confidence intervals, the score is reduced.',
}
)}
/>
</span>
),
description: explanation.high_variance_penalty ? yes : no,
});
}
if (explanation.multimodal_distribution !== undefined) {
impactDetails.push({
title: (
<EuiToolTip
position="left"
content={i18n.translate(
'xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.multimodalTooltip',
{
defaultMessage:
'Indicates whether the prior distribution of the time series is multi-modal or has a single mode.',
}
)}
>
<span>
<FormattedMessage
id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.multimodal"
defaultMessage="Multi-modal distribution"
/>
<EuiIcon size="s" color="subdued" type="questionInCircle" className="eui-alignTop" />
</span>
</EuiToolTip>
<span>
<FormattedMessage
id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.multimodal"
defaultMessage="Multi-modal distribution"
/>
&nbsp;
<EuiIconTip
size="s"
color="subdued"
type="questionInCircle"
className="eui-alignTop"
position="left"
content={i18n.translate(
'xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.multimodalTooltip',
{
defaultMessage:
'Indicates whether the prior distribution of the time series is multi-modal or has a single mode.',
}
)}
/>
</span>
),
description: explanation.multimodal_distribution ? yes : no,
});
}
if (explanation.incomplete_bucket_penalty !== undefined) {
impactDetails.push({
title: (
<EuiToolTip
position="left"
content={i18n.translate(
'xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.incompleteBucketTooltip',
{
defaultMessage:
'If the bucket contains fewer samples than expected, the score is reduced.',
}
)}
>
<span>
<FormattedMessage
id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.incompleteBucket"
defaultMessage="Incomplete bucket"
/>
<EuiIcon size="s" color="subdued" type="questionInCircle" className="eui-alignTop" />
</span>
</EuiToolTip>
<span>
<FormattedMessage
id="xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.incompleteBucket"
defaultMessage="Incomplete bucket"
/>
&nbsp;
<EuiIconTip
size="s"
color="subdued"
type="questionInCircle"
className="eui-alignTop"
position="left"
content={i18n.translate(
'xpack.ml.anomaliesTable.anomalyDetails.anomalyExplanationDetails.incompleteBucketTooltip',
{
defaultMessage:
'If the bucket contains fewer samples than expected, the score is reduced.',
}
)}
/>
</span>
),
description: explanation.incomplete_bucket_penalty ? yes : no,
});
Expand Down

0 comments on commit f023c2c

Please sign in to comment.