From 07f62bf560c1902b1f79baa04176b732478222ab Mon Sep 17 00:00:00 2001 From: Stratoula Kalafateli Date: Tue, 5 Dec 2023 18:42:19 +0200 Subject: [PATCH] [Lens] Fixes the transition to a dashboard when originatingApp is not given (#172543) ## Summary Closes https://github.com/elastic/kibana/issues/172410 This is a regression caused by https://github.com/elastic/kibana/pull/167019. The originatingApp on the navigateToPrefilledEditor defaults to "" (empty string) and not undefined. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --- .../app_plugin/save_modal_container.tsx | 37 +-------- .../save_modal_container_helpers.test.ts | 76 +++++++++++++++++++ .../save_modal_container_helpers.ts | 44 +++++++++++ 3 files changed, 122 insertions(+), 35 deletions(-) create mode 100644 x-pack/plugins/lens/public/app_plugin/save_modal_container_helpers.test.ts create mode 100644 x-pack/plugins/lens/public/app_plugin/save_modal_container_helpers.ts diff --git a/x-pack/plugins/lens/public/app_plugin/save_modal_container.tsx b/x-pack/plugins/lens/public/app_plugin/save_modal_container.tsx index 83ae6cd66702c..3bebdb2e7c214 100644 --- a/x-pack/plugins/lens/public/app_plugin/save_modal_container.tsx +++ b/x-pack/plugins/lens/public/app_plugin/save_modal_container.tsx @@ -16,10 +16,11 @@ import type { LensAppProps, LensAppServices } from './types'; import type { SaveProps } from './app'; import { Document, checkForDuplicateTitle, SavedObjectIndexStore } from '../persistence'; import type { LensByReferenceInput, LensEmbeddableInput } from '../embeddable'; -import { APP_ID, getFullPath, LENS_EMBEDDABLE_TYPE } from '../../common/constants'; +import { APP_ID, getFullPath } from '../../common/constants'; import type { LensAppState } from '../state_management'; import { getPersisted } from '../state_management/init_middleware/load_initial'; import { VisualizeEditorContext } from '../types'; +import { redirectToDashboard } from './save_modal_container_helpers'; type ExtraProps = Pick & Partial>; @@ -171,40 +172,6 @@ export function SaveModalContainer({ ); } -const redirectToDashboard = ({ - embeddableInput, - dashboardFeatureFlag, - dashboardId, - originatingApp, - getOriginatingPath, - stateTransfer, -}: { - embeddableInput: LensEmbeddableInput; - dashboardId: string; - dashboardFeatureFlag: LensAppServices['dashboardFeatureFlag']; - originatingApp?: string; - getOriginatingPath?: (dashboardId: string) => string | undefined; - stateTransfer: LensAppServices['stateTransfer']; -}) => { - if (!dashboardFeatureFlag.allowByValueEmbeddables) { - throw new Error('redirectToDashboard called with by-value embeddables disabled'); - } - - const state = { - input: embeddableInput, - type: LENS_EMBEDDABLE_TYPE, - }; - - const path = - getOriginatingPath?.(dashboardId) ?? - (dashboardId === 'new' ? '#/create' : `#/view/${dashboardId}`); - const appId = originatingApp ?? 'dashboards'; - stateTransfer.navigateToWithEmbeddablePackage(appId, { - state, - path, - }); -}; - const getDocToSave = ( lastKnownDoc: Document, saveProps: SaveProps, diff --git a/x-pack/plugins/lens/public/app_plugin/save_modal_container_helpers.test.ts b/x-pack/plugins/lens/public/app_plugin/save_modal_container_helpers.test.ts new file mode 100644 index 0000000000000..0bf4be34a9db0 --- /dev/null +++ b/x-pack/plugins/lens/public/app_plugin/save_modal_container_helpers.test.ts @@ -0,0 +1,76 @@ +/* + * 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 { makeDefaultServices } from '../mocks'; +import type { LensEmbeddableInput } from '../embeddable'; +import type { LensAppServices } from './types'; +import { redirectToDashboard } from './save_modal_container_helpers'; + +describe('redirectToDashboard', () => { + const embeddableInput = { + test: 'test', + } as unknown as LensEmbeddableInput; + const mockServices = makeDefaultServices(); + + it('should return error in case of allowByValueEmbeddables false', () => { + expect(() => { + redirectToDashboard({ + embeddableInput, + dashboardFeatureFlag: { + allowByValueEmbeddables: false, + }, + dashboardId: 'id', + originatingApp: '', + getOriginatingPath: jest.fn(), + stateTransfer: mockServices.stateTransfer, + }); + }).toThrow('redirectToDashboard called with by-value embeddables disabled'); + }); + + it('should call the navigateToWithEmbeddablePackage with the correct args if originatingApp is given', () => { + const navigateToWithEmbeddablePackageSpy = jest.fn(); + const transferService = { + ...mockServices.stateTransfer, + navigateToWithEmbeddablePackage: navigateToWithEmbeddablePackageSpy, + } as unknown as LensAppServices['stateTransfer']; + redirectToDashboard({ + embeddableInput, + dashboardFeatureFlag: { + allowByValueEmbeddables: true, + }, + dashboardId: 'id', + originatingApp: 'security', + getOriginatingPath: jest.fn(), + stateTransfer: transferService, + }); + expect(navigateToWithEmbeddablePackageSpy).toHaveBeenCalledWith('security', { + path: '#/view/id', + state: { input: { test: 'test' }, type: 'lens' }, + }); + }); + + it('should call the navigateToWithEmbeddablePackage with the correct args if originatingApp is an empty string', () => { + const navigateToWithEmbeddablePackageSpy = jest.fn(); + const transferService = { + ...mockServices.stateTransfer, + navigateToWithEmbeddablePackage: navigateToWithEmbeddablePackageSpy, + } as unknown as LensAppServices['stateTransfer']; + redirectToDashboard({ + embeddableInput, + dashboardFeatureFlag: { + allowByValueEmbeddables: true, + }, + dashboardId: 'id', + originatingApp: '', + getOriginatingPath: jest.fn(), + stateTransfer: transferService, + }); + expect(navigateToWithEmbeddablePackageSpy).toHaveBeenCalledWith('dashboards', { + path: '#/view/id', + state: { input: { test: 'test' }, type: 'lens' }, + }); + }); +}); diff --git a/x-pack/plugins/lens/public/app_plugin/save_modal_container_helpers.ts b/x-pack/plugins/lens/public/app_plugin/save_modal_container_helpers.ts new file mode 100644 index 0000000000000..b8a9a8da72a49 --- /dev/null +++ b/x-pack/plugins/lens/public/app_plugin/save_modal_container_helpers.ts @@ -0,0 +1,44 @@ +/* + * 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 { LensAppServices } from './types'; +import type { LensEmbeddableInput } from '../embeddable'; +import { LENS_EMBEDDABLE_TYPE } from '../../common/constants'; + +export const redirectToDashboard = ({ + embeddableInput, + dashboardFeatureFlag, + dashboardId, + originatingApp, + getOriginatingPath, + stateTransfer, +}: { + embeddableInput: LensEmbeddableInput; + dashboardId: string; + dashboardFeatureFlag: LensAppServices['dashboardFeatureFlag']; + originatingApp?: string; + getOriginatingPath?: (dashboardId: string) => string | undefined; + stateTransfer: LensAppServices['stateTransfer']; +}) => { + if (!dashboardFeatureFlag.allowByValueEmbeddables) { + throw new Error('redirectToDashboard called with by-value embeddables disabled'); + } + + const state = { + input: embeddableInput, + type: LENS_EMBEDDABLE_TYPE, + }; + + const path = + getOriginatingPath?.(dashboardId) ?? + (dashboardId === 'new' ? '#/create' : `#/view/${dashboardId}`); + const appId = originatingApp || 'dashboards'; + stateTransfer.navigateToWithEmbeddablePackage(appId, { + state, + path, + }); +};