Skip to content

Commit e600b6b

Browse files
Return to dashboard after editing embeddable (#62865) (#65371)
Changed the process for saving visualizations and lens visualizations when the user has been redirected there from another application. Co-authored-by: Elastic Machine <[email protected]>
1 parent 87494df commit e600b6b

File tree

34 files changed

+650
-198
lines changed

34 files changed

+650
-198
lines changed

src/plugins/dashboard/public/application/embeddable/viewport/dashboard_viewport.test.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
import { KibanaContextProvider } from '../../../../../kibana_react/public';
3535
// eslint-disable-next-line
3636
import { embeddablePluginMock } from 'src/plugins/embeddable/public/mocks';
37+
import { applicationServiceMock } from '../../../../../../core/public/mocks';
3738

3839
let dashboardContainer: DashboardContainer | undefined;
3940

@@ -50,7 +51,7 @@ function getProps(
5051

5152
const start = doStart();
5253
const options: DashboardContainerOptions = {
53-
application: {} as any,
54+
application: applicationServiceMock.createStartContract(),
5455
embeddable: {
5556
getTriggerCompatibleActions: (() => []) as any,
5657
getEmbeddableFactories: start.getEmbeddableFactories,

src/plugins/dashboard/public/application/tests/dashboard_container.test.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import { embeddablePluginMock } from '../../../../embeddable/public/mocks';
3838
import { inspectorPluginMock } from '../../../../inspector/public/mocks';
3939
import { KibanaContextProvider } from '../../../../kibana_react/public';
4040
import { uiActionsPluginMock } from '../../../../ui_actions/public/mocks';
41+
import { applicationServiceMock } from '../../../../../core/public/mocks';
4142

4243
test('DashboardContainer in edit mode shows edit mode actions', async () => {
4344
const inspector = inspectorPluginMock.createStartContract();
@@ -56,7 +57,7 @@ test('DashboardContainer in edit mode shows edit mode actions', async () => {
5657

5758
const initialInput = getSampleDashboardInput({ viewMode: ViewMode.VIEW });
5859
const options: DashboardContainerOptions = {
59-
application: {} as any,
60+
application: applicationServiceMock.createStartContract(),
6061
embeddable: start,
6162
notifications: {} as any,
6263
overlays: {} as any,
@@ -84,7 +85,7 @@ test('DashboardContainer in edit mode shows edit mode actions', async () => {
8485
getAllEmbeddableFactories={(() => []) as any}
8586
getEmbeddableFactory={(() => null) as any}
8687
notifications={{} as any}
87-
application={{} as any}
88+
application={options.application}
8889
overlays={{} as any}
8990
inspector={inspector}
9091
SavedObjectFinder={() => null}

src/plugins/dashboard/public/dashboard_constants.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
*/
1919

2020
export const DashboardConstants = {
21-
ADD_VISUALIZATION_TO_DASHBOARD_MODE_PARAM: 'addToDashboard',
2221
LANDING_PAGE_PATH: '/dashboards',
2322
CREATE_NEW_DASHBOARD_URL: '/dashboard',
2423
ADD_EMBEDDABLE_ID: 'addEmbeddableId',

src/plugins/embeddable/public/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import './index.scss';
2222
import { PluginInitializerContext } from 'src/core/public';
2323
import { EmbeddablePublicPlugin } from './plugin';
2424

25+
export { EMBEDDABLE_ORIGINATING_APP_PARAM } from './types';
2526
export {
2627
ACTION_ADD_PANEL,
2728
ACTION_APPLY_FILTER,

src/plugins/embeddable/public/lib/actions/edit_panel_action.test.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@ import { Embeddable, EmbeddableInput } from '../embeddables';
2222
import { ViewMode } from '../types';
2323
import { ContactCardEmbeddable } from '../test_samples';
2424
import { embeddablePluginMock } from '../../mocks';
25+
import { applicationServiceMock } from '../../../../../core/public/mocks';
2526

2627
const { doStart } = embeddablePluginMock.createInstance();
2728
const start = doStart();
2829
const getFactory = start.getEmbeddableFactory;
30+
const applicationMock = applicationServiceMock.createStartContract();
2931

3032
class EditableEmbeddable extends Embeddable {
3133
public readonly type = 'EDITABLE_EMBEDDABLE';
@@ -41,7 +43,7 @@ class EditableEmbeddable extends Embeddable {
4143
}
4244

4345
test('is compatible when edit url is available, in edit mode and editable', async () => {
44-
const action = new EditPanelAction(getFactory, {} as any);
46+
const action = new EditPanelAction(getFactory, applicationMock);
4547
expect(
4648
await action.isCompatible({
4749
embeddable: new EditableEmbeddable({ id: '123', viewMode: ViewMode.EDIT }, true),
@@ -50,7 +52,7 @@ test('is compatible when edit url is available, in edit mode and editable', asyn
5052
});
5153

5254
test('getHref returns the edit urls', async () => {
53-
const action = new EditPanelAction(getFactory, {} as any);
55+
const action = new EditPanelAction(getFactory, applicationMock);
5456
expect(action.getHref).toBeDefined();
5557

5658
if (action.getHref) {
@@ -64,7 +66,7 @@ test('getHref returns the edit urls', async () => {
6466
});
6567

6668
test('is not compatible when edit url is not available', async () => {
67-
const action = new EditPanelAction(getFactory, {} as any);
69+
const action = new EditPanelAction(getFactory, applicationMock);
6870
const embeddable = new ContactCardEmbeddable(
6971
{
7072
id: '123',
@@ -83,7 +85,7 @@ test('is not compatible when edit url is not available', async () => {
8385
});
8486

8587
test('is not visible when edit url is available but in view mode', async () => {
86-
const action = new EditPanelAction(getFactory, {} as any);
88+
const action = new EditPanelAction(getFactory, applicationMock);
8789
expect(
8890
await action.isCompatible({
8991
embeddable: new EditableEmbeddable(
@@ -98,7 +100,7 @@ test('is not visible when edit url is available but in view mode', async () => {
98100
});
99101

100102
test('is not compatible when edit url is available, in edit mode, but not editable', async () => {
101-
const action = new EditPanelAction(getFactory, {} as any);
103+
const action = new EditPanelAction(getFactory, applicationMock);
102104
expect(
103105
await action.isCompatible({
104106
embeddable: new EditableEmbeddable(

src/plugins/embeddable/public/lib/actions/edit_panel_action.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@
2020
import { i18n } from '@kbn/i18n';
2121
import { ApplicationStart } from 'kibana/public';
2222
import { Action } from 'src/plugins/ui_actions/public';
23+
import { take } from 'rxjs/operators';
2324
import { ViewMode } from '../types';
2425
import { EmbeddableFactoryNotFoundError } from '../errors';
25-
import { IEmbeddable } from '../embeddables';
2626
import { EmbeddableStart } from '../../plugin';
27+
import { EMBEDDABLE_ORIGINATING_APP_PARAM, IEmbeddable } from '../..';
2728

2829
export const ACTION_EDIT_PANEL = 'editPanel';
2930

@@ -35,11 +36,18 @@ export class EditPanelAction implements Action<ActionContext> {
3536
public readonly type = ACTION_EDIT_PANEL;
3637
public readonly id = ACTION_EDIT_PANEL;
3738
public order = 50;
39+
public currentAppId: string | undefined;
3840

3941
constructor(
4042
private readonly getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory'],
4143
private readonly application: ApplicationStart
42-
) {}
44+
) {
45+
if (this.application?.currentAppId$) {
46+
this.application.currentAppId$
47+
.pipe(take(1))
48+
.subscribe((appId: string | undefined) => (this.currentAppId = appId));
49+
}
50+
}
4351

4452
public getDisplayName({ embeddable }: ActionContext) {
4553
const factory = this.getEmbeddableFactory(embeddable.type);
@@ -93,7 +101,15 @@ export class EditPanelAction implements Action<ActionContext> {
93101
}
94102

95103
public async getHref({ embeddable }: ActionContext): Promise<string> {
96-
const editUrl = embeddable ? embeddable.getOutput().editUrl : undefined;
104+
let editUrl = embeddable ? embeddable.getOutput().editUrl : undefined;
105+
if (editUrl && this.currentAppId) {
106+
editUrl += `?${EMBEDDABLE_ORIGINATING_APP_PARAM}=${this.currentAppId}`;
107+
108+
// TODO: Remove this after https://github.com/elastic/kibana/pull/63443
109+
if (this.currentAppId === 'kibana') {
110+
editUrl += `:${window.location.hash.split(/[\/\?]/)[1]}`;
111+
}
112+
}
97113
return editUrl ? editUrl : '';
98114
}
99115
}

src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import {
4444
import { inspectorPluginMock } from '../../../../inspector/public/mocks';
4545
import { EuiBadge } from '@elastic/eui';
4646
import { embeddablePluginMock } from '../../mocks';
47+
import { applicationServiceMock } from '../../../../../core/public/mocks';
4748

4849
const actionRegistry = new Map<string, Action>();
4950
const triggerRegistry = new Map<string, Trigger>();
@@ -55,6 +56,7 @@ const trigger: Trigger = {
5556
id: CONTEXT_MENU_TRIGGER,
5657
};
5758
const embeddableFactory = new ContactCardEmbeddableFactory((() => null) as any, {} as any);
59+
const applicationMock = applicationServiceMock.createStartContract();
5860

5961
actionRegistry.set(editModeAction.id, editModeAction);
6062
triggerRegistry.set(trigger.id, trigger);
@@ -159,7 +161,7 @@ test('HelloWorldContainer in view mode hides edit mode actions', async () => {
159161
getAllEmbeddableFactories={start.getEmbeddableFactories}
160162
getEmbeddableFactory={start.getEmbeddableFactory}
161163
notifications={{} as any}
162-
application={{} as any}
164+
application={applicationMock}
163165
overlays={{} as any}
164166
inspector={inspector}
165167
SavedObjectFinder={() => null}
@@ -199,7 +201,7 @@ const renderInEditModeAndOpenContextMenu = async (
199201
getEmbeddableFactory={start.getEmbeddableFactory}
200202
notifications={{} as any}
201203
overlays={{} as any}
202-
application={{} as any}
204+
application={applicationMock}
203205
inspector={inspector}
204206
SavedObjectFinder={() => null}
205207
/>
@@ -306,7 +308,7 @@ test('HelloWorldContainer in edit mode shows edit mode actions', async () => {
306308
getEmbeddableFactory={start.getEmbeddableFactory}
307309
notifications={{} as any}
308310
overlays={{} as any}
309-
application={{} as any}
311+
application={applicationMock}
310312
inspector={inspector}
311313
SavedObjectFinder={() => null}
312314
/>
@@ -369,7 +371,7 @@ test('Updates when hidePanelTitles is toggled', async () => {
369371
getEmbeddableFactory={start.getEmbeddableFactory}
370372
notifications={{} as any}
371373
overlays={{} as any}
372-
application={{} as any}
374+
application={applicationMock}
373375
inspector={inspector}
374376
SavedObjectFinder={() => null}
375377
/>
@@ -422,7 +424,7 @@ test('Check when hide header option is false', async () => {
422424
getEmbeddableFactory={start.getEmbeddableFactory}
423425
notifications={{} as any}
424426
overlays={{} as any}
425-
application={{} as any}
427+
application={applicationMock}
426428
inspector={inspector}
427429
SavedObjectFinder={() => null}
428430
hideHeader={false}

src/plugins/embeddable/public/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import {
2626
EmbeddableFactoryDefinition,
2727
} from './lib/embeddables';
2828

29+
export const EMBEDDABLE_ORIGINATING_APP_PARAM = 'embeddableOriginatingApp';
30+
2931
export type EmbeddableFactoryRegistry = Map<string, EmbeddableFactory>;
3032

3133
export type EmbeddableFactoryProvider = <

src/plugins/saved_objects/public/index.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,14 @@
1919

2020
import { SavedObjectsPublicPlugin } from './plugin';
2121

22-
export { OnSaveProps, SavedObjectSaveModal, SaveResult, showSaveModal } from './save_modal';
22+
export {
23+
OnSaveProps,
24+
SavedObjectSaveModal,
25+
SavedObjectSaveModalOrigin,
26+
SaveModalState,
27+
SaveResult,
28+
showSaveModal,
29+
} from './save_modal';
2330
export { getSavedObjectFinder, SavedObjectFinderUi, SavedObjectMetaData } from './finder';
2431
export {
2532
SavedObjectLoader,

src/plugins/saved_objects/public/save_modal/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@
1717
* under the License.
1818
*/
1919

20-
export { SavedObjectSaveModal, OnSaveProps } from './saved_object_save_modal';
20+
export { SavedObjectSaveModal, OnSaveProps, SaveModalState } from './saved_object_save_modal';
21+
export { SavedObjectSaveModalOrigin } from './saved_object_save_modal_origin';
2122
export { showSaveModal, SaveResult } from './show_saved_object_save_modal';

0 commit comments

Comments
 (0)