Skip to content

Duplicate panel feature#61367

Merged
ThomThomson merged 29 commits intoelastic:masterfrom
ThomThomson:dashboard/duplicatePanel
Apr 17, 2020
Merged

Duplicate panel feature#61367
ThomThomson merged 29 commits intoelastic:masterfrom
ThomThomson:dashboard/duplicatePanel

Conversation

@ThomThomson
Copy link
Copy Markdown
Contributor

@ThomThomson ThomThomson commented Mar 25, 2020

Summary

Adds the ability to duplicate any embeddable on a dashboard.

Closes #60921

New Cloning Behavior

Functionality Overview

The clone functionality does the following when the user executes the action:

  • Creates a 'placeholder embeddable'
  • Places the placeholder on the dashboard beside the panel that was cloned.
  • Duplicates the saved object associated with the embeddable if one exists
  • Creates a new embeddable of the same type
  • Copies all explicit Input from the old embeddable to the new embeddable
  • Replaces the embeddable with the newly cloned embeddable.

This functionality should work on all kinds of embeddables.

Placement

When duplicating, the system creates a new gridData of the correct shape, and uses it to check for free space to the right, to the bottom, and to the left of the cloned panel.

  • If enough space is found in any direction, the clone takes the blank space and the dashboard's groove is left alone.

NewClonePlacement

  • If an intersection is found, the clone takes the space directly below the panel that was cloned, pushing any panels below it downward.

Naming

When a saved object is duplicated, a unique name is created by attaching an internationalized tag, and a count of other savedObjects with a similar title. If the original saved object is called 'testObj', the first duplicate will be called 'testObj (copy)' and the second duplicate will be called 'testObj (copy 1)'

Checklist

Delete any items that are not applicable to this PR.

For maintainers

@ThomThomson ThomThomson self-assigned this Mar 25, 2020
@ThomThomson ThomThomson force-pushed the dashboard/duplicatePanel branch from 55d45ad to 69753b2 Compare April 3, 2020 18:51
@ThomThomson ThomThomson marked this pull request as ready for review April 6, 2020 17:51
@ThomThomson ThomThomson requested a review from a team April 6, 2020 17:51
@ThomThomson ThomThomson requested a review from majagrubic April 6, 2020 21:31
@ThomThomson ThomThomson requested a review from timroes April 6, 2020 21:32
@ryankeairns
Copy link
Copy Markdown
Contributor

Nice work! Just a couple of quick takes:

  • I think we've tried to coalesce around the word 'Clone' versus 'Duplicate'. @gchaps is that accurate?
  • This likely opens a larger can of worms that could be addressed separately, but it's worth noting that the new panel can become oddly arranged in the layout and shift other panels around. I do like that the new panel is added next to the original (as opposed to the bottom of the dashboard, for example), but I expected it to stay on the same row and push that longer area chart down.

Screenshot 2020-04-07 14 38 44

@ThomThomson ThomThomson linked an issue Apr 7, 2020 that may be closed by this pull request
@ThomThomson ThomThomson added the Team:Visualizations Team label for Lens, elastic-charts, Graph, legacy editors (TSVB, Visualize, Timelion) t// label Apr 7, 2020
@elasticmachine
Copy link
Copy Markdown
Contributor

Pinging @elastic/kibana-app (Team:KibanaApp)

@gchaps
Copy link
Copy Markdown
Contributor

gchaps commented Apr 7, 2020

Yes, we prefer "clone" over "duplicate".

So the menu item should be "Clone panel"

For the notification: Cloned panel

@ThomThomson ThomThomson requested a review from gchaps April 7, 2020 22:26
@majagrubic
Copy link
Copy Markdown
Contributor

majagrubic commented Apr 8, 2020

Having a look at this, as Ryan pointed out, positioning of the panels doesn't look good. On the sample flight dashboard, the panels are weirdly rearranged, but we can work on figuring out the best positioning of the cloned widget.
What I'm more worried about is this 1-2 sec lag from when a user clicks on the duplicate panel before the panel appears. There is no return information to the user that something is happening, and then the panel just appears out of the blue. Visible from the GIF:
duplicate_panel

Here's what I think the flow should be:

  1. User selects "duplicate panel"
  2. The placeholder panel appears immediately with a loading spinner
  3. Then we copy the input from the original panel to the new one

Example, compare the flow above to this flow:

cloudwatch_clone

…one is done. Reorganized duplication and placement mechanics. TODO: Hide settings on placeholder panel, change placement method to work better
@ThomThomson
Copy link
Copy Markdown
Contributor Author

Thanks for the idea Maja, I was able to give much quicker feedback to the user by immediately creating and placing a 'placeholder' embeddable in the final spot, then swapping it out for the final embeddable once the clone has finished.

newCloneBehavior

Panel placement definitely needs to be revisited, so I will see if I can make it more robust!
Additionally, the placeholder could use a bit more snazziness, and its context menu should definitely be hidden.

Copy link
Copy Markdown
Contributor

@majagrubic majagrubic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks dope, will have another pass at testing / have a look at the code first thing tomorrow morning 🙌

…space in 3 directions around the panel they're cloned from, failing that, they take the space directly below their origin and push down all panels that conflict
…isn't room push down all panels that are below it.
Copy link
Copy Markdown
Contributor

@majagrubic majagrubic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested this in Chrome 80 on Mac OS and it works great. I've tried:

  • duplicating the panel
  • duplicating the panel multiple times
  • editing one visualization doesn't affect the duplicated one
  • filtering works on all cloned visualizations
  • changing the title of one of the duplicated panels didn't affect the other panels
  • replacing one of the duplicated panels didn't affect the other panels
  • maximizing the panel works as expected

One minor nit I found is that in the visualize listing the visualization with the copy title will be placed after copy1, copy2 etc:
Screenshot 2020-04-16 at 11 22 18
If I'm not mistaken, adding a space at the end of copy title will solve this problem.

The placeholder panel is an amazing addition and the user experience is so much nicer now.

In terms of positioning, I think there are still some tweaks to be done, but I would suggest we do them in a subsequent PR, before this becomes too large to merge.

Here is an example: when there are only two panels on the dashboard, duplicating the rightmost one renders the panel immediately below:
clone_panel_1
In my opinion, this should be rendered in the next row leftmost.
Moreover, if you duplicate this panel now, it will be rendered to the left:
clone_panel_2
so we basically created this right-to-left flow, which I'm not particularly sure I like.

My suggestion is that after this is merged, you and @ryankeairns make a detailed pass through all the common scenarios of where the duplicated panel is to be placed, and then we can implement it properly.

As I said - to me this is good enough to merge for now, unless someone has strong objections otherwise. Some code comments below.

defaultMessage: 'copy',
});
const cloneRegex = new RegExp(`\\(${clonedTag}\\)`, 'g');
const cloneNumberRegex = new RegExp(`\\(${clonedTag} [0-9]+\\)`, 'g');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What exactly is the purpose of these regexes?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are used to remove any cloning artefacts from the name of the savedObject, so that you don't end up with a title like "Hello World (copy) (copy 1) (copy 2)"

: baseTitle + ` (${clonedTag} ${similarBaseTitlesCount})`;
}

private async cloneEmbeddable(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this be better suited to live on the embeddable itself? In case we have other uses-cases like this? Just thinking out loud, and definitely doesn't need to be made as part of this PR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method currently seems to work on every different type of embeddable, it would be pretty cool though if embeddables had a way to override it.

Additionally, it could later be moved onto the dashboard embeddable so that it could be re-used if we do need it!

return createPanelState(panelState, this.input.panels);
}

public showPlaceholderUntil<TPlacementMethodArgs extends IPanelPlacementArgs>(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙌 🙌

} from '../../../embeddable_plugin';
import { PlaceholderEmbeddable, PLACEHOLDER_EMBEDDABLE } from './placeholder_embeddable';

export class PlaceholderEmbeddableFactory implements EmbeddableFactoryDefinition {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a unit test for this?

const panel = dashboard.getInput().panels[embeddable.id] as DashboardPanelState;
const action = new ClonePanelAction(coreStart);
// @ts-ignore
const newPanel = await action.cloneEmbeddable(panel, embeddable.type);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What was the ts-error here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the cloneEmbeddable method is set to private

);
// @ts-ignore
expect(await action.getUniqueTitle('testSecondTitle (copy 20)', embeddable.type)).toEqual(
'testSecondTitle (copy 40)'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I understand this - shouldn't the next title be copy 41?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The titling uses a system like file copies in windows, the order looks like this:

OG Title
OG Title (copy)
OG Title (copy 1)

That means that the next title is always the number of similar titles - 1. So if there were 41 similar titles, the next title would be OG Title (Copy 40)

@kibanamachine
Copy link
Copy Markdown
Contributor

💚 Build Succeeded

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

@ThomThomson ThomThomson merged commit 3f98f0f into elastic:master Apr 17, 2020
ThomThomson added a commit to ThomThomson/kibana that referenced this pull request Apr 20, 2020
Added a new cloning feature for panels on a dashboard.
ThomThomson added a commit that referenced this pull request Apr 20, 2020
Added a new cloning feature for panels on a dashboard.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature:Dashboard Dashboard related features release_note:enhancement Team:Visualizations Team label for Lens, elastic-charts, Graph, legacy editors (TSVB, Visualize, Timelion) t// v7.8.0 v8.0.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for cloning/duplicating panel on a dashboard

7 participants