From 0c6b0c0f73466518603568b168abbe4be15e1ebc Mon Sep 17 00:00:00 2001 From: Chris Roberson Date: Wed, 7 Feb 2018 16:59:23 -0500 Subject: [PATCH 1/6] First pass at new scripted fields table --- .../edit_index_pattern.html | 5 +- .../edit_index_pattern/edit_index_pattern.js | 44 ++- .../scripted_field_table.test.js.snap | 298 ++++++++++++++++ .../__tests__/scripted_field_table.test.js | 133 +++++++ .../__snapshots__/call_outs.test.js.snap | 31 ++ .../call_outs/__tests__/call_outs.test.js | 28 ++ .../components/call_outs/call_outs.js | 33 ++ .../components/call_outs/index.js | 1 + .../__snapshots__/header.test.js.snap | 21 ++ .../header/__tests__/header.test.js | 14 + .../components/header/header.js | 23 ++ .../components/header/index.js | 1 + .../__snapshots__/table.test.js.snap | 92 +++++ .../components/table/__tests__/table.test.js | 41 +++ .../components/table/index.js | 1 + .../components/table/table.js | 112 ++++++ .../scripted_fields_table/index.js | 35 +- .../lib/__tests__/table.test.js | 78 ++++ .../scripted_fields_table/lib/index.js | 1 + .../scripted_fields_table/lib/table.js | 61 ++++ .../scripted_fields_table.js | 333 +++++++++++------- .../scripted_fields_table_angular.js | 138 ++++++++ 22 files changed, 1383 insertions(+), 141 deletions(-) create mode 100644 src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/__snapshots__/scripted_field_table.test.js.snap create mode 100644 src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/scripted_field_table.test.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/call_outs/__tests__/__snapshots__/call_outs.test.js.snap create mode 100644 src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/call_outs/__tests__/call_outs.test.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/call_outs/call_outs.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/call_outs/index.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/header/__tests__/__snapshots__/header.test.js.snap create mode 100644 src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/header/__tests__/header.test.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/header/header.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/header/index.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/__tests__/__snapshots__/table.test.js.snap create mode 100644 src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/__tests__/table.test.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/index.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/table.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/lib/__tests__/table.test.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/lib/index.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/lib/table.js create mode 100644 src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table_angular.js diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.html b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.html index 2df9f88abd760..3cecfe82a8def 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.html +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.html @@ -145,10 +145,7 @@ class="fields indexed-fields" > - +
{ + $scope.kbnUrl.redirectToRoute(obj, route); + $scope.$apply(); + }, + getRouteHref: (obj, route) => $scope.kbnUrl.getRouteHref(obj, route), + } + ); + }; + + $scope.$watch('fieldFilter', () => { + if ($scope.fieldFilter !== undefined && $state.tab === 'scriptedFields') { + $scope.renderScriptedFieldsTable(); + } + }); + + $scope.$watch('scriptedFieldLanguageFilter', () => { + if ($scope.scriptedFieldLanguageFilter !== undefined && $state.tab === 'scriptedFields') { + $scope.renderScriptedFieldsTable(); + } + }); + + $scope.$on('$destory', () => { + destroyScriptedFieldsTable(); + }); + + $scope.tryToRenderScriptedFieldsTable(); }); diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/__snapshots__/scripted_field_table.test.js.snap b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/__snapshots__/scripted_field_table.test.js.snap new file mode 100644 index 0000000000000..3d1e53a261f74 --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/__snapshots__/scripted_field_table.test.js.snap @@ -0,0 +1,298 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ScriptedFieldsTable should filter based on the lang filter 1`] = ` + +
+
+ + + Add Scripted Field + + + + table +
+ +
+
+`; + +exports[`ScriptedFieldsTable should filter based on the query bar 1`] = ` + +
+
+ + + Add Scripted Field + + + + table +
+ +
+
+`; + +exports[`ScriptedFieldsTable should render normally 1`] = ` + +
+
+ + + Add Scripted Field + + + + table +
+ +
+
+`; + +exports[`ScriptedFieldsTable should show a message if there are no scripted fields 1`] = ` + +
+
+ + + Add Scripted Field + + + + table +
+ + No scripted fields found. + + +
+
+`; diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/scripted_field_table.test.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/scripted_field_table.test.js new file mode 100644 index 0000000000000..daae70282a97e --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/scripted_field_table.test.js @@ -0,0 +1,133 @@ +import React from 'react'; +import { mount } from 'enzyme'; + +import { ScriptedFieldsTable } from '../scripted_fields_table'; + +jest.mock('@elastic/eui', () => ({ + EuiButton: 'eui-button', + EuiTableOfRecords: 'eui-table-of-records', + EuiTitle: 'eui-title', + EuiText: 'eui-text', + EuiButton: 'eui-button', + EuiHorizontalRule: 'eui-horizontal-rule', + EuiSpacer: 'eui-spacer', + EuiCallOut: 'eui-call-out', + EuiLink: 'eui-link', + EuiOverlayMask: 'eui-overlay-mask', + EuiConfirmModal: 'eui-confirm-modal', + Comparators: { + property: () => {}, + default: () => {}, + }, +})); +jest.mock('../components/header', () => ({ Header: 'header' })); +jest.mock('../components/call_outs', () => ({ CallOuts: 'call-outs' })); +jest.mock('../components/table', () => ({ + // Note: this seems to fix React complaining about non lowercase attributes + Table: () => { + return 'table'; + } +})); +jest.mock('ui/scripting_languages', () => ({ + getSupportedScriptingLanguages: () => ['painless'], + getDeprecatedScriptingLanguages: () => [], +})); +jest.mock('ui/documentation_links', () => ({ + documentationLinks: { + scriptedFields: { + painless: 'painlessDocs' + } + } +})); + +const helpers = { + redirectToRoute: () => {}, + getRouteHref: () => {}, +}; + +const indexPattern = { + getScriptedFields: () => ([ + { name: 'ScriptedField', lang: 'painless', script: 'x++' }, + { name: 'JustATest', lang: 'painless', script: 'z++' }, + ]) +}; + +describe('ScriptedFieldsTable', () => { + it('should render normally', async () => { + const component = mount( + + ); + + // Allow the componentWillMount code to execute + // https://github.com/airbnb/enzyme/issues/450 + await component.update(); // Fire `componentWillMount()` + await component.update(); // Force update the component post async actions + + expect(component).toMatchSnapshot(); + }); + + it('should filter based on the query bar', async () => { + const component = mount( + + ); + + // Allow the componentWillMount code to execute + // https://github.com/airbnb/enzyme/issues/450 + await component.update(); // Fire `componentWillMount()` + await component.update(); // Force update the component post async actions + + component.setProps({ fieldFilter: 'Just' }); + component.update(); + + expect(component).toMatchSnapshot(); + }); + + it('should filter based on the lang filter', async () => { + const component = mount( + ([ + { name: 'ScriptedField', lang: 'painless', script: 'x++' }, + { name: 'JustATest', lang: 'painless', script: 'z++' }, + { name: 'Bad', lang: 'somethingElse', script: 'z++' }, + ]) + }} + helpers={helpers} + /> + ); + + // Allow the componentWillMount code to execute + // https://github.com/airbnb/enzyme/issues/450 + await component.update(); // Fire `componentWillMount()` + await component.update(); // Force update the component post async actions + + component.setProps({ scriptedFieldLanguageFilter: 'painless' }); + component.update(); + + expect(component).toMatchSnapshot(); + }); + + it('should show a message if there are no scripted fields', async () => { + const component = mount( + ([]) + }} + helpers={helpers} + /> + ); + + // Allow the componentWillMount code to execute + // https://github.com/airbnb/enzyme/issues/450 + await component.update(); // Fire `componentWillMount()` + await component.update(); // Force update the component post async actions + + expect(component).toMatchSnapshot(); + }); +}); diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/call_outs/__tests__/__snapshots__/call_outs.test.js.snap b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/call_outs/__tests__/__snapshots__/call_outs.test.js.snap new file mode 100644 index 0000000000000..e188c9f58b515 --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/call_outs/__tests__/__snapshots__/call_outs.test.js.snap @@ -0,0 +1,31 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CallOuts should render normally 1`] = ` +
+ +

+ We've detected that the following deprecated languages are in use: + php + . Support for these languages will be removed in the next major version of Kibana and Elasticsearch. We recommend converting your scripted fields to + + Painless + + . +

+
+ +
+`; + +exports[`CallOuts should render without any call outs 1`] = `""`; diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/call_outs/__tests__/call_outs.test.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/call_outs/__tests__/call_outs.test.js new file mode 100644 index 0000000000000..4395c830d6f4a --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/call_outs/__tests__/call_outs.test.js @@ -0,0 +1,28 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { CallOuts } from '../call_outs'; + +describe('CallOuts', () => { + it('should render normally', async () => { + const component = shallow( + + ); + + expect(component).toMatchSnapshot(); + }); + + it('should render without any call outs', async () => { + const component = shallow( + + ); + + expect(component).toMatchSnapshot(); + }); +}); diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/call_outs/call_outs.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/call_outs/call_outs.js new file mode 100644 index 0000000000000..b9b6d5ff6437c --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/call_outs/call_outs.js @@ -0,0 +1,33 @@ +import React from 'react'; + +import { + EuiCallOut, + EuiLink, + EuiSpacer, +} from '@elastic/eui'; + +export const CallOuts = ({ + deprecatedLangsInUse, + painlessDocLink, +}) => { + if (!deprecatedLangsInUse.length) { + return null; + } + + return ( +
+ +

+ We've detected that the following deprecated languages are in use: {deprecatedLangsInUse.join(', ')}. + Support for these languages will be removed in the next major version of Kibana and Elasticsearch. + We recommend converting your scripted fields to Painless. +

+
+ +
+ ); +}; diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/call_outs/index.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/call_outs/index.js new file mode 100644 index 0000000000000..0df8edb404e9d --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/call_outs/index.js @@ -0,0 +1 @@ +export { CallOuts } from './call_outs'; diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/header/__tests__/__snapshots__/header.test.js.snap b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/header/__tests__/__snapshots__/header.test.js.snap new file mode 100644 index 0000000000000..937eabb7cad49 --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/header/__tests__/__snapshots__/header.test.js.snap @@ -0,0 +1,21 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Header should render normally 1`] = ` +
+ +

+ Scripted fields +

+
+ +

+ These scripted fields are computed on the fly from your data. They can be used in visualizations and displayed in your documents, however they can not be searched. You can manage them here and add new ones as you see fit, but be careful, scripts can be tricky! +

+
+ +
+`; diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/header/__tests__/header.test.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/header/__tests__/header.test.js new file mode 100644 index 0000000000000..aa668eef621fa --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/header/__tests__/header.test.js @@ -0,0 +1,14 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { Header } from '../header'; + +describe('Header', () => { + it('should render normally', async () => { + const component = shallow( +
+ ); + + expect(component).toMatchSnapshot(); + }); +}); diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/header/header.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/header/header.js new file mode 100644 index 0000000000000..21283aca1107b --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/header/header.js @@ -0,0 +1,23 @@ +import React from 'react'; + +import { + EuiTitle, + EuiText, + EuiSpacer, +} from '@elastic/eui'; + +export const Header = () => ( +
+ +

Scripted fields

+
+ +

+ These scripted fields are computed on the fly from your data. + They can be used in visualizations and displayed in your documents, however they can not be searched. + You can manage them here and add new ones as you see fit, but be careful, scripts can be tricky! +

+
+ +
+); diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/header/index.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/header/index.js new file mode 100644 index 0000000000000..ddd9723152366 --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/header/index.js @@ -0,0 +1 @@ +export { Header } from './header'; diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/__tests__/__snapshots__/table.test.js.snap b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/__tests__/__snapshots__/table.test.js.snap new file mode 100644 index 0000000000000..b979f0b85bd57 --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/__tests__/__snapshots__/table.test.js.snap @@ -0,0 +1,92 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Table should render normally 1`] = ` + +`; diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/__tests__/table.test.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/__tests__/table.test.js new file mode 100644 index 0000000000000..dd8c98dcedb83 --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/__tests__/table.test.js @@ -0,0 +1,41 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { Table } from '../table'; + +const indexPattern = { + fieldFormatMap: {} +}; + +const model = { + data: { + records: [{ id: 1, name: 'Elastic' }], + totalRecordCount: 1, + }, + criteria: { + page: { + index: 0, + size: 10, + }, + sort: { + field: 'name', + direction: 'asc' + }, + } +}; + +describe('Table', () => { + it('should render normally', async () => { + const component = shallow( + {}} + deleteField={() => {}} + onDataCriteriaChange={() => {}} + /> + ); + + expect(component).toMatchSnapshot(); + }); +}); diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/index.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/index.js new file mode 100644 index 0000000000000..48232283cba67 --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/index.js @@ -0,0 +1 @@ +export { Table } from './table'; diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/table.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/table.js new file mode 100644 index 0000000000000..ad9a756617a5d --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/table.js @@ -0,0 +1,112 @@ +import React, { PureComponent } from 'react'; +import PropTypes from 'prop-types'; + +import { + EuiTableOfRecords +} from '@elastic/eui'; + +export class Table extends PureComponent { + static propTypes = { + indexPattern: PropTypes.object.isRequired, + model: PropTypes.shape({ + data: PropTypes.shape({ + records: PropTypes.array.isRequired, + totalRecordCount: PropTypes.number.isRequired, + }).isRequired, + criteria: PropTypes.shape({ + page: PropTypes.shape({ + index: PropTypes.number.isRequired, + size: PropTypes.number.isRequired, + }).isRequired, + sort: PropTypes.shape({ + field: PropTypes.string.isRequired, + direction: PropTypes.string.isRequired, + }).isRequired, + }).isRequired, + }), + editField: PropTypes.func.isRequired, + deleteField: PropTypes.func.isRequired, + onDataCriteriaChange: PropTypes.func.isRequired, + } + + renderFormatCell = (value) => { + const { indexPattern } = this.props; + + const title = indexPattern.fieldFormatMap[value] && indexPattern.fieldFormatMap[value].type + ? indexPattern.fieldFormatMap[value].type.title + : ''; + + return ( + {title} + ); + } + + getTableConfig() { + const { editField, deleteField, onDataCriteriaChange } = this.props; + + return { + recordId: 'id', + columns: [ + { + field: 'name', + name: 'Name', + description: `Name of the field`, + dataType: 'string', + sortable: true, + }, + { + field: 'lang', + name: 'Name', + description: `Language used for the field`, + dataType: 'string', + sortable: true, + }, + { + field: 'script', + name: 'Script', + description: `Script for the field`, + dataType: 'string', + sortable: true, + }, + { + field: 'name', + name: 'Format', + description: `Format used for the field`, + render: this.renderFormatCell, + sortable: false, + }, + { + name: '', + actions: [ + { + name: 'Edit', + description: 'Edit this field', + icon: 'pencil', + onClick: editField, + }, + { + name: 'Delete', + description: 'Delete this field', + icon: 'trash', + color: 'danger', + onClick: deleteField, + }, + ] + } + ], + pagination: { + pageSizeOptions: [5, 10, 25, 50] + }, + selection: undefined, + onDataCriteriaChange, + }; + } + + render() { + const { model } = this.props; + + return ( + + ); + } +} diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/index.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/index.js index 547ccdebf2dd4..317ad472e05a6 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/index.js +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/index.js @@ -1 +1,34 @@ -import './scripted_fields_table'; +import React from 'react'; +import { render, unmountComponentAtNode } from 'react-dom'; +import { ScriptedFieldsTable } from './scripted_fields_table'; + +import './scripted_fields_table_angular'; + +const DOM_ELEMENT_ID = 'reactScriptedFieldsTable'; + +export function renderScriptedFieldsTable( + indexPattern, + fieldFilter, + scriptedFieldLanguageFilter, + helpers, +) { + const node = document.getElementById(DOM_ELEMENT_ID); + if (!node) { + return; + } + + render( + , + node, + ); +} + +export function destroyScriptedFieldsTable() { + const node = document.getElementById(DOM_ELEMENT_ID); + node && unmountComponentAtNode(node); +} diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/lib/__tests__/table.test.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/lib/__tests__/table.test.js new file mode 100644 index 0000000000000..69eaadae63432 --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/lib/__tests__/table.test.js @@ -0,0 +1,78 @@ +import { + getTableOfRecordsState, +} from '../table'; + +jest.mock('@elastic/eui', () => ({ + Comparators: { + property: () => {}, + default: () => {}, + }, +})); + +const items = [ + { name: 'Kibana' }, + { name: 'Elasticsearch' }, + { name: 'Logstash' }, +]; + +describe('getTableOfRecordsState', () => { + it('should return a TableOfRecords model', () => { + const model = getTableOfRecordsState(items, { + page: { + index: 0, + size: 10, + }, + sort: { + field: 'name', + direction: 'asc', + }, + }); + + expect(model).toEqual({ + data: { + records: items, + totalRecordCount: items.length, + }, + criteria: { + page: { + index: 0, + size: 10 + }, + sort: { + field: 'name', + direction: 'asc' + }, + } + }); + }); + + it('should paginate', () => { + const model = getTableOfRecordsState(items, { + page: { + index: 1, + size: 1, + }, + sort: { + field: 'name', + direction: 'asc', + }, + }); + + expect(model).toEqual({ + data: { + records: [{ name: 'Elasticsearch' }], + totalRecordCount: items.length, + }, + criteria: { + page: { + index: 1, + size: 1 + }, + sort: { + field: 'name', + direction: 'asc' + }, + } + }); + }); +}); diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/lib/index.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/lib/index.js new file mode 100644 index 0000000000000..01643f0f57fd8 --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/lib/index.js @@ -0,0 +1 @@ +export * from './table'; diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/lib/table.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/lib/table.js new file mode 100644 index 0000000000000..707187312103b --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/lib/table.js @@ -0,0 +1,61 @@ +import { + Comparators +} from '@elastic/eui'; + +export const getPage = (data, pageIndex, pageSize, sort) => { + let list = data; + if (sort) { + list = data.sort(Comparators.property(sort.field, Comparators.default(sort.direction))); + } + if (!pageIndex && !pageSize) { + return { + index: 0, + size: list.length, + items: list, + totalRecordCount: list.length + }; + } + const from = pageIndex * pageSize; + const items = list.slice(from, Math.min(from + pageSize, list.length)); + return { + index: pageIndex, + size: pageSize, + items, + totalRecordCount: list.length + }; +}; + +export const getTableOfRecordsState = (items, criteria) => { + const page = getPage(items, criteria.page.index, criteria.page.size, criteria.sort); + + return { + data: { + records: page.items, + totalRecordCount: page.totalRecordCount, + }, + criteria: { + page: { + index: page.index, + size: page.size + }, + sort: criteria.sort, + } + }; +}; + +export const DEFAULT_TABLE_OF_RECORDS_STATE = { + data: { + records: [], + totalRecordCount: 0, + }, + criteria: { + page: { + index: 0, + size: 10, + }, + sort: { + field: 'name', + direction: 'asc', + } + } +}; diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table.js index 0a53d89a93da7..e817c49238f69 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table.js +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table.js @@ -1,138 +1,201 @@ - -import _ from 'lodash'; -import 'ui/paginated_table'; -import fieldControlsHtml from '../field_controls.html'; -import { dateScripts } from './date_scripts'; -import { uiModules } from 'ui/modules'; -import { toastNotifications } from 'ui/notify'; -import template from './scripted_fields_table.html'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import { getSupportedScriptingLanguages, getDeprecatedScriptingLanguages } from 'ui/scripting_languages'; -import { documentationLinks } from 'ui/documentation_links/documentation_links'; - -uiModules.get('apps/management') - .directive('scriptedFieldsTable', function (kbnUrl, $filter, confirmModal) { - const rowScopes = []; // track row scopes, so they can be destroyed as needed - const filter = $filter('filter'); - - return { - restrict: 'E', - template, - scope: true, - link: function ($scope) { - - const fieldCreatorPath = '/management/kibana/indices/{{ indexPattern }}/scriptedField'; - const fieldEditorPath = fieldCreatorPath + '/{{ fieldName }}'; - - $scope.docLinks = documentationLinks.scriptedFields; - $scope.perPage = 25; - $scope.columns = [ - { title: 'name' }, - { title: 'lang' }, - { title: 'script' }, - { title: 'format' }, - { title: 'controls', sortable: false } - ]; - - $scope.$watchMulti(['[]indexPattern.fields', 'fieldFilter', 'scriptedFieldLanguageFilter'], refreshRows); - - function refreshRows() { - _.invoke(rowScopes, '$destroy'); - rowScopes.length = 0; - - const fields = filter($scope.indexPattern.getScriptedFields(), { - name: $scope.fieldFilter, - lang: $scope.scriptedFieldLanguageFilter - }); - _.find($scope.editSections, { index: 'scriptedFields' }).count = fields.length; // Update the tab count - - $scope.rows = fields.map(function (field) { - const rowScope = $scope.$new(); - rowScope.field = field; - rowScopes.push(rowScope); - - return [ - _.escape(field.name), - { - markup: field.lang, - attr: { - 'data-test-subj': 'scriptedFieldLang' - } - }, - _.escape(field.script), - _.get($scope.indexPattern, ['fieldFormatMap', field.name, 'type', 'title']), - { - markup: fieldControlsHtml, - scope: rowScope - } - ]; - }); - } - - $scope.addDateScripts = function () { - const conflictFields = []; - let fieldsAdded = 0; - _.each(dateScripts($scope.indexPattern), function (script, field) { - try { - $scope.indexPattern.addScriptedField(field, script, 'number'); - fieldsAdded++; - } catch (e) { - conflictFields.push(field); - } - }); - - if (fieldsAdded > 0) { - toastNotifications.addSuccess({ - title: 'Created script fields', - text: `Created ${fieldsAdded}`, - }); - } - - if (conflictFields.length > 0) { - toastNotifications.addWarning({ - title: `Didn't add duplicate fields`, - text: `${conflictFields.length} fields: ${conflictFields.join(', ')}`, - }); - } - }; - - $scope.create = function () { - const params = { - indexPattern: $scope.indexPattern.id - }; - - kbnUrl.change(fieldCreatorPath, params); - }; - - $scope.edit = function (field) { - const params = { - indexPattern: $scope.indexPattern.id, - fieldName: field.name - }; - - kbnUrl.change(fieldEditorPath, params); - }; - - $scope.remove = function (field) { - const confirmModalOptions = { - confirmButtonText: 'Delete', - onConfirm: () => { $scope.indexPattern.removeScriptedField(field.name); }, - title: `Delete scripted field '${field.name}'?` - }; - confirmModal(`You can't recover scripted fields.`, confirmModalOptions); - }; - - function getLanguagesInUse() { - const fields = $scope.indexPattern.getScriptedFields(); - return _.uniq(_.map(fields, 'lang')); - } - - $scope.getDeprecatedLanguagesInUse = function () { - return _.intersection(getLanguagesInUse(), getDeprecatedScriptingLanguages()); - }; - - $scope.getUnsupportedLanguagesInUse = function () { - return _.difference(getLanguagesInUse(), _.union(getSupportedScriptingLanguages(), getDeprecatedScriptingLanguages())); - }; +import { documentationLinks } from 'ui/documentation_links'; + +import { + EuiText, + EuiButton, + EuiHorizontalRule, + EuiSpacer, + EuiOverlayMask, + EuiConfirmModal, + EUI_MODAL_CONFIRM_BUTTON, +} from '@elastic/eui'; + +import { Table } from './components/table'; +import { Header } from './components/header'; +import { CallOuts } from './components/call_outs'; +import { getTableOfRecordsState, DEFAULT_TABLE_OF_RECORDS_STATE } from './lib'; + + +export class ScriptedFieldsTable extends Component { + static propTypes = { + indexPattern: PropTypes.object.isRequired, + fieldFilter: PropTypes.string, + scriptedFieldLanguageFilter: PropTypes.string, + helpers: PropTypes.shape({ + redirectToRoute: PropTypes.func.isRequired, + getRouteHref: PropTypes.func.isRequired, + }), + } + + constructor(props) { + super(props); + + this.state = { + deprecatedLangsInUse: [], + fieldToDelete: undefined, + isDeleteConfirmationModalVisible: false, + fields: [], + ...DEFAULT_TABLE_OF_RECORDS_STATE, + }; + } + + componentWillMount() { + this.fetchFields(); + } + + fetchFields = async () => { + const fields = await this.props.indexPattern.getScriptedFields(); + + const deprecatedLangsInUse = []; + const deprecatedLangs = getDeprecatedScriptingLanguages(); + const supportedLangs = getSupportedScriptingLanguages(); + + for (const { lang } of fields) { + if (deprecatedLangs.includes(lang) || !supportedLangs.includes(lang)) { + deprecatedLangsInUse.push(lang); } + } + + this.setState({ + fields, + deprecatedLangsInUse, + ...this.computeTableState(this.state.criteria, this.props, fields) + }); + } + + onDataCriteriaChange = criteria => { + this.setState(this.computeTableState(criteria)); + } + + componentWillReceiveProps(nextProps) { + if (this.props.fieldFilter !== nextProps.fieldFilter) { + this.setState(this.computeTableState(this.state.criteria, nextProps)); + } + if (this.props.scriptedFieldLanguageFilter !== nextProps.scriptedFieldLanguageFilter) { + this.setState(this.computeTableState(this.state.criteria, nextProps)); + } + } + + computeTableState(criteria, props = this.props, fields = this.state.fields) { + let items = fields; + if (props.fieldFilter) { + const fieldFilter = props.fieldFilter.toLowerCase(); + items = items.filter(field => field.name.toLowerCase().includes(fieldFilter)); + } + if (props.scriptedFieldLanguageFilter) { + items = items.filter(field => field.lang === props.scriptedFieldLanguageFilter); + } + + return getTableOfRecordsState(items, criteria); + } + + renderCallOuts() { + const { deprecatedLangsInUse } = this.state; + + return ( + + ); + } + + startDeleteField = field => { + this.setState({ fieldToDelete: field, isDeleteConfirmationModalVisible: true }); + } + + hideDeleteConfirmationModal = () => { + this.setState({ fieldToDelete: undefined, isDeleteConfirmationModalVisible: false }); + } + + deleteField = () => { + const { indexPattern } = this.props; + const { fieldToDelete } = this.state; + + indexPattern.removeScriptedField(fieldToDelete.name); + this.fetchFields(); + this.hideDeleteConfirmationModal(); + } + + renderDeleteConfirmationModal() { + const { fieldToDelete } = this.state; + + if (!fieldToDelete) { + return null; + } + + return ( + + + + ); + } + + renderNoFieldsFound() { + const { fields } = this.state; + + if (fields.length > 0) { + return null; + } + + return ( + + No scripted fields found. + + ); + } + + render() { + const { + helpers, + indexPattern, + } = this.props; + + const { + data, + criteria: { + page, + sort, + }, + } = this.state; + + const model = { + data, + criteria: { + page, + sort, + }, }; - }); + + return ( +
+
+ {this.renderCallOuts()} + + Add Scripted Field + + +
this.props.helpers.redirectToRoute(field, 'edit')} + deleteField={this.startDeleteField} + onDataCriteriaChange={this.onDataCriteriaChange} + /> + {this.renderDeleteConfirmationModal()} + {this.renderNoFieldsFound()} + + + ); + } +} diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table_angular.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table_angular.js new file mode 100644 index 0000000000000..0a53d89a93da7 --- /dev/null +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table_angular.js @@ -0,0 +1,138 @@ + +import _ from 'lodash'; +import 'ui/paginated_table'; +import fieldControlsHtml from '../field_controls.html'; +import { dateScripts } from './date_scripts'; +import { uiModules } from 'ui/modules'; +import { toastNotifications } from 'ui/notify'; +import template from './scripted_fields_table.html'; +import { getSupportedScriptingLanguages, getDeprecatedScriptingLanguages } from 'ui/scripting_languages'; +import { documentationLinks } from 'ui/documentation_links/documentation_links'; + +uiModules.get('apps/management') + .directive('scriptedFieldsTable', function (kbnUrl, $filter, confirmModal) { + const rowScopes = []; // track row scopes, so they can be destroyed as needed + const filter = $filter('filter'); + + return { + restrict: 'E', + template, + scope: true, + link: function ($scope) { + + const fieldCreatorPath = '/management/kibana/indices/{{ indexPattern }}/scriptedField'; + const fieldEditorPath = fieldCreatorPath + '/{{ fieldName }}'; + + $scope.docLinks = documentationLinks.scriptedFields; + $scope.perPage = 25; + $scope.columns = [ + { title: 'name' }, + { title: 'lang' }, + { title: 'script' }, + { title: 'format' }, + { title: 'controls', sortable: false } + ]; + + $scope.$watchMulti(['[]indexPattern.fields', 'fieldFilter', 'scriptedFieldLanguageFilter'], refreshRows); + + function refreshRows() { + _.invoke(rowScopes, '$destroy'); + rowScopes.length = 0; + + const fields = filter($scope.indexPattern.getScriptedFields(), { + name: $scope.fieldFilter, + lang: $scope.scriptedFieldLanguageFilter + }); + _.find($scope.editSections, { index: 'scriptedFields' }).count = fields.length; // Update the tab count + + $scope.rows = fields.map(function (field) { + const rowScope = $scope.$new(); + rowScope.field = field; + rowScopes.push(rowScope); + + return [ + _.escape(field.name), + { + markup: field.lang, + attr: { + 'data-test-subj': 'scriptedFieldLang' + } + }, + _.escape(field.script), + _.get($scope.indexPattern, ['fieldFormatMap', field.name, 'type', 'title']), + { + markup: fieldControlsHtml, + scope: rowScope + } + ]; + }); + } + + $scope.addDateScripts = function () { + const conflictFields = []; + let fieldsAdded = 0; + _.each(dateScripts($scope.indexPattern), function (script, field) { + try { + $scope.indexPattern.addScriptedField(field, script, 'number'); + fieldsAdded++; + } catch (e) { + conflictFields.push(field); + } + }); + + if (fieldsAdded > 0) { + toastNotifications.addSuccess({ + title: 'Created script fields', + text: `Created ${fieldsAdded}`, + }); + } + + if (conflictFields.length > 0) { + toastNotifications.addWarning({ + title: `Didn't add duplicate fields`, + text: `${conflictFields.length} fields: ${conflictFields.join(', ')}`, + }); + } + }; + + $scope.create = function () { + const params = { + indexPattern: $scope.indexPattern.id + }; + + kbnUrl.change(fieldCreatorPath, params); + }; + + $scope.edit = function (field) { + const params = { + indexPattern: $scope.indexPattern.id, + fieldName: field.name + }; + + kbnUrl.change(fieldEditorPath, params); + }; + + $scope.remove = function (field) { + const confirmModalOptions = { + confirmButtonText: 'Delete', + onConfirm: () => { $scope.indexPattern.removeScriptedField(field.name); }, + title: `Delete scripted field '${field.name}'?` + }; + confirmModal(`You can't recover scripted fields.`, confirmModalOptions); + }; + + function getLanguagesInUse() { + const fields = $scope.indexPattern.getScriptedFields(); + return _.uniq(_.map(fields, 'lang')); + } + + $scope.getDeprecatedLanguagesInUse = function () { + return _.intersection(getLanguagesInUse(), getDeprecatedScriptingLanguages()); + }; + + $scope.getUnsupportedLanguagesInUse = function () { + return _.difference(getLanguagesInUse(), _.union(getSupportedScriptingLanguages(), getDeprecatedScriptingLanguages())); + }; + } + }; + }); From 1aa89e6fe13490bda8d545971e40af656092cd89 Mon Sep 17 00:00:00 2001 From: Chris Roberson Date: Thu, 8 Feb 2018 09:47:39 -0500 Subject: [PATCH 2/6] Ensure we destroy when we switch tabs --- .../sections/indices/edit_index_pattern/edit_index_pattern.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.js index 2dd23b51e1aaa..2c471c87d5aa0 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.js +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.js @@ -147,6 +147,8 @@ uiModules.get('apps/management') $scope.tryToRenderScriptedFieldsTable = function () { if ($state.tab === 'scriptedFields') { $scope.$$postDigest($scope.renderScriptedFieldsTable); + } else { + destroyScriptedFieldsTable(); } }; From d2cae1f063c94b0461afebe3d0c9bebc468b9d81 Mon Sep 17 00:00:00 2001 From: Chris Roberson Date: Thu, 8 Feb 2018 10:22:05 -0500 Subject: [PATCH 3/6] PR feedback --- .../indices/edit_index_pattern/edit_index_pattern.js | 1 - .../__snapshots__/scripted_field_table.test.js.snap | 12 ------------ .../scripted_fields_table/scripted_fields_table.js | 2 -- 3 files changed, 15 deletions(-) diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.js index 2c471c87d5aa0..f5a13a2c5c6f0 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.js +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.js @@ -1,7 +1,6 @@ import _ from 'lodash'; import './index_header'; import './indexed_fields_table'; -// import './scripted_fields_table'; import './scripted_field_editor'; import './source_filters_table'; import { KbnUrlProvider } from 'ui/url'; diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/__snapshots__/scripted_field_table.test.js.snap b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/__snapshots__/scripted_field_table.test.js.snap index 3d1e53a261f74..714c5e66f238a 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/__snapshots__/scripted_field_table.test.js.snap +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/__snapshots__/scripted_field_table.test.js.snap @@ -74,9 +74,6 @@ exports[`ScriptedFieldsTable should filter based on the lang filter 1`] = ` > table
- `; @@ -146,9 +143,6 @@ exports[`ScriptedFieldsTable should filter based on the query bar 1`] = ` > table - `; @@ -222,9 +216,6 @@ exports[`ScriptedFieldsTable should render normally 1`] = ` > table - `; @@ -290,9 +281,6 @@ exports[`ScriptedFieldsTable should show a message if there are no scripted fiel No scripted fields found. - `; diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table.js index e817c49238f69..a0903834cd249 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table.js +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table.js @@ -6,7 +6,6 @@ import { documentationLinks } from 'ui/documentation_links'; import { EuiText, EuiButton, - EuiHorizontalRule, EuiSpacer, EuiOverlayMask, EuiConfirmModal, @@ -194,7 +193,6 @@ export class ScriptedFieldsTable extends Component { /> {this.renderDeleteConfirmationModal()} {this.renderNoFieldsFound()} - ); } From fe6e112c9ec4c07d422481783d27d6e09e3d0c97 Mon Sep 17 00:00:00 2001 From: Chris Roberson Date: Thu, 8 Feb 2018 10:38:50 -0500 Subject: [PATCH 4/6] Fix functional tests --- .../__snapshots__/scripted_field_table.test.js.snap | 4 ++++ .../scripted_fields_table/scripted_fields_table.js | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/__snapshots__/scripted_field_table.test.js.snap b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/__snapshots__/scripted_field_table.test.js.snap index 714c5e66f238a..f7a2eb5e7dcd6 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/__snapshots__/scripted_field_table.test.js.snap +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/__snapshots__/scripted_field_table.test.js.snap @@ -26,6 +26,7 @@ exports[`ScriptedFieldsTable should filter based on the lang filter 1`] = ` painlessDocLink="painlessDocs" /> Add Scripted Field @@ -100,6 +101,7 @@ exports[`ScriptedFieldsTable should filter based on the query bar 1`] = ` painlessDocLink="painlessDocs" /> Add Scripted Field @@ -168,6 +170,7 @@ exports[`ScriptedFieldsTable should render normally 1`] = ` painlessDocLink="painlessDocs" /> Add Scripted Field @@ -241,6 +244,7 @@ exports[`ScriptedFieldsTable should show a message if there are no scripted fiel painlessDocLink="painlessDocs" /> Add Scripted Field diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table.js index a0903834cd249..500180840870f 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table.js +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table.js @@ -180,7 +180,10 @@ export class ScriptedFieldsTable extends Component {
{this.renderCallOuts()} - + Add Scripted Field From 70cdca1ec9f928a0e90daac33fc655a190271432 Mon Sep 17 00:00:00 2001 From: Chris Roberson Date: Thu, 8 Feb 2018 13:19:47 -0500 Subject: [PATCH 5/6] Fix functional tests --- .../table/__tests__/__snapshots__/table.test.js.snap | 3 ++- .../scripted_fields_table/components/table/table.js | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/__tests__/__snapshots__/table.test.js.snap b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/__tests__/__snapshots__/table.test.js.snap index b979f0b85bd57..f7c77884101cd 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/__tests__/__snapshots__/table.test.js.snap +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/__tests__/__snapshots__/table.test.js.snap @@ -16,7 +16,8 @@ exports[`Table should render normally 1`] = ` "dataType": "string", "description": "Language used for the field", "field": "lang", - "name": "Name", + "name": "Lang", + "render": [Function], "sortable": true, }, Object { diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/table.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/table.js index ad9a756617a5d..9f75c6e7874a5 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/table.js +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/table.js @@ -56,10 +56,17 @@ export class Table extends PureComponent { }, { field: 'lang', - name: 'Name', + name: 'Lang', description: `Language used for the field`, dataType: 'string', sortable: true, + render: value => { + return ( + + {value} + + ); + } }, { field: 'script', From 1376df5b87105ae83e19383958603b7b051021a7 Mon Sep 17 00:00:00 2001 From: Chris Roberson Date: Fri, 9 Feb 2018 10:53:36 -0500 Subject: [PATCH 6/6] PR feedback and more tests --- .../edit_index_pattern.html | 5 +- .../edit_index_pattern/edit_index_pattern.js | 78 +-- .../edit_index_pattern/edit_sections.js | 6 +- .../scripted_field_table.test.js.snap | 487 ++++++++---------- .../__tests__/scripted_field_table.test.js | 48 +- .../__snapshots__/call_outs.test.js.snap | 8 +- .../components/call_outs/call_outs.js | 8 +- .../__snapshots__/header.test.js.snap | 2 +- .../components/header/header.js | 5 +- .../__snapshots__/table.test.js.snap | 6 + .../components/table/__tests__/table.test.js | 60 ++- .../scripted_fields_table/date_scripts.js | 26 - .../scripted_fields_table/index.js | 35 +- .../scripted_fields_table.html | 80 --- .../scripted_fields_table.js | 40 +- .../scripted_fields_table_angular.js | 138 ----- 16 files changed, 413 insertions(+), 619 deletions(-) delete mode 100644 src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/date_scripts.js delete mode 100644 src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table.html delete mode 100644 src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table_angular.js diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.html b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.html index 3cecfe82a8def..8afc1837e6c7c 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.html +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.html @@ -23,10 +23,7 @@

- This page lists every field in the {{::indexPattern.title}} - index and the field's associated core type as recorded by Elasticsearch. - While this list allows you to view the core type of each field, changing - field types must be done using Elasticsearch's + This page lists every field in the {{::indexPattern.title}} index and the field's associated core type as recorded by Elasticsearch. To change a field type, use the Elasticsearch Mapping API diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.js index f5a13a2c5c6f0..8a8d1fb3c8e4f 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.js +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_index_pattern.js @@ -10,7 +10,49 @@ import uiRoutes from 'ui/routes'; import { uiModules } from 'ui/modules'; import template from './edit_index_pattern.html'; -import { renderScriptedFieldsTable, destroyScriptedFieldsTable } from './scripted_fields_table'; +import React from 'react'; +import { render, unmountComponentAtNode } from 'react-dom'; +import { ScriptedFieldsTable } from './scripted_fields_table'; + +const REACT_SCRIPTED_FIELDS_DOM_ELEMENT_ID = 'reactScriptedFieldsTable'; + +function updateScriptedFieldsTable($scope, $state) { + if ($state.tab === 'scriptedFields') { + $scope.$$postDigest(() => { + const node = document.getElementById(REACT_SCRIPTED_FIELDS_DOM_ELEMENT_ID); + if (!node) { + return; + } + + render( + { + $scope.kbnUrl.redirectToRoute(obj, route); + $scope.$apply(); + }, + getRouteHref: (obj, route) => $scope.kbnUrl.getRouteHref(obj, route), + }} + onRemoveField={() => { + $scope.editSections = $scope.editSectionsProvider($scope.indexPattern); + $scope.refreshFilters(); + }} + />, + node, + ); + }); + } else { + destroyScriptedFieldsTable(); + } +} + +function destroyScriptedFieldsTable() { + const node = document.getElementById(REACT_SCRIPTED_FIELDS_DOM_ELEMENT_ID); + node && unmountComponentAtNode(node); +} uiRoutes .when('/management/kibana/indices/:indexPatternId', { @@ -46,6 +88,7 @@ uiModules.get('apps/management') const notify = new Notifier(); const $state = $scope.state = new AppState(); + $scope.editSectionsProvider = Private(IndicesEditSectionsProvider); $scope.kbnUrl = Private(KbnUrlProvider); $scope.indexPattern = $route.current.locals.indexPattern; docTitle.change($scope.indexPattern.title); @@ -55,7 +98,7 @@ uiModules.get('apps/management') }); $scope.$watch('indexPattern.fields', function () { - $scope.editSections = Private(IndicesEditSectionsProvider)($scope.indexPattern); + $scope.editSections = $scope.editSectionsProvider($scope.indexPattern); $scope.refreshFilters(); }); @@ -80,7 +123,7 @@ uiModules.get('apps/management') $scope.changeTab = function (obj) { $state.tab = obj.index; - $scope.tryToRenderScriptedFieldsTable(); + updateScriptedFieldsTable($scope, $state); $state.save(); }; @@ -143,38 +186,15 @@ uiModules.get('apps/management') return $scope.indexPattern.save(); }; - $scope.tryToRenderScriptedFieldsTable = function () { - if ($state.tab === 'scriptedFields') { - $scope.$$postDigest($scope.renderScriptedFieldsTable); - } else { - destroyScriptedFieldsTable(); - } - }; - - $scope.renderScriptedFieldsTable = function () { - renderScriptedFieldsTable( - $scope.indexPattern, - $scope.fieldFilter, - $scope.scriptedFieldLanguageFilter, - { - redirectToRoute: (obj, route) => { - $scope.kbnUrl.redirectToRoute(obj, route); - $scope.$apply(); - }, - getRouteHref: (obj, route) => $scope.kbnUrl.getRouteHref(obj, route), - } - ); - }; - $scope.$watch('fieldFilter', () => { if ($scope.fieldFilter !== undefined && $state.tab === 'scriptedFields') { - $scope.renderScriptedFieldsTable(); + updateScriptedFieldsTable($scope, $state); } }); $scope.$watch('scriptedFieldLanguageFilter', () => { if ($scope.scriptedFieldLanguageFilter !== undefined && $state.tab === 'scriptedFields') { - $scope.renderScriptedFieldsTable(); + updateScriptedFieldsTable($scope, $state); } }); @@ -182,5 +202,5 @@ uiModules.get('apps/management') destroyScriptedFieldsTable(); }); - $scope.tryToRenderScriptedFieldsTable(); + updateScriptedFieldsTable($scope, $state); }); diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_sections.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_sections.js index c83b7bbe2d4c2..c538a894ed287 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_sections.js +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/edit_sections.js @@ -15,17 +15,17 @@ export function IndicesEditSectionsProvider() { return [ { - title: 'fields', + title: 'Fields', index: 'indexedFields', count: fieldCount.indexed }, { - title: 'scripted fields', + title: 'Scripted fields', index: 'scriptedFields', count: fieldCount.scripted }, { - title: 'source filters', + title: 'Source filters', index: 'sourceFilters', count: fieldCount.sourceFilters } diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/__snapshots__/scripted_field_table.test.js.snap b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/__snapshots__/scripted_field_table.test.js.snap index f7a2eb5e7dcd6..e80f3de86d401 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/__snapshots__/scripted_field_table.test.js.snap +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/__snapshots__/scripted_field_table.test.js.snap @@ -1,290 +1,255 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`ScriptedFieldsTable should filter based on the lang filter 1`] = ` - +

+ -
-
- - - Add Scripted Field - - - + + Add scripted field + + +
- table -
-
- + } + onDataCriteriaChange={[Function]} + /> +
`; exports[`ScriptedFieldsTable should filter based on the query bar 1`] = ` - -
-
- - - Add Scripted Field - - - +
+ + + Add scripted field + + +
- table -
-
-
+ } + onDataCriteriaChange={[Function]} + /> + +`; + +exports[`ScriptedFieldsTable should hide the table if there are no scripted fields 1`] = ` +
+
+ + + Add scripted field + + +
`; exports[`ScriptedFieldsTable should render normally 1`] = ` - -
-
- - - Add Scripted Field - - - +
+ + + Add scripted field + + +
- table -
-
-
+ } + onDataCriteriaChange={[Function]} + /> + `; -exports[`ScriptedFieldsTable should show a message if there are no scripted fields 1`] = ` - -
-
- - - Add Scripted Field - - - +
+ + + Add scripted field + + +
- table -
- - No scripted fields found. - -
-
+ } + onDataCriteriaChange={[Function]} + /> + + + + `; diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/scripted_field_table.test.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/scripted_field_table.test.js index daae70282a97e..63a39ec8c08b7 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/scripted_field_table.test.js +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/__tests__/scripted_field_table.test.js @@ -1,5 +1,5 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { shallow } from 'enzyme'; import { ScriptedFieldsTable } from '../scripted_fields_table'; @@ -54,7 +54,7 @@ const indexPattern = { describe('ScriptedFieldsTable', () => { it('should render normally', async () => { - const component = mount( + const component = shallow( { }); it('should filter based on the query bar', async () => { - const component = mount( + const component = shallow( { }); it('should filter based on the lang filter', async () => { - const component = mount( + const component = shallow( ([ @@ -113,8 +113,8 @@ describe('ScriptedFieldsTable', () => { expect(component).toMatchSnapshot(); }); - it('should show a message if there are no scripted fields', async () => { - const component = mount( + it('should hide the table if there are no scripted fields', async () => { + const component = shallow( ([]) @@ -130,4 +130,40 @@ describe('ScriptedFieldsTable', () => { expect(component).toMatchSnapshot(); }); + + it('should show a delete modal', async () => { + const component = shallow( + + ); + + await component.update(); // Fire `componentWillMount()` + component.instance().startDeleteField({ name: 'ScriptedField' }); + await component.update(); + + // Ensure the modal is visible + expect(component).toMatchSnapshot(); + }); + + it('should delete a field', async () => { + const removeScriptedField = jest.fn(); + const component = shallow( + + ); + + await component.update(); // Fire `componentWillMount()` + component.instance().startDeleteField({ name: 'ScriptedField' }); + await component.update(); + await component.instance().deleteField(); + await component.update(); + expect(removeScriptedField).toBeCalled(); + }); }); diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/call_outs/__tests__/__snapshots__/call_outs.test.js.snap b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/call_outs/__tests__/__snapshots__/call_outs.test.js.snap index e188c9f58b515..66b1cfd191a60 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/call_outs/__tests__/__snapshots__/call_outs.test.js.snap +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/call_outs/__tests__/__snapshots__/call_outs.test.js.snap @@ -6,12 +6,12 @@ exports[`CallOuts should render normally 1`] = ` color="danger" iconType="cross" size="m" - title="Deprecation Warning" + title="Deprecation languages in use" >

- We've detected that the following deprecated languages are in use: + The following deprecated languages are in use: php - . Support for these languages will be removed in the next major version of Kibana and Elasticsearch. We recommend converting your scripted fields to + . Support for these languages will be removed in the next major version of Kibana and Elasticsearch. Convert you scripted fields to Painless - . + to avoid any problems.

- We've detected that the following deprecated languages are in use: {deprecatedLangsInUse.join(', ')}. - Support for these languages will be removed in the next major version of Kibana and Elasticsearch. - We recommend converting your scripted fields to Painless. + The following deprecated languages are in use: {deprecatedLangsInUse.join(', ')}. + Support for these languages will be removed in the next major version of Kibana + and Elasticsearch. Convert you scripted fields to Painless to avoid any problems.

diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/header/__tests__/__snapshots__/header.test.js.snap b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/header/__tests__/__snapshots__/header.test.js.snap index 937eabb7cad49..546262f62f45a 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/header/__tests__/__snapshots__/header.test.js.snap +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/header/__tests__/__snapshots__/header.test.js.snap @@ -11,7 +11,7 @@ exports[`Header should render normally 1`] = `

- These scripted fields are computed on the fly from your data. They can be used in visualizations and displayed in your documents, however they can not be searched. You can manage them here and add new ones as you see fit, but be careful, scripts can be tricky! + You can use scripted fields in visualizations and display them in your documents. However, you cannot search scripted fields.

(

- These scripted fields are computed on the fly from your data. - They can be used in visualizations and displayed in your documents, however they can not be searched. - You can manage them here and add new ones as you see fit, but be careful, scripts can be tricky! + You can use scripted fields in visualizations and display them in your documents. + However, you cannot search scripted fields.

diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/__tests__/__snapshots__/table.test.js.snap b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/__tests__/__snapshots__/table.test.js.snap index f7c77884101cd..91a623f8cf899 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/__tests__/__snapshots__/table.test.js.snap +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/__tests__/__snapshots__/table.test.js.snap @@ -91,3 +91,9 @@ exports[`Table should render normally 1`] = ` } /> `; + +exports[`Table should render the format 1`] = ` + + string + +`; diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/__tests__/table.test.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/__tests__/table.test.js index dd8c98dcedb83..02a2e26287868 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/__tests__/table.test.js +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/components/table/__tests__/table.test.js @@ -4,7 +4,13 @@ import { shallow } from 'enzyme'; import { Table } from '../table'; const indexPattern = { - fieldFormatMap: {} + fieldFormatMap: { + Elastic: { + type: { + title: 'string' + } + } + } }; const model = { @@ -38,4 +44,56 @@ describe('Table', () => { expect(component).toMatchSnapshot(); }); + + it('should render the format', async () => { + const component = shallow( + {}} + deleteField={() => {}} + onDataCriteriaChange={() => {}} + /> + ); + + const formatTableCell = shallow(component.prop('config').columns[3].render('Elastic')); + expect(formatTableCell).toMatchSnapshot(); + }); + + it('should allow edits', () => { + const editField = jest.fn(); + + const component = shallow( +
{}} + onDataCriteriaChange={() => {}} + /> + ); + + // Click the delete button + component.prop('config').columns[4].actions[0].onClick(); + expect(editField).toBeCalled(); + }); + + it('should allow deletes', () => { + const deleteField = jest.fn(); + + const component = shallow( +
{}} + deleteField={deleteField} + onDataCriteriaChange={() => {}} + /> + ); + + // Click the delete button + component.prop('config').columns[4].actions[1].onClick(); + expect(deleteField).toBeCalled(); + }); + }); diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/date_scripts.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/date_scripts.js deleted file mode 100644 index 559bb2a31a806..0000000000000 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/date_scripts.js +++ /dev/null @@ -1,26 +0,0 @@ -import _ from 'lodash'; - -export function dateScripts(indexPattern) { - const dateScripts = {}; - const scripts = { - __dayOfMonth: 'dayOfMonth', - __dayOfWeek: 'dayOfWeek', - __dayOfYear: 'dayOfYear', - __hourOfDay: 'hourOfDay', - __minuteOfDay: 'minuteOfDay', - __minuteOfHour: 'minuteOfHour', - __monthOfYear: 'monthOfYear', - __weekOfYear: 'weekOfWeekyear', - __year: 'year' - }; - - _.each(indexPattern.fields.byType.date, function (field) { - if (field.indexed) { - _.each(scripts, function (value, key) { - dateScripts[field.name + '.' + key] = 'doc["' + field.name + '"].date.' + value; - }); - } - }); - - return dateScripts; -} diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/index.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/index.js index 317ad472e05a6..3083fd4de7539 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/index.js +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/index.js @@ -1,34 +1 @@ -import React from 'react'; -import { render, unmountComponentAtNode } from 'react-dom'; -import { ScriptedFieldsTable } from './scripted_fields_table'; - -import './scripted_fields_table_angular'; - -const DOM_ELEMENT_ID = 'reactScriptedFieldsTable'; - -export function renderScriptedFieldsTable( - indexPattern, - fieldFilter, - scriptedFieldLanguageFilter, - helpers, -) { - const node = document.getElementById(DOM_ELEMENT_ID); - if (!node) { - return; - } - - render( - , - node, - ); -} - -export function destroyScriptedFieldsTable() { - const node = document.getElementById(DOM_ELEMENT_ID); - node && unmountComponentAtNode(node); -} +export { ScriptedFieldsTable } from './scripted_fields_table'; diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table.html b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table.html deleted file mode 100644 index 98b5eaa438c2c..0000000000000 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table.html +++ /dev/null @@ -1,80 +0,0 @@ -

- Scripted fields -

- -

- These scripted fields are computed on the fly from your data. They can be used in visualizations and displayed in your documents, however they can not be searched. You can manage them here and add new ones as you see fit, but be careful, scripts can be tricky! -

- -
-
- - - Deprecation Warning - -
- -
-
- We've detected that the following deprecated languages are in use: {{ getDeprecatedLanguagesInUse().join(', ') }}. - Support for these languages will be removed in the next major version of Kibana and Elasticsearch. - We recommend converting your scripted fields to - Painless. -
-
-
- -
-
- - - Unsupported Languages - -
- -
-
- We've detected that the following unsupported languages are in use: {{ getUnsupportedLanguagesInUse().join(', ') }}. - All scripted fields must be converted to Painless. -
-
-
- - - - Add Scripted Field - - -
- -
- -
-
- - - No scripted fields found. - -
-
diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table.js index 500180840870f..1104075f54c4c 100644 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table.js +++ b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table.js @@ -4,7 +4,6 @@ import { getSupportedScriptingLanguages, getDeprecatedScriptingLanguages } from import { documentationLinks } from 'ui/documentation_links'; import { - EuiText, EuiButton, EuiSpacer, EuiOverlayMask, @@ -27,6 +26,7 @@ export class ScriptedFieldsTable extends Component { redirectToRoute: PropTypes.func.isRequired, getRouteHref: PropTypes.func.isRequired, }), + onRemoveField: PropTypes.func, } constructor(props) { @@ -111,10 +111,11 @@ export class ScriptedFieldsTable extends Component { } deleteField = () => { - const { indexPattern } = this.props; + const { indexPattern, onRemoveField } = this.props; const { fieldToDelete } = this.state; indexPattern.removeScriptedField(fieldToDelete.name); + onRemoveField && onRemoveField(); this.fetchFields(); this.hideDeleteConfirmationModal(); } @@ -140,20 +141,6 @@ export class ScriptedFieldsTable extends Component { ); } - renderNoFieldsFound() { - const { fields } = this.state; - - if (fields.length > 0) { - return null; - } - - return ( - - No scripted fields found. - - ); - } - render() { const { helpers, @@ -166,6 +153,7 @@ export class ScriptedFieldsTable extends Component { page, sort, }, + fields, } = this.state; const model = { @@ -184,18 +172,20 @@ export class ScriptedFieldsTable extends Component { data-test-subj="addScriptedFieldLink" href={helpers.getRouteHref(indexPattern, 'addField')} > - Add Scripted Field + Add scripted field -
this.props.helpers.redirectToRoute(field, 'edit')} - deleteField={this.startDeleteField} - onDataCriteriaChange={this.onDataCriteriaChange} - /> + { fields.length > 0 ? +
this.props.helpers.redirectToRoute(field, 'edit')} + deleteField={this.startDeleteField} + onDataCriteriaChange={this.onDataCriteriaChange} + /> + : null + } {this.renderDeleteConfirmationModal()} - {this.renderNoFieldsFound()} ); } diff --git a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table_angular.js b/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table_angular.js deleted file mode 100644 index 0a53d89a93da7..0000000000000 --- a/src/core_plugins/kibana/public/management/sections/indices/edit_index_pattern/scripted_fields_table/scripted_fields_table_angular.js +++ /dev/null @@ -1,138 +0,0 @@ - -import _ from 'lodash'; -import 'ui/paginated_table'; -import fieldControlsHtml from '../field_controls.html'; -import { dateScripts } from './date_scripts'; -import { uiModules } from 'ui/modules'; -import { toastNotifications } from 'ui/notify'; -import template from './scripted_fields_table.html'; -import { getSupportedScriptingLanguages, getDeprecatedScriptingLanguages } from 'ui/scripting_languages'; -import { documentationLinks } from 'ui/documentation_links/documentation_links'; - -uiModules.get('apps/management') - .directive('scriptedFieldsTable', function (kbnUrl, $filter, confirmModal) { - const rowScopes = []; // track row scopes, so they can be destroyed as needed - const filter = $filter('filter'); - - return { - restrict: 'E', - template, - scope: true, - link: function ($scope) { - - const fieldCreatorPath = '/management/kibana/indices/{{ indexPattern }}/scriptedField'; - const fieldEditorPath = fieldCreatorPath + '/{{ fieldName }}'; - - $scope.docLinks = documentationLinks.scriptedFields; - $scope.perPage = 25; - $scope.columns = [ - { title: 'name' }, - { title: 'lang' }, - { title: 'script' }, - { title: 'format' }, - { title: 'controls', sortable: false } - ]; - - $scope.$watchMulti(['[]indexPattern.fields', 'fieldFilter', 'scriptedFieldLanguageFilter'], refreshRows); - - function refreshRows() { - _.invoke(rowScopes, '$destroy'); - rowScopes.length = 0; - - const fields = filter($scope.indexPattern.getScriptedFields(), { - name: $scope.fieldFilter, - lang: $scope.scriptedFieldLanguageFilter - }); - _.find($scope.editSections, { index: 'scriptedFields' }).count = fields.length; // Update the tab count - - $scope.rows = fields.map(function (field) { - const rowScope = $scope.$new(); - rowScope.field = field; - rowScopes.push(rowScope); - - return [ - _.escape(field.name), - { - markup: field.lang, - attr: { - 'data-test-subj': 'scriptedFieldLang' - } - }, - _.escape(field.script), - _.get($scope.indexPattern, ['fieldFormatMap', field.name, 'type', 'title']), - { - markup: fieldControlsHtml, - scope: rowScope - } - ]; - }); - } - - $scope.addDateScripts = function () { - const conflictFields = []; - let fieldsAdded = 0; - _.each(dateScripts($scope.indexPattern), function (script, field) { - try { - $scope.indexPattern.addScriptedField(field, script, 'number'); - fieldsAdded++; - } catch (e) { - conflictFields.push(field); - } - }); - - if (fieldsAdded > 0) { - toastNotifications.addSuccess({ - title: 'Created script fields', - text: `Created ${fieldsAdded}`, - }); - } - - if (conflictFields.length > 0) { - toastNotifications.addWarning({ - title: `Didn't add duplicate fields`, - text: `${conflictFields.length} fields: ${conflictFields.join(', ')}`, - }); - } - }; - - $scope.create = function () { - const params = { - indexPattern: $scope.indexPattern.id - }; - - kbnUrl.change(fieldCreatorPath, params); - }; - - $scope.edit = function (field) { - const params = { - indexPattern: $scope.indexPattern.id, - fieldName: field.name - }; - - kbnUrl.change(fieldEditorPath, params); - }; - - $scope.remove = function (field) { - const confirmModalOptions = { - confirmButtonText: 'Delete', - onConfirm: () => { $scope.indexPattern.removeScriptedField(field.name); }, - title: `Delete scripted field '${field.name}'?` - }; - confirmModal(`You can't recover scripted fields.`, confirmModalOptions); - }; - - function getLanguagesInUse() { - const fields = $scope.indexPattern.getScriptedFields(); - return _.uniq(_.map(fields, 'lang')); - } - - $scope.getDeprecatedLanguagesInUse = function () { - return _.intersection(getLanguagesInUse(), getDeprecatedScriptingLanguages()); - }; - - $scope.getUnsupportedLanguagesInUse = function () { - return _.difference(getLanguagesInUse(), _.union(getSupportedScriptingLanguages(), getDeprecatedScriptingLanguages())); - }; - } - }; - });