onEvent prop for expression component (#64995)
* feat: 🎸 add onEvent prop to expression component * feat: 🎸 add type safety to onEvent prop in expression component Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
c995a333de
commit
4d19323150
|
@ -37,7 +37,7 @@ export {
|
|||
ReactExpressionRendererProps,
|
||||
ReactExpressionRendererType,
|
||||
} from './react_expression_renderer';
|
||||
export { ExpressionRenderHandler } from './render';
|
||||
export { ExpressionRenderHandler, ExpressionRendererEvent } from './render';
|
||||
export {
|
||||
AnyExpressionFunctionDefinition,
|
||||
AnyExpressionTypeDefinition,
|
||||
|
|
|
@ -26,6 +26,7 @@ import { ExpressionLoader } from './loader';
|
|||
import { mount } from 'enzyme';
|
||||
import { EuiProgress } from '@elastic/eui';
|
||||
import { RenderErrorHandlerFnType } from './types';
|
||||
import { ExpressionRendererEvent } from './render';
|
||||
|
||||
jest.mock('./loader', () => {
|
||||
return {
|
||||
|
@ -135,4 +136,44 @@ describe('ExpressionRenderer', () => {
|
|||
expect(instance.find(EuiProgress)).toHaveLength(0);
|
||||
expect(instance.find('[data-test-subj="custom-error"]')).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should fire onEvent prop on every events$ observable emission in loader', () => {
|
||||
const dataSubject = new Subject();
|
||||
const data$ = dataSubject.asObservable().pipe(share());
|
||||
const renderSubject = new Subject();
|
||||
const render$ = renderSubject.asObservable().pipe(share());
|
||||
const loadingSubject = new Subject();
|
||||
const loading$ = loadingSubject.asObservable().pipe(share());
|
||||
const eventsSubject = new Subject<ExpressionRendererEvent>();
|
||||
const events$ = eventsSubject.asObservable().pipe(share());
|
||||
|
||||
const onEvent = jest.fn();
|
||||
const event: ExpressionRendererEvent = {
|
||||
name: 'foo',
|
||||
data: {
|
||||
bar: 'baz',
|
||||
},
|
||||
};
|
||||
|
||||
(ExpressionLoader as jest.Mock).mockImplementation(() => {
|
||||
return {
|
||||
render$,
|
||||
data$,
|
||||
loading$,
|
||||
events$,
|
||||
update: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
mount(<ReactExpressionRenderer expression="" onEvent={onEvent} />);
|
||||
|
||||
expect(onEvent).toHaveBeenCalledTimes(0);
|
||||
|
||||
act(() => {
|
||||
eventsSubject.next(event);
|
||||
});
|
||||
|
||||
expect(onEvent).toHaveBeenCalledTimes(1);
|
||||
expect(onEvent.mock.calls[0][0]).toBe(event);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -27,6 +27,7 @@ import theme from '@elastic/eui/dist/eui_theme_light.json';
|
|||
import { IExpressionLoaderParams, RenderError } from './types';
|
||||
import { ExpressionAstExpression, IInterpreterRenderHandlers } from '../common';
|
||||
import { ExpressionLoader } from './loader';
|
||||
import { ExpressionRendererEvent } from './render';
|
||||
|
||||
// Accept all options of the runner as props except for the
|
||||
// dom element which is provided by the component itself
|
||||
|
@ -36,6 +37,7 @@ export interface ReactExpressionRendererProps extends IExpressionLoaderParams {
|
|||
expression: string | ExpressionAstExpression;
|
||||
renderError?: (error?: string | null) => React.ReactElement | React.ReactElement[];
|
||||
padding?: 'xs' | 's' | 'm' | 'l' | 'xl';
|
||||
onEvent?: (event: ExpressionRendererEvent) => void;
|
||||
}
|
||||
|
||||
export type ReactExpressionRendererType = React.ComponentType<ReactExpressionRendererProps>;
|
||||
|
@ -60,6 +62,7 @@ export const ReactExpressionRenderer = ({
|
|||
padding,
|
||||
renderError,
|
||||
expression,
|
||||
onEvent,
|
||||
...expressionLoaderOptions
|
||||
}: ReactExpressionRendererProps) => {
|
||||
const mountpoint: React.MutableRefObject<null | HTMLDivElement> = useRef(null);
|
||||
|
@ -99,6 +102,13 @@ export const ReactExpressionRenderer = ({
|
|||
}
|
||||
: expressionLoaderOptions.onRenderError,
|
||||
});
|
||||
if (onEvent) {
|
||||
subs.push(
|
||||
expressionLoaderRef.current.events$.subscribe(event => {
|
||||
onEvent(event);
|
||||
})
|
||||
);
|
||||
}
|
||||
subs.push(
|
||||
expressionLoaderRef.current.loading$.subscribe(() => {
|
||||
hasHandledErrorRef.current = false;
|
||||
|
@ -123,7 +133,7 @@ export const ReactExpressionRenderer = ({
|
|||
|
||||
errorRenderHandlerRef.current = null;
|
||||
};
|
||||
}, [hasCustomRenderErrorHandler]);
|
||||
}, [hasCustomRenderErrorHandler, onEvent]);
|
||||
|
||||
// Re-fetch data automatically when the inputs change
|
||||
useShallowCompareEffect(
|
||||
|
|
|
@ -32,7 +32,7 @@ export interface ExpressionRenderHandlerParams {
|
|||
onRenderError: RenderErrorHandlerFnType;
|
||||
}
|
||||
|
||||
interface Event {
|
||||
export interface ExpressionRendererEvent {
|
||||
name: string;
|
||||
data: any;
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ interface UpdateValue {
|
|||
export class ExpressionRenderHandler {
|
||||
render$: Observable<number>;
|
||||
update$: Observable<UpdateValue | null>;
|
||||
events$: Observable<Event>;
|
||||
events$: Observable<ExpressionRendererEvent>;
|
||||
|
||||
private element: HTMLElement;
|
||||
private destroyFn?: any;
|
||||
|
@ -63,7 +63,7 @@ export class ExpressionRenderHandler {
|
|||
this.element = element;
|
||||
|
||||
this.eventsSubject = new Rx.Subject();
|
||||
this.events$ = this.eventsSubject.asObservable() as Observable<Event>;
|
||||
this.events$ = this.eventsSubject.asObservable() as Observable<ExpressionRendererEvent>;
|
||||
|
||||
this.onRenderError = onRenderError || defaultRenderErrorHandler;
|
||||
|
||||
|
|
Loading…
Reference in a new issue