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

[Embeddables Rebuild] Migrate Visualize #183197

Merged
merged 243 commits into from
Aug 30, 2024

Conversation

Zacqary
Copy link
Contributor

@Zacqary Zacqary commented May 10, 2024

Summary

Closes #174958

This migrates the Visualize embeddable to the new React Embeddable framework.

Migrated:

  • Edit visualization action
  • Convert to lens action
  • Extracting/injecting references on serialize and deserialize
  • Inspector adapters
  • Dashboard settings
  • Drilldown support
  • Timeslice/time slider support
  • Custom time ranges

Also adds deprecation statements to legacy Embeddable factories

In a second PR, we'll move the embeddable folder to legacy/embeddable and rename react_embeddable to embeddable. I don't know if git will be able to diff that change in a comprehensible way in this PR, so I want to save it for the next one.

Checklist

@Zacqary Zacqary added Team:Presentation Presentation Team for Dashboard, Input Controls, and Canvas release_note:skip Skip the PR/issue when compiling release notes Feature:Embeddables Relating to the Embeddable system v8.15.0 labels May 10, 2024
@apmmachine
Copy link
Contributor

🤖 GitHub comments

Expand to view the GitHub comments

Just comment with:

  • /oblt-deploy : Deploy a Kibana instance using the Observability test environments.
  • run docs-build : Re-trigger the docs validation. (use unformatted text in the comment!)

@Zacqary Zacqary marked this pull request as ready for review May 13, 2024 15:11
@Zacqary Zacqary requested review from a team as code owners May 13, 2024 15:11
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-presentation (Team:Presentation)

@Zacqary
Copy link
Contributor Author

Zacqary commented May 13, 2024

@elasticmachine merge upstream

Comment on lines 33 to 46
const observer = new MutationObserver((mutationList) => {
for (const mutation of mutationList) {
if (mutation.type === 'attributes') {
if (
mutation.attributeName === 'data-render-complete' &&
visualization.getAttribute('data-render-complete') === 'true'
) {
observer.disconnect();
resolve();
}
}
}
});
observer.observe(visualization, { attributes: true });
Copy link
Contributor

Choose a reason for hiding this comment

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

I didn't run this locally, but I suppose we are leveraging mutation observers because the renderComplete event no longer gets dispatched, I see that it ideally would have been dispatched here https://github.com/elastic/kibana/blob/main/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx#L392, is this intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, in the new embeddable framework everything goes through React, so it's much more cumbersome to get the kind of DOM access we need to emit events from the correct element. We're trying to move away from event emitters in new code.

Copy link
Contributor

Choose a reason for hiding this comment

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

My concern is that previously the implementation detail for when a render completes was contained, and any interested consumer of visualizations need only care if a renderComplete event was emitted on any said visualization element. I think that a replacement util for signalling renderComplete in the new code should be provided, as it rather seems that the implementation detail of determining if a render has completed is now being shifted on to the consumer.

VISUALIZE_EMBEDDABLE_TYPE,
VisualizeEmbeddableFactory,
} from './embeddable';
import { createVisEmbeddableFromObject } from './embeddable';
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you async import createVisEmbeddableFromObject where its used in mount callback?

@Zacqary Zacqary enabled auto-merge (squash) August 27, 2024 18:17
vis$.subscribe((vis) => vis.uiState.on('change', onUiStateChange));

// When the serialized vis changes, update the vis instance
serializedVis$.subscribe(async (serializedVis) => {
Copy link
Contributor

@nreese nreese Aug 27, 2024

Choose a reason for hiding this comment

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

This should use a switchMap to fetch async items. Then subscribe should apply them. Otherwise, you are introducing a race condition where an serializedVis$ emit before the previous serializedVis$ emit async tasks complete may call .next out of order.

serializedVis$.pipe(
  switchMap((serializedVis) => {
    const vis = await createVisInstance(serializedVis)
    const const { params, abortController } = await getExpressionParams();
    return { vis, params, abortController };
  })
).subscribe((vis, params, abortController) => {
  vis$.next(vis);
  if (params) expressionParams$.next(params);
  expressionAbortController$.next(abortController);
})

Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like you lost the below in the fix. Is that still needed?

const currentVis = vis$.getValue();
      if (currentVis) currentVis.uiState.off('change', onUiStateChange);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Probably necessary yeah, might have memory leaks without

Copy link
Contributor

@mbondyra mbondyra left a comment

Choose a reason for hiding this comment

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

Tested and approving! Would appreciate double check for Visualizations team from @dej611 as he has more knowledge in the embeddable refactor area 🙏🏼

@Zacqary
Copy link
Contributor Author

Zacqary commented Aug 28, 2024

/ci

@Zacqary
Copy link
Contributor Author

Zacqary commented Aug 28, 2024

@elasticmachine merge upstream

@Zacqary
Copy link
Contributor Author

Zacqary commented Aug 28, 2024

I guess that doesn't work anymore?

@Zacqary
Copy link
Contributor Author

Zacqary commented Aug 28, 2024

/ci

onAdd: (container, savedObject) => {
container.addNewPanel<VisualizeRuntimeState>({
panelType: VISUALIZE_EMBEDDABLE_TYPE,
initialState: savedObjectToRuntimeState(savedObject),
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't container.addNewPanel get passed serializedState? Why are you converting the state to runtime state? What happens if you remove savedObjectToRuntimeState?

The reason I ask is that this PR adds 10KB to the page load size and am trying to track down all possible increases. It would be great if we could avoid importing savedObjectToRuntimeState into the page load bundle size. I don't think this is needed.

Copy link
Contributor

Choose a reason for hiding this comment

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

Just tested it and the following works.

container.addNewPanel<VisualizeSerializedState>({
          panelType: VISUALIZE_EMBEDDABLE_TYPE,
          initialState: { savedObjectId: savedObject.id },
        });

Copy link
Contributor Author

Choose a reason for hiding this comment

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

At one point this was necessary after a merge with main broke the embeddable, but I guess something with the panel handling changed and now it's no longer necessary? Still works without passing this in. I'll remove.

@Zacqary
Copy link
Contributor Author

Zacqary commented Aug 28, 2024

/ci

Comment on lines 502 to 505
if (hasRendered) {
domNode.current?.dispatchEvent(new Event('renderComplete'));
}
}, [hasRendered]);
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for opting to support signalling render completion using events. I wonder though if we could leverage the already existing util for doing this in place for constructing the event inline. See here

@kibana-ci
Copy link
Collaborator

kibana-ci commented Aug 29, 2024

💛 Build succeeded, but was flaky

Failed CI Steps

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
aiops 654 655 +1
controls 300 301 +1
dashboardEnhanced 94 95 +1
dataVisualizer 811 812 +1
embeddable 141 142 +1
imageEmbeddable 139 140 +1
infra 1578 1579 +1
lens 1510 1511 +1
links 129 130 +1
ml 2025 2026 +1
presentationPanel 103 104 +1
slo 899 900 +1
synthetics 1022 1023 +1
visualizations 466 474 +8
total +21

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/presentation-containers 76 80 +4
visualizations 838 841 +3
total +7

Async chunks

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

id before after diff
aiops 633.3KB 633.7KB +342.0B
dashboard 547.7KB 547.8KB +106.0B
dataVisualizer 811.0KB 811.1KB +114.0B
imageEmbeddable 68.9KB 69.0KB +114.0B
ml 4.6MB 4.6MB +456.0B
visualizations 302.2KB 315.7KB +13.6KB
total +14.7KB

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
visualizations 19 20 +1

Page load bundle

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

id before after diff
visualizations 63.5KB 71.0KB +7.5KB
Unknown metric groups

API count

id before after diff
@kbn/presentation-containers 88 92 +4
visualizations 869 872 +3
total +7

async chunk count

id before after diff
visualizations 15 16 +1

References to deprecated APIs

id before after diff
maps 30 33 +3
visualizations 60 58 -2
total +1

History

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

Copy link
Contributor

@nreese nreese left a comment

Choose a reason for hiding this comment

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

kibana-presentation changes LGTM
code review and tested in chrome

@Zacqary Zacqary merged commit ee28e20 into elastic:main Aug 30, 2024
30 checks passed
@kibanamachine kibanamachine added the backport:skip This commit does not require backporting label Aug 30, 2024
nreese added a commit to nreese/kibana that referenced this pull request Sep 3, 2024
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 ci:build-all-platforms ci:build-cloud-image ci:build-serverless-image ci:cloud-deploy Create or update a Cloud deployment Feature:Embeddables Relating to the Embeddable system release_note:skip Skip the PR/issue when compiling release notes Team:Presentation Presentation Team for Dashboard, Input Controls, and Canvas v8.16.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Embeddables Rebuild] Migrate Visualize