From 58d335f224e5e2b750b36eaae9091aa5827a5c9b Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Wed, 11 Aug 2021 17:23:16 +0300 Subject: [PATCH] [Lens] Register all expression functions to the server (#107836) (#108175) Part of: #97134 Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../common/expressions/datatable/datatable.ts | 14 ++-- x-pack/plugins/lens/kibana.json | 1 + .../lens/public/app_plugin/lens_top_nav.tsx | 5 +- .../lens/public/app_plugin/mounter.tsx | 10 ++- .../plugins/lens/public/app_plugin/types.ts | 31 ++++---- .../expression.test.tsx | 8 +-- .../public/datatable_visualization/index.ts | 7 +- .../heatmap_visualization/expression.tsx | 5 +- .../public/heatmap_visualization/index.ts | 2 +- .../datapanel.test.tsx | 2 + .../indexpattern_datasource/datapanel.tsx | 18 +++-- .../field_item.test.tsx | 19 +++-- .../indexpattern_datasource/field_item.tsx | 6 +- .../fields_accordion.test.tsx | 7 +- .../fields_accordion.tsx | 4 +- .../public/indexpattern_datasource/index.ts | 37 ++++++---- .../indexpattern.test.ts | 3 + .../indexpattern_datasource/indexpattern.tsx | 18 +++-- .../metric_visualization/expression.tsx | 11 +-- .../lens/public/metric_visualization/index.ts | 2 +- x-pack/plugins/lens/public/mocks.tsx | 10 +-- .../public/pie_visualization/expression.tsx | 12 ++-- .../lens/public/pie_visualization/index.ts | 2 +- x-pack/plugins/lens/public/plugin.ts | 43 +++++++++-- .../public/xy_visualization/expression.tsx | 6 +- .../lens/public/xy_visualization/index.ts | 6 +- .../xy_visualization/to_expression.test.ts | 4 +- .../xy_visualization/visualization.test.ts | 6 +- .../public/xy_visualization/visualization.tsx | 10 +-- .../xy_visualization/xy_suggestions.test.ts | 8 +-- .../lens/server/expressions/expressions.ts | 71 +++++++++++++++++++ .../plugins/lens/server/expressions/index.ts | 8 +++ x-pack/plugins/lens/server/plugin.tsx | 5 ++ 33 files changed, 272 insertions(+), 129 deletions(-) create mode 100644 x-pack/plugins/lens/server/expressions/expressions.ts create mode 100644 x-pack/plugins/lens/server/expressions/index.ts diff --git a/x-pack/plugins/lens/common/expressions/datatable/datatable.ts b/x-pack/plugins/lens/common/expressions/datatable/datatable.ts index d2db63a01793ed..32f6c1c089543d 100644 --- a/x-pack/plugins/lens/common/expressions/datatable/datatable.ts +++ b/x-pack/plugins/lens/common/expressions/datatable/datatable.ts @@ -8,6 +8,7 @@ import { i18n } from '@kbn/i18n'; import { cloneDeep } from 'lodash'; import type { + ExecutionContext, DatatableColumnMeta, ExpressionFunctionDefinition, } from '../../../../../../src/plugins/expressions/common'; @@ -46,15 +47,13 @@ function isRange(meta: { params?: { id?: string } } | undefined) { return meta?.params?.id === 'range'; } -export const getDatatable = ({ - formatFactory, -}: { - formatFactory: FormatFactory; -}): ExpressionFunctionDefinition< +export const getDatatable = ( + getFormatFactory: (context: ExecutionContext) => FormatFactory | Promise +): ExpressionFunctionDefinition< 'lens_datatable', LensMultiTable, DatatableArgs, - DatatableRender + Promise > => ({ name: 'lens_datatable', type: 'render', @@ -87,12 +86,13 @@ export const getDatatable = ({ help: '', }, }, - fn(data, args, context) { + async fn(data, args, context) { let untransposedData: LensMultiTable | undefined; // do the sorting at this level to propagate it also at CSV download const [firstTable] = Object.values(data.tables); const [layerId] = Object.keys(context.inspectorAdapters.tables || {}); const formatters: Record> = {}; + const formatFactory = await getFormatFactory(context); firstTable.columns.forEach((column) => { formatters[column.id] = formatFactory(column.meta?.params); diff --git a/x-pack/plugins/lens/kibana.json b/x-pack/plugins/lens/kibana.json index 6a3e0f40c48f4a..9565bf57a315f3 100644 --- a/x-pack/plugins/lens/kibana.json +++ b/x-pack/plugins/lens/kibana.json @@ -8,6 +8,7 @@ "data", "charts", "expressions", + "fieldFormats", "inspector", "navigation", "urlForwarding", diff --git a/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx b/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx index 5f348d2a88ea08..06420051678ee4 100644 --- a/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx +++ b/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx @@ -141,6 +141,7 @@ export const LensTopNavMenu = ({ }: LensTopNavMenuProps) => { const { data, + fieldFormats, navigation, uiSettings, application, @@ -255,7 +256,7 @@ export const LensTopNavMenu = ({ content: exporters.datatableToCSV(datatable, { csvSeparator: uiSettings.get('csv:separator', ','), quoteValues: uiSettings.get('csv:quoteValues', true), - formatFactory: data.fieldFormats.deserialize, + formatFactory: fieldFormats.deserialize, escapeFormulaValues: false, }), type: exporters.CSV_MIME_TYPE, @@ -305,7 +306,7 @@ export const LensTopNavMenu = ({ activeData, attributeService, dashboardFeatureFlag.allowByValueEmbeddables, - data.fieldFormats.deserialize, + fieldFormats.deserialize, getIsByValueMode, initialInput, isLinkedToOriginatingApp, diff --git a/x-pack/plugins/lens/public/app_plugin/mounter.tsx b/x-pack/plugins/lens/public/app_plugin/mounter.tsx index 55f3e7463754e3..5a783bc4180d3f 100644 --- a/x-pack/plugins/lens/public/app_plugin/mounter.tsx +++ b/x-pack/plugins/lens/public/app_plugin/mounter.tsx @@ -46,7 +46,14 @@ export async function getLensServices( startDependencies: LensPluginStartDependencies, attributeService: () => Promise ): Promise { - const { data, navigation, embeddable, savedObjectsTagging, usageCollection } = startDependencies; + const { + data, + navigation, + embeddable, + savedObjectsTagging, + usageCollection, + fieldFormats, + } = startDependencies; const storage = new Storage(localStorage); const stateTransfer = embeddable?.getStateTransfer(); @@ -56,6 +63,7 @@ export async function getLensServices( data, storage, navigation, + fieldFormats, stateTransfer, usageCollection, savedObjectsTagging, diff --git a/x-pack/plugins/lens/public/app_plugin/types.ts b/x-pack/plugins/lens/public/app_plugin/types.ts index c482b56b70301c..b6530b90ac3f5d 100644 --- a/x-pack/plugins/lens/public/app_plugin/types.ts +++ b/x-pack/plugins/lens/public/app_plugin/types.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { History } from 'history'; -import { OnSaveProps } from 'src/plugins/saved_objects/public'; -import { +import type { History } from 'history'; +import type { OnSaveProps } from 'src/plugins/saved_objects/public'; +import type { ApplicationStart, AppMountParameters, ChromeStart, @@ -17,25 +17,27 @@ import { OverlayStart, SavedObjectsStart, } from '../../../../../src/core/public'; -import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; -import { UsageCollectionStart } from '../../../../../src/plugins/usage_collection/public'; -import { DashboardStart } from '../../../../../src/plugins/dashboard/public'; -import { LensEmbeddableInput } from '../embeddable/embeddable'; -import { NavigationPublicPluginStart } from '../../../../../src/plugins/navigation/public'; -import { LensAttributeService } from '../lens_attribute_service'; -import { IStorageWrapper } from '../../../../../src/plugins/kibana_utils/public'; -import { DashboardFeatureFlagConfig } from '../../../../../src/plugins/dashboard/public'; +import type { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; +import type { UsageCollectionStart } from '../../../../../src/plugins/usage_collection/public'; +import type { DashboardStart } from '../../../../../src/plugins/dashboard/public'; +import type { LensEmbeddableInput } from '../embeddable/embeddable'; +import type { NavigationPublicPluginStart } from '../../../../../src/plugins/navigation/public'; +import type { LensAttributeService } from '../lens_attribute_service'; +import type { IStorageWrapper } from '../../../../../src/plugins/kibana_utils/public'; +import type { DashboardFeatureFlagConfig } from '../../../../../src/plugins/dashboard/public'; import type { SavedObjectTaggingPluginStart } from '../../../saved_objects_tagging/public'; import { VisualizeFieldContext, ACTION_VISUALIZE_LENS_FIELD, } from '../../../../../src/plugins/ui_actions/public'; -import { +import type { EmbeddableEditorState, EmbeddableStateTransfer, } from '../../../../../src/plugins/embeddable/public'; -import { DatasourceMap, EditorFrameInstance, VisualizationMap } from '../types'; -import { PresentationUtilPluginStart } from '../../../../../src/plugins/presentation_util/public'; +import type { DatasourceMap, EditorFrameInstance, VisualizationMap } from '../types'; +import type { PresentationUtilPluginStart } from '../../../../../src/plugins/presentation_util/public'; +import type { FieldFormatsStart } from '../../../../../src/plugins/field_formats/public'; + export interface RedirectToOriginProps { input?: LensEmbeddableInput; isCopied?: boolean; @@ -97,6 +99,7 @@ export interface LensAppServices { overlays: OverlayStart; storage: IStorageWrapper; dashboard: DashboardStart; + fieldFormats: FieldFormatsStart; data: DataPublicPluginStart; uiSettings: IUiSettingsClient; application: ApplicationStart; diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx index 163971c4ba9fb3..b2a25cba329df9 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx @@ -5,10 +5,10 @@ * 2.0. */ -import { DatatableProps } from '../../common/expressions'; +import type { DatatableProps } from '../../common/expressions'; import type { LensMultiTable } from '../../common'; import { createMockExecutionContext } from '../../../../../src/plugins/expressions/common/mocks'; -import type { IFieldFormat } from '../../../../../src/plugins/field_formats/common'; +import type { FormatFactory } from '../../common'; import { getDatatable } from './expression'; function sampleArgs() { @@ -83,9 +83,9 @@ function sampleArgs() { describe('datatable_expression', () => { describe('datatable renders', () => { - test('it renders with the specified data and args', () => { + test('it renders with the specified data and args', async () => { const { data, args } = sampleArgs(); - const result = getDatatable({ formatFactory: (x) => x as IFieldFormat }).fn( + const result = await getDatatable(() => Promise.resolve((() => {}) as FormatFactory)).fn( data, args, createMockExecutionContext() diff --git a/x-pack/plugins/lens/public/datatable_visualization/index.ts b/x-pack/plugins/lens/public/datatable_visualization/index.ts index b4f37faf0bc005..3349f229a6048c 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/index.ts +++ b/x-pack/plugins/lens/public/datatable_visualization/index.ts @@ -17,7 +17,7 @@ interface DatatableVisualizationPluginStartPlugins { } export interface DatatableVisualizationPluginSetupPlugins { expressions: ExpressionsSetup; - formatFactory: Promise; + formatFactory: FormatFactory; editorFrame: EditorFrameSetup; charts: ChartsPluginSetup; } @@ -37,13 +37,12 @@ export class DatatableVisualization { getDatatableVisualization, } = await import('../async_services'); const palettes = await charts.palettes.getPalettes(); - const resolvedFormatFactory = await formatFactory; expressions.registerFunction(() => datatableColumn); - expressions.registerFunction(() => getDatatable({ formatFactory: resolvedFormatFactory })); + expressions.registerFunction(() => getDatatable(() => formatFactory)); expressions.registerRenderer(() => getDatatableRenderer({ - formatFactory: resolvedFormatFactory, + formatFactory, getType: core .getStartServices() .then(([_, { data: dataStart }]) => dataStart.search.aggs.types.get), diff --git a/x-pack/plugins/lens/public/heatmap_visualization/expression.tsx b/x-pack/plugins/lens/public/heatmap_visualization/expression.tsx index 27be4b9ce7fe97..98ce4b399ae8d1 100644 --- a/x-pack/plugins/lens/public/heatmap_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/heatmap_visualization/expression.tsx @@ -20,7 +20,7 @@ import type { HeatmapExpressionProps } from './types'; export { heatmapGridConfig, heatmapLegendConfig, heatmap } from '../../common/expressions'; export const getHeatmapRenderer = (dependencies: { - formatFactory: Promise; + formatFactory: FormatFactory; chartsThemeService: ChartsPluginSetup['theme']; paletteService: PaletteRegistry; timeZone: string; @@ -37,7 +37,6 @@ export const getHeatmapRenderer = (dependencies: { config: HeatmapExpressionProps, handlers: IInterpreterRenderHandlers ) => { - const formatFactory = await dependencies.formatFactory; const onClickValue = (data: LensFilterEvent['data']) => { handlers.event({ name: 'filter', data }); }; @@ -53,7 +52,7 @@ export const getHeatmapRenderer = (dependencies: { onClickValue={onClickValue} onSelectRange={onSelectRange} timeZone={dependencies.timeZone} - formatFactory={formatFactory} + formatFactory={dependencies.formatFactory} chartsThemeService={dependencies.chartsThemeService} paletteService={dependencies.paletteService} /> diff --git a/x-pack/plugins/lens/public/heatmap_visualization/index.ts b/x-pack/plugins/lens/public/heatmap_visualization/index.ts index 11f9b907eb9291..5fb4524939f111 100644 --- a/x-pack/plugins/lens/public/heatmap_visualization/index.ts +++ b/x-pack/plugins/lens/public/heatmap_visualization/index.ts @@ -14,7 +14,7 @@ import type { FormatFactory } from '../../common'; export interface HeatmapVisualizationPluginSetupPlugins { expressions: ExpressionsSetup; - formatFactory: Promise; + formatFactory: FormatFactory; editorFrame: EditorFrameSetup; charts: ChartsPluginSetup; } diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx index 03eb234d907660..59aebc517bf22a 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx @@ -20,6 +20,7 @@ import { ChangeIndexPattern } from './change_indexpattern'; import { EuiProgress, EuiLoadingSpinner } from '@elastic/eui'; import { documentField } from './document_field'; import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks'; +import { fieldFormatsServiceMock } from '../../../../../src/plugins/field_formats/public/mocks'; import { indexPatternFieldEditorPluginMock } from '../../../../../src/plugins/index_pattern_field_editor/public/mocks'; import { getFieldByNameFactory } from './pure_helpers'; import { uiActionsPluginMock } from '../../../../../src/plugins/ui_actions/public/mocks'; @@ -251,6 +252,7 @@ describe('IndexPattern Data Panel', () => { indexPatternRefs: [], existingFields: {}, data: dataPluginMock.createStartContract(), + fieldFormats: fieldFormatsServiceMock.createStartContract(), indexPatternFieldEditor: indexPatternFieldEditorPluginMock.createStartContract(), onUpdateIndexPattern: jest.fn(), dragDropContext: createMockedDragDropContext(), diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx index 0e53b0f3c8d443..5db5404f3d9daa 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/datapanel.tsx @@ -23,14 +23,15 @@ import { EuiButtonIcon, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { EsQueryConfig, Query, Filter } from '@kbn/es-query'; +import type { EsQueryConfig, Query, Filter } from '@kbn/es-query'; import { FormattedMessage } from '@kbn/i18n/react'; -import { CoreStart } from 'kibana/public'; -import { DataPublicPluginStart } from 'src/plugins/data/public'; +import type { CoreStart } from 'kibana/public'; +import type { DataPublicPluginStart } from 'src/plugins/data/public'; +import type { FieldFormatsStart } from 'src/plugins/field_formats/public'; import { htmlIdGenerator } from '@elastic/eui'; -import { DatasourceDataPanelProps, DataType, StateSetter } from '../types'; +import type { DatasourceDataPanelProps, DataType, StateSetter } from '../types'; import { ChildDragDropProvider, DragContextState } from '../drag_drop'; -import { +import type { IndexPattern, IndexPatternPrivateState, IndexPatternField, @@ -46,6 +47,7 @@ import { VISUALIZE_GEO_FIELD_TRIGGER } from '../../../../../src/plugins/ui_actio export type Props = Omit, 'core'> & { data: DataPublicPluginStart; + fieldFormats: FieldFormatsStart; changeIndexPattern: ( id: string, state: IndexPatternPrivateState, @@ -118,6 +120,7 @@ export function IndexPatternDataPanel({ dragDropContext, core, data, + fieldFormats, query, filters, dateRange, @@ -231,6 +234,7 @@ export function IndexPatternDataPanel({ dragDropContext={dragDropContext} core={core} data={data} + fieldFormats={fieldFormats} charts={charts} indexPatternFieldEditor={indexPatternFieldEditor} onChangeIndexPattern={onChangeIndexPattern} @@ -289,6 +293,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ onUpdateIndexPattern, core, data, + fieldFormats, indexPatternFieldEditor, existingFields, charts, @@ -297,6 +302,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ uiActions, }: Omit & { data: DataPublicPluginStart; + fieldFormats: FieldFormatsStart; core: CoreStart; currentIndexPatternId: string; indexPatternRefs: IndexPatternRef[]; @@ -565,6 +571,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ () => ({ core, data, + fieldFormats, indexPattern: currentIndexPattern, highlight: localState.nameFilter.toLowerCase(), dateRange, @@ -575,6 +582,7 @@ export const InnerIndexPatternDataPanel = function InnerIndexPatternDataPanel({ [ core, data, + fieldFormats, currentIndexPattern, dateRange, query, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.test.tsx index 2aa031959f5d7e..7cfa957f8a855a 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.test.tsx @@ -12,12 +12,12 @@ import { EuiLoadingSpinner, EuiPopover } from '@elastic/eui'; import { InnerFieldItem, FieldItemProps } from './field_item'; import { coreMock } from 'src/core/public/mocks'; import { mountWithIntl } from '@kbn/test/jest'; -import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; -import { dataPluginMock } from '../../../../../src/plugins/data/public/mocks'; +import { fieldFormatsServiceMock } from '../../../../../src/plugins/field_formats/public/mocks'; import { IndexPattern } from './types'; import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks'; import { documentField } from './document_field'; import { uiActionsPluginMock } from '../../../../../src/plugins/ui_actions/public/mocks'; +import { FieldFormatsStart } from '../../../../../src/plugins/field_formats/public'; const chartsThemeService = chartPluginMock.createSetupContract().theme; @@ -29,7 +29,6 @@ describe('IndexPattern Field Item', () => { let defaultProps: FieldItemProps; let indexPattern: IndexPattern; let core: ReturnType; - let data: DataPublicPluginStart; beforeEach(() => { indexPattern = { @@ -84,11 +83,15 @@ describe('IndexPattern Field Item', () => { } as IndexPattern; core = coreMock.createSetup(); - data = dataPluginMock.createStartContract(); core.http.post.mockClear(); defaultProps = { indexPattern, - data, + fieldFormats: ({ + ...fieldFormatsServiceMock.createStartContract(), + getDefaultInstance: jest.fn(() => ({ + convert: jest.fn((s: unknown) => JSON.stringify(s)), + })), + } as unknown) as FieldFormatsStart, core, highlight: '', dateRange: { @@ -112,12 +115,6 @@ describe('IndexPattern Field Item', () => { hasSuggestionForField: () => false, uiActions: uiActionsPluginMock.createStartContract(), }; - - data.fieldFormats = ({ - getDefaultInstance: jest.fn(() => ({ - convert: jest.fn((s: unknown) => JSON.stringify(s)), - })), - } as unknown) as DataPublicPluginStart['fieldFormats']; }); it('should display displayName of a field', () => { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx index 5ceb452038426a..9c22ec9d4bb05b 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx @@ -36,7 +36,7 @@ import { TooltipType, } from '@elastic/charts'; import { i18n } from '@kbn/i18n'; -import { DataPublicPluginStart } from 'src/plugins/data/public'; +import type { FieldFormatsStart } from 'src/plugins/field_formats/public'; import { EuiHighlight } from '@elastic/eui'; import { Query, @@ -61,7 +61,7 @@ import { debouncedComponent } from '../debounced_component'; export interface FieldItemProps { core: DatasourceDataPanelProps['core']; - data: DataPublicPluginStart; + fieldFormats: FieldFormatsStart; field: IndexPatternField; indexPattern: IndexPattern; highlight?: string; @@ -395,7 +395,7 @@ function FieldItemPopoverContents(props: State & FieldItemProps) { core, sampledValues, chartsThemeService, - data: { fieldFormats }, + fieldFormats, dropOntoWorkspace, editField, removeField, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.test.tsx index 6270b94abf5653..b3ade3ebc48b8d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.test.tsx @@ -9,8 +9,7 @@ import React from 'react'; import { EuiLoadingSpinner, EuiNotificationBadge } from '@elastic/eui'; import { coreMock } from 'src/core/public/mocks'; import { mountWithIntl, shallowWithIntl } from '@kbn/test/jest'; -import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; -import { dataPluginMock } from '../../../../../src/plugins/data/public/mocks'; +import { fieldFormatsServiceMock } from '../../../../../src/plugins/field_formats/public/mocks'; import { IndexPattern } from './types'; import { FieldItem } from './field_item'; import { FieldsAccordion, FieldsAccordionProps, FieldItemSharedProps } from './fields_accordion'; @@ -21,7 +20,6 @@ describe('Fields Accordion', () => { let defaultProps: FieldsAccordionProps; let indexPattern: IndexPattern; let core: ReturnType; - let data: DataPublicPluginStart; let fieldProps: FieldItemSharedProps; beforeEach(() => { @@ -45,12 +43,11 @@ describe('Fields Accordion', () => { ], } as IndexPattern; core = coreMock.createSetup(); - data = dataPluginMock.createStartContract(); core.http.post.mockClear(); fieldProps = { indexPattern, - data, + fieldFormats: fieldFormatsServiceMock.createStartContract(), core, highlight: '', dateRange: { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx index 9f5409f9837f41..6a89d1770743cc 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/fields_accordion.tsx @@ -17,7 +17,7 @@ import { EuiIconTip, } from '@elastic/eui'; import classNames from 'classnames'; -import { DataPublicPluginStart } from 'src/plugins/data/public'; +import { FieldFormatsStart } from 'src/plugins/field_formats/public'; import { IndexPatternField } from './types'; import { FieldItem } from './field_item'; import { Query, Filter } from '../../../../../src/plugins/data/public'; @@ -28,7 +28,7 @@ import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; export interface FieldItemSharedProps { core: DatasourceDataPanelProps['core']; - data: DataPublicPluginStart; + fieldFormats: FieldFormatsStart; chartsThemeService: ChartsPluginSetup['theme']; indexPattern: IndexPattern; highlight?: string; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/index.ts b/x-pack/plugins/lens/public/indexpattern_datasource/index.ts index b5844fa5cf4d6b..5ac9797d68db41 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/index.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/index.ts @@ -5,20 +5,25 @@ * 2.0. */ -import { CoreSetup } from 'kibana/public'; +import type { CoreSetup } from 'kibana/public'; import { Storage } from '../../../../../src/plugins/kibana_utils/public'; -import { ExpressionsSetup } from '../../../../../src/plugins/expressions/public'; -import { ChartsPluginSetup } from '../../../../../src/plugins/charts/public'; -import { IndexPatternFieldEditorStart } from '../../../../../src/plugins/index_pattern_field_editor/public'; -import { +import type { ExpressionsSetup } from '../../../../../src/plugins/expressions/public'; +import type { ChartsPluginSetup } from '../../../../../src/plugins/charts/public'; +import type { IndexPatternFieldEditorStart } from '../../../../../src/plugins/index_pattern_field_editor/public'; +import type { DataPublicPluginSetup, DataPublicPluginStart, } from '../../../../../src/plugins/data/public'; -import { Datasource, EditorFrameSetup } from '../types'; -import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; +import type { Datasource, EditorFrameSetup } from '../types'; +import type { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; +import type { + FieldFormatsStart, + FieldFormatsSetup, +} from '../../../../../src/plugins/field_formats/public'; export interface IndexPatternDatasourceSetupPlugins { expressions: ExpressionsSetup; + fieldFormats: FieldFormatsSetup; data: DataPublicPluginSetup; editorFrame: EditorFrameSetup; charts: ChartsPluginSetup; @@ -26,6 +31,7 @@ export interface IndexPatternDatasourceSetupPlugins { export interface IndexPatternDatasourceStartPlugins { data: DataPublicPluginStart; + fieldFormats: FieldFormatsStart; indexPatternFieldEditor: IndexPatternFieldEditorStart; uiActions: UiActionsStart; } @@ -35,7 +41,12 @@ export class IndexPatternDatasource { setup( core: CoreSetup, - { expressions, editorFrame, charts, data: dataSetup }: IndexPatternDatasourceSetupPlugins + { + fieldFormats: fieldFormatsSetup, + expressions, + editorFrame, + charts, + }: IndexPatternDatasourceSetupPlugins ) { editorFrame.registerDatasource(async () => { const { @@ -48,10 +59,11 @@ export class IndexPatternDatasource { } = await import('../async_services'); return core .getStartServices() - .then(([coreStart, { indexPatternFieldEditor, uiActions, data }]) => { - const suffixFormatter = getSuffixFormatter(data.fieldFormats.deserialize); - if (!dataSetup.fieldFormats.has(suffixFormatter.id)) { - dataSetup.fieldFormats.register([suffixFormatter]); + .then(([coreStart, { indexPatternFieldEditor, uiActions, data, fieldFormats }]) => { + const suffixFormatter = getSuffixFormatter(fieldFormats.deserialize); + if (!fieldFormats.has(suffixFormatter.id)) { + // todo: this code should be executed on setup phase. + fieldFormatsSetup.register([suffixFormatter]); } expressions.registerFunction(timeScale); expressions.registerFunction(counterRate); @@ -59,6 +71,7 @@ export class IndexPatternDatasource { expressions.registerFunction(formatColumn); return getIndexPatternDatasource({ core: coreStart, + fieldFormats, storage: new Storage(localStorage), data, charts, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts index 261a73287dba9d..b3176dbcfe409b 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.test.ts @@ -20,6 +20,8 @@ import { operationDefinitionMap, getErrorMessages } from './operations'; import { createMockedFullReference } from './operations/mocks'; import { indexPatternFieldEditorPluginMock } from 'src/plugins/index_pattern_field_editor/public/mocks'; import { uiActionsPluginMock } from '../../../../../src/plugins/ui_actions/public/mocks'; +import { fieldFormatsServiceMock } from '../../../../../src/plugins/field_formats/public/mocks'; + jest.mock('./loader'); jest.mock('../id_generator'); jest.mock('./operations'); @@ -172,6 +174,7 @@ describe('IndexPattern Data Source', () => { storage: {} as IStorageWrapper, core: coreMock.createStart(), data: dataPluginMock.createStartContract(), + fieldFormats: fieldFormatsServiceMock.createStartContract(), charts: chartPluginMock.createSetupContract(), indexPatternFieldEditor: indexPatternFieldEditorPluginMock.createStartContract(), uiActions: uiActionsPluginMock.createStartContract(), diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx index 2cbe801a5b7b85..3a2d0df88a6cda 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern.tsx @@ -8,11 +8,12 @@ import React from 'react'; import { render } from 'react-dom'; import { I18nProvider } from '@kbn/i18n/react'; -import { CoreStart, SavedObjectReference } from 'kibana/public'; +import type { CoreStart, SavedObjectReference } from 'kibana/public'; import { i18n } from '@kbn/i18n'; -import { IStorageWrapper } from 'src/plugins/kibana_utils/public'; -import { IndexPatternFieldEditorStart } from '../../../../../src/plugins/index_pattern_field_editor/public'; -import { +import type { IStorageWrapper } from 'src/plugins/kibana_utils/public'; +import type { FieldFormatsStart } from 'src/plugins/field_formats/public'; +import type { IndexPatternFieldEditorStart } from '../../../../../src/plugins/index_pattern_field_editor/public'; +import type { DatasourceDimensionEditorProps, DatasourceDimensionTriggerProps, DatasourceDataPanelProps, @@ -83,6 +84,7 @@ export function getIndexPatternDatasource({ core, storage, data, + fieldFormats, charts, indexPatternFieldEditor, uiActions, @@ -90,6 +92,7 @@ export function getIndexPatternDatasource({ core: CoreStart; storage: IStorageWrapper; data: DataPublicPluginStart; + fieldFormats: FieldFormatsStart; charts: ChartsPluginSetup; indexPatternFieldEditor: IndexPatternFieldEditorStart; uiActions: UiActionsStart; @@ -202,6 +205,7 @@ export function getIndexPatternDatasource({ { + updateStateOnCloseDimension: ({ state, layerId }) => { const layer = state.layers[layerId]; if (!Object.values(layer.incompleteColumns || {}).length) { return; @@ -408,7 +414,7 @@ export function getIndexPatternDatasource({ getDatasourceSuggestionsFromCurrentState, getDatasourceSuggestionsForVisualizeField, - getErrorMessages(state, layersGroups) { + getErrorMessages(state) { if (!state) { return; } diff --git a/x-pack/plugins/lens/public/metric_visualization/expression.tsx b/x-pack/plugins/lens/public/metric_visualization/expression.tsx index 5a1e0d7fb5bdf6..41b487e790a08c 100644 --- a/x-pack/plugins/lens/public/metric_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/metric_visualization/expression.tsx @@ -24,22 +24,17 @@ export { metricChart } from '../../common/expressions'; export type { MetricState, MetricConfig } from '../../common/expressions'; export const getMetricChartRenderer = ( - formatFactory: Promise + formatFactory: FormatFactory ): ExpressionRenderDefinition => ({ name: 'lens_metric_chart_renderer', displayName: 'Metric chart', help: 'Metric chart renderer', validate: () => undefined, reuseDomNode: true, - render: async ( - domNode: Element, - config: MetricChartProps, - handlers: IInterpreterRenderHandlers - ) => { - const resolvedFormatFactory = await formatFactory; + render: (domNode: Element, config: MetricChartProps, handlers: IInterpreterRenderHandlers) => { ReactDOM.render( - + , domNode, () => { diff --git a/x-pack/plugins/lens/public/metric_visualization/index.ts b/x-pack/plugins/lens/public/metric_visualization/index.ts index 484dc6140ecf22..29138979ab858a 100644 --- a/x-pack/plugins/lens/public/metric_visualization/index.ts +++ b/x-pack/plugins/lens/public/metric_visualization/index.ts @@ -12,7 +12,7 @@ import type { FormatFactory } from '../../common'; export interface MetricVisualizationPluginSetupPlugins { expressions: ExpressionsSetup; - formatFactory: Promise; + formatFactory: FormatFactory; editorFrame: EditorFrameSetup; } diff --git a/x-pack/plugins/lens/public/mocks.tsx b/x-pack/plugins/lens/public/mocks.tsx index 9258c94ad2ab46..611b50b413b716 100644 --- a/x-pack/plugins/lens/public/mocks.tsx +++ b/x-pack/plugins/lens/public/mocks.tsx @@ -20,11 +20,11 @@ import { DeepPartial } from '@reduxjs/toolkit'; import { LensPublicStart } from '.'; import { visualizationTypes } from './xy_visualization/types'; import { navigationPluginMock } from '../../../../src/plugins/navigation/public/mocks'; -import { LensAppServices } from './app_plugin/types'; +import type { LensAppServices } from './app_plugin/types'; import { DOC_TYPE } from '../common'; import { DataPublicPluginStart, esFilters, UI_SETTINGS } from '../../../../src/plugins/data/public'; import { dashboardPluginMock } from '../../../../src/plugins/dashboard/public/mocks'; -import { +import type { LensByValueInput, LensSavedObjectAttributes, LensByReferenceInput, @@ -33,8 +33,9 @@ import { mockAttributeService, createEmbeddableStateTransferMock, } from '../../../../src/plugins/embeddable/public/mocks'; -import { LensAttributeService } from './lens_attribute_service'; -import { EmbeddableStateTransfer } from '../../../../src/plugins/embeddable/public'; +import { fieldFormatsServiceMock } from '../../../../src/plugins/field_formats/public/mocks'; +import type { LensAttributeService } from './lens_attribute_service'; +import type { EmbeddableStateTransfer } from '../../../../src/plugins/embeddable/public'; import { makeConfigureStore, LensAppState, LensState } from './state_management/index'; import { getResolvedDateRange } from './utils'; @@ -391,6 +392,7 @@ export function makeDefaultServices( getUrlForApp: jest.fn((appId: string) => `/testbasepath/app/${appId}#/`), }, data: mockDataPlugin(sessionIdSubject), + fieldFormats: fieldFormatsServiceMock.createStartContract(), storage: { get: jest.fn(), set: jest.fn(), diff --git a/x-pack/plugins/lens/public/pie_visualization/expression.tsx b/x-pack/plugins/lens/public/pie_visualization/expression.tsx index ce36f88b2805e9..c1b9f4c799e64a 100644 --- a/x-pack/plugins/lens/public/pie_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/pie_visualization/expression.tsx @@ -22,7 +22,7 @@ import type { ChartsPluginSetup, PaletteRegistry } from '../../../../../src/plug export { pie } from '../../common/expressions'; export const getPieRenderer = (dependencies: { - formatFactory: Promise; + formatFactory: FormatFactory; chartsThemeService: ChartsPluginSetup['theme']; paletteService: PaletteRegistry; }): ExpressionRenderDefinition => ({ @@ -33,20 +33,16 @@ export const getPieRenderer = (dependencies: { help: '', validate: () => undefined, reuseDomNode: true, - render: async ( - domNode: Element, - config: PieExpressionProps, - handlers: IInterpreterRenderHandlers - ) => { + render: (domNode: Element, config: PieExpressionProps, handlers: IInterpreterRenderHandlers) => { const onClickValue = (data: LensFilterEvent['data']) => { handlers.event({ name: 'filter', data }); }; - const formatFactory = await dependencies.formatFactory; + ReactDOM.render( ; + formatFactory: FormatFactory; charts: ChartsPluginSetup; } diff --git a/x-pack/plugins/lens/public/plugin.ts b/x-pack/plugins/lens/public/plugin.ts index 26608f9cc78bea..e0a48489742379 100644 --- a/x-pack/plugins/lens/public/plugin.ts +++ b/x-pack/plugins/lens/public/plugin.ts @@ -7,6 +7,7 @@ import { AppMountParameters, CoreSetup, CoreStart } from 'kibana/public'; import type { Start as InspectorStartContract } from 'src/plugins/inspector/public'; +import type { FieldFormatsSetup, FieldFormatsStart } from 'src/plugins/field_formats/public'; import { UsageCollectionSetup, UsageCollectionStart } from 'src/plugins/usage_collection/public'; import { DataPublicPluginSetup, DataPublicPluginStart } from '../../../../src/plugins/data/public'; import { EmbeddableSetup, EmbeddableStart } from '../../../../src/plugins/embeddable/public'; @@ -57,7 +58,7 @@ import { ACTION_VISUALIZE_FIELD, VISUALIZE_FIELD_TRIGGER, } from '../../../../src/plugins/ui_actions/public'; -import { APP_ID, getEditPath, NOT_INTERNATIONALIZED_PRODUCT_NAME } from '../common'; +import { APP_ID, FormatFactory, getEditPath, NOT_INTERNATIONALIZED_PRODUCT_NAME } from '../common'; import type { EditorFrameStart, VisualizationType } from './types'; import { getLensAliasConfig } from './vis_type_alias'; import { visualizeFieldAction } from './trigger_actions/visualize_field_actions'; @@ -77,6 +78,7 @@ export interface LensPluginSetupDependencies { urlForwarding: UrlForwardingSetup; expressions: ExpressionsSetup; data: DataPublicPluginSetup; + fieldFormats: FieldFormatsSetup; embeddable?: EmbeddableSetup; visualizations: VisualizationsSetup; charts: ChartsPluginSetup; @@ -86,6 +88,7 @@ export interface LensPluginSetupDependencies { export interface LensPluginStartDependencies { data: DataPublicPluginStart; + fieldFormats: FieldFormatsStart; expressions: ExpressionsStart; navigation: NavigationPublicPluginStart; uiActions: UiActionsStart; @@ -158,6 +161,7 @@ export class LensPlugin { urlForwarding, expressions, data, + fieldFormats, embeddable, visualizations, charts, @@ -170,9 +174,21 @@ export class LensPlugin { const [coreStart, startDependencies] = await core.getStartServices(); return getLensAttributeService(coreStart, startDependencies); }; + const getStartServices = async (): Promise => { const [coreStart, deps] = await core.getStartServices(); - this.initParts(core, data, embeddable, charts, expressions, usageCollection); + + this.initParts( + core, + data, + embeddable, + charts, + expressions, + usageCollection, + fieldFormats, + deps.fieldFormats.deserialize + ); + return { attributeService: await this.attributeService!(), capabilities: coreStart.application.capabilities, @@ -210,7 +226,19 @@ export class LensPlugin { title: NOT_INTERNATIONALIZED_PRODUCT_NAME, navLinkStatus: AppNavLinkStatus.hidden, mount: async (params: AppMountParameters) => { - await this.initParts(core, data, embeddable, charts, expressions, usageCollection); + const [, deps] = await core.getStartServices(); + + await this.initParts( + core, + data, + embeddable, + charts, + expressions, + usageCollection, + fieldFormats, + deps.fieldFormats.deserialize + ); + const { mountApp, stopReportManager } = await import('./async_services'); this.stopReportManager = stopReportManager; await ensureDefaultIndexPattern(); @@ -245,7 +273,9 @@ export class LensPlugin { embeddable: EmbeddableSetup | undefined, charts: ChartsPluginSetup, expressions: ExpressionsServiceSetup, - usageCollection: UsageCollectionSetup | undefined + usageCollection: UsageCollectionSetup | undefined, + fieldFormats: FieldFormatsSetup, + formatFactory: FormatFactory ) { const { DatatableVisualization, @@ -277,11 +307,10 @@ export class LensPlugin { PieVisualizationPluginSetupPlugins = { expressions, data, + fieldFormats, charts, editorFrame: editorFrameSetupInterface, - formatFactory: core - .getStartServices() - .then(([_, { data: dataStart }]) => dataStart.fieldFormats.deserialize), + formatFactory, }; this.indexpatternDatasource.setup(core, dependencies); this.xyVisualization.setup(core, dependencies); diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.tsx index 23b251b76e9504..9ef87fe4f48d4a 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.tsx @@ -123,7 +123,7 @@ export function calculateMinInterval({ args: { layers }, data }: XYChartProps) { } export const getXyChartRenderer = (dependencies: { - formatFactory: Promise; + formatFactory: FormatFactory; chartsThemeService: ChartsPluginStart['theme']; chartsActiveCursorService: ChartsPluginStart['activeCursor']; paletteService: PaletteRegistry; @@ -148,12 +148,12 @@ export const getXyChartRenderer = (dependencies: { const onSelectRange = (data: LensBrushEvent['data']) => { handlers.event({ name: 'brush', data }); }; - const formatFactory = await dependencies.formatFactory; + ReactDOM.render( ; + formatFactory: FormatFactory; editorFrame: EditorFrameSetup; charts: ChartsPluginSetup; } @@ -41,7 +41,7 @@ export class XyVisualization { getXyChartRenderer, getXyVisualization, } = await import('../async_services'); - const [, { data, charts }] = await core.getStartServices(); + const [, { charts, fieldFormats }] = await core.getStartServices(); const palettes = await charts.palettes.getPalettes(); expressions.registerFunction(() => legendConfig); expressions.registerFunction(() => yAxisConfig); @@ -62,7 +62,7 @@ export class XyVisualization { timeZone: getTimeZone(core.uiSettings), }) ); - return getXyVisualization({ paletteService: palettes, data }); + return getXyVisualization({ paletteService: palettes, fieldFormats }); }); } } diff --git a/x-pack/plugins/lens/public/xy_visualization/to_expression.test.ts b/x-pack/plugins/lens/public/xy_visualization/to_expression.test.ts index f43b633f4a7161..621e2897a10597 100644 --- a/x-pack/plugins/lens/public/xy_visualization/to_expression.test.ts +++ b/x-pack/plugins/lens/public/xy_visualization/to_expression.test.ts @@ -11,12 +11,12 @@ import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks' import { getXyVisualization } from './xy_visualization'; import { Operation } from '../types'; import { createMockDatasource, createMockFramePublicAPI } from '../mocks'; -import { dataPluginMock } from '../../../../../src/plugins/data/public/mocks'; +import { fieldFormatsServiceMock } from '../../../../../src/plugins/field_formats/public/mocks'; describe('#toExpression', () => { const xyVisualization = getXyVisualization({ paletteService: chartPluginMock.createPaletteRegistry(), - data: dataPluginMock.createStartContract(), + fieldFormats: fieldFormatsServiceMock.createStartContract(), }); let mockDatasource: ReturnType; let frame: ReturnType; diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts b/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts index fd80b9d96d30af..ef97e2622ee82b 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts +++ b/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts @@ -13,7 +13,7 @@ import type { SeriesType, XYLayerConfig } from '../../common/expressions'; import { createMockDatasource, createMockFramePublicAPI } from '../mocks'; import { LensIconChartBar } from '../assets/chart_bar'; import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks'; -import { dataPluginMock } from '../../../../../src/plugins/data/public/mocks'; +import { fieldFormatsServiceMock } from '../../../../../src/plugins/field_formats/public/mocks'; function exampleState(): State { return { @@ -32,11 +32,11 @@ function exampleState(): State { }; } const paletteServiceMock = chartPluginMock.createPaletteRegistry(); -const dataMock = dataPluginMock.createStartContract(); +const fieldFormatsMock = fieldFormatsServiceMock.createStartContract(); const xyVisualization = getXyVisualization({ paletteService: paletteServiceMock, - data: dataMock, + fieldFormats: fieldFormatsMock, }); describe('xy_visualization', () => { diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx index 40caed7188190a..799246ef26b806 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx @@ -12,7 +12,7 @@ import { Position } from '@elastic/charts'; import { FormattedMessage, I18nProvider } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { PaletteRegistry } from 'src/plugins/charts/public'; -import { DataPublicPluginStart } from 'src/plugins/data/public'; +import { FieldFormatsStart } from 'src/plugins/field_formats/public'; import { getSuggestions } from './xy_suggestions'; import { LayerContextMenu, XyToolbar, DimensionEditor } from './xy_config_panel'; import type { @@ -87,10 +87,10 @@ function getDescription(state?: State) { export const getXyVisualization = ({ paletteService, - data, + fieldFormats, }: { paletteService: PaletteRegistry; - data: DataPublicPluginStart; + fieldFormats: FieldFormatsStart; }): Visualization => ({ id: 'lnsXY', @@ -190,7 +190,7 @@ export const getXyVisualization = ({ const colorAssignments = getColorAssignments( state.layers, { tables: frame.activeData }, - data.fieldFormats.deserialize + fieldFormats.deserialize ); mappedAccessors = getAccessorColorConfig( colorAssignments, @@ -336,7 +336,7 @@ export const getXyVisualization = ({ , diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_suggestions.test.ts b/x-pack/plugins/lens/public/xy_visualization/xy_suggestions.test.ts index 87165d64625e74..924b87647fcee5 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_suggestions.test.ts +++ b/x-pack/plugins/lens/public/xy_visualization/xy_suggestions.test.ts @@ -6,19 +6,19 @@ */ import { getSuggestions } from './xy_suggestions'; -import { TableSuggestionColumn, VisualizationSuggestion, TableSuggestion } from '../types'; +import type { TableSuggestionColumn, VisualizationSuggestion, TableSuggestion } from '../types'; import { State, XYState, visualizationTypes } from './types'; import { generateId } from '../id_generator'; import { getXyVisualization } from './xy_visualization'; import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks'; -import { dataPluginMock } from '../../../../../src/plugins/data/public/mocks'; -import { PaletteOutput } from 'src/plugins/charts/public'; +import { fieldFormatsServiceMock } from '../../../../../src/plugins/field_formats/public/mocks'; +import type { PaletteOutput } from 'src/plugins/charts/public'; jest.mock('../id_generator'); const xyVisualization = getXyVisualization({ paletteService: chartPluginMock.createPaletteRegistry(), - data: dataPluginMock.createStartContract(), + fieldFormats: fieldFormatsServiceMock.createStartContract(), }); describe('xy_suggestions', () => { diff --git a/x-pack/plugins/lens/server/expressions/expressions.ts b/x-pack/plugins/lens/server/expressions/expressions.ts new file mode 100644 index 00000000000000..8f8e6131b0728a --- /dev/null +++ b/x-pack/plugins/lens/server/expressions/expressions.ts @@ -0,0 +1,71 @@ +/* + * 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 type { CoreSetup, CoreStart, KibanaRequest } from 'kibana/server'; +import { + pie, + xyChart, + timeScale, + counterRate, + metricChart, + yAxisConfig, + layerConfig, + formatColumn, + legendConfig, + renameColumns, + gridlinesConfig, + datatableColumn, + tickLabelsConfig, + axisTitlesVisibilityConfig, + getDatatable, +} from '../../common/expressions'; +import type { PluginStartContract } from '../plugin'; +import type { + ExecutionContext, + ExpressionsServerSetup, +} from '../../../../../src/plugins/expressions/server'; + +const getUiSettings = (coreStart: CoreStart, kibanaRequest: KibanaRequest) => + coreStart.uiSettings.asScopedToClient(coreStart.savedObjects.getScopedClient(kibanaRequest)); + +export const setupExpressions = ( + core: CoreSetup, + expressions: ExpressionsServerSetup +) => { + const getFormatFactory = async (context: ExecutionContext) => { + const [coreStart, { fieldFormats: fieldFormatsStart }] = await core.getStartServices(); + const kibanaRequest = context.getKibanaRequest?.(); + + if (!kibanaRequest) { + throw new Error('"lens_datatable" expression function requires a KibanaRequest to execute'); + } + + const fieldFormats = await fieldFormatsStart.fieldFormatServiceFactory( + getUiSettings(coreStart, kibanaRequest) + ); + + return fieldFormats.deserialize; + }; + + [ + pie, + xyChart, + timeScale, + counterRate, + metricChart, + yAxisConfig, + layerConfig, + formatColumn, + legendConfig, + renameColumns, + gridlinesConfig, + datatableColumn, + tickLabelsConfig, + axisTitlesVisibilityConfig, + getDatatable(getFormatFactory), + ].forEach((expressionFn) => expressions.registerFunction(expressionFn)); +}; diff --git a/x-pack/plugins/lens/server/expressions/index.ts b/x-pack/plugins/lens/server/expressions/index.ts new file mode 100644 index 00000000000000..b726ba94ae5bca --- /dev/null +++ b/x-pack/plugins/lens/server/expressions/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export { setupExpressions } from './expressions'; diff --git a/x-pack/plugins/lens/server/plugin.tsx b/x-pack/plugins/lens/server/plugin.tsx index b47019fa54ec09..f0ee801ece89bc 100644 --- a/x-pack/plugins/lens/server/plugin.tsx +++ b/x-pack/plugins/lens/server/plugin.tsx @@ -10,6 +10,7 @@ import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { Observable } from 'rxjs'; import { PluginStart as DataPluginStart } from 'src/plugins/data/server'; import { ExpressionsServerSetup } from 'src/plugins/expressions/server'; +import { FieldFormatsStart } from 'src/plugins/field_formats/server'; import { TaskManagerSetupContract, TaskManagerStartContract } from '../../task_manager/server'; import { setupRoutes } from './routes'; import { @@ -20,6 +21,7 @@ import { import { setupSavedObjects } from './saved_objects'; import { EmbeddableSetup } from '../../../../src/plugins/embeddable/server'; import { lensEmbeddableFactory } from './embeddable/lens_embeddable_factory'; +import { setupExpressions } from './expressions'; export interface PluginSetupContract { usageCollection?: UsageCollectionSetup; @@ -30,6 +32,7 @@ export interface PluginSetupContract { export interface PluginStartContract { taskManager?: TaskManagerStartContract; + fieldFormats: FieldFormatsStart; data: DataPluginStart; } @@ -44,6 +47,8 @@ export class LensServerPlugin implements Plugin<{}, {}, {}, {}> { setup(core: CoreSetup, plugins: PluginSetupContract) { setupSavedObjects(core); setupRoutes(core, this.initializerContext.logger.get()); + setupExpressions(core, plugins.expressions); + if (plugins.usageCollection && plugins.taskManager) { registerLensUsageCollector( plugins.usageCollection,