Skip to content

Commit

Permalink
[Canvas] Canvas embeddable (#39839)
Browse files Browse the repository at this point in the history
* Adds embeddable objects to canvas

* Handle embeddable_api -> NewPlatform changes

* Addressing PR feedback

* Properly mock new platform

* Snake case filenames{

* Switch relative paths to src/
  • Loading branch information
Corey Robertson authored Aug 21, 2019
1 parent 6ab5be1 commit 54e2edc
Show file tree
Hide file tree
Showing 29 changed files with 862 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { ExpressionType } from 'src/plugins/data/common/expressions';
import { EmbeddableInput } from 'src/legacy/core_plugins/embeddable_api/public/np_ready/public';
import { EmbeddableTypes } from './embeddable_types';

export const EmbeddableExpressionType = 'embeddable';
export { EmbeddableTypes };

export interface EmbeddableExpression<Input extends EmbeddableInput> {
type: typeof EmbeddableExpressionType;
input: Input;
embeddableType: string;
}

export const embeddableType = (): ExpressionType<
typeof EmbeddableExpressionType,
EmbeddableExpression<any>
> => ({
name: EmbeddableExpressionType,
to: {
render: (embeddableExpression: EmbeddableExpression<any>) => {
return {
type: 'render',
as: EmbeddableExpressionType,
value: embeddableExpression,
};
},
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

// @ts-ignore
import { MAP_SAVED_OBJECT_TYPE } from '../../../maps/common/constants';
import { SEARCH_EMBEDDABLE_TYPE } from '../../../../../../src/legacy/core_plugins/kibana/public/discover/embeddable/search_embeddable';
import { VISUALIZE_EMBEDDABLE_TYPE } from '../../../../../../src/legacy/core_plugins/kibana/public/visualize/embeddable';

export const EmbeddableTypes = {
map: MAP_SAVED_OBJECT_TYPE,
search: SEARCH_EMBEDDABLE_TYPE,
visualization: VISUALIZE_EMBEDDABLE_TYPE,
};
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;
* you may not use this file except in compliance with the Elastic License.
*/

import { embeddableType } from './embeddable';

export * from './embeddable';

export const typeFunctions = [embeddableType];
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ import { rounddate } from './rounddate';
import { rowCount } from './rowCount';
import { repeatImage } from './repeatImage';
import { revealImage } from './revealImage';
import { savedMap } from './saved_map';
import { savedSearch } from './saved_search';
import { savedVisualization } from './saved_visualization';
import { seriesStyle } from './seriesStyle';
import { shape } from './shape';
import { sort } from './sort';
Expand Down Expand Up @@ -103,6 +106,9 @@ export const functions = [
revealImage,
rounddate,
rowCount,
savedMap,
savedSearch,
savedVisualization,
seriesStyle,
shape,
sort,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
jest.mock('ui/new_platform');
import { savedMap } from './saved_map';
import { buildEmbeddableFilters } from '../../../server/lib/build_embeddable_filters';

const filterContext = {
and: [
{ and: [], value: 'filter-value', column: 'filter-column', type: 'exactly' },
{
and: [],
column: 'time-column',
type: 'time',
from: '2019-06-04T04:00:00.000Z',
to: '2019-06-05T04:00:00.000Z',
},
],
};

describe('savedMap', () => {
const fn = savedMap().fn;
const args = {
id: 'some-id',
};

it('accepts null context', () => {
const expression = fn(null, args, {});

expect(expression.input.filters).toEqual([]);
expect(expression.input.timeRange).toBeUndefined();
});

it('accepts filter context', () => {
const expression = fn(filterContext, args, {});
const embeddableFilters = buildEmbeddableFilters(filterContext.and);

expect(expression.input.filters).toEqual(embeddableFilters.filters);
expect(expression.input.timeRange).toEqual(embeddableFilters.timeRange);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { Filter as ESFilterType } from '@kbn/es-query';
import { ExpressionFunction } from 'src/legacy/core_plugins/interpreter/public';
import { TimeRange } from 'ui/timefilter/time_history';
import { EmbeddableInput } from 'src/legacy/core_plugins/embeddable_api/public/np_ready/public';
import { buildEmbeddableFilters } from '../../../server/lib/build_embeddable_filters';
import { Filter } from '../../../types';
import {
EmbeddableTypes,
EmbeddableExpressionType,
EmbeddableExpression,
} from '../../expression_types';
import { getFunctionHelp } from '../../strings';

interface Arguments {
id: string;
}

// Map embeddable is missing proper typings, so type is just to document what we
// are expecting to pass to the embeddable
interface SavedMapInput extends EmbeddableInput {
id: string;
timeRange?: TimeRange;
refreshConfig: {
isPaused: boolean;
interval: number;
};
filters: ESFilterType[];
}

type Return = EmbeddableExpression<SavedMapInput>;

export function savedMap(): ExpressionFunction<'savedMap', Filter | null, Arguments, Return> {
const { help, args: argHelp } = getFunctionHelp().savedMap;
return {
name: 'savedMap',
help,
args: {
id: {
types: ['string'],
required: false,
help: argHelp.id,
},
},
type: EmbeddableExpressionType,
fn: (context, { id }) => {
const filters = context ? context.and : [];

return {
type: EmbeddableExpressionType,
input: {
id,
...buildEmbeddableFilters(filters),

refreshConfig: {
isPaused: false,
interval: 0,
},
},
embeddableType: EmbeddableTypes.map,
};
},
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
jest.mock('ui/new_platform');
import { savedSearch } from './saved_search';
import { buildEmbeddableFilters } from '../../../server/lib/build_embeddable_filters';

const filterContext = {
and: [
{ and: [], value: 'filter-value', column: 'filter-column', type: 'exactly' },
{
and: [],
column: 'time-column',
type: 'time',
from: '2019-06-04T04:00:00.000Z',
to: '2019-06-05T04:00:00.000Z',
},
],
};

describe('savedSearch', () => {
const fn = savedSearch().fn;
const args = {
id: 'some-id',
};

it('accepts null context', () => {
const expression = fn(null, args, {});

expect(expression.input.filters).toEqual([]);
expect(expression.input.timeRange).toBeUndefined();
});

it('accepts filter context', () => {
const expression = fn(filterContext, args, {});
const embeddableFilters = buildEmbeddableFilters(filterContext.and);

expect(expression.input.filters).toEqual(embeddableFilters.filters);
expect(expression.input.timeRange).toEqual(embeddableFilters.timeRange);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { ExpressionFunction } from 'src/legacy/core_plugins/interpreter/public';
import { SearchInput } from 'src/legacy/core_plugins/kibana/public/discover/embeddable';
import {
EmbeddableTypes,
EmbeddableExpressionType,
EmbeddableExpression,
} from '../../expression_types';

import { buildEmbeddableFilters } from '../../../server/lib/build_embeddable_filters';
import { Filter } from '../../../types';
import { getFunctionHelp } from '../../strings';

interface Arguments {
id: string;
}

type Return = EmbeddableExpression<Partial<SearchInput> & { id: SearchInput['id'] }>;

export function savedSearch(): ExpressionFunction<'savedSearch', Filter | null, Arguments, Return> {
const { help, args: argHelp } = getFunctionHelp().savedSearch;
return {
name: 'savedSearch',
help,
args: {
id: {
types: ['string'],
required: false,
help: argHelp.id,
},
},
type: EmbeddableExpressionType,
fn: (context, { id }) => {
const filters = context ? context.and : [];
return {
type: EmbeddableExpressionType,
input: {
id,
...buildEmbeddableFilters(filters),
},
embeddableType: EmbeddableTypes.search,
};
},
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
jest.mock('ui/new_platform');
import { savedVisualization } from './saved_visualization';
import { buildEmbeddableFilters } from '../../../server/lib/build_embeddable_filters';

const filterContext = {
and: [
{ and: [], value: 'filter-value', column: 'filter-column', type: 'exactly' },
{
and: [],
column: 'time-column',
type: 'time',
from: '2019-06-04T04:00:00.000Z',
to: '2019-06-05T04:00:00.000Z',
},
],
};

describe('savedVisualization', () => {
const fn = savedVisualization().fn;
const args = {
id: 'some-id',
};

it('accepts null context', () => {
const expression = fn(null, args, {});

expect(expression.input.filters).toEqual([]);
expect(expression.input.timeRange).toBeUndefined();
});

it('accepts filter context', () => {
const expression = fn(filterContext, args, {});
const embeddableFilters = buildEmbeddableFilters(filterContext.and);

expect(expression.input.filters).toEqual(embeddableFilters.filters);
expect(expression.input.timeRange).toEqual(embeddableFilters.timeRange);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { ExpressionFunction } from 'src/legacy/core_plugins/interpreter/public';
import { VisualizeInput } from 'src/legacy/core_plugins/kibana/public/visualize/embeddable';
import {
EmbeddableTypes,
EmbeddableExpressionType,
EmbeddableExpression,
} from '../../expression_types';
import { buildEmbeddableFilters } from '../../../server/lib/build_embeddable_filters';
import { Filter } from '../../../types';
import { getFunctionHelp } from '../../strings';

interface Arguments {
id: string;
}

type Return = EmbeddableExpression<VisualizeInput>;

export function savedVisualization(): ExpressionFunction<
'savedVisualization',
Filter | null,
Arguments,
Return
> {
const { help, args: argHelp } = getFunctionHelp().savedVisualization;
return {
name: 'savedVisualization',
help,
args: {
id: {
types: ['string'],
required: false,
help: argHelp.id,
},
},
type: EmbeddableExpressionType,
fn: (context, { id }) => {
const filters = context ? context.and : [];

return {
type: EmbeddableExpressionType,
input: {
id,
...buildEmbeddableFilters(filters),
},
embeddableType: EmbeddableTypes.visualization,
};
},
};
}
Loading

0 comments on commit 54e2edc

Please sign in to comment.