Skip to content

Commit

Permalink
React/EUI-ify indexed fields table (#16695) (#17068)
Browse files Browse the repository at this point in the history
* React/EUI-ifying indexed fields table
  • Loading branch information
jen-huang authored Mar 9, 2018
1 parent d27a2a4 commit 03d9c42
Show file tree
Hide file tree
Showing 24 changed files with 940 additions and 169 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@
"redux-thunk": "2.2.0",
"regression": "2.0.0",
"request": "2.61.0",
"reselect": "^3.0.1",
"resize-observer-polyfill": "1.2.1",
"rimraf": "2.4.3",
"rison-node": "1.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,7 @@

<!-- Tab content -->
<div class="kuiVerticalRhythm">
<indexed-fields-table
ng-show="state.tab == 'indexedFields'"
class="fields indexed-fields"
></indexed-fields-table>
<div id="reactIndexedFieldsTable"></div>

<div id="reactScriptedFieldsTable"></div>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import _ from 'lodash';
import './index_header';
import './indexed_fields_table';
import './scripted_field_editor';
import './source_filters_table';
import { KbnUrlProvider } from 'ui/url';
Expand All @@ -9,11 +8,14 @@ import { fatalError } from 'ui/notify';
import uiRoutes from 'ui/routes';
import { uiModules } from 'ui/modules';
import template from './edit_index_pattern.html';
import { FieldWildcardProvider } from 'ui/field_wildcard';

import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { IndexedFieldsTable } from './indexed_fields_table';
import { ScriptedFieldsTable } from './scripted_fields_table';

const REACT_INDEXED_FIELDS_DOM_ELEMENT_ID = 'reactIndexedFieldsTable';
const REACT_SCRIPTED_FIELDS_DOM_ELEMENT_ID = 'reactScriptedFieldsTable';

function updateScriptedFieldsTable($scope, $state) {
Expand Down Expand Up @@ -54,6 +56,41 @@ function destroyScriptedFieldsTable() {
node && unmountComponentAtNode(node);
}

function updateIndexedFieldsTable($scope, $state) {
if ($state.tab === 'indexedFields') {
$scope.$$postDigest(() => {
const node = document.getElementById(REACT_INDEXED_FIELDS_DOM_ELEMENT_ID);
if (!node) {
return;
}

render(
<IndexedFieldsTable
fields={$scope.fields}
indexPattern={$scope.indexPattern}
fieldFilter={$scope.fieldFilter}
fieldWildcardMatcher={$scope.fieldWildcardMatcher}
indexedFieldTypeFilter={$scope.indexedFieldTypeFilter}
helpers={{
redirectToRoute: (obj, route) => {
$scope.kbnUrl.redirectToRoute(obj, route);
$scope.$apply();
},
}}
/>,
node,
);
});
} else {
destroyIndexedFieldsTable();
}
}

function destroyIndexedFieldsTable() {
const node = document.getElementById(REACT_INDEXED_FIELDS_DOM_ELEMENT_ID);
node && unmountComponentAtNode(node);
}

uiRoutes
.when('/management/kibana/indices/:indexPatternId', {
template,
Expand Down Expand Up @@ -87,7 +124,9 @@ uiModules.get('apps/management')
$scope, $location, $route, config, courier, Notifier, Private, AppState, docTitle, confirmModal) {
const notify = new Notifier();
const $state = $scope.state = new AppState();
const { fieldWildcardMatcher } = Private(FieldWildcardProvider);

$scope.fieldWildcardMatcher = fieldWildcardMatcher;
$scope.editSectionsProvider = Private(IndicesEditSectionsProvider);
$scope.kbnUrl = Private(KbnUrlProvider);
$scope.indexPattern = $route.current.locals.indexPattern;
Expand All @@ -100,6 +139,9 @@ uiModules.get('apps/management')
$scope.$watch('indexPattern.fields', function () {
$scope.editSections = $scope.editSectionsProvider($scope.indexPattern);
$scope.refreshFilters();
$scope.fields = $scope.indexPattern.getNonScriptedFields();
updateIndexedFieldsTable($scope, $state);
updateScriptedFieldsTable($scope, $state);
});

$scope.refreshFilters = function () {
Expand All @@ -123,6 +165,7 @@ uiModules.get('apps/management')

$scope.changeTab = function (obj) {
$state.tab = obj.index;
updateIndexedFieldsTable($scope, $state);
updateScriptedFieldsTable($scope, $state);
$state.save();
};
Expand All @@ -139,7 +182,10 @@ uiModules.get('apps/management')
$scope.refreshFields = function () {
const confirmModalOptions = {
confirmButtonText: 'Refresh',
onConfirm: () => { $scope.indexPattern.refreshFields(); },
onConfirm: async () => {
await $scope.indexPattern.refreshFields();
$scope.fields = $scope.indexPattern.getNonScriptedFields();
},
title: 'Refresh field list?'
};
confirmModal(
Expand Down Expand Up @@ -187,8 +233,21 @@ uiModules.get('apps/management')
};

$scope.$watch('fieldFilter', () => {
if ($scope.fieldFilter !== undefined && $state.tab === 'scriptedFields') {
updateScriptedFieldsTable($scope, $state);
if ($scope.fieldFilter === undefined) {
return;
}

switch($state.tab) {
case 'indexedFields':
updateIndexedFieldsTable($scope, $state);
case 'scriptedFields':
updateScriptedFieldsTable($scope, $state);
}
});

$scope.$watch('indexedFieldTypeFilter', () => {
if ($scope.indexedFieldTypeFilter !== undefined && $state.tab === 'indexedFields') {
updateIndexedFieldsTable($scope, $state);
}
});

Expand All @@ -199,8 +258,7 @@ uiModules.get('apps/management')
});

$scope.$on('$destory', () => {
destroyIndexedFieldsTable();
destroyScriptedFieldsTable();
});

updateScriptedFieldsTable($scope, $state);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`IndexedFieldsTable should filter based on the query bar 1`] = `
<div>
<Table
editField={[Function]}
indexPattern={
Object {
"getNonScriptedFields": [Function],
}
}
items={
Array [
Object {
"displayName": "Elastic",
"excluded": false,
"format": undefined,
"indexPattern": undefined,
"name": "Elastic",
"routes": undefined,
"searchable": true,
},
]
}
/>
</div>
`;

exports[`IndexedFieldsTable should filter based on the type filter 1`] = `
<div>
<Table
editField={[Function]}
indexPattern={
Object {
"getNonScriptedFields": [Function],
}
}
items={
Array [
Object {
"displayName": "timestamp",
"excluded": false,
"format": undefined,
"indexPattern": undefined,
"name": "timestamp",
"routes": undefined,
"type": "date",
},
]
}
/>
</div>
`;

exports[`IndexedFieldsTable should render normally 1`] = `
<div>
<Table
editField={[Function]}
indexPattern={
Object {
"getNonScriptedFields": [Function],
}
}
items={
Array [
Object {
"displayName": "Elastic",
"excluded": false,
"format": undefined,
"indexPattern": undefined,
"name": "Elastic",
"routes": undefined,
"searchable": true,
},
Object {
"displayName": "timestamp",
"excluded": false,
"format": undefined,
"indexPattern": undefined,
"name": "timestamp",
"routes": undefined,
"type": "date",
},
Object {
"displayName": "conflictingField",
"excluded": false,
"format": undefined,
"indexPattern": undefined,
"name": "conflictingField",
"routes": undefined,
"type": "conflict",
},
]
}
/>
</div>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React from 'react';
import { shallow } from 'enzyme';

import { IndexedFieldsTable } from '../indexed_fields_table';

jest.mock('@elastic/eui', () => ({
EuiFlexGroup: 'eui-flex-group',
EuiFlexItem: 'eui-flex-item',
EuiIcon: 'eui-icon',
EuiInMemoryTable: 'eui-in-memory-table',
TooltipTrigger: 'tooltip-trigger'
}));

jest.mock('../components/table', () => ({
// Note: this seems to fix React complaining about non lowercase attributes
Table: () => {
return 'table';
}
}));

const helpers = {
redirectToRoute: () => {},
};

const fields = [
{ name: 'Elastic', displayName: 'Elastic', searchable: true },
{ name: 'timestamp', displayName: 'timestamp', type: 'date' },
{ name: 'conflictingField', displayName: 'conflictingField', type: 'conflict' },
];

const indexPattern = {
getNonScriptedFields: () => fields,
};

describe('IndexedFieldsTable', () => {
it('should render normally', async () => {
const component = shallow(
<IndexedFieldsTable
fields={fields}
indexPattern={indexPattern}
helpers={helpers}
fieldWildcardMatcher={() => {}}
/>
);

await new Promise(resolve => process.nextTick(resolve));
component.update();

expect(component).toMatchSnapshot();
});

it('should filter based on the query bar', async () => {
const component = shallow(
<IndexedFieldsTable
fields={fields}
indexPattern={indexPattern}
helpers={helpers}
fieldWildcardMatcher={() => {}}
/>
);

await new Promise(resolve => process.nextTick(resolve));
component.setProps({ fieldFilter: 'Elast' });
component.update();

expect(component).toMatchSnapshot();
});

it('should filter based on the type filter', async () => {
const component = shallow(
<IndexedFieldsTable
fields={fields}
indexPattern={indexPattern}
helpers={helpers}
fieldWildcardMatcher={() => {}}
/>
);

await new Promise(resolve => process.nextTick(resolve));
component.setProps({ indexedFieldTypeFilter: 'date' });
component.update();

expect(component).toMatchSnapshot();
});
});
Loading

0 comments on commit 03d9c42

Please sign in to comment.