Skip to content

Commit 77af7f9

Browse files
[D&D] Adds Bar line and Area charts to Wizard (#2266)
* Working histogram Signed-off-by: Ashwin Pc <ashwinpc@amazon.com> * Adds histogram options Signed-off-by: Ashwin Pc <ashwinpc@amazon.com> * Adds line chart Signed-off-by: Ashwin Pc <ashwinpc@amazon.com> * Adds area chart Signed-off-by: Ashwin Pc <ashwinpc@amazon.com> * updates nav sizes Signed-off-by: Ashwin Pc <ashwinpc@amazon.com> * adds resizeable container to right nav Signed-off-by: Ashwin Pc <ashwinpc@amazon.com> * Misc fixes Signed-off-by: Ashwin Pc <ashwinpc@amazon.com> * Adds chart switcher test Signed-off-by: Ashwin Pc <ashwinpc@amazon.com> * Github comment feedback Co-authored-by: Josh Romero <rmerqg@amazon.com> Signed-off-by: Ashwin Pc <ashwinpc@amazon.com> * Updates copy Signed-off-by: Ashwin Pc <ashwinpc@amazon.com> Signed-off-by: Ashwin Pc <ashwinpc@amazon.com> Co-authored-by: Josh Romero <rmerqg@amazon.com>
1 parent 7f71c87 commit 77af7f9

35 files changed

+811
-80
lines changed

src/plugins/vis_type_vislib/public/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,6 @@ export function plugin(initializerContext: PluginInitializerContext) {
3535
return new Plugin(initializerContext);
3636
}
3737

38+
export { getConfigCollections } from './utils/collections';
39+
3840
export * from './types';

src/plugins/vis_type_vislib/public/types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,5 @@ export interface BasicVislibParams extends CommonVislibParams {
106106
times: TimeMarker[];
107107
type: string;
108108
}
109+
110+
export { Positions };

src/plugins/visualizations/public/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export { Vis } from './vis';
4343
export { TypesService } from './vis_types/types_service';
4444
export { VISUALIZE_EMBEDDABLE_TYPE, VIS_EVENT_TO_TRIGGER } from './embeddable';
4545
export { VisualizationContainer, VisualizationNoResults } from './components';
46-
export { getSchemas as getVisSchemas } from './legacy/build_pipeline';
46+
export { getSchemas as getVisSchemas, buildVislibDimensions } from './legacy/build_pipeline';
4747

4848
/** @public types */
4949
export { VisualizationsSetup, VisualizationsStart };

src/plugins/wizard/opensearch_dashboards.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
"dashboard",
1717
"visualizations",
1818
"opensearchUiShared",
19-
"visDefaultEditor"
19+
"visDefaultEditor",
20+
"visTypeVislib"
2021
],
2122
"optionalPlugins": []
2223
}

src/plugins/wizard/public/application/_variables.scss

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66
@import "@elastic/eui/src/global_styling/variables/form";
77

88
$osdHeaderOffset: $euiHeaderHeightCompensation;
9-
$wizSideNavWidth: 470px;
9+
$wizLeftNavWidth: 462px;

src/plugins/wizard/public/application/app.scss

+11-2
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,18 @@
88
padding: 0;
99
display: grid;
1010
grid-template:
11-
"topNav topNav topNav" min-content
12-
"leftNav workspace rightNav" 1fr / #{$wizSideNavWidth} 1fr #{$wizSideNavWidth};
11+
"topNav topNav" min-content
12+
"leftNav workspaceNav" 1fr / #{$wizLeftNavWidth} 1fr;
1313
height: calc(100vh - #{$osdHeaderOffset});
14+
15+
&__resizeContainer {
16+
min-height: 0;
17+
background-color: $euiColorEmptyShade;
18+
}
19+
20+
&__resizeButton {
21+
transform: translateX(-$euiSizeM / 2);
22+
}
1423
}
1524

1625
.headerIsExpanded .wizLayout {

src/plugins/wizard/public/application/app.tsx

+32-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import React from 'react';
77
import { I18nProvider } from '@osd/i18n/react';
8-
import { EuiPage } from '@elastic/eui';
8+
import { EuiPage, EuiResizableContainer } from '@elastic/eui';
99
import { DragDropProvider } from './utils/drag_drop/drag_drop_context';
1010
import { LeftNav } from './components/left_nav';
1111
import { TopNav } from './components/top_nav';
@@ -21,8 +21,37 @@ export const WizardApp = () => {
2121
<EuiPage className="wizLayout">
2222
<TopNav />
2323
<LeftNav />
24-
<Workspace />
25-
<RightNav />
24+
<EuiResizableContainer className="wizLayout__resizeContainer">
25+
{(EuiResizablePanel, EuiResizableButton) => (
26+
<>
27+
<EuiResizablePanel
28+
className="wizLayout__workspaceResize"
29+
paddingSize="none"
30+
initialSize={80}
31+
minSize="300px"
32+
mode="main"
33+
>
34+
<Workspace />
35+
</EuiResizablePanel>
36+
<EuiResizableButton className="wizLayout__resizeButton" />
37+
<EuiResizablePanel
38+
className="wizLayout__rightNavResize"
39+
paddingSize="none"
40+
initialSize={20}
41+
minSize="250px"
42+
mode={[
43+
'collapsible',
44+
{
45+
position: 'top',
46+
},
47+
]}
48+
id="wizRightResize"
49+
>
50+
<RightNav />
51+
</EuiResizablePanel>
52+
</>
53+
)}
54+
</EuiResizableContainer>
2655
</EuiPage>
2756
</DragDropProvider>
2857
</I18nProvider>

src/plugins/wizard/public/application/components/data_tab/field_selector.scss

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
overflow-y: auto;
1616
margin-right: -$euiSizeS;
1717
padding-right: $euiSizeS;
18+
margin-left: -$euiSizeS;
19+
padding-left: $euiSizeS;
1820
margin-top: $euiSizeS;
1921
}
2022

src/plugins/wizard/public/application/components/experimental_info.tsx

+15-17
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,35 @@
66
import React, { memo } from 'react';
77
import { EuiCallOut, EuiLink } from '@elastic/eui';
88
import { FormattedMessage } from '@osd/i18n/react';
9+
import { i18n } from '@osd/i18n';
910

1011
export const InfoComponent = () => {
11-
const title = (
12-
<>
12+
return (
13+
<EuiCallOut
14+
className="hide-for-sharing"
15+
data-test-subj="experimentalVisInfo"
16+
size="s"
17+
title={i18n.translate('wizard.experimentalInfoTitle', {
18+
defaultMessage: 'This editor is experimental and should not be used in production',
19+
})}
20+
iconType="beaker"
21+
>
1322
<FormattedMessage
1423
id="wizard.experimentalInfoText"
15-
defaultMessage="This editor is experimental, do not use in production.
16-
For feedback, please create an issue in {githubLink}."
24+
defaultMessage="We want to hear from you about how we can improve your experience. Leave feedback in {githubLink}."
1725
values={{
1826
githubLink: (
1927
<EuiLink
2028
external
21-
href="https://github.com/opensearch-project/OpenSearch-Dashboards/issues/new/choose"
29+
href="https://github.com/opensearch-project/OpenSearch-Dashboards/issues/2280"
2230
target="_blank"
2331
>
24-
GitHub
32+
the GitHub issue
2533
</EuiLink>
2634
),
2735
}}
2836
/>
29-
</>
30-
);
31-
32-
return (
33-
<EuiCallOut
34-
className="hide-for-sharing"
35-
data-test-subj="experimentalVisInfo"
36-
size="s"
37-
title={title}
38-
iconType="beaker"
39-
/>
37+
</EuiCallOut>
4038
);
4139
};
4240

src/plugins/wizard/public/application/components/right_nav.tsx

+47-8
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,24 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
import React from 'react';
7-
import { EuiSuperSelect, EuiSuperSelectOption, EuiIcon, IconType } from '@elastic/eui';
6+
import React, { useState } from 'react';
7+
import {
8+
EuiSuperSelect,
9+
EuiSuperSelectOption,
10+
EuiIcon,
11+
IconType,
12+
EuiConfirmModal,
13+
} from '@elastic/eui';
14+
import { i18n } from '@osd/i18n';
15+
import { FormattedMessage } from '@osd/i18n/react';
816
import { useVisualizationType } from '../utils/use';
917
import './side_nav.scss';
1018
import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public';
1119
import { WizardServices } from '../../types';
1220
import { setActiveVisualization, useTypedDispatch } from '../utils/state_management';
1321

1422
export const RightNav = () => {
23+
const [newVisType, setNewVisType] = useState<string>();
1524
const {
1625
services: { types },
1726
} = useOpenSearchDashboards<WizardServices>();
@@ -23,6 +32,7 @@ export const RightNav = () => {
2332
value: name,
2433
inputDisplay: <OptionItem icon={icon} title={title} />,
2534
dropdownDisplay: <OptionItem icon={icon} title={title} />,
35+
'data-test-subj': `visType-${name}`,
2636
}));
2737

2838
return (
@@ -32,19 +42,48 @@ export const RightNav = () => {
3242
options={options}
3343
valueOfSelected={activeVisName}
3444
onChange={(name) => {
35-
dispatch(
36-
setActiveVisualization({
37-
name,
38-
style: types.get(name)?.ui.containerConfig.style.defaults,
39-
})
40-
);
45+
setNewVisType(name);
4146
}}
4247
fullWidth
48+
data-test-subj="chartPicker"
4349
/>
4450
</div>
4551
<div className="wizSidenav__style">
4652
<StyleSection />
4753
</div>
54+
{newVisType && (
55+
<EuiConfirmModal
56+
title={i18n.translate('wizard.rightNav.changeVisType.modalTitle', {
57+
defaultMessage: 'Change visualization type',
58+
})}
59+
confirmButtonText={i18n.translate('wizard.rightNav.changeVisType.confirmText', {
60+
defaultMessage: 'Change type',
61+
})}
62+
cancelButtonText={i18n.translate('wizard.rightNav.changeVisType.cancelText', {
63+
defaultMessage: 'Cancel',
64+
})}
65+
onCancel={() => setNewVisType(undefined)}
66+
onConfirm={() => {
67+
dispatch(
68+
setActiveVisualization({
69+
name: newVisType,
70+
style: types.get(newVisType)?.ui.containerConfig.style.defaults,
71+
})
72+
);
73+
74+
setNewVisType(undefined);
75+
}}
76+
maxWidth="300px"
77+
data-test-subj="confirmVisChangeModal"
78+
>
79+
<p>
80+
<FormattedMessage
81+
id="wizard.rightNav.changeVisType.modalDescription"
82+
defaultMessage="Changing the visualization type will reset all field selections. Do you want to continue?"
83+
/>
84+
</p>
85+
</EuiConfirmModal>
86+
)}
4887
</section>
4988
);
5089
};

src/plugins/wizard/public/application/components/searchable_dropdown.scss

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
}
2323

2424
&--fixedWidthChild {
25-
width: calc(#{$wizSideNavWidth} - #{$euiSizeXL} * 2);
25+
width: calc(#{$wizLeftNavWidth} - #{$euiSizeXL} * 2);
2626
}
2727

2828
&--selectableWrapper .euiSelectableList {

src/plugins/wizard/public/application/components/side_nav.scss

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
&.right {
1717
border-left: $euiBorderThin;
1818
grid-area: rightNav;
19+
height: 100%;
1920
}
2021

2122
&__header {
@@ -46,5 +47,5 @@
4647
}
4748

4849
.wizDatasourceSelect {
49-
max-width: calc(#{$wizSideNavWidth} - 1px);
50+
max-width: calc(#{$wizLeftNavWidth} - 1px);
5051
}

src/plugins/wizard/public/application/components/workspace.scss

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
grid-gap: $euiSizeM;
1111
padding: $euiSizeM;
1212
background-color: $euiColorEmptyShade;
13+
height: 100%;
1314

1415
&__empty {
1516
height: 100%;

src/plugins/wizard/public/application/components/workspace.tsx

+8-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { WizardServices } from '../../types';
1111
import { validateSchemaState } from '../utils/validate_schema_state';
1212
import { useTypedSelector } from '../utils/state_management';
1313
import { useVisualizationType } from '../utils/use';
14+
import { PersistedState } from '../../../../visualizations/public';
1415

1516
import hand_field from '../../assets/hand_field.svg';
1617
import fields_bg from '../../assets/fields_bg.svg';
@@ -34,6 +35,8 @@ export const Workspace: FC = ({ children }) => {
3435
timeRange: data.query.timefilter.timefilter.getTime(),
3536
});
3637
const rootState = useTypedSelector((state) => state);
38+
// Visualizations require the uiState to persist even when the expression changes
39+
const uiState = useMemo(() => new PersistedState(), []);
3740

3841
useEffect(() => {
3942
async function loadExpression() {
@@ -77,7 +80,11 @@ export const Workspace: FC = ({ children }) => {
7780
</EuiFlexGroup>
7881
<EuiPanel className="wizCanvas" data-test-subj="visualizationLoader">
7982
{expression ? (
80-
<ReactExpressionRenderer expression={expression} searchContext={searchContext} />
83+
<ReactExpressionRenderer
84+
expression={expression}
85+
searchContext={searchContext}
86+
uiState={uiState}
87+
/>
8188
) : (
8289
<EuiFlexItem className="wizWorkspace__empty" data-test-subj="emptyWorkspace">
8390
<EuiEmptyPrompt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import { cloneDeep } from 'lodash';
7+
import { OpenSearchaggsExpressionFunctionDefinition } from '../../../../data/public';
8+
import { ExpressionFunctionOpenSearchDashboards } from '../../../../expressions';
9+
import { buildExpressionFunction } from '../../../../expressions/public';
10+
import { VisualizationState } from '../../application/utils/state_management';
11+
import { getAggService, getIndexPatterns } from '../../plugin_services';
12+
13+
export const getAggExpressionFunctions = async (visualization: VisualizationState) => {
14+
const { activeVisualization, indexPattern: indexId = '' } = visualization;
15+
const { aggConfigParams } = activeVisualization || {};
16+
17+
const indexPatternsService = getIndexPatterns();
18+
const indexPattern = await indexPatternsService.get(indexId);
19+
// aggConfigParams is the serealizeable aggConfigs that need to be reconstructed here using the agg servce
20+
const aggConfigs = getAggService().createAggConfigs(indexPattern, cloneDeep(aggConfigParams));
21+
22+
const opensearchDashboards = buildExpressionFunction<ExpressionFunctionOpenSearchDashboards>(
23+
'opensearchDashboards',
24+
{}
25+
);
26+
27+
// soon this becomes: const opensearchaggs = vis.data.aggs!.toExpressionAst();
28+
const opensearchaggs = buildExpressionFunction<OpenSearchaggsExpressionFunctionDefinition>(
29+
'opensearchaggs',
30+
{
31+
index: indexId,
32+
metricsAtAllLevels: false,
33+
partialRows: false,
34+
aggConfigs: JSON.stringify(aggConfigs.aggs),
35+
includeFormatHints: false,
36+
}
37+
);
38+
39+
return {
40+
aggConfigs,
41+
expressionFns: [opensearchDashboards, opensearchaggs],
42+
};
43+
};

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

+7-1
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,15 @@
55

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

910
export function registerDefaultTypes(typeServiceSetup: TypeServiceSetup) {
10-
const visualizationTypes = [createMetricConfig];
11+
const visualizationTypes = [
12+
createHistogramConfig,
13+
createLineConfig,
14+
createAreaConfig,
15+
createMetricConfig,
16+
];
1117

1218
visualizationTypes.forEach((createTypeConfig) => {
1319
typeServiceSetup.createVisualizationType(createTypeConfig());

0 commit comments

Comments
 (0)