Skip to content

Commit

Permalink
[ML] Migrate field-type-icon to EUI/React. (#19159) (#19168)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
walterra committed May 17, 2018
1 parent 25a8402 commit 143e6d7
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 48 deletions.
Original file line number Diff line number Diff line change
@@ -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' }}"
Expand Down
Original file line number Diff line number Diff line change
@@ -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"
/>
`;

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,38 @@



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');

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]
);
}
}
};
});
Original file line number Diff line number Diff line change
@@ -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>
);
}
Original file line number Diff line number Diff line change
@@ -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();
});

});

0 comments on commit 143e6d7

Please sign in to comment.