-
+ type="card.type"
+ tooltip-enabled="true"
+ />
+
+
+
+
+`;
+
+exports[`FieldTypeIcon render component when type matches a field type 1`] = `
+
+`;
+
+exports[`FieldTypeIcon update component 1`] = `
+
+`;
diff --git a/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon.html b/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon.html
deleted file mode 100644
index d60055c38d67e3..00000000000000
--- a/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon.html
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
-
-
- #
-
-
-
-
- t
-
-
-
-
-
-
diff --git a/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon_directive.js b/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon_directive.js
index 024c751b0e72e3..4fef02f0c8bfd2 100644
--- a/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon_directive.js
+++ b/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon_directive.js
@@ -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]
+ );
+ }
}
};
});
diff --git a/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon_view.js b/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon_view.js
new file mode 100644
index 00000000000000..89275999e9ff92
--- /dev/null
+++ b/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon_view.js
@@ -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 because EuiToolTip doesn't seem
+ // to support having another component directly inside the tooltip anchor
+ // see https://github.com/elastic/eui/issues/839
+ return (
+
+
+
+ );
+ }
+
+ return ;
+}
+FieldTypeIcon.propTypes = {
+ tooltipEnabled: PropTypes.bool,
+ type: PropTypes.string
+};
+
+function FieldTypeIconContainer({ ariaLabel, className, iconChar }) {
+ return (
+
+ {(iconChar === '') ? (
+
+ ) : (
+
+ {iconChar}
+
+ )}
+
+ );
+}
diff --git a/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon_view.test.js b/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon_view.test.js
new file mode 100644
index 00000000000000..0f89deddade19e
--- /dev/null
+++ b/x-pack/plugins/ml/public/components/field_type_icon/field_type_icon_view.test.js
@@ -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();
+ expect(wrapper.isEmptyRender()).toBeTruthy();
+ });
+
+ test(`don't render component when type doesn't match a field type`, () => {
+ const wrapper = shallow();
+ expect(wrapper.isEmptyRender()).toBeTruthy();
+ });
+
+ test(`render component when type matches a field type`, () => {
+ const wrapper = shallow();
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ test(`render component inside tooltip wrapper`, () => {
+ const wrapper = shallow();
+ expect(wrapper).toMatchSnapshot();
+ });
+
+ test(`update component`, () => {
+ const wrapper = shallow();
+ expect(wrapper.isEmptyRender()).toBeTruthy();
+ wrapper.setProps({ type: 'keyword' });
+ expect(wrapper).toMatchSnapshot();
+ });
+
+});