From aea0e87bdb4682451d061ed0ce34db25d082c4de Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Tue, 3 Sep 2024 08:17:48 -0600 Subject: [PATCH] Revert "[Embeddables Rebuild] Migrate Visualize (#183197)" This reverts commit ee28e20de899d47f1cfff20ab30a1701f952d85d. --- .../presentation_containers/index.ts | 13 +- .../presentation_publishing/tsconfig.json | 2 +- .../common/content_management/index.ts | 1 - src/plugins/visualizations/common/types.ts | 4 +- src/plugins/visualizations/kibana.jsonc | 12 +- .../create_vis_embeddable_from_object.ts | 4 - .../embeddable/visualize_embeddable.tsx | 4 - .../embeddable/visualize_embeddable_async.ts | 4 - .../visualize_embeddable_factory.tsx | 4 - src/plugins/visualizations/public/index.ts | 5 +- src/plugins/visualizations/public/mocks.ts | 1 + src/plugins/visualizations/public/plugin.ts | 84 +-- .../react_embeddable/create_vis_instance.ts | 24 - .../get_expression_renderer_props.ts | 117 ---- .../public/react_embeddable/index.ts | 9 - .../react_embeddable/save_to_library.ts | 69 --- .../public/react_embeddable/state.test.ts | 234 -------- .../public/react_embeddable/state.ts | 225 ------- .../public/react_embeddable/types.ts | 106 ---- .../react_embeddable/visualize_embeddable.tsx | 547 ------------------ src/plugins/visualizations/public/services.ts | 23 +- .../save_with_confirmation.ts | 5 +- .../saved_visualization_references/index.ts | 8 +- .../saved_visualization_references.ts | 125 +--- .../public/utils/saved_visualize_utils.ts | 12 +- .../public/visualize_app/types.ts | 4 - .../utils/get_top_nav_config.tsx | 10 +- .../utils/get_visualization_instance.ts | 9 +- .../make_visualize_embeddable_factory.ts | 2 +- src/plugins/visualizations/tsconfig.json | 23 +- .../apps/dashboard/group3/dashboard_state.ts | 4 +- .../group5/dashboard_error_handling.ts | 2 +- .../dashboard/group6/embeddable_library.ts | 4 +- .../public/sample_panel_action.tsx | 6 +- .../lens_migration_smoke_test.ts | 2 +- .../tsvb_migration_smoke_test.ts | 2 +- .../visualize_migration_smoke_test.ts | 2 +- .../dashboard/group3/reporting/screenshots.ts | 2 +- .../apps/lens/open_in_lens/tsvb/dashboard.ts | 11 +- .../functional/apps/visualize/reporting.ts | 2 +- .../tests/browser.ts | 2 +- .../group3/open_in_lens/tsvb/dashboard.ts | 2 +- 42 files changed, 126 insertions(+), 1605 deletions(-) delete mode 100644 src/plugins/visualizations/public/react_embeddable/create_vis_instance.ts delete mode 100644 src/plugins/visualizations/public/react_embeddable/get_expression_renderer_props.ts delete mode 100644 src/plugins/visualizations/public/react_embeddable/index.ts delete mode 100644 src/plugins/visualizations/public/react_embeddable/save_to_library.ts delete mode 100644 src/plugins/visualizations/public/react_embeddable/state.test.ts delete mode 100644 src/plugins/visualizations/public/react_embeddable/state.ts delete mode 100644 src/plugins/visualizations/public/react_embeddable/types.ts delete mode 100644 src/plugins/visualizations/public/react_embeddable/visualize_embeddable.tsx diff --git a/packages/presentation/presentation_containers/index.ts b/packages/presentation/presentation_containers/index.ts index 2ecd8f5a4cb2d..224cfbb876214 100644 --- a/packages/presentation/presentation_containers/index.ts +++ b/packages/presentation/presentation_containers/index.ts @@ -25,20 +25,14 @@ export { type CanDuplicatePanels, type CanExpandPanels, } from './interfaces/panel_management'; -export { - canTrackContentfulRender, - type TrackContentfulRender, - type TracksQueryPerformance, -} from './interfaces/performance_trackers'; export { apiIsPresentationContainer, - combineCompatibleChildrenApis, getContainerParentFromAPI, listenForCompatibleApi, + combineCompatibleChildrenApis, type PanelPackage, type PresentationContainer, } from './interfaces/presentation_container'; -export { apiPublishesSettings, type PublishesSettings } from './interfaces/publishes_settings'; export { apiHasSerializableState, type HasSerializableState, @@ -46,3 +40,8 @@ export { type SerializedPanelState, } from './interfaces/serialized_state'; export { tracksOverlays, type TracksOverlays } from './interfaces/tracks_overlays'; +export { + canTrackContentfulRender, + type TrackContentfulRender, + type TracksQueryPerformance, +} from './interfaces/performance_trackers'; diff --git a/packages/presentation/presentation_publishing/tsconfig.json b/packages/presentation/presentation_publishing/tsconfig.json index a08944f9674da..6d98f0d821401 100644 --- a/packages/presentation/presentation_publishing/tsconfig.json +++ b/packages/presentation/presentation_publishing/tsconfig.json @@ -10,6 +10,6 @@ "@kbn/es-query", "@kbn/data-views-plugin", "@kbn/expressions-plugin", - "@kbn/core-execution-context-common" + "@kbn/core-execution-context-common", ] } diff --git a/src/plugins/visualizations/common/content_management/index.ts b/src/plugins/visualizations/common/content_management/index.ts index a9bdcf090cf8f..ebdd647c181d4 100644 --- a/src/plugins/visualizations/common/content_management/index.ts +++ b/src/plugins/visualizations/common/content_management/index.ts @@ -31,4 +31,3 @@ export type { } from './latest'; export * as VisualizationV1 from './v1'; -export type { Reference } from './v1'; diff --git a/src/plugins/visualizations/common/types.ts b/src/plugins/visualizations/common/types.ts index 27919bf225b1b..1394a11bc1909 100644 --- a/src/plugins/visualizations/common/types.ts +++ b/src/plugins/visualizations/common/types.ts @@ -15,7 +15,6 @@ import { BUCKET_TYPES, } from '@kbn/data-plugin/common'; import type { SerializedFieldFormat } from '@kbn/field-formats-plugin/common'; -import { Reference } from './content_management'; export interface VisParams { [key: string]: any; @@ -37,9 +36,8 @@ export type { export interface SerializedVisData { expression?: string; aggs: AggConfigSerialized[]; - searchSource: SerializedSearchSourceFields & { indexRefName?: string }; + searchSource: SerializedSearchSourceFields; savedSearchId?: string; - savedSearchRefName?: string | Reference; } export interface SerializedVis { diff --git a/src/plugins/visualizations/kibana.jsonc b/src/plugins/visualizations/kibana.jsonc index 95a2999611bd4..9d1c6c1da0e58 100644 --- a/src/plugins/visualizations/kibana.jsonc +++ b/src/plugins/visualizations/kibana.jsonc @@ -26,7 +26,7 @@ "savedObjectsFinder", "savedObjectsManagement", "savedSearch", - "contentManagement" + "contentManagement", ], "optionalPlugins": [ "home", @@ -34,10 +34,14 @@ "spaces", "savedObjectsTaggingOss", "serverless", - "noDataPage", - "embeddableEnhanced" + "noDataPage" + ], + "requiredBundles": [ + "kibanaUtils", + "kibanaReact", + "charts", + "savedObjects", ], - "requiredBundles": ["kibanaUtils", "kibanaReact", "charts", "savedObjects"], "extraPublicDirs": [ "common/constants", "common/utils", diff --git a/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts b/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts index 110543b59b2d8..03a4be179e7b2 100644 --- a/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts +++ b/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts @@ -21,10 +21,6 @@ import { urlFor } from '../utils/saved_visualize_utils'; import { VisualizeEmbeddableFactoryDeps } from './visualize_embeddable_factory'; import { createVisualizeEmbeddableAsync } from './visualize_embeddable_async'; -/** @deprecated - * VisualizeEmbeddable is no longer registered with the legacy embeddable system and is only - * used within the visualize editor. - */ export const createVisEmbeddableFromObject = (deps: VisualizeEmbeddableFactoryDeps) => async ( diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx b/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx index 4d1f2295cfadd..c6d90d879e8c7 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx @@ -91,10 +91,6 @@ export type VisualizeSavedObjectAttributes = SavedObjectAttributes & { export type VisualizeByValueInput = { attributes: VisualizeSavedObjectAttributes } & VisualizeInput; export type VisualizeByReferenceInput = SavedObjectEmbeddableInput & VisualizeInput; -/** @deprecated - * VisualizeEmbeddable is no longer registered with the legacy embeddable system and is only - * used within the visualize editor. - */ export class VisualizeEmbeddable extends Embeddable implements diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable_async.ts b/src/plugins/visualizations/public/embeddable/visualize_embeddable_async.ts index 70c2c570131f9..2fa22cfe8d80b 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable_async.ts +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable_async.ts @@ -8,10 +8,6 @@ import type { VisualizeEmbeddable as VisualizeEmbeddableType } from './visualize_embeddable'; -/** @deprecated - * VisualizeEmbeddable is no longer registered with the legacy embeddable system and is only - * used within the visualize editor. - */ export const createVisualizeEmbeddableAsync = async ( ...args: ConstructorParameters ) => { diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx b/src/plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx index b98b9df7d6728..abaee498da2ec 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable_factory.tsx @@ -70,10 +70,6 @@ export interface VisualizeEmbeddableFactoryDeps { >; } -/** @deprecated - * VisualizeEmbeddable is no longer registered with the legacy embeddable system and is only - * used within the visualize editor. - */ export class VisualizeEmbeddableFactory implements EmbeddableFactoryDefinition< diff --git a/src/plugins/visualizations/public/index.ts b/src/plugins/visualizations/public/index.ts index 8d5df8ed497d5..838ac3dbd7547 100644 --- a/src/plugins/visualizations/public/index.ts +++ b/src/plugins/visualizations/public/index.ts @@ -19,6 +19,7 @@ export function plugin(initializerContext: PluginInitializerContext) { export { TypesService } from './vis_types/types_service'; export { apiHasVisualizeConfig, + VISUALIZE_EMBEDDABLE_TYPE, VIS_EVENT_TO_TRIGGER, COMMON_VISUALIZATION_GROUPING, } from './embeddable'; @@ -37,13 +38,12 @@ export type { VisualizationClient, SerializableAttributes, } from './vis_types'; -export type { VisualizeEditorInput } from './react_embeddable/types'; export type { Vis, SerializedVis, SerializedVisData, VisData } from './vis'; export type VisualizeEmbeddableFactoryContract = PublicContract; export type VisualizeEmbeddableContract = PublicContract; +export type { VisualizeInput, VisualizeEmbeddable, HasVisualizeConfig } from './embeddable'; export type { SchemaConfig } from '../common/types'; export { updateOldState } from './legacy/vis_update_state'; -export type { VisualizeInput, VisualizeEmbeddable, HasVisualizeConfig } from './embeddable'; export type { PersistedState } from './persisted_state'; export type { ISavedVis, @@ -63,7 +63,6 @@ export { LegendSize, LegendSizeToPixels, DEFAULT_LEGEND_SIZE, - VISUALIZE_EMBEDDABLE_TYPE, } from '../common/constants'; export type { SavedVisState, VisParams, Dimension } from '../common'; export { prepareLogTable, XYCurveTypes } from '../common'; diff --git a/src/plugins/visualizations/public/mocks.ts b/src/plugins/visualizations/public/mocks.ts index 6c16a56f3c6b4..9bc31adccd3ba 100644 --- a/src/plugins/visualizations/public/mocks.ts +++ b/src/plugins/visualizations/public/mocks.ts @@ -75,6 +75,7 @@ const createInstance = async () => { application: applicationServiceMock.createStartContract(), embeddable: embeddablePluginMock.createStartContract(), spaces: spacesPluginMock.createStartContract(), + getAttributeService: jest.fn(), savedObjectsClient: coreMock.createStart().savedObjects.client, savedObjects: savedObjectsPluginMock.createStartContract(), savedObjectsTaggingOss: savedObjectTaggingOssPluginMock.createStart(), diff --git a/src/plugins/visualizations/public/plugin.ts b/src/plugins/visualizations/public/plugin.ts index 77826ad153869..bb931a072f192 100644 --- a/src/plugins/visualizations/public/plugin.ts +++ b/src/plugins/visualizations/public/plugin.ts @@ -69,8 +69,6 @@ import { ContentManagementPublicStart, } from '@kbn/content-management-plugin/public'; import type { NoDataPagePluginStart } from '@kbn/no-data-page-plugin/public'; -import { EmbeddableEnhancedPluginStart } from '@kbn/embeddable-enhanced-plugin/public'; - import type { TypesSetup, TypesStart } from './vis_types'; import type { VisualizeServices } from './visualize_app/types'; import { @@ -85,6 +83,11 @@ import { xyDimension as xyDimensionExpressionFunction } from '../common/expressi import { visDimension as visDimensionExpressionFunction } from '../common/expression_functions/vis_dimension'; import { range as rangeExpressionFunction } from '../common/expression_functions/range'; import { TypesService } from './vis_types/types_service'; +import { + createVisEmbeddableFromObject, + VISUALIZE_EMBEDDABLE_TYPE, + VisualizeEmbeddableFactory, +} from './embeddable'; import { setUISettings, setTypes, @@ -112,20 +115,18 @@ import { setSavedObjectsManagement, setContentManagement, setSavedSearch, - setDataViews, - setInspector, - getTypes, } from './services'; -import { VisualizeConstants, VISUALIZE_EMBEDDABLE_TYPE } from '../common/constants'; +import { VisualizeConstants } from '../common/constants'; import { EditInLensAction } from './actions/edit_in_lens_action'; -import { ListingViewRegistry } from './types'; +import { ListingViewRegistry, SerializedVis } from './types'; import { LATEST_VERSION, CONTENT_ID, VisualizationSavedObjectAttributes, } from '../common/content_management'; +import { SerializedVisData } from '../common'; +import { VisualizeByValueInput } from './embeddable/visualize_embeddable'; import { AddAggVisualizationPanelAction } from './actions/add_agg_vis_action'; -import { VisualizeSerializedState } from './react_embeddable/types'; /** * Interface for this plugin's returned setup/start contracts. @@ -162,6 +163,7 @@ export interface VisualizationsStartDeps { inspector: InspectorStart; uiActions: UiActionsStart; application: ApplicationStart; + getAttributeService: EmbeddableStart['getAttributeService']; navigation: NavigationStart; presentationUtil: PresentationUtilPluginStart; savedObjects: SavedObjectsStart; @@ -179,7 +181,6 @@ export interface VisualizationsStartDeps { contentManagement: ContentManagementPublicStart; serverless?: ServerlessPluginStart; noDataPage?: NoDataPagePluginStart; - embeddableEnhanced?: EmbeddableEnhancedPluginStart; } /** @@ -307,7 +308,6 @@ export class VisualizationsPlugin * this should be replaced to use only scoped history after moving legacy apps to browser routing */ const history = createHashHistory(); - const { createVisEmbeddableFromObject } = await import('./embeddable'); const services: VisualizeServices = { ...coreStart, history, @@ -332,7 +332,6 @@ export class VisualizationsPlugin embeddable: pluginsStart.embeddable, stateTransferService: pluginsStart.embeddable.getStateTransfer(), setActiveUrl, - /** @deprecated */ createVisEmbeddableFromObject: createVisEmbeddableFromObject({ start }), scopedHistory: params.history, restorePreviousUrl, @@ -401,31 +400,8 @@ export class VisualizationsPlugin uiActions.registerTrigger(dashboardVisualizationPanelTrigger); const editInLensAction = new EditInLensAction(data.query.timefilter.timefilter); uiActions.addTriggerAction(CONTEXT_MENU_TRIGGER, editInLensAction); - embeddable.registerReactEmbeddableFactory(VISUALIZE_EMBEDDABLE_TYPE, async () => { - const { - plugins: { embeddable: embeddableStart, embeddableEnhanced: embeddableEnhancedStart }, - } = start(); - - const { getVisualizeEmbeddableFactory } = await import('./react_embeddable'); - return getVisualizeEmbeddableFactory({ embeddableStart, embeddableEnhancedStart }); - }); - embeddable.registerReactEmbeddableSavedObject({ - onAdd: (container, savedObject) => { - container.addNewPanel({ - panelType: VISUALIZE_EMBEDDABLE_TYPE, - initialState: { savedObjectId: savedObject.id }, - }); - }, - embeddableType: VISUALIZE_EMBEDDABLE_TYPE, - savedObjectType: VISUALIZE_EMBEDDABLE_TYPE, - savedObjectName: i18n.translate('visualizations.visualizeSavedObjectName', { - defaultMessage: 'Visualization', - }), - getIconForSavedObject: (savedObject) => { - const visState = JSON.parse(savedObject.attributes.visState ?? '{}'); - return getTypes().get(visState.type)?.icon ?? ''; - }, - }); + const embeddableFactory = new VisualizeEmbeddableFactory({ start }); + embeddable.registerEmbeddableFactory(VISUALIZE_EMBEDDABLE_TYPE, embeddableFactory); contentManagement.registry.register({ id: CONTENT_ID, @@ -435,6 +411,37 @@ export class VisualizationsPlugin name: 'Visualize Library', }); + embeddable.registerSavedObjectToPanelMethod< + VisualizationSavedObjectAttributes, + VisualizeByValueInput + >(CONTENT_ID, (savedObject) => { + const visState = savedObject.attributes.visState; + + // not sure if visState actually is ever undefined, but following the type + if (!savedObject.managed || !visState) { + return { + savedObjectId: savedObject.id, + }; + } + + // data is not always defined, so I added a default value since the extract + // routine in the embeddable factory expects it to be there + const savedVis = JSON.parse(visState) as Omit & { + data?: SerializedVisData; + }; + + if (!savedVis.data) { + savedVis.data = { + searchSource: {}, + aggs: [], + }; + } + + return { + savedVis: savedVis as SerializedVis, // now we're sure we have "data" prop + }; + }); + return { ...this.types.setup(), visEditorsRegistry, @@ -449,6 +456,7 @@ export class VisualizationsPlugin expressions, uiActions, embeddable, + savedObjects, spaces, savedObjectsTaggingOss, fieldFormats, @@ -456,8 +464,6 @@ export class VisualizationsPlugin savedObjectsManagement, contentManagement, savedSearch, - dataViews, - inspector, }: VisualizationsStartDeps ): VisualizationsStart { const types = this.types.start(); @@ -482,8 +488,6 @@ export class VisualizationsPlugin setSavedObjectsManagement(savedObjectsManagement); setContentManagement(contentManagement); setSavedSearch(savedSearch); - setDataViews(dataViews); - setInspector(inspector); if (spaces) { setSpaces(spaces); diff --git a/src/plugins/visualizations/public/react_embeddable/create_vis_instance.ts b/src/plugins/visualizations/public/react_embeddable/create_vis_instance.ts deleted file mode 100644 index 660f876f33f04..0000000000000 --- a/src/plugins/visualizations/public/react_embeddable/create_vis_instance.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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 { SerializedVis } from '../vis'; -import { createVisAsync } from '../vis_async'; -import { getSavedSearch } from '../services'; - -export const createVisInstance = async (serializedVis: SerializedVis) => { - const vis = await createVisAsync(serializedVis.type, serializedVis); - if (serializedVis.data.savedSearchId) { - const savedSearch = await getSavedSearch().get(serializedVis.data.savedSearchId); - const indexPattern = savedSearch.searchSource.getField('index'); - if (indexPattern) { - vis.data.indexPattern = indexPattern; - vis.data.searchSource?.setField('index', indexPattern); - } - } - return vis; -}; diff --git a/src/plugins/visualizations/public/react_embeddable/get_expression_renderer_props.ts b/src/plugins/visualizations/public/react_embeddable/get_expression_renderer_props.ts deleted file mode 100644 index ad2bbb3036c5d..0000000000000 --- a/src/plugins/visualizations/public/react_embeddable/get_expression_renderer_props.ts +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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 type { KibanaExecutionContext } from '@kbn/core-execution-context-common'; -import { AggregateQuery, Filter, Query, TimeRange } from '@kbn/es-query'; -import { ExpressionRendererEvent, ExpressionRendererParams } from '@kbn/expressions-plugin/public'; -import { toExpressionAst } from '../embeddable/to_ast'; -import { getExecutionContext, getTimeFilter } from '../services'; -import type { VisParams } from '../types'; -import type { Vis } from '../vis'; - -interface GetExpressionRendererPropsParams { - unifiedSearch: { - filters?: Filter[]; - query?: Query | AggregateQuery; - }; - timeRange?: TimeRange; - disableTriggers?: boolean; - settings: { - syncColors?: boolean; - syncCursor?: boolean; - syncTooltips?: boolean; - }; - parentExecutionContext?: KibanaExecutionContext; - searchSessionId?: string; - abortController?: AbortController; - vis: Vis; - timeslice?: [number, number]; - onRender: (renderCount: number) => void; - onEvent: (event: ExpressionRendererEvent) => void; - onData: ExpressionRendererParams['onData$']; -} - -export const getExpressionRendererProps: (params: GetExpressionRendererPropsParams) => Promise<{ - abortController: AbortController; - params: ExpressionRendererParams | null; -}> = async ({ - unifiedSearch: { query, filters }, - settings: { syncColors = true, syncCursor = true, syncTooltips = false }, - disableTriggers = false, - parentExecutionContext, - searchSessionId, - vis, - abortController, - timeRange, - onRender, - onEvent, - onData, -}) => { - const parentContext = parentExecutionContext ?? getExecutionContext().get(); - const childContext: KibanaExecutionContext = { - type: 'agg_based', - name: vis.type.name, - id: vis.id ?? 'new', - description: vis.title, - }; - - const executionContext = { - ...parentContext, - childContext, - }; - - const timefilter = getTimeFilter(); - const expressionVariables = await vis.type.getExpressionVariables?.(vis, timefilter); - const inspectorAdapters = vis.type.inspectorAdapters - ? typeof vis.type.inspectorAdapters === 'function' - ? vis.type.inspectorAdapters() - : vis.type.inspectorAdapters - : undefined; - const loaderParams = { - searchContext: { - timeRange, - query, - filters, - disableWarningToasts: true, - }, - variables: { - embeddableTitle: vis.title, - ...expressionVariables, - }, - searchSessionId, - syncColors, - syncTooltips, - syncCursor, - uiState: vis.uiState, - interactive: !disableTriggers, - inspectorAdapters, - executionContext, - onRender$: onRender, - onData$: onData, - onEvent, - }; - - if (abortController) { - abortController.abort(); - } - - const newAbortController = new AbortController(); - - const expression = await toExpressionAst(vis, { - timefilter, - timeRange, - abortSignal: newAbortController.signal, - }); - if (!newAbortController.signal.aborted) { - return { - params: { expression, ...loaderParams } as ExpressionRendererParams, - abortController: newAbortController, - }; - } - - return { params: null, abortController: newAbortController }; -}; diff --git a/src/plugins/visualizations/public/react_embeddable/index.ts b/src/plugins/visualizations/public/react_embeddable/index.ts deleted file mode 100644 index 1794f21560c68..0000000000000 --- a/src/plugins/visualizations/public/react_embeddable/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* - * 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 { getVisualizeEmbeddableFactory } from './visualize_embeddable'; diff --git a/src/plugins/visualizations/public/react_embeddable/save_to_library.ts b/src/plugins/visualizations/public/react_embeddable/save_to_library.ts deleted file mode 100644 index bda0c09eb268b..0000000000000 --- a/src/plugins/visualizations/public/react_embeddable/save_to_library.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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 { Reference } from '../../common/content_management'; -import { PersistedState } from '../persisted_state'; -import { getAnalytics, getI18n, getOverlays, getTheme } from '../services'; -import { saveVisualization } from '../utils/saved_visualize_utils'; -import { VisualizeOutputState } from './types'; - -export const saveToLibrary = async ({ - uiState, - rawState, - references, -}: { - uiState: PersistedState; - rawState: VisualizeOutputState; - references: Reference[]; -}) => { - const { - savedVis: serializedVis, - title, - description, - getDisplayName, - getEsType, - managed, - } = rawState; - - const visSavedObjectAttributes = { - title, - description, - visState: { - type: serializedVis.type, - params: serializedVis.params, - aggs: serializedVis.data.aggs, - title: serializedVis.title, - }, - savedSearchId: serializedVis.data.savedSearchId, - ...(serializedVis.data.savedSearchRefName - ? { savedSearchRefName: String(serializedVis.data.savedSearchRefName) } - : {}), - searchSourceFields: serializedVis.data.searchSource, - uiStateJSON: uiState.toString(), - lastSavedTitle: '', - displayName: title, - getDisplayName, - getEsType, - managed, - }; - - const libraryId = await saveVisualization( - visSavedObjectAttributes, - { - confirmOverwrite: false, - }, - { - analytics: getAnalytics(), - i18n: getI18n(), - overlays: getOverlays(), - theme: getTheme(), - }, - references ?? [] - ); - return libraryId; -}; diff --git a/src/plugins/visualizations/public/react_embeddable/state.test.ts b/src/plugins/visualizations/public/react_embeddable/state.test.ts deleted file mode 100644 index 4ffd22f79003c..0000000000000 --- a/src/plugins/visualizations/public/react_embeddable/state.test.ts +++ /dev/null @@ -1,234 +0,0 @@ -/* - * 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 { SerializedPanelState } from '@kbn/presentation-containers'; -import { serializeState, deserializeSavedVisState } from './state'; -import { VisualizeSavedVisInputState } from './types'; - -describe('visualize_embeddable state', () => { - test('extracts saved search references for search source state and does not store them in state', () => { - const { rawState, references } = serializeState({ - serializedVis: { - type: 'area', - params: {}, - uiState: {}, - data: { - aggs: [ - { - id: '1', - enabled: true, - type: 'count', - params: {}, - schema: 'metric', - }, - ], - searchSource: { - query: { - query: '', - language: 'kuery', - }, - filter: [], - }, - savedSearchId: '123', - }, - title: 'owo', - }, - titles: {}, - }) as SerializedPanelState; - expect(references).toEqual([ - { - type: 'search', - name: 'search_0', - id: '123', - }, - ]); - expect('savedSearchId' in rawState.savedVis.data).toBeFalsy(); - }); - - test('extracts data view references for search source state and does not store them in state', () => { - const { rawState, references } = serializeState({ - serializedVis: { - type: 'area', - params: {}, - uiState: {}, - data: { - aggs: [ - { - id: '1', - enabled: true, - type: 'count', - params: {}, - schema: 'metric', - }, - ], - searchSource: { - query: { - query: '', - language: 'kuery', - }, - index: '123', - filter: [], - }, - }, - title: 'owo', - }, - titles: {}, - }) as SerializedPanelState; - expect(references).toEqual([ - { - type: 'index-pattern', - name: ( - rawState.savedVis.data.searchSource as { - indexRefName: string; - } - ).indexRefName, - id: '123', - }, - ]); - expect(rawState.savedVis.data.searchSource.index).toBeUndefined(); - }); - - test('injects data view references into search source state', async () => { - const deserializedSavedVis = await deserializeSavedVisState( - { - savedVis: { - type: 'area', - params: {}, - uiState: {}, - data: { - aggs: [ - { - id: '1', - enabled: true, - type: 'count', - params: {}, - schema: 'metric', - }, - ], - searchSource: { - query: { - query: '', - language: 'kuery', - }, - indexRefName: 'x', - filter: [], - }, - }, - title: 'owo', - }, - }, - [{ name: 'x', id: '123', type: 'index-pattern' }] - ); - expect(deserializedSavedVis.data.searchSource.index).toBe('123'); - expect((deserializedSavedVis.data.searchSource as { indexRefName: string }).indexRefName).toBe( - undefined - ); - }); - - test('injects data view reference into search source state even if it is injected already', async () => { - const deserializedSavedVis = await deserializeSavedVisState( - { - savedVis: { - type: 'area', - params: {}, - uiState: {}, - data: { - aggs: [ - { - id: '1', - enabled: true, - type: 'count', - params: {}, - schema: 'metric', - }, - ], - searchSource: { - query: { - query: '', - language: 'kuery', - }, - index: '456', - filter: [], - }, - }, - title: 'owo', - }, - }, - [{ name: 'kibanaSavedObjectMeta.searchSourceJSON.index', id: '123', type: 'index-pattern' }] - ); - expect(deserializedSavedVis.data.searchSource?.index).toBe('123'); - expect(deserializedSavedVis.data.searchSource?.indexRefName).toBe(undefined); - }); - - test('injects search reference into search source state', async () => { - const deserializedSavedVis = await deserializeSavedVisState( - { - savedVis: { - type: 'area', - params: {}, - uiState: {}, - data: { - aggs: [ - { - id: '1', - enabled: true, - type: 'count', - params: {}, - schema: 'metric', - }, - ], - searchSource: { - query: { - query: '', - language: 'kuery', - }, - filter: [], - }, - }, - title: 'owo', - }, - }, - [{ name: 'search_0', id: '123', type: 'search' }] - ); - expect(deserializedSavedVis.data.savedSearchId).toBe('123'); - }); - - test('injects search reference into search source state even if it is injected already', async () => { - const deserializedSavedVis = await deserializeSavedVisState( - { - savedVis: { - type: 'area', - params: {}, - uiState: {}, - data: { - aggs: [ - { - id: '1', - enabled: true, - type: 'count', - params: {}, - schema: 'metric', - }, - ], - searchSource: { - query: { - query: '', - language: 'kuery', - }, - filter: [], - }, - savedSearchId: '789', - }, - title: 'owo', - }, - }, - [{ name: 'search_0', id: '123', type: 'search' }] - ); - expect(deserializedSavedVis.data.savedSearchId).toBe('123'); - }); -}); diff --git a/src/plugins/visualizations/public/react_embeddable/state.ts b/src/plugins/visualizations/public/react_embeddable/state.ts deleted file mode 100644 index 9f677e42cf8c7..0000000000000 --- a/src/plugins/visualizations/public/react_embeddable/state.ts +++ /dev/null @@ -1,225 +0,0 @@ -/* - * 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 type { SerializedSearchSourceFields } from '@kbn/data-plugin/public'; -import { extractSearchSourceReferences } from '@kbn/data-plugin/public'; -import { SerializedPanelState } from '@kbn/presentation-containers'; -import { SerializedTitles } from '@kbn/presentation-publishing'; -import { cloneDeep, isEmpty, omit } from 'lodash'; -import { Reference } from '../../common/content_management'; -import { - getAnalytics, - getDataViews, - getI18n, - getOverlays, - getSavedObjectTagging, - getSearch, - getSpaces, - getTheme, -} from '../services'; -import { - deserializeReferences, - serializeReferences, -} from '../utils/saved_visualization_references'; -import { getSavedVisualization } from '../utils/saved_visualize_utils'; -import type { SerializedVis } from '../vis'; -import { - isVisualizeSavedObjectState, - VisualizeSavedObjectInputState, - VisualizeSerializedState, - VisualizeRuntimeState, - VisualizeSavedVisInputState, - ExtraSavedObjectProperties, - isVisualizeRuntimeState, -} from './types'; - -export const deserializeState = async ( - state: SerializedPanelState | { rawState: undefined } -) => { - if (!state.rawState) - return { - serializedVis: { - data: {}, - }, - } as VisualizeRuntimeState; - let serializedState = cloneDeep(state.rawState); - if (isVisualizeSavedObjectState(serializedState)) { - serializedState = await deserializeSavedObjectState(serializedState); - } else if (isVisualizeRuntimeState(serializedState)) { - return serializedState as VisualizeRuntimeState; - } - - const references: Reference[] = state.references ?? []; - - const deserializedSavedVis = deserializeSavedVisState(serializedState, references); - - return { - ...serializedState, - serializedVis: deserializedSavedVis, - } as VisualizeRuntimeState; -}; - -export const deserializeSavedVisState = ( - serializedState: VisualizeSavedVisInputState, - references: Reference[] -) => { - const { data } = serializedState.savedVis ?? { data: {} }; - let serializedSearchSource = data.searchSource as SerializedSearchSourceFields & { - indexRefName: string; - }; - let serializedReferences = [...references]; - if (data.searchSource && !('indexRefName' in data.searchSource)) { - // due to a bug in 8.0, some visualizations were saved with an injected state - re-extract in that case and inject the upstream references because they might have changed - const [extractedSearchSource, extractedReferences] = - extractSearchSourceReferences(serializedSearchSource); - - serializedSearchSource = extractedSearchSource as SerializedSearchSourceFields & { - indexRefName: string; - }; - serializedReferences = [...references, ...extractedReferences]; - } - - const { references: deserializedReferences, deserializedSearchSource } = deserializeReferences( - { - ...serializedState, - savedVis: { - ...serializedState.savedVis, - data: { ...data, searchSource: serializedSearchSource }, - }, - }, - serializedReferences - ); - - return { - ...serializedState.savedVis, - data: { - ...data, - searchSource: deserializedSearchSource, - savedSearchId: - deserializedReferences.find((r) => r.name === 'search_0')?.id ?? data.savedSearchId, - }, - }; -}; - -export const deserializeSavedObjectState = async ({ - savedObjectId, - enhancements, - uiState, - timeRange, -}: VisualizeSavedObjectInputState) => { - // Load a saved visualization from the library - const { - title, - description, - visState, - searchSource, - searchSourceFields, - savedSearchId, - savedSearchRefName, - uiStateJSON, - ...savedObjectProperties - } = await getSavedVisualization( - { - dataViews: getDataViews(), - search: getSearch(), - savedObjectsTagging: getSavedObjectTagging().getTaggingApi(), - spaces: getSpaces(), - i18n: getI18n(), - overlays: getOverlays(), - analytics: getAnalytics(), - theme: getTheme(), - }, - savedObjectId - ); - return { - savedVis: { - title, - type: visState.type, - params: visState.params, - uiState: uiState ?? (uiStateJSON ? JSON.parse(uiStateJSON) : {}), - data: { - aggs: visState.aggs, - searchSource: (searchSource ?? searchSourceFields) as SerializedSearchSourceFields, - savedSearchId, - }, - }, - title, - description, - savedObjectId, - savedObjectProperties, - linkedToLibrary: true, - ...(timeRange ? { timeRange } : {}), - ...(enhancements ? { enhancements } : {}), - } as VisualizeSavedVisInputState; -}; - -export const serializeState: (props: { - serializedVis: SerializedVis; - titles: SerializedTitles; - id?: string; - savedObjectProperties?: ExtraSavedObjectProperties; - linkedToLibrary?: boolean; - enhancements?: VisualizeRuntimeState['enhancements']; - timeRange?: VisualizeRuntimeState['timeRange']; -}) => Required> = ({ - serializedVis, // Serialize the vis before passing it to this function for easier testing - titles, - id, - savedObjectProperties, - linkedToLibrary, - enhancements, - timeRange, -}) => { - const titlesWithDefaults = { - title: '', - description: '', - ...titles, - }; - const { references, serializedSearchSource } = serializeReferences(serializedVis); - - // Serialize ONLY the savedObjectId. This ensures that when this vis is loaded again, it will always fetch the - // latest revision of the saved object - if (linkedToLibrary) { - return { - rawState: { - savedObjectId: id, - ...(enhancements ? { enhancements } : {}), - ...(!isEmpty(serializedVis.uiState) ? { uiState: serializedVis.uiState } : {}), - ...(timeRange ? { timeRange } : {}), - } as VisualizeSavedObjectInputState, - references, - }; - } - - const savedSearchRefName = serializedVis.data.savedSearchId - ? references.find((r) => r.id === serializedVis.data.savedSearchId)?.name - : undefined; - - return { - rawState: { - ...titlesWithDefaults, - ...savedObjectProperties, - ...(enhancements ? { enhancements } : {}), - ...(timeRange ? { timeRange } : {}), - savedVis: { - ...serializedVis, - id, - data: { - ...omit(serializedVis.data, 'savedSearchId'), - searchSource: serializedSearchSource, - ...(savedSearchRefName - ? { - savedSearchRefName, - } - : {}), - }, - }, - } as VisualizeSavedVisInputState, - references, - }; -}; diff --git a/src/plugins/visualizations/public/react_embeddable/types.ts b/src/plugins/visualizations/public/react_embeddable/types.ts deleted file mode 100644 index e37588a0d22bd..0000000000000 --- a/src/plugins/visualizations/public/react_embeddable/types.ts +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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 type { OverlayRef } from '@kbn/core-mount-utils-browser'; -import { DynamicActionsSerializedState } from '@kbn/embeddable-enhanced-plugin/public/plugin'; -import { DefaultEmbeddableApi } from '@kbn/embeddable-plugin/public'; -import type { TimeRange } from '@kbn/es-query'; -import { HasInspectorAdapters } from '@kbn/inspector-plugin/public'; -import { - HasEditCapabilities, - HasSupportedTriggers, - PublishesDataLoading, - PublishesDataViews, - PublishesTimeRange, - SerializedTimeRange, - SerializedTitles, -} from '@kbn/presentation-publishing'; -import { DeepPartial } from '@kbn/utility-types'; -import { HasVisualizeConfig } from '../embeddable'; -import type { Vis, VisParams, VisSavedObject } from '../types'; -import type { SerializedVis } from '../vis'; - -export type ExtraSavedObjectProperties = Pick< - VisSavedObject, - | 'lastSavedTitle' - | 'displayName' - | 'getDisplayName' - | 'getEsType' - | 'managed' - | 'sharingSavedObjectProps' ->; - -export type VisualizeRuntimeState = SerializedTitles & - SerializedTimeRange & - Partial & { - serializedVis: SerializedVis; - savedObjectId?: string; - savedObjectProperties?: ExtraSavedObjectProperties; - linkedToLibrary?: boolean; - }; - -export type VisualizeEditorInput = Omit & { - savedVis?: SerializedVis; - timeRange: TimeRange; - vis?: Vis & { colors?: Record; legendOpen?: boolean }; -}; - -export type VisualizeSavedObjectInputState = SerializedTitles & - Partial & { - savedObjectId: string; - timeRange?: TimeRange; - uiState?: any; - }; - -export type VisualizeSavedVisInputState = SerializedTitles & - Partial & { - savedVis: SerializedVis; - timeRange?: TimeRange; - }; - -export type VisualizeSerializedState = VisualizeSavedObjectInputState | VisualizeSavedVisInputState; -export type VisualizeOutputState = VisualizeSavedVisInputState & - Required> & - ExtraSavedObjectProperties; - -export const isVisualizeSavedObjectState = ( - state: unknown -): state is VisualizeSavedObjectInputState => { - return ( - typeof state !== 'undefined' && - (state as VisualizeSavedObjectInputState).savedObjectId !== undefined && - !!(state as VisualizeSavedObjectInputState).savedObjectId && - !('savedVis' in (state as VisualizeSavedObjectInputState)) && - !('serializedVis' in (state as VisualizeSavedObjectInputState)) - ); -}; - -export const isVisualizeRuntimeState = (state: unknown): state is VisualizeRuntimeState => { - return ( - !isVisualizeSavedObjectState(state) && - !('savedVis' in (state as VisualizeRuntimeState)) && - (state as VisualizeRuntimeState).serializedVis !== undefined - ); -}; - -export type VisualizeApi = HasEditCapabilities & - PublishesDataViews & - PublishesDataLoading & - HasVisualizeConfig & - HasInspectorAdapters & - HasSupportedTriggers & - PublishesTimeRange & - DefaultEmbeddableApi & { - updateVis: (vis: DeepPartial>) => void; - openInspector: () => OverlayRef | undefined; - saveToLibrary: (title: string) => Promise; - canLinkToLibrary: () => boolean; - canUnlinkFromLibrary: () => boolean; - checkForDuplicateTitle: (title: string) => boolean; - getByValueState: () => VisualizeSerializedState; - getByReferenceState: (id: string) => VisualizeSerializedState; - }; diff --git a/src/plugins/visualizations/public/react_embeddable/visualize_embeddable.tsx b/src/plugins/visualizations/public/react_embeddable/visualize_embeddable.tsx deleted file mode 100644 index a5d2df7a2c92e..0000000000000 --- a/src/plugins/visualizations/public/react_embeddable/visualize_embeddable.tsx +++ /dev/null @@ -1,547 +0,0 @@ -/* - * 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 { EuiEmptyPrompt, EuiFlexGroup, EuiLoadingChart } from '@elastic/eui'; -import { isChartSizeEvent } from '@kbn/chart-expressions-common'; -import { APPLY_FILTER_TRIGGER } from '@kbn/data-plugin/public'; -import type { DataView } from '@kbn/data-views-plugin/public'; -import { EmbeddableEnhancedPluginStart } from '@kbn/embeddable-enhanced-plugin/public'; -import { - EmbeddableStart, - ReactEmbeddableFactory, - SELECT_RANGE_TRIGGER, -} from '@kbn/embeddable-plugin/public'; -import { ExpressionRendererParams, useExpressionRenderer } from '@kbn/expressions-plugin/public'; -import { i18n } from '@kbn/i18n'; -import { dispatchRenderComplete } from '@kbn/kibana-utils-plugin/public'; -import { apiPublishesSettings } from '@kbn/presentation-containers'; -import { - apiHasAppContext, - apiHasDisableTriggers, - apiHasExecutionContext, - apiIsOfType, - apiPublishesTimeRange, - apiPublishesTimeslice, - apiPublishesUnifiedSearch, - apiPublishesViewMode, - fetch$, - getUnchangingComparator, - initializeTimeRange, - initializeTitles, - useStateFromPublishingSubject, -} from '@kbn/presentation-publishing'; -import { apiPublishesSearchSession } from '@kbn/presentation-publishing/interfaces/fetch/publishes_search_session'; -import { get, isEmpty, isEqual, isNil, omitBy } from 'lodash'; -import React, { useEffect, useRef } from 'react'; -import { BehaviorSubject, switchMap } from 'rxjs'; -import { VISUALIZE_APP_NAME, VISUALIZE_EMBEDDABLE_TYPE } from '../../common/constants'; -import { VIS_EVENT_TO_TRIGGER } from '../embeddable'; -import { getCapabilities, getInspector, getUiActions, getUsageCollection } from '../services'; -import { ACTION_CONVERT_TO_LENS } from '../triggers'; -import { urlFor } from '../utils/saved_visualize_utils'; -import type { SerializedVis, Vis } from '../vis'; -import { createVisInstance } from './create_vis_instance'; -import { getExpressionRendererProps } from './get_expression_renderer_props'; -import { saveToLibrary } from './save_to_library'; -import { deserializeState, serializeState } from './state'; -import { - ExtraSavedObjectProperties, - VisualizeApi, - VisualizeOutputState, - VisualizeRuntimeState, - VisualizeSerializedState, - isVisualizeSavedObjectState, -} from './types'; - -export const getVisualizeEmbeddableFactory: (deps: { - embeddableStart: EmbeddableStart; - embeddableEnhancedStart?: EmbeddableEnhancedPluginStart; -}) => ReactEmbeddableFactory = ({ - embeddableStart, - embeddableEnhancedStart, -}) => ({ - type: VISUALIZE_EMBEDDABLE_TYPE, - deserializeState, - buildEmbeddable: async (initialState: unknown, buildApi, uuid, parentApi) => { - // Handle state transfer from legacy visualize editor, which uses the legacy visualize embeddable and doesn't - // produce a snapshot state. If buildEmbeddable is passed only a savedObjectId in the state, this means deserializeState - // was never run, and it needs to be invoked manually - const state = isVisualizeSavedObjectState(initialState) - ? await deserializeState({ - rawState: initialState, - }) - : (initialState as VisualizeRuntimeState); - - // Initialize dynamic actions - const dynamicActionsApi = embeddableEnhancedStart?.initializeReactEmbeddableDynamicActions( - uuid, - () => titlesApi.panelTitle.getValue(), - state - ); - // if it is provided, start the dynamic actions manager - const maybeStopDynamicActions = dynamicActionsApi?.startDynamicActions(); - - const { titlesApi, titleComparators, serializeTitles } = initializeTitles(state); - - // Count renders; mostly used for testing. - const renderCount$ = new BehaviorSubject(0); - const hasRendered$ = new BehaviorSubject(false); - - // Track vis data and initialize it into a vis instance - const serializedVis$ = new BehaviorSubject(state.serializedVis); - const initialVisInstance = await createVisInstance(state.serializedVis); - const vis$ = new BehaviorSubject(initialVisInstance); - - // Track UI state - const onUiStateChange = () => serializedVis$.next(vis$.getValue().serialize()); - initialVisInstance.uiState.on('change', onUiStateChange); - vis$.subscribe((vis) => vis.uiState.on('change', onUiStateChange)); - - // When the serialized vis changes, update the vis instance - serializedVis$ - .pipe( - switchMap(async (serializedVis) => { - const currentVis = vis$.getValue(); - if (currentVis) currentVis.uiState.off('change', onUiStateChange); - const vis = await createVisInstance(serializedVis); - const { params, abortController } = await getExpressionParams(); - return { vis, params, abortController }; - }) - ) - .subscribe(({ vis, params, abortController }) => { - vis$.next(vis); - if (params) expressionParams$.next(params); - expressionAbortController$.next(abortController); - }); - - // Track visualizations linked to a saved object in the library - const savedObjectId$ = new BehaviorSubject( - state.savedObjectId ?? state.serializedVis.id - ); - const savedObjectProperties$ = new BehaviorSubject( - undefined - ); - const linkedToLibrary$ = new BehaviorSubject(state.linkedToLibrary); - - // Track the vis expression - const expressionParams$ = new BehaviorSubject({ - expression: '', - }); - - const expressionAbortController$ = new BehaviorSubject(new AbortController()); - let getExpressionParams: () => ReturnType = async () => ({ - params: expressionParams$.getValue(), - abortController: expressionAbortController$.getValue(), - }); - - const { - api: customTimeRangeApi, - serialize: serializeCustomTimeRange, - comparators: customTimeRangeComparators, - } = initializeTimeRange(state); - - const searchSessionId$ = new BehaviorSubject(''); - - const viewMode$ = apiPublishesViewMode(parentApi) - ? parentApi.viewMode - : new BehaviorSubject('view'); - - const executionContext = apiHasExecutionContext(parentApi) - ? parentApi.executionContext - : undefined; - - const disableTriggers = apiHasDisableTriggers(parentApi) - ? parentApi.disableTriggers - : undefined; - - const parentApiContext = apiHasAppContext(parentApi) ? parentApi.getAppContext() : undefined; - - const inspectorAdapters$ = new BehaviorSubject>({}); - - // Track data views - let initialDataViews: DataView[] | undefined = []; - if (initialVisInstance.data.indexPattern) - initialDataViews = [initialVisInstance.data.indexPattern]; - if (initialVisInstance.type.getUsedIndexPattern) { - initialDataViews = await initialVisInstance.type.getUsedIndexPattern( - initialVisInstance.params - ); - } - - const dataLoading$ = new BehaviorSubject(true); - - const defaultPanelTitle = new BehaviorSubject(initialVisInstance.title); - - const api = buildApi( - { - ...customTimeRangeApi, - ...titlesApi, - ...(dynamicActionsApi?.dynamicActionsApi ?? {}), - defaultPanelTitle, - dataLoading: dataLoading$, - dataViews: new BehaviorSubject(initialDataViews), - supportedTriggers: () => [ - ACTION_CONVERT_TO_LENS, - APPLY_FILTER_TRIGGER, - SELECT_RANGE_TRIGGER, - ], - serializeState: () => { - const savedObjectProperties = savedObjectProperties$.getValue(); - return serializeState({ - serializedVis: vis$.getValue().serialize(), - titles: serializeTitles(), - id: savedObjectId$.getValue(), - linkedToLibrary: - // In the visualize editor, linkedToLibrary should always be false to force the full state to be serialized, - // instead of just passing a reference to the linked saved object. Other contexts like dashboards should - // serialize the state with just the savedObjectId so that the current revision of the vis is always used - apiIsOfType(parentApi, VISUALIZE_APP_NAME) ? false : linkedToLibrary$.getValue(), - ...(savedObjectProperties ? { savedObjectProperties } : {}), - ...(dynamicActionsApi?.serializeDynamicActions?.() ?? {}), - ...serializeCustomTimeRange(), - }); - }, - getVis: () => vis$.getValue(), - getInspectorAdapters: () => inspectorAdapters$.getValue(), - getTypeDisplayName: () => - i18n.translate('visualizations.displayName', { - defaultMessage: 'visualization', - }), - onEdit: async () => { - const stateTransferService = embeddableStart.getStateTransfer(); - const visId = savedObjectId$.getValue(); - const editPath = visId ? urlFor(visId) : '#/edit_by_value'; - const parentTimeRange = apiPublishesTimeRange(parentApi) - ? parentApi.timeRange$.getValue() - : {}; - const customTimeRange = customTimeRangeApi.timeRange$.getValue(); - - await stateTransferService.navigateToEditor('visualize', { - path: editPath, - state: { - embeddableId: uuid, - valueInput: { - savedVis: vis$.getValue().serialize(), - title: api.panelTitle?.getValue(), - description: api.panelDescription?.getValue(), - timeRange: customTimeRange ?? parentTimeRange, - }, - originatingApp: parentApiContext?.currentAppId ?? '', - searchSessionId: searchSessionId$.getValue() || undefined, - originatingPath: parentApiContext?.getCurrentPath?.(), - }, - }); - }, - isEditingEnabled: () => { - if (viewMode$.getValue() !== 'edit') return false; - const readOnly = Boolean(vis$.getValue().type.disableEdit); - if (readOnly) return false; - const capabilities = getCapabilities(); - const isByValue = !savedObjectId$.getValue(); - if (isByValue) - return Boolean( - capabilities.dashboard?.showWriteControls && capabilities.visualize?.show - ); - else return Boolean(capabilities.visualize?.save); - }, - updateVis: async (visUpdates) => { - const currentSerializedVis = vis$.getValue().serialize(); - serializedVis$.next({ - ...currentSerializedVis, - ...visUpdates, - params: { - ...currentSerializedVis.params, - ...visUpdates.params, - }, - data: { - ...currentSerializedVis.data, - ...visUpdates.data, - }, - } as SerializedVis); - if (visUpdates.title) { - titlesApi.setPanelTitle(visUpdates.title); - } - }, - openInspector: () => { - const adapters = inspectorAdapters$.getValue(); - if (!adapters) return; - const inspector = getInspector(); - if (!inspector.isAvailable(adapters)) return; - return getInspector().open(adapters, { - title: - titlesApi.panelTitle?.getValue() || - i18n.translate('visualizations.embeddable.inspectorTitle', { - defaultMessage: 'Inspector', - }), - }); - }, - // Library transforms - saveToLibrary: (newTitle: string) => { - titlesApi.setPanelTitle(newTitle); - const { rawState, references } = serializeState({ - serializedVis: vis$.getValue().serialize(), - titles: { - ...serializeTitles(), - title: newTitle, - }, - }); - return saveToLibrary({ - uiState: vis$.getValue().uiState, - rawState: rawState as VisualizeOutputState, - references, - }); - }, - canLinkToLibrary: () => !state.linkedToLibrary, - canUnlinkFromLibrary: () => !!state.linkedToLibrary, - checkForDuplicateTitle: () => false, // Handled by saveToLibrary action - getByValueState: () => ({ - savedVis: vis$.getValue().serialize(), - ...serializeTitles(), - }), - getByReferenceState: (libraryId) => - serializeState({ - serializedVis: vis$.getValue().serialize(), - titles: serializeTitles(), - id: libraryId, - linkedToLibrary: true, - }).rawState, - }, - { - ...titleComparators, - ...customTimeRangeComparators, - ...(dynamicActionsApi?.dynamicActionsComparator ?? { - enhancements: getUnchangingComparator(), - }), - serializedVis: [ - serializedVis$, - (value) => { - serializedVis$.next(value); - }, - (a, b) => { - const visA = a - ? { - ...omitBy(a, isEmpty), - data: omitBy(a.data, isNil), - params: omitBy(a.params, isNil), - } - : {}; - const visB = b - ? { - ...omitBy(b, isEmpty), - data: omitBy(b.data, isNil), - params: omitBy(b.params, isNil), - } - : {}; - return isEqual(visA, visB); - }, - ], - savedObjectId: [ - savedObjectId$, - (value) => savedObjectId$.next(value), - (a, b) => { - if (!a && !b) return true; - return a === b; - }, - ], - savedObjectProperties: getUnchangingComparator(), - linkedToLibrary: [linkedToLibrary$, (value) => linkedToLibrary$.next(value)], - } - ); - - const fetchSubscription = fetch$(api) - .pipe( - switchMap(async (data) => { - const unifiedSearch = apiPublishesUnifiedSearch(parentApi) - ? { - query: data.query, - filters: data.filters, - } - : {}; - const searchSessionId = apiPublishesSearchSession(parentApi) ? data.searchSessionId : ''; - searchSessionId$.next(searchSessionId); - const settings = apiPublishesSettings(parentApi) - ? { - syncColors: parentApi.settings.syncColors$.getValue(), - syncCursor: parentApi.settings.syncCursor$.getValue(), - syncTooltips: parentApi.settings.syncTooltips$.getValue(), - } - : {}; - - dataLoading$.next(true); - - const timeslice = apiPublishesTimeslice(parentApi) - ? parentApi.timeslice$.getValue() - : undefined; - - const customTimeRange = customTimeRangeApi.timeRange$.getValue(); - const parentTimeRange = apiPublishesTimeRange(parentApi) ? data.timeRange : undefined; - const timesliceTimeRange = timeslice - ? { - from: new Date(timeslice[0]).toISOString(), - to: new Date(timeslice[1]).toISOString(), - mode: 'absolute' as 'absolute', - } - : undefined; - - // Precedence should be: - // custom time range from state > - // timeslice time range > - // parent API time range from e.g. unified search - const timeRangeToRender = customTimeRange ?? timesliceTimeRange ?? parentTimeRange; - - getExpressionParams = async () => { - return await getExpressionRendererProps({ - unifiedSearch, - vis: vis$.getValue(), - settings, - disableTriggers, - searchSessionId, - parentExecutionContext: executionContext, - abortController: expressionAbortController$.getValue(), - timeRange: timeRangeToRender, - onRender: async (renderCount) => { - if (renderCount === renderCount$.getValue()) return; - renderCount$.next(renderCount); - const visInstance = vis$.getValue(); - const visTypeName = visInstance.type.name; - - let telemetryVisTypeName = visTypeName; - if (visTypeName === 'metrics') { - telemetryVisTypeName = 'legacy_metric'; - } - if (visTypeName === 'pie' && visInstance.params.isDonut) { - telemetryVisTypeName = 'donut'; - } - if ( - visTypeName === 'area' && - visInstance.params.seriesParams.some( - (seriesParams: { mode: string }) => seriesParams.mode === 'stacked' - ) - ) { - telemetryVisTypeName = 'area_stacked'; - } - - getUsageCollection().reportUiCounter( - executionContext?.type ?? '', - 'count', - `render_agg_based_${telemetryVisTypeName}` - ); - - if (hasRendered$.getValue() === true) return; - hasRendered$.next(true); - hasRendered$.complete(); - }, - onEvent: async (event) => { - // Visualize doesn't respond to sizing events, so ignore. - if (isChartSizeEvent(event)) { - return; - } - const currentVis = vis$.getValue(); - if (!disableTriggers) { - const triggerId = get( - VIS_EVENT_TO_TRIGGER, - event.name, - VIS_EVENT_TO_TRIGGER.filter - ); - let context; - - if (triggerId === VIS_EVENT_TO_TRIGGER.applyFilter) { - context = { - embeddable: api, - timeFieldName: currentVis.data.indexPattern?.timeFieldName!, - ...event.data, - }; - } else { - context = { - embeddable: api, - data: { - timeFieldName: currentVis.data.indexPattern?.timeFieldName!, - ...event.data, - }, - }; - } - await getUiActions().getTrigger(triggerId).exec(context); - } - }, - onData: (_, inspectorAdapters) => { - inspectorAdapters$.next( - typeof inspectorAdapters === 'function' ? inspectorAdapters() : inspectorAdapters - ); - dataLoading$.next(false); - }, - }); - }; - return await getExpressionParams(); - }) - ) - .subscribe(({ params, abortController }) => { - if (params) expressionParams$.next(params); - expressionAbortController$.next(abortController); - }); - - return { - api, - Component: () => { - const expressionParams = useStateFromPublishingSubject(expressionParams$); - const renderCount = useStateFromPublishingSubject(renderCount$); - const hasRendered = useStateFromPublishingSubject(hasRendered$); - const domNode = useRef(null); - const { error, isLoading } = useExpressionRenderer(domNode, expressionParams); - - useEffect(() => { - return () => { - fetchSubscription.unsubscribe(); - maybeStopDynamicActions?.stopDynamicActions(); - }; - }, []); - - useEffect(() => { - if (hasRendered && domNode.current) { - dispatchRenderComplete(domNode.current); - } - }, [hasRendered]); - - return ( -
- {/* Replicate the loading state for the expression renderer to avoid FOUC */} - - {isLoading && } - {!isLoading && error && ( - - {i18n.translate('visualizations.embeddable.errorTitle', { - defaultMessage: 'Unable to load visualization ', - })} - - } - body={ -

- {error.name}: {error.message} -

- } - /> - )} -
-
- ); - }, - }; - }, -}); diff --git a/src/plugins/visualizations/public/services.ts b/src/plugins/visualizations/public/services.ts index 1fc9f9a30f345..446ac602365c7 100644 --- a/src/plugins/visualizations/public/services.ts +++ b/src/plugins/visualizations/public/services.ts @@ -6,34 +6,32 @@ * Side Public License, v 1. */ -import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; +import { createGetterSetter } from '@kbn/kibana-utils-plugin/public'; import type { ApplicationStart, Capabilities, ChromeStart, - DocLinksStart, HttpStart, IUiSettingsClient, OverlayStart, SavedObjectsStart, + DocLinksStart, ThemeServiceStart, ExecutionContextSetup, AnalyticsServiceStart, I18nStart, } from '@kbn/core/public'; +import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import type { DataPublicPluginStart, TimefilterContract } from '@kbn/data-plugin/public'; -import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; -import type { EmbeddableStart } from '@kbn/embeddable-plugin/public'; import type { ExpressionsStart } from '@kbn/expressions-plugin/public'; import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; -import type { Start as InspectorStart } from '@kbn/inspector-plugin/public'; -import { createGetterSetter } from '@kbn/kibana-utils-plugin/public'; -import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; -import type { SavedObjectTaggingOssPluginStart } from '@kbn/saved-objects-tagging-oss-plugin/public'; -import type { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public'; -import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; +import type { EmbeddableStart } from '@kbn/embeddable-plugin/public'; +import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; +import type { SavedObjectTaggingOssPluginStart } from '@kbn/saved-objects-tagging-oss-plugin/public'; import type { UsageCollectionStart } from '@kbn/usage-collection-plugin/public'; +import { SavedObjectsManagementPluginStart } from '@kbn/saved-objects-management-plugin/public'; +import type { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public'; import type { TypesStart } from './vis_types'; export const [getUISettings, setUISettings] = createGetterSetter('UISettings'); @@ -94,8 +92,3 @@ export const [getContentManagement, setContentManagement] = export const [getSavedSearch, setSavedSearch] = createGetterSetter('SavedSearch'); - -export const [getDataViews, setDataViews] = - createGetterSetter('DataViews'); - -export const [getInspector, setInspector] = createGetterSetter('Inspector'); diff --git a/src/plugins/visualizations/public/utils/saved_objects_utils/save_with_confirmation.ts b/src/plugins/visualizations/public/utils/saved_objects_utils/save_with_confirmation.ts index 127db257e6450..55cea2a79b37c 100644 --- a/src/plugins/visualizations/public/utils/saved_objects_utils/save_with_confirmation.ts +++ b/src/plugins/visualizations/public/utils/saved_objects_utils/save_with_confirmation.ts @@ -11,10 +11,9 @@ import { i18n } from '@kbn/i18n'; import type { SavedObjectsCreateOptions } from '@kbn/core/public'; import { OVERWRITE_REJECTED } from './constants'; import { confirmModalPromise } from './confirm_modal_promise'; -import type { StartServices } from '../../types'; +import type { StartServices, VisSavedObject } from '../../types'; import { visualizationsClient } from '../../content_management'; import { VisualizationSavedObjectAttributes, VisualizationSavedObject } from '../../../common'; -import { VisualizeOutputState } from '../../react_embeddable/types'; /** * Attempts to create the current object using the serialized source. If an object already @@ -31,7 +30,7 @@ import { VisualizeOutputState } from '../../react_embeddable/types'; */ export async function saveWithConfirmation( source: VisualizationSavedObjectAttributes, - savedObject: Pick, + savedObject: Pick, options: SavedObjectsCreateOptions, services: StartServices ): Promise<{ item: VisualizationSavedObject }> { diff --git a/src/plugins/visualizations/public/utils/saved_visualization_references/index.ts b/src/plugins/visualizations/public/utils/saved_visualization_references/index.ts index a7097c3ec9759..0acda1c0a0f80 100644 --- a/src/plugins/visualizations/public/utils/saved_visualization_references/index.ts +++ b/src/plugins/visualizations/public/utils/saved_visualization_references/index.ts @@ -9,10 +9,4 @@ export { extractControlsReferences, injectControlsReferences } from './controls_references'; export { extractTimeSeriesReferences, injectTimeSeriesReferences } from './timeseries_references'; -export { - extractReferences, - injectReferences, - serializeReferences, - deserializeReferences, - convertSavedObjectAttributesToReferences, -} from './saved_visualization_references'; +export { extractReferences, injectReferences } from './saved_visualization_references'; diff --git a/src/plugins/visualizations/public/utils/saved_visualization_references/saved_visualization_references.ts b/src/plugins/visualizations/public/utils/saved_visualization_references/saved_visualization_references.ts index fd5849bf85de6..8945da771db7f 100644 --- a/src/plugins/visualizations/public/utils/saved_visualization_references/saved_visualization_references.ts +++ b/src/plugins/visualizations/public/utils/saved_visualization_references/saved_visualization_references.ts @@ -12,128 +12,11 @@ import { injectSearchSourceReferences, SerializedSearchSourceFields, } from '@kbn/data-plugin/public'; -import { DATA_VIEW_SAVED_OBJECT_TYPE } from '@kbn/data-views-plugin/common'; -import { isObject } from 'lodash'; -import { Reference } from '../../../common/content_management'; -import { VisualizeSavedVisInputState } from '../../react_embeddable/types'; -import { SavedVisState, SerializedVis, VisSavedObject } from '../../types'; -import type { SerializableAttributes } from '../../vis_types/vis_type_alias_registry'; -import { extractControlsReferences, injectControlsReferences } from './controls_references'; -import { extractTimeSeriesReferences, injectTimeSeriesReferences } from './timeseries_references'; - -const isValidSavedVis = (savedVis: unknown): savedVis is SavedVisState => - isObject(savedVis) && 'type' in savedVis && 'params' in savedVis; - -// Data plugin's `isSerializedSearchSource` does not actually rule out objects that aren't serialized search source fields -function isSerializedSearchSource( - maybeSerializedSearchSource: unknown -): maybeSerializedSearchSource is SerializedSearchSourceFields { - return ( - typeof maybeSerializedSearchSource === 'object' && - maybeSerializedSearchSource !== null && - !Object.hasOwn(maybeSerializedSearchSource, 'dependencies') && - !Object.hasOwn(maybeSerializedSearchSource, 'fields') - ); -} +import { SavedVisState, VisSavedObject } from '../../types'; -export function serializeReferences(savedVis: SerializedVis) { - const { searchSource, savedSearchId } = savedVis.data; - const references: Reference[] = []; - let serializedSearchSource = searchSource; - - // TSVB uses legacy visualization state, which doesn't serialize search source properly - if (!isSerializedSearchSource(searchSource)) { - serializedSearchSource = (searchSource as { fields: SerializedSearchSourceFields }).fields; - } - - if (searchSource) { - const [extractedSearchSource, searchSourceReferences] = - extractSearchSourceReferences(serializedSearchSource); - serializedSearchSource = extractedSearchSource; - searchSourceReferences.forEach((r) => references.push(r)); - } - - // Extract saved search - if (savedSearchId) { - references.push({ - name: 'search_0', - type: 'search', - id: String(savedSearchId), - }); - } - - // Extract index patterns from controls - if (isValidSavedVis(savedVis)) { - extractControlsReferences(savedVis.type, savedVis.params, references); - extractTimeSeriesReferences(savedVis.type, savedVis.params, references); - } - - return { references, serializedSearchSource }; -} - -export function deserializeReferences( - state: VisualizeSavedVisInputState, - references: Reference[] = [] -) { - const { savedVis } = state; - const { searchSource, savedSearchRefName } = savedVis.data; - const updatedReferences: Reference[] = [...references]; - let deserializedSearchSource = searchSource; - if (searchSource) { - // TSVB uses legacy visualization state, which doesn't serialize search source properly - if (!isSerializedSearchSource(searchSource)) { - deserializedSearchSource = (searchSource as { fields: SerializedSearchSourceFields }).fields; - } - try { - deserializedSearchSource = injectSearchSourceReferences( - deserializedSearchSource as any, - updatedReferences - ); - } catch (e) { - // Allow missing index pattern error to surface in vis - } - } - if (savedSearchRefName) { - const savedSearchReference = updatedReferences.find( - (reference) => reference.name === savedSearchRefName - ); - - if (!savedSearchReference) { - throw new Error(`Could not find saved search reference "${savedSearchRefName}"`); - } - } - - if (isValidSavedVis(savedVis)) { - injectControlsReferences(savedVis.type, savedVis.params, updatedReferences); - injectTimeSeriesReferences(savedVis.type, savedVis.params, updatedReferences); - } - return { references: updatedReferences, deserializedSearchSource }; -} - -export function convertSavedObjectAttributesToReferences(attributes: { - kibanaSavedObjectMeta?: { searchSourceJSON: string }; - savedSearchId?: string; -}) { - const references: Reference[] = []; - if (attributes.kibanaSavedObjectMeta?.searchSourceJSON) { - const searchSource = JSON.parse(attributes.kibanaSavedObjectMeta.searchSourceJSON); - const indexId = searchSource.index.id; - const refName = 'kibanaSavedObjectMeta.searchSourceJSON.index'; - references.push({ - name: refName, - type: DATA_VIEW_SAVED_OBJECT_TYPE, - id: indexId, - }); - } - if (attributes.savedSearchId) { - references.push({ - name: 'search_0', - type: 'search', - id: attributes.savedSearchId, - }); - } - return references; -} +import { extractTimeSeriesReferences, injectTimeSeriesReferences } from './timeseries_references'; +import { extractControlsReferences, injectControlsReferences } from './controls_references'; +import type { SerializableAttributes } from '../../vis_types/vis_type_alias_registry'; export function extractReferences({ attributes, diff --git a/src/plugins/visualizations/public/utils/saved_visualize_utils.ts b/src/plugins/visualizations/public/utils/saved_visualize_utils.ts index e8b2fc4a9f6a0..f8a47ba1efa66 100644 --- a/src/plugins/visualizations/public/utils/saved_visualize_utils.ts +++ b/src/plugins/visualizations/public/utils/saved_visualize_utils.ts @@ -17,7 +17,7 @@ import { } from '@kbn/data-plugin/public'; import type { SavedObjectsTaggingApi } from '@kbn/saved-objects-tagging-oss-plugin/public'; import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; -import { VisualizationSavedObject, Reference } from '../../common/content_management'; +import { VisualizationSavedObject } from '../../common/content_management'; import { saveWithConfirmation, checkForDuplicateTitle } from './saved_objects_utils'; import { VisualizationsAppExtension } from '../vis_types/vis_type_alias_registry'; import type { @@ -223,6 +223,7 @@ export async function getSavedVisualization( if (typeof opts !== 'object') { opts = { id: opts } as GetVisOptions; } + const id = (opts.id as string) || ''; const savedObject = { id, @@ -320,8 +321,7 @@ export async function saveVisualization( }: SaveVisOptions, services: StartServices & { savedObjectsTagging?: SavedObjectsTaggingApi; - }, - baseReferences: Reference[] = [] + } ) { // Save the original id in case the save fails. const originalId = savedObject.id; @@ -341,11 +341,10 @@ export async function saveVisualization( uiStateJSON: savedObject.uiStateJSON, description: savedObject.description, savedSearchId: savedObject.savedSearchId, - savedSearchRefName: savedObject.savedSearchRefName, - version: savedObject.version ?? '1', + version: savedObject.version, kibanaSavedObjectMeta: {}, }; - let references: SavedObjectReference[] = baseReferences; + let references: SavedObjectReference[] = []; if (savedObject.searchSource) { const { searchSourceJSON, references: searchSourceReferences } = @@ -388,7 +387,6 @@ export async function saveVisualization( migrationVersion: savedObject.migrationVersion, references: extractedRefs.references, }; - const resp = confirmOverwrite ? await saveWithConfirmation(attributes, savedObject, createOpt, services) : savedObject.id diff --git a/src/plugins/visualizations/public/visualize_app/types.ts b/src/plugins/visualizations/public/visualize_app/types.ts index 8c397e1a51fe1..7e91cd4ce2bd0 100644 --- a/src/plugins/visualizations/public/visualize_app/types.ts +++ b/src/plugins/visualizations/public/visualize_app/types.ts @@ -105,10 +105,6 @@ export interface VisualizeServices extends CoreStart { visualizeCapabilities: Record>; dashboardCapabilities: Record>; setActiveUrl: (newUrl: string) => void; - /** @deprecated - * VisualizeEmbeddable is no longer registered with the legacy embeddable system and is only - * used within the visualize editor. - */ createVisEmbeddableFromObject: ReturnType; restorePreviousUrl: () => void; scopedHistory: ScopedHistory; diff --git a/src/plugins/visualizations/public/visualize_app/utils/get_top_nav_config.tsx b/src/plugins/visualizations/public/visualize_app/utils/get_top_nav_config.tsx index 1ae4e5f8f6b73..c903b49518246 100644 --- a/src/plugins/visualizations/public/visualize_app/utils/get_top_nav_config.tsx +++ b/src/plugins/visualizations/public/visualize_app/utils/get_top_nav_config.tsx @@ -28,7 +28,7 @@ import { import { unhashUrl } from '@kbn/kibana-utils-plugin/public'; import { EmbeddableStateTransfer } from '@kbn/embeddable-plugin/public'; import { saveVisualization } from '../../utils/saved_visualize_utils'; -import { VISUALIZE_EMBEDDABLE_TYPE, getFullPath } from '../..'; +import { VISUALIZE_EMBEDDABLE_TYPE, VisualizeInput, getFullPath } from '../..'; import { VisualizeServices, @@ -245,8 +245,8 @@ export const getTopNavConfig = ( const state = { input: { - serializedVis: vis.serialize(), - }, + savedVis: vis.serialize(), + } as VisualizeInput, embeddableId, type: VISUALIZE_EMBEDDABLE_TYPE, searchSessionId: data.search.session.getSessionId(), @@ -514,12 +514,12 @@ export const getTopNavConfig = ( const state = { input: { - serializedVis: { + savedVis: { ...vis.serialize(), title: newTitle, description: newDescription, }, - }, + } as VisualizeInput, embeddableId, type: VISUALIZE_EMBEDDABLE_TYPE, searchSessionId: data.search.session.getSessionId(), diff --git a/src/plugins/visualizations/public/visualize_app/utils/get_visualization_instance.ts b/src/plugins/visualizations/public/visualize_app/utils/get_visualization_instance.ts index f019819301011..9b3c929e54c69 100644 --- a/src/plugins/visualizations/public/visualize_app/utils/get_visualization_instance.ts +++ b/src/plugins/visualizations/public/visualize_app/utils/get_visualization_instance.ts @@ -12,9 +12,14 @@ import { SavedFieldNotFound, SavedFieldTypeInvalidForAgg } from '@kbn/kibana-uti import { SavedSearch } from '@kbn/saved-search-plugin/public'; import { createVisAsync } from '../../vis_async'; import { convertToSerializedVis, getSavedVisualization } from '../../utils/saved_visualize_utils'; -import { SerializedVis, Vis, VisSavedObject, VisualizeEmbeddableContract } from '../..'; +import { + SerializedVis, + Vis, + VisSavedObject, + VisualizeEmbeddableContract, + VisualizeInput, +} from '../..'; import type { VisInstance, VisualizeServices } from '../types'; -import { VisualizeInput } from '../../embeddable'; function isErrorRelatedToRuntimeFields(error: ExpressionValueError['error']) { const originalError = error.original || error; diff --git a/src/plugins/visualizations/server/embeddable/make_visualize_embeddable_factory.ts b/src/plugins/visualizations/server/embeddable/make_visualize_embeddable_factory.ts index 27c0eefe40340..3122fb8a09f66 100644 --- a/src/plugins/visualizations/server/embeddable/make_visualize_embeddable_factory.ts +++ b/src/plugins/visualizations/server/embeddable/make_visualize_embeddable_factory.ts @@ -126,7 +126,7 @@ const getEmbeddedVisualizationSearchSourceMigrations = ( searchSource: migrate(_state.savedVis.data.searchSource), }, }, - } as SerializableRecord; + }; } ); diff --git a/src/plugins/visualizations/tsconfig.json b/src/plugins/visualizations/tsconfig.json index 06d3931fe8e08..1592eff839af3 100644 --- a/src/plugins/visualizations/tsconfig.json +++ b/src/plugins/visualizations/tsconfig.json @@ -1,9 +1,14 @@ { "extends": "../../../tsconfig.base.json", "compilerOptions": { - "outDir": "target/types" + "outDir": "target/types", }, - "include": ["common/**/*", "public/**/*", "server/**/*", "../../../typings/**/*"], + "include": [ + "common/**/*", + "public/**/*", + "server/**/*", + "../../../typings/**/*" + ], "kbn_references": [ "@kbn/core", "@kbn/charts-plugin", @@ -55,8 +60,10 @@ "@kbn/content-management-table-list-view-table", "@kbn/content-management-tabbed-table-list-view", "@kbn/content-management-table-list-view", + "@kbn/content-management-utils", "@kbn/serverless", "@kbn/no-data-page-plugin", + "@kbn/search-response-warnings", "@kbn/logging", "@kbn/content-management-table-list-view-common", "@kbn/chart-expressions-common", @@ -66,13 +73,9 @@ "@kbn/shared-ux-markdown", "@kbn/react-kibana-context-render", "@kbn/react-kibana-mount", - "@kbn/core-execution-context-common", - "@kbn/presentation-containers", - "@kbn/core-mount-utils-browser", - "@kbn/presentation-containers", - "@kbn/search-response-warnings", - "@kbn/embeddable-enhanced-plugin", - "@kbn/content-management-utils" + "@kbn/presentation-containers" ], - "exclude": ["target/**/*"] + "exclude": [ + "target/**/*", + ] } diff --git a/test/functional/apps/dashboard/group3/dashboard_state.ts b/test/functional/apps/dashboard/group3/dashboard_state.ts index 449d7277f55b5..2c1ebee573599 100644 --- a/test/functional/apps/dashboard/group3/dashboard_state.ts +++ b/test/functional/apps/dashboard/group3/dashboard_state.ts @@ -185,9 +185,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.dashboard.waitForRenderComplete(); }; - // Skip this test; directly modifying the URL app state isn't fully supported in the new - // React embeddable framework, but this user interaction is not a high priority - describe.skip('Directly modifying url updates dashboard state', () => { + describe('Directly modifying url updates dashboard state', () => { before(async () => { await PageObjects.dashboard.gotoDashboardLandingPage(); await PageObjects.dashboard.clickNewDashboard(); diff --git a/test/functional/apps/dashboard/group5/dashboard_error_handling.ts b/test/functional/apps/dashboard/group5/dashboard_error_handling.ts index 2b000b1b7e9fe..ab8e8ac76f85b 100644 --- a/test/functional/apps/dashboard/group5/dashboard_error_handling.ts +++ b/test/functional/apps/dashboard/group5/dashboard_error_handling.ts @@ -59,7 +59,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const embeddableError = await testSubjects.find('embeddableError'); const errorMessage = await embeddableError.getVisibleText(); - expect(errorMessage).to.contain('Could not locate that data view'); + expect(errorMessage).to.contain('Could not find the data view'); }); }); }); diff --git a/test/functional/apps/dashboard/group6/embeddable_library.ts b/test/functional/apps/dashboard/group6/embeddable_library.ts index b0f68e84d738f..aa0a7341e17c0 100644 --- a/test/functional/apps/dashboard/group6/embeddable_library.ts +++ b/test/functional/apps/dashboard/group6/embeddable_library.ts @@ -41,7 +41,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dashboardAddPanel.closeAddPanel(); const originalPanel = await testSubjects.find('embeddablePanelHeading-RenderingTest:heatmap'); - await panelActions.unlinkFromLibrary(originalPanel); + await panelActions.legacyUnlinkFromLibrary(originalPanel); await testSubjects.existOrFail('unlinkPanelSuccess'); const updatedPanel = await testSubjects.find('embeddablePanelHeading-RenderingTest:heatmap'); @@ -59,7 +59,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('save visualize panel to embeddable library', async () => { const originalPanel = await testSubjects.find('embeddablePanelHeading-RenderingTest:heatmap'); - await panelActions.saveToLibrary('Rendering Test: heatmap - copy', originalPanel); + await panelActions.legacySaveToLibrary('Rendering Test: heatmap - copy', originalPanel); await testSubjects.existOrFail('addPanelToLibrarySuccess'); const updatedPanel = await testSubjects.find( diff --git a/test/plugin_functional/plugins/kbn_sample_panel_action/public/sample_panel_action.tsx b/test/plugin_functional/plugins/kbn_sample_panel_action/public/sample_panel_action.tsx index da0a3b55eb3ea..aa92d75fc0c13 100644 --- a/test/plugin_functional/plugins/kbn_sample_panel_action/public/sample_panel_action.tsx +++ b/test/plugin_functional/plugins/kbn_sample_panel_action/public/sample_panel_action.tsx @@ -10,14 +10,14 @@ import { CoreSetup } from '@kbn/core/public'; import { EuiFlyoutBody, EuiFlyoutHeader, EuiTitle } from '@elastic/eui'; import React from 'react'; -import { DefaultEmbeddableApi } from '@kbn/embeddable-plugin/public'; +import { IEmbeddable } from '@kbn/embeddable-plugin/public'; import { createAction } from '@kbn/ui-actions-plugin/public'; import { toMountPoint } from '@kbn/react-kibana-mount'; export const SAMPLE_PANEL_ACTION = 'samplePanelAction'; export interface SamplePanelActionContext { - embeddable: DefaultEmbeddableApi; + embeddable: IEmbeddable; } export function createSamplePanelAction(getStartServices: CoreSetup['getStartServices']) { @@ -37,7 +37,7 @@ export function createSamplePanelAction(getStartServices: CoreSetup['getStartSer -

{embeddable.panelTitle?.value}

+

{embeddable.getTitle()}

diff --git a/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/lens_migration_smoke_test.ts b/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/lens_migration_smoke_test.ts index 69f4f0e8f4915..6f6e19bb54ee8 100644 --- a/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/lens_migration_smoke_test.ts +++ b/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/lens_migration_smoke_test.ts @@ -21,7 +21,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'settings', 'header', 'savedObjects', 'dashboard']); - describe('Lens - Export import saved objects between versions', () => { + describe('Export import saved objects between versions', () => { before(async () => { await esArchiver.loadIfNeeded( 'x-pack/test/functional/es_archives/getting_started/shakespeare' diff --git a/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/tsvb_migration_smoke_test.ts b/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/tsvb_migration_smoke_test.ts index 49996231ecb70..c6d947337da21 100644 --- a/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/tsvb_migration_smoke_test.ts +++ b/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/tsvb_migration_smoke_test.ts @@ -17,7 +17,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'settings', 'header', 'savedObjects', 'dashboard']); - describe('TSVB - Export import saved objects between versions', () => { + describe('Export import saved objects between versions', () => { describe('From 7.12.1', () => { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); diff --git a/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/visualize_migration_smoke_test.ts b/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/visualize_migration_smoke_test.ts index 7ba93ff5c2298..6f8a387d276a0 100644 --- a/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/visualize_migration_smoke_test.ts +++ b/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/visualize_migration_smoke_test.ts @@ -21,7 +21,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects(['common', 'settings', 'header', 'savedObjects', 'dashboard']); - describe('Visualize - Export import saved objects between versions', () => { + describe('Export import saved objects between versions', () => { before(async () => { await esArchiver.loadIfNeeded( 'x-pack/test/functional/es_archives/getting_started/shakespeare' diff --git a/x-pack/test/functional/apps/dashboard/group3/reporting/screenshots.ts b/x-pack/test/functional/apps/dashboard/group3/reporting/screenshots.ts index 39420d619a91f..0a09c785d64a4 100644 --- a/x-pack/test/functional/apps/dashboard/group3/reporting/screenshots.ts +++ b/x-pack/test/functional/apps/dashboard/group3/reporting/screenshots.ts @@ -237,7 +237,7 @@ export default function ({ updateBaselines ); - expect(percentDiff).to.be.lessThan(0.1); + expect(percentDiff).to.be.lessThan(0.035); }); }); }); diff --git a/x-pack/test/functional/apps/lens/open_in_lens/tsvb/dashboard.ts b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/dashboard.ts index ca53fd388301f..880c35c98975e 100644 --- a/x-pack/test/functional/apps/lens/open_in_lens/tsvb/dashboard.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/dashboard.ts @@ -55,14 +55,9 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await dashboard.waitForRenderComplete(); await dashboardBadgeActions.expectExistsTimeRangeBadgeAction(); await panelActions.openContextMenu(); - const editInLensExists = await testSubjects.exists( - 'embeddablePanelAction-ACTION_EDIT_IN_LENS' - ); - if (!editInLensExists) { - await testSubjects.click('embeddablePanelMore-mainMenu'); - } - await testSubjects.click('embeddablePanelAction-ACTION_EDIT_IN_LENS'); + await panelActions.clickEdit(); + await visualize.navigateToLensFromAnotherVisualization(); await lens.waitForVisualization('xyVisChart'); await retry.try(async () => { const dimensions = await testSubjects.findAll('lns-dimensionTrigger'); @@ -90,7 +85,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await testSubjects.click('visualizesaveAndReturnButton'); // save it to library const originalPanel = await testSubjects.find('embeddablePanelHeading-'); - await panelActions.saveToLibrary('My TSVB to Lens viz 2', originalPanel); + await panelActions.legacySaveToLibrary('My TSVB to Lens viz 2', originalPanel); await dashboard.waitForRenderComplete(); const originalEmbeddableCount = await canvas.getEmbeddableCount(); diff --git a/x-pack/test/functional/apps/visualize/reporting.ts b/x-pack/test/functional/apps/visualize/reporting.ts index d6cdb5fedd728..cb29379fbbffb 100644 --- a/x-pack/test/functional/apps/visualize/reporting.ts +++ b/x-pack/test/functional/apps/visualize/reporting.ts @@ -138,7 +138,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.reporting.clickGenerateReportButton(); log.debug('get the report download URL'); - const url = await PageObjects.reporting.getReportURL(120000); + const url = await PageObjects.reporting.getReportURL(60000); log.debug('download the report'); const reportData = await PageObjects.reporting.getRawReportData(url ?? ''); const sessionReportPath = await PageObjects.reporting.writeSessionReport( diff --git a/x-pack/test/functional_execution_context/tests/browser.ts b/x-pack/test/functional_execution_context/tests/browser.ts index e1d7ba6a3b965..f7d265316decb 100644 --- a/x-pack/test/functional_execution_context/tests/browser.ts +++ b/x-pack/test/functional_execution_context/tests/browser.ts @@ -396,7 +396,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - describe.skip('propagates context for Vega visualizations', () => { + describe('propagates context for Vega visualizations', () => { // CHECKPOINT this is the test that failed and caused the global .skip() it('propagates to Elasticsearch via "x-opaque-id" header', async () => { await logContains({ diff --git a/x-pack/test_serverless/functional/test_suites/common/visualizations/group3/open_in_lens/tsvb/dashboard.ts b/x-pack/test_serverless/functional/test_suites/common/visualizations/group3/open_in_lens/tsvb/dashboard.ts index 91e5d16a8df5b..c41bf13a1e678 100644 --- a/x-pack/test_serverless/functional/test_suites/common/visualizations/group3/open_in_lens/tsvb/dashboard.ts +++ b/x-pack/test_serverless/functional/test_suites/common/visualizations/group3/open_in_lens/tsvb/dashboard.ts @@ -80,7 +80,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { // save it to library const originalPanel = await testSubjects.find('embeddablePanelHeading-'); - await panelActions.saveToLibrary('My TSVB to Lens viz 2', originalPanel); + await panelActions.legacySaveToLibrary('My TSVB to Lens viz 2', originalPanel); await dashboard.waitForRenderComplete(); const originalEmbeddableCount = await canvas.getEmbeddableCount();