[ML] Data Visualizer redesign (#54358)
* [ML] change basic page structure * [ML] adjust search panel * [ML] adjust fields_panel.tsx * [ML] card icon styles * [ML] styles * [ML] adjust actions_panel.tsx * Update styling of panels, spacing * [ML] change basic page structure * [ML] adjust search panel * [ML] adjust fields_panel.tsx * [ML] card icon styles * [ML] styles * [ML] adjust actions_panel.tsx * [ML] fix i18n * [ML] fix styles * [ML] adjust top values styles * [ML] remove conflicts artifacts * Use EuiBorderColor * [ML] fix i18n * [ML] fix i18n * [ML] fix counters * [ML] fixed width for sample size select * [ML] fix layout for file viz * [ML] fix empty cards rendering * Update text styling and spacing * [ML] fix field stats card * [ML] fix counter for showAllFields * [ML] reset title for the badge * [ML] boolean_content.tsx with the bar chart * [ML] fix counters Co-authored-by: DeFazio <michael.defazio@elastic.co> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
5738855389
commit
1b076171f3
|
@ -13,11 +13,11 @@ export const DisplayValue: FC<{ value: any }> = ({ value }) => {
|
|||
const length = String(value).length;
|
||||
|
||||
if (length <= MAX_CHARS) {
|
||||
return value;
|
||||
return <b>{value}</b>;
|
||||
} else {
|
||||
return (
|
||||
<EuiToolTip content={value} anchorClassName="valueWrapper">
|
||||
<span>{value}</span>
|
||||
<b>{value}</b>
|
||||
</EuiToolTip>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
.ml-field-title-bar {
|
||||
color: $euiColorEmptyShade;
|
||||
@include euiFontSizeL;
|
||||
@include euiFontSizeM;
|
||||
font-family: Roboto Mono, serif;
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
font-size: $euiFontSizeS;
|
||||
border-radius: $euiBorderRadius $euiBorderRadius 0 0;
|
||||
padding: $euiSizeXS;
|
||||
margin: (-$euiSize) (-$euiSize) 0 (-$euiSize);
|
||||
border-top: 3px solid;
|
||||
text-align: center;
|
||||
border-radius: $euiBorderRadius $euiBorderRadius 0px 0px;
|
||||
padding-bottom: $euiSizeXS/2;
|
||||
|
||||
.field-type-icon {
|
||||
vertical-align: middle;
|
||||
|
@ -18,5 +23,6 @@
|
|||
padding-right: $euiSizeS;
|
||||
max-width: 290px; // SASSTODO: Calculate value
|
||||
display: inline-block;
|
||||
margin-left: $euiSizeS;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,18 @@
|
|||
$icon-size: 20px;
|
||||
|
||||
.field-type-icon-container {
|
||||
display: inline !important;
|
||||
display: inline-block !important;
|
||||
vertical-align: middle;
|
||||
border: 1px solid;
|
||||
border-radius: 4px;
|
||||
width: $icon-size;
|
||||
height: $icon-size;
|
||||
line-height: $icon-size;;
|
||||
text-align: center;
|
||||
|
||||
.field-type-icon {
|
||||
padding-right: $euiSizeXS / 2;
|
||||
padding: 0;
|
||||
display: inline !important;
|
||||
vertical-align: initial;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,56 +8,96 @@
|
|||
// These styles should all be removed once the file data visualizer is using
|
||||
// the same field_data_card component as the index based data visualizer.
|
||||
height: 408px;
|
||||
box-shadow: none;
|
||||
border-color: $euiBorderColor;
|
||||
|
||||
// Note the names of these styles need to match the type of the field they are displaying.
|
||||
.boolean {
|
||||
background-color: #e6c220;
|
||||
color: $euiColorVis5;
|
||||
border-color: $euiColorVis5;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis5, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.date {
|
||||
background-color: #f98510;
|
||||
color: $euiColorVis7;
|
||||
border-color: $euiColorVis7;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis7, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.document_count {
|
||||
background-color: #db1374;
|
||||
color: $euiColorVis2;
|
||||
border-color: $euiColorVis2;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis2, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.geo_point {
|
||||
background-color: #461a0a;
|
||||
color: $euiColorVis8;
|
||||
border-color: $euiColorVis8;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis8, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.ip {
|
||||
background-color: #490092;
|
||||
color: $euiColorVis3;
|
||||
border-color: $euiColorVis3;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis3, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.keyword {
|
||||
background-color: #00b3a4;
|
||||
color: $euiColorVis0;
|
||||
border-color: $euiColorVis0;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis0, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.number {
|
||||
background-color: #3185fc;
|
||||
color: $euiColorVis1;
|
||||
border-color: $euiColorVis1;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis1, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
background-color: #920000;
|
||||
color: $euiColorVis9;
|
||||
border-color: $euiColorVis9;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis9, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.type-other,
|
||||
.unknown {
|
||||
background-color: #bfa180;
|
||||
color: $euiColorVis6;
|
||||
border-color: $euiColorVis6;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis6, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
// Use euiPanel styling
|
||||
@include euiPanel($selector: '.card-contents');
|
||||
|
||||
.card-contents {
|
||||
height: 378px;
|
||||
line-height: 21px;
|
||||
border-radius: 0px 0px $euiBorderRadius $euiBorderRadius;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.stats {
|
||||
padding: 10px 10px 0px 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiSpacer } from '@elastic/eui';
|
||||
import { EuiSpacer, EuiPanel, EuiFlexGroup, EuiFlexItem, EuiText, EuiProgress } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { FieldTypeIcon } from '../../../../components/field_type_icon';
|
||||
|
@ -25,129 +25,136 @@ export function FieldStatsCard({ field }) {
|
|||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="card-container">
|
||||
<div className="ml-field-data-card">
|
||||
<div className={`ml-field-title-bar ${type}`}>
|
||||
<FieldTypeIcon type={type} needsAria={false} />
|
||||
<div
|
||||
className="field-name"
|
||||
tabIndex="0"
|
||||
aria-label={`${cardTitleAriaLabel.join(', ')}`}
|
||||
>
|
||||
{field.name}
|
||||
</div>
|
||||
<EuiPanel hasShadow={false} className="mlFieldDataCard">
|
||||
<div className="ml-field-data-card">
|
||||
<div className={`ml-field-title-bar ${type}`}>
|
||||
<FieldTypeIcon type={type} needsAria={false} />
|
||||
<div className="field-name" tabIndex="0" aria-label={`${cardTitleAriaLabel.join(', ')}`}>
|
||||
{field.name}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="card-contents">
|
||||
{field.count > 0 && (
|
||||
<React.Fragment>
|
||||
<div className="stats">
|
||||
<div className="stat">
|
||||
<i className="fa fa-files-o" aria-hidden="true" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fieldStatsCard.documentsCountDescription"
|
||||
defaultMessage="{fieldCount, plural, zero {# document} one {# document} other {# documents}} ({fieldPercent}%)"
|
||||
values={{
|
||||
fieldCount: field.count,
|
||||
fieldPercent: field.percent,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="stat">
|
||||
<i className="fa fa-cubes" aria-hidden="true" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fieldStatsCard.distinctCountDescription"
|
||||
defaultMessage="{fieldCardinality} distinct {fieldCardinality, plural, zero {value} one {value} other {values}}"
|
||||
values={{
|
||||
fieldCardinality: field.cardinality,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{field.median_value && (
|
||||
<React.Fragment>
|
||||
<div>
|
||||
<div className="stat min heading">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fieldStatsCard.minTitle"
|
||||
defaultMessage="min"
|
||||
/>
|
||||
</div>
|
||||
<div className="stat median heading">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fieldStatsCard.medianTitle"
|
||||
defaultMessage="median"
|
||||
/>
|
||||
</div>
|
||||
<div className="stat max heading">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fieldStatsCard.maxTitle"
|
||||
defaultMessage="max"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
)}
|
||||
<div className="mlFieldDataCard__content">
|
||||
{field.count > 0 && (
|
||||
<React.Fragment>
|
||||
<div className="stats">
|
||||
<div className="stat">
|
||||
<i className="fa fa-files-o" aria-hidden="true" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fieldStatsCard.documentsCountDescription"
|
||||
defaultMessage="{fieldCount, plural, zero {# document} one {# document} other {# documents}} ({fieldPercent}%)"
|
||||
values={{
|
||||
fieldCount: field.count,
|
||||
fieldPercent: field.percent,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="stat">
|
||||
<i className="fa fa-cubes" aria-hidden="true" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fieldStatsCard.distinctCountDescription"
|
||||
defaultMessage="{fieldCardinality} distinct {fieldCardinality, plural, zero {value} one {value} other {values}}"
|
||||
values={{
|
||||
fieldCardinality: field.cardinality,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{field.top_hits && (
|
||||
{field.median_value && (
|
||||
<React.Fragment>
|
||||
<EuiSpacer size="s" />
|
||||
|
||||
<div className="stats">
|
||||
<div className="stat">
|
||||
<div>
|
||||
<div className="stat min heading">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fieldStatsCard.topStatsValuesDescription"
|
||||
defaultMessage="top values"
|
||||
id="xpack.ml.fileDatavisualizer.fieldStatsCard.minTitle"
|
||||
defaultMessage="min"
|
||||
/>
|
||||
</div>
|
||||
{field.top_hits.map(({ count, value }) => {
|
||||
const pcnt = Math.round((count / field.count) * 100 * 100) / 100;
|
||||
return (
|
||||
<div key={value} className="top-value">
|
||||
<div className="field-label">{value} </div>
|
||||
<div className="top-value-bar-holder">
|
||||
<div
|
||||
className={`top-value-bar ${type}`}
|
||||
style={{ width: `${pcnt}%` }}
|
||||
/>
|
||||
</div>
|
||||
<div className="count-label">{pcnt}%</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<div className="stat median heading">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fieldStatsCard.medianTitle"
|
||||
defaultMessage="median"
|
||||
/>
|
||||
</div>
|
||||
<div className="stat max heading">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fieldStatsCard.maxTitle"
|
||||
defaultMessage="max"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
)}
|
||||
</React.Fragment>
|
||||
)}
|
||||
{field.count === 0 && (
|
||||
<div className="stats">
|
||||
<div className="stat">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fieldStatsCard.noFieldInformationAvailableDescription"
|
||||
defaultMessage="No field information available"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{field.top_hits && (
|
||||
<React.Fragment>
|
||||
<EuiSpacer size="s" />
|
||||
|
||||
<div className="stats">
|
||||
<div className="stat">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fieldStatsCard.topStatsValuesDescription"
|
||||
defaultMessage="top values"
|
||||
/>
|
||||
</div>
|
||||
{field.top_hits.map(({ count, value }) => {
|
||||
const pcnt = Math.round((count / field.count) * 100 * 100) / 100;
|
||||
return (
|
||||
<EuiFlexGroup gutterSize="xs" alignItems="center" key={value}>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
style={{ width: 100 }}
|
||||
className="eui-textTruncate"
|
||||
>
|
||||
<EuiText size="xs" textAlign="right" color="subdued">
|
||||
{value}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiProgress value={count} max={field.count} color="primary" size="m" />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
style={{ width: 70 }}
|
||||
className="eui-textTruncate"
|
||||
>
|
||||
<EuiText size="xs" textAlign="left" color="subdued">
|
||||
{pcnt}%
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</React.Fragment>
|
||||
)}
|
||||
{field.count === 0 && (
|
||||
<div className="stats">
|
||||
<div className="stat">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fieldStatsCard.noFieldInformationAvailableDescription"
|
||||
defaultMessage="No field information available"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
</EuiPanel>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { EuiFlexGrid, EuiFlexItem } from '@elastic/eui';
|
||||
import { FieldStatsCard } from './field_stats_card';
|
||||
import { getFieldNames } from './get_field_names';
|
||||
import { ML_JOB_FIELD_TYPES } from '../../../../../../common/constants/field_types';
|
||||
|
@ -29,9 +30,13 @@ export class FieldsStats extends Component {
|
|||
render() {
|
||||
return (
|
||||
<div className="fields-stats">
|
||||
{this.state.fields.map(f => (
|
||||
<FieldStatsCard field={f} key={f.name} />
|
||||
))}
|
||||
<EuiFlexGrid gutterSize="m">
|
||||
{this.state.fields.map(f => (
|
||||
<EuiFlexItem key={f.name} style={{ minWidth: '360px' }}>
|
||||
<FieldStatsCard field={f} />
|
||||
</EuiFlexItem>
|
||||
))}
|
||||
</EuiFlexGrid>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import React, { FC, useState } from 'react';
|
|||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiPanel, EuiSpacer, EuiText, EuiTitle, EuiFlexGroup } from '@elastic/eui';
|
||||
import { EuiSpacer, EuiText, EuiTitle, EuiFlexGroup } from '@elastic/eui';
|
||||
|
||||
import { IndexPattern } from '../../../../../../../../../../src/plugins/data/public';
|
||||
import { CreateJobLinkCard } from '../../../../components/create_job_link_card';
|
||||
|
@ -38,8 +38,8 @@ export const ActionsPanel: FC<Props> = ({ indexPattern }) => {
|
|||
// passed the recognizerResults object, and then run the recognizer check which
|
||||
// controls whether the recognizer section is ultimately displayed.
|
||||
return (
|
||||
<EuiPanel data-test-subj="mlDataVisualizerActionsPanel">
|
||||
<EuiTitle>
|
||||
<div data-test-subj="mlDataVisualizerActionsPanel">
|
||||
<EuiTitle size="s">
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.actionsPanel.createJobTitle"
|
||||
|
@ -49,7 +49,7 @@ export const ActionsPanel: FC<Props> = ({ indexPattern }) => {
|
|||
</EuiTitle>
|
||||
<EuiSpacer size="s" />
|
||||
<div style={recognizerResultsCount === 0 ? { display: 'none' } : {}}>
|
||||
<EuiText>
|
||||
<EuiText size="s" color="subdued">
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.actionsPanel.selectKnownConfigurationDescription"
|
||||
|
@ -67,7 +67,7 @@ export const ActionsPanel: FC<Props> = ({ indexPattern }) => {
|
|||
</EuiFlexGroup>
|
||||
<EuiSpacer size="l" />
|
||||
</div>
|
||||
<EuiText>
|
||||
<EuiText size="s" color="subdued">
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.actionsPanel.createJobDescription"
|
||||
|
@ -88,6 +88,6 @@ export const ActionsPanel: FC<Props> = ({ indexPattern }) => {
|
|||
onClick={openAdvancedJobWizard}
|
||||
href={`#/jobs/new_job/advanced?index=${indexPattern}`}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,52 +1,94 @@
|
|||
.mlFieldDataCard {
|
||||
height: 420px;
|
||||
width: 360px;
|
||||
box-shadow: none;
|
||||
border-color: $euiBorderColor;
|
||||
|
||||
// Note the names of these styles need to match the type of the field they are displaying.
|
||||
.boolean {
|
||||
background-color: $euiColorVis5;
|
||||
color: $euiColorVis5;
|
||||
border-color: $euiColorVis5;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis5, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.date {
|
||||
background-color: $euiColorVis7;
|
||||
color: $euiColorVis7;
|
||||
border-color: $euiColorVis7;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis7, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.document_count {
|
||||
background-color: $euiColorVis2;
|
||||
color: $euiColorVis2;
|
||||
border-color: $euiColorVis2;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis2, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.geo_point {
|
||||
background-color: $euiColorVis8;
|
||||
color: $euiColorVis8;
|
||||
border-color: $euiColorVis8;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis8, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.ip {
|
||||
background-color: $euiColorVis3;
|
||||
color: $euiColorVis3;
|
||||
border-color: $euiColorVis3;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis3, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.keyword {
|
||||
background-color: $euiColorVis0;
|
||||
color: $euiColorVis0;
|
||||
border-color: $euiColorVis0;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis0, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.number {
|
||||
background-color: $euiColorVis1;
|
||||
color: $euiColorVis1;
|
||||
border-color: $euiColorVis1;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis1, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
background-color: $euiColorVis9;
|
||||
color: $euiColorVis9;
|
||||
border-color: $euiColorVis9;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis9, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.type-other,
|
||||
.unknown {
|
||||
background-color: $euiColorVis6;
|
||||
}
|
||||
color: $euiColorVis6;
|
||||
border-color: $euiColorVis6;
|
||||
|
||||
// Use euiPanel styling
|
||||
@include euiPanel($selector: '.mlFieldDataCard__content');
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis6, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
.mlFieldDataCard__content {
|
||||
@include euiFontSizeS;
|
||||
height: 385px;
|
||||
border-radius: 0px 0px $euiBorderRadius $euiBorderRadius;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,21 +5,20 @@
|
|||
*/
|
||||
|
||||
import React, { FC } from 'react';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiProgress, EuiSpacer, EuiText } from '@elastic/eui';
|
||||
import { EuiIcon, EuiSpacer, EuiText } from '@elastic/eui';
|
||||
import { Axis, BarSeries, Chart, Settings } from '@elastic/charts';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { FieldDataCardProps } from '../field_data_card';
|
||||
import { roundToDecimalPlace } from '../../../../../formatters/round_to_decimal_place';
|
||||
|
||||
function getPercentLabel(valueCount: number, totalCount: number): string {
|
||||
if (valueCount === 0) {
|
||||
function getPercentLabel(value: number): string {
|
||||
if (value === 0) {
|
||||
return '0%';
|
||||
}
|
||||
|
||||
const percent = (100 * valueCount) / totalCount;
|
||||
if (percent >= 0.1) {
|
||||
return `${roundToDecimalPlace(percent, 1)}%`;
|
||||
if (value >= 0.1) {
|
||||
return `${value}%`;
|
||||
} else {
|
||||
return '< 0.1%';
|
||||
}
|
||||
|
@ -31,64 +30,74 @@ export const BooleanContent: FC<FieldDataCardProps> = ({ config }) => {
|
|||
const { count, sampleCount, trueCount, falseCount } = stats;
|
||||
const docsPercent = roundToDecimalPlace((count / sampleCount) * 100);
|
||||
|
||||
// TODO - display counts of true / false in an Elastic Charts bar chart (or Pie chart if available).
|
||||
|
||||
return (
|
||||
<div className="mlFieldDataCard__stats">
|
||||
<div>
|
||||
<EuiIcon type="document" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardBoolean.documentsCountDescription"
|
||||
defaultMessage="{count, plural, zero {# document} one {# document} other {# documents}} ({docsPercent}%)"
|
||||
values={{
|
||||
count,
|
||||
docsPercent,
|
||||
}}
|
||||
/>
|
||||
<EuiText size="xs" color="subdued">
|
||||
<EuiIcon type="document" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardBoolean.documentsCountDescription"
|
||||
defaultMessage="{count, plural, zero {# document} one {# document} other {# documents}} ({docsPercent}%)"
|
||||
values={{
|
||||
count,
|
||||
docsPercent,
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
</div>
|
||||
|
||||
<EuiSpacer size="m" />
|
||||
|
||||
<div>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardBoolean.valuesLabel"
|
||||
defaultMessage="values"
|
||||
/>
|
||||
<EuiSpacer size="xs" />
|
||||
<EuiFlexGroup gutterSize="xs" alignItems="center">
|
||||
<EuiFlexItem grow={false} style={{ width: 100 }} className="eui-textTruncate">
|
||||
<EuiText size="s" textAlign="right">
|
||||
true
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiProgress value={trueCount} max={count} color="primary" size="l" />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false} style={{ width: 70 }} className="eui-textTruncate">
|
||||
<EuiText size="s" textAlign="left">
|
||||
{getPercentLabel(trueCount, count)}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
||||
<EuiSpacer size="xs" />
|
||||
|
||||
<EuiFlexGroup gutterSize="xs" alignItems="center">
|
||||
<EuiFlexItem grow={false} style={{ width: 100 }} className="eui-textTruncate">
|
||||
<EuiText size="s" textAlign="right">
|
||||
false
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiProgress value={falseCount} max={count} color="subdued" size="l" />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false} style={{ width: 70 }} className="eui-textTruncate">
|
||||
<EuiText size="s" textAlign="left">
|
||||
{getPercentLabel(falseCount, count)}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiText size="s">
|
||||
<h6>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardBoolean.valuesLabel"
|
||||
defaultMessage="Values"
|
||||
/>
|
||||
</h6>
|
||||
</EuiText>
|
||||
<EuiSpacer size="s" />
|
||||
<Chart renderer="canvas" className="story-chart" size={{ height: 200 }}>
|
||||
<Axis id="bottom" position="bottom" showOverlappingTicks />
|
||||
<Settings
|
||||
showLegend={false}
|
||||
theme={{
|
||||
barSeriesStyle: {
|
||||
displayValue: {
|
||||
fill: '#000',
|
||||
fontSize: 12,
|
||||
fontStyle: 'normal',
|
||||
offsetX: 0,
|
||||
offsetY: -5,
|
||||
padding: 0,
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<BarSeries
|
||||
id={config.fieldName || config.fieldFormat}
|
||||
data={[
|
||||
{ x: 'true', y: roundToDecimalPlace((trueCount / count) * 100) },
|
||||
{ x: 'false', y: roundToDecimalPlace((falseCount / count) * 100) },
|
||||
]}
|
||||
displayValueSettings={{
|
||||
hideClippedValue: true,
|
||||
isAlternatingValueLabel: true,
|
||||
valueFormatter: getPercentLabel,
|
||||
isValueContainedInElement: false,
|
||||
showValueLabel: true,
|
||||
}}
|
||||
customSeriesColors={['rgba(230, 194, 32, 0.5)', 'rgba(224, 187, 20, 0.71)']}
|
||||
splitSeriesAccessors={['x']}
|
||||
stackAccessors={['x']}
|
||||
xAccessor="x"
|
||||
xScaleType="ordinal"
|
||||
yAccessors={['y']}
|
||||
yScaleType="linear"
|
||||
/>
|
||||
</Chart>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import React, { FC } from 'react';
|
||||
import { EuiIcon, EuiSpacer } from '@elastic/eui';
|
||||
import { EuiIcon, EuiSpacer, EuiText } from '@elastic/eui';
|
||||
// @ts-ignore
|
||||
import { formatDate } from '@elastic/eui/lib/services/format';
|
||||
|
||||
|
@ -25,19 +25,21 @@ export const DateContent: FC<FieldDataCardProps> = ({ config }) => {
|
|||
return (
|
||||
<div className="mlFieldDataCard__stats">
|
||||
<div>
|
||||
<EuiIcon type="document" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardDate.documentsCountDescription"
|
||||
defaultMessage="{count, plural, zero {# document} one {# document} other {# documents}} ({docsPercent}%)"
|
||||
values={{
|
||||
count,
|
||||
docsPercent,
|
||||
}}
|
||||
/>
|
||||
<EuiText size="xs" color="subdued">
|
||||
<EuiIcon type="document" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardDate.documentsCountDescription"
|
||||
defaultMessage="{count, plural, zero {# document} one {# document} other {# documents}} ({docsPercent}%)"
|
||||
values={{
|
||||
count,
|
||||
docsPercent,
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
</div>
|
||||
|
||||
<EuiSpacer size="s" />
|
||||
<EuiSpacer size="m" />
|
||||
|
||||
<div>
|
||||
<FormattedMessage
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import React, { FC } from 'react';
|
||||
import { EuiIcon, EuiSpacer } from '@elastic/eui';
|
||||
import { EuiIcon, EuiSpacer, EuiText } from '@elastic/eui';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
|
@ -42,33 +42,37 @@ export const GeoPointContent: FC<FieldDataCardProps> = ({ config }) => {
|
|||
return (
|
||||
<div className="mlFieldDataCard__stats">
|
||||
<div>
|
||||
<EuiIcon type="document" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardGeoPoint.documentsCountDescription"
|
||||
defaultMessage="{count, plural, zero {# document} one {# document} other {# documents}} ({docsPercent}%)"
|
||||
values={{
|
||||
count,
|
||||
docsPercent,
|
||||
}}
|
||||
/>
|
||||
<EuiText size="xs" color="subdued">
|
||||
<EuiIcon type="document" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardGeoPoint.documentsCountDescription"
|
||||
defaultMessage="{count, plural, zero {# document} one {# document} other {# documents}} ({docsPercent}%)"
|
||||
values={{
|
||||
count,
|
||||
docsPercent,
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
</div>
|
||||
|
||||
<EuiSpacer size="xs" />
|
||||
|
||||
<div>
|
||||
<EuiIcon type="database" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardGeoPoint.distinctCountDescription"
|
||||
defaultMessage="{cardinality} distinct {cardinality, plural, zero {value} one {value} other {values}}"
|
||||
values={{
|
||||
cardinality,
|
||||
}}
|
||||
/>
|
||||
<EuiText size="xs" color="subdued">
|
||||
<EuiIcon type="database" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardGeoPoint.distinctCountDescription"
|
||||
defaultMessage="{cardinality} distinct {cardinality, plural, zero {value} one {value} other {values}}"
|
||||
values={{
|
||||
cardinality,
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
</div>
|
||||
|
||||
<EuiSpacer size="s" />
|
||||
<EuiSpacer size="m" />
|
||||
|
||||
<ExamplesList examples={examples} />
|
||||
</div>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import React, { FC } from 'react';
|
||||
import { EuiIcon, EuiSpacer } from '@elastic/eui';
|
||||
import { EuiIcon, EuiSpacer, EuiText } from '@elastic/eui';
|
||||
// @ts-ignore
|
||||
import { formatDate } from '@elastic/eui/lib/services/format';
|
||||
|
||||
|
@ -24,30 +24,34 @@ export const IpContent: FC<FieldDataCardProps> = ({ config }) => {
|
|||
return (
|
||||
<div className="mlFieldDataCard__stats">
|
||||
<div>
|
||||
<EuiIcon type="document" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardIp.documentsCountDescription"
|
||||
defaultMessage="{count, plural, zero {# document} one {# document} other {# documents}} ({docsPercent}%)"
|
||||
values={{
|
||||
count,
|
||||
docsPercent,
|
||||
}}
|
||||
/>
|
||||
<EuiText size="xs" color="subdued">
|
||||
<EuiIcon type="document" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardIp.documentsCountDescription"
|
||||
defaultMessage="{count, plural, zero {# document} one {# document} other {# documents}} ({docsPercent}%)"
|
||||
values={{
|
||||
count,
|
||||
docsPercent,
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
</div>
|
||||
|
||||
<EuiSpacer size="xs" />
|
||||
|
||||
<div>
|
||||
<EuiIcon type="database" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardIp.distinctCountDescription"
|
||||
defaultMessage="{cardinality} distinct {cardinality, plural, zero {value} one {value} other {values}}"
|
||||
values={{
|
||||
cardinality,
|
||||
}}
|
||||
/>
|
||||
<EuiText size="xs" color="subdued">
|
||||
<EuiIcon type="database" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardIp.distinctCountDescription"
|
||||
defaultMessage="{cardinality} distinct {cardinality, plural, zero {value} one {value} other {values}}"
|
||||
values={{
|
||||
cardinality,
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
</div>
|
||||
|
||||
<EuiSpacer size="m" />
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import React, { FC } from 'react';
|
||||
import { EuiIcon, EuiSpacer } from '@elastic/eui';
|
||||
import { EuiIcon, EuiSpacer, EuiText } from '@elastic/eui';
|
||||
// @ts-ignore
|
||||
import { formatDate } from '@elastic/eui/lib/services/format';
|
||||
|
||||
|
@ -24,40 +24,49 @@ export const KeywordContent: FC<FieldDataCardProps> = ({ config }) => {
|
|||
return (
|
||||
<div className="mlFieldDataCard__stats">
|
||||
<div>
|
||||
<EuiIcon type="document" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardKeyword.documentsCountDescription"
|
||||
defaultMessage="{count, plural, zero {# document} one {# document} other {# documents}} ({docsPercent}%)"
|
||||
values={{
|
||||
count,
|
||||
docsPercent,
|
||||
}}
|
||||
/>
|
||||
<EuiText size="xs" color="subdued">
|
||||
<EuiIcon type="document" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardKeyword.documentsCountDescription"
|
||||
defaultMessage="{count, plural, zero {# document} one {# document} other {# documents}} ({docsPercent}%)"
|
||||
values={{
|
||||
count,
|
||||
docsPercent,
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
</div>
|
||||
|
||||
<EuiSpacer size="xs" />
|
||||
|
||||
<div>
|
||||
<EuiIcon type="database" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardKeyword.distinctCountDescription"
|
||||
defaultMessage="{cardinality} distinct {cardinality, plural, zero {value} one {value} other {values}}"
|
||||
values={{
|
||||
cardinality,
|
||||
}}
|
||||
/>
|
||||
<EuiText size="xs" color="subdued">
|
||||
<EuiIcon type="database" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardKeyword.distinctCountDescription"
|
||||
defaultMessage="{cardinality} distinct {cardinality, plural, zero {value} one {value} other {values}}"
|
||||
values={{
|
||||
cardinality,
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
</div>
|
||||
|
||||
<EuiSpacer size="m" />
|
||||
|
||||
<div>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardKeyword.topValuesLabel"
|
||||
defaultMessage="top values"
|
||||
/>
|
||||
<EuiSpacer size="xs" />
|
||||
<EuiText size="s">
|
||||
<h6>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardKeyword.topValuesLabel"
|
||||
defaultMessage="Top values"
|
||||
/>
|
||||
</h6>
|
||||
</EuiText>
|
||||
|
||||
<EuiSpacer size="s" />
|
||||
<TopValues stats={stats} fieldFormat={fieldFormat} barColor="secondary" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -5,29 +5,23 @@
|
|||
*/
|
||||
|
||||
import React, { FC, Fragment } from 'react';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSpacer } from '@elastic/eui';
|
||||
import { EuiIcon, EuiSpacer, EuiText } from '@elastic/eui';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
export const NotInDocsContent: FC = () => (
|
||||
<Fragment>
|
||||
<EuiSpacer size="xxl" />
|
||||
<EuiFlexGroup justifyContent="spaceAround">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup gutterSize="xs" justifyContent="spaceAround">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIcon type="alert" />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiFlexGroup style={{ padding: '0px 16px', textAlign: 'center' }}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.fieldNotInDocsLabel"
|
||||
defaultMessage="This field does not appear in any documents for the selected time range"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiText textAlign="center">
|
||||
<EuiIcon type="alert" />
|
||||
</EuiText>
|
||||
|
||||
<EuiSpacer size="s" />
|
||||
<EuiText textAlign="center">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.fieldNotInDocsLabel"
|
||||
defaultMessage="This field does not appear in any documents for the selected time range"
|
||||
/>
|
||||
</EuiText>
|
||||
</Fragment>
|
||||
);
|
||||
|
|
|
@ -5,7 +5,14 @@
|
|||
*/
|
||||
|
||||
import React, { FC, Fragment, useEffect, useState } from 'react';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSelect, EuiSpacer, EuiText } from '@elastic/eui';
|
||||
import {
|
||||
EuiButtonGroup,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiIcon,
|
||||
EuiSpacer,
|
||||
EuiText,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
@ -53,15 +60,15 @@ export const NumberContent: FC<FieldDataCardProps> = ({ config }) => {
|
|||
|
||||
const detailsOptions = [
|
||||
{
|
||||
value: DETAILS_MODE.DISTRIBUTION,
|
||||
text: i18n.translate('xpack.ml.fieldDataCard.cardNumber.details.distributionOfValuesLabel', {
|
||||
defaultMessage: 'distribution of values',
|
||||
id: DETAILS_MODE.TOP_VALUES,
|
||||
label: i18n.translate('xpack.ml.fieldDataCard.cardNumber.details.topValuesLabel', {
|
||||
defaultMessage: 'Top values',
|
||||
}),
|
||||
},
|
||||
{
|
||||
value: DETAILS_MODE.TOP_VALUES,
|
||||
text: i18n.translate('xpack.ml.fieldDataCard.cardNumber.details.topValuesLabel', {
|
||||
defaultMessage: 'top values',
|
||||
id: DETAILS_MODE.DISTRIBUTION,
|
||||
label: i18n.translate('xpack.ml.fieldDataCard.cardNumber.details.distributionOfValuesLabel', {
|
||||
defaultMessage: 'Distribution',
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
@ -69,49 +76,60 @@ export const NumberContent: FC<FieldDataCardProps> = ({ config }) => {
|
|||
return (
|
||||
<div className="mlFieldDataCard__stats">
|
||||
<div>
|
||||
<EuiIcon type="document" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardNumber.documentsCountDescription"
|
||||
defaultMessage="{count, plural, zero {# document} one {# document} other {# documents}} ({docsPercent}%)"
|
||||
values={{
|
||||
count,
|
||||
docsPercent,
|
||||
}}
|
||||
/>
|
||||
<EuiText size="xs" color="subdued">
|
||||
<EuiIcon type="document" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardNumber.documentsCountDescription"
|
||||
defaultMessage="{count, plural, zero {# document} one {# document} other {# documents}} ({docsPercent}%)"
|
||||
values={{
|
||||
count,
|
||||
docsPercent,
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
</div>
|
||||
|
||||
<EuiSpacer size="xs" />
|
||||
|
||||
<div>
|
||||
<EuiIcon type="database" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardNumber.distinctCountDescription"
|
||||
defaultMessage="{cardinality} distinct {cardinality, plural, zero {value} one {value} other {values}}"
|
||||
values={{
|
||||
cardinality,
|
||||
}}
|
||||
/>
|
||||
<EuiText size="xs" color="subdued">
|
||||
<EuiIcon type="database" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardNumber.distinctCountDescription"
|
||||
defaultMessage="{cardinality} distinct {cardinality, plural, zero {value} one {value} other {values}}"
|
||||
values={{
|
||||
cardinality,
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
</div>
|
||||
|
||||
<EuiSpacer size="xs" />
|
||||
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFlexGroup gutterSize="xs" justifyContent="center">
|
||||
<EuiFlexItem grow={1}>
|
||||
<FormattedMessage id="xpack.ml.fieldDataCard.cardNumber.minLabel" defaultMessage="min" />
|
||||
<EuiText color="subdued" size="xs">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardNumber.minLabel"
|
||||
defaultMessage="min"
|
||||
/>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={1}>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardNumber.medianLabel"
|
||||
defaultMessage="median"
|
||||
/>
|
||||
<EuiText color="subdued" size="xs">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardNumber.medianLabel"
|
||||
defaultMessage="median"
|
||||
/>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={1}>
|
||||
<FormattedMessage id="xpack.ml.fieldDataCard.cardNumber.maxLabel" defaultMessage="max" />
|
||||
<EuiText color="subdued" size="xs">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardNumber.maxLabel"
|
||||
defaultMessage="max"
|
||||
/>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
||||
<EuiFlexGroup gutterSize="xs" justifyContent="center">
|
||||
<EuiFlexItem grow={1} className="eui-textTruncate">
|
||||
<DisplayValue value={kibanaFieldFormat(min, fieldFormat)} />
|
||||
|
@ -123,30 +141,22 @@ export const NumberContent: FC<FieldDataCardProps> = ({ config }) => {
|
|||
<DisplayValue value={kibanaFieldFormat(max, fieldFormat)} />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
||||
<EuiSpacer size="s" />
|
||||
|
||||
<EuiFlexGroup gutterSize="xs" justifyContent="center">
|
||||
<EuiFlexItem grow={false} style={{ width: 200 }} className="eui-textTruncate">
|
||||
<EuiSelect
|
||||
options={detailsOptions}
|
||||
value={detailsMode}
|
||||
compressed
|
||||
onChange={e => setDetailsMode(e.target.value as DETAILS_MODE)}
|
||||
style={{ width: '200px' }}
|
||||
aria-label={i18n.translate(
|
||||
'xpack.ml.fieldDataCard.cardNumber.selectMetricDetailsDisplayAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Select display option for metric details',
|
||||
}
|
||||
)}
|
||||
data-test-subj="mlFieldDataCardNumberDetailsSelect"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
||||
<EuiSpacer size="s" />
|
||||
|
||||
<EuiButtonGroup
|
||||
options={detailsOptions}
|
||||
idSelected={detailsMode}
|
||||
onChange={optionId => setDetailsMode(optionId as DETAILS_MODE)}
|
||||
aria-label={i18n.translate(
|
||||
'xpack.ml.fieldDataCard.cardNumber.selectMetricDetailsDisplayAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Select display option for metric details',
|
||||
}
|
||||
)}
|
||||
data-test-subj="mlFieldDataCardNumberDetailsSelect"
|
||||
isFullWidth={true}
|
||||
buttonSize="compressed"
|
||||
/>
|
||||
<EuiSpacer size="m" />
|
||||
{detailsMode === DETAILS_MODE.DISTRIBUTION && (
|
||||
<Fragment>
|
||||
<EuiFlexGroup justifyContent="spaceAround" gutterSize="xs">
|
||||
|
@ -175,7 +185,6 @@ export const NumberContent: FC<FieldDataCardProps> = ({ config }) => {
|
|||
</EuiFlexGroup>
|
||||
</Fragment>
|
||||
)}
|
||||
|
||||
{detailsMode === DETAILS_MODE.TOP_VALUES && (
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
|
|
|
@ -36,30 +36,34 @@ export const OtherContent: FC<FieldDataCardProps> = ({ config }) => {
|
|||
<Fragment>
|
||||
<EuiSpacer size="s" />
|
||||
<div>
|
||||
<EuiIcon type="document" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardOther.documentsCountDescription"
|
||||
defaultMessage="{count, plural, zero {# document} one {# document} other {# documents}} ({docsPercent}%)"
|
||||
values={{
|
||||
count,
|
||||
docsPercent,
|
||||
}}
|
||||
/>
|
||||
<EuiText size="xs" color="subdued">
|
||||
<EuiIcon type="document" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardOther.documentsCountDescription"
|
||||
defaultMessage="{count, plural, zero {# document} one {# document} other {# documents}} ({docsPercent}%)"
|
||||
values={{
|
||||
count,
|
||||
docsPercent,
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
</div>
|
||||
|
||||
<EuiSpacer size="xs" />
|
||||
|
||||
<div>
|
||||
<EuiIcon type="database" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardOther.distinctCountDescription"
|
||||
defaultMessage="{cardinality} distinct {cardinality, plural, zero {value} one {value} other {values}}"
|
||||
values={{
|
||||
cardinality,
|
||||
}}
|
||||
/>
|
||||
<EuiText size="xs" color="subdued">
|
||||
<EuiIcon type="database" />
|
||||
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardOther.distinctCountDescription"
|
||||
defaultMessage="{cardinality} distinct {cardinality, plural, zero {value} one {value} other {values}}"
|
||||
values={{
|
||||
cardinality,
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
</div>
|
||||
</Fragment>
|
||||
)}
|
||||
|
|
|
@ -27,14 +27,16 @@ export const ExamplesList: FC<Props> = ({ examples }) => {
|
|||
|
||||
return (
|
||||
<div>
|
||||
<EuiText>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardText.examplesTitle"
|
||||
defaultMessage="{numExamples, plural, one {value} other {examples}}"
|
||||
values={{
|
||||
numExamples: examples.length,
|
||||
}}
|
||||
/>
|
||||
<EuiText size="s">
|
||||
<h6>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fieldDataCard.cardText.examplesTitle"
|
||||
defaultMessage="{numExamples, plural, one {value} other {examples}}"
|
||||
values={{
|
||||
numExamples: examples.length,
|
||||
}}
|
||||
/>
|
||||
</h6>
|
||||
</EuiText>
|
||||
<EuiSpacer size="s" />
|
||||
{examplesContent}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { EuiPanel } from '@elastic/eui';
|
||||
import React, { FC } from 'react';
|
||||
|
||||
import { ML_JOB_FIELD_TYPES } from '../../../../../../common/constants/field_types';
|
||||
|
@ -30,11 +31,7 @@ export interface FieldDataCardProps {
|
|||
}
|
||||
|
||||
export const FieldDataCard: FC<FieldDataCardProps> = ({ config }) => {
|
||||
const { fieldName, loading, type, existsInDocs, stats } = config;
|
||||
|
||||
if (stats === undefined) {
|
||||
return null;
|
||||
}
|
||||
const { fieldName, loading, type, existsInDocs } = config;
|
||||
|
||||
function getCardContent() {
|
||||
if (existsInDocs === false) {
|
||||
|
@ -73,13 +70,15 @@ export const FieldDataCard: FC<FieldDataCardProps> = ({ config }) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<div data-test-subj={`mlFieldDataCard ${fieldName} ${type}`}>
|
||||
<div className="mlFieldDataCard">
|
||||
<FieldTitleBar card={config} />
|
||||
<div className="mlFieldDataCard__content">
|
||||
{loading === true ? <LoadingIndicator /> : getCardContent()}
|
||||
</div>
|
||||
<EuiPanel
|
||||
data-test-subj={`mlFieldDataCard ${fieldName} ${type}`}
|
||||
className="mlFieldDataCard"
|
||||
hasShadow={false}
|
||||
>
|
||||
<FieldTitleBar card={config} />
|
||||
<div className="mlFieldDataCard__content">
|
||||
{loading === true ? <LoadingIndicator /> : getCardContent()}
|
||||
</div>
|
||||
</div>
|
||||
</EuiPanel>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -50,16 +50,16 @@ export const TopValues: FC<Props> = ({ stats, fieldFormat, barColor }) => {
|
|||
<EuiFlexGroup gutterSize="xs" alignItems="center" key={value.key}>
|
||||
<EuiFlexItem grow={false} style={{ width: 100 }} className="eui-textTruncate">
|
||||
<EuiToolTip content={kibanaFieldFormat(value.key, fieldFormat)} position="right">
|
||||
<EuiText size="s" textAlign="right">
|
||||
<EuiText size="xs" textAlign="right" color="subdued">
|
||||
{kibanaFieldFormat(value.key, fieldFormat)}
|
||||
</EuiText>
|
||||
</EuiToolTip>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiProgress value={value.doc_count} max={progressBarMax} color={barColor} size="l" />
|
||||
<EuiProgress value={value.doc_count} max={progressBarMax} color={barColor} size="m" />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false} style={{ width: 70 }} className="eui-textTruncate">
|
||||
<EuiText size="s" textAlign="left">
|
||||
<EuiText size="xs" textAlign="left" color="subdued">
|
||||
{getPercentLabel(value.doc_count, progressBarMax)}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
|
|
|
@ -7,15 +7,17 @@
|
|||
import React, { FC } from 'react';
|
||||
|
||||
import {
|
||||
EuiCheckbox,
|
||||
EuiBadge,
|
||||
EuiFlexGrid,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiPanel,
|
||||
// @ts-ignore
|
||||
EuiSearchBar,
|
||||
EuiSpacer,
|
||||
EuiSwitch,
|
||||
EuiText,
|
||||
EuiTitle,
|
||||
EuiToolTip,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
@ -78,51 +80,62 @@ export const FieldsPanel: FC<Props> = ({
|
|||
}
|
||||
|
||||
return (
|
||||
<EuiPanel data-test-subj={`mlDataVisualizerFieldsPanel ${fieldTypes}`}>
|
||||
<EuiTitle>
|
||||
<h2>{title}</h2>
|
||||
</EuiTitle>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiFlexGroup alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<span>
|
||||
{showAllFields === true ? (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.fieldsPanel.showAllCountDescription"
|
||||
defaultMessage="{wrappedCardsCount} {cardsCount, plural, one {field} other {fields}} ({wrappedPopulatedFieldCount} {populatedFieldCount, plural, one {exists} other {exist}} in documents)"
|
||||
values={{
|
||||
cardsCount: fieldVisConfigs.length,
|
||||
wrappedCardsCount: <b>{fieldVisConfigs.length}</b>,
|
||||
populatedFieldCount,
|
||||
wrappedPopulatedFieldCount: <b>{populatedFieldCount}</b>,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.fieldsPanel.fieldsCountDescription"
|
||||
defaultMessage="{wrappedCardsCount} {cardsCount, plural, one {field exists} other {fields exist}} in documents ({wrappedTotalFieldCount} in total)"
|
||||
values={{
|
||||
cardsCount: fieldVisConfigs.length,
|
||||
wrappedCardsCount: <b>{fieldVisConfigs.length}</b>,
|
||||
wrappedTotalFieldCount: <b>{totalFieldCount}</b>,
|
||||
}}
|
||||
/>
|
||||
<div data-test-subj={`mlDataVisualizerFieldsPanel ${fieldTypes}`}>
|
||||
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween">
|
||||
<EuiFlexItem>
|
||||
<EuiFlexGroup alignItems="center" gutterSize="m">
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiTitle size="m">
|
||||
<h2>{title}</h2>
|
||||
</EuiTitle>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiToolTip
|
||||
position="top"
|
||||
content={
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.fieldsPanel.countDescription"
|
||||
defaultMessage="{cardsCount} {cardsCount, plural, one {field exists} other {fields exist}} in documents sampled"
|
||||
values={{ cardsCount: populatedFieldCount }}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiBadge title="">
|
||||
<b>{populatedFieldCount}</b>
|
||||
</EuiBadge>
|
||||
</EuiToolTip>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText size="s" color="subdued">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.fieldsPanel.totalFieldLabel"
|
||||
defaultMessage="Total fields: {wrappedTotalFields}"
|
||||
values={{
|
||||
wrappedTotalFields: <b>{totalFieldCount}</b>,
|
||||
}}
|
||||
/>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
{populatedFieldCount < totalFieldCount && (
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiSwitch
|
||||
id={`${title}_show_empty_fields`}
|
||||
label={i18n.translate(
|
||||
'xpack.ml.datavisualizer.fieldsPanel.showEmptyFieldsLabel',
|
||||
{
|
||||
defaultMessage: 'Show empty fields',
|
||||
}
|
||||
)}
|
||||
checked={showAllFields}
|
||||
onChange={onShowAllFieldsChange}
|
||||
data-test-subj="mlDataVisualizerShowEmptyFieldsCheckbox"
|
||||
compressed
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</span>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
{populatedFieldCount < totalFieldCount && (
|
||||
<EuiFlexItem>
|
||||
<EuiCheckbox
|
||||
id={`${title}_show_empty_fields`}
|
||||
label={i18n.translate('xpack.ml.datavisualizer.fieldsPanel.showEmptyFieldsLabel', {
|
||||
defaultMessage: 'show empty fields',
|
||||
})}
|
||||
checked={showAllFields}
|
||||
onChange={onShowAllFieldsChange}
|
||||
data-test-subj="mlDataVisualizerShowEmptyFieldsCheckbox"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
|
||||
<EuiFlexItem grow={true}>
|
||||
<EuiFlexGroup alignItems="center" gutterSize="m" direction="rowReverse">
|
||||
<EuiFlexItem
|
||||
|
@ -135,9 +148,7 @@ export const FieldsPanel: FC<Props> = ({
|
|||
box={{
|
||||
placeholder: i18n.translate(
|
||||
'xpack.ml.datavisualizer.fieldsPanel.filterFieldsPlaceholder',
|
||||
{
|
||||
defaultMessage: 'filter',
|
||||
}
|
||||
{ defaultMessage: 'Filter {type}', values: { type: title } }
|
||||
),
|
||||
}}
|
||||
onChange={onSearchBarChange}
|
||||
|
@ -156,14 +167,19 @@ export const FieldsPanel: FC<Props> = ({
|
|||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer size="s" />
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFlexGrid gutterSize="m">
|
||||
{fieldVisConfigs.map((visConfig, i) => (
|
||||
<EuiFlexItem key={`card_${i}`} style={{ minWidth: '360px' }}>
|
||||
<FieldDataCard config={visConfig} />
|
||||
</EuiFlexItem>
|
||||
))}
|
||||
{fieldVisConfigs
|
||||
.filter(({ stats }) => stats !== undefined)
|
||||
.map((visConfig, i) => (
|
||||
<EuiFlexItem
|
||||
key={`${visConfig.fieldName}_${visConfig.stats.count}`}
|
||||
style={{ minWidth: '360px' }}
|
||||
>
|
||||
<FieldDataCard config={visConfig} />
|
||||
</EuiFlexItem>
|
||||
))}
|
||||
</EuiFlexGrid>
|
||||
</EuiPanel>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -13,9 +13,8 @@ import {
|
|||
EuiForm,
|
||||
EuiFormRow,
|
||||
EuiIconTip,
|
||||
EuiPanel,
|
||||
EuiSelect,
|
||||
EuiSpacer,
|
||||
EuiSuperSelect,
|
||||
EuiText,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
@ -41,6 +40,25 @@ interface Props {
|
|||
totalCount: number;
|
||||
}
|
||||
|
||||
const searchSizeOptions = [1000, 5000, 10000, 100000, -1].map(v => {
|
||||
return {
|
||||
value: String(v),
|
||||
inputDisplay:
|
||||
v > 0 ? (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.searchPanel.sampleSizeOptionLabel"
|
||||
defaultMessage="Sample size (per shard): {wrappedValue}"
|
||||
values={{ wrappedValue: <b>{v}</b> }}
|
||||
/>
|
||||
) : (
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.searchPanel.allOptionLabel"
|
||||
defaultMessage="Search all"
|
||||
/>
|
||||
),
|
||||
};
|
||||
});
|
||||
|
||||
export const SearchPanel: FC<Props> = ({
|
||||
indexPattern,
|
||||
searchString,
|
||||
|
@ -52,94 +70,81 @@ export const SearchPanel: FC<Props> = ({
|
|||
setSamplerShardSize,
|
||||
totalCount,
|
||||
}) => {
|
||||
const searchAllOptionText = i18n.translate('xpack.ml.datavisualizer.searchPanel.allOptionLabel', {
|
||||
defaultMessage: 'all',
|
||||
});
|
||||
|
||||
const searchSizeOptions = [
|
||||
{ value: '1000', text: '1000' },
|
||||
{ value: '5000', text: '5000' },
|
||||
{ value: '10000', text: '10000' },
|
||||
{ value: '100000', text: '100000' },
|
||||
{ value: '-1', text: searchAllOptionText },
|
||||
];
|
||||
|
||||
const searchHandler = (d: Record<string, any>) => {
|
||||
setSearchQuery(d.filterQuery);
|
||||
};
|
||||
|
||||
return (
|
||||
<EuiPanel grow={false} data-test-subj="mlDataVisualizerSearchPanel">
|
||||
{searchQueryLanguage === SEARCH_QUERY_LANGUAGE.KUERY ? (
|
||||
<KqlFilterBar
|
||||
indexPattern={indexPattern}
|
||||
onSubmit={searchHandler}
|
||||
initialValue={searchString}
|
||||
placeholder={i18n.translate(
|
||||
'xpack.ml.datavisualizer.searchPanel.queryBarPlaceholderText',
|
||||
{
|
||||
defaultMessage: 'Search… (e.g. status:200 AND extension:"PHP")',
|
||||
}
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<EuiForm>
|
||||
<EuiFormRow
|
||||
helpText={i18n.translate('xpack.ml.datavisualizer.searchPanel.kqlEditOnlyLabel', {
|
||||
defaultMessage: 'Currently only KQL saved searches can be edited',
|
||||
})}
|
||||
>
|
||||
<EuiFieldSearch
|
||||
value={`${searchString}`}
|
||||
readOnly
|
||||
data-test-subj="mlDataVisualizerLuceneSearchBarl"
|
||||
<EuiFlexGroup gutterSize="m" alignItems="center" data-test-subj="mlDataVisualizerSearchPanel">
|
||||
<EuiFlexItem>
|
||||
{searchQueryLanguage === SEARCH_QUERY_LANGUAGE.KUERY ? (
|
||||
<KqlFilterBar
|
||||
indexPattern={indexPattern}
|
||||
onSubmit={searchHandler}
|
||||
initialValue={searchString}
|
||||
placeholder={i18n.translate(
|
||||
'xpack.ml.datavisualizer.searchPanel.queryBarPlaceholderText',
|
||||
{
|
||||
defaultMessage: 'Search… (e.g. status:200 AND extension:"PHP")',
|
||||
}
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<EuiForm>
|
||||
<EuiFormRow
|
||||
helpText={i18n.translate('xpack.ml.datavisualizer.searchPanel.kqlEditOnlyLabel', {
|
||||
defaultMessage: 'Currently only KQL saved searches can be edited',
|
||||
})}
|
||||
>
|
||||
<EuiFieldSearch
|
||||
value={`${searchString}`}
|
||||
readOnly
|
||||
data-test-subj="mlDataVisualizerLuceneSearchBarl"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiForm>
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiFlexGroup alignItems="center" gutterSize="s" responsive={false}>
|
||||
<EuiFlexItem grow={false} style={{ width: 270 }}>
|
||||
<EuiSuperSelect
|
||||
options={searchSizeOptions}
|
||||
valueOfSelected={String(samplerShardSize)}
|
||||
onChange={value => setSamplerShardSize(+value)}
|
||||
aria-label={i18n.translate(
|
||||
'xpack.ml.datavisualizer.searchPanel.sampleSizeAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Select number of documents to sample',
|
||||
}
|
||||
)}
|
||||
data-test-subj="mlDataVisualizerShardSizeSelect"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiForm>
|
||||
)}
|
||||
<EuiSpacer size="l" />
|
||||
<EuiFlexGroup gutterSize="xs" alignItems="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIconTip
|
||||
content={i18n.translate('xpack.ml.datavisualizer.searchPanel.queryBarPlaceholder', {
|
||||
defaultMessage:
|
||||
'Selecting a smaller sample size will reduce query run times and the load on the cluster.',
|
||||
})}
|
||||
position="right"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText size="s">
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.searchPanel.sampleLabel"
|
||||
defaultMessage="Sample"
|
||||
id="xpack.ml.datavisualizer.searchPanel.documentsPerShardLabel"
|
||||
defaultMessage="Total documents: {wrappedTotalCount}"
|
||||
values={{
|
||||
wrappedTotalCount: <b data-test-subj="mlDataVisualizerTotalDocCount">{totalCount}</b>,
|
||||
}}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiSelect
|
||||
options={searchSizeOptions}
|
||||
value={samplerShardSize}
|
||||
onChange={e => setSamplerShardSize(+e.target.value)}
|
||||
aria-label={i18n.translate('xpack.ml.datavisualizer.searchPanel.sampleSizeAriaLabel', {
|
||||
defaultMessage: 'Select number of documents to sample',
|
||||
})}
|
||||
data-test-subj="mlDataVisualizerShardSizeSelect"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.datavisualizer.searchPanel.documentsPerShardLabel"
|
||||
defaultMessage="documents per shard from a total of {wrappedTotalCount} {totalCount, plural, one {document} other {documents}}"
|
||||
values={{
|
||||
wrappedTotalCount: (
|
||||
<b data-test-subj="mlDataVisualizerTotalDocCount">{totalCount}</b>
|
||||
),
|
||||
totalCount,
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIconTip
|
||||
content={i18n.translate('xpack.ml.datavisualizer.searchPanel.queryBarPlaceholder', {
|
||||
defaultMessage:
|
||||
'Selecting a smaller sample size will reduce query run times and the load on the cluster.',
|
||||
})}
|
||||
position="right"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false} />
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -13,11 +13,13 @@ import { timefilter } from 'ui/timefilter';
|
|||
import {
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiHorizontalRule,
|
||||
EuiPage,
|
||||
EuiPageBody,
|
||||
EuiPageContentBody,
|
||||
EuiPageContentHeader,
|
||||
EuiPageContentHeaderSection,
|
||||
EuiPanel,
|
||||
EuiSpacer,
|
||||
EuiTitle,
|
||||
} from '@elastic/eui';
|
||||
|
@ -585,84 +587,96 @@ export const Page: FC = () => {
|
|||
setNonMetricConfigs(configs);
|
||||
}
|
||||
|
||||
const wizardPanelWidth = '280px';
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<NavigationMenu tabId="datavisualizer" />
|
||||
<EuiPage data-test-subj="mlPageIndexDataVisualizer">
|
||||
<EuiPageBody>
|
||||
<EuiPageContentHeader>
|
||||
<EuiPageContentHeaderSection>
|
||||
<EuiTitle size="l">
|
||||
<h1>{currentIndexPattern.title}</h1>
|
||||
</EuiTitle>
|
||||
</EuiPageContentHeaderSection>
|
||||
{currentIndexPattern.timeFieldName !== undefined && (
|
||||
<EuiPageContentHeaderSection data-test-subj="mlDataVisualizerTimeRangeSelectorSection">
|
||||
<FullTimeRangeSelector
|
||||
indexPattern={currentIndexPattern}
|
||||
query={combinedQuery}
|
||||
disabled={false}
|
||||
/>
|
||||
</EuiPageContentHeaderSection>
|
||||
)}
|
||||
</EuiPageContentHeader>
|
||||
<EuiFlexGroup gutterSize="m">
|
||||
<EuiFlexItem>
|
||||
<EuiPageContentHeader>
|
||||
<EuiPageContentHeaderSection>
|
||||
<EuiTitle size="l">
|
||||
<h1>{currentIndexPattern.title}</h1>
|
||||
</EuiTitle>
|
||||
</EuiPageContentHeaderSection>
|
||||
{currentIndexPattern.timeFieldName !== undefined && (
|
||||
<EuiPageContentHeaderSection data-test-subj="mlDataVisualizerTimeRangeSelectorSection">
|
||||
<FullTimeRangeSelector
|
||||
indexPattern={currentIndexPattern}
|
||||
query={combinedQuery}
|
||||
disabled={false}
|
||||
/>
|
||||
</EuiPageContentHeaderSection>
|
||||
)}
|
||||
</EuiPageContentHeader>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false} style={{ width: wizardPanelWidth }} />
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiPageContentBody>
|
||||
<EuiFlexGroup gutterSize="m">
|
||||
<EuiFlexItem>
|
||||
<SearchPanel
|
||||
indexPattern={currentIndexPattern}
|
||||
searchString={searchString}
|
||||
setSearchString={setSearchString}
|
||||
searchQuery={searchQuery}
|
||||
setSearchQuery={setSearchQuery}
|
||||
searchQueryLanguage={searchQueryLanguage}
|
||||
samplerShardSize={samplerShardSize}
|
||||
setSamplerShardSize={setSamplerShardSize}
|
||||
totalCount={overallStats.totalCount}
|
||||
/>
|
||||
<EuiSpacer size="m" />
|
||||
<EuiFlexGroup gutterSize="m">
|
||||
<EuiFlexItem>
|
||||
{totalMetricFieldCount > 0 && (
|
||||
<Fragment>
|
||||
<FieldsPanel
|
||||
title={i18n.translate('xpack.ml.datavisualizer.page.metricsPanelTitle', {
|
||||
defaultMessage: 'Metrics',
|
||||
})}
|
||||
totalFieldCount={totalMetricFieldCount}
|
||||
populatedFieldCount={populatedMetricFieldCount}
|
||||
fieldTypes={[ML_JOB_FIELD_TYPES.NUMBER]}
|
||||
showFieldType={ML_JOB_FIELD_TYPES.NUMBER}
|
||||
showAllFields={showAllMetrics}
|
||||
setShowAllFields={setShowAllMetrics}
|
||||
fieldSearchBarQuery={metricFieldQuery}
|
||||
setFieldSearchBarQuery={setMetricFieldQuery}
|
||||
fieldVisConfigs={metricConfigs}
|
||||
/>
|
||||
<EuiSpacer size="m" />
|
||||
</Fragment>
|
||||
)}
|
||||
<FieldsPanel
|
||||
title={i18n.translate('xpack.ml.datavisualizer.page.fieldsPanelTitle', {
|
||||
defaultMessage: 'Fields',
|
||||
})}
|
||||
totalFieldCount={totalNonMetricFieldCount}
|
||||
populatedFieldCount={populatedNonMetricFieldCount}
|
||||
showAllFields={showAllNonMetrics}
|
||||
setShowAllFields={setShowAllNonMetrics}
|
||||
fieldTypes={indexedFieldTypes}
|
||||
showFieldType={nonMetricShowFieldType}
|
||||
setShowFieldType={setNonMetricShowFieldType}
|
||||
fieldSearchBarQuery={nonMetricFieldQuery}
|
||||
setFieldSearchBarQuery={setNonMetricFieldQuery}
|
||||
fieldVisConfigs={nonMetricConfigs}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiPanel>
|
||||
<SearchPanel
|
||||
indexPattern={currentIndexPattern}
|
||||
searchString={searchString}
|
||||
setSearchString={setSearchString}
|
||||
searchQuery={searchQuery}
|
||||
setSearchQuery={setSearchQuery}
|
||||
searchQueryLanguage={searchQueryLanguage}
|
||||
samplerShardSize={samplerShardSize}
|
||||
setSamplerShardSize={setSamplerShardSize}
|
||||
totalCount={overallStats.totalCount}
|
||||
/>
|
||||
<EuiHorizontalRule />
|
||||
<EuiFlexGroup gutterSize="m">
|
||||
<EuiFlexItem>
|
||||
{totalMetricFieldCount > 0 && (
|
||||
<Fragment>
|
||||
<FieldsPanel
|
||||
title={i18n.translate(
|
||||
'xpack.ml.datavisualizer.page.metricsPanelTitle',
|
||||
{
|
||||
defaultMessage: 'Metrics',
|
||||
}
|
||||
)}
|
||||
totalFieldCount={totalMetricFieldCount}
|
||||
populatedFieldCount={populatedMetricFieldCount}
|
||||
fieldTypes={[ML_JOB_FIELD_TYPES.NUMBER]}
|
||||
showFieldType={ML_JOB_FIELD_TYPES.NUMBER}
|
||||
showAllFields={showAllMetrics}
|
||||
setShowAllFields={setShowAllMetrics}
|
||||
fieldSearchBarQuery={metricFieldQuery}
|
||||
setFieldSearchBarQuery={setMetricFieldQuery}
|
||||
fieldVisConfigs={metricConfigs}
|
||||
/>
|
||||
<EuiSpacer size="xl" />
|
||||
</Fragment>
|
||||
)}
|
||||
<FieldsPanel
|
||||
title={i18n.translate('xpack.ml.datavisualizer.page.fieldsPanelTitle', {
|
||||
defaultMessage: 'Fields',
|
||||
})}
|
||||
totalFieldCount={totalNonMetricFieldCount}
|
||||
populatedFieldCount={populatedNonMetricFieldCount}
|
||||
showAllFields={showAllNonMetrics}
|
||||
setShowAllFields={setShowAllNonMetrics}
|
||||
fieldTypes={indexedFieldTypes}
|
||||
showFieldType={nonMetricShowFieldType}
|
||||
setShowFieldType={setNonMetricShowFieldType}
|
||||
fieldSearchBarQuery={nonMetricFieldQuery}
|
||||
setFieldSearchBarQuery={setNonMetricFieldQuery}
|
||||
fieldVisConfigs={nonMetricConfigs}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiPanel>
|
||||
</EuiFlexItem>
|
||||
{showActionsPanel === true && (
|
||||
<EuiFlexItem grow={false} style={{ width: '280px' }}>
|
||||
<EuiFlexItem grow={false} style={{ width: wizardPanelWidth }}>
|
||||
<ActionsPanel indexPattern={currentIndexPattern} />
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
|
|
|
@ -7782,10 +7782,7 @@
|
|||
"xpack.ml.datavisualizer.actionsPanel.createJobTitle": "ジョブの作成",
|
||||
"xpack.ml.datavisualizer.actionsPanel.selectKnownConfigurationDescription": "認識されたデータの既知の構成を選択します:",
|
||||
"xpack.ml.datavisualizer.dataLoader.internalServerErrorMessage": "インデックス {index} のデータの読み込み中にエラーが発生。{message}。リクエストがタイムアウトした可能性があります。小さなサンプルサイズを使うか、時間範囲を狭めてみてください。",
|
||||
"xpack.ml.datavisualizer.fieldsPanel.fieldsCountDescription": "ドキュメントに {wrappedCardsCount} {cardsCount, plural, one {個のフィールドが存在します} other {個のフィールドが存在します}} (合計 {wrappedTotalFieldCount} 個)",
|
||||
"xpack.ml.datavisualizer.fieldsPanel.filterFieldsPlaceholder": "フィルター",
|
||||
"xpack.ml.datavisualizer.fieldsPanel.searchBarError": "検索の実行中にエラーが発生。{message}。",
|
||||
"xpack.ml.datavisualizer.fieldsPanel.showAllCountDescription": "{wrappedCardsCount} {cardsCount, plural, one {field} other {fields}} ({wrappedPopulatedFieldCount} {populatedFieldCount, plural, one {exists} other {exist}}ドキュメントに)",
|
||||
"xpack.ml.datavisualizer.fieldsPanel.showEmptyFieldsLabel": "空のフィールドを表示",
|
||||
"xpack.ml.datavisualizer.fieldTypesSelect.allFieldsTypeOptionLabel": "すべてのフィールドタイプ",
|
||||
"xpack.ml.datavisualizer.fieldTypesSelect.selectAriaLabel": "表示するフィールドタイプを選択してください",
|
||||
|
@ -7795,11 +7792,9 @@
|
|||
"xpack.ml.datavisualizer.page.fieldsPanelTitle": "フィールド",
|
||||
"xpack.ml.datavisualizer.page.metricsPanelTitle": "メトリック",
|
||||
"xpack.ml.datavisualizer.searchPanel.allOptionLabel": "すべて",
|
||||
"xpack.ml.datavisualizer.searchPanel.documentsPerShardLabel": "合計 {wrappedTotalCount} {totalCount, plural, one {document} other {documents}}からのシャードごとのドキュメント数",
|
||||
"xpack.ml.datavisualizer.searchPanel.kqlEditOnlyLabel": "現在 KQAL で保存された検索のみ編集できます。",
|
||||
"xpack.ml.datavisualizer.searchPanel.queryBarPlaceholder": "小さいサンプルサイズを選択することで、クエリの実行時間を短縮しクラスターへの負荷を軽減できます。",
|
||||
"xpack.ml.datavisualizer.searchPanel.queryBarPlaceholderText": "検索… (例: status:200 AND extension:\"PHP\")",
|
||||
"xpack.ml.datavisualizer.searchPanel.sampleLabel": "サンプル",
|
||||
"xpack.ml.datavisualizer.searchPanel.sampleSizeAriaLabel": "サンプリングするドキュメント数を選択してください",
|
||||
"xpack.ml.datavisualizer.selector.dataVisualizerDescription": "機械学習データビジュアライザーツールは、ログファイルのメトリックとフィールド、または既存の Elasticsearch インデックスを分析し、データの理解を助けます。",
|
||||
"xpack.ml.datavisualizer.selector.dataVisualizerTitle": "データビジュアライザー",
|
||||
|
|
|
@ -7781,10 +7781,7 @@
|
|||
"xpack.ml.datavisualizer.actionsPanel.createJobTitle": "创建作业",
|
||||
"xpack.ml.datavisualizer.actionsPanel.selectKnownConfigurationDescription": "选择已识别数据的已知配置:",
|
||||
"xpack.ml.datavisualizer.dataLoader.internalServerErrorMessage": "加载索引 {index} 中的数据时出错。{message}。请求可能已超时。请尝试使用较小的样例大小或缩小时间范围。",
|
||||
"xpack.ml.datavisualizer.fieldsPanel.fieldsCountDescription": "{wrappedCardsCount} {cardsCount, plural, one { 个字段存在} other { 个字段存在}}于文档中(共 {wrappedTotalFieldCount} 个)",
|
||||
"xpack.ml.datavisualizer.fieldsPanel.filterFieldsPlaceholder": "筛选",
|
||||
"xpack.ml.datavisualizer.fieldsPanel.searchBarError": "运行搜索时发生错误。{message}。",
|
||||
"xpack.ml.datavisualizer.fieldsPanel.showAllCountDescription": "{wrappedCardsCount} {cardsCount, plural, one { 个字段} other { 个字段}}({wrappedPopulatedFieldCount} {populatedFieldCount, plural, one { 存在} other { 存在}}于文档中)",
|
||||
"xpack.ml.datavisualizer.fieldsPanel.showEmptyFieldsLabel": "显示空字段",
|
||||
"xpack.ml.datavisualizer.fieldTypesSelect.allFieldsTypeOptionLabel": "所有字段类型",
|
||||
"xpack.ml.datavisualizer.fieldTypesSelect.selectAriaLabel": "选择要显示的字段类型",
|
||||
|
@ -7794,11 +7791,9 @@
|
|||
"xpack.ml.datavisualizer.page.fieldsPanelTitle": "字段",
|
||||
"xpack.ml.datavisualizer.page.metricsPanelTitle": "指标",
|
||||
"xpack.ml.datavisualizer.searchPanel.allOptionLabel": "全部",
|
||||
"xpack.ml.datavisualizer.searchPanel.documentsPerShardLabel": "每个分片的文档,共 {wrappedTotalCount} {totalCount, plural, one { 个文档 } other { 个文档}}",
|
||||
"xpack.ml.datavisualizer.searchPanel.kqlEditOnlyLabel": "当前仅可以编辑 KQL 已保存搜索",
|
||||
"xpack.ml.datavisualizer.searchPanel.queryBarPlaceholder": "选择较小的样例大小将减少查询运行时间和集群上的负载。",
|
||||
"xpack.ml.datavisualizer.searchPanel.queryBarPlaceholderText": "搜索……(例如,status:200 AND extension:\"PHP\")",
|
||||
"xpack.ml.datavisualizer.searchPanel.sampleLabel": "采样",
|
||||
"xpack.ml.datavisualizer.searchPanel.sampleSizeAriaLabel": "选择要采样的文档数目",
|
||||
"xpack.ml.datavisualizer.selector.dataVisualizerDescription": "Machine Learning Data Visualizer 工具通过分析日志文件或现有 Elasticsearch 索引中的指标和字段,帮助您理解数据。",
|
||||
"xpack.ml.datavisualizer.selector.dataVisualizerTitle": "数据可视化工具",
|
||||
|
|
Loading…
Reference in a new issue