diff --git a/src/legacy/core_plugins/vis_type_table/public/__tests__/table_vis_controller.js b/src/legacy/core_plugins/vis_type_table/public/__tests__/table_vis_controller.js
deleted file mode 100644
index e22dd4caa6d01..0000000000000
--- a/src/legacy/core_plugins/vis_type_table/public/__tests__/table_vis_controller.js
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * 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 $ from 'jquery';
-import expect from '@kbn/expect';
-import ngMock from 'ng_mock';
-import { legacyResponseHandlerProvider } from 'ui/vis/response_handlers/legacy';
-import { Vis } from '../../../visualizations/public';
-import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
-import { AppStateProvider } from 'ui/state_management/app_state';
-import { tabifyAggResponse } from 'ui/agg_response/tabify';
-
-import { tableVisTypeDefinition } from '../table_vis_type';
-import { setup as visualizationsSetup } from '../../../visualizations/public/np_ready/public/legacy';
-
-describe('Table Vis - Controller', async function () {
- let $rootScope;
- let $compile;
- let Private;
- let $scope;
- let $el;
- let fixtures;
- let AppState;
- let tableAggResponse;
- let tabifiedResponse;
-
- ngMock.inject(function () {
-
- visualizationsSetup.types.createBaseVisualization(tableVisTypeDefinition);
- });
-
- beforeEach(ngMock.module('kibana', 'kibana/table_vis'));
- beforeEach(
- ngMock.inject(function ($injector) {
- Private = $injector.get('Private');
- $rootScope = $injector.get('$rootScope');
- $compile = $injector.get('$compile');
- fixtures = require('fixtures/fake_hierarchical_data');
- AppState = Private(AppStateProvider);
- tableAggResponse = legacyResponseHandlerProvider().handler;
- })
- );
-
- function OneRangeVis(params) {
- return new Vis(Private(FixturesStubbedLogstashIndexPatternProvider), {
- type: 'table',
- params: params || {},
- aggs: [
- { type: 'count', schema: 'metric' },
- {
- type: 'range',
- schema: 'bucket',
- params: {
- field: 'bytes',
- ranges: [{ from: 0, to: 1000 }, { from: 1000, to: 2000 }],
- },
- },
- ],
- });
- }
-
- const dimensions = {
- buckets: [
- {
- accessor: 0,
- },
- ],
- metrics: [
- {
- accessor: 1,
- format: { id: 'range' },
- },
- ],
- };
-
- // basically a parameterized beforeEach
- function initController(vis) {
- vis.aggs.aggs.forEach(function (agg, i) {
- agg.id = 'agg_' + (i + 1);
- });
-
- tabifiedResponse = tabifyAggResponse(vis.aggs, fixtures.oneRangeBucket);
- $rootScope.vis = vis;
- $rootScope.visParams = vis.params;
- $rootScope.uiState = new AppState({ uiState: {} }).makeStateful('uiState');
- $rootScope.renderComplete = () => {};
- $rootScope.newScope = function (scope) {
- $scope = scope;
- };
-
- $el = $('
')
- .attr('ng-controller', 'KbnTableVisController')
- .attr('ng-init', 'newScope(this)');
-
- $compile($el)($rootScope);
- }
-
- // put a response into the controller
- function attachEsResponseToScope(resp) {
- $rootScope.esResponse = resp;
- $rootScope.$apply();
- }
-
- // remove the response from the controller
- function removeEsResponseFromScope() {
- delete $rootScope.esResponse;
- $rootScope.renderComplete = () => {};
- $rootScope.$apply();
- }
-
- it('exposes #tableGroups and #hasSomeRows when a response is attached to scope', async function () {
- const vis = new OneRangeVis();
- initController(vis);
-
- expect(!$scope.tableGroups).to.be.ok();
- expect(!$scope.hasSomeRows).to.be.ok();
-
- attachEsResponseToScope(await tableAggResponse(tabifiedResponse, dimensions));
-
- expect($scope.hasSomeRows).to.be(true);
- expect($scope.tableGroups).to.have.property('tables');
- expect($scope.tableGroups.tables).to.have.length(1);
- expect($scope.tableGroups.tables[0].columns).to.have.length(2);
- expect($scope.tableGroups.tables[0].rows).to.have.length(2);
- });
-
- it('clears #tableGroups and #hasSomeRows when the response is removed', async function () {
- const vis = new OneRangeVis();
- initController(vis);
-
- attachEsResponseToScope(await tableAggResponse(tabifiedResponse, dimensions));
- removeEsResponseFromScope();
-
- expect(!$scope.hasSomeRows).to.be.ok();
- expect(!$scope.tableGroups).to.be.ok();
- });
-
- it('sets the sort on the scope when it is passed as a vis param', async function () {
- const sortObj = {
- columnIndex: 1,
- direction: 'asc',
- };
- const vis = new OneRangeVis({ sort: sortObj });
- initController(vis);
-
- attachEsResponseToScope(await tableAggResponse(tabifiedResponse, dimensions));
-
- expect($scope.sort.columnIndex).to.equal(sortObj.columnIndex);
- expect($scope.sort.direction).to.equal(sortObj.direction);
- });
-
- it('sets #hasSomeRows properly if the table group is empty', async function () {
- const vis = new OneRangeVis();
- initController(vis);
-
- tabifiedResponse.rows = [];
-
- attachEsResponseToScope(await tableAggResponse(tabifiedResponse, dimensions));
-
- expect($scope.hasSomeRows).to.be(false);
- expect(!$scope.tableGroups).to.be.ok();
- });
-
- it('passes partialRows:true to tabify based on the vis params', function () {
- const vis = new OneRangeVis({ showPartialRows: true });
- initController(vis);
-
- expect(vis.isHierarchical()).to.equal(true);
- });
-
- it('passes partialRows:false to tabify based on the vis params', function () {
- const vis = new OneRangeVis({ showPartialRows: false });
- initController(vis);
-
- expect(vis.isHierarchical()).to.equal(false);
- });
-});
diff --git a/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table.js b/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table.js
index 2978856a3511d..25a28333b07ff 100644
--- a/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table.js
+++ b/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table.js
@@ -23,14 +23,15 @@ import ngMock from 'ng_mock';
import expect from '@kbn/expect';
import fixtures from 'fixtures/fake_hierarchical_data';
import sinon from 'sinon';
-import { legacyResponseHandlerProvider } from 'ui/vis/response_handlers/legacy';
+import { legacyResponseHandlerProvider, tabifyAggResponse, npStart } from '../../legacy_imports';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
-import { Vis } from '../../../../visualizations/public';
-import { tabifyAggResponse } from 'ui/agg_response/tabify';
import { round } from 'lodash';
+import { Vis } from '../../../../visualizations/public';
import { tableVisTypeDefinition } from '../../table_vis_type';
import { setup as visualizationsSetup } from '../../../../visualizations/public/np_ready/public/legacy';
+import { getAngularModule } from '../../get_inner_angular';
+import { initTableVisLegacyModule } from '../../table_vis_legacy_module';
describe('Table Vis - AggTable Directive', function () {
let $rootScope;
@@ -96,11 +97,18 @@ describe('Table Vis - AggTable Directive', function () {
);
};
+ const initLocalAngular = () => {
+ const tableVisModule = getAngularModule('kibana/table_vis', npStart.core);
+ initTableVisLegacyModule(tableVisModule);
+ };
+
+ beforeEach(initLocalAngular);
+
ngMock.inject(function () {
visualizationsSetup.types.createBaseVisualization(tableVisTypeDefinition);
});
- beforeEach(ngMock.module('kibana'));
+ beforeEach(ngMock.module('kibana/table_vis'));
beforeEach(
ngMock.inject(function ($injector, Private, config) {
tableAggResponse = legacyResponseHandlerProvider().handler;
diff --git a/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table_group.js b/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table_group.js
index f4e3a8e36605c..be981829ae909 100644
--- a/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table_group.js
+++ b/src/legacy/core_plugins/vis_type_table/public/agg_table/__tests__/agg_table_group.js
@@ -21,10 +21,11 @@ import $ from 'jquery';
import ngMock from 'ng_mock';
import expect from '@kbn/expect';
import fixtures from 'fixtures/fake_hierarchical_data';
-import { legacyResponseHandlerProvider } from 'ui/vis/response_handlers/legacy';
+import { legacyResponseHandlerProvider, tabifyAggResponse, npStart } from '../../legacy_imports';
import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern';
-import { Vis } from 'ui/vis';
-import { tabifyAggResponse } from 'ui/agg_response/tabify';
+import { Vis } from '../../../../visualizations/public';
+import { getAngularModule } from '../../get_inner_angular';
+import { initTableVisLegacyModule } from '../../table_vis_legacy_module';
describe('Table Vis - AggTableGroup Directive', function () {
let $rootScope;
@@ -52,7 +53,14 @@ describe('Table Vis - AggTableGroup Directive', function () {
tabifiedData.threeTermBuckets = tabifyAggResponse(vis2.aggs, fixtures.threeTermBuckets);
};
- beforeEach(ngMock.module('kibana'));
+ const initLocalAngular = () => {
+ const tableVisModule = getAngularModule('kibana/table_vis', npStart.core);
+ initTableVisLegacyModule(tableVisModule);
+ };
+
+ beforeEach(initLocalAngular);
+
+ beforeEach(ngMock.module('kibana/table_vis'));
beforeEach(
ngMock.inject(function ($injector, Private) {
// this is provided in table_vis_controller.js
diff --git a/src/legacy/core_plugins/vis_type_table/public/agg_table/agg_table.js b/src/legacy/core_plugins/vis_type_table/public/agg_table/agg_table.js
index 06cca15f88556..8bc275f5255bb 100644
--- a/src/legacy/core_plugins/vis_type_table/public/agg_table/agg_table.js
+++ b/src/legacy/core_plugins/vis_type_table/public/agg_table/agg_table.js
@@ -18,7 +18,7 @@
*/
import _ from 'lodash';
import aggTableTemplate from './agg_table.html';
-import { getFormat } from 'ui/visualize/loader/pipeline_helpers/utilities';
+import { getFormat } from '../legacy_imports';
import { i18n } from '@kbn/i18n';
export function KbnAggTable(config, RecursionHelper) {
diff --git a/src/legacy/core_plugins/vis_type_table/public/components/table_vis_options.tsx b/src/legacy/core_plugins/vis_type_table/public/components/table_vis_options.tsx
index fdcd531ad6930..4d69af59b0c99 100644
--- a/src/legacy/core_plugins/vis_type_table/public/components/table_vis_options.tsx
+++ b/src/legacy/core_plugins/vis_type_table/public/components/table_vis_options.tsx
@@ -23,8 +23,7 @@ import { EuiIconTip, EuiPanel } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
-import { tabifyGetColumns } from 'ui/agg_response/tabify/_get_columns';
-import { VisOptionsProps } from 'ui/vis/editors/default';
+import { tabifyGetColumns, VisOptionsProps } from '../legacy_imports';
import {
NumberInputOption,
SwitchOption,
diff --git a/src/legacy/core_plugins/vis_type_table/public/get_inner_angular.ts b/src/legacy/core_plugins/vis_type_table/public/get_inner_angular.ts
new file mode 100644
index 0000000000000..9f3a8327c9ad9
--- /dev/null
+++ b/src/legacy/core_plugins/vis_type_table/public/get_inner_angular.ts
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+// inner angular imports
+// these are necessary to bootstrap the local angular.
+// They can stay even after NP cutover
+import angular from 'angular';
+import 'ui/angular-bootstrap';
+import 'angular-recursion';
+import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular';
+import { CoreStart, LegacyCoreStart, IUiSettingsClient } from 'kibana/public';
+import {
+ PrivateProvider,
+ PaginateDirectiveProvider,
+ PaginateControlsDirectiveProvider,
+ watchMultiDecorator,
+ KbnAccessibleClickProvider,
+ StateManagementConfigProvider,
+ configureAppAngularModule,
+} from './legacy_imports';
+
+const thirdPartyAngularDependencies = ['ngSanitize', 'ui.bootstrap', 'RecursionHelper'];
+
+export function getAngularModule(name: string, core: CoreStart) {
+ const uiModule = getInnerAngular(name, core);
+ configureAppAngularModule(uiModule, core as LegacyCoreStart, true);
+ return uiModule;
+}
+
+let initialized = false;
+
+export function getInnerAngular(name = 'kibana/table_vis', core: CoreStart) {
+ if (!initialized) {
+ createLocalPrivateModule();
+ createLocalI18nModule();
+ createLocalConfigModule(core.uiSettings);
+ createLocalPaginateModule();
+ initialized = true;
+ }
+ return angular
+ .module(name, [
+ ...thirdPartyAngularDependencies,
+ 'tableVisPaginate',
+ 'tableVisConfig',
+ 'tableVisPrivate',
+ 'tableVisI18n',
+ ])
+ .config(watchMultiDecorator)
+ .directive('kbnAccessibleClick', KbnAccessibleClickProvider);
+}
+
+function createLocalPrivateModule() {
+ angular.module('tableVisPrivate', []).provider('Private', PrivateProvider);
+}
+
+function createLocalConfigModule(uiSettings: IUiSettingsClient) {
+ angular
+ .module('tableVisConfig', ['tableVisPrivate'])
+ .provider('stateManagementConfig', StateManagementConfigProvider)
+ .provider('config', function() {
+ return {
+ $get: () => ({
+ get: (value: string) => {
+ return uiSettings ? uiSettings.get(value) : undefined;
+ },
+ // set method is used in agg_table mocha test
+ set: (key: string, value: string) => {
+ return uiSettings ? uiSettings.set(key, value) : undefined;
+ },
+ }),
+ };
+ });
+}
+
+function createLocalI18nModule() {
+ angular
+ .module('tableVisI18n', [])
+ .provider('i18n', I18nProvider)
+ .filter('i18n', i18nFilter)
+ .directive('i18nId', i18nDirective);
+}
+
+function createLocalPaginateModule() {
+ angular
+ .module('tableVisPaginate', [])
+ .directive('paginate', PaginateDirectiveProvider)
+ .directive('paginateControls', PaginateControlsDirectiveProvider);
+}
diff --git a/src/legacy/core_plugins/vis_type_table/public/legacy.ts b/src/legacy/core_plugins/vis_type_table/public/legacy.ts
index 8513622dec9aa..e5b2619ef2970 100644
--- a/src/legacy/core_plugins/vis_type_table/public/legacy.ts
+++ b/src/legacy/core_plugins/vis_type_table/public/legacy.ts
@@ -18,20 +18,15 @@
*/
import { PluginInitializerContext } from 'kibana/public';
-import { npSetup, npStart } from 'ui/new_platform';
+import { npSetup, npStart } from './legacy_imports';
import { plugin } from '.';
import { TablePluginSetupDependencies } from './plugin';
import { setup as visualizationsSetup } from '../../visualizations/public/np_ready/public/legacy';
-import { LegacyDependenciesPlugin } from './shim';
const plugins: Readonly
= {
expressions: npSetup.plugins.expressions,
visualizations: visualizationsSetup,
-
- // Temporary solution
- // It will be removed when all dependent services are migrated to the new platform.
- __LEGACY: new LegacyDependenciesPlugin(),
};
const pluginInstance = plugin({} as PluginInitializerContext);
diff --git a/src/legacy/core_plugins/vis_type_table/public/legacy_imports.ts b/src/legacy/core_plugins/vis_type_table/public/legacy_imports.ts
new file mode 100644
index 0000000000000..a372eced3e34b
--- /dev/null
+++ b/src/legacy/core_plugins/vis_type_table/public/legacy_imports.ts
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+export { npSetup, npStart } from 'ui/new_platform';
+export { getFormat } from 'ui/visualize/loader/pipeline_helpers/utilities';
+export { AggConfig } from 'ui/vis';
+export { AggGroupNames, VisOptionsProps } from 'ui/vis/editors/default';
+// @ts-ignore
+export { Schemas } from 'ui/vis/editors/default/schemas';
+// @ts-ignore
+export { legacyResponseHandlerProvider } from 'ui/vis/response_handlers/legacy';
+
+// @ts-ignore
+export { PrivateProvider } from 'ui/private/private';
+// @ts-ignore
+export { PaginateDirectiveProvider } from 'ui/directives/paginate';
+// @ts-ignore
+export { PaginateControlsDirectiveProvider } from 'ui/directives/paginate';
+// @ts-ignore
+export { watchMultiDecorator } from 'ui/directives/watch_multi/watch_multi';
+
+// @ts-ignore
+export { KbnAccessibleClickProvider } from 'ui/accessibility/kbn_accessible_click';
+// @ts-ignore
+export { StateManagementConfigProvider } from 'ui/state_management/config_provider';
+export { configureAppAngularModule } from 'ui/legacy_compat';
+
+export { tabifyGetColumns } from 'ui/agg_response/tabify/_get_columns';
+// @ts-ignore
+export { tabifyAggResponse } from 'ui/agg_response/tabify';
diff --git a/src/legacy/core_plugins/vis_type_table/public/paginated_table/__tests__/paginated_table.js b/src/legacy/core_plugins/vis_type_table/public/paginated_table/__tests__/paginated_table.js
deleted file mode 100644
index d146a1bddf260..0000000000000
--- a/src/legacy/core_plugins/vis_type_table/public/paginated_table/__tests__/paginated_table.js
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * 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 _ from 'lodash';
-import expect from '@kbn/expect';
-import ngMock from 'ng_mock';
-
-import $ from 'jquery';
-
-describe('Table Vis - Paginated table', function () {
- let $el;
- let $rootScope;
- let $compile;
- let $scope;
- const defaultPerPage = 10;
-
- const makeData = function (colCount, rowCount) {
- let columns = [];
- let rows = [];
-
- if (_.isNumber(colCount)) {
- _.times(colCount, function (i) {
- columns.push({ id: i, title: 'column' + i, formatter: { convert: _.identity } });
- });
- } else {
- columns = colCount.map((col, i) => ({
- id: i,
- title: col.title,
- formatter: col.formatter || { convert: _.identity }
- }));
- }
-
- if (_.isNumber(rowCount)) {
- _.times(rowCount, function (row) {
- const rowItems = {};
-
- _.times(columns.length, function (col) {
- rowItems[col] = 'item' + col + row;
- });
-
- rows.push(rowItems);
- });
- } else {
- rows = rowCount.map(row => {
- const newRow = {};
- row.forEach((v, i) => newRow[i] = v);
- return newRow;
- });
- }
-
- return {
- columns: columns,
- rows: rows
- };
- };
-
- const renderTable = function (table, cols, rows, perPage, sort, linkToTop) {
- $scope.table = table || { columns: [], rows: [] };
- $scope.cols = cols || [];
- $scope.rows = rows || [];
- $scope.perPage = perPage || defaultPerPage;
- $scope.sort = sort || {};
- $scope.linkToTop = linkToTop;
-
- const template = `
- `;
- $el = $compile(template)($scope);
-
- $scope.$digest();
- };
-
- beforeEach(ngMock.module('kibana'));
- beforeEach(ngMock.inject(function (_$rootScope_, _$compile_) {
- $rootScope = _$rootScope_;
- $compile = _$compile_;
- $scope = $rootScope.$new();
- }));
-
- describe('rendering', function () {
- it('should not display without rows', function () {
- const cols = [{
- title: 'test1'
- }];
- const rows = [];
-
- renderTable(null, cols, rows);
- expect($el.children().length).to.be(0);
- });
-
- it('should render columns and rows', function () {
- const data = makeData(2, 2);
- const cols = data.columns;
- const rows = data.rows;
-
- renderTable(data, cols, rows);
- expect($el.children().length).to.be(1);
- const tableRows = $el.find('tbody tr');
- // should contain the row data
- expect(tableRows.eq(0).find('td').eq(0).text()).to.be(rows[0][0]);
- expect(tableRows.eq(0).find('td').eq(1).text()).to.be(rows[0][1]);
- expect(tableRows.eq(1).find('td').eq(0).text()).to.be(rows[1][0]);
- expect(tableRows.eq(1).find('td').eq(1).text()).to.be(rows[1][1]);
- });
-
- it('should paginate rows', function () {
- // note: paginate truncates pages, so don't make too many
- const rowCount = _.random(16, 24);
- const perPageCount = _.random(5, 8);
- const data = makeData(3, rowCount);
- const pageCount = Math.ceil(rowCount / perPageCount);
-
- renderTable(data, data.columns, data.rows, perPageCount);
- const tableRows = $el.find('tbody tr');
- expect(tableRows.length).to.be(perPageCount);
- // add 2 for the first and last page links
- expect($el.find('paginate-controls button').length).to.be(pageCount + 2);
- });
-
- it('should not show blank rows on last page', function () {
- const rowCount = 7;
- const perPageCount = 10;
- const data = makeData(3, rowCount);
-
- renderTable(data, data.columns, data.rows, perPageCount, null);
- const tableRows = $el.find('tbody tr');
- expect(tableRows.length).to.be(rowCount);
- });
-
- it('should not show link to top when not set', function () {
- const data = makeData(5, 5);
- renderTable(data, data.columns, data.rows, 10, null);
-
- const linkToTop = $el.find('[data-test-subj="paginateControlsLinkToTop"]');
- expect(linkToTop.length).to.be(0);
- });
-
- it('should show link to top when set', function () {
- const data = makeData(5, 5);
- renderTable(data, data.columns, data.rows, 10, null, true);
-
- const linkToTop = $el.find('[data-test-subj="paginateControlsLinkToTop"]');
- expect(linkToTop.length).to.be(1);
- });
-
- });
-
- describe('sorting', function () {
- let data;
- let lastRowIndex;
- let paginatedTable;
-
- beforeEach(function () {
- data = makeData(3, [
- ['bbbb', 'aaaa', 'zzzz'],
- ['cccc', 'cccc', 'aaaa'],
- ['zzzz', 'bbbb', 'bbbb'],
- ['aaaa', 'zzzz', 'cccc'],
- ]);
-
- lastRowIndex = data.rows.length - 1;
- renderTable(data, data.columns, data.rows);
- paginatedTable = $el.isolateScope().paginatedTable;
- });
-
- // afterEach(function () {
- // $scope.$destroy();
- // });
-
- it('should not sort by default', function () {
- const tableRows = $el.find('tbody tr');
- expect(tableRows.eq(0).find('td').eq(0).text()).to.be(data.rows[0][0]);
- expect(tableRows.eq(lastRowIndex).find('td').eq(0).text()).to.be(data.rows[lastRowIndex][0]);
- });
-
- it('should do nothing when sorting by invalid column id', function () {
- // sortColumn
- paginatedTable.sortColumn(999);
- $scope.$digest();
-
- const tableRows = $el.find('tbody tr');
- expect(tableRows.eq(0).find('td').eq(0).text()).to.be('bbbb');
- expect(tableRows.eq(0).find('td').eq(1).text()).to.be('aaaa');
- expect(tableRows.eq(0).find('td').eq(2).text()).to.be('zzzz');
- });
-
- it('should do nothing when sorting by non sortable column', function () {
- data.columns[0].sortable = false;
-
- // sortColumn
- paginatedTable.sortColumn(0);
- $scope.$digest();
-
- const tableRows = $el.find('tbody tr');
- expect(tableRows.eq(0).find('td').eq(0).text()).to.be('bbbb');
- expect(tableRows.eq(0).find('td').eq(1).text()).to.be('aaaa');
- expect(tableRows.eq(0).find('td').eq(2).text()).to.be('zzzz');
- });
-
- it('should set the sort direction to asc when it\'s not explicitly set', function () {
- paginatedTable.sortColumn(1);
- $scope.$digest();
-
- const tableRows = $el.find('tbody tr');
- expect(tableRows.eq(2).find('td').eq(1).text()).to.be('cccc');
- expect(tableRows.eq(1).find('td').eq(1).text()).to.be('bbbb');
- expect(tableRows.eq(0).find('td').eq(1).text()).to.be('aaaa');
- });
-
- it('should allow you to explicitly set the sort direction', function () {
- paginatedTable.sortColumn(1, 'desc');
- $scope.$digest();
-
- const tableRows = $el.find('tbody tr');
- expect(tableRows.eq(0).find('td').eq(1).text()).to.be('zzzz');
- expect(tableRows.eq(1).find('td').eq(1).text()).to.be('cccc');
- expect(tableRows.eq(2).find('td').eq(1).text()).to.be('bbbb');
- });
-
- it('should sort ascending on first invocation', function () {
- // sortColumn
- paginatedTable.sortColumn(0);
- $scope.$digest();
-
- const tableRows = $el.find('tbody tr');
- expect(tableRows.eq(0).find('td').eq(0).text()).to.be('aaaa');
- expect(tableRows.eq(lastRowIndex).find('td').eq(0).text()).to.be('zzzz');
- });
-
- it('should sort descending on second invocation', function () {
- // sortColumn
- paginatedTable.sortColumn(0);
- paginatedTable.sortColumn(0);
- $scope.$digest();
-
- const tableRows = $el.find('tbody tr');
- expect(tableRows.eq(0).find('td').eq(0).text()).to.be('zzzz');
- expect(tableRows.eq(lastRowIndex).find('td').eq(0).text()).to.be('aaaa');
- });
-
- it('should clear sorting on third invocation', function () {
- // sortColumn
- paginatedTable.sortColumn(0);
- paginatedTable.sortColumn(0);
- paginatedTable.sortColumn(0);
- $scope.$digest();
-
- const tableRows = $el.find('tbody tr');
- expect(tableRows.eq(0).find('td').eq(0).text()).to.be(data.rows[0][0]);
- expect(tableRows.eq(lastRowIndex).find('td').eq(0).text()).to.be('aaaa');
- });
-
- it('should sort new column ascending', function () {
- // sort by first column
- paginatedTable.sortColumn(0);
- $scope.$digest();
-
- // sort by second column
- paginatedTable.sortColumn(1);
- $scope.$digest();
-
- const tableRows = $el.find('tbody tr');
- expect(tableRows.eq(0).find('td').eq(1).text()).to.be('aaaa');
- expect(tableRows.eq(lastRowIndex).find('td').eq(1).text()).to.be('zzzz');
- });
-
- });
-
- describe('sorting duplicate columns', function () {
- let data;
- let paginatedTable;
- const colText = 'test row';
-
- beforeEach(function () {
- const cols = [
- { title: colText },
- { title: colText },
- { title: colText }
- ];
- const rows = [
- ['bbbb', 'aaaa', 'zzzz'],
- ['cccc', 'cccc', 'aaaa'],
- ['zzzz', 'bbbb', 'bbbb'],
- ['aaaa', 'zzzz', 'cccc'],
- ];
- data = makeData(cols, rows);
-
- renderTable(data, data.columns, data.rows);
- paginatedTable = $el.isolateScope().paginatedTable;
- });
-
- it('should have duplicate column titles', function () {
- const columns = $el.find('thead th span');
- columns.each(function () {
- expect($(this).text()).to.be(colText);
- });
- });
-
- it('should handle sorting on columns with the same name', function () {
- // sort by the last column
- paginatedTable.sortColumn(2);
- $scope.$digest();
-
- const tableRows = $el.find('tbody tr');
- expect(tableRows.eq(0).find('td').eq(0).text()).to.be('cccc');
- expect(tableRows.eq(0).find('td').eq(1).text()).to.be('cccc');
- expect(tableRows.eq(0).find('td').eq(2).text()).to.be('aaaa');
- expect(tableRows.eq(1).find('td').eq(2).text()).to.be('bbbb');
- expect(tableRows.eq(2).find('td').eq(2).text()).to.be('cccc');
- expect(tableRows.eq(3).find('td').eq(2).text()).to.be('zzzz');
- });
-
- it('should sort correctly between columns', function () {
- // sort by the last column
- paginatedTable.sortColumn(2);
- $scope.$digest();
-
- let tableRows = $el.find('tbody tr');
- expect(tableRows.eq(0).find('td').eq(0).text()).to.be('cccc');
- expect(tableRows.eq(0).find('td').eq(1).text()).to.be('cccc');
- expect(tableRows.eq(0).find('td').eq(2).text()).to.be('aaaa');
-
- // sort by the first column
- paginatedTable.sortColumn(0);
- $scope.$digest();
-
- tableRows = $el.find('tbody tr');
- expect(tableRows.eq(0).find('td').eq(0).text()).to.be('aaaa');
- expect(tableRows.eq(0).find('td').eq(1).text()).to.be('zzzz');
- expect(tableRows.eq(0).find('td').eq(2).text()).to.be('cccc');
-
- expect(tableRows.eq(1).find('td').eq(0).text()).to.be('bbbb');
- expect(tableRows.eq(2).find('td').eq(0).text()).to.be('cccc');
- expect(tableRows.eq(3).find('td').eq(0).text()).to.be('zzzz');
- });
-
- it('should not sort duplicate columns', function () {
- paginatedTable.sortColumn(1);
- $scope.$digest();
-
- const sorters = $el.find('thead th i');
- expect(sorters.eq(0).hasClass('fa-sort')).to.be(true);
- expect(sorters.eq(1).hasClass('fa-sort')).to.be(false);
- expect(sorters.eq(2).hasClass('fa-sort')).to.be(true);
- });
-
- });
-
-
- describe('object rows', function () {
- let cols;
- let rows;
- let paginatedTable;
-
- beforeEach(function () {
- cols = [{
- title: 'object test',
- id: 0,
- formatter: { convert: val => {
- return val === 'zzz' ? 'hello
' : val;
- } }
- }];
- rows = [
- ['aaaa'],
- ['zzz'],
- ['bbbb']
- ];
- renderTable({ columns: cols, rows }, cols, rows);
- paginatedTable = $el.isolateScope().paginatedTable;
- });
-
- it('should append object markup', function () {
- const tableRows = $el.find('tbody tr');
- expect(tableRows.eq(0).find('h1').length).to.be(0);
- expect(tableRows.eq(1).find('h1').length).to.be(1);
- expect(tableRows.eq(2).find('h1').length).to.be(0);
- });
-
- it('should sort using object value', function () {
- paginatedTable.sortColumn(0);
- $scope.$digest();
- let tableRows = $el.find('tbody tr');
- expect(tableRows.eq(0).find('h1').length).to.be(0);
- expect(tableRows.eq(1).find('h1').length).to.be(0);
- // html row should be the last row
- expect(tableRows.eq(2).find('h1').length).to.be(1);
-
- paginatedTable.sortColumn(0);
- $scope.$digest();
- tableRows = $el.find('tbody tr');
- // html row should be the first row
- expect(tableRows.eq(0).find('h1').length).to.be(1);
- expect(tableRows.eq(1).find('h1').length).to.be(0);
- expect(tableRows.eq(2).find('h1').length).to.be(0);
- });
- });
-});
diff --git a/src/legacy/core_plugins/vis_type_table/public/paginated_table/paginated_table.test.ts b/src/legacy/core_plugins/vis_type_table/public/paginated_table/paginated_table.test.ts
new file mode 100644
index 0000000000000..781782e42fbaf
--- /dev/null
+++ b/src/legacy/core_plugins/vis_type_table/public/paginated_table/paginated_table.test.ts
@@ -0,0 +1,713 @@
+/*
+ * 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 { isNumber, times, identity, random } from 'lodash';
+import angular, { IRootScopeService, IScope, ICompileService } from 'angular';
+import $ from 'jquery';
+import 'angular-sanitize';
+import 'angular-mocks';
+import '../table_vis.mock';
+
+import { getAngularModule } from '../get_inner_angular';
+import { initTableVisLegacyModule } from '../table_vis_legacy_module';
+import { npStart } from '../legacy_imports';
+
+interface Sort {
+ columnIndex: number;
+ direction: string;
+}
+
+interface Row {
+ [key: string]: number | string;
+}
+
+interface Column {
+ id?: string;
+ title: string;
+ formatter?: {
+ convert?: (val: string) => string;
+ };
+ sortable?: boolean;
+}
+
+interface Table {
+ columns: Column[];
+ rows: Row[];
+}
+
+interface PaginatedTableScope extends IScope {
+ table?: Table;
+ cols?: Column[];
+ rows?: Row[];
+ perPage?: number;
+ sort?: Sort;
+ linkToTop?: boolean;
+}
+
+describe('Table Vis - Paginated table', () => {
+ let $el: JQuery;
+ let $rootScope: IRootScopeService;
+ let $compile: ICompileService;
+ let $scope: PaginatedTableScope;
+ const defaultPerPage = 10;
+ let paginatedTable: any;
+
+ const initLocalAngular = () => {
+ const tableVisModule = getAngularModule('kibana/table_vis', npStart.core);
+ initTableVisLegacyModule(tableVisModule);
+ };
+
+ beforeEach(initLocalAngular);
+ beforeEach(angular.mock.module('kibana/table_vis'));
+
+ beforeEach(
+ angular.mock.inject((_$rootScope_: IRootScopeService, _$compile_: ICompileService) => {
+ $rootScope = _$rootScope_;
+ $compile = _$compile_;
+ $scope = $rootScope.$new();
+ })
+ );
+
+ afterEach(() => {
+ $scope.$destroy();
+ });
+
+ const makeData = (colCount: number | Column[], rowCount: number | string[][]) => {
+ let columns: Column[] = [];
+ let rows: Row[] = [];
+
+ if (isNumber(colCount)) {
+ times(colCount, i => {
+ columns.push({ id: `${i}`, title: `column${i}`, formatter: { convert: identity } });
+ });
+ } else {
+ columns = colCount.map(
+ (col, i) =>
+ ({
+ id: `${i}`,
+ title: col.title,
+ formatter: col.formatter || { convert: identity },
+ } as Column)
+ );
+ }
+
+ if (isNumber(rowCount)) {
+ times(rowCount, row => {
+ const rowItems: Row = {};
+
+ times(columns.length, col => {
+ rowItems[`${col}`] = `item-${col}-${row}`;
+ });
+
+ rows.push(rowItems);
+ });
+ } else {
+ rows = rowCount.map((row: string[]) => {
+ const newRow: Row = {};
+ row.forEach((v, i) => (newRow[i] = v));
+ return newRow;
+ });
+ }
+
+ return {
+ columns,
+ rows,
+ };
+ };
+
+ const renderTable = (
+ table: { columns: Column[]; rows: Row[] } | null,
+ cols: Column[],
+ rows: Row[],
+ perPage?: number,
+ sort?: Sort,
+ linkToTop?: boolean
+ ) => {
+ $scope.table = table || { columns: [], rows: [] };
+ $scope.cols = cols || [];
+ $scope.rows = rows || [];
+ $scope.perPage = perPage || defaultPerPage;
+ $scope.sort = sort;
+ $scope.linkToTop = linkToTop;
+
+ const template = `
+ `;
+ const element = $compile(template)($scope);
+ $el = $(element);
+
+ $scope.$digest();
+ paginatedTable = element.controller('paginatedTable');
+ };
+
+ describe('rendering', () => {
+ test('should not display without rows', () => {
+ const cols: Column[] = [
+ {
+ id: 'col-1-1',
+ title: 'test1',
+ },
+ ];
+ const rows: Row[] = [];
+
+ renderTable(null, cols, rows);
+ expect($el.children().length).toBe(0);
+ });
+
+ test('should render columns and rows', () => {
+ const data = makeData(2, 2);
+ const cols = data.columns;
+ const rows = data.rows;
+
+ renderTable(data, cols, rows);
+ expect($el.children().length).toBe(1);
+ const tableRows = $el.find('tbody tr');
+
+ // should contain the row data
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(0)
+ .text()
+ ).toBe(rows[0][0]);
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(1)
+ .text()
+ ).toBe(rows[0][1]);
+ expect(
+ tableRows
+ .eq(1)
+ .find('td')
+ .eq(0)
+ .text()
+ ).toBe(rows[1][0]);
+ expect(
+ tableRows
+ .eq(1)
+ .find('td')
+ .eq(1)
+ .text()
+ ).toBe(rows[1][1]);
+ });
+
+ test('should paginate rows', () => {
+ // note: paginate truncates pages, so don't make too many
+ const rowCount = random(16, 24);
+ const perPageCount = random(5, 8);
+ const data = makeData(3, rowCount);
+ const pageCount = Math.ceil(rowCount / perPageCount);
+
+ renderTable(data, data.columns, data.rows, perPageCount);
+ const tableRows = $el.find('tbody tr');
+ expect(tableRows.length).toBe(perPageCount);
+ // add 2 for the first and last page links
+ expect($el.find('paginate-controls button').length).toBe(pageCount + 2);
+ });
+
+ test('should not show blank rows on last page', () => {
+ const rowCount = 7;
+ const perPageCount = 10;
+ const data = makeData(3, rowCount);
+
+ renderTable(data, data.columns, data.rows, perPageCount);
+ const tableRows = $el.find('tbody tr');
+ expect(tableRows.length).toBe(rowCount);
+ });
+
+ test('should not show link to top when not set', () => {
+ const data = makeData(5, 5);
+ renderTable(data, data.columns, data.rows, 10);
+
+ const linkToTop = $el.find('[data-test-subj="paginateControlsLinkToTop"]');
+ expect(linkToTop.length).toBe(0);
+ });
+
+ test('should show link to top when set', () => {
+ const data = makeData(5, 5);
+ renderTable(data, data.columns, data.rows, 10, undefined, true);
+
+ const linkToTop = $el.find('[data-test-subj="paginateControlsLinkToTop"]');
+ expect(linkToTop.length).toBe(1);
+ });
+ });
+
+ describe('sorting', () => {
+ let data: Table;
+ let lastRowIndex: number;
+
+ beforeEach(() => {
+ data = makeData(3, [
+ ['bbbb', 'aaaa', 'zzzz'],
+ ['cccc', 'cccc', 'aaaa'],
+ ['zzzz', 'bbbb', 'bbbb'],
+ ['aaaa', 'zzzz', 'cccc'],
+ ]);
+
+ lastRowIndex = data.rows.length - 1;
+ renderTable(data, data.columns, data.rows);
+ });
+
+ test('should not sort by default', () => {
+ const tableRows = $el.find('tbody tr');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(0)
+ .text()
+ ).toBe(data.rows[0][0]);
+ expect(
+ tableRows
+ .eq(lastRowIndex)
+ .find('td')
+ .eq(0)
+ .text()
+ ).toBe(data.rows[lastRowIndex][0]);
+ });
+
+ test('should do nothing when sorting by invalid column id', () => {
+ // sortColumn
+ paginatedTable.sortColumn(999);
+ $scope.$digest();
+
+ const tableRows = $el.find('tbody tr');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(0)
+ .text()
+ ).toBe('bbbb');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(1)
+ .text()
+ ).toBe('aaaa');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(2)
+ .text()
+ ).toBe('zzzz');
+ });
+
+ test('should do nothing when sorting by non sortable column', () => {
+ data.columns[0].sortable = false;
+
+ // sortColumn
+ paginatedTable.sortColumn(0);
+ $scope.$digest();
+
+ const tableRows = $el.find('tbody tr');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(0)
+ .text()
+ ).toBe('bbbb');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(1)
+ .text()
+ ).toBe('aaaa');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(2)
+ .text()
+ ).toBe('zzzz');
+ });
+
+ test("should set the sort direction to asc when it's not explicitly set", () => {
+ paginatedTable.sortColumn(1);
+ $scope.$digest();
+
+ const tableRows = $el.find('tbody tr');
+ expect(
+ tableRows
+ .eq(2)
+ .find('td')
+ .eq(1)
+ .text()
+ ).toBe('cccc');
+ expect(
+ tableRows
+ .eq(1)
+ .find('td')
+ .eq(1)
+ .text()
+ ).toBe('bbbb');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(1)
+ .text()
+ ).toBe('aaaa');
+ });
+
+ test('should allow you to explicitly set the sort direction', () => {
+ paginatedTable.sortColumn(1, 'desc');
+ $scope.$digest();
+
+ const tableRows = $el.find('tbody tr');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(1)
+ .text()
+ ).toBe('zzzz');
+ expect(
+ tableRows
+ .eq(1)
+ .find('td')
+ .eq(1)
+ .text()
+ ).toBe('cccc');
+ expect(
+ tableRows
+ .eq(2)
+ .find('td')
+ .eq(1)
+ .text()
+ ).toBe('bbbb');
+ });
+
+ test('should sort ascending on first invocation', () => {
+ // sortColumn
+ paginatedTable.sortColumn(0);
+ $scope.$digest();
+
+ const tableRows = $el.find('tbody tr');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(0)
+ .text()
+ ).toBe('aaaa');
+ expect(
+ tableRows
+ .eq(lastRowIndex)
+ .find('td')
+ .eq(0)
+ .text()
+ ).toBe('zzzz');
+ });
+
+ test('should sort descending on second invocation', () => {
+ // sortColumn
+ paginatedTable.sortColumn(0);
+ paginatedTable.sortColumn(0);
+ $scope.$digest();
+
+ const tableRows = $el.find('tbody tr');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(0)
+ .text()
+ ).toBe('zzzz');
+ expect(
+ tableRows
+ .eq(lastRowIndex)
+ .find('td')
+ .eq(0)
+ .text()
+ ).toBe('aaaa');
+ });
+
+ test('should clear sorting on third invocation', () => {
+ // sortColumn
+ paginatedTable.sortColumn(0);
+ paginatedTable.sortColumn(0);
+ paginatedTable.sortColumn(0);
+ $scope.$digest();
+
+ const tableRows = $el.find('tbody tr');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(0)
+ .text()
+ ).toBe(data.rows[0][0]);
+ expect(
+ tableRows
+ .eq(lastRowIndex)
+ .find('td')
+ .eq(0)
+ .text()
+ ).toBe('aaaa');
+ });
+
+ test('should sort new column ascending', () => {
+ // sort by first column
+ paginatedTable.sortColumn(0);
+ $scope.$digest();
+
+ // sort by second column
+ paginatedTable.sortColumn(1);
+ $scope.$digest();
+
+ const tableRows = $el.find('tbody tr');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(1)
+ .text()
+ ).toBe('aaaa');
+ expect(
+ tableRows
+ .eq(lastRowIndex)
+ .find('td')
+ .eq(1)
+ .text()
+ ).toBe('zzzz');
+ });
+ });
+
+ describe('sorting duplicate columns', () => {
+ let data;
+ const colText = 'test row';
+
+ beforeEach(() => {
+ const cols: Column[] = [{ title: colText }, { title: colText }, { title: colText }];
+ const rows = [
+ ['bbbb', 'aaaa', 'zzzz'],
+ ['cccc', 'cccc', 'aaaa'],
+ ['zzzz', 'bbbb', 'bbbb'],
+ ['aaaa', 'zzzz', 'cccc'],
+ ];
+ data = makeData(cols, rows);
+
+ renderTable(data, data.columns, data.rows);
+ });
+
+ test('should have duplicate column titles', () => {
+ const columns = $el.find('thead th span');
+ columns.each((i, col) => {
+ expect($(col).text()).toBe(colText);
+ });
+ });
+
+ test('should handle sorting on columns with the same name', () => {
+ // sort by the last column
+ paginatedTable.sortColumn(2);
+ $scope.$digest();
+
+ const tableRows = $el.find('tbody tr');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(0)
+ .text()
+ ).toBe('cccc');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(1)
+ .text()
+ ).toBe('cccc');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(2)
+ .text()
+ ).toBe('aaaa');
+ expect(
+ tableRows
+ .eq(1)
+ .find('td')
+ .eq(2)
+ .text()
+ ).toBe('bbbb');
+ expect(
+ tableRows
+ .eq(2)
+ .find('td')
+ .eq(2)
+ .text()
+ ).toBe('cccc');
+ expect(
+ tableRows
+ .eq(3)
+ .find('td')
+ .eq(2)
+ .text()
+ ).toBe('zzzz');
+ });
+
+ test('should sort correctly between columns', () => {
+ // sort by the last column
+ paginatedTable.sortColumn(2);
+ $scope.$digest();
+
+ let tableRows = $el.find('tbody tr');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(0)
+ .text()
+ ).toBe('cccc');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(1)
+ .text()
+ ).toBe('cccc');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(2)
+ .text()
+ ).toBe('aaaa');
+
+ // sort by the first column
+ paginatedTable.sortColumn(0);
+ $scope.$digest();
+
+ tableRows = $el.find('tbody tr');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(0)
+ .text()
+ ).toBe('aaaa');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(1)
+ .text()
+ ).toBe('zzzz');
+ expect(
+ tableRows
+ .eq(0)
+ .find('td')
+ .eq(2)
+ .text()
+ ).toBe('cccc');
+
+ expect(
+ tableRows
+ .eq(1)
+ .find('td')
+ .eq(0)
+ .text()
+ ).toBe('bbbb');
+ expect(
+ tableRows
+ .eq(2)
+ .find('td')
+ .eq(0)
+ .text()
+ ).toBe('cccc');
+ expect(
+ tableRows
+ .eq(3)
+ .find('td')
+ .eq(0)
+ .text()
+ ).toBe('zzzz');
+ });
+
+ test('should not sort duplicate columns', () => {
+ paginatedTable.sortColumn(1);
+ $scope.$digest();
+
+ const sorters = $el.find('thead th i');
+ expect(sorters.eq(0).hasClass('fa-sort')).toBe(true);
+ expect(sorters.eq(1).hasClass('fa-sort')).toBe(false);
+ expect(sorters.eq(2).hasClass('fa-sort')).toBe(true);
+ });
+ });
+
+ describe('object rows', () => {
+ let cols: Column[];
+ let rows: any;
+
+ beforeEach(() => {
+ cols = [
+ {
+ title: 'object test',
+ id: '0',
+ formatter: {
+ convert: val => {
+ return val === 'zzz' ? 'hello
' : val;
+ },
+ },
+ },
+ ];
+ rows = [['aaaa'], ['zzz'], ['bbbb']];
+ renderTable({ columns: cols, rows }, cols, rows);
+ });
+
+ test('should append object markup', () => {
+ const tableRows = $el.find('tbody tr');
+ expect(tableRows.eq(0).find('h1').length).toBe(0);
+ expect(tableRows.eq(1).find('h1').length).toBe(1);
+ expect(tableRows.eq(2).find('h1').length).toBe(0);
+ });
+
+ test('should sort using object value', () => {
+ paginatedTable.sortColumn(0);
+ $scope.$digest();
+ let tableRows = $el.find('tbody tr');
+ expect(tableRows.eq(0).find('h1').length).toBe(0);
+ expect(tableRows.eq(1).find('h1').length).toBe(0);
+ // html row should be the last row
+ expect(tableRows.eq(2).find('h1').length).toBe(1);
+
+ paginatedTable.sortColumn(0);
+ $scope.$digest();
+ tableRows = $el.find('tbody tr');
+ // html row should be the first row
+ expect(tableRows.eq(0).find('h1').length).toBe(1);
+ expect(tableRows.eq(1).find('h1').length).toBe(0);
+ expect(tableRows.eq(2).find('h1').length).toBe(0);
+ });
+ });
+});
diff --git a/src/legacy/core_plugins/vis_type_table/public/plugin.ts b/src/legacy/core_plugins/vis_type_table/public/plugin.ts
index ce8d349d8dd7a..17c50b0567b67 100644
--- a/src/legacy/core_plugins/vis_type_table/public/plugin.ts
+++ b/src/legacy/core_plugins/vis_type_table/public/plugin.ts
@@ -21,8 +21,6 @@ import { VisualizationsSetup } from '../../visualizations/public';
import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from '../../../../core/public';
-import { LegacyDependenciesPlugin } from './shim';
-
import { createTableVisFn } from './table_vis_fn';
import { tableVisTypeDefinition } from './table_vis_type';
@@ -30,7 +28,6 @@ import { tableVisTypeDefinition } from './table_vis_type';
export interface TablePluginSetupDependencies {
expressions: ReturnType;
visualizations: VisualizationsSetup;
- __LEGACY: LegacyDependenciesPlugin;
}
/** @internal */
@@ -43,9 +40,8 @@ export class TableVisPlugin implements Plugin, void> {
public async setup(
core: CoreSetup,
- { expressions, visualizations, __LEGACY }: TablePluginSetupDependencies
+ { expressions, visualizations }: TablePluginSetupDependencies
) {
- __LEGACY.setup();
expressions.registerFunction(createTableVisFn);
visualizations.types.createBaseVisualization(tableVisTypeDefinition);
diff --git a/src/legacy/core_plugins/vis_type_table/public/shim/index.ts b/src/legacy/core_plugins/vis_type_table/public/shim/index.ts
deleted file mode 100644
index cfc7b62ff4f86..0000000000000
--- a/src/legacy/core_plugins/vis_type_table/public/shim/index.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * 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.
- */
-
-export * from './legacy_dependencies_plugin';
diff --git a/src/legacy/core_plugins/vis_type_table/public/shim/legacy_dependencies_plugin.ts b/src/legacy/core_plugins/vis_type_table/public/table_vis.mock.ts
similarity index 51%
rename from src/legacy/core_plugins/vis_type_table/public/shim/legacy_dependencies_plugin.ts
rename to src/legacy/core_plugins/vis_type_table/public/table_vis.mock.ts
index ba30664951f47..d04964cb7af03 100644
--- a/src/legacy/core_plugins/vis_type_table/public/shim/legacy_dependencies_plugin.ts
+++ b/src/legacy/core_plugins/vis_type_table/public/table_vis.mock.ts
@@ -17,16 +17,30 @@
* under the License.
*/
-import { CoreStart, Plugin } from '../../../../../core/public';
-import { initTableVisLegacyModule } from './table_vis_legacy_module';
+import { createUiNewPlatformMock } from 'ui/new_platform/__mocks__/helpers';
+import { StubBrowserStorage } from 'test_utils/stub_browser_storage';
+import { injectedMetadataServiceMock } from '../../../../core/public/mocks';
-/** @internal */
-export class LegacyDependenciesPlugin implements Plugin {
- public setup() {
- initTableVisLegacyModule();
- }
+jest.doMock('ui/new_platform', () => {
+ const npMock = createUiNewPlatformMock();
+ return {
+ npSetup: {
+ ...npMock.npSetup,
+ core: {
+ ...npMock.npSetup.core,
+ injectedMetadata: injectedMetadataServiceMock.createSetupContract(),
+ },
+ },
+ npStart: {
+ ...npMock.npStart,
+ core: {
+ ...npMock.npStart.core,
+ injectedMetadata: injectedMetadataServiceMock.createStartContract(),
+ },
+ },
+ };
+});
- public start(core: CoreStart) {
- // nothing to do here yet
- }
-}
+Object.assign(window, {
+ sessionStorage: new StubBrowserStorage(),
+});
diff --git a/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts b/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts
new file mode 100644
index 0000000000000..5ae58204a8cf3
--- /dev/null
+++ b/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts
@@ -0,0 +1,257 @@
+/*
+ * 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 angular, { IRootScopeService, IScope, ICompileService } from 'angular';
+import 'angular-mocks';
+import 'angular-sanitize';
+import $ from 'jquery';
+import './table_vis.mock';
+
+// @ts-ignore
+import StubIndexPattern from 'test_utils/stub_index_pattern';
+import { getAngularModule } from './get_inner_angular';
+import { initTableVisLegacyModule } from './table_vis_legacy_module';
+import {
+ npStart,
+ legacyResponseHandlerProvider,
+ AggConfig,
+ tabifyAggResponse,
+} from './legacy_imports';
+import { tableVisTypeDefinition } from './table_vis_type';
+import { Vis } from '../../visualizations/public';
+import { setup as visualizationsSetup } from '../../visualizations/public/np_ready/public/legacy';
+// eslint-disable-next-line
+import { stubFields } from '../../../../plugins/data/public/stubs';
+// eslint-disable-next-line
+import { setFieldFormats } from '../../../../plugins/data/public/index_patterns/services';
+
+interface TableVisScope extends IScope {
+ [key: string]: any;
+}
+
+const oneRangeBucket = {
+ hits: {
+ total: 6039,
+ max_score: 0,
+ hits: [],
+ },
+ aggregations: {
+ agg_2: {
+ buckets: {
+ '0.0-1000.0': {
+ from: 0,
+ from_as_string: '0.0',
+ to: 1000,
+ to_as_string: '1000.0',
+ doc_count: 606,
+ },
+ '1000.0-2000.0': {
+ from: 1000,
+ from_as_string: '1000.0',
+ to: 2000,
+ to_as_string: '2000.0',
+ doc_count: 298,
+ },
+ },
+ },
+ },
+};
+
+describe('Table Vis - Controller', () => {
+ let $rootScope: IRootScopeService & { [key: string]: any };
+ let $compile: ICompileService;
+ let $scope: TableVisScope;
+ let $el: JQuery;
+ let tableAggResponse: any;
+ let tabifiedResponse: any;
+ let stubIndexPattern: any;
+
+ const initLocalAngular = () => {
+ const tableVisModule = getAngularModule('kibana/table_vis', npStart.core);
+ initTableVisLegacyModule(tableVisModule);
+ };
+
+ beforeEach(initLocalAngular);
+ beforeAll(() => {
+ visualizationsSetup.types.createBaseVisualization(tableVisTypeDefinition);
+ });
+ beforeEach(angular.mock.module('kibana/table_vis'));
+
+ beforeEach(
+ angular.mock.inject((_$rootScope_: IRootScopeService, _$compile_: ICompileService) => {
+ $rootScope = _$rootScope_;
+ $compile = _$compile_;
+ tableAggResponse = legacyResponseHandlerProvider().handler;
+ })
+ );
+
+ beforeEach(() => {
+ setFieldFormats(({
+ getDefaultInstance: jest.fn(),
+ } as unknown) as any);
+ stubIndexPattern = new StubIndexPattern(
+ 'logstash-*',
+ (cfg: any) => cfg,
+ 'time',
+ stubFields,
+ npStart.core.uiSettings
+ );
+ });
+
+ function getRangeVis(params?: object) {
+ // @ts-ignore
+ return new Vis(stubIndexPattern, {
+ type: 'table',
+ params: params || {},
+ aggs: [
+ { type: 'count', schema: 'metric' },
+ {
+ type: 'range',
+ schema: 'bucket',
+ params: {
+ field: 'bytes',
+ ranges: [
+ { from: 0, to: 1000 },
+ { from: 1000, to: 2000 },
+ ],
+ },
+ },
+ ],
+ });
+ }
+
+ const dimensions = {
+ buckets: [
+ {
+ accessor: 0,
+ },
+ ],
+ metrics: [
+ {
+ accessor: 1,
+ format: { id: 'range' },
+ },
+ ],
+ };
+
+ // basically a parameterized beforeEach
+ function initController(vis: Vis) {
+ vis.aggs.aggs.forEach((agg: AggConfig, i: number) => {
+ agg.id = 'agg_' + (i + 1);
+ });
+
+ tabifiedResponse = tabifyAggResponse(vis.aggs, oneRangeBucket);
+ $rootScope.vis = vis;
+ $rootScope.visParams = vis.params;
+ $rootScope.uiState = {
+ get: jest.fn(),
+ set: jest.fn(),
+ };
+ $rootScope.renderComplete = () => {};
+ $rootScope.newScope = (scope: TableVisScope) => {
+ $scope = scope;
+ };
+
+ $el = $('')
+ .attr('ng-controller', 'KbnTableVisController')
+ .attr('ng-init', 'newScope(this)');
+
+ $compile($el)($rootScope);
+ }
+
+ // put a response into the controller
+ function attachEsResponseToScope(resp: object) {
+ $rootScope.esResponse = resp;
+ $rootScope.$apply();
+ }
+
+ // remove the response from the controller
+ function removeEsResponseFromScope() {
+ delete $rootScope.esResponse;
+ $rootScope.renderComplete = () => {};
+ $rootScope.$apply();
+ }
+
+ test('exposes #tableGroups and #hasSomeRows when a response is attached to scope', async () => {
+ const vis: Vis = getRangeVis();
+ initController(vis);
+
+ expect(!$scope.tableGroups).toBeTruthy();
+ expect(!$scope.hasSomeRows).toBeTruthy();
+
+ attachEsResponseToScope(await tableAggResponse(tabifiedResponse, dimensions));
+
+ expect($scope.hasSomeRows).toBeTruthy();
+ expect($scope.tableGroups.tables).toBeDefined();
+ expect($scope.tableGroups.tables.length).toBe(1);
+ expect($scope.tableGroups.tables[0].columns.length).toBe(2);
+ expect($scope.tableGroups.tables[0].rows.length).toBe(2);
+ });
+
+ test('clears #tableGroups and #hasSomeRows when the response is removed', async () => {
+ const vis = getRangeVis();
+ initController(vis);
+
+ attachEsResponseToScope(await tableAggResponse(tabifiedResponse, dimensions));
+ removeEsResponseFromScope();
+
+ expect(!$scope.hasSomeRows).toBeTruthy();
+ expect(!$scope.tableGroups).toBeTruthy();
+ });
+
+ test('sets the sort on the scope when it is passed as a vis param', async () => {
+ const sortObj = {
+ columnIndex: 1,
+ direction: 'asc',
+ };
+ const vis = getRangeVis({ sort: sortObj });
+ initController(vis);
+
+ attachEsResponseToScope(await tableAggResponse(tabifiedResponse, dimensions));
+
+ expect($scope.sort.columnIndex).toEqual(sortObj.columnIndex);
+ expect($scope.sort.direction).toEqual(sortObj.direction);
+ });
+
+ test('sets #hasSomeRows properly if the table group is empty', async () => {
+ const vis = getRangeVis();
+ initController(vis);
+
+ tabifiedResponse.rows = [];
+
+ attachEsResponseToScope(await tableAggResponse(tabifiedResponse, dimensions));
+
+ expect($scope.hasSomeRows).toBeFalsy();
+ expect(!$scope.tableGroups).toBeTruthy();
+ });
+
+ test('passes partialRows:true to tabify based on the vis params', () => {
+ const vis = getRangeVis({ showPartialRows: true });
+ initController(vis);
+
+ expect(vis.isHierarchical()).toEqual(true);
+ });
+
+ test('passes partialRows:false to tabify based on the vis params', () => {
+ const vis = getRangeVis({ showPartialRows: false });
+ initController(vis);
+
+ expect(vis.isHierarchical()).toEqual(false);
+ });
+});
diff --git a/src/legacy/core_plugins/vis_type_table/public/table_vis_fn.test.ts b/src/legacy/core_plugins/vis_type_table/public/table_vis_fn.test.ts
index d909842a71e2d..c1def9b55aae2 100644
--- a/src/legacy/core_plugins/vis_type_table/public/table_vis_fn.test.ts
+++ b/src/legacy/core_plugins/vis_type_table/public/table_vis_fn.test.ts
@@ -22,9 +22,7 @@ import { createTableVisFn } from './table_vis_fn';
// eslint-disable-next-line
import { functionWrapper } from '../../../../plugins/expressions/public/functions/tests/utils';
-jest.mock('ui/new_platform');
-
-jest.mock('ui/vis/response_handlers/legacy', () => {
+jest.mock('./legacy_imports', () => {
const mockResponseHandler = jest.fn().mockReturnValue(
Promise.resolve({
tables: [{ columns: [], rows: [] }],
@@ -37,7 +35,7 @@ jest.mock('ui/vis/response_handlers/legacy', () => {
};
});
-const { mockResponseHandler } = jest.requireMock('ui/vis/response_handlers/legacy');
+const { mockResponseHandler } = jest.requireMock('./legacy_imports');
describe('interpreter/functions#table', () => {
const fn = functionWrapper(createTableVisFn);
diff --git a/src/legacy/core_plugins/vis_type_table/public/shim/table_vis_legacy_module.ts b/src/legacy/core_plugins/vis_type_table/public/table_vis_legacy_module.ts
similarity index 65%
rename from src/legacy/core_plugins/vis_type_table/public/shim/table_vis_legacy_module.ts
rename to src/legacy/core_plugins/vis_type_table/public/table_vis_legacy_module.ts
index e148fd98490df..57d8b7c448b4c 100644
--- a/src/legacy/core_plugins/vis_type_table/public/shim/table_vis_legacy_module.ts
+++ b/src/legacy/core_plugins/vis_type_table/public/table_vis_legacy_module.ts
@@ -17,32 +17,25 @@
* under the License.
*/
-import { once } from 'lodash';
+import { IModule } from 'angular';
// @ts-ignore
-import { uiModules } from 'ui/modules';
-
-import 'angular-recursion';
-import 'ui/directives/paginate';
-
-// @ts-ignore
-import { TableVisController } from '../table_vis_controller.js';
+import { TableVisController } from './table_vis_controller.js';
// @ts-ignore
-import { KbnAggTable } from '../agg_table/agg_table';
+import { KbnAggTable } from './agg_table/agg_table';
// @ts-ignore
-import { KbnAggTableGroup } from '../agg_table/agg_table_group';
+import { KbnAggTableGroup } from './agg_table/agg_table_group';
// @ts-ignore
-import { KbnRows } from '../paginated_table/rows';
+import { KbnRows } from './paginated_table/rows';
// @ts-ignore
-import { PaginatedTable } from '../paginated_table/paginated_table';
+import { PaginatedTable } from './paginated_table/paginated_table';
/** @internal */
-export const initTableVisLegacyModule = once((): void => {
- uiModules
- .get('kibana/table_vis', ['kibana', 'RecursionHelper'])
+export const initTableVisLegacyModule = (angularIns: IModule): void => {
+ angularIns
.controller('KbnTableVisController', TableVisController)
.directive('kbnAggTable', KbnAggTable)
.directive('kbnAggTableGroup', KbnAggTableGroup)
.directive('kbnRows', KbnRows)
.directive('paginatedTable', PaginatedTable);
-});
+};
diff --git a/src/legacy/core_plugins/vis_type_table/public/table_vis_request_handler.ts b/src/legacy/core_plugins/vis_type_table/public/table_vis_request_handler.ts
index c432dfd84cbb8..1a6d4600025f1 100644
--- a/src/legacy/core_plugins/vis_type_table/public/table_vis_request_handler.ts
+++ b/src/legacy/core_plugins/vis_type_table/public/table_vis_request_handler.ts
@@ -17,7 +17,6 @@
* under the License.
*/
-// @ts-ignore
-import { legacyResponseHandlerProvider } from 'ui/vis/response_handlers/legacy';
+import { legacyResponseHandlerProvider } from './legacy_imports';
export const tableVisResponseHandler = legacyResponseHandlerProvider().handler;
diff --git a/src/legacy/core_plugins/vis_type_table/public/table_vis_type.ts b/src/legacy/core_plugins/vis_type_table/public/table_vis_type.ts
index 7e8537a1fee54..5186b6cf59dfd 100644
--- a/src/legacy/core_plugins/vis_type_table/public/table_vis_type.ts
+++ b/src/legacy/core_plugins/vis_type_table/public/table_vis_type.ts
@@ -18,18 +18,13 @@
*/
import { i18n } from '@kbn/i18n';
-import { Vis } from 'ui/vis';
-// @ts-ignore
-
-// @ts-ignore
-import { Schemas } from 'ui/vis/editors/default/schemas';
-// @ts-ignore
-import { AngularVisController } from 'ui/vis/vis_types/angular_vis_type';
-import { AggGroupNames } from 'ui/vis/editors/default';
+import { AggGroupNames, Schemas } from './legacy_imports';
+import { Vis } from '../../visualizations/public';
import { tableVisResponseHandler } from './table_vis_request_handler';
// @ts-ignore
import tableVisTemplate from './table_vis.html';
import { TableOptions } from './components/table_vis_options';
+import { TableVisualizationController } from './vis_controller';
export const tableVisTypeDefinition = {
type: 'table',
@@ -41,7 +36,7 @@ export const tableVisTypeDefinition = {
description: i18n.translate('visTypeTable.tableVisDescription', {
defaultMessage: 'Display values in a table',
}),
- visualization: AngularVisController,
+ visualization: TableVisualizationController,
visConfig: {
defaults: {
perPage: 10,
diff --git a/src/legacy/core_plugins/vis_type_table/public/vis_controller.ts b/src/legacy/core_plugins/vis_type_table/public/vis_controller.ts
new file mode 100644
index 0000000000000..7adaa21cac593
--- /dev/null
+++ b/src/legacy/core_plugins/vis_type_table/public/vis_controller.ts
@@ -0,0 +1,104 @@
+/*
+ * 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 angular, { IModule, auto, IRootScopeService, IScope, ICompileService } from 'angular';
+import $ from 'jquery';
+
+import { Vis, VisParams } from '../../visualizations/public';
+import { npStart } from './legacy_imports';
+import { getAngularModule } from './get_inner_angular';
+import { initTableVisLegacyModule } from './table_vis_legacy_module';
+
+const innerAngularName = 'kibana/table_vis';
+
+export class TableVisualizationController {
+ private tableVisModule: IModule | undefined;
+ private injector: auto.IInjectorService | undefined;
+ el: JQuery
;
+ vis: Vis;
+ $rootScope: IRootScopeService | null = null;
+ $scope: (IScope & { [key: string]: any }) | undefined;
+ $compile: ICompileService | undefined;
+
+ constructor(domeElement: Element, vis: Vis) {
+ this.el = $(domeElement);
+ this.vis = vis;
+ }
+
+ getInjector() {
+ if (!this.injector) {
+ const mountpoint = document.createElement('div');
+ mountpoint.setAttribute('style', 'height: 100%; width: 100%;');
+ this.injector = angular.bootstrap(mountpoint, [innerAngularName]);
+ this.el.append(mountpoint);
+ }
+
+ return this.injector;
+ }
+
+ initLocalAngular() {
+ if (!this.tableVisModule) {
+ this.tableVisModule = getAngularModule(innerAngularName, npStart.core);
+ initTableVisLegacyModule(this.tableVisModule);
+ }
+ }
+
+ async render(esResponse: object, visParams: VisParams, status: { [key: string]: boolean }) {
+ this.initLocalAngular();
+
+ return new Promise(async (resolve, reject) => {
+ if (!this.$rootScope) {
+ const $injector = this.getInjector();
+ this.$rootScope = $injector.get('$rootScope');
+ this.$compile = $injector.get('$compile');
+ }
+ const updateScope = () => {
+ if (!this.$scope) {
+ return;
+ }
+ this.$scope.vis = this.vis;
+ this.$scope.visState = this.vis.getState();
+ this.$scope.esResponse = esResponse;
+ this.$scope.visParams = visParams;
+ this.$scope.renderComplete = resolve;
+ this.$scope.renderFailed = reject;
+ this.$scope.resize = Date.now();
+ this.$scope.updateStatus = status;
+ this.$scope.$apply();
+ };
+
+ if (!this.$scope && this.$compile) {
+ this.$scope = this.$rootScope.$new();
+ this.$scope.uiState = this.vis.getUiState();
+ updateScope();
+ this.el.find('div').append(this.$compile(this.vis.type.visConfig.template)(this.$scope));
+ this.$scope.$apply();
+ } else {
+ updateScope();
+ }
+ });
+ }
+
+ destroy() {
+ if (this.$rootScope) {
+ this.$rootScope.$destroy();
+ this.$rootScope = null;
+ }
+ }
+}
diff --git a/src/legacy/ui/public/directives/paginate.js b/src/legacy/ui/public/directives/paginate.js
index 7ecd5fefe6710..6663e1fb8b6e4 100644
--- a/src/legacy/ui/public/directives/paginate.js
+++ b/src/legacy/ui/public/directives/paginate.js
@@ -22,209 +22,215 @@ import { i18n } from '@kbn/i18n';
import { uiModules } from '../modules';
import paginateControlsTemplate from './partials/paginate_controls.html';
-uiModules.get('kibana')
- .directive('paginate', function ($parse, $compile) {
- return {
- restrict: 'E',
- scope: true,
- link: {
- pre: function ($scope, $el, attrs) {
- if (_.isUndefined(attrs.bottomControls)) attrs.bottomControls = true;
- if ($el.find('paginate-controls.paginate-bottom').length === 0 && attrs.bottomControls) {
- $el.append($compile('')($scope));
- }
- },
- post: function ($scope, $el, attrs) {
- if (_.isUndefined(attrs.topControls)) attrs.topControls = false;
- if ($el.find('paginate-controls.paginate-top').length === 0 && attrs.topControls) {
- $el.prepend($compile('')($scope));
- }
-
- const paginate = $scope.paginate;
-
- // add some getters to the controller powered by attributes
- paginate.getList = $parse(attrs.list);
- paginate.perPageProp = attrs.perPageProp;
-
- if (attrs.perPage) {
- paginate.perPage = attrs.perPage;
- $scope.showSelector = false;
- } else {
- $scope.showSelector = true;
- }
-
- paginate.otherWidthGetter = $parse(attrs.otherWidth);
-
- paginate.init();
+export function PaginateDirectiveProvider($parse, $compile) {
+ return {
+ restrict: 'E',
+ scope: true,
+ link: {
+ pre: function ($scope, $el, attrs) {
+ if (_.isUndefined(attrs.bottomControls)) attrs.bottomControls = true;
+ if ($el.find('paginate-controls.paginate-bottom').length === 0 && attrs.bottomControls) {
+ $el.append($compile('')($scope));
}
},
- controllerAs: 'paginate',
- controller: function ($scope, $document) {
- const self = this;
- const ALL = 0;
- const allSizeTitle = i18n.translate('common.ui.directives.paginate.size.allDropDownOptionLabel', {
- defaultMessage: 'All',
- });
+ post: function ($scope, $el, attrs) {
+ if (_.isUndefined(attrs.topControls)) attrs.topControls = false;
+ if ($el.find('paginate-controls.paginate-top').length === 0 && attrs.topControls) {
+ $el.prepend($compile('')($scope));
+ }
- self.sizeOptions = [
- { title: '10', value: 10 },
- { title: '25', value: 25 },
- { title: '100', value: 100 },
- { title: allSizeTitle, value: ALL }
- ];
+ const paginate = $scope.paginate;
- // setup the watchers, called in the post-link function
- self.init = function () {
+ // add some getters to the controller powered by attributes
+ paginate.getList = $parse(attrs.list);
+ paginate.perPageProp = attrs.perPageProp;
- self.perPage = _.parseInt(self.perPage) || $scope[self.perPageProp];
+ if (attrs.perPage) {
+ paginate.perPage = attrs.perPage;
+ $scope.showSelector = false;
+ } else {
+ $scope.showSelector = true;
+ }
- $scope.$watchMulti([
- 'paginate.perPage',
- self.perPageProp,
- self.otherWidthGetter
- ], function (vals, oldVals) {
- const intChanges = vals[0] !== oldVals[0];
+ paginate.otherWidthGetter = $parse(attrs.otherWidth);
- if (intChanges) {
- if (!setPerPage(self.perPage)) {
+ paginate.init();
+ },
+ },
+ controllerAs: 'paginate',
+ controller: function ($scope, $document) {
+ const self = this;
+ const ALL = 0;
+ const allSizeTitle = i18n.translate(
+ 'common.ui.directives.paginate.size.allDropDownOptionLabel',
+ {
+ defaultMessage: 'All',
+ }
+ );
+
+ self.sizeOptions = [
+ { title: '10', value: 10 },
+ { title: '25', value: 25 },
+ { title: '100', value: 100 },
+ { title: allSizeTitle, value: ALL },
+ ];
+
+ // setup the watchers, called in the post-link function
+ self.init = function () {
+ self.perPage = _.parseInt(self.perPage) || $scope[self.perPageProp];
+
+ $scope.$watchMulti(['paginate.perPage', self.perPageProp, self.otherWidthGetter], function (
+ vals,
+ oldVals
+ ) {
+ const intChanges = vals[0] !== oldVals[0];
+
+ if (intChanges) {
+ if (!setPerPage(self.perPage)) {
// if we are not able to set the external value,
// render now, otherwise wait for the external value
// to trigger the watcher again
- self.renderList();
- }
- return;
+ self.renderList();
}
+ return;
+ }
- self.perPage = _.parseInt(self.perPage) || $scope[self.perPageProp];
- if (self.perPage == null) {
- self.perPage = ALL;
- return;
- }
+ self.perPage = _.parseInt(self.perPage) || $scope[self.perPageProp];
+ if (self.perPage == null) {
+ self.perPage = ALL;
+ return;
+ }
- self.renderList();
- });
+ self.renderList();
+ });
- $scope.$watch('page', self.changePage);
- $scope.$watchCollection(self.getList, function (list) {
- $scope.list = list;
- self.renderList();
- });
- };
+ $scope.$watch('page', self.changePage);
+ $scope.$watchCollection(self.getList, function (list) {
+ $scope.list = list;
+ self.renderList();
+ });
+ };
- self.goToPage = function (number) {
- if (number) {
- if (number.hasOwnProperty('number')) number = number.number;
- $scope.page = $scope.pages[number - 1] || $scope.pages[0];
- }
- };
+ self.goToPage = function (number) {
+ if (number) {
+ if (number.hasOwnProperty('number')) number = number.number;
+ $scope.page = $scope.pages[number - 1] || $scope.pages[0];
+ }
+ };
- self.goToTop = function goToTop() {
- $document.scrollTop(0);
- };
+ self.goToTop = function goToTop() {
+ $document.scrollTop(0);
+ };
- self.renderList = function () {
- $scope.pages = [];
- if (!$scope.list) return;
+ self.renderList = function () {
+ $scope.pages = [];
+ if (!$scope.list) return;
- const perPage = _.parseInt(self.perPage);
- const count = perPage ? Math.ceil($scope.list.length / perPage) : 1;
+ const perPage = _.parseInt(self.perPage);
+ const count = perPage ? Math.ceil($scope.list.length / perPage) : 1;
- _.times(count, function (i) {
- let page;
+ _.times(count, function (i) {
+ let page;
- if (perPage) {
- const start = perPage * i;
- page = $scope.list.slice(start, start + perPage);
- } else {
- page = $scope.list.slice(0);
- }
+ if (perPage) {
+ const start = perPage * i;
+ page = $scope.list.slice(start, start + perPage);
+ } else {
+ page = $scope.list.slice(0);
+ }
- page.number = i + 1;
- page.i = i;
+ page.number = i + 1;
+ page.i = i;
- page.count = count;
- page.first = page.number === 1;
- page.last = page.number === count;
- page.firstItem = (page.number - 1) * perPage + 1;
- page.lastItem = Math.min(page.number * perPage, $scope.list.length);
+ page.count = count;
+ page.first = page.number === 1;
+ page.last = page.number === count;
+ page.firstItem = (page.number - 1) * perPage + 1;
+ page.lastItem = Math.min(page.number * perPage, $scope.list.length);
- page.prev = $scope.pages[i - 1];
- if (page.prev) page.prev.next = page;
+ page.prev = $scope.pages[i - 1];
+ if (page.prev) page.prev.next = page;
- $scope.pages.push(page);
- });
+ $scope.pages.push(page);
+ });
- // set the new page, or restore the previous page number
- if ($scope.page && $scope.page.i < $scope.pages.length) {
- $scope.page = $scope.pages[$scope.page.i];
- } else {
- $scope.page = $scope.pages[0];
- }
+ // set the new page, or restore the previous page number
+ if ($scope.page && $scope.page.i < $scope.pages.length) {
+ $scope.page = $scope.pages[$scope.page.i];
+ } else {
+ $scope.page = $scope.pages[0];
+ }
- if ($scope.page && $scope.onPageChanged) {
- $scope.onPageChanged($scope.page);
- }
- };
+ if ($scope.page && $scope.onPageChanged) {
+ $scope.onPageChanged($scope.page);
+ }
+ };
- self.changePage = function (page) {
- if (!page) {
- $scope.otherPages = null;
- return;
- }
+ self.changePage = function (page) {
+ if (!page) {
+ $scope.otherPages = null;
+ return;
+ }
- // setup the list of the other pages to link to
- $scope.otherPages = [];
- const width = +self.otherWidthGetter($scope) || 5;
- let left = page.i - Math.round((width - 1) / 2);
- let right = left + width - 1;
+ // setup the list of the other pages to link to
+ $scope.otherPages = [];
+ const width = +self.otherWidthGetter($scope) || 5;
+ let left = page.i - Math.round((width - 1) / 2);
+ let right = left + width - 1;
- // shift neg count from left to right
- if (left < 0) {
- right += 0 - left;
- left = 0;
- }
+ // shift neg count from left to right
+ if (left < 0) {
+ right += 0 - left;
+ left = 0;
+ }
- // shift extra right nums to left
- const lastI = page.count - 1;
- if (right > lastI) {
- right = lastI;
- left = right - width + 1;
- }
+ // shift extra right nums to left
+ const lastI = page.count - 1;
+ if (right > lastI) {
+ right = lastI;
+ left = right - width + 1;
+ }
- for (let i = left; i <= right; i++) {
- const other = $scope.pages[i];
+ for (let i = left; i <= right; i++) {
+ const other = $scope.pages[i];
- if (!other) continue;
+ if (!other) continue;
- $scope.otherPages.push(other);
- if (other.last) $scope.otherPages.containsLast = true;
- if (other.first) $scope.otherPages.containsFirst = true;
- }
+ $scope.otherPages.push(other);
+ if (other.last) $scope.otherPages.containsLast = true;
+ if (other.first) $scope.otherPages.containsFirst = true;
+ }
- if ($scope.onPageChanged) {
- $scope.onPageChanged($scope.page);
- }
- };
+ if ($scope.onPageChanged) {
+ $scope.onPageChanged($scope.page);
+ }
+ };
- function setPerPage(val) {
- let $ppParent = $scope;
+ function setPerPage(val) {
+ let $ppParent = $scope;
- while ($ppParent && !_.has($ppParent, self.perPageProp)) {
- $ppParent = $ppParent.$parent;
- }
+ while ($ppParent && !_.has($ppParent, self.perPageProp)) {
+ $ppParent = $ppParent.$parent;
+ }
- if ($ppParent) {
- $ppParent[self.perPageProp] = val;
- return true;
- }
+ if ($ppParent) {
+ $ppParent[self.perPageProp] = val;
+ return true;
}
}
- };
- })
- .directive('paginateControls', function () {
+ },
+ };
+}
+
+export function PaginateControlsDirectiveProvider() {
// this directive is automatically added by paginate if not found within it's $el
- return {
- restrict: 'E',
- template: paginateControlsTemplate
- };
- });
+ return {
+ restrict: 'E',
+ template: paginateControlsTemplate,
+ };
+}
+
+uiModules
+ .get('kibana')
+ .directive('paginate', PaginateDirectiveProvider)
+ .directive('paginateControls', PaginateControlsDirectiveProvider);
diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js
index 80031efba6e48..f8850d1691cdd 100644
--- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js
+++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js
@@ -114,8 +114,10 @@ export const npSetup = {
registerAction: sinon.fake(),
registerTrigger: sinon.fake(),
},
- feature_catalogue: {
- register: sinon.fake(),
+ home: {
+ featureCatalogue: {
+ register: sinon.fake(),
+ },
},
},
};
@@ -229,8 +231,10 @@ export const npStart = {
getTriggerActions: sinon.fake(),
getTriggerCompatibleActions: sinon.fake(),
},
- feature_catalogue: {
- register: sinon.fake(),
+ home: {
+ featureCatalogue: {
+ register: sinon.fake(),
+ },
},
},
};