Skip to content

Commit

Permalink
[Canvas] Expression shape (#103219)
Browse files Browse the repository at this point in the history
* expression_reveal_image skeleton.

* expression_functions added.

* expression_renderers added.

* Backup of daily work.

* Fixed errors.

* Added legacy support. Added button for legacy.

* Added storybook.

* Removed revealImage from canvas.

* Types fixed.

* Fixed test suite error.

* Fixed eslint error.

* Moved UI and elements, related to expressionRevealImage from canvas.

* Fixed unused translations errors.

* Moved type of element to types.

* Fixed types and added service for representing elements, ui and supported renderers to canvas.

* Added expression registration to canvas.

* Fixed

* Fixed mutiple call of the function.

* Removed support of a legacy lib for revealImage chart.

* Removed legacy presentation_utils plugin import.

* Removed useless translations and tried to fix error.

* One more fix.

* Small imports fix.

* Fixed translations.

* Made fixes based on nits.

* Removed useless params.

* fix.

* Fixed errors, related to jest and __mocks__.

* Removed useless type definition.

* Replaced RendererHandlers with IInterpreterRendererHandlers.

* fixed supported_shareable.

* Moved elements back to canvas.

* Moved views to canvas, removed expression service and imported renderer to canvas.

* Fixed translations.

* Moved libs to presentation utils.

* Fixed types and removed function_wrapper.ts

* Fixed types of test helpers.

* Fixed imports.

* One more fix.

* Fixed public API.

* Moved css to component.

* Fixed spaces at element.

* Removed unused plugin.

* Basic setup of error plugin.

* Removed not used `function` files at `error` expression.

* Moved related components from canvas.

* Changed imports of components.

* Removed useless translations and fixed .i18nrc.json

* More fixes of i18nrc.

* Fixed async functions.

Written current code, based on storybookjs/storybook#7745

* Fixed one test with Expression input.

After changing the way of rendering in stories, all elements are mounting and componentDidMount is involved. The previous snapshot was without
mounted `monaco` editor.

* generated plugin and copied code from expression_reveal_image

* fixed double import after merge.

* Changed all names from reveal_image to shape.

* moved shape to plugin and added all necessary configs

* Fixed translations, fixed all imports and debug of svg.

* `function` moved to `server`.

* One shape is rewritten to `React` and rendering is written with passing necessary props.

* changed default width and heigth.

* Added `ShapeHOC`.

* Shapes changed.

* small refactor.

* Removed useless import.

* one more refactor.

* Refactor + fix errors + updated limits.

* Changed ShapePreview from pure js to react and removed `dangerouslySetInnerHTML`

* Fixed types of viewbox.

* Changed types source for Shape components.

* small refactor.

* Fixed imports.

* Removed `shape` from `canvas`

* Updated docs.

* Basic setup of error plugin.

* Removed not used `function` files at `error` expression.

* Changed imports of components.

* Fixed errors, related to shape and autosuggestions.

* Fixed i18n for shape.

* Moved function from public to common and registered at server.

* Fixed types error.

* Fixed snapshots and shape mocks.

* Moved some libs from `presentations_util` to `expression_shape`

* Shape refactored.

* Shape picker fixed.

* Moved `Popover` back to `canvas`

* Removed `Popover` export from presentation_utils components.

* Moved error_component and debug_component from presentation_util to expression_error.

* Removed `.i18nrc.json`.

* Removed `.i18nrc.json`.

* Removed useless scss.

* Fixed color of `error`.

* added fixes of rebase.

* More fixes of rebase error .

* Removed useless .i18nrc.json file.

* More fixes.

* More fixes of rebase.

* One more fix.

* More fixes.

* Fixed limits and translations.

* Added.

* Fixed i18nrc.

* Fixed error..

* Moved shapes to async chunks.

* One more fix.

* Some fixes.

* Trying to fix the typecheck error.

* Added temp of drawer.

* Moved shapes to the async chunk in a less complex way.

* Made `ShapeDrawer` reusable among different `expressions`.

* Changed type of `shapes` from `any` and `Shape` to `string`.

* Made changes, based on nits.

* Removed not necessary changes.

* Moved all reusable libs to `expression_shapes`.

* Reduced the size of the bundle.

* Hope, fixed type check errors.

* Removed getDefaultShapeData.

* Removed `getViewBox` from bundle.
  • Loading branch information
Kuznietsov authored Jul 21, 2021
1 parent 8460035 commit 473b6aa
Show file tree
Hide file tree
Showing 100 changed files with 1,852 additions and 490 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,7 @@ module.exports = {
'!(src|x-pack)/plugins/**/(public|server)/mocks/index.{js,mjs,ts}',
'!(src|x-pack)/plugins/**/(public|server)/(index|mocks).{js,mjs,ts,tsx}',
'!(src|x-pack)/plugins/**/__stories__/index.{js,mjs,ts,tsx}',
'!(src|x-pack)/plugins/**/__fixtures__/index.{js,mjs,ts,tsx}',
],
allowSameFolder: true,
errorMessage: 'Plugins may only import from top-level public and server modules.',
Expand Down
1 change: 1 addition & 0 deletions .i18nrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"expressions": "src/plugins/expressions",
"expressionError": "src/plugins/expression_error",
"expressionRevealImage": "src/plugins/expression_reveal_image",
"expressionShape": "src/plugins/expression_shape",
"inputControl": "src/plugins/input_control_vis",
"inspector": "src/plugins/inspector",
"inspectorViews": "src/legacy/core_plugins/inspector_views",
Expand Down
4 changes: 4 additions & 0 deletions docs/developer/plugin-list.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ want to incorporate their own functions, types, and renderers into the service
for use in their own application.
|{kib-repo}blob/{branch}/src/plugins/expression_shape/README.md[expressionShape]
|Expression Shape plugin adds a shape function to the expression plugin and an associated renderer. The renderer will display the given shape with selected decorations.
|{kib-repo}blob/{branch}/src/plugins/home/README.md[home]
|Moves the legacy ui/registry/feature_catalogue module for registering "features" that should be shown in the home page's feature catalogue to a service within a "home" plugin. The feature catalogue refered to here should not be confused with the "feature" plugin for registering features used to derive UI capabilities for feature controls.
Expand Down
1 change: 1 addition & 0 deletions packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,4 @@ pageLoadAssetSize:
cases: 144442
expressionError: 22127
userSetup: 18532
expressionShape: 30033
1 change: 1 addition & 0 deletions src/dev/storybook/aliases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const storybookAliases = {
embeddable: 'src/plugins/embeddable/.storybook',
expression_error: 'src/plugins/expression_error/.storybook',
expression_reveal_image: 'src/plugins/expression_reveal_image/.storybook',
expression_shape: 'src/plugins/expression_shape/.storybook',
infra: 'x-pack/plugins/infra/.storybook',
security_solution: 'x-pack/plugins/security_solution/.storybook',
ui_actions_enhanced: 'x-pack/plugins/ui_actions_enhanced/.storybook',
Expand Down
10 changes: 10 additions & 0 deletions src/plugins/expression_shape/.storybook/main.js
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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

// eslint-disable-next-line import/no-commonjs
module.exports = require('@kbn/storybook').defaultConfig;
9 changes: 9 additions & 0 deletions src/plugins/expression_shape/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# expressionShape

Expression Shape plugin adds a `shape` function to the expression plugin and an associated renderer. The renderer will display the given shape with selected decorations.

---

## Development

See the [kibana contributing guide](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md) for instructions setting up your development environment.
12 changes: 12 additions & 0 deletions src/plugins/expression_shape/__fixtures__/function_specs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { shapeFunction } from '../common/expression_functions';
import { ExpressionFunction } from '../../../../src/plugins/expressions';

export const functionSpecs = [shapeFunction].map((fn) => new ExpressionFunction(fn()));
9 changes: 9 additions & 0 deletions src/plugins/expression_shape/__fixtures__/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

export * from './function_specs';
11 changes: 11 additions & 0 deletions src/plugins/expression_shape/common/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

export const PLUGIN_ID = 'expressionShape';
export const PLUGIN_NAME = 'expressionShape';
export const SVG = 'SVG';
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

export { shapeFunction } from './shape_function';
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { i18n } from '@kbn/i18n';
import { ExpressionShapeFunction, Shape } from '../types';
import { SVG } from '../constants';
import { getAvailableShapes } from '../lib';

export const strings = {
help: i18n.translate('expressionShape.functions.shapeHelpText', {
defaultMessage: 'Creates a shape.',
}),
args: {
shape: i18n.translate('expressionShape.functions.shape.args.shapeHelpText', {
defaultMessage: 'Pick a shape.',
}),
border: i18n.translate('expressionShape.functions.shape.args.borderHelpText', {
defaultMessage: 'An {SVG} color for the border outlining the shape.',
values: {
SVG,
},
}),
borderWidth: i18n.translate('expressionShape.functions.shape.args.borderWidthHelpText', {
defaultMessage: 'The thickness of the border.',
}),
fill: i18n.translate('expressionShape.functions.shape.args.fillHelpText', {
defaultMessage: 'An {SVG} color to fill the shape.',
values: {
SVG,
},
}),
maintainAspect: i18n.translate('expressionShape.functions.shape.args.maintainAspectHelpText', {
defaultMessage: `Maintain the shape's original aspect ratio?`,
}),
},
};

export const errors = {
invalidShape: (shape: string) =>
new Error(
i18n.translate('expressionShape.functions.shape.invalidShapeErrorMessage', {
defaultMessage: "Invalid value: '{shape}'. Such a shape doesn't exist.",
values: {
shape,
},
})
),
};

export const shapeFunction: ExpressionShapeFunction = () => {
const { help, args: argHelp } = strings;

return {
name: 'shape',
aliases: [],
inputTypes: ['null'],
help,
args: {
shape: {
types: ['string'],
help: argHelp.shape,
aliases: ['_'],
default: 'square',
options: Object.values(Shape),
},
border: {
types: ['string'],
aliases: ['stroke'],
help: argHelp.border,
},
borderWidth: {
types: ['number'],
aliases: ['strokeWidth'],
help: argHelp.borderWidth,
default: 0,
},
fill: {
types: ['string'],
help: argHelp.fill,
default: 'black',
},
maintainAspect: {
types: ['boolean'],
help: argHelp.maintainAspect,
default: false,
options: [true, false],
},
},
fn: (input, args) => {
const avaliableShapes = getAvailableShapes();
if (!avaliableShapes.includes(args.shape)) {
throw errors.invalidShape(args.shape);
}

return {
type: 'shape',
...args,
};
},
};
};
12 changes: 12 additions & 0 deletions src/plugins/expression_shape/common/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

export * from './constants';
export * from './types';

export { getAvailableShapes } from './lib/available_shapes';
11 changes: 11 additions & 0 deletions src/plugins/expression_shape/common/lib/available_shapes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { Shape } from '../types';

export const getAvailableShapes = () => Object.values(Shape);
10 changes: 10 additions & 0 deletions src/plugins/expression_shape/common/lib/index.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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

export * from './view_box';
export * from './available_shapes';
52 changes: 52 additions & 0 deletions src/plugins/expression_shape/common/lib/view_box.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { ParentNodeParams, ViewBoxParams } from '../types';

export function viewBoxToString(viewBox?: ViewBoxParams): undefined | string {
if (!viewBox) return;
return `${viewBox?.minX} ${viewBox?.minY} ${viewBox?.width} ${viewBox?.height}`;
}

function getMinxAndWidth(viewBoxParams: ViewBoxParams, { borderOffset, width }: ParentNodeParams) {
let { minX, width: shapeWidth } = viewBoxParams;
if (width) {
const xOffset = (shapeWidth / width) * borderOffset;
minX -= xOffset;
shapeWidth += xOffset * 2;
} else {
shapeWidth = 0;
}

return [minX, shapeWidth];
}

function getMinyAndHeight(
viewBoxParams: ViewBoxParams,
{ borderOffset, height }: ParentNodeParams
) {
let { minY, height: shapeHeight } = viewBoxParams;
if (height) {
const yOffset = (shapeHeight / height) * borderOffset;
minY -= yOffset;
shapeHeight += yOffset * 2;
} else {
shapeHeight = 0;
}

return [minY, shapeHeight];
}

export function getViewBox(
viewBoxParams: ViewBoxParams,
parentNodeParams: ParentNodeParams
): ViewBoxParams {
const [minX, width] = getMinxAndWidth(viewBoxParams, parentNodeParams);
const [minY, height] = getMinyAndHeight(viewBoxParams, parentNodeParams);
return { minX, minY, width, height };
}
46 changes: 46 additions & 0 deletions src/plugins/expression_shape/common/types/expression_functions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { ExpressionFunctionDefinition } from 'src/plugins/expressions';

export enum Shape {
ARROW = 'arrow',
ARROW_MULTI = 'arrowMulti',
BOOKMARK = 'bookmark',
CIRCLE = 'circle',
CROSS = 'cross',
HEXAGON = 'hexagon',
KITE = 'kite',
PENTAGON = 'pentagon',
RHOMBUS = 'rhombus',
SEMICIRCLE = 'semicircle',
SPEECH_BUBBLE = 'speechBubble',
SQUARE = 'square',
STAR = 'star',
TAG = 'tag',
TRIANGLE = 'triangle',
TRIANGLE_RIGHT = 'triangleRight',
}

interface Arguments {
border: string;
borderWidth: number;
shape: Shape;
fill: string;
maintainAspect: boolean;
}

export interface Output extends Arguments {
type: 'shape';
}

export type ExpressionShapeFunction = () => ExpressionFunctionDefinition<
'shape',
number | null,
Arguments,
Output
>;
35 changes: 35 additions & 0 deletions src/plugins/expression_shape/common/types/expression_renderers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { Shape } from './expression_functions';

export type OriginString = 'bottom' | 'left' | 'top' | 'right';
export interface ShapeRendererConfig {
border: string;
borderWidth: number;
shape: Shape;
fill: string;
maintainAspect: boolean;
}

export interface NodeDimensions {
width: number;
height: number;
}

export interface ParentNodeParams {
borderOffset: number;
width: number;
height: number;
}

export interface ViewBoxParams {
minX: number;
minY: number;
width: number;
height: number;
}
9 changes: 9 additions & 0 deletions src/plugins/expression_shape/common/types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
export * from './expression_functions';
export * from './expression_renderers';
Loading

0 comments on commit 473b6aa

Please sign in to comment.