Skip to content

Commit

Permalink
[7.x] [Lens] Expose active data in some places (elastic#79851) (elast…
Browse files Browse the repository at this point in the history
  • Loading branch information
flash1293 authored Nov 9, 2020
1 parent 2d41717 commit e411757
Show file tree
Hide file tree
Showing 20 changed files with 211 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
<b>Signature:</b>

```typescript
ReactExpressionRenderer: ({ className, dataAttrs, padding, renderError, expression, onEvent, reload$, debounce, ...expressionLoaderOptions }: ReactExpressionRendererProps) => JSX.Element
ReactExpressionRenderer: ({ className, dataAttrs, padding, renderError, expression, onEvent, onData$, reload$, debounce, ...expressionLoaderOptions }: ReactExpressionRendererProps) => JSX.Element
```
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface ReactExpressionRendererProps extends IExpressionLoaderParams
| [dataAttrs](./kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.dataattrs.md) | <code>string[]</code> | |
| [debounce](./kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.debounce.md) | <code>number</code> | |
| [expression](./kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.expression.md) | <code>string &#124; ExpressionAstExpression</code> | |
| [onData$](./kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.ondata_.md) | <code>&lt;TData, TInspectorAdapters&gt;(data: TData, adapters?: TInspectorAdapters) =&gt; void</code> | |
| [onEvent](./kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.onevent.md) | <code>(event: ExpressionRendererEvent) =&gt; void</code> | |
| [padding](./kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.padding.md) | <code>'xs' &#124; 's' &#124; 'm' &#124; 'l' &#124; 'xl'</code> | |
| [reload$](./kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.reload_.md) | <code>Observable&lt;unknown&gt;</code> | An observable which can be used to re-run the expression without destroying the component |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-plugins-expressions-public](./kibana-plugin-plugins-expressions-public.md) &gt; [ReactExpressionRendererProps](./kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.md) &gt; [onData$](./kibana-plugin-plugins-expressions-public.reactexpressionrendererprops.ondata_.md)

## ReactExpressionRendererProps.onData$ property

<b>Signature:</b>

```typescript
onData$?: <TData, TInspectorAdapters>(data: TData, adapters?: TInspectorAdapters) => void;
```
4 changes: 3 additions & 1 deletion src/plugins/expressions/public/public.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1057,7 +1057,7 @@ export interface Range {
// Warning: (ae-missing-release-tag) "ReactExpressionRenderer" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const ReactExpressionRenderer: ({ className, dataAttrs, padding, renderError, expression, onEvent, reload$, debounce, ...expressionLoaderOptions }: ReactExpressionRendererProps) => JSX.Element;
export const ReactExpressionRenderer: ({ className, dataAttrs, padding, renderError, expression, onEvent, onData$, reload$, debounce, ...expressionLoaderOptions }: ReactExpressionRendererProps) => JSX.Element;

// Warning: (ae-missing-release-tag) "ReactExpressionRendererProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
Expand All @@ -1072,6 +1072,8 @@ export interface ReactExpressionRendererProps extends IExpressionLoaderParams {
// (undocumented)
expression: string | ExpressionAstExpression;
// (undocumented)
onData$?: <TData, TInspectorAdapters>(data: TData, adapters?: TInspectorAdapters) => void;
// (undocumented)
onEvent?: (event: ExpressionRendererEvent) => void;
// (undocumented)
padding?: 'xs' | 's' | 'm' | 'l' | 'xl';
Expand Down
32 changes: 32 additions & 0 deletions src/plugins/expressions/public/react_expression_renderer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,38 @@ describe('ExpressionRenderer', () => {
expect(instance.find('[data-test-subj="custom-error"]')).toHaveLength(0);
});

it('should call onData$ prop on every data$ observable emission in loader', () => {
const dataSubject = new Subject();
const data$ = dataSubject.asObservable().pipe(share());

const newData = {};
const inspectData = {};
const onData$ = jest.fn();

(ExpressionLoader as jest.Mock).mockImplementation(() => {
return {
render$: new Subject(),
data$,
loading$: new Subject(),
events$: new Subject(),
update: jest.fn(),
inspect: jest.fn(() => inspectData),
};
});

mount(<ReactExpressionRenderer expression="" onData$={onData$} />);

expect(onData$).toHaveBeenCalledTimes(0);

act(() => {
dataSubject.next(newData);
});

expect(onData$).toHaveBeenCalledTimes(1);
expect(onData$.mock.calls[0][0]).toBe(newData);
expect(onData$.mock.calls[0][1]).toBe(inspectData);
});

it('should fire onEvent prop on every events$ observable emission in loader', () => {
const dataSubject = new Subject();
const data$ = dataSubject.asObservable().pipe(share());
Expand Down
9 changes: 9 additions & 0 deletions src/plugins/expressions/public/react_expression_renderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export interface ReactExpressionRendererProps extends IExpressionLoaderParams {
) => React.ReactElement | React.ReactElement[];
padding?: 'xs' | 's' | 'm' | 'l' | 'xl';
onEvent?: (event: ExpressionRendererEvent) => void;
onData$?: <TData, TInspectorAdapters>(data: TData, adapters?: TInspectorAdapters) => void;
/**
* An observable which can be used to re-run the expression without destroying the component
*/
Expand Down Expand Up @@ -71,6 +72,7 @@ export const ReactExpressionRenderer = ({
renderError,
expression,
onEvent,
onData$,
reload$,
debounce,
...expressionLoaderOptions
Expand Down Expand Up @@ -135,6 +137,13 @@ export const ReactExpressionRenderer = ({
})
);
}
if (onData$) {
subs.push(
expressionLoaderRef.current.data$.subscribe((newData) => {
onData$(newData, expressionLoaderRef.current?.inspect());
})
);
}
subs.push(
expressionLoaderRef.current.loading$.subscribe(() => {
hasHandledErrorRef.current = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export function LayerPanel(
state: props.visualizationState,
frame: props.framePublicAPI,
dateRange: props.framePublicAPI.dateRange,
activeData: props.framePublicAPI.activeData,
};
const datasourceId = datasourcePublicAPI.datasourceId;
const layerDatasourceState = props.datasourceStates[datasourceId].state;
Expand All @@ -111,6 +112,7 @@ export function LayerPanel(
...layerDatasourceDropProps,
frame: props.framePublicAPI,
dateRange: props.framePublicAPI.dateRange,
activeData: props.framePublicAPI.activeData,
};

const { groups } = activeVisualization.getConfiguration(layerVisualizationConfigProps);
Expand Down Expand Up @@ -140,6 +142,7 @@ export function LayerPanel(
nativeProps={{
layerId,
state: layerDatasourceState,
activeData: props.framePublicAPI.activeData,
setState: (updater: unknown) => {
const newState =
typeof updater === 'function' ? updater(layerDatasourceState) : updater;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export function EditorFrame(props: EditorFrameProps) {

const framePublicAPI: FramePublicAPI = {
datasourceLayers,
activeData: state.activeData,
dateRange: props.dateRange,
query: props.query,
filters: props.filters,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import { EditorFrameProps } from './index';
import { Document } from '../../persistence/saved_object_store';
import { TableInspectorAdapter } from '../types';

export interface PreviewState {
visualization: {
Expand All @@ -21,6 +22,7 @@ export interface EditorFrameState extends PreviewState {
description?: string;
stagedPreview?: PreviewState;
activeDatasourceId: string | null;
activeData?: TableInspectorAdapter;
}

export type Action =
Expand All @@ -32,6 +34,10 @@ export type Action =
type: 'UPDATE_TITLE';
title: string;
}
| {
type: 'UPDATE_ACTIVE_DATA';
tables: TableInspectorAdapter;
}
| {
type: 'UPDATE_STATE';
// Just for diagnostics, so we can determine what action
Expand Down Expand Up @@ -139,6 +145,11 @@ export const reducer = (state: EditorFrameState, action: Action): EditorFrameSta
return { ...state, title: action.title };
case 'UPDATE_STATE':
return action.updater(state);
case 'UPDATE_ACTIVE_DATA':
return {
...state,
activeData: action.tables,
};
case 'UPDATE_LAYER':
return {
...state,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import _ from 'lodash';
import { Ast } from '@kbn/interpreter/common';
import { IconType } from '@elastic/eui/src/components/icon/icon';
import { Datatable } from 'src/plugins/expressions';
import { PaletteOutput } from 'src/plugins/charts/public';
import { VisualizeFieldContext } from '../../../../../../src/plugins/ui_actions/public';
import {
Expand Down Expand Up @@ -50,6 +51,7 @@ export function getSuggestions({
visualizationState,
field,
visualizeTriggerFieldContext,
activeData,
mainPalette,
}: {
datasourceMap: Record<string, Datasource>;
Expand All @@ -66,6 +68,7 @@ export function getSuggestions({
visualizationState: unknown;
field?: unknown;
visualizeTriggerFieldContext?: VisualizeFieldContext;
activeData?: Record<string, Datatable>;
mainPalette?: PaletteOutput;
}): Suggestion[] {
const datasources = Object.entries(datasourceMap).filter(
Expand All @@ -87,7 +90,8 @@ export function getSuggestions({
dataSourceSuggestions = datasource.getDatasourceSuggestionsForField(datasourceState, field);
} else {
dataSourceSuggestions = datasource.getDatasourceSuggestionsFromCurrentState(
datasourceState
datasourceState,
activeData
);
}
return dataSourceSuggestions.map((suggestion) => ({ ...suggestion, datasourceId }));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ export function SuggestionPanel({
visualizationMap,
activeVisualizationId: currentVisualizationId,
visualizationState: currentVisualizationState,
activeData: frame.activeData,
})
.filter((suggestion) => !suggestion.hide)
.filter(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ function getTopSuggestion(
activeVisualizationId: props.visualizationId,
visualizationState: props.visualizationState,
subVisualizationId,
activeData: props.framePublicAPI.activeData,
mainPalette,
});
const suggestions = unfilteredSuggestions.filter((suggestion) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,48 @@ describe('workspace_panel', () => {
expect(trigger.exec).toHaveBeenCalledWith({ data: eventData });
});

it('should push add current data table to state on data$ emitting value', () => {
const framePublicAPI = createMockFramePublicAPI();
framePublicAPI.datasourceLayers = {
first: mockDatasource.publicAPIMock,
};
mockDatasource.toExpression.mockReturnValue('datasource');
mockDatasource.getLayers.mockReturnValue(['first']);
const dispatch = jest.fn();

instance = mount(
<WorkspacePanel
activeDatasourceId={'mock'}
datasourceStates={{
mock: {
state: {},
isLoading: false,
},
}}
datasourceMap={{
mock: mockDatasource,
}}
framePublicAPI={framePublicAPI}
activeVisualizationId="vis"
visualizationMap={{
vis: { ...mockVisualization, toExpression: () => 'vis' },
}}
visualizationState={{}}
dispatch={dispatch}
ExpressionRenderer={expressionRendererMock}
core={coreMock.createSetup()}
plugins={{ uiActions: uiActionsMock, data: dataMock }}
/>
);

const onData = expressionRendererMock.mock.calls[0][0].onData$!;

const tableData = { table1: { columns: [], rows: [] } };
onData(undefined, { tables: tableData });

expect(dispatch).toHaveBeenCalledWith({ type: 'UPDATE_ACTIVE_DATA', tables: tableData });
});

it('should include data fetching for each layer in the expression', () => {
const mockDatasource2 = createMockDatasource('a');
const framePublicAPI = createMockFramePublicAPI();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import {
} from '../../../../../../../src/plugins/data/public';
import { WorkspacePanelWrapper } from './workspace_panel_wrapper';
import { DropIllustration } from '../../../assets/drop_illustration';
import { LensInspectorAdapters } from '../../types';
import { getOriginalRequestErrorMessage } from '../../error_helper';
import { validateDatasourceAndVisualization } from '../state_helpers';

Expand Down Expand Up @@ -296,6 +297,7 @@ export function WorkspacePanel({
expression={expression}
framePublicAPI={framePublicAPI}
timefilter={plugins.data.query.timefilter.timefilter}
dispatch={dispatch}
onEvent={onEvent}
setLocalState={setLocalState}
localState={{ ...localState, configurationValidationError }}
Expand Down Expand Up @@ -339,11 +341,13 @@ export const InnerVisualizationWrapper = ({
setLocalState,
localState,
ExpressionRendererComponent,
dispatch,
}: {
expression: Ast | null | undefined;
framePublicAPI: FramePublicAPI;
timefilter: TimefilterContract;
onEvent: (event: ExpressionRendererEvent) => void;
dispatch: (action: Action) => void;
setLocalState: (dispatch: (prevState: WorkspaceState) => WorkspaceState) => void;
localState: WorkspaceState & {
configurationValidationError?: Array<{ shortMessage: string; longMessage: string }>;
Expand All @@ -369,6 +373,18 @@ export const InnerVisualizationWrapper = ({
]
);

const onData$ = useCallback(
(data: unknown, inspectorAdapters?: LensInspectorAdapters) => {
if (inspectorAdapters && inspectorAdapters.tables) {
dispatch({
type: 'UPDATE_ACTIVE_DATA',
tables: inspectorAdapters.tables,
});
}
},
[dispatch]
);

if (localState.configurationValidationError) {
let showExtraErrors = null;
if (localState.configurationValidationError.length > 1) {
Expand Down Expand Up @@ -455,6 +471,7 @@ export const InnerVisualizationWrapper = ({
searchContext={context}
reload$={autoRefreshFetch$}
onEvent={onEvent}
onData$={onData$}
renderError={(errorMessage?: string | null, error?: ExpressionRenderError | null) => {
const visibleErrorMessage = getOriginalRequestErrorMessage(error) || errorMessage;

Expand Down
Loading

0 comments on commit e411757

Please sign in to comment.