Skip to content

Commit 8654086

Browse files
ananzhAjay Gupta
authored andcommitted
[Vis Builder] Add an experimental table visualization in vis builder (opensearch-project#2705)
* [Vis Builder] Add an experimental table visualization in vis builder In this PR, we hook up an experimental table vis in vis builder. This table vis is a refactor of previous table. It is written in React and DataGrid component. In this PR, we did two main things: * add an experimental table visualization * enable it in vis builder Issue Resolved (hook up table in vis builder): opensearch-project#2704 The experimental table vis has all the features from current table, including * restore table vis in react using a Datagrid component * datagrid component does not support splitted grids. For future transfer to OUI Datagrid, we create a tableGroup in visData for splitted grids. * restore basic pagenation, sort and format. * implement datagrid columns * display column title correctly * deangular and re-use formatted column * convert formatted column to data grid column * restore filter in and filter out value functions * format table cell to show Date and percent * restore showTotal feature: it allows table vis to show total, avg, min, max and count statics on count * restore export csv feature to table vis * split table in rows and columns Beside of restoring original features, there are some changes: * [IMPROVE] remove repeated column from split tables Currently, when we split table by columns, the split column is shown both in the table title and as a separate column. This is not needed. In this PR, we remove the repeated column in split tables in col. * [NEW FEATURE] adjustable table column width In the new table visualization, customer can adjust the column width as needed. Issue Resolved: opensearch-project#2212 opensearch-project#2213 opensearch-project#2305 opensearch-project#2379 opensearch-project#2579 Since this is a hookup PR, we remove un-used table vis types and options because they could be defined in vis builder. We also create follow up issues for some un-resolved PR comments. Signed-off-by: Anan Zhuang <[email protected]> * remove unused scss tyle Signed-off-by: Anan Zhuang <[email protected]> * remove total func and percentage col total func and percentage col are two features that we might need to remove or re-invent for future table vis. For hookup purpose, it doesn't make sense to include some features that we would like to remove. this PR removes total func and percentage col in both table vis and vis builder Signed-off-by: Anan Zhuang <[email protected]> * comment out cellActions currently filter in/out cell doesn't function in vis builder. we will coumment out cell actions for now. Signed-off-by: Anan Zhuang <[email protected]> Signed-off-by: Anan Zhuang <[email protected]> Signed-off-by: Ajay Gupta <[email protected]>
1 parent b4c0478 commit 8654086

28 files changed

+1380
-6
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
4040
- [Multi DataSource] Update MD data source documentation link ([#2693](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2693))
4141
- [Save Object Aggregation View] Add extension point in saved object management to register namespaces and show filter ([#2656](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2656))
4242
- [Save Object Aggregation View] Fix for export all after scroll count response changed in PR#2656 ([#2696](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2696))
43+
- [Vis Builder] Add an experimental table visualization in vis builder ([#2705](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/2705))
4344

4445
### 🐛 Bug Fixes
4546

src/plugins/vis_builder/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,6 @@ Outline:
3131

3232
**Notes:**
3333

34-
- Currently only the metric viz is defined, so schema properties that other vis types might need may be missing and require further setup.
34+
- Currently only the metric and table viz are defined, so schema properties that other vis types might need may be missing and require further setup.
3535
- `to_expression` has not yet been abstracted into a common utility for different visualizations. Adding more visualization types should make it easier to identify which parts of expression creation are common, and which are visualization-specific.
3636

src/plugins/vis_builder/public/application/utils/use/use_saved_vis_builder_vis.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import {
1313
} from '../../../../../opensearch_dashboards_utils/public';
1414
import { EDIT_PATH, PLUGIN_ID } from '../../../../common';
1515
import { VisBuilderServices } from '../../../types';
16-
import { MetricOptionsDefaults } from '../../../visualizations/metric/metric_viz_type';
1716
import { getCreateBreadcrumbs, getEditBreadcrumbs } from '../breadcrumbs';
1817
import { getSavedVisBuilderVis } from '../get_saved_vis_builder_vis';
1918
import {
@@ -81,7 +80,7 @@ export const useSavedVisBuilderVis = (visualizationIdFromUrl: string | undefined
8180
}
8281
}
8382

84-
dispatch(setStyleState<MetricOptionsDefaults>(styleState));
83+
dispatch(setStyleState(styleState));
8584
dispatch(setVisualizationState(visualizationState));
8685
}
8786

src/plugins/vis_builder/public/visualizations/common/expression_helpers.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,12 @@ import { ExpressionFunctionOpenSearchDashboards } from '../../../../expressions'
99
import { buildExpressionFunction } from '../../../../expressions/public';
1010
import { VisualizationState } from '../../application/utils/state_management';
1111
import { getSearchService, getIndexPatterns } from '../../plugin_services';
12+
import { StyleState } from '../../application/utils/state_management';
1213

13-
export const getAggExpressionFunctions = async (visualization: VisualizationState) => {
14+
export const getAggExpressionFunctions = async (
15+
visualization: VisualizationState,
16+
style?: StyleState
17+
) => {
1418
const { activeVisualization, indexPattern: indexId = '' } = visualization;
1519
const { aggConfigParams } = activeVisualization || {};
1620

@@ -32,8 +36,8 @@ export const getAggExpressionFunctions = async (visualization: VisualizationStat
3236
'opensearchaggs',
3337
{
3438
index: indexId,
35-
metricsAtAllLevels: false,
36-
partialRows: false,
39+
metricsAtAllLevels: style?.showMetricsAtAllLevels || false,
40+
partialRows: style?.showPartialRows || false,
3741
aggConfigs: JSON.stringify(aggConfigs.aggs),
3842
includeFormatHints: false,
3943
}

src/plugins/vis_builder/public/visualizations/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import type { TypeServiceSetup } from '../services/type_service';
77
import { createMetricConfig } from './metric';
8+
import { createTableConfig } from './table';
89
import { createHistogramConfig, createLineConfig, createAreaConfig } from './vislib';
910

1011
export function registerDefaultTypes(typeServiceSetup: TypeServiceSetup) {
@@ -13,6 +14,7 @@ export function registerDefaultTypes(typeServiceSetup: TypeServiceSetup) {
1314
createLineConfig,
1415
createAreaConfig,
1516
createMetricConfig,
17+
createTableConfig,
1618
];
1719

1820
visualizationTypes.forEach((createTypeConfig) => {
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import { get } from 'lodash';
7+
import React, { useCallback, useEffect, useMemo } from 'react';
8+
import { i18n } from '@osd/i18n';
9+
import { FormattedMessage } from '@osd/i18n/react';
10+
import produce from 'immer';
11+
import { Draft } from 'immer';
12+
import { EuiIconTip } from '@elastic/eui';
13+
import { search } from '../../../../../data/public';
14+
import { NumberInputOption, SwitchOption } from '../../../../../charts/public';
15+
import {
16+
useTypedDispatch,
17+
useTypedSelector,
18+
setStyleState,
19+
} from '../../../application/utils/state_management';
20+
import { TableOptionsDefaults } from '../table_viz_type';
21+
import { Option } from '../../../application/app';
22+
23+
function TableVizOptions() {
24+
const styleState = useTypedSelector((state) => state.style) as TableOptionsDefaults;
25+
const dispatch = useTypedDispatch();
26+
27+
const setOption = useCallback(
28+
(callback: (draft: Draft<typeof styleState>) => void) => {
29+
const newState = produce(styleState, callback);
30+
dispatch(setStyleState<TableOptionsDefaults>(newState));
31+
},
32+
[dispatch, styleState]
33+
);
34+
35+
const isPerPageValid = styleState.perPage === '' || styleState.perPage > 0;
36+
37+
return (
38+
<>
39+
<Option
40+
title={i18n.translate('visTypeTableNewNew.params.settingsTitle', {
41+
defaultMessage: 'Settings',
42+
})}
43+
initialIsOpen
44+
>
45+
<NumberInputOption
46+
label={
47+
<>
48+
{i18n.translate('visTypeTableNewNew.params.perPageLabel', {
49+
defaultMessage: 'Max rows per page',
50+
})}
51+
<EuiIconTip
52+
content={
53+
<FormattedMessage
54+
id="visTypeTableNewNews.field.emptyTooltip"
55+
defaultMessage="Leaving this field empty means it will use number of buckets from the response."
56+
/>
57+
}
58+
position="right"
59+
/>
60+
</>
61+
}
62+
isInvalid={!isPerPageValid}
63+
min={1}
64+
paramName="perPage"
65+
value={styleState.perPage}
66+
setValue={(_, value) =>
67+
setOption((draft) => {
68+
draft.perPage = value;
69+
})
70+
}
71+
/>
72+
73+
<SwitchOption
74+
label={i18n.translate('visTypeTableNewNew.params.showMetricsLabel', {
75+
defaultMessage: 'Show metrics for every bucket/level',
76+
})}
77+
paramName="showMetricsAtAllLevels"
78+
value={styleState.showMetricsAtAllLevels}
79+
setValue={(_, value) =>
80+
setOption((draft) => {
81+
draft.showMetricsAtAllLevels = value;
82+
})
83+
}
84+
data-test-subj="showMetricsAtAllLevels"
85+
/>
86+
87+
<SwitchOption
88+
label={i18n.translate('visTypeTableNewNew.params.showPartialRowsLabel', {
89+
defaultMessage: 'Show partial rows',
90+
})}
91+
tooltip={i18n.translate('visTypeTableNewNew.params.showPartialRowsTip', {
92+
defaultMessage:
93+
'Show rows that have partial data. This will still calculate metrics for every bucket/level, even if they are not displayed.',
94+
})}
95+
paramName="showPartialRows"
96+
value={styleState.showPartialRows}
97+
setValue={(_, value) =>
98+
setOption((draft) => {
99+
draft.showPartialRows = value;
100+
})
101+
}
102+
data-test-subj="showPartialRows"
103+
/>
104+
</Option>
105+
</>
106+
);
107+
}
108+
109+
export { TableVizOptions };
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
export { createTableConfig } from './table_viz_type';
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import { i18n } from '@osd/i18n';
7+
import { Schemas } from '../../../../vis_default_editor/public';
8+
import { AggGroupNames } from '../../../../data/public';
9+
import { TableVizOptions } from './components/table_viz_options';
10+
import { VisualizationTypeOptions } from '../../services/type_service';
11+
import { toExpression } from './to_expression';
12+
13+
export interface TableOptionsDefaults {
14+
perPage: number | '';
15+
showPartialRows: boolean;
16+
showMetricsAtAllLevels: boolean;
17+
}
18+
19+
export const createTableConfig = (): VisualizationTypeOptions<TableOptionsDefaults> => ({
20+
name: 'table',
21+
title: 'Table',
22+
icon: 'visTable',
23+
description: 'Display table visualizations',
24+
toExpression,
25+
ui: {
26+
containerConfig: {
27+
data: {
28+
schemas: new Schemas([
29+
{
30+
group: AggGroupNames.Metrics,
31+
name: 'metric',
32+
title: i18n.translate('visTypeTableNewNew.tableVisEditorConfig.schemas.metricTitle', {
33+
defaultMessage: 'Metric',
34+
}),
35+
min: 1,
36+
aggFilter: ['!geo_centroid', '!geo_bounds'],
37+
aggSettings: {
38+
top_hits: {
39+
allowStrings: true,
40+
},
41+
},
42+
defaults: {
43+
aggTypes: ['avg', 'cardinality'],
44+
},
45+
},
46+
{
47+
group: AggGroupNames.Buckets,
48+
name: 'bucket',
49+
title: i18n.translate('visTypeTableNewNew.tableVisEditorConfig.schemas.bucketTitle', {
50+
defaultMessage: 'Split rows',
51+
}),
52+
aggFilter: ['!filter'],
53+
defaults: {
54+
aggTypes: ['terms'],
55+
},
56+
},
57+
{
58+
group: AggGroupNames.Buckets,
59+
name: 'split_row',
60+
title: i18n.translate('visTypeTableNewNew.tableVisEditorConfig.schemas.splitTitle', {
61+
defaultMessage: 'Split table in rows',
62+
}),
63+
min: 0,
64+
max: 1,
65+
aggFilter: ['!filter'],
66+
defaults: {
67+
aggTypes: ['terms'],
68+
},
69+
},
70+
{
71+
group: AggGroupNames.Buckets,
72+
name: 'split_column',
73+
title: i18n.translate('visTypeTableNewNew.tableVisEditorConfig.schemas.splitTitle', {
74+
defaultMessage: 'Split table in columns',
75+
}),
76+
min: 0,
77+
max: 1,
78+
aggFilter: ['!filter'],
79+
defaults: {
80+
aggTypes: ['terms'],
81+
},
82+
},
83+
]),
84+
},
85+
style: {
86+
defaults: {
87+
perPage: 10,
88+
showPartialRows: false,
89+
showMetricsAtAllLevels: false,
90+
},
91+
render: TableVizOptions,
92+
},
93+
},
94+
},
95+
});

0 commit comments

Comments
 (0)