[ML] Migrate field-type-icon to EUI/React. (#19159) (#19168)

Migrates the field-type-icon directive to use EUI/React. Instead of the angular/bootstrap tooltip attribute on the directive's tag, there's now an option tooltip-enabled which when true wraps the component inside EuiToolTip.
This commit is contained in:
Walter Rafelsberger 2018-05-17 14:28:54 +02:00 committed by GitHub
parent 25a8402423
commit 143e6d7d8b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 195 additions and 48 deletions

View file

@ -1,11 +1,9 @@
<div class="ml-field-data-card">
<div class="euiText title-bar" ng-class="card.fieldName===undefined ? 'document_count': card.isUnsupportedType===true ? 'type-other' : card.type">
<ml-field-type-icon
type="card.type"
tooltip="{{ card.type }}"
tooltip-placement="left"
tooltip-append-to-body="true">
</ml-field-type-icon>
type="card.type"
tooltip-enabled="true"
/>
<div
class="field-name"
tooltip="{{ mlEscape(card.fieldName) || 'document count' }}"

View file

@ -0,0 +1,32 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`FieldTypeIcon render component inside tooltip wrapper 1`] = `
<EuiToolTip
content="keyword"
position="left"
>
<span>
<FieldTypeIconContainer
ariaLabel="Aggregatable string field"
className="field-type-icon"
iconChar="t"
/>
</span>
</EuiToolTip>
`;
exports[`FieldTypeIcon render component when type matches a field type 1`] = `
<FieldTypeIconContainer
ariaLabel="Aggregatable string field"
className="field-type-icon"
iconChar="t"
/>
`;
exports[`FieldTypeIcon update component 1`] = `
<FieldTypeIconContainer
ariaLabel="Aggregatable string field"
className="field-type-icon"
iconChar="t"
/>
`;

View file

@ -1,37 +0,0 @@
<span class="field-type-icon-container">
<span
ng-if="type===ML_JOB_FIELD_TYPES.BOOLEAN"
aria-label="Boolean field"
class="field-type-icon kuiIcon fa-adjust">
</span>
<span
ng-if="type===ML_JOB_FIELD_TYPES.DATE"
aria-label="Date field"
class="field-type-icon kuiIcon fa-clock-o">
</span>
<span
ng-if="type===ML_JOB_FIELD_TYPES.NUMBER"
aria-label="Metric field"
class="field-type-icon">
<strong aria-hidden="true">#</strong>
</span>
<span
ng-if="type===ML_JOB_FIELD_TYPES.GEO_POINT"
aria-label="Geo-point field"
class="field-type-icon kuiIcon fa-globe">
</span>
<span
ng-if="type===ML_JOB_FIELD_TYPES.KEYWORD"
aria-label="Aggregatable string field"
class="field-type-icon">
<strong aria-hidden="true">t</strong>
</span>
<span ng-if="type===ML_JOB_FIELD_TYPES.TEXT"
aria-label="String field"
class="field-type-icon kuiIcon fa-file-text-o">
</span>
<span ng-if="type===ML_JOB_FIELD_TYPES.IP"
aria-label="IP address field"
class="field-type-icon kuiIcon fa-laptop">
</span>
</span>

View file

@ -6,8 +6,10 @@
import template from './field_type_icon.html';
import { ML_JOB_FIELD_TYPES } from 'plugins/ml/../common/constants/field_types';
import React from 'react';
import ReactDOM from 'react-dom';
import { FieldTypeIcon } from './field_type_icon_view.js';
import { uiModules } from 'ui/modules';
const module = uiModules.get('apps/ml');
@ -15,13 +17,27 @@ const module = uiModules.get('apps/ml');
module.directive('mlFieldTypeIcon', function () {
return {
restrict: 'E',
replace: true,
replace: false,
scope: {
tooltipEnabled: '=',
type: '='
},
template,
controller: function ($scope) {
$scope.ML_JOB_FIELD_TYPES = ML_JOB_FIELD_TYPES;
link: function (scope, element) {
scope.$watch('type', updateComponent);
updateComponent();
function updateComponent() {
const props = {
tooltipEnabled: scope.tooltipEnabled,
type: scope.type
};
ReactDOM.render(
React.createElement(FieldTypeIcon, props),
element[0]
);
}
}
};
});

View file

@ -0,0 +1,97 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import PropTypes from 'prop-types';
import React from 'react';
import { EuiToolTip } from '@elastic/eui';
// don't use something like plugins/ml/../common
// because it won't work with the jest tests
import { ML_JOB_FIELD_TYPES } from '../../../common/constants/field_types';
export function FieldTypeIcon({ tooltipEnabled = false, type }) {
let ariaLabel = '';
let iconClass = '';
let iconChar = '';
switch (type) {
case ML_JOB_FIELD_TYPES.BOOLEAN:
ariaLabel = 'Boolean field';
iconClass = 'fa-adjust';
break;
case ML_JOB_FIELD_TYPES.DATE:
ariaLabel = 'Date field';
iconClass = 'fa-clock-o';
break;
case ML_JOB_FIELD_TYPES.NUMBER:
ariaLabel = 'Metric field';
iconChar = '#';
break;
case ML_JOB_FIELD_TYPES.GEO_POINT:
ariaLabel = 'Geo-point field';
iconClass = 'fa-globe';
break;
case ML_JOB_FIELD_TYPES.KEYWORD:
ariaLabel = 'Aggregatable string field';
iconChar = 't';
break;
case ML_JOB_FIELD_TYPES.TEXT:
ariaLabel = 'String field';
iconClass = 'fa-file-text-o';
break;
case ML_JOB_FIELD_TYPES.IP:
ariaLabel = 'IP address field';
iconClass = 'fa-laptop';
break;
default:
// if type doesn't match one of ML_JOB_FIELD_TYPES
// don't render the component at all
return null;
}
let className = 'field-type-icon';
if (iconClass !== '') {
className += ' kuiIcon ' + iconClass;
}
const containerProps = {
ariaLabel,
className,
iconChar
};
if (tooltipEnabled === true) {
// wrap the inner component inside <span> because EuiToolTip doesn't seem
// to support having another component directly inside the tooltip anchor
// see https://github.com/elastic/eui/issues/839
return (
<EuiToolTip position="left" content={type}>
<span><FieldTypeIconContainer {...containerProps} /></span>
</EuiToolTip>
);
}
return <FieldTypeIconContainer {...containerProps} />;
}
FieldTypeIcon.propTypes = {
tooltipEnabled: PropTypes.bool,
type: PropTypes.string
};
function FieldTypeIconContainer({ ariaLabel, className, iconChar }) {
return (
<span className="field-type-icon-container">
{(iconChar === '') ? (
<span aria-label={ariaLabel} className={className} />
) : (
<span aria-label={ariaLabel} className={className}>
<strong aria-hidden="true">{iconChar}</strong>
</span>
)}
</span>
);
}

View file

@ -0,0 +1,41 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { shallow } from 'enzyme';
import React from 'react';
import { FieldTypeIcon } from './field_type_icon_view';
describe('FieldTypeIcon', () => {
test(`don't render component when type is undefined`, () => {
const wrapper = shallow(<FieldTypeIcon />);
expect(wrapper.isEmptyRender()).toBeTruthy();
});
test(`don't render component when type doesn't match a field type`, () => {
const wrapper = shallow(<FieldTypeIcon type="foo" />);
expect(wrapper.isEmptyRender()).toBeTruthy();
});
test(`render component when type matches a field type`, () => {
const wrapper = shallow(<FieldTypeIcon type="keyword" />);
expect(wrapper).toMatchSnapshot();
});
test(`render component inside tooltip wrapper`, () => {
const wrapper = shallow(<FieldTypeIcon type="keyword" tooltipEnabled={true} />);
expect(wrapper).toMatchSnapshot();
});
test(`update component`, () => {
const wrapper = shallow(<FieldTypeIcon />);
expect(wrapper.isEmptyRender()).toBeTruthy();
wrapper.setProps({ type: 'keyword' });
expect(wrapper).toMatchSnapshot();
});
});