[ML] Prevent overflow of large metric values in data visualizer/file data visualizer cards (#36932) (#37268)

* filedataviz cards - abbrev long numeric values

* add directive for index dataviz values

* Add arg to indicate format. update tests

* truncate with ellipsis

* use eui ellipsis truncation

* increase card content height

* ensure truncation for firefox and safari
This commit is contained in:
Melissa Alvarez 2019-05-28 16:25:46 -04:00 committed by GitHub
parent 7da631e095
commit 256b4c21c3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 99 additions and 12 deletions

View file

@ -0,0 +1,34 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import React from 'react';
import {
EuiToolTip
} from '@elastic/eui';
const MAX_CHARS = 12;
export function DisplayValue({ value }) {
const length = String(value).length;
let formattedValue;
if (length <= MAX_CHARS) {
formattedValue = value;
} else {
formattedValue = (
<EuiToolTip content={value} anchorClassName="valueWrapper">
<span>
{value}
</span>
</EuiToolTip>
);
}
return formattedValue;
}

View file

@ -0,0 +1,7 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
export { DisplayValue } from './display_value';

View file

@ -45,7 +45,7 @@
@include euiPanel($selector: 'card-contents');
.card-contents {
height: 393px;
height: 400px;
border-radius: 0px 0px $euiBorderRadius $euiBorderRadius;
overflow: hidden;
}
@ -68,6 +68,15 @@
display: inline-block;
}
.stat.min.value, .stat.max.value, .stat.median.value {
font-size: $euiFontSizeS;
@include euiTextTruncate;
}
.valueWrapper {
display: inline;
}
.not-exist-message {
padding: 50px 30px 0px 30px;
text-align: center;

View file

@ -1,5 +1,5 @@
<div ng-if="card.existsInDocs === true" class="card-contents">
<div class="stats euiText">
<div class="stats euiText--small">
<div class="stat"><i class="fa fa-files-o" aria-hidden="true"></i>
<span
i18n-id="xpack.ml.fieldDataCard.cardNumber.cardStatsCountDocumentsPercentsLabel"
@ -37,9 +37,18 @@
></div>
</div>
<div>
<div class="stat min">{{ card.stats.min | formatField:card.fieldFormat }}</div>
<div class="stat median">{{ card.stats.median | formatField:card.fieldFormat }}</div>
<div class="stat max">{{ card.stats.max | formatField:card.fieldFormat }}</div>
<div class="stat min value">
<ml-display-value value="card.stats.min | formatField:card.fieldFormat">
</ml-display-value>
</div>
<div class="stat median value">
<ml-display-value value="card.stats.median | formatField:card.fieldFormat">
</ml-display-value>
</div>
<div class="stat max value">
<ml-display-value value="card.stats.max | formatField:card.fieldFormat">
</ml-display-value>
</div>
</div>
</div>

View file

@ -0,0 +1,21 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import 'ngreact';
import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml', ['react']);
import { DisplayValue } from '../../components/display_value';
module.directive('mlDisplayValue', function (reactDirective) {
return reactDirective(
DisplayValue,
undefined,
{ restrict: 'E' }
);
});

View file

@ -7,6 +7,7 @@
import './document_count_chart_directive';
import './display_value_directive';
import './field_data_card_directive';
import './metric_distribution_chart_directive';
import './top_values_directive';

View file

@ -28,7 +28,7 @@
</div>
<div
ng-if="card.stats.isTopValuesSampled === true"
class="sampled-message euiText"
class="sampled-message euiText--small"
i18n-id="xpack.ml.fieldDataCard.calculatedFromSampleDescription"
i18n-default-message="Calculated from sample of {topValuesSamplerShardSize} documents per shard"
i18n-values="{

View file

@ -11,6 +11,7 @@ import {
import { FormattedMessage } from '@kbn/i18n/react';
import { FieldTypeIcon } from '../../../components/field_type_icon';
import { DisplayValue } from '../../../components/display_value';
import { getMLJobTypeAriaLabel } from '../../../util/field_types_utils';
export function FieldStatsCard({ field }) {
@ -93,9 +94,15 @@ export function FieldStatsCard({ field }) {
</div>
</div>
<div>
<div className="stat min heading">{field.min_value}</div>
<div className="stat median heading">{field.median_value}</div>
<div className="stat max heading">{field.max_value}</div>
<div className="stat min value">
<DisplayValue value={field.min_value}/>
</div>
<div className="stat median value">
<DisplayValue value={field.median_value}/>
</div>
<div className="stat max value">
<DisplayValue value={field.max_value}/>
</div>
</div>
</React.Fragment>
}

View file

@ -12,9 +12,8 @@
*/
import numeral from '@elastic/numeral';
export function abbreviateWholeNumber(value, maxDigits) {
const maxNumDigits = (maxDigits !== undefined ? maxDigits : 3);
if (Math.abs(value) < Math.pow(10, maxNumDigits)) {
export function abbreviateWholeNumber(value, maxDigits = 3) {
if (Math.abs(value) < Math.pow(10, maxDigits)) {
return value;
} else {
return numeral(value).format('0a');