mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
This commit is contained in:
parent
1223d666f4
commit
885af43ba1
20 changed files with 210 additions and 276 deletions
|
@ -23,7 +23,6 @@
|
|||
@import 'components/controls/index';
|
||||
@import 'components/entity_cell/index';
|
||||
@import 'components/field_title_bar/index';
|
||||
@import 'components/field_type_icon/index';
|
||||
@import 'components/influencers_list/index';
|
||||
@import 'components/items_grid/index';
|
||||
@import 'components/job_selector/index';
|
||||
|
|
|
@ -120,8 +120,6 @@ export const renderApp = (
|
|||
urlGenerators: deps.share.urlGenerators,
|
||||
});
|
||||
|
||||
deps.kibanaLegacy.loadFontAwesome();
|
||||
|
||||
appMountParams.onAppLeave((actions) => actions.default());
|
||||
|
||||
const mlLicense = setLicenseCache(deps.licensing, [
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
.field-type-icon {
|
||||
vertical-align: middle;
|
||||
padding-right: $euiSizeXS;
|
||||
margin-bottom: -$euiSizeXS;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,26 +5,22 @@
|
|||
*/
|
||||
|
||||
import { mountWithIntl } from '@kbn/test/jest';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { FieldTitleBar } from './field_title_bar';
|
||||
|
||||
// helper to let PropTypes throw errors instead of just doing console.error()
|
||||
const error = console.error;
|
||||
console.error = (warning, ...args) => {
|
||||
if (/(Invalid prop|Failed prop type)/gi.test(warning)) {
|
||||
throw new Error(warning);
|
||||
}
|
||||
error.apply(console, [warning, ...args]);
|
||||
};
|
||||
import { ML_JOB_FIELD_TYPES } from '../../../../common/constants/field_types';
|
||||
|
||||
describe('FieldTitleBar', () => {
|
||||
test(`throws an error because card is a required prop`, () => {
|
||||
expect(() => <FieldTitleBar />).toThrow();
|
||||
});
|
||||
|
||||
test(`card prop is an empty object`, () => {
|
||||
const props = { card: {} };
|
||||
const props = {
|
||||
card: {
|
||||
type: ML_JOB_FIELD_TYPES.NUMBER,
|
||||
existsInDocs: true,
|
||||
loading: false,
|
||||
aggregatable: true,
|
||||
},
|
||||
};
|
||||
|
||||
const wrapper = mountWithIntl(<FieldTitleBar {...props} />);
|
||||
|
||||
|
@ -36,29 +32,43 @@ describe('FieldTitleBar', () => {
|
|||
});
|
||||
|
||||
test(`card.isUnsupportedType is true`, () => {
|
||||
const testFieldName = 'foo';
|
||||
const props = { card: { fieldName: testFieldName, isUnsupportedType: true } };
|
||||
const props = {
|
||||
card: {
|
||||
type: ML_JOB_FIELD_TYPES.UNKNOWN,
|
||||
fieldName: 'foo',
|
||||
existsInDocs: true,
|
||||
loading: false,
|
||||
aggregatable: true,
|
||||
isUnsupportedType: true,
|
||||
},
|
||||
};
|
||||
|
||||
const wrapper = mountWithIntl(<FieldTitleBar {...props} />);
|
||||
|
||||
const fieldName = wrapper.find({ className: 'field-name' }).text();
|
||||
expect(fieldName).toEqual(testFieldName);
|
||||
expect(fieldName).toEqual(props.card.fieldName);
|
||||
|
||||
const hasClassName = wrapper.find('EuiText').hasClass('type-other');
|
||||
expect(hasClassName).toBeTruthy();
|
||||
});
|
||||
|
||||
test(`card.fieldName and card.type is set`, () => {
|
||||
const testFieldName = 'foo';
|
||||
const testType = 'bar';
|
||||
const props = { card: { fieldName: testFieldName, type: testType } };
|
||||
const props = {
|
||||
card: {
|
||||
type: ML_JOB_FIELD_TYPES.KEYWORD,
|
||||
fieldName: 'bar',
|
||||
existsInDocs: true,
|
||||
loading: false,
|
||||
aggregatable: true,
|
||||
},
|
||||
};
|
||||
|
||||
const wrapper = mountWithIntl(<FieldTitleBar {...props} />);
|
||||
|
||||
const fieldName = wrapper.find({ className: 'field-name' }).text();
|
||||
expect(fieldName).toEqual(testFieldName);
|
||||
expect(fieldName).toEqual(props.card.fieldName);
|
||||
|
||||
const hasClassName = wrapper.find('EuiText').hasClass(testType);
|
||||
const hasClassName = wrapper.find('EuiText').hasClass(props.card.type);
|
||||
expect(hasClassName).toBeTruthy();
|
||||
});
|
||||
|
||||
|
@ -66,11 +76,19 @@ describe('FieldTitleBar', () => {
|
|||
// Use fake timers so we don't have to wait for the EuiToolTip timeout
|
||||
jest.useFakeTimers();
|
||||
|
||||
const props = { card: { fieldName: 'foo', type: 'bar' } };
|
||||
const props = {
|
||||
card: {
|
||||
type: ML_JOB_FIELD_TYPES.KEYWORD,
|
||||
fieldName: 'bar',
|
||||
existsInDocs: true,
|
||||
loading: false,
|
||||
aggregatable: true,
|
||||
},
|
||||
};
|
||||
const wrapper = mountWithIntl(<FieldTitleBar {...props} />);
|
||||
const container = wrapper.find({ className: 'field-name' });
|
||||
|
||||
expect(wrapper.find('EuiToolTip').children()).toHaveLength(1);
|
||||
expect(wrapper.find('EuiToolTip').children()).toHaveLength(2);
|
||||
|
||||
container.simulate('mouseover');
|
||||
|
||||
|
@ -78,7 +96,7 @@ describe('FieldTitleBar', () => {
|
|||
jest.runAllTimers();
|
||||
|
||||
wrapper.update();
|
||||
expect(wrapper.find('EuiToolTip').children()).toHaveLength(2);
|
||||
expect(wrapper.find('EuiToolTip').children()).toHaveLength(3);
|
||||
|
||||
container.simulate('mouseout');
|
||||
|
||||
|
@ -86,7 +104,7 @@ describe('FieldTitleBar', () => {
|
|||
jest.runAllTimers();
|
||||
|
||||
wrapper.update();
|
||||
expect(wrapper.find('EuiToolTip').children()).toHaveLength(1);
|
||||
expect(wrapper.find('EuiToolTip').children()).toHaveLength(2);
|
||||
|
||||
// Clearing all mocks will also reset fake timers.
|
||||
jest.clearAllMocks();
|
|
@ -4,21 +4,21 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import React, { FC } from 'react';
|
||||
|
||||
import { EuiText, EuiToolTip } from '@elastic/eui';
|
||||
|
||||
import { FieldTypeIcon } from '../field_type_icon';
|
||||
import { getMLJobTypeAriaLabel } from '../../util/field_types_utils';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export function FieldTitleBar({ card }) {
|
||||
// don't render and fail gracefully if card prop isn't set
|
||||
if (typeof card !== 'object' || card === null) {
|
||||
return null;
|
||||
}
|
||||
import { FieldTypeIcon } from '../field_type_icon';
|
||||
import { FieldVisConfig } from '../../datavisualizer/index_based/common';
|
||||
import { getMLJobTypeAriaLabel } from '../../util/field_types_utils';
|
||||
|
||||
interface Props {
|
||||
card: FieldVisConfig;
|
||||
}
|
||||
|
||||
export const FieldTitleBar: FC<Props> = ({ card }) => {
|
||||
const fieldName =
|
||||
card.fieldName ||
|
||||
i18n.translate('xpack.ml.fieldTitleBar.documentCountLabel', {
|
||||
|
@ -37,20 +37,23 @@ export function FieldTitleBar({ card }) {
|
|||
}
|
||||
|
||||
if (card.isUnsupportedType !== true) {
|
||||
cardTitleAriaLabel.unshift(getMLJobTypeAriaLabel(card.type));
|
||||
// All the supported field types have aria labels.
|
||||
cardTitleAriaLabel.unshift(getMLJobTypeAriaLabel(card.type)!);
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiText className={classNames.join(' ')}>
|
||||
<FieldTypeIcon type={card.type} tooltipEnabled={true} needsAria={false} />
|
||||
<FieldTypeIcon
|
||||
type={card.type}
|
||||
fieldName={card.fieldName}
|
||||
tooltipEnabled={true}
|
||||
needsAria={false}
|
||||
/>
|
||||
<EuiToolTip position="left" content={fieldName}>
|
||||
<div className="field-name" tabIndex="0" aria-label={`${cardTitleAriaLabel.join(', ')}`}>
|
||||
<div className="field-name" tabIndex={0} aria-label={`${cardTitleAriaLabel.join(', ')}`}>
|
||||
{fieldName}
|
||||
</div>
|
||||
</EuiToolTip>
|
||||
</EuiText>
|
||||
);
|
||||
}
|
||||
FieldTitleBar.propTypes = {
|
||||
card: PropTypes.object.isRequired,
|
||||
};
|
|
@ -1,19 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`FieldTypeIcon render component when type matches a field type 1`] = `
|
||||
<FieldTypeIconContainer
|
||||
ariaLabel="keyword type"
|
||||
className="field-type-icon"
|
||||
iconChar="t"
|
||||
needsAria={true}
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`FieldTypeIcon update component 1`] = `
|
||||
<FieldTypeIconContainer
|
||||
ariaLabel="ip type"
|
||||
className="field-type-icon kuiIcon fa-laptop"
|
||||
iconChar=""
|
||||
needsAria={true}
|
||||
/>
|
||||
`;
|
|
@ -0,0 +1,16 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`FieldTypeIcon render component when type matches a field type 1`] = `
|
||||
<EuiToolTip
|
||||
content="keyword type"
|
||||
delay="regular"
|
||||
position="left"
|
||||
>
|
||||
<FieldTypeIconContainer
|
||||
ariaLabel="keyword type"
|
||||
color="euiColorVis0"
|
||||
iconType="tokenText"
|
||||
needsAria={false}
|
||||
/>
|
||||
</EuiToolTip>
|
||||
`;
|
|
@ -1,22 +0,0 @@
|
|||
$icon-size: 20px;
|
||||
|
||||
.field-type-icon-container {
|
||||
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;
|
||||
position: relative;
|
||||
|
||||
.field-type-icon {
|
||||
padding: 0;
|
||||
display: inline-block !important;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
@import 'field_type_icon';
|
|
@ -11,18 +11,10 @@ import { FieldTypeIcon } from './field_type_icon';
|
|||
import { ML_JOB_FIELD_TYPES } from '../../../../common/constants/field_types';
|
||||
|
||||
describe('FieldTypeIcon', () => {
|
||||
test(`don't render component when type is undefined`, () => {
|
||||
const typeIconComponent = shallow(<FieldTypeIcon />);
|
||||
expect(typeIconComponent.isEmptyRender()).toBeTruthy();
|
||||
});
|
||||
|
||||
test(`don't render component when type doesn't match a field type`, () => {
|
||||
const typeIconComponent = shallow(<FieldTypeIcon type="foo" />);
|
||||
expect(typeIconComponent.isEmptyRender()).toBeTruthy();
|
||||
});
|
||||
|
||||
test(`render component when type matches a field type`, () => {
|
||||
const typeIconComponent = shallow(<FieldTypeIcon type={ML_JOB_FIELD_TYPES.KEYWORD} />);
|
||||
const typeIconComponent = shallow(
|
||||
<FieldTypeIcon type={ML_JOB_FIELD_TYPES.KEYWORD} tooltipEnabled={true} needsAria={false} />
|
||||
);
|
||||
expect(typeIconComponent).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
@ -31,9 +23,9 @@ describe('FieldTypeIcon', () => {
|
|||
jest.useFakeTimers();
|
||||
|
||||
const typeIconComponent = mount(
|
||||
<FieldTypeIcon type={ML_JOB_FIELD_TYPES.KEYWORD} tooltipEnabled={true} />
|
||||
<FieldTypeIcon type={ML_JOB_FIELD_TYPES.KEYWORD} tooltipEnabled={true} needsAria={false} />
|
||||
);
|
||||
const container = typeIconComponent.find({ className: 'field-type-icon-container' });
|
||||
const container = typeIconComponent.find({ 'data-test-subj': 'mlFieldTypeIcon' });
|
||||
|
||||
expect(typeIconComponent.find('EuiToolTip').children()).toHaveLength(1);
|
||||
|
||||
|
@ -56,11 +48,4 @@ describe('FieldTypeIcon', () => {
|
|||
// Clearing all mocks will also reset fake timers.
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test(`update component`, () => {
|
||||
const typeIconComponent = shallow(<FieldTypeIcon />);
|
||||
expect(typeIconComponent.isEmptyRender()).toBeTruthy();
|
||||
typeIconComponent.setProps({ type: ML_JOB_FIELD_TYPES.IP });
|
||||
expect(typeIconComponent).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -4,63 +4,80 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import React, { FC } from 'react';
|
||||
|
||||
import { EuiToolTip } from '@elastic/eui';
|
||||
import { EuiToken, EuiToolTip } from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { getMLJobTypeAriaLabel } from '../../util/field_types_utils';
|
||||
import { ML_JOB_FIELD_TYPES } from '../../../../common/constants/field_types';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export const FieldTypeIcon = ({ tooltipEnabled = false, type, needsAria = true }) => {
|
||||
interface FieldTypeIconProps {
|
||||
tooltipEnabled: boolean;
|
||||
type: ML_JOB_FIELD_TYPES;
|
||||
fieldName?: string;
|
||||
needsAria: boolean;
|
||||
}
|
||||
|
||||
interface FieldTypeIconContainerProps {
|
||||
ariaLabel: string | null;
|
||||
iconType: string;
|
||||
color: string;
|
||||
needsAria: boolean;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export const FieldTypeIcon: FC<FieldTypeIconProps> = ({
|
||||
tooltipEnabled = false,
|
||||
type,
|
||||
fieldName,
|
||||
needsAria = true,
|
||||
}) => {
|
||||
const ariaLabel = getMLJobTypeAriaLabel(type);
|
||||
|
||||
if (ariaLabel === null) {
|
||||
// All ml job field types should have associated aria labels.
|
||||
// Once it is missing, it means that the passed *type* is not a valid field type.
|
||||
// if type doesn't match one of ML_JOB_FIELD_TYPES
|
||||
// don't render the component at all
|
||||
return null;
|
||||
}
|
||||
|
||||
const iconClass = ['field-type-icon'];
|
||||
let iconChar = '';
|
||||
let iconType = 'questionInCircle';
|
||||
let color = 'euiColorVis6';
|
||||
|
||||
switch (type) {
|
||||
// icon class names
|
||||
// Set icon types and colors
|
||||
case ML_JOB_FIELD_TYPES.BOOLEAN:
|
||||
iconClass.push('kuiIcon', 'fa-adjust');
|
||||
iconType = 'tokenBoolean';
|
||||
color = 'euiColorVis5';
|
||||
break;
|
||||
case ML_JOB_FIELD_TYPES.DATE:
|
||||
iconClass.push('kuiIcon', 'fa-clock-o');
|
||||
iconType = 'tokenDate';
|
||||
color = 'euiColorVis7';
|
||||
break;
|
||||
case ML_JOB_FIELD_TYPES.GEO_POINT:
|
||||
iconClass.push('kuiIcon', 'fa-globe');
|
||||
iconType = 'tokenGeo';
|
||||
color = 'euiColorVis8';
|
||||
break;
|
||||
case ML_JOB_FIELD_TYPES.TEXT:
|
||||
iconClass.push('kuiIcon', 'fa-file-text-o');
|
||||
iconType = 'document';
|
||||
color = 'euiColorVis9';
|
||||
break;
|
||||
case ML_JOB_FIELD_TYPES.IP:
|
||||
iconClass.push('kuiIcon', 'fa-laptop');
|
||||
iconType = 'tokenIP';
|
||||
color = 'euiColorVis3';
|
||||
break;
|
||||
|
||||
// icon chars
|
||||
case ML_JOB_FIELD_TYPES.KEYWORD:
|
||||
iconChar = 't';
|
||||
iconType = 'tokenText';
|
||||
color = 'euiColorVis0';
|
||||
break;
|
||||
case ML_JOB_FIELD_TYPES.NUMBER:
|
||||
iconChar = '#';
|
||||
iconType = 'tokenNumber';
|
||||
color = fieldName !== undefined ? 'euiColorVis1' : 'euiColorVis2';
|
||||
break;
|
||||
case ML_JOB_FIELD_TYPES.UNKNOWN:
|
||||
iconChar = '?';
|
||||
// Use defaults
|
||||
break;
|
||||
}
|
||||
|
||||
const containerProps = {
|
||||
ariaLabel,
|
||||
className: iconClass.join(' '),
|
||||
iconChar,
|
||||
iconType,
|
||||
color,
|
||||
needsAria,
|
||||
};
|
||||
|
||||
|
@ -84,28 +101,27 @@ export const FieldTypeIcon = ({ tooltipEnabled = false, type, needsAria = true }
|
|||
return <FieldTypeIconContainer {...containerProps} />;
|
||||
};
|
||||
|
||||
FieldTypeIcon.propTypes = {
|
||||
tooltipEnabled: PropTypes.bool,
|
||||
type: PropTypes.string,
|
||||
};
|
||||
|
||||
// If the tooltip is used, it will apply its events to its first inner child.
|
||||
// To pass on its properties we apply `rest` to the outer `span` element.
|
||||
function FieldTypeIconContainer({ ariaLabel, className, iconChar, needsAria, ...rest }) {
|
||||
const wrapperProps = { className };
|
||||
const FieldTypeIconContainer: FC<FieldTypeIconContainerProps> = ({
|
||||
ariaLabel,
|
||||
iconType,
|
||||
color,
|
||||
needsAria,
|
||||
...rest
|
||||
}) => {
|
||||
const wrapperProps: { className: string; 'aria-label'?: string } = {
|
||||
className: 'field-type-icon',
|
||||
};
|
||||
if (needsAria && ariaLabel) {
|
||||
wrapperProps['aria-label'] = ariaLabel;
|
||||
}
|
||||
|
||||
return (
|
||||
<span className="field-type-icon-container" {...rest}>
|
||||
{iconChar === '' ? (
|
||||
<span {...wrapperProps} />
|
||||
) : (
|
||||
<span {...wrapperProps}>
|
||||
<strong aria-hidden="true">{iconChar}</strong>
|
||||
</span>
|
||||
)}
|
||||
<span data-test-subj="mlFieldTypeIcon" {...rest}>
|
||||
<span {...wrapperProps}>
|
||||
<EuiToken iconType={iconType} shape="square" size="s" color={color} />
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
};
|
|
@ -15,83 +15,47 @@
|
|||
.boolean {
|
||||
color: $euiColorVis5;
|
||||
border-color: $euiColorVis5;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis5, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.date {
|
||||
color: $euiColorVis7;
|
||||
border-color: $euiColorVis7;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis7, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.document_count {
|
||||
color: $euiColorVis2;
|
||||
border-color: $euiColorVis2;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis2, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.geo_point {
|
||||
color: $euiColorVis8;
|
||||
border-color: $euiColorVis8;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis8, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.ip {
|
||||
color: $euiColorVis3;
|
||||
border-color: $euiColorVis3;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis3, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.keyword {
|
||||
color: $euiColorVis0;
|
||||
border-color: $euiColorVis0;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis0, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.number {
|
||||
color: $euiColorVis1;
|
||||
border-color: $euiColorVis1;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis1, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
color: $euiColorVis9;
|
||||
border-color: $euiColorVis9;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis9, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.type-other,
|
||||
.unknown {
|
||||
color: $euiColorVis6;
|
||||
border-color: $euiColorVis6;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis6, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
// Use euiPanel styling
|
||||
|
|
|
@ -5,7 +5,15 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiSpacer, EuiPanel, EuiFlexGroup, EuiFlexItem, EuiText, EuiProgress } from '@elastic/eui';
|
||||
import {
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiIcon,
|
||||
EuiPanel,
|
||||
EuiProgress,
|
||||
EuiSpacer,
|
||||
EuiText,
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { FieldTypeIcon } from '../../../../components/field_type_icon';
|
||||
|
@ -28,7 +36,7 @@ export function FieldStatsCard({ field }) {
|
|||
<EuiPanel hasShadow={false} className="mlFieldDataCard">
|
||||
<div className="ml-field-data-card" data-test-subj="mlPageFileDataVisFieldDataCard">
|
||||
<div className={`ml-field-title-bar ${type}`}>
|
||||
<FieldTypeIcon type={type} needsAria={false} />
|
||||
<FieldTypeIcon type={type} needsAria={false} fieldName={field.name} />
|
||||
<div className="field-name" tabIndex="0" aria-label={`${cardTitleAriaLabel.join(', ')}`}>
|
||||
{field.name}
|
||||
</div>
|
||||
|
@ -38,29 +46,45 @@ export function FieldStatsCard({ field }) {
|
|||
{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>
|
||||
<EuiFlexGroup
|
||||
gutterSize="xs"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
className="stat"
|
||||
>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIcon type="document" />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fieldStatsCard.documentsCountDescription"
|
||||
defaultMessage="{fieldCount, plural, zero {# document} one {# document} other {# documents}} ({fieldPercent}%)"
|
||||
values={{
|
||||
fieldCount: field.count,
|
||||
fieldPercent: field.percent,
|
||||
}}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiFlexGroup
|
||||
gutterSize="xs"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
className="stat"
|
||||
>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiIcon type="database" />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<FormattedMessage
|
||||
id="xpack.ml.fileDatavisualizer.fieldStatsCard.distinctCountDescription"
|
||||
defaultMessage="{fieldCardinality} distinct {fieldCardinality, plural, zero {value} one {value} other {values}}"
|
||||
values={{
|
||||
fieldCardinality: field.cardinality,
|
||||
}}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
|
||||
{field.median_value && (
|
||||
<React.Fragment>
|
||||
|
|
|
@ -7,83 +7,47 @@
|
|||
.boolean {
|
||||
color: $euiColorVis5;
|
||||
border-color: $euiColorVis5;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis5, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.date {
|
||||
color: $euiColorVis7;
|
||||
border-color: $euiColorVis7;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis7, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.document_count {
|
||||
color: $euiColorVis2;
|
||||
border-color: $euiColorVis2;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis2, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.geo_point {
|
||||
color: $euiColorVis8;
|
||||
border-color: $euiColorVis8;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis8, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.ip {
|
||||
color: $euiColorVis3;
|
||||
border-color: $euiColorVis3;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis3, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.keyword {
|
||||
color: $euiColorVis0;
|
||||
border-color: $euiColorVis0;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis0, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.number {
|
||||
color: $euiColorVis1;
|
||||
border-color: $euiColorVis1;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis1, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
color: $euiColorVis9;
|
||||
border-color: $euiColorVis9;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis9, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.type-other,
|
||||
.unknown {
|
||||
color: $euiColorVis6;
|
||||
border-color: $euiColorVis6;
|
||||
|
||||
.field-type-icon-container {
|
||||
background-color: rgba($euiColorVis6, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.mlFieldDataCard__content {
|
||||
|
|
|
@ -10,7 +10,6 @@ import React, { FC } from 'react';
|
|||
import { ML_JOB_FIELD_TYPES } from '../../../../../../common/constants/field_types';
|
||||
|
||||
import { FieldVisConfig } from '../../common';
|
||||
// @ts-ignore
|
||||
import { FieldTitleBar } from '../../../../components/field_title_bar/index';
|
||||
import {
|
||||
BooleanContent,
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
// SASSTODO: There is a lot of very specific sizing in here that look brittle to touch
|
||||
.explorer-charts {
|
||||
|
||||
ml-explorer-charts-container {
|
||||
|
||||
ml-explorer-charts-container {
|
||||
.row {
|
||||
padding: 10px;
|
||||
}
|
||||
|
@ -42,7 +40,7 @@
|
|||
padding: 0px 0px 2px 0px;
|
||||
}
|
||||
|
||||
table tr>td:first-child {
|
||||
table tr > td:first-child {
|
||||
padding-left: 2px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
@ -54,20 +52,13 @@
|
|||
td:nth-child(2) {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
// Hide filtering icons until that functionality is available.
|
||||
i.fa-search-plus, i.fa-search-minus {
|
||||
display: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* wrapper class for the top right alert icon and view button */
|
||||
.ml-explorer-chart-icons {
|
||||
float:right;
|
||||
float: right;
|
||||
padding-left: 5px;
|
||||
/* counter-margin for EuiButtonEmpty's padding */
|
||||
margin: 2px -8px 0 0;
|
||||
|
|
|
@ -166,7 +166,6 @@
|
|||
}
|
||||
|
||||
.forecast {
|
||||
|
||||
.metric-value,
|
||||
.metric-value:hover {
|
||||
stroke: #cca300;
|
||||
|
@ -201,7 +200,6 @@
|
|||
a:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -246,7 +244,6 @@
|
|||
stroke-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.swimlane .axis text {
|
||||
|
@ -290,10 +287,8 @@
|
|||
text-align: center;
|
||||
cursor: ew-resize;
|
||||
margin-top: 9px;
|
||||
|
||||
i.fa {
|
||||
margin-top: 30px;
|
||||
}
|
||||
font-size: $euiFontSizeS;
|
||||
fill: $euiColorDarkShade;
|
||||
}
|
||||
|
||||
div.brush-handle-inner-left {
|
||||
|
|
|
@ -1237,19 +1237,23 @@ class TimeseriesChartIntl extends Component {
|
|||
.attr('width', 10)
|
||||
.attr('height', 90)
|
||||
.attr('class', 'brush-handle')
|
||||
.attr('x', contextXScale(handleBrushExtent[0]) - 10)
|
||||
.html(
|
||||
'<div class="brush-handle-inner brush-handle-inner-left"><i class="fa fa-caret-left"></i></div>'
|
||||
);
|
||||
.attr('x', contextXScale(handleBrushExtent[0]) - 10).html(`
|
||||
<div class="brush-handle-inner brush-handle-inner-left" style="padding-top: 27px">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="6" height="9">
|
||||
<polygon points="5,0 5,8 0,4" />
|
||||
</svg>
|
||||
</div>`);
|
||||
const rightHandle = contextGroup
|
||||
.append('foreignObject')
|
||||
.attr('width', 10)
|
||||
.attr('height', 90)
|
||||
.attr('class', 'brush-handle')
|
||||
.attr('x', contextXScale(handleBrushExtent[1]) + 0)
|
||||
.html(
|
||||
'<div class="brush-handle-inner brush-handle-inner-right"><i class="fa fa-caret-right"></i></div>'
|
||||
);
|
||||
.attr('x', contextXScale(handleBrushExtent[1]) + 0).html(`
|
||||
<div class="brush-handle-inner brush-handle-inner-right" style="padding-top: 27px">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="6" height="9">
|
||||
<polygon points="0,0 0,8 5,4" />
|
||||
</svg>
|
||||
</div>`);
|
||||
|
||||
function brushing() {
|
||||
const brushExtent = brush.extent();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue