mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
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:
parent
25a8402423
commit
143e6d7d8b
6 changed files with 195 additions and 48 deletions
|
@ -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' }}"
|
||||
|
|
|
@ -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"
|
||||
/>
|
||||
`;
|
|
@ -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>
|
|
@ -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]
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
}
|
|
@ -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();
|
||||
});
|
||||
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue