Skip to content

Commit

Permalink
[Time to Visualize] Fix Unlink Action via Rollback of ReplacePanel (#…
Browse files Browse the repository at this point in the history
…83873) (#84346)

* Fixed unlink action via rollback of replacePanel changes
  • Loading branch information
ThomThomson authored Nov 25, 2020
1 parent 0b5404c commit dfc0123
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,17 @@ test('Add to library is not compatible when embeddable is not in a dashboard con
test('Add to library replaces embeddableId and retains panel count', async () => {
const dashboard = embeddable.getRoot() as IContainer;
const originalPanelCount = Object.keys(dashboard.getInput().panels).length;
const originalPanelKeySet = new Set(Object.keys(dashboard.getInput().panels));

const action = new AddToLibraryAction({ toasts: coreStart.notifications.toasts });
await action.execute({ embeddable });
expect(Object.keys(container.getInput().panels).length).toEqual(originalPanelCount);
expect(Object.keys(container.getInput().panels)).toContain(embeddable.id);
const newPanel = container.getInput().panels[embeddable.id!];

const newPanelId = Object.keys(container.getInput().panels).find(
(key) => !originalPanelKeySet.has(key)
);
expect(newPanelId).toBeDefined();
const newPanel = container.getInput().panels[newPanelId!];
expect(newPanel.type).toEqual(embeddable.type);
});

Expand All @@ -158,10 +163,15 @@ test('Add to library returns reference type input', async () => {
mockedByReferenceInput: { savedObjectId: 'testSavedObjectId', id: embeddable.id },
mockedByValueInput: { attributes: complicatedAttributes, id: embeddable.id } as EmbeddableInput,
});
const dashboard = embeddable.getRoot() as IContainer;
const originalPanelKeySet = new Set(Object.keys(dashboard.getInput().panels));
const action = new AddToLibraryAction({ toasts: coreStart.notifications.toasts });
await action.execute({ embeddable });
expect(Object.keys(container.getInput().panels)).toContain(embeddable.id);
const newPanel = container.getInput().panels[embeddable.id!];
const newPanelId = Object.keys(container.getInput().panels).find(
(key) => !originalPanelKeySet.has(key)
);
expect(newPanelId).toBeDefined();
const newPanel = container.getInput().panels[newPanelId!];
expect(newPanel.type).toEqual(embeddable.type);
expect(newPanel.explicitInput.attributes).toBeUndefined();
expect(newPanel.explicitInput.savedObjectId).toBe('testSavedObjectId');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

import { i18n } from '@kbn/i18n';
import _ from 'lodash';
import uuid from 'uuid';
import { ActionByType, IncompatibleActionError } from '../../ui_actions_plugin';
import { ViewMode, PanelState, IEmbeddable } from '../../embeddable_plugin';
import {
Expand Down Expand Up @@ -89,9 +88,9 @@ export class AddToLibraryAction implements ActionByType<typeof ACTION_ADD_TO_LIB

const newPanel: PanelState<EmbeddableInput> = {
type: embeddable.type,
explicitInput: { ...newInput, id: uuid.v4() },
explicitInput: { ...newInput },
};
dashboard.replacePanel(panelToReplace, newPanel);
dashboard.replacePanel(panelToReplace, newPanel, true);

const title = i18n.translate('dashboard.panel.addToLibrary.successMessage', {
defaultMessage: `Panel '{panelTitle}' was added to the visualize library`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,16 @@ test('Unlink is not compatible when embeddable is not in a dashboard container',
test('Unlink replaces embeddableId and retains panel count', async () => {
const dashboard = embeddable.getRoot() as IContainer;
const originalPanelCount = Object.keys(dashboard.getInput().panels).length;
const originalPanelKeySet = new Set(Object.keys(dashboard.getInput().panels));
const action = new UnlinkFromLibraryAction({ toasts: coreStart.notifications.toasts });
await action.execute({ embeddable });
expect(Object.keys(container.getInput().panels).length).toEqual(originalPanelCount);
expect(Object.keys(container.getInput().panels)).toContain(embeddable.id);
const newPanel = container.getInput().panels[embeddable.id!];

const newPanelId = Object.keys(container.getInput().panels).find(
(key) => !originalPanelKeySet.has(key)
);
expect(newPanelId).toBeDefined();
const newPanel = container.getInput().panels[newPanelId!];
expect(newPanel.type).toEqual(embeddable.type);
});

Expand All @@ -159,10 +164,15 @@ test('Unlink unwraps all attributes from savedObject', async () => {
mockedByReferenceInput: { savedObjectId: 'testSavedObjectId', id: embeddable.id },
mockedByValueInput: { attributes: complicatedAttributes, id: embeddable.id },
});
const dashboard = embeddable.getRoot() as IContainer;
const originalPanelKeySet = new Set(Object.keys(dashboard.getInput().panels));
const action = new UnlinkFromLibraryAction({ toasts: coreStart.notifications.toasts });
await action.execute({ embeddable });
expect(Object.keys(container.getInput().panels)).toContain(embeddable.id);
const newPanel = container.getInput().panels[embeddable.id!];
const newPanelId = Object.keys(container.getInput().panels).find(
(key) => !originalPanelKeySet.has(key)
);
expect(newPanelId).toBeDefined();
const newPanel = container.getInput().panels[newPanelId!];
expect(newPanel.type).toEqual(embeddable.type);
expect(newPanel.explicitInput.attributes).toEqual(complicatedAttributes);
});
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

import { i18n } from '@kbn/i18n';
import _ from 'lodash';
import uuid from 'uuid';
import { ActionByType, IncompatibleActionError } from '../../ui_actions_plugin';
import { ViewMode, PanelState, IEmbeddable } from '../../embeddable_plugin';
import {
Expand Down Expand Up @@ -88,9 +87,9 @@ export class UnlinkFromLibraryAction implements ActionByType<typeof ACTION_UNLIN

const newPanel: PanelState<EmbeddableInput> = {
type: embeddable.type,
explicitInput: { ...newInput, id: uuid.v4() },
explicitInput: { ...newInput },
};
dashboard.replacePanel(panelToReplace, newPanel);
dashboard.replacePanel(panelToReplace, newPanel, true);

const title = embeddable.getTitle()
? i18n.translate('dashboard.panel.unlinkFromLibrary.successMessageWithTitle', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,30 @@ export class DashboardContainer extends Container<InheritedChildInput, Dashboard

public replacePanel(
previousPanelState: DashboardPanelState<EmbeddableInput>,
newPanelState: Partial<PanelState>
newPanelState: Partial<PanelState>,
generateNewId?: boolean
) {
// Because the embeddable type can change, we have to operate at the container level here
return this.updateInput({
panels: {
let panels;
if (generateNewId) {
// replace panel can be called with generateNewId in order to totally destroy and recreate the embeddable
panels = { ...this.input.panels };
delete panels[previousPanelState.explicitInput.id];
const newId = uuid.v4();
panels[newId] = {
...previousPanelState,
...newPanelState,
gridData: {
...previousPanelState.gridData,
i: newId,
},
explicitInput: {
...newPanelState.explicitInput,
id: newId,
},
};
} else {
// Because the embeddable type can change, we have to operate at the container level here
panels = {
...this.input.panels,
[previousPanelState.explicitInput.id]: {
...previousPanelState,
Expand All @@ -190,7 +209,11 @@ export class DashboardContainer extends Container<InheritedChildInput, Dashboard
id: previousPanelState.explicitInput.id,
},
},
},
};
}

return this.updateInput({
panels,
lastReloadRequestTime: new Date().getTime(),
});
}
Expand Down

0 comments on commit dfc0123

Please sign in to comment.