mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
* [Vis] TableVis uses local angular (#50759)
* TableVis uses local angular
* Clean up
* Fix TS
* Update angular_config
* Fix export
* Update render_app.ts
* Cetralize ui deps
* Fix loading KbnTableVisController in Dashboard
* Fix graph
* Rename const
* Add table vis mocks
* Fix kbn_top_nav
* Add TS for test
* Complete conversion paginated_table test to Jest
* Convert table_vis_controller test to Jest
* Convert table_vis_controller test to Jest
* Create agg_table.test.ts
* Fix mocha tests
* Refactoring
* Remove module dep
* Remove LegacyDependenciesPlugin
* Move file
* Fix path
* Fix path
* Fix TS
* Fix Jest test
* Fix TS
* Revert "Fix TS"
This reverts commit 4cff6f6767
.
This commit is contained in:
parent
542b94a242
commit
83fb4f6453
21 changed files with 1486 additions and 879 deletions
|
@ -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 = $('<div>')
|
||||
.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);
|
||||
});
|
||||
});
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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<TablePluginSetupDependencies> = {
|
||||
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);
|
||||
|
|
|
@ -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';
|
|
@ -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 = `
|
||||
<paginated-table
|
||||
table="table"
|
||||
columns="cols"
|
||||
rows="rows"
|
||||
per-page="perPage"
|
||||
sort="sort"
|
||||
link-to-top="linkToTop">`;
|
||||
$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' ? '<h1>hello</h1>' : 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);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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<Element>;
|
||||
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 = `
|
||||
<paginated-table
|
||||
table="table"
|
||||
columns="cols"
|
||||
rows="rows"
|
||||
per-page="perPage"
|
||||
sort="sort"
|
||||
link-to-top="linkToTop">`;
|
||||
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' ? '<h1>hello</h1>' : 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);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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<ExpressionsPublicPlugin['setup']>;
|
||||
visualizations: VisualizationsSetup;
|
||||
__LEGACY: LegacyDependenciesPlugin;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
@ -43,9 +40,8 @@ export class TableVisPlugin implements Plugin<Promise<void>, void> {
|
|||
|
||||
public async setup(
|
||||
core: CoreSetup,
|
||||
{ expressions, visualizations, __LEGACY }: TablePluginSetupDependencies
|
||||
{ expressions, visualizations }: TablePluginSetupDependencies
|
||||
) {
|
||||
__LEGACY.setup();
|
||||
expressions.registerFunction(createTableVisFn);
|
||||
|
||||
visualizations.types.createBaseVisualization(tableVisTypeDefinition);
|
||||
|
|
|
@ -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';
|
|
@ -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(),
|
||||
});
|
|
@ -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<HTMLElement>;
|
||||
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 = $('<div>')
|
||||
.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);
|
||||
});
|
||||
});
|
|
@ -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);
|
||||
|
|
|
@ -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';
|
||||
|
||||
import { TableVisController } from './table_vis_controller.js';
|
||||
// @ts-ignore
|
||||
import { TableVisController } from '../table_vis_controller.js';
|
||||
import { KbnAggTable } from './agg_table/agg_table';
|
||||
// @ts-ignore
|
||||
import { KbnAggTable } from '../agg_table/agg_table';
|
||||
import { KbnAggTableGroup } from './agg_table/agg_table_group';
|
||||
// @ts-ignore
|
||||
import { KbnAggTableGroup } from '../agg_table/agg_table_group';
|
||||
import { KbnRows } from './paginated_table/rows';
|
||||
// @ts-ignore
|
||||
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);
|
||||
});
|
||||
};
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
104
src/legacy/core_plugins/vis_type_table/public/vis_controller.ts
Normal file
104
src/legacy/core_plugins/vis_type_table/public/vis_controller.ts
Normal file
|
@ -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<Element>;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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('<paginate-controls class="paginate-bottom">')($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('<paginate-controls class="paginate-top">')($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('<paginate-controls class="paginate-bottom">')($scope));
|
||||
}
|
||||
},
|
||||
controllerAs: 'paginate',
|
||||
controller: function ($scope, $document) {
|
||||
const self = this;
|
||||
const ALL = 0;
|
||||
const allSizeTitle = i18n.translate('common.ui.directives.paginate.size.allDropDownOptionLabel', {
|
||||
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('<paginate-controls class="paginate-top">')($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();
|
||||
},
|
||||
},
|
||||
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 }
|
||||
];
|
||||
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 () {
|
||||
// setup the watchers, called in the post-link function
|
||||
self.init = function () {
|
||||
self.perPage = _.parseInt(self.perPage) || $scope[self.perPageProp];
|
||||
|
||||
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];
|
||||
|
||||
$scope.$watchMulti([
|
||||
'paginate.perPage',
|
||||
self.perPageProp,
|
||||
self.otherWidthGetter
|
||||
], function (vals, oldVals) {
|
||||
const intChanges = vals[0] !== oldVals[0];
|
||||
|
||||
if (intChanges) {
|
||||
if (!setPerPage(self.perPage)) {
|
||||
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();
|
||||
}
|
||||
|
||||
self.perPage = _.parseInt(self.perPage) || $scope[self.perPageProp];
|
||||
if (self.perPage == null) {
|
||||
self.perPage = ALL;
|
||||
return;
|
||||
}
|
||||
|
||||
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.goToTop = function goToTop() {
|
||||
$document.scrollTop(0);
|
||||
};
|
||||
|
||||
self.renderList = function () {
|
||||
$scope.pages = [];
|
||||
if (!$scope.list) return;
|
||||
|
||||
const perPage = _.parseInt(self.perPage);
|
||||
const count = perPage ? Math.ceil($scope.list.length / perPage) : 1;
|
||||
|
||||
_.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);
|
||||
}
|
||||
|
||||
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.prev = $scope.pages[i - 1];
|
||||
if (page.prev) page.prev.next = 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];
|
||||
}
|
||||
|
||||
if ($scope.page && $scope.onPageChanged) {
|
||||
$scope.onPageChanged($scope.page);
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
// shift neg count from left to right
|
||||
if (left < 0) {
|
||||
right += 0 - left;
|
||||
left = 0;
|
||||
self.perPage = _.parseInt(self.perPage) || $scope[self.perPageProp];
|
||||
if (self.perPage == null) {
|
||||
self.perPage = ALL;
|
||||
return;
|
||||
}
|
||||
|
||||
// shift extra right nums to left
|
||||
const lastI = page.count - 1;
|
||||
if (right > lastI) {
|
||||
right = lastI;
|
||||
left = right - width + 1;
|
||||
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.goToTop = function goToTop() {
|
||||
$document.scrollTop(0);
|
||||
};
|
||||
|
||||
self.renderList = function () {
|
||||
$scope.pages = [];
|
||||
if (!$scope.list) return;
|
||||
|
||||
const perPage = _.parseInt(self.perPage);
|
||||
const count = perPage ? Math.ceil($scope.list.length / perPage) : 1;
|
||||
|
||||
_.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);
|
||||
}
|
||||
|
||||
for (let i = left; i <= right; i++) {
|
||||
const other = $scope.pages[i];
|
||||
page.number = i + 1;
|
||||
page.i = i;
|
||||
|
||||
if (!other) continue;
|
||||
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);
|
||||
|
||||
$scope.otherPages.push(other);
|
||||
if (other.last) $scope.otherPages.containsLast = true;
|
||||
if (other.first) $scope.otherPages.containsFirst = true;
|
||||
}
|
||||
page.prev = $scope.pages[i - 1];
|
||||
if (page.prev) page.prev.next = page;
|
||||
|
||||
if ($scope.onPageChanged) {
|
||||
$scope.onPageChanged($scope.page);
|
||||
}
|
||||
};
|
||||
$scope.pages.push(page);
|
||||
});
|
||||
|
||||
function setPerPage(val) {
|
||||
let $ppParent = $scope;
|
||||
// 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];
|
||||
}
|
||||
|
||||
while ($ppParent && !_.has($ppParent, self.perPageProp)) {
|
||||
$ppParent = $ppParent.$parent;
|
||||
}
|
||||
if ($scope.page && $scope.onPageChanged) {
|
||||
$scope.onPageChanged($scope.page);
|
||||
}
|
||||
};
|
||||
|
||||
if ($ppParent) {
|
||||
$ppParent[self.perPageProp] = val;
|
||||
return true;
|
||||
}
|
||||
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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
for (let i = left; i <= right; i++) {
|
||||
const other = $scope.pages[i];
|
||||
|
||||
if (!other) continue;
|
||||
|
||||
$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);
|
||||
}
|
||||
};
|
||||
|
||||
function setPerPage(val) {
|
||||
let $ppParent = $scope;
|
||||
|
||||
while ($ppParent && !_.has($ppParent, self.perPageProp)) {
|
||||
$ppParent = $ppParent.$parent;
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -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(),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue