Skip to content

Commit

Permalink
[canvas] Create Expressions Service; remove legacy service
Browse files Browse the repository at this point in the history
  • Loading branch information
clintandrewhall committed Aug 2, 2021
1 parent 01eb6c7 commit 9ff5def
Show file tree
Hide file tree
Showing 21 changed files with 195 additions and 160 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import { ExpressionFunctionDefinition } from 'src/plugins/expressions/common';
import { Render, ContainerStyle } from '../../../types';
import { ExpressionValueRender, ContainerStyle } from '../../../types';
import { getFunctionHelp } from '../../../i18n';
import { DEFAULT_ELEMENT_CSS } from '../../../common/lib/constants';

Expand All @@ -19,11 +19,14 @@ interface Arguments {
css: string;
containerStyle: ContainerStyleArgument;
}

export type Renderable = ExpressionValueRender<Arguments> & Arguments;

export function render(): ExpressionFunctionDefinition<
'render',
Render<any>,
ExpressionValueRender<any>,
Arguments,
Render<Arguments>
ExpressionValueRender<Arguments>
> {
const { help, args: argHelp } = getFunctionHelp().render;

Expand Down
22 changes: 13 additions & 9 deletions x-pack/plugins/canvas/public/application.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,12 @@ import { init as initStatsReporter } from './lib/ui_metric';

import { CapabilitiesStrings } from '../i18n';

import { startServices, services, LegacyServicesProvider, CanvasPluginServices } from './services';
import {
startLegacyServices,
services,
LegacyServicesProvider,
CanvasPluginServices,
} from './services';
import { initFunctions } from './functions';
// @ts-expect-error untyped local
import { appUnload } from './state/actions/app';
Expand Down Expand Up @@ -93,9 +98,11 @@ export const initializeCanvas = async (
setupPlugins: CanvasSetupDeps,
startPlugins: CanvasStartDeps,
registries: SetupRegistries,
appUpdater: BehaviorSubject<AppUpdater>
appUpdater: BehaviorSubject<AppUpdater>,
pluginServices: PluginServices<CanvasPluginServices>
) => {
await startServices(coreSetup, coreStart, setupPlugins, startPlugins, appUpdater);
await startLegacyServices(coreSetup, coreStart, setupPlugins, startPlugins, appUpdater);
const { expressions } = pluginServices.getServices();

// Adding these functions here instead of in plugin.ts.
// Some of these functions have deep dependencies into Canvas, which was bulking up the size
Expand All @@ -108,13 +115,13 @@ export const initializeCanvas = async (
});

for (const fn of canvasFunctions) {
services.expressions.getService().registerFunction(fn);
expressions.registerFunction(fn);
}

// Create Store
const canvasStore = await createStore(coreSetup);

registerLanguage(Object.values(services.expressions.getService().getFunctions()));
registerLanguage(Object.values(expressions.getFunctions()));

// Init Registries
initRegistries();
Expand Down Expand Up @@ -145,10 +152,7 @@ export const initializeCanvas = async (
},
],
content: (domNode) => {
ReactDOM.render(
<HelpMenu functionRegistry={services.expressions.getService().getFunctions()} />,
domNode
);
ReactDOM.render(<HelpMenu functionRegistry={expressions.getFunctions()} />, domNode);
return () => ReactDOM.unmountComponentAtNode(domNode);
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,49 +6,62 @@
*/

import React from 'react';
import PropTypes from 'prop-types';
import { omitBy, isNil } from 'lodash';
// @ts-expect-error Untyped library
import Style from 'style-it';

import { ExpressionRenderer } from 'src/plugins/expressions';
import { getType } from '@kbn/interpreter/common';
import { Loading } from '../loading';
import { RenderWithFn } from '../render_with_fn';
// @ts-expect-error Untyped local
import { ElementShareContainer } from '../element_share_container';
import { InvalidExpression } from './invalid_expression';
import { InvalidElementType } from './invalid_element_type';
import { RendererHandlers } from '../../../types';
import { Renderable } from '../../../canvas_plugin_src/functions/common/render';

const isLoading = (renderable, state) => !state || !renderable;

const isNotValidForRendering = (renderable, renderFunction) =>
renderable && getType(renderable) !== 'render' && !renderFunction;

const isNotValidExpression = (renderable, renderFunction, state) =>
state === 'error' || // The renderable has an error
getType(renderable) !== 'render' || // The renderable isn't, well, renderable
!renderFunction; // We can't find an element in the registry for this
export interface Props {
renderable: Renderable | null;
renderFunction: ExpressionRenderer<any> | null;
height: number;
width: number;
handlers: RendererHandlers;
backgroundColor: string;
selectElement: () => void;
state: string;
}

export const ElementContent = (props) => {
export const ElementContent = (props: Props) => {
const { renderable, renderFunction, width, height, handlers, backgroundColor, state } = props;
const { onComplete } = handlers;

if (isLoading(renderable, state)) {
if (!state || !renderable) {
return <Loading backgroundColor={backgroundColor} />;
}

// renderable is available, but no matching element is found, render invalid
if (isNotValidForRendering(renderable, renderFunction)) {
if (renderable && getType(renderable) !== 'render' && !renderFunction) {
return <InvalidElementType {...props} renderableType={renderable?.as} />;
}

// error state, render invalid expression notice
if (isNotValidExpression(renderable, renderFunction, state)) {
if (
state === 'error' || // The renderable has an error
getType(renderable) !== 'render' || // The renderable isn't, well, renderable
!renderFunction // We can't find an element in the registry for this
) {
return <InvalidExpression {...props} />;
}

const containerStyle = omitBy(renderable.containerStyle, isNil);

return Style.it(
renderable.css,
<div
// TODO: 'canvas__element' was added for BWC, It can be removed after a while
className={'canvas__element canvasElement'}
style={{ ...renderable.containerStyle, width, height }}
style={{ ...containerStyle, width, height }}
data-test-subj="canvasWorkpadPageElementContent"
>
<ElementShareContainer
Expand All @@ -70,24 +83,3 @@ export const ElementContent = (props) => {
</div>
);
};

ElementContent.propTypes = {
renderable: PropTypes.shape({
css: PropTypes.string,
value: PropTypes.object,
}),
renderFunction: PropTypes.shape({
name: PropTypes.string,
render: PropTypes.func,
reuseDomNode: PropTypes.bool,
}),
size: PropTypes.object,
handlers: PropTypes.shape({
setFilter: PropTypes.func.isRequired,
getFilter: PropTypes.func.isRequired,
done: PropTypes.func.isRequired,
onComplete: PropTypes.func.isRequired, // local, not passed through
}).isRequired,
state: PropTypes.string,
backgroundColor: PropTypes.string,
};
32 changes: 0 additions & 32 deletions x-pack/plugins/canvas/public/components/element_content/index.js

This file was deleted.

27 changes: 27 additions & 0 deletions x-pack/plugins/canvas/public/components/element_content/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { useSelector } from 'react-redux';
import { getSelectedPage, getPageById } from '../../state/selectors/workpad';
import { useExpressionsService } from '../../services';
import { ElementContent as Component, Props as ComponentProps } from './element_content';
import { State } from '../../../types';

export type Props = Omit<ComponentProps, 'renderFunction' | 'backgroundColor'>;

export const ElementContent = (props: Props) => {
const expressionsService = useExpressionsService();
const selectedPageId = useSelector(getSelectedPage);
const backgroundColor =
useSelector((state: State) => getPageById(state, selectedPageId)?.style.background) || '';
const { renderable } = props;

const renderFunction = renderable ? expressionsService.getRenderer(renderable.as) : null;

return <Component {...{ ...props, renderFunction, backgroundColor }} />;
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@
import React from 'react';
import PropTypes from 'prop-types';

export const InvalidElementType = ({ renderableType, selectElement }) => (
export interface Props {
renderableType: string;
selectElement: () => void;
}

export const InvalidElementType = ({ renderableType, selectElement }: Props) => (
<h3 onClick={selectElement}>Element not found: {renderableType}</h3>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@
import React from 'react';
import PropTypes from 'prop-types';

export const InvalidExpression = ({ selectElement }) => (
export interface Props {
selectElement: () => void;
}

export const InvalidExpression = ({ selectElement }: Props) => (
<h3 onClick={selectElement}>Invalid expression</h3>
);

Expand Down
6 changes: 3 additions & 3 deletions x-pack/plugins/canvas/public/components/expression/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import React, { FC, useState, useCallback, useMemo, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fromExpression } from '@kbn/interpreter/common';
import { useServices } from '../../services';
import { useExpressionsService } from '../../services';
import { getSelectedPage, getSelectedElement } from '../../state/selectors/workpad';
// @ts-expect-error
import { setExpression, flushContext } from '../../state/actions/elements';
Expand Down Expand Up @@ -45,7 +45,7 @@ export const Expression: FC<ExpressionProps> = ({ done }) => {
};

const ExpressionContainer: FC<ExpressionContainerProps> = ({ done, element, pageId }) => {
const services = useServices();
const expressions = useExpressionsService();
const dispatch = useDispatch();
const [isCompact, setCompact] = useState<boolean>(true);
const toggleCompactView = useCallback(() => {
Expand Down Expand Up @@ -114,7 +114,7 @@ const ExpressionContainer: FC<ExpressionContainerProps> = ({ done, element, page
<Component
done={done}
isCompact={isCompact}
functionDefinitions={Object.values(services.expressions.getFunctions())}
functionDefinitions={Object.values(expressions.getFunctions())}
formState={formState}
setExpression={onSetExpression}
toggleCompactView={toggleCompactView}
Expand Down
15 changes: 5 additions & 10 deletions x-pack/plugins/canvas/public/lib/run_interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import { fromExpression, getType } from '@kbn/interpreter/common';
import { pluck } from 'rxjs/operators';
import { ExpressionValue, ExpressionAstExpression } from 'src/plugins/expressions/public';
import { pluginServices, expressionsService } from '../services';
import { pluginServices } from '../services';

interface Options {
castToRender?: boolean;
Expand All @@ -22,12 +22,8 @@ export async function interpretAst(
variables: Record<string, any>
): Promise<ExpressionValue> {
const context = { variables };
return await expressionsService
.getService()
.execute(ast, null, context)
.getData()
.pipe(pluck('result'))
.toPromise();
const { execute } = pluginServices.getServices().expressions;
return await execute(ast, null, context).getData().pipe(pluck('result')).toPromise();
}

/**
Expand All @@ -49,9 +45,8 @@ export async function runInterpreter(
const context = { variables };

try {
const renderable = await expressionsService
.getService()
.execute(ast, input, context)
const { execute } = pluginServices.getServices().expressions;
const renderable = await execute(ast, input, context)
.getData()
.pipe(pluck('result'))
.toPromise();
Expand Down
8 changes: 7 additions & 1 deletion x-pack/plugins/canvas/public/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { Start as InspectorStart } from '../../../../src/plugins/inspector/publi
import { BfetchPublicSetup } from '../../../../src/plugins/bfetch/public';
import { PresentationUtilPluginStart } from '../../../../src/plugins/presentation_util/public';
import { getPluginApi, CanvasApi } from './plugin_api';
import { setupExpressions } from './setup_expressions';
import { pluginServiceRegistry } from './services/kibana';

export { CoreStart, CoreSetup };
Expand Down Expand Up @@ -87,12 +88,15 @@ export class CanvasPlugin
const lastPath = getSessionStorage().get(
`${SESSIONSTORAGE_LASTPATH}:${coreSetup.http.basePath.get()}`
);

if (lastPath) {
this.appUpdater.next(() => ({
defaultPath: `#${lastPath}`,
}));
}

setupExpressions({ coreSetup, setupPlugins });

coreSetup.application.register({
category: DEFAULT_APP_CATEGORIES.kibana,
id: 'canvas',
Expand Down Expand Up @@ -124,7 +128,8 @@ export class CanvasPlugin
setupPlugins,
startPlugins,
registries,
this.appUpdater
this.appUpdater,
pluginServices
);

const unmount = renderApp({ coreStart, startPlugins, params, canvasStore, pluginServices });
Expand All @@ -145,6 +150,7 @@ export class CanvasPlugin
const { argTypeSpecs } = await import('./expression_types/arg_types');
return argTypeSpecs;
});

canvasApi.addTransitions(async () => {
const { transitions } = await import('./transitions');
return transitions;
Expand Down
10 changes: 10 additions & 0 deletions x-pack/plugins/canvas/public/services/expressions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { ExpressionsService } from '../../../../../src/plugins/expressions/public';

export type CanvasExpressionsService = ExpressionsService;
Loading

0 comments on commit 9ff5def

Please sign in to comment.