Skip to content

Commit

Permalink
De-angularize field-name directive (#40744) (#41106)
Browse files Browse the repository at this point in the history
  • Loading branch information
kertal authored Jul 15, 2019
1 parent df954c7 commit 9ed0b2f
Show file tree
Hide file tree
Showing 18 changed files with 355 additions and 199 deletions.
46 changes: 24 additions & 22 deletions src/legacy/core_plugins/kbn_doc_views/public/__tests__/doc_views.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,15 @@ describe('docViews', function () {

it('should have the field name in the first column', function () {
_.each(_.keys(flattened), function (field) {
expect($elem.find('td[title="' + field + '"]').length).to.be(1);
expect($elem.find('[data-test-subj="tableDocViewRow-' + field + '"]').length).to.be(1);
});
});

it('should have the a value for each field', function () {
_.each(_.keys(flattened), function (field) {
const cellValue = $elem.find('td[title="' + field + '"]').siblings().find('.kbnDocViewer__value').text();
const cellValue = $elem
.find('[data-test-subj="tableDocViewRow-' + field + '"]')
.find('.kbnDocViewer__value').text();

// This sucks, but testing the filter chain is too hairy ATM
expect(cellValue.length).to.be.greaterThan(0);
Expand All @@ -117,48 +119,48 @@ describe('docViews', function () {

describe('filtering', function () {
it('should apply a filter when clicking filterable fields', function () {
const cell = $elem.find('td[title="bytes"]').prev();
const row = $elem.find('[data-test-subj="tableDocViewRow-bytes"]');

cell.find('.fa-search-plus').first().click();
row.find('.fa-search-plus').first().click();
expect($scope.filter.calledOnce).to.be(true);
cell.find('.fa-search-minus').first().click();
row.find('.fa-search-minus').first().click();
expect($scope.filter.calledTwice).to.be(true);
cell.find('.fa-asterisk').first().click();
row.find('.fa-asterisk').first().click();
expect($scope.filter.calledThrice).to.be(true);
});

it('should NOT apply a filter when clicking non-filterable fields', function () {
const cell = $elem.find('td[title="area"]').prev();
const row = $elem.find('[data-test-subj="tableDocViewRow-area"]');

cell.find('.fa-search-plus').first().click();
row.find('.fa-search-plus').first().click();
expect($scope.filter.calledOnce).to.be(false);
cell.find('.fa-search-minus').first().click();
row.find('.fa-search-minus').first().click();
expect($scope.filter.calledTwice).to.be(false);
cell.find('.fa-asterisk').first().click();
row.find('.fa-asterisk').first().click();
expect($scope.filter.calledOnce).to.be(true);
});
});

describe('warnings', function () {
it('displays a warning about field name starting with underscore', function () {
const cells = $elem.find('td[title="_underscore"]').siblings();
expect(cells.find('.kbnDocViewer__underscore').length).to.be(1);
expect(cells.find('.kbnDocViewer__noMapping').length).to.be(0);
expect(cells.find('.kbnDocViewer__objectArray').length).to.be(0);
const row = $elem.find('[data-test-subj="tableDocViewRow-_underscore"]');
expect(row.find('.kbnDocViewer__underscore').length).to.be(1);
expect(row.find('.kbnDocViewer__noMapping').length).to.be(0);
expect(row.find('.kbnDocViewer__objectArray').length).to.be(0);
});

it('displays a warning about missing mappings', function () {
const cells = $elem.find('td[title="noMapping"]').siblings();
expect(cells.find('.kbnDocViewer__underscore').length).to.be(0);
expect(cells.find('.kbnDocViewer__noMapping').length).to.be(1);
expect(cells.find('.kbnDocViewer__objectArray').length).to.be(0);
const row = $elem.find('[data-test-subj="tableDocViewRow-noMapping"]');
expect(row.find('.kbnDocViewer__underscore').length).to.be(0);
expect(row.find('.kbnDocViewer__noMapping').length).to.be(1);
expect(row.find('.kbnDocViewer__objectArray').length).to.be(0);
});

it('displays a warning about objects in arrays', function () {
const cells = $elem.find('td[title="objectArray"]').siblings();
expect(cells.find('.kbnDocViewer__underscore').length).to.be(0);
expect(cells.find('.kbnDocViewer__noMapping').length).to.be(0);
expect(cells.find('.kbnDocViewer__objectArray').length).to.be(1);
const row = $elem.find('[data-test-subj="tableDocViewRow-objectArray"]');
expect(row.find('.kbnDocViewer__underscore').length).to.be(0);
expect(row.find('.kbnDocViewer__noMapping').length).to.be(0);
expect(row.find('.kbnDocViewer__objectArray').length).to.be(1);
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,8 @@ discover-app {
color: $euiColorDarkShade;
}

// SASSTODO: replace the margin-right value with a variables
.dscField__icon {
margin-right: 5px;
margin-right: $euiSizeS;
text-align: center;
display: inline-block;
width: $euiSizeM;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
kbn-accessible-click
class="sidebar-item-title dscSidebarItem"
>
<field-name
class="dscField dscSidebarItem__label"
field="field"
></field-name>
<div class="dscField dscSidebarItem__label">
<field-name
field="field"
></field-name>
</div>

<button
ng-if="field.name !== '_source'"
Expand Down
137 changes: 14 additions & 123 deletions src/legacy/ui/public/directives/field_name.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,131 +16,22 @@
* specific language governing permissions and limitations
* under the License.
*/

import $ from 'jquery';
import { i18n } from '@kbn/i18n';
import { template } from 'lodash';
import { shortenDottedString } from '../../../core_plugins/kibana/common/utils/shorten_dotted_string';
import booleanFieldNameIcon from './field_name_icons/boolean_field_name_icon.html';
import conflictFieldNameIcon from './field_name_icons/conflict_field_name_icon.html';
import dateFieldNameIcon from './field_name_icons/date_field_name_icon.html';
import geoPointFieldNameIcon from './field_name_icons/geo_point_field_name_icon.html';
import ipFieldNameIcon from './field_name_icons/ip_field_name_icon.html';
import murmur3FieldNameIcon from './field_name_icons/murmur3_field_name_icon.html';
import numberFieldNameIcon from './field_name_icons/number_field_name_icon.html';
import sourceFieldNameIcon from './field_name_icons/source_field_name_icon.html';
import stringFieldNameIcon from './field_name_icons/string_field_name_icon.html';
import unknownFieldNameIcon from './field_name_icons/unknown_field_name_icon.html';

import { FieldName } from './field_name/field_name';
import { uiModules } from '../modules';
import { wrapInI18nContext } from 'ui/i18n';
const module = uiModules.get('kibana');

const compiledBooleanFieldNameIcon = template(booleanFieldNameIcon);
const compiledConflictFieldNameIcon = template(conflictFieldNameIcon);
const compiledDateFieldNameIcon = template(dateFieldNameIcon);
const compiledGeoPointFieldNameIcon = template(geoPointFieldNameIcon);
const compiledIpFieldNameIcon = template(ipFieldNameIcon);
const compiledMurmur3FieldNameIcon = template(murmur3FieldNameIcon);
const compiledNumberFieldNameIcon = template(numberFieldNameIcon);
const compiledSourceFieldNameIcon = template(sourceFieldNameIcon);
const compiledStringFieldNameIcon = template(stringFieldNameIcon);
const compiledUnknownFieldNameIcon = template(unknownFieldNameIcon);

module.directive('fieldName', function ($rootScope, config) {
return {
restrict: 'AE',
scope: {
'field': '=',
'fieldName': '=',
'fieldType': '='
},
link: function ($scope, $el) {
const typeToIconMap = {
boolean: compiledBooleanFieldNameIcon({
booleanFieldAriaLabel: i18n.translate('common.ui.directives.fieldNameIcons.booleanAriaLabel', {
defaultMessage: 'Boolean field'
}),
}),
conflict: compiledConflictFieldNameIcon({
conflictingFieldAriaLabel: i18n.translate('common.ui.directives.fieldNameIcons.conflictFieldAriaLabel', {
defaultMessage: 'Conflicting field'
}),
}),
date: compiledDateFieldNameIcon({
dateFieldAriaLabel: i18n.translate('common.ui.directives.fieldNameIcons.dateFieldAriaLabel', {
defaultMessage: 'Date field'
}),
}),
geo_point: compiledGeoPointFieldNameIcon({
geoPointFieldAriaLabel: i18n.translate('common.ui.directives.fieldNameIcons.geoPointFieldAriaLabel', {
defaultMessage: 'Date field'
}),
}),
ip: compiledIpFieldNameIcon({
ipAddressFieldAriaLabel: i18n.translate('common.ui.directives.fieldNameIcons.ipAddressFieldAriaLabel', {
defaultMessage: 'IP address field'
}),
}),
murmur3: compiledMurmur3FieldNameIcon({
murmur3FieldAriaLabel: i18n.translate('common.ui.directives.fieldNameIcons.murmur3FieldAriaLabel', {
defaultMessage: 'Murmur3 field'
}),
}),
number: compiledNumberFieldNameIcon({
numberFieldAriaLabel: i18n.translate('common.ui.directives.fieldNameIcons.numberFieldAriaLabel', {
defaultMessage: 'Number field'
}),
}),
source: compiledSourceFieldNameIcon({
sourceFieldAriaLabel: i18n.translate('common.ui.directives.fieldNameIcons.sourceFieldAriaLabel', {
defaultMessage: 'Source field'
}),
}),
string: compiledStringFieldNameIcon({
stringFieldAriaLabel: i18n.translate('common.ui.directives.fieldNameIcons.stringFieldAriaLabel', {
defaultMessage: 'String field'
}),
}),
};

function typeIcon(fieldType) {
if (typeToIconMap.hasOwnProperty(fieldType)) {
return typeToIconMap[fieldType];
}

return compiledUnknownFieldNameIcon({
unknownFieldAriaLabel: i18n.translate('common.ui.directives.fieldNameIcons.unknownFieldAriaLabel', {
defaultMessage: 'Unknown field'
}),
});
}

$rootScope.$watchMulti.call($scope, [
'field',
'fieldName',
'fieldType',
'field.rowCount'
], function () {

const type = $scope.field ? $scope.field.type : $scope.fieldType;
const name = $scope.field ? $scope.field.name : $scope.fieldName;
const results = $scope.field ? !$scope.field.rowCount && !$scope.field.scripted : false;
const scripted = $scope.field ? $scope.field.scripted : false;


const isShortDots = config.get('shortDots:enable');
const displayName = isShortDots ? shortenDottedString(name) : name;

$el
.attr('title', name)
.toggleClass('dscField--noResults', results)
.toggleClass('scripted', scripted)
.prepend(typeIcon(type))
.append($('<span>')
.text(displayName)
.addClass('dscFieldName')
);
});
module.directive('fieldName', function (config, reactDirective) {
return reactDirective(
wrapInI18nContext(FieldName),
[
['field', { watchDepth: 'collection' }],
['fieldName', { watchDepth: 'reference' }],
['fieldType', { watchDepth: 'reference' }],
],
{ restrict: 'AE' },
{
useShortDots: config.get('shortDots:enable'),
}
};
);
});

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 50 additions & 0 deletions src/legacy/ui/public/directives/field_name/field_name.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import React from 'react';
import { render } from 'enzyme';
import { FieldName } from './field_name';

// Note that it currently provides just 2 basic tests, there should be more, but
// the components involved will soon change
test('FieldName renders a string field by providing fieldType and fieldName', () => {
const component = render(<FieldName fieldType="string" fieldName="test" />);
expect(component).toMatchSnapshot();
});

test('FieldName renders a number field by providing a field record, useShortDots is set to false', () => {
const field = {
type: 'number',
name: 'test.test.test',
rowCount: 100,
scripted: false,
};
const component = render(<FieldName field={field} />);
expect(component).toMatchSnapshot();
});

test('FieldName renders a geo field, useShortDots is set to true', () => {
const field = {
type: 'geo_point',
name: 'test.test.test',
rowCount: 0,
scripted: false,
};
const component = render(<FieldName field={field} useShortDots={true} />);
expect(component).toMatchSnapshot();
});
Loading

0 comments on commit 9ed0b2f

Please sign in to comment.