Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image Embeddable #146421

Merged
merged 52 commits into from Dec 19, 2022
Merged

Image Embeddable #146421

merged 52 commits into from Dec 19, 2022

Conversation

Dosant
Copy link
Contributor

@Dosant Dosant commented Nov 28, 2022

close #81345

Summary

This PR adds an image embeddable - a new embeddable type that allows to insert images into dashboard.

Feature Review

Adding an Image panel

To add an image embeddable to a dashboard use a shortcut "add image" button or an panel type picker

Screenshot 2022-12-06 at 15 27 52

Image editor opens in a flyout without navigating away from a Dashboard app.
First pick an image source: either upload a file or add an external URL

Screenshot 2022-12-15 at 12 50 29

When using "upload" option:

  • drag'n'drop an image file or click on the placeholder area to open a file system selector to upload an image
  • Or use "select from previously uploaded images" option to open a file picker and pick from earlier uploaded images

Screenshot 2022-12-06 at 15 33 58

When imaged picked or uploaded it is displayed in a preview container:

Screenshot 2022-12-06 at 15 35 03

  • Click clear button to clear the preview and pick another image
  • Or click on the image to open the file picker and pick another image
  • tweak sizing and background-color options and see the changes reflected in the preview container

Screenshot 2022-12-15 at 12 52 13

Users can also add images by providing external URL

Screenshot 2022-12-15 at 12 52 37

Screenshot 2022-12-15 at 12 53 25

Url validation checks the URL using http.externalUrl service and expects an absolute URL over https? protocols
In case URL is invalid or doesn't point to an image, error is displayed and preview container shows not found state

Screenshot 2022-12-15 at 12 54 04

  • In case URL validation didn't pass - save button is disabled.
  • In case URL validation passed, but wasn't able to load an image - save button is still enabled

Image Panel on a Dashboard

If image URL validation passes and image loads the image displays as configured:

Screenshot 2022-12-06 at 15 55 27
In case panel doesn't have panel title, image can be displayed nicely occupying the whole panel

In case of image load error or validation error, we display an error state. Visually it depends on screen size and panel size:

Screenshot 2022-12-15 at 12 54 15

Screenshot 2022-12-06 at 15 55 06

Original image is visually hidden, so screen readers can still read alt text in this case.

TODO

This PR

  • Make work with reporting (render complete attributes)
  • Functional test
  • Design Review and visual tweaks
  • Copy Review and tweaks
  • Telemetry check

Later (create issues)

  • Support 2nd set of images for dark more
  • Integrate with drill downs

Checklist

Delete any items that are not applicable to this PR.

Dosant and others added 30 commits October 26, 2022 11:28
@Dosant
Copy link
Contributor Author

Dosant commented Dec 15, 2022

@gchaps, I updated the screenshots in the description with the latest copy

@Dosant
Copy link
Contributor Author

Dosant commented Dec 15, 2022

@elasticmachine merge upstream

…age-embeddable

# Conflicts:
#	src/plugins/dashboard/public/application/top_nav/dashboard_top_nav.tsx
#	src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.tsx
#	src/plugins/dashboard/public/dashboard_strings.ts
@Dosant Dosant force-pushed the d/2022-10-24-image-embeddable branch from e37dc6c to 91bd7ac Compare December 15, 2022 16:36
Copy link
Contributor

@ThomThomson ThomThomson left a comment

Choose a reason for hiding this comment

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

Read through the code and also tested this locally. Code LGTM, but I left a few nits and a couple questions.

I also ran this locally and ran into some small issues. Nothing major though, so am approving.

  • When you're editing an image, the save button at the bottom still says Edit image. Usually we have some sort of confirm, or save down here. Not sure what @gchaps said about that, but it seemed strange to me.
  • If you open the editor, then cancel, there is an error in the console
  • While typing into the URL section, each keystroke trIes to request the image which results in some flashing of the error state, potentially this could be at least debounced.
  • By default the background color is transparent, but if you change the color you cannot set it back to transparent as far as I can tell.
  • I anticipate that users will want to show an image with a transparent background, and avoid all the panel styling that Dashboard embeddables come with. We should maybe expose an option to not show the panel shading / background color etc.

},
})
: i18n.translate('dashboard.addPanel.panelAddedToContainerSuccessMessageTitle', {
defaultMessage: 'A panel was added',
Copy link
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 toast when the panel is added? Adding other panels like this doesn't show a toast, this is only used when you add Library visualizations.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I moved the code that adds an embeddable and calls this toast from src/plugins/dashboard/public/dashboard_app/top_nav/editor_menu.tsx to src/plugins/dashboard/public/dashboard_app/top_nav/dashboard_editing_toolbar.tsx to use it for creating image embeddable. The toast came with the code.

Do you think I should add an if/else there to not show a toast in case this wasn't a library viz? I personally not sure why the behavior has to be different.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, makes sense! I didn't realize that you standardized these calls. Thanks Anton!

);
const inDashboardEditMode = embeddable.getInput().viewMode === ViewMode.EDIT;
return Boolean(canEditEmbeddable && inDashboardEditMode);
}

public async execute(context: ActionContext) {
const embeddable = context.embeddable;
const { editableWithExplicitInput } = embeddable.getOutput();
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason this is exposed via embeddable output rather than as either a method call or as a property on the embeddable definition? Do you expect this to change during the life time of individual embeddables?

It looks like this matches the current editable behaviour, I wonder if we have any instances where this changes.

Copy link
Contributor Author

@Dosant Dosant Dec 16, 2022

Choose a reason for hiding this comment

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

I am not sure! As you said, I followed the editable and other edit* related props pattern.

....

Looked around a bit:

Seems like editable can be dynamic, for example:

  private getIsEditable() {
    return (
      this.deps.capabilities.canSaveVisualizations ||
      (!this.inputIsRefType(this.getInput()) && this.deps.capabilities.canSaveDashboards)
    );
  }

editUrl is also can be dynamic depending on savedObjectId, for example.

editApp don't think so. and editableWithExplicitInput also not at least at the moment.
But I think makes sense to keep these properties together.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds good for the moment! Eventually we're hoping to remove the extra step of accessing these sorts of things via output, and standardize on calling them as methods on the embeddable instance, like getIsEditable. But that process doesn't have to start quite yet!

@Dosant
Copy link
Contributor Author

Dosant commented Dec 16, 2022

I also ran this locally and ran into some small issues. Nothing major though, so am approving.

@ThomThomson, thank you for the review!

When you're editing an image, the save button at the bottom still says Edit image. Usually we have some sort of confirm, or save down here. Not sure what @gchaps said about that, but it seemed strange to me.

I followed @gchaps's recommendation to change from "save" to "add/edit". I didn't consider it is "Save" for all other flyouts. For consistency, considering to change it back.

If you open the editor, then cancel, there is an error in the console

Going to fix this.

While typing into the URL section, each keystroke trIes to request the image which results in some flashing of the error state, potentially this could be at least debounced.

Will look into it

I remembered that I decided to not worry about this after I realized that this is more of a dev/testing edge-case, as in the real world you will likely copy paste a URL from somewhere and won't type it.
I was thinking that it is not really worth it to make code a bit more complicated for this.

By default the background color is transparent, but if you change the color you cannot set it back to transparent as far as I can tell.

You can by removing the color. Either in the input with the keyboard or by clicking "remove" button in the input

I anticipate that users will want to show an image with a transparent background, and avoid all the panel styling that Dashboard embeddables come with. We should maybe expose an option to not show the panel shading / background color etc.

Probably. In case there will be interested, I think we will be able to add something like this. Maybe this could be useful for some other panel types

Copy link
Contributor

@jloleysens jloleysens left a comment

Choose a reason for hiding this comment

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

This is look really great @Dosant . I read over the code fairly quickly, from what I can see the implementation is looking very clean. Only minor comments. Did not really focus on integration with Dashboard or use of embeddable code.

I had a few UX comments I wanted to get your thoughts on:


Screenshot 2022-12-16 at 13 36 44

At the moment we have tabbed content for "upload" and "use link" flows. What do you think about not having tabs and instead have some kind of field toggle for "use link" at the top of the form that will just toggle the upload field to a text field?


Screenshot 2022-12-16 at 13 42 51

Minor: it looks like the "Or use a previously uploaded image" button link is not being disabled during upload.

Another minor: currently this places a lot of emphasis on the upload new image flow. If we want to present them as equal options we could place them next to each other, but that would require some redesign.

I also see what you mean regarding the "Cancel" button that pops in and causing a layout shift. I wonder if we could solve this by only showing the image configuration fields when the image is uploaded.


Screenshot 2022-12-16 at 13 52 54

I would consider change this text to "Done". "Edit image" is a bit unclear to me as the label of the primary action button in this context. Although I'd be curious to hear what a writer thinks.


NOTE: this comment makes most sense if we also consider the field toggle approach I described above.

Screenshot 2022-12-16 at 13 55 58

At the moment, we have the image "field" and the image "preview" functioning as the same thing. I wonder if we kept the image "field" functioning just as a field we could move the "preview" down to the bottom of the flyout. This introduces a new state for the upload field since it will need to, for example, just contain the image name. But it could look like:

Screenshot 2022-12-16 at 14 02 13


Let me know what you think! None of these need to be actioned of course.

validateUrl: ValidateUrlFn;
}

export function ImageEditorFlyout(props: ImageEditorFlyoutProps) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Did you consider using the form lib here?

src/plugins/es_ui_shared/static/forms/docs/welcome.mdx

It comes with some pre-made fields and takes care of a lot of the awkward "in-between" states a form can be in.

Perhaps not worth doing now, just wanted to get your thoughts.

Copy link
Contributor

Choose a reason for hiding this comment

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

Could probably also split out some of the JSX to smaller, sub-components.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Did you consider using the form lib here?

I thought I'd start with plain React and if it starts to get weird, I'd try a form lib. But I don't think I hit that point with the current implementation where I felt that starting using a form worse it.

Could probably also split out some of the JSX to smaller, sub-components.

Same thinking here. I though I'd start creating sub-components when I'd feel specific fragments are becoming bloated and/or for re-render perf optimization reasons. but I don't think I hit that point.
Most of the components would mostly be Inputs with texts wrapped into components and I didn't think it worse it.

* Makes sure the container has not too large height to preserve vertical space for the image configuration in the flyout
*/
const CONTAINER_SIZING_CSS = css({
aspectRatio: `21 / 9`,
Copy link
Contributor

Choose a reason for hiding this comment

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

just curious, how did we land on this number?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I started with 16 / 9 (common aspect-ratio everyone used at) but then had concerns that on some screens and sizes image placeholder takes to much height. So I picked another common aspect-ratio which would have less height.

Copy link
Contributor

@vadimkibana vadimkibana left a comment

Choose a reason for hiding this comment

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

Code LGTM, tested on Mac/Chrome all seems good 🚀


Regarding drilldown integration, what is the latest there? Did we decide not to do them or that would be a separate work item?


Not directly related to this PR, but there is this "Customize time range" action and some other actions, which maybe should not appear on image panels.

image

Copy link
Contributor

@gchaps gchaps left a comment

Choose a reason for hiding this comment

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

Thanks for including the updated screenshots. Looks good. Here are a few minor changes.

Remove the word “Or”

Use a previously uploaded image

Add serial comma to hint text

Supported file types: png, jpeg, web, and avif.

Remove URL from message

Unable to load image.

It’s the same as in the text field directly above the message and it just makes the message harder to read.

@Dosant
Copy link
Contributor Author

Dosant commented Dec 19, 2022

@jloleysens, thank you for the feedback and idea.

I would consider change this text to "Done". "Edit image" is a bit unclear to me as the label of the primary action button in this context. Although I'd be curious to hear what a writer thinks.

This was changed

I also see what you mean regarding the "Cancel" button that pops in and causing a layout shift. I wonder if we could solve this by only showing the image configuration fields when the image is uploaded.

This jump is annoying, but I don't think it worth changing the form flow.
I still think best would be to move that cancel inside the upload container somehow. Have you by any chance created that issue for EUI?

At the moment we have tabbed content for "upload" and "use link" flows. What do you think about not having tabs and instead have some kind of field toggle for "use link" at the top of the form that will just toggle the upload field to a text field?
Another minor: currently this places a lot of emphasis on the upload new image flow. If we want to present them as equal options we could place them next to each other, but that would require some redesign.
At the moment, we have the image "field" and the image "preview" functioning as the same thing. I wonder if we kept the image "field" functioning just as a field we could move the "preview" down to the bottom of the flyout. This introduces a new state for the upload field since it will need to, for example, just contain the image name. But it could look like:

I think these are really good ideas! I agree that combined this could be a really good alternative UX with bunch of advantages over the current version.
But considering the lowish impact and priority of this feature, I think we would agree that it probably won't worth it to scratch the current version and start discussions and implementations about this alternative.

@Dosant
Copy link
Contributor Author

Dosant commented Dec 19, 2022

@vadimkibana,

Regarding drilldown integration, what is the latest there? Did we decide not to do them or that would be a separate work item?

I didn't get to it in this PR. I'll create a separate issue and will time box like a day to add it

Not directly related to this PR, but there is this "Customize time range" action and some other actions, which maybe should not appear on image panels.

Good catch. I'll try to take a look

@kibana-ci
Copy link
Collaborator

💛 Build succeeded, but was flaky

Failed CI Steps

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
imageEmbeddable - 68 +68

Public APIs missing comments

Total count of every public API that lacks a comment. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats comments for more detailed information.

id before after diff
@kbn/shared-ux-file-picker 0 5 +5
@kbn/shared-ux-file-upload 0 7 +7
embeddable 421 423 +2
total +14

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
dashboard 371.3KB 377.3KB +6.0KB
filesManagement 93.9KB 93.9KB +10.0B
imageEmbeddable - 46.5KB +46.5KB
total +52.5KB

Public APIs missing exports

Total count of every type that is part of your API that should be exported but is not. This will cause broken links in the API documentation system. Target amount is 0. Run node scripts/build_api_docs --plugin [yourplugin] --stats exports for more detailed information.

id before after diff
@kbn/shared-ux-file-upload 0 1 +1

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
embeddable 70.2KB 70.6KB +355.0B
files 9.4KB 10.0KB +624.0B
imageEmbeddable - 7.6KB +7.6KB
uiActionsEnhanced 22.3KB 22.4KB +23.0B
total +8.6KB
Unknown metric groups

API count

id before after diff
@kbn/shared-ux-file-picker 0 11 +11
@kbn/shared-ux-file-upload 0 7 +7
embeddable 522 524 +2
total +20

async chunk count

id before after diff
imageEmbeddable - 4 +4

ESLint disabled in files

id before after diff
osquery 1 2 +1

ESLint disabled line counts

id before after diff
enterpriseSearch 19 21 +2
fleet 61 67 +6
imageEmbeddable - 2 +2
osquery 109 115 +6
securitySolution 439 445 +6
total +22

miscellaneous assets size

id before after diff
imageEmbeddable - 215.0KB ⚠️ +215.0KB

Total ESLint disabled count

id before after diff
enterpriseSearch 20 22 +2
fleet 70 76 +6
imageEmbeddable - 2 +2
osquery 110 117 +7
securitySolution 516 522 +6
total +23

History

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

@Dosant Dosant added impact:medium Addressing this issue will have a medium level of impact on the quality/strength of our product. loe:weeks labels Dec 19, 2022
@Dosant Dosant merged commit 74ab075 into elastic:main Dec 19, 2022
@kibanamachine kibanamachine added the backport:skip This commit does not require backporting label Dec 19, 2022
crespocarlos pushed a commit to crespocarlos/kibana that referenced this pull request Dec 23, 2022
close elastic#81345

Adds an image embeddable - a new embeddable type that allows to
insert images into dashboard using the new file service
@jloleysens
Copy link
Contributor

I still think best would be to move that cancel inside the upload container somehow. Have you by any chance created that issue for EUI?

Just created it :) elastic/eui#6509

@Dosant

Dosant added a commit that referenced this pull request Jan 9, 2023
## Summary

Close #148008
follow up to #146421

Adds drilldowns integration to image embeddable 
Now it is possible to create Dashboard-to-Dashboard or URL to an image.
The drilldown is triggered on image click.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport:skip This commit does not require backporting Feature:Dashboard Dashboard related features Feature:Embedding Embedding content via iFrame feature:Files impact:medium Addressing this issue will have a medium level of impact on the quality/strength of our product. release_note:feature Makes this part of the condensed release notes Team:Presentation Presentation Team for Dashboard, Input Controls, and Canvas Team:SharedUX Team label for AppEx-SharedUX (formerly Global Experience) v8.7.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Image embeddable