')
- .attr('ng-controller', 'OsdTableVisController')
- .attr('ng-init', 'newScope(this)');
-
- $compile($el)($rootScope);
- }
-
- // put a response into the controller
- function attachOpenSearchResponseToScope(resp: object) {
- $rootScope.opensearchResponse = resp;
- $rootScope.$apply();
- }
-
- // remove the response from the controller
- function removeOpenSearchResponseFromScope() {
- delete $rootScope.opensearchResponse;
- $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();
-
- attachOpenSearchResponseToScope(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);
-
- attachOpenSearchResponseToScope(await tableAggResponse(tabifiedResponse, dimensions));
- removeOpenSearchResponseFromScope();
-
- 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);
-
- attachOpenSearchResponseToScope(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 = [];
-
- attachOpenSearchResponseToScope(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.type.hierarchicalData as Function)(vis)).toEqual(true);
- });
-
- test('passes partialRows:false to tabify based on the vis params', () => {
- const vis = getRangeVis({ showPartialRows: false });
- initController(vis);
-
- expect((vis.type.hierarchicalData as Function)(vis)).toEqual(false);
- });
-});
diff --git a/src/plugins/vis_type_table/public/table_vis_fn.test.ts b/src/plugins/vis_type_table/public/table_vis_fn.test.ts
deleted file mode 100644
index f7723456b757..000000000000
--- a/src/plugins/vis_type_table/public/table_vis_fn.test.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * SPDX-License-Identifier: Apache-2.0
- *
- * The OpenSearch Contributors require contributions made to
- * this file be licensed under the Apache-2.0 license or a
- * compatible open source license.
- *
- * Any modifications Copyright OpenSearch Contributors. See
- * GitHub history for details.
- */
-
-/*
- * 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 { createTableVisFn } from './table_vis_fn';
-import { tableVisResponseHandler } from './table_vis_response_handler';
-
-import { functionWrapper } from '../../expressions/common/expression_functions/specs/tests/utils';
-
-jest.mock('./table_vis_response_handler', () => ({
- tableVisResponseHandler: jest.fn().mockReturnValue({
- tables: [{ columns: [], rows: [] }],
- }),
-}));
-
-describe('interpreter/functions#table', () => {
- const fn = functionWrapper(createTableVisFn());
- const context = {
- type: 'opensearch_dashboards_datatable',
- rows: [{ 'col-0-1': 0 }],
- columns: [{ id: 'col-0-1', name: 'Count' }],
- };
- const visConfig = {
- title: 'My Chart title',
- perPage: 10,
- showPartialRows: false,
- showMetricsAtAllLevels: false,
- sort: {
- columnIndex: null,
- direction: null,
- },
- showTotal: false,
- totalFunc: 'sum',
- dimensions: {
- metrics: [
- {
- accessor: 0,
- format: {
- id: 'number',
- },
- params: {},
- aggType: 'count',
- },
- ],
- buckets: [],
- },
- };
-
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
- it('returns an object with the correct structure', async () => {
- const actual = await fn(context, { visConfig: JSON.stringify(visConfig) }, undefined);
- expect(actual).toMatchSnapshot();
- });
-
- it('calls response handler with correct values', async () => {
- await fn(context, { visConfig: JSON.stringify(visConfig) }, undefined);
- expect(tableVisResponseHandler).toHaveBeenCalledTimes(1);
- expect(tableVisResponseHandler).toHaveBeenCalledWith(context, visConfig.dimensions);
- });
-});
diff --git a/src/plugins/vis_type_table/public/table_vis_fn.ts b/src/plugins/vis_type_table/public/table_vis_fn.ts
index daf76580b59f..3e3bd38dba47 100644
--- a/src/plugins/vis_type_table/public/table_vis_fn.ts
+++ b/src/plugins/vis_type_table/public/table_vis_fn.ts
@@ -1,31 +1,6 @@
/*
+ * Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
- *
- * The OpenSearch Contributors require contributions made to
- * this file be licensed under the Apache-2.0 license or a
- * compatible open source license.
- *
- * Any modifications Copyright OpenSearch Contributors. See
- * GitHub history for details.
- */
-
-/*
- * 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 { i18n } from '@osd/i18n';
@@ -35,7 +10,7 @@ import {
OpenSearchDashboardsDatatable,
Render,
} from '../../expressions/public';
-import { VisRenderValue } from '../../visualizations/public';
+import { TableVisConfig } from './types';
export type Input = OpenSearchDashboardsDatatable;
@@ -43,17 +18,20 @@ interface Arguments {
visConfig: string | null;
}
-interface RenderValue extends VisRenderValue {
+export interface TableVisRenderValue {
visData: TableContext;
visType: 'table';
+ visConfig: TableVisConfig;
}
-export const createTableVisFn = (): ExpressionFunctionDefinition<
+export type TableVisExpressionFunctionDefinition = ExpressionFunctionDefinition<
'opensearch_dashboards_table',
Input,
Arguments,
- Render
-> => ({
+ Render
+>;
+
+export const createTableVisFn = (): TableVisExpressionFunctionDefinition => ({
name: 'opensearch_dashboards_table',
type: 'render',
inputTypes: ['opensearch_dashboards_datatable'],
@@ -69,18 +47,18 @@ export const createTableVisFn = (): ExpressionFunctionDefinition<
},
fn(input, args) {
const visConfig = args.visConfig && JSON.parse(args.visConfig);
- const convertedData = tableVisResponseHandler(input, visConfig.dimensions);
+ const convertedData = tableVisResponseHandler(input, visConfig);
return {
type: 'render',
- as: 'visualization',
+ as: 'table_vis',
value: {
visData: convertedData,
visType: 'table',
visConfig,
- params: {
- listenOnChange: true,
- },
+ },
+ params: {
+ listenOnChange: true,
},
};
},
diff --git a/src/plugins/vis_type_table/public/table_vis_legacy_module.ts b/src/plugins/vis_type_table/public/table_vis_legacy_module.ts
deleted file mode 100644
index 49eed3494f92..000000000000
--- a/src/plugins/vis_type_table/public/table_vis_legacy_module.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SPDX-License-Identifier: Apache-2.0
- *
- * The OpenSearch Contributors require contributions made to
- * this file be licensed under the Apache-2.0 license or a
- * compatible open source license.
- *
- * Any modifications Copyright OpenSearch Contributors. See
- * GitHub history for details.
- */
-
-/*
- * 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 { IModule } from 'angular';
-
-// @ts-ignore
-import { TableVisController } from './table_vis_controller.js';
-// @ts-ignore
-import { OsdAggTable } from './agg_table/agg_table';
-// @ts-ignore
-import { OsdAggTableGroup } from './agg_table/agg_table_group';
-// @ts-ignore
-import { OsdRows } from './paginated_table/rows';
-// @ts-ignore
-import { PaginatedTable } from './paginated_table/paginated_table';
-
-/** @internal */
-export const initTableVisLegacyModule = (angularIns: IModule): void => {
- angularIns
- .controller('OsdTableVisController', TableVisController)
- .directive('osdAggTable', OsdAggTable)
- .directive('osdAggTableGroup', OsdAggTableGroup)
- .directive('osdRows', OsdRows)
- .directive('paginatedTable', PaginatedTable);
-};
diff --git a/src/plugins/vis_type_table/public/table_vis_renderer.tsx b/src/plugins/vis_type_table/public/table_vis_renderer.tsx
new file mode 100644
index 000000000000..a717d38e04b2
--- /dev/null
+++ b/src/plugins/vis_type_table/public/table_vis_renderer.tsx
@@ -0,0 +1,37 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React from 'react';
+import { render, unmountComponentAtNode } from 'react-dom';
+
+import { CoreStart } from 'opensearch-dashboards/public';
+import { VisualizationContainer } from '../../visualizations/public';
+import { ExpressionRenderDefinition } from '../../expressions/common/expression_renderers';
+import { TableVisRenderValue } from './table_vis_fn';
+import { TableVisApp } from './components/table_vis_app';
+
+export const getTableVisRenderer: (
+ core: CoreStart
+) => ExpressionRenderDefinition = (core) => ({
+ name: 'table_vis',
+ displayName: 'table visualization',
+ reuseDomNode: true,
+ render: async (domNode, { visData, visConfig }, handlers) => {
+ handlers.onDestroy(() => {
+ unmountComponentAtNode(domNode);
+ });
+
+ const showNoResult = visData.table
+ ? visData.table.rows.length === 0
+ : visData.tableGroups?.length === 0;
+
+ render(
+
+
+ ,
+ domNode
+ );
+ },
+});
diff --git a/src/plugins/vis_type_table/public/table_vis_response_handler.ts b/src/plugins/vis_type_table/public/table_vis_response_handler.ts
index 78b2306e744b..b1d41edfff8b 100644
--- a/src/plugins/vis_type_table/public/table_vis_response_handler.ts
+++ b/src/plugins/vis_type_table/public/table_vis_response_handler.ts
@@ -28,19 +28,17 @@
* under the License.
*/
-import { Required } from '@osd/utility-types';
-
import { getFormatService } from './services';
-import { Input } from './table_vis_fn';
+import { OpenSearchDashboardsDatatable } from '../../expressions/public';
+import { TableVisConfig } from './types';
-export interface TableContext {
- tables: Array;
- direction?: 'row' | 'column';
+export interface Table {
+ columns: OpenSearchDashboardsDatatable['columns'];
+ rows: OpenSearchDashboardsDatatable['rows'];
}
export interface TableGroup {
- $parent: TableContext;
- table: Input;
+ table: OpenSearchDashboardsDatatable;
tables: Table[];
title: string;
name: string;
@@ -49,61 +47,66 @@ export interface TableGroup {
row: number;
}
-export interface Table {
- $parent?: TableGroup;
- columns: Input['columns'];
- rows: Input['rows'];
+export interface TableContext {
+ table?: Table;
+ tableGroups: TableGroup[];
+ direction?: 'row' | 'column';
}
-export function tableVisResponseHandler(table: Input, dimensions: any): TableContext {
- const converted: TableContext = {
- tables: [],
- };
+export function tableVisResponseHandler(
+ input: OpenSearchDashboardsDatatable,
+ config: TableVisConfig
+): TableContext {
+ let table: Table | undefined;
+ const tableGroups: TableGroup[] = [];
+ let direction: TableContext['direction'];
- const split = dimensions.splitColumn || dimensions.splitRow;
+ const split = config.splitColumn || config.splitRow;
if (split) {
- converted.direction = dimensions.splitRow ? 'row' : 'column';
+ direction = config.splitRow ? 'row' : 'column';
const splitColumnIndex = split[0].accessor;
const splitColumnFormatter = getFormatService().deserialize(split[0].format);
- const splitColumn = table.columns[splitColumnIndex];
- const splitMap = {};
+ const splitColumn = input.columns[splitColumnIndex];
+ const splitMap: { [key: string]: number } = {};
let splitIndex = 0;
- table.rows.forEach((row, rowIndex) => {
+ input.rows.forEach((row, rowIndex) => {
const splitValue: any = row[splitColumn.id];
if (!splitMap.hasOwnProperty(splitValue as any)) {
(splitMap as any)[splitValue] = splitIndex++;
- const tableGroup: Required = {
- $parent: converted,
+ const tableGroup: TableGroup = {
title: `${splitColumnFormatter.convert(splitValue)}: ${splitColumn.name}`,
name: splitColumn.name,
key: splitValue,
column: splitColumnIndex,
row: rowIndex,
- table,
+ table: input,
tables: [],
};
tableGroup.tables.push({
- $parent: tableGroup,
- columns: table.columns,
+ columns: input.columns,
rows: [],
});
- converted.tables.push(tableGroup);
+ tableGroups.push(tableGroup);
}
const tableIndex = (splitMap as any)[splitValue];
- (converted.tables[tableIndex] as any).tables[0].rows.push(row);
+ (tableGroups[tableIndex] as any).tables[0].rows.push(row);
});
} else {
- converted.tables.push({
- columns: table.columns,
- rows: table.rows,
- });
+ table = {
+ columns: input.columns,
+ rows: input.rows,
+ };
}
- return converted;
+ return {
+ table,
+ tableGroups,
+ direction,
+ };
}
diff --git a/src/plugins/vis_type_table/public/table_vis_type.ts b/src/plugins/vis_type_table/public/table_vis_type.ts
index df1495a3d06b..0c27e7a8af0b 100644
--- a/src/plugins/vis_type_table/public/table_vis_type.ts
+++ b/src/plugins/vis_type_table/public/table_vis_type.ts
@@ -28,91 +28,78 @@
* under the License.
*/
-import { CoreSetup, PluginInitializerContext } from 'opensearch-dashboards/public';
import { i18n } from '@osd/i18n';
import { AggGroupNames } from '../../data/public';
import { Schemas } from '../../vis_default_editor/public';
import { BaseVisTypeOptions } from '../../visualizations/public';
import { tableVisResponseHandler } from './table_vis_response_handler';
-// @ts-ignore
-import tableVisTemplate from './table_vis.html';
+import { toExpressionAst } from './to_ast';
+import { VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
import { TableOptions } from './components/table_vis_options_lazy';
-import { getTableVisualizationControllerClass } from './vis_controller';
-import { VIS_EVENT_TO_TRIGGER } from '../../visualizations/public';
-export function getTableVisTypeDefinition(
- core: CoreSetup,
- context: PluginInitializerContext
-): BaseVisTypeOptions {
- return {
- name: 'table',
- title: i18n.translate('visTypeTable.tableVisTitle', {
- defaultMessage: 'Data Table',
- }),
- icon: 'visTable',
- description: i18n.translate('visTypeTable.tableVisDescription', {
- defaultMessage: 'Display values in a table',
- }),
- visualization: getTableVisualizationControllerClass(core, context),
- getSupportedTriggers: () => {
- return [VIS_EVENT_TO_TRIGGER.filter];
+export const getTableVisTypeDefinition = (): BaseVisTypeOptions => ({
+ name: 'table',
+ title: i18n.translate('visTypeTable.tableVisTitle', {
+ defaultMessage: 'Data Table',
+ }),
+ icon: 'visTable',
+ description: i18n.translate('visTypeTable.tableVisDescription', {
+ defaultMessage: 'Display values in a table',
+ }),
+ toExpressionAst,
+ visConfig: {
+ defaults: {
+ perPage: 10,
+ showPartialRows: false,
+ showMetricsAtAllLevels: false,
+ showTotal: false,
+ totalFunc: 'sum',
+ percentageCol: '',
},
- visConfig: {
- defaults: {
- perPage: 10,
- showPartialRows: false,
- showMetricsAtAllLevels: false,
- sort: {
- columnIndex: null,
- direction: null,
- },
- showTotal: false,
- totalFunc: 'sum',
- percentageCol: '',
- },
- template: tableVisTemplate,
- },
- editorConfig: {
- optionsTemplate: TableOptions,
- schemas: new Schemas([
- {
- group: AggGroupNames.Metrics,
- name: 'metric',
- title: i18n.translate('visTypeTable.tableVisEditorConfig.schemas.metricTitle', {
- defaultMessage: 'Metric',
- }),
- aggFilter: ['!geo_centroid', '!geo_bounds'],
- aggSettings: {
- top_hits: {
- allowStrings: true,
- },
+ },
+ editorConfig: {
+ optionsTemplate: TableOptions,
+ schemas: new Schemas([
+ {
+ group: AggGroupNames.Metrics,
+ name: 'metric',
+ title: i18n.translate('visTypeTable.tableVisEditorConfig.schemas.metricTitle', {
+ defaultMessage: 'Metric',
+ }),
+ aggFilter: ['!geo_centroid', '!geo_bounds'],
+ aggSettings: {
+ top_hits: {
+ allowStrings: true,
},
- min: 1,
- defaults: [{ type: 'count', schema: 'metric' }],
- },
- {
- group: AggGroupNames.Buckets,
- name: 'bucket',
- title: i18n.translate('visTypeTable.tableVisEditorConfig.schemas.bucketTitle', {
- defaultMessage: 'Split rows',
- }),
- aggFilter: ['!filter'],
- },
- {
- group: AggGroupNames.Buckets,
- name: 'split',
- title: i18n.translate('visTypeTable.tableVisEditorConfig.schemas.splitTitle', {
- defaultMessage: 'Split table',
- }),
- min: 0,
- max: 1,
- aggFilter: ['!filter'],
},
- ]),
- },
- responseHandler: tableVisResponseHandler,
- hierarchicalData: (vis) => {
- return Boolean(vis.params.showPartialRows || vis.params.showMetricsAtAllLevels);
- },
- };
-}
+ min: 1,
+ defaults: [{ type: 'count', schema: 'metric' }],
+ },
+ {
+ group: AggGroupNames.Buckets,
+ name: 'bucket',
+ title: i18n.translate('visTypeTable.tableVisEditorConfig.schemas.bucketTitle', {
+ defaultMessage: 'Split rows',
+ }),
+ aggFilter: ['!filter'],
+ },
+ {
+ group: AggGroupNames.Buckets,
+ name: 'split',
+ title: i18n.translate('visTypeTable.tableVisEditorConfig.schemas.splitTitle', {
+ defaultMessage: 'Split table',
+ }),
+ min: 0,
+ max: 1,
+ aggFilter: ['!filter'],
+ },
+ ]),
+ },
+ responseHandler: tableVisResponseHandler,
+ getSupportedTriggers: () => {
+ return [VIS_EVENT_TO_TRIGGER.filter];
+ },
+ hierarchicalData: (vis) => {
+ return Boolean(vis.params.showPartialRows || vis.params.showMetricsAtAllLevels);
+ },
+});
diff --git a/src/plugins/vis_type_table/public/to_ast.ts b/src/plugins/vis_type_table/public/to_ast.ts
new file mode 100644
index 000000000000..61752c971d00
--- /dev/null
+++ b/src/plugins/vis_type_table/public/to_ast.ts
@@ -0,0 +1,62 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { getVisSchemas, Vis } from '../../visualizations/public';
+import { buildExpression, buildExpressionFunction } from '../../expressions/public';
+import { TableVisExpressionFunctionDefinition } from './table_vis_fn';
+import { OpenSearchaggsExpressionFunctionDefinition } from '../../data/common/search/expressions';
+
+export const toExpressionAst = (vis: Vis, params: any) => {
+ const opensearchaggs = buildExpressionFunction(
+ 'opensearchaggs',
+ {
+ index: vis.data.indexPattern!.id!,
+ metricsAtAllLevels: vis.isHierarchical(),
+ partialRows: vis.params.showPartialRows || false,
+ aggConfigs: JSON.stringify(vis.data.aggs!.aggs),
+ includeFormatHints: false,
+ }
+ );
+
+ const schemas = getVisSchemas(vis, params);
+ // manul slice to remove duplicate metrics
+ const metrics =
+ schemas.bucket && vis.params.showPartialRows && !vis.params.showMetricsAtAllLevels
+ ? schemas.metric.slice(-1 * (schemas.metric.length / schemas.bucket.length))
+ : schemas.metric;
+
+ const tableData = {
+ title: vis.title,
+ metrics,
+ buckets: schemas.bucket || [],
+ splitRow: schemas.split_row,
+ splitColumn: schemas.split_column,
+ };
+
+ const tableConfig = {
+ perPage: vis.params.perPage,
+ percentageCol: vis.params.percentageCol,
+ showPartialRows: vis.params.showPartialRows,
+ showMetricsAtAllLevels: vis.params.showMetricsAtAllLevels,
+ showTotal: vis.params.showTotal,
+ totalFunc: vis.params.totalFunc,
+ };
+
+ const visConfig = {
+ ...tableConfig,
+ ...tableData,
+ };
+
+ const tableVis = buildExpressionFunction(
+ 'opensearch_dashboards_table',
+ {
+ visConfig: JSON.stringify(visConfig),
+ }
+ );
+
+ const ast = buildExpression([opensearchaggs, tableVis]);
+
+ return ast.toAst();
+};
diff --git a/src/plugins/vis_type_table/public/types.ts b/src/plugins/vis_type_table/public/types.ts
index c780ef3b5db9..6355044556ab 100644
--- a/src/plugins/vis_type_table/public/types.ts
+++ b/src/plugins/vis_type_table/public/types.ts
@@ -28,7 +28,8 @@
* under the License.
*/
-import { SchemaConfig } from '../../visualizations/public';
+import { SchemaConfig } from 'src/plugins/visualizations/public';
+import { IFieldFormat } from 'src/plugins/data/public';
export enum AggTypes {
SUM = 'sum',
@@ -38,22 +39,39 @@ export enum AggTypes {
COUNT = 'count',
}
-export interface Dimensions {
- buckets: SchemaConfig[];
+export interface TableVisConfig extends TableVisParams {
+ title: string;
metrics: SchemaConfig[];
+ buckets: SchemaConfig[];
+ splitRow?: SchemaConfig[];
+ splitColumn?: SchemaConfig[];
}
export interface TableVisParams {
- type: 'table';
perPage: number | '';
showPartialRows: boolean;
showMetricsAtAllLevels: boolean;
- sort: {
- columnIndex: number | null;
- direction: string | null;
- };
showTotal: boolean;
totalFunc: AggTypes;
percentageCol: string;
- dimensions: Dimensions;
+}
+
+export interface FormattedColumn {
+ id: string;
+ title: string;
+ formatter: IFieldFormat;
+ filterable: boolean;
+ formattedTotal?: string | number;
+ sumTotal?: number;
+ total?: number;
+}
+
+export interface ColumnWidth {
+ colIndex: number;
+ width: number;
+}
+
+export interface SortColumn {
+ colIndex: number;
+ direction: 'asc' | 'desc';
}
diff --git a/src/plugins/vis_type_table/public/utils/convert_to_csv_data.ts b/src/plugins/vis_type_table/public/utils/convert_to_csv_data.ts
new file mode 100644
index 000000000000..2c37df1aa3d5
--- /dev/null
+++ b/src/plugins/vis_type_table/public/utils/convert_to_csv_data.ts
@@ -0,0 +1,85 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ *
+ * Any modifications Copyright OpenSearch Contributors. See
+ * GitHub history for details.
+ */
+
+/*
+ * 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 { isObject } from 'lodash';
+// @ts-ignore
+import { saveAs } from '@elastic/filesaver';
+import { CoreStart } from 'opensearch-dashboards/public';
+import { CSV_SEPARATOR_SETTING, CSV_QUOTE_VALUES_SETTING } from '../../../share/public';
+import { OpenSearchDashboardsDatatable } from '../../../expressions/public';
+import { FormattedColumn } from '../types';
+
+const nonAlphaNumRE = /[^a-zA-Z0-9]/;
+const allDoubleQuoteRE = /"/g;
+
+interface CSVDataProps {
+ filename?: string;
+ rows: OpenSearchDashboardsDatatable['rows'];
+ columns: FormattedColumn[];
+ uiSettings: CoreStart['uiSettings'];
+}
+
+const toCsv = function (formatted: boolean, { rows, columns, uiSettings }: CSVDataProps) {
+ const separator = uiSettings.get(CSV_SEPARATOR_SETTING);
+ const quoteValues = uiSettings.get(CSV_QUOTE_VALUES_SETTING);
+
+ function escape(val: any) {
+ if (!formatted && isObject(val)) val = val.valueOf();
+ val = String(val);
+ if (quoteValues && nonAlphaNumRE.test(val)) {
+ val = '"' + val.replace(allDoubleQuoteRE, '""') + '"';
+ }
+ return val;
+ }
+
+ let csvRows: string[][] = [];
+ for (const row of rows) {
+ const rowArray = [];
+ for (const col of columns) {
+ const value = row[col.id];
+ const formattedValue =
+ formatted && col.formatter ? escape(col.formatter.convert(value)) : escape(value);
+ rowArray.push(formattedValue);
+ }
+ csvRows = [...csvRows, rowArray];
+ }
+
+ // add the columns to the rows
+ csvRows.unshift(columns.map((col) => escape(col.title)));
+
+ return csvRows.map((row) => row.join(separator) + '\r\n').join('');
+};
+
+export const exportAsCsv = function (formatted: boolean, csvData: CSVDataProps) {
+ const csv = new Blob([toCsv(formatted, csvData)], { type: 'text/csv;charset=utf-8' });
+ const type = formatted ? 'formatted' : 'raw';
+ if (csvData.filename) saveAs(csv, `${csvData.filename}-${type}.csv`);
+ else saveAs(csv, `unsaved-${type}.csv`);
+};
diff --git a/src/plugins/vis_type_table/public/utils/convert_to_formatted_data.ts b/src/plugins/vis_type_table/public/utils/convert_to_formatted_data.ts
new file mode 100644
index 000000000000..0b0c31eaec8e
--- /dev/null
+++ b/src/plugins/vis_type_table/public/utils/convert_to_formatted_data.ts
@@ -0,0 +1,179 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * The OpenSearch Contributors require contributions made to
+ * this file be licensed under the Apache-2.0 license or a
+ * compatible open source license.
+ *
+ * Any modifications Copyright OpenSearch Contributors. See
+ * GitHub history for details.
+ */
+
+/*
+ * 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 { i18n } from '@osd/i18n';
+import { chain } from 'lodash';
+import { OpenSearchDashboardsDatatableRow } from 'src/plugins/expressions';
+import { Table } from '../table_vis_response_handler';
+import { AggTypes, TableVisConfig } from '../types';
+import { getFormatService } from '../services';
+import { FormattedColumn } from '../types';
+
+function insert(arr: FormattedColumn[], index: number, col: FormattedColumn) {
+ const newArray = [...arr];
+ newArray.splice(index + 1, 0, col);
+ return newArray;
+}
+
+/**
+ * @param columns - the formatted columns that will be displayed
+ * @param title - the title of the column to add to
+ * @param rows - the row data for the columns
+ * @param insertAtIndex - the index to insert the percentage column at
+ * @returns cols and rows for the table to render now included percentage column(s)
+ */
+function addPercentageCol(
+ columns: FormattedColumn[],
+ title: string,
+ rows: Table['rows'],
+ insertAtIndex: number
+) {
+ const { id, sumTotal } = columns[insertAtIndex];
+ const newId = `${id}-percents`;
+ const formatter = getFormatService().deserialize({ id: 'percent' });
+ const i18nTitle = i18n.translate('visTypeTable.params.percentageTableColumnName', {
+ defaultMessage: '{title} percentages',
+ values: { title },
+ });
+ const newCols = insert(columns, insertAtIndex, {
+ title: i18nTitle,
+ id: newId,
+ formatter,
+ filterable: false,
+ });
+ const newRows = rows.map((row) => ({
+ [newId]: (row[id] as number) / (sumTotal as number),
+ ...row,
+ }));
+
+ return { cols: newCols, rows: newRows };
+}
+
+export interface FormattedDataProps {
+ formattedRows: OpenSearchDashboardsDatatableRow[];
+ formattedColumns: FormattedColumn[];
+}
+
+export const convertToFormattedData = (
+ table: Table,
+ visConfig: TableVisConfig
+): FormattedDataProps => {
+ const { buckets, metrics } = visConfig;
+ let formattedRows: OpenSearchDashboardsDatatableRow[] = table.rows;
+ let formattedColumns: FormattedColumn[] = table.columns
+ .map(function (col, i) {
+ const isBucket = buckets.find((bucket) => bucket.accessor === i);
+ const dimension = isBucket || metrics.find((metric) => metric.accessor === i);
+
+ if (!dimension) return undefined;
+
+ const formatter = getFormatService().deserialize(dimension.format);
+
+ const formattedColumn: FormattedColumn = {
+ id: col.id,
+ title: col.name,
+ formatter,
+ filterable: !!isBucket,
+ };
+
+ const isDate = dimension?.format?.id === 'date' || dimension?.format?.params?.id === 'date';
+ const allowsNumericalAggregations = formatter?.allowsNumericalAggregations;
+
+ if (allowsNumericalAggregations || isDate || visConfig.totalFunc === AggTypes.COUNT) {
+ const sum = table.rows.reduce((prev, curr) => {
+ // some metrics return undefined for some of the values
+ // derivative is an example of this as it returns undefined in the first row
+ if (curr[col.id] === undefined) return prev;
+ return prev + (curr[col.id] as number);
+ }, 0);
+
+ formattedColumn.sumTotal = sum;
+ switch (visConfig.totalFunc) {
+ case AggTypes.SUM: {
+ if (!isDate) {
+ formattedColumn.formattedTotal = formatter?.convert(sum);
+ formattedColumn.total = formattedColumn.sumTotal;
+ }
+ break;
+ }
+ case AggTypes.AVG: {
+ if (!isDate) {
+ const total = sum / table.rows.length;
+ formattedColumn.formattedTotal = formatter?.convert(total);
+ formattedColumn.total = total;
+ }
+ break;
+ }
+ case AggTypes.MIN: {
+ const total = chain(table.rows).map(col.id).min().value() as number;
+ formattedColumn.formattedTotal = formatter?.convert(total);
+ formattedColumn.total = total;
+ break;
+ }
+ case AggTypes.MAX: {
+ const total = chain(table.rows).map(col.id).max().value() as number;
+ formattedColumn.formattedTotal = formatter?.convert(total);
+ formattedColumn.total = total;
+ break;
+ }
+ case 'count': {
+ const total = table.rows.length;
+ formattedColumn.formattedTotal = total;
+ formattedColumn.total = total;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ return formattedColumn;
+ })
+ .filter((column): column is FormattedColumn => !!column);
+
+ if (visConfig.percentageCol) {
+ const insertAtIndex = formattedColumns.findIndex(
+ (col) => col.title === visConfig.percentageCol
+ );
+
+ // column to show percentage for was removed
+ if (insertAtIndex < 0) return { formattedRows, formattedColumns };
+
+ const { cols, rows } = addPercentageCol(
+ formattedColumns,
+ visConfig.percentageCol,
+ table.rows,
+ insertAtIndex
+ );
+ formattedRows = rows;
+ formattedColumns = cols;
+ }
+ return { formattedRows, formattedColumns };
+};
diff --git a/src/plugins/vis_type_table/public/utils/index.ts b/src/plugins/vis_type_table/public/utils/index.ts
new file mode 100644
index 000000000000..eb9be554ae05
--- /dev/null
+++ b/src/plugins/vis_type_table/public/utils/index.ts
@@ -0,0 +1,7 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export * from './convert_to_formatted_data';
+export * from './use_pagination';
diff --git a/src/plugins/vis_type_table/public/utils/use_pagination.ts b/src/plugins/vis_type_table/public/utils/use_pagination.ts
new file mode 100644
index 000000000000..41bb31d34086
--- /dev/null
+++ b/src/plugins/vis_type_table/public/utils/use_pagination.ts
@@ -0,0 +1,39 @@
+/*
+ * Copyright OpenSearch Contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import { useCallback, useEffect, useMemo, useState } from 'react';
+import { TableVisConfig } from '../types';
+
+export const usePagination = (visConfig: TableVisConfig, nRow: number) => {
+ const [pagination, setPagination] = useState({
+ pageIndex: 0,
+ pageSize: visConfig.perPage || 0,
+ });
+ const onChangeItemsPerPage = useCallback(
+ (pageSize) => setPagination((p) => ({ ...p, pageSize, pageIndex: 0 })),
+ [setPagination]
+ );
+ const onChangePage = useCallback((pageIndex) => setPagination((p) => ({ ...p, pageIndex })), [
+ setPagination,
+ ]);
+
+ useEffect(() => {
+ const perPage = visConfig.perPage || 0;
+ const maxiPageIndex = Math.ceil(nRow / perPage) - 1;
+ setPagination((p) => ({
+ pageIndex: p.pageIndex > maxiPageIndex ? maxiPageIndex : p.pageIndex,
+ pageSize: perPage,
+ }));
+ }, [nRow, visConfig.perPage]);
+
+ return useMemo(
+ () => ({
+ ...pagination,
+ onChangeItemsPerPage,
+ onChangePage,
+ }),
+ [pagination, onChangeItemsPerPage, onChangePage]
+ );
+};
diff --git a/src/plugins/vis_type_table/public/vis_controller.ts b/src/plugins/vis_type_table/public/vis_controller.ts
deleted file mode 100644
index aa7ffb05110a..000000000000
--- a/src/plugins/vis_type_table/public/vis_controller.ts
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * SPDX-License-Identifier: Apache-2.0
- *
- * The OpenSearch Contributors require contributions made to
- * this file be licensed under the Apache-2.0 license or a
- * compatible open source license.
- *
- * Any modifications Copyright OpenSearch Contributors. See
- * GitHub history for details.
- */
-
-/*
- * 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 { CoreSetup, PluginInitializerContext } from 'opensearch-dashboards/public';
-import angular, { IModule, auto, IRootScopeService, IScope, ICompileService } from 'angular';
-import $ from 'jquery';
-
-import { VisParams, ExprVis } from '../../visualizations/public';
-import { getAngularModule } from './get_inner_angular';
-import { getOpenSearchDashboardsLegacy } from './services';
-import { initTableVisLegacyModule } from './table_vis_legacy_module';
-
-const innerAngularName = 'opensearch-dashboards/table_vis';
-
-export function getTableVisualizationControllerClass(
- core: CoreSetup,
- context: PluginInitializerContext
-) {
- return class TableVisualizationController {
- private tableVisModule: IModule | undefined;
- private injector: auto.IInjectorService | undefined;
- el: JQuery;
- vis: ExprVis;
- $rootScope: IRootScopeService | null = null;
- $scope: (IScope & { [key: string]: any }) | undefined;
- $compile: ICompileService | undefined;
-
- constructor(domeElement: Element, vis: ExprVis) {
- 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;
- }
-
- async initLocalAngular() {
- if (!this.tableVisModule) {
- const [coreStart] = await core.getStartServices();
- this.tableVisModule = getAngularModule(innerAngularName, coreStart, context);
- initTableVisLegacyModule(this.tableVisModule);
- }
- }
-
- async render(opensearchResponse: object, visParams: VisParams): Promise {
- getOpenSearchDashboardsLegacy().loadFontAwesome();
- await 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;
- }
-
- // How things get into this $scope?
- // To inject variables into this $scope there's the following pipeline of stuff to check:
- // - visualize_embeddable => that's what the editor creates to wrap this Angular component
- // - build_pipeline => it serialize all the params into an Angular template compiled on the fly
- // - table_vis_fn => unserialize the params and prepare them for the final React/Angular bridge
- // - visualization_renderer => creates the wrapper component for this controller and passes the params
- //
- // In case some prop is missing check into the top of the chain if they are available and check
- // the list above that it is passing through
- this.$scope.vis = this.vis;
- this.$scope.visState = { params: visParams, title: visParams.title };
- this.$scope.opensearchResponse = opensearchResponse;
-
- this.$scope.visParams = visParams;
- this.$scope.renderComplete = resolve;
- this.$scope.renderFailed = reject;
- this.$scope.resize = Date.now();
- 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/plugins/vis_type_table/server/index.ts b/src/plugins/vis_type_table/server/index.ts
index 5ec9b8b91c03..e0c27a37755c 100644
--- a/src/plugins/vis_type_table/server/index.ts
+++ b/src/plugins/vis_type_table/server/index.ts
@@ -34,9 +34,6 @@ import { configSchema, ConfigSchema } from '../config';
export const config: PluginConfigDescriptor = {
schema: configSchema,
- deprecations: ({ renameFromRoot }) => [
- renameFromRoot('table_vis.enabled', 'vis_type_table.enabled'),
- ],
};
export const plugin = () => ({
diff --git a/src/plugins/visualizations/public/legacy/__snapshots__/build_pipeline.test.ts.snap b/src/plugins/visualizations/public/legacy/__snapshots__/build_pipeline.test.ts.snap
index b3b4dc5e09b1..6a16b5caa15c 100644
--- a/src/plugins/visualizations/public/legacy/__snapshots__/build_pipeline.test.ts.snap
+++ b/src/plugins/visualizations/public/legacy/__snapshots__/build_pipeline.test.ts.snap
@@ -12,15 +12,15 @@ exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunct
exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles region_map function without buckets 1`] = `"regionmap visConfig='{\\"metric\\":{\\"accessor\\":0,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"}}' "`;
-exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles table function with showPartialRows=true and showMetricsAtAllLevels=false 1`] = `"opensearch_dashboards_table visConfig='{\\"showMetricsAtAllLevels\\":false,\\"showPartialRows\\":true,\\"dimensions\\":{\\"metrics\\":[{\\"accessor\\":4,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"},{\\"accessor\\":5,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"}],\\"buckets\\":[0,3]}}' "`;
+exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles table function with showPartialRows=true and showMetricsAtAllLevels=false 1`] = `"visTable visConfig='{\\"showMetricsAtAllLevels\\":false,\\"showPartialRows\\":true,\\"dimensions\\":{\\"metrics\\":[{\\"accessor\\":4,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"},{\\"accessor\\":5,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"}],\\"buckets\\":[0,3]}}' "`;
-exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles table function with showPartialRows=true and showMetricsAtAllLevels=true 1`] = `"opensearch_dashboards_table visConfig='{\\"showMetricsAtAllLevels\\":true,\\"showPartialRows\\":true,\\"dimensions\\":{\\"metrics\\":[{\\"accessor\\":1,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"},{\\"accessor\\":2,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"},{\\"accessor\\":4,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"},{\\"accessor\\":5,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"}],\\"buckets\\":[0,3]}}' "`;
+exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles table function with showPartialRows=true and showMetricsAtAllLevels=true 1`] = `"visTable visConfig='{\\"showMetricsAtAllLevels\\":true,\\"showPartialRows\\":true,\\"dimensions\\":{\\"metrics\\":[{\\"accessor\\":1,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"},{\\"accessor\\":2,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"},{\\"accessor\\":4,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"},{\\"accessor\\":5,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"}],\\"buckets\\":[0,3]}}' "`;
-exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles table function with splits 1`] = `"opensearch_dashboards_table visConfig='{\\"foo\\":\\"bar\\",\\"dimensions\\":{\\"metrics\\":[{\\"accessor\\":0,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"}],\\"buckets\\":[],\\"splitRow\\":[1,2]}}' "`;
+exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles table function with splits 1`] = `"visTable visConfig='{\\"foo\\":\\"bar\\",\\"dimensions\\":{\\"metrics\\":[{\\"accessor\\":0,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"}],\\"buckets\\":[],\\"splitRow\\":[1,2]}}' "`;
-exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles table function with splits and buckets 1`] = `"opensearch_dashboards_table visConfig='{\\"foo\\":\\"bar\\",\\"dimensions\\":{\\"metrics\\":[{\\"accessor\\":0,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"},{\\"accessor\\":1,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"}],\\"buckets\\":[3],\\"splitRow\\":[2,4]}}' "`;
+exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles table function with splits and buckets 1`] = `"visTable visConfig='{\\"foo\\":\\"bar\\",\\"dimensions\\":{\\"metrics\\":[{\\"accessor\\":0,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"},{\\"accessor\\":1,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"}],\\"buckets\\":[3],\\"splitRow\\":[2,4]}}' "`;
-exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles table function without splits or buckets 1`] = `"opensearch_dashboards_table visConfig='{\\"foo\\":\\"bar\\",\\"dimensions\\":{\\"metrics\\":[{\\"accessor\\":0,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"},{\\"accessor\\":1,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"}],\\"buckets\\":[]}}' "`;
+exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles table function without splits or buckets 1`] = `"visTable visConfig='{\\"foo\\":\\"bar\\",\\"dimensions\\":{\\"metrics\\":[{\\"accessor\\":0,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"},{\\"accessor\\":1,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"}],\\"buckets\\":[]}}' "`;
exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles tile_map function 1`] = `"tilemap visConfig='{\\"metric\\":{},\\"dimensions\\":{\\"metric\\":{\\"accessor\\":0,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"},\\"geohash\\":1,\\"geocentroid\\":3}}' "`;
diff --git a/src/plugins/visualizations/public/legacy/build_pipeline.test.ts b/src/plugins/visualizations/public/legacy/build_pipeline.test.ts
index 90721f66c4af..5f240f82602c 100644
--- a/src/plugins/visualizations/public/legacy/build_pipeline.test.ts
+++ b/src/plugins/visualizations/public/legacy/build_pipeline.test.ts
@@ -128,84 +128,6 @@ describe('visualize loader pipeline helpers: build pipeline', () => {
expect(actual).toMatchSnapshot();
});
- describe('handles table function', () => {
- it('without splits or buckets', () => {
- const params = { foo: 'bar' };
- const schemas = {
- ...schemasDef,
- metric: [
- { ...schemaConfig, accessor: 0 },
- { ...schemaConfig, accessor: 1 },
- ],
- };
- const actual = buildPipelineVisFunction.table(params, schemas, uiState);
- expect(actual).toMatchSnapshot();
- });
-
- it('with splits', () => {
- const params = { foo: 'bar' };
- const schemas = {
- ...schemasDef,
- split_row: [1, 2],
- };
- const actual = buildPipelineVisFunction.table(params, schemas, uiState);
- expect(actual).toMatchSnapshot();
- });
-
- it('with splits and buckets', () => {
- const params = { foo: 'bar' };
- const schemas = {
- ...schemasDef,
- metric: [
- { ...schemaConfig, accessor: 0 },
- { ...schemaConfig, accessor: 1 },
- ],
- split_row: [2, 4],
- bucket: [3],
- };
- const actual = buildPipelineVisFunction.table(params, schemas, uiState);
- expect(actual).toMatchSnapshot();
- });
-
- it('with showPartialRows=true and showMetricsAtAllLevels=true', () => {
- const params = {
- showMetricsAtAllLevels: true,
- showPartialRows: true,
- };
- const schemas = {
- ...schemasDef,
- metric: [
- { ...schemaConfig, accessor: 1 },
- { ...schemaConfig, accessor: 2 },
- { ...schemaConfig, accessor: 4 },
- { ...schemaConfig, accessor: 5 },
- ],
- bucket: [0, 3],
- };
- const actual = buildPipelineVisFunction.table(params, schemas, uiState);
- expect(actual).toMatchSnapshot();
- });
-
- it('with showPartialRows=true and showMetricsAtAllLevels=false', () => {
- const params = {
- showMetricsAtAllLevels: false,
- showPartialRows: true,
- };
- const schemas = {
- ...schemasDef,
- metric: [
- { ...schemaConfig, accessor: 1 },
- { ...schemaConfig, accessor: 2 },
- { ...schemaConfig, accessor: 4 },
- { ...schemaConfig, accessor: 5 },
- ],
- bucket: [0, 3],
- };
- const actual = buildPipelineVisFunction.table(params, schemas, uiState);
- expect(actual).toMatchSnapshot();
- });
- });
-
describe('handles region_map function', () => {
it('without buckets', () => {
const params = { metric: {} };
diff --git a/src/plugins/visualizations/public/legacy/build_pipeline.ts b/src/plugins/visualizations/public/legacy/build_pipeline.ts
index 7a28ae7ac394..1cbb3bc38879 100644
--- a/src/plugins/visualizations/public/legacy/build_pipeline.ts
+++ b/src/plugins/visualizations/public/legacy/build_pipeline.ts
@@ -278,13 +278,6 @@ export const buildPipelineVisFunction: BuildPipelineVisFunction = {
const paramsArray = [paramsJson, uiStateJson].filter((param) => Boolean(param));
return `tsvb ${paramsArray.join(' ')}`;
},
- table: (params, schemas) => {
- const visConfig = {
- ...params,
- ...buildVisConfig.table(schemas, params),
- };
- return `opensearch_dashboards_table ${prepareJson('visConfig', visConfig)}`;
- },
region_map: (params, schemas) => {
const visConfig = {
...params,
@@ -309,26 +302,6 @@ export const buildPipelineVisFunction: BuildPipelineVisFunction = {
};
const buildVisConfig: BuildVisConfigFunction = {
- table: (schemas, visParams = {}) => {
- const visConfig = {} as any;
- const metrics = schemas.metric;
- const buckets = schemas.bucket || [];
- visConfig.dimensions = {
- metrics,
- buckets,
- splitRow: schemas.split_row,
- splitColumn: schemas.split_column,
- };
-
- if (visParams.showMetricsAtAllLevels === false && visParams.showPartialRows === true) {
- // Handle case where user wants to see partial rows but not metrics at all levels.
- // This requires calculating how many metrics will come back in the tabified response,
- // and removing all metrics from the dimensions except the last set.
- const metricsPerBucket = metrics.length / buckets.length;
- visConfig.dimensions.metrics.splice(0, metricsPerBucket * buckets.length - metricsPerBucket);
- }
- return visConfig;
- },
region_map: (schemas) => {
const visConfig = {} as any;
visConfig.metric = schemas.metric[0];