Skip to content

Commit

Permalink
[Canvas] Expression reveal image. Async libs and images loading. (ela…
Browse files Browse the repository at this point in the history
…stic#103399) (elastic#106103)

* Added lazy loading of async libs to storybook.

* Refactored lazy loading of import for a storybook.

* more refactoring stuff.

* more refactoring.

* small refactor of waitFor.

* Added support of async functions.

* Types fix.

* fixed docs.

* Fixed some mistakes.

* Fixed type of tests.

* added type for async function to write dicts easier.

* Updated stories and view with async image.

* Changed all static to  async imports.

* Removed static import of `elasticLogo`. Fixed type error.

* Changed way of returning async functions in `functionWrapper`.

* fixed renderer test.

* fixed errors.

* added outline and fixed types.

* added outline everywhere.

* waitFor fixed.

* removed useless exports.

* Fixed type error.

* fixed types of dropdown_control.test.ts

* fixed `csv.test.ts` types.

* Tests fixed.

* Fixed storybooks.

* Fixed failed tests.

* [Canvas] Expression reveal image. (elastic#101987)

* 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.

* setState while rendering error fixed.

* tsconfig.json added.

* jest.config.js added.

* Demo doc added.

* Types fixed.

* added limits.

* Removed not used imports.

* i18n namespaces fixed.

* Fixed test suite error.

* Some errors fixed.

* Fixed eslint error.

* Removed more unused translations.

* 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.

* Doc error fixed.

* 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.

* Types fix.

* Moved libs to presentation utils.

* Fixed one mistake.

* removed dataurl lib.

* Fixed jest files.

* elasticLogo removed.

* Removed elastic_outline.

* removed httpurl.

* Removed missing_asset.

* removed url.

* replaced mostly all tests.

* Fixed types.

* Fixed types and removed function_wrapper.ts

* Fixed types of test helpers.

* Changed limits of presentationUtil plugin.

* Fixed imports.

* One more fix.

* Fixed huge size of bundle.

* Reduced allow limit for presentationUtil

* Updated limits for presentationUtil.

* Fixed public API.

* fixed type errors.

* Moved css to component.

* Fixed spaces at element.

* Changed order of requiredPlugins.

* Updated limits.

* Removed unused plugin.

* Added rule for allowing import from __stories__ directory.

* removed useless comment.

* Changed readme.md

* Fixed docs error.

* A possible of smoke test.

* onResize changed to useResizeObserver.

* Remove useless events and `useEffect` block.

* Changed from passing handlers to separate functions.

* `function` moved to `server`.

* Fixed eslint error.

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>

* Fixed mistake of merge.

* Storybook fixed.

* Fixed a mistake that occurred while resolving merge conflicts.

* removed registerFunctionAsync and changed functionWrapper from async to sync. + RepeatImageFunction.

* Fixed async functionWrapper usage and fixed `image.test.js` to run.

* Added default value for image.

* More fixes of async.

* Fixed a lot of legacy.

* Type fixes.

* Fix of fallen tests.

* First part of suggestions completed.

* Made image required.

* Removed useless `async`

* Jest test fixed.

* Fixed code, based on nits.

* Moved to `emotion`.

* Fixed prettier error.

* replaced jsx pragma with react.

* Removed unused jsx.

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>

Co-authored-by: Yaroslav Kuznietsov <kuznetsov.yaroslav.yk@gmail.com>
  • Loading branch information
kibanamachine and Kuznietsov authored Jul 19, 2021
1 parent 735c04d commit c80f0f7
Show file tree
Hide file tree
Showing 67 changed files with 758 additions and 627 deletions.
3 changes: 3 additions & 0 deletions src/plugins/expression_reveal_image/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@
*/
export const PLUGIN_ID = 'expressionRevealImage';
export const PLUGIN_NAME = 'expressionRevealImage';

export const BASE64 = '`base64`';
export const URL = 'URL';
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,26 @@

import {
functionWrapper,
elasticOutline,
elasticLogo,
getElasticOutline,
getElasticLogo,
} from '../../../presentation_util/common/lib';
import { getFunctionErrors } from '../i18n';
import { revealImageFunction } from './reveal_image_function';
import { revealImageFunction, errors } from './reveal_image_function';
import { Origin } from '../types';
import { ExecutionContext } from 'src/plugins/expressions';

const errors = getFunctionErrors().revealImage;

describe('revealImageFunction', () => {
const fn = functionWrapper(revealImageFunction);

it('returns a render as revealImage', () => {
const result = fn(
let elasticLogo = '';
let elasticOutline = '';

beforeEach(async () => {
elasticLogo = (await getElasticLogo()).elasticLogo;
elasticOutline = (await getElasticOutline()).elasticOutline;
});

it('returns a render as revealImage', async () => {
const result = await fn(
0.5,
{
image: null,
Expand All @@ -36,130 +41,147 @@ describe('revealImageFunction', () => {
});

describe('context', () => {
it('throws when context is not a number between 0 and 1', () => {
expect(() => {
fn(
10,
{
image: elasticLogo,
emptyImage: elasticOutline,
origin: Origin.TOP,
},
{} as ExecutionContext
);
}).toThrow(new RegExp(errors.invalidPercent(10).message));
it('throws when context is not a number between 0 and 1', async () => {
expect.assertions(2);
await fn(
10,
{
image: elasticLogo,
emptyImage: elasticOutline,
origin: Origin.TOP,
},
{} as ExecutionContext
).catch((e: any) => {
expect(e.message).toMatch(new RegExp(errors.invalidPercent(10).message));
});

expect(() => {
fn(
-0.1,
{
image: elasticLogo,
emptyImage: elasticOutline,
origin: Origin.TOP,
},
{} as ExecutionContext
);
}).toThrow(new RegExp(errors.invalidPercent(-0.1).message));
await fn(
-0.1,
{
image: elasticLogo,
emptyImage: elasticOutline,
origin: Origin.TOP,
},
{} as ExecutionContext
).catch((e: any) => {
expect(e.message).toMatch(new RegExp(errors.invalidPercent(-0.1).message));
});
});
});

describe('args', () => {
describe('image', () => {
it('sets the image', () => {
const result = fn(
0.89,
{
emptyImage: null,
origin: Origin.TOP,
image: elasticLogo,
},
{} as ExecutionContext
it('sets the image', async () => {
const result = (
await fn(
0.89,
{
emptyImage: null,
origin: Origin.TOP,
image: elasticLogo,
},
{} as ExecutionContext
)
).value;
expect(result).toHaveProperty('image', elasticLogo);
});

it('defaults to the Elastic outline logo', () => {
const result = fn(
0.89,
{
emptyImage: null,
origin: Origin.TOP,
image: null,
},
{} as ExecutionContext
it('defaults to the Elastic outline logo', async () => {
const result = (
await fn(
0.89,
{
emptyImage: null,
origin: Origin.TOP,
image: null,
},
{} as ExecutionContext
)
).value;
expect(result).toHaveProperty('image', elasticOutline);
});
});

describe('emptyImage', () => {
it('sets the background image', () => {
const result = fn(
0,
{
emptyImage: elasticLogo,
origin: Origin.TOP,
image: null,
},
{} as ExecutionContext
it('sets the background image', async () => {
const result = (
await fn(
0,
{
emptyImage: elasticLogo,
origin: Origin.TOP,
image: null,
},
{} as ExecutionContext
)
).value;
expect(result).toHaveProperty('emptyImage', elasticLogo);
});

it('sets emptyImage to null', () => {
const result = fn(
0,
{
emptyImage: null,
origin: Origin.TOP,
image: null,
},
{} as ExecutionContext
it('sets emptyImage to null', async () => {
const result = (
await fn(
0,
{
emptyImage: null,
origin: Origin.TOP,
image: null,
},
{} as ExecutionContext
)
).value;
expect(result).toHaveProperty('emptyImage', null);
});
});

describe('origin', () => {
it('sets which side to start the reveal from', () => {
let result = fn(
1,
{
emptyImage: null,
origin: Origin.TOP,
image: null,
},
{} as ExecutionContext
it('sets which side to start the reveal from', async () => {
let result = (
await fn(
1,
{
emptyImage: null,
origin: Origin.TOP,
image: null,
},
{} as ExecutionContext
)
).value;
expect(result).toHaveProperty('origin', 'top');
result = fn(
1,
{
emptyImage: null,
origin: Origin.LEFT,
image: null,
},
{} as ExecutionContext
result = (
await fn(
1,
{
emptyImage: null,
origin: Origin.LEFT,
image: null,
},
{} as ExecutionContext
)
).value;
expect(result).toHaveProperty('origin', 'left');
result = fn(
1,
{
emptyImage: null,
origin: Origin.BOTTOM,
image: null,
},
{} as ExecutionContext
result = (
await fn(
1,
{
emptyImage: null,
origin: Origin.BOTTOM,
image: null,
},
{} as ExecutionContext
)
).value;
expect(result).toHaveProperty('origin', 'bottom');
result = fn(
1,
{
emptyImage: null,
origin: Origin.RIGHT,
image: null,
},
{} as ExecutionContext
result = (
await fn(
1,
{
emptyImage: null,
origin: Origin.RIGHT,
image: null,
},
{} as ExecutionContext
)
).value;
expect(result).toHaveProperty('origin', 'right');
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,77 @@
* Side Public License, v 1.
*/

import { resolveWithMissingImage, elasticOutline } from '../../../presentation_util/common/lib';
import { getFunctionHelp, getFunctionErrors } from '../i18n';
import { ExpressionRevealImageFunction, Origin } from '../types';
import { i18n } from '@kbn/i18n';
import {
resolveWithMissingImage,
getElasticOutline,
isValidUrl,
} from '../../../presentation_util/common/lib';
import { ExpressionRevealImageFunction, Origin, Position } from '../../common/types';
import { BASE64, URL } from '../../common/constants';

const strings = {
help: i18n.translate('expressionRevealImage.functions.revealImageHelpText', {
defaultMessage: 'Configures an image reveal element.',
}),
args: {
image: i18n.translate('expressionRevealImage.functions.revealImage.args.imageHelpText', {
defaultMessage:
'The image to reveal. Provide an image asset as a {BASE64} data {URL}, ' +
'or pass in a sub-expression.',
values: {
BASE64,
URL,
},
}),
emptyImage: i18n.translate(
'expressionRevealImage.functions.revealImage.args.emptyImageHelpText',
{
defaultMessage:
'An optional background image to reveal over. ' +
'Provide an image asset as a `{BASE64}` data {URL}, or pass in a sub-expression.',
values: {
BASE64,
URL,
},
}
),
origin: i18n.translate('expressionRevealImage.functions.revealImage.args.originHelpText', {
defaultMessage: 'The position to start the image fill. For example, {list}, or {end}.',
values: {
list: Object.values(Position)
.slice(0, -1)
.map((position) => `\`"${position}"\``)
.join(', '),
end: Object.values(Position).slice(-1)[0],
},
}),
},
};

export const errors = {
invalidPercent: (percent: number) =>
new Error(
i18n.translate('expressionRevealImage.functions.revealImage.invalidPercentErrorMessage', {
defaultMessage: "Invalid value: '{percent}'. Percentage must be between 0 and 1",
values: {
percent,
},
})
),
invalidImageUrl: (imageUrl: string) =>
new Error(
i18n.translate('expressionRevealImage.functions.revealImage.invalidImageUrl', {
defaultMessage: "Invalid image url: '{imageUrl}'.",
values: {
imageUrl,
},
})
),
};

export const revealImageFunction: ExpressionRevealImageFunction = () => {
const { help, args: argHelp } = getFunctionHelp().revealImage;
const errors = getFunctionErrors().revealImage;
const { help, args: argHelp } = strings;

return {
name: 'revealImage',
Expand All @@ -24,7 +88,7 @@ export const revealImageFunction: ExpressionRevealImageFunction = () => {
image: {
types: ['string', 'null'],
help: argHelp.image,
default: elasticOutline,
default: null,
},
emptyImage: {
types: ['string', 'null'],
Expand All @@ -38,11 +102,16 @@ export const revealImageFunction: ExpressionRevealImageFunction = () => {
options: Object.values(Origin),
},
},
fn: (percent, args) => {
fn: async (percent, args) => {
if (percent > 1 || percent < 0) {
throw errors.invalidPercent(percent);
}

if (args.image && !isValidUrl(args.image)) {
throw errors.invalidImageUrl(args.image);
}

const { elasticOutline } = await getElasticOutline();
return {
type: 'render',
as: 'revealImage',
Expand Down
Loading

0 comments on commit c80f0f7

Please sign in to comment.