Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Backport 2.x] [VisBuilder] fixes filters for table visualisation #3232

Merged
merged 1 commit into from
Jan 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,24 @@
* SPDX-License-Identifier: Apache-2.0
*/

import React, { useCallback, useMemo, useState } from 'react';
import React, { Component, useCallback, useMemo, useState } from 'react';
import { cloneDeep, get } from 'lodash';
import { useDebounce } from 'react-use';
import { i18n } from '@osd/i18n';
import { EuiCallOut } from '@elastic/eui';
import { useTypedDispatch, useTypedSelector } from '../../utils/state_management';
import { DefaultEditorAggParams } from '../../../../../vis_default_editor/public';
import { Title } from './title';
import { useIndexPatterns, useVisualizationType } from '../../utils/use';
import { useOpenSearchDashboards } from '../../../../../opensearch_dashboards_react/public';
import {
OpenSearchDashboardsContextProvider,
useOpenSearchDashboards,
} from '../../../../../opensearch_dashboards_react/public';
import { VisBuilderServices } from '../../../types';
import { AggParam, IAggType, IFieldParamType } from '../../../../../data/public';
import { saveDraftAgg, editDraftAgg } from '../../utils/state_management/visualization_slice';
import { setValidity } from '../../utils/state_management/metadata_slice';
import { Storage } from '../../../../../opensearch_dashboards_utils/public';

const EDITOR_KEY = 'CONFIG_PANEL';

Expand All @@ -27,13 +33,12 @@ export function SecondaryPanel() {
const dispatch = useTypedDispatch();
const vizType = useVisualizationType();
const indexPattern = useIndexPatterns().selected;
const { services } = useOpenSearchDashboards<VisBuilderServices>();
const {
services: {
data: {
search: { aggs: aggService },
},
data: {
search: { aggs: aggService },
},
} = useOpenSearchDashboards<VisBuilderServices>();
} = services;
const schemas = vizType.ui.containerConfig.data.schemas.all;

const aggConfigs = useMemo(() => {
Expand Down Expand Up @@ -98,49 +103,98 @@ export function SecondaryPanel() {
<div className="vbConfig__section vbConfig--secondary">
<Title title={selectedSchema?.title ?? 'Edit'} isSecondary closeMenu={closeMenu} />
{showAggParamEditor && (
<DefaultEditorAggParams
className="vbConfig__aggEditor"
agg={aggConfig!}
indexPattern={indexPattern!}
setValidity={handleSetValid}
setTouched={setTouched}
schemas={schemas}
formIsTouched={touched}
groupName={selectedSchema?.group ?? 'none'}
metricAggs={metricAggs}
state={{
data: {},
description: '',
title: '',
<OpenSearchDashboardsContextProvider
services={{
...services,
storage: new Storage(window.localStorage), // This is necessary for filters
}}
setAggParamValue={function <T extends string | number | symbol>(
aggId: string,
paramName: T,
value: any
): void {
aggConfig.params[paramName] = value;
dispatch(editDraftAgg(aggConfig.serialize()));
}}
onAggTypeChange={function (aggId: string, aggType: IAggType): void {
aggConfig.type = aggType;

// Persist field if the new agg type supports the existing field
const fieldParam = (aggType.params as AggParam[]).find(({ type }) => type === 'field');
if (fieldParam) {
const availableFields = (fieldParam as IFieldParamType).getAvailableFields(aggConfig);
const indexField = availableFields.find(
({ name }) => name === get(draftAgg, 'params.field')
);

if (indexField) {
aggConfig.params.field = indexField;
}
}

dispatch(editDraftAgg(aggConfig.serialize()));
}}
/>
>
<EditorErrorBoundary>
<DefaultEditorAggParams
className="vbConfig__aggEditor"
agg={aggConfig!}
indexPattern={indexPattern!}
setValidity={handleSetValid}
setTouched={setTouched}
schemas={schemas}
formIsTouched={touched}
groupName={selectedSchema?.group ?? 'none'}
metricAggs={metricAggs}
state={{
data: {},
description: '',
title: '',
}}
setAggParamValue={function <T extends string | number | symbol>(
aggId: string,
paramName: T,
value: any
): void {
aggConfig.params[paramName] = value;
dispatch(editDraftAgg(aggConfig.serialize()));
}}
onAggTypeChange={function (aggId: string, aggType: IAggType): void {
aggConfig.type = aggType;

// Persist field if the new agg type supports the existing field
const fieldParam = (aggType.params as AggParam[]).find(
({ type }) => type === 'field'
);
if (fieldParam) {
const availableFields = (fieldParam as IFieldParamType).getAvailableFields(
aggConfig
);
const indexField = availableFields.find(
({ name }) => name === get(draftAgg, 'params.field')
);

if (indexField) {
aggConfig.params.field = indexField;
}
}

dispatch(editDraftAgg(aggConfig.serialize()));
}}
/>
</EditorErrorBoundary>
</OpenSearchDashboardsContextProvider>
)}
</div>
);
}

class EditorErrorBoundary extends Component<{}, { error?: any }> {
state = {
error: undefined,
};

static getDerivedStateFromError(error: any) {
return { error };
}

componentDidCatch(error) {
// eslint-disable-next-line no-console
console.error(error);
}

render() {
if (this.state.error) {
return (
<EuiCallOut
title={i18n.translate('visBuilder.aggParamsEditor.errorTitle', {
defaultMessage: 'Error',
})}
color="danger"
iconType="alert"
>
<p>
{i18n.translate('visBuilder.aggParamsEditor.errorMsg', {
defaultMessage: 'Something went wrong while editing the aggregation',
})}
</p>
</EuiCallOut>
);
}
return this.props.children;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import { useUnmount } from 'react-use';
import { PLUGIN_ID } from '../../../common';
import { useOpenSearchDashboards } from '../../../../opensearch_dashboards_react/public';
import { getTopNavConfig } from '../utils/get_top_nav_config';
import { VisBuilderServices } from '../../types';
Expand All @@ -29,6 +28,7 @@ export const TopNav = () => {
navigation: {
ui: { TopNavMenu },
},
appName,
} = services;
const rootState = useTypedSelector((state) => state);
const dispatch = useTypedDispatch();
Expand Down Expand Up @@ -81,7 +81,7 @@ export const TopNav = () => {
return (
<div className="vbTopNav">
<TopNavMenu
appName={PLUGIN_ID}
appName={appName}
config={config}
setMenuMountPoint={setHeaderActionMenu}
indexPatterns={indexPattern ? [indexPattern] : []}
Expand Down
1 change: 1 addition & 0 deletions src/plugins/vis_builder/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ export class VisBuilderPlugin

const services: VisBuilderServices = {
...coreStart,
appName: PLUGIN_ID,
scopedHistory: this.currentHistory,
history: this.currentHistory,
osdUrlStateStorage: createOsdUrlStateStorage({
Expand Down
1 change: 1 addition & 0 deletions src/plugins/vis_builder/public/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export interface VisBuilderPluginStartDependencies {
}

export interface VisBuilderServices extends CoreStart {
appName: string;
setHeaderActionMenu: AppMountParameters['setHeaderActionMenu'];
savedVisBuilderLoader: VisBuilderStart['savedVisBuilderLoader'];
toastNotifications: ToastsStart;
Expand Down
3 changes: 3 additions & 0 deletions src/plugins/vis_type_table/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ import { TableVisPlugin as Plugin } from './plugin';
export function plugin(initializerContext: PluginInitializerContext) {
return new Plugin(initializerContext);
}

/* Public Types */
export { TableVisExpressionFunctionDefinition } from './table_vis_fn';