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

Embeddable telemetry and reference extraction/injection #74352

Merged
merged 32 commits into from
Sep 18, 2020

Conversation

ppisljar
Copy link
Member

@ppisljar ppisljar commented Aug 5, 2020

Summary

adds .telemetry .extract and .inject functions to embeddable service, which can take in any embeddable input and perform associated action on it.

embeddable service exposes .telemetry .inject and .extract function which then:

  • runs those functions for base embeddable input
  • checks embeddable factory registry for specified embeddable type and runs those functions on it
  • checks enhancements registry for present enhancements (new registry) and runs those functions on them

same set of function was also added to dynamic actions registry:

  • dynamic action enhancement uses uiActionsEnhanced plugin (calls those methods on it_)
  • uiActionsEnhanced plugin checks dynamic action registry and runs those functions on the found item

As we need this functionality on the server as well and embeddable plugin and uiActionEnhanced plugins didn't have server contract until now, that was added as well, together with all the mentioned registried and functions.

note that telemetry/extract/inject functions were not added for any embeddable and should be done as a followup. most of them also have nested state dependency tree (for example visualize embeddable will need to check visualizations registry (which will need to provide all above functions, as well as every visualization registered), and some visualizations will need to go further like getting search source functions, which in turn shall get filter, query and timerange functions.

Checklist

Delete any items that are not applicable to this PR.

For maintainers

@ppisljar ppisljar added WIP Work in progress Feature:Embedding Embedding content via iFrame Team:AppArch Feature:Drilldowns Embeddable panel Drilldowns labels Aug 5, 2020
@ppisljar ppisljar requested a review from stacey-gammon August 5, 2020 11:26
@ppisljar ppisljar requested a review from a team as a code owner August 5, 2020 11:26
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-app-arch (Team:AppArch)

@ppisljar ppisljar force-pushed the embeddableMigrations branch 2 times, most recently from 412dfc9 to 28b78c7 Compare August 5, 2020 13:31
@ppisljar ppisljar requested a review from a team August 5, 2020 13:31
@ppisljar ppisljar added release_note:skip Skip the PR/issue when compiling release notes v7.10.0 v8.0.0 labels Aug 5, 2020
@ppisljar ppisljar force-pushed the embeddableMigrations branch from 28b78c7 to 9192a0a Compare August 5, 2020 13:33
Copy link
Contributor

@Dosant Dosant left a comment

Choose a reason for hiding this comment

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

Just picked around during our meeting ( when you presented it )
Will try to play and understand a bit later.


We have this one place where we do migration for dashboard drilldown:
https://github.com/elastic/kibana/blob/master/x-pack/plugins/embeddable_enhanced/public/embeddables/embeddable_action_storage.ts#L122

Should we try to refactor it to use new approach in this pr?

@stacey-gammon
Copy link
Contributor

Can you add tests for migrating base, extended and enhanced state?

};
}

public stop() {}

private migrateEmbeddableInput = (input: Serializable) => {
const enhancements: Record<string, any> = (input as any).enhanecemnts || {};
const factory = this.getEmbeddableFactory((input as SerializableRecord).id as string);
Copy link
Contributor

Choose a reason for hiding this comment

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

input.id != type - this won't work.

I think the migrate function will have to ask for type, separate from input.

@stacey-gammon
Copy link
Contributor

This is generally inline with my thinking. Few things though:

  • tests to make sure it works as expected. I have been playing around with an isolated example on CodeSandbox with tests and I had to loop through multiple possible versions for it to work correctly. I think you also need version passed in to migrate, and I also had to pass in type.

  • Add type guards to avoid casting and any. Throw (or return) errors if the input doesn't match expectations.

Example:

  migrate(state: unknown, version: number) {
    if (version === 1 && isValid1State(state)) {
      return state;
    } else if (version === 0 && isValid0State(state)) {
      return migrateBarChart0(state);
    } else {
      throw new Error("Invalid state");
    }
  }
}
  • Somewhere in here we should warn that we are only temporarily passing the full input state to the factory.migrate functions and the plan is to extract extended state out and store it separately to ensure the migrations only have access to the state they own.

@ppisljar ppisljar force-pushed the embeddableMigrations branch from 9192a0a to 3408f1d Compare August 20, 2020 12:02
@ppisljar ppisljar changed the title Embeddable migrations and reference extraction/injection Embeddable telemetry and reference extraction/injection Aug 25, 2020
@ppisljar ppisljar force-pushed the embeddableMigrations branch 2 times, most recently from 7f06f38 to 60cf0b1 Compare August 26, 2020 11:43
@ppisljar
Copy link
Member Author

@elasticmachine merge upstream

Copy link
Contributor

@Dosant Dosant left a comment

Choose a reason for hiding this comment

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

lgtm,
thanks for addressing latest feedback and merging clean up pr

P.S.: not sure why CI is going crazy. I assume small ts export / reexport mistake

@@ -4,10 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/

export interface UrlDrilldownConfig {
// eslint-disable-next-line
Copy link
Contributor

Choose a reason for hiding this comment

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

// disable can be also remove?

@@ -9,7 +9,8 @@ import { ApplyGlobalFilterActionContext } from '../../../../../src/plugins/data/

export type ActionContext = ApplyGlobalFilterActionContext;

export interface Config {
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
Copy link
Contributor

Choose a reason for hiding this comment

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

I think also worth disabling this rule for ui_actions_enhanced_examples

@ppisljar ppisljar force-pushed the embeddableMigrations branch from be0a8dd to 43438c3 Compare September 16, 2020 11:13
Copy link
Contributor

@flash1293 flash1293 left a comment

Choose a reason for hiding this comment

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

Left a few more comments. Especially the ones about ts-ignore and the way telemetry works should be addressed before merging this

@@ -44,7 +45,8 @@ export interface EmbeddableFactory<
TEmbeddableOutput
>,
TSavedObjectAttributes extends SavedObjectAttributes = SavedObjectAttributes
> {
// @ts-ignore
Copy link
Contributor

@flash1293 flash1293 Sep 16, 2020

Choose a reason for hiding this comment

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

This is worrying in such a basic type - can we avoid it to make sure we don't introduce actually wrong types here in the future?

return {
telemetry: this.telemetry,
extract: this.extract,
inject: this.inject,
Copy link
Contributor

Choose a reason for hiding this comment

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

We can probably live without it for now, but as Tim mentioned once we have migrations on that level we also need to add them on the server as well and migrate everything before fetching telemetry

Copy link
Member Author

Choose a reason for hiding this comment

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

adding migrations is the next step for this which will be done in a followup


telemetryBaseEmbeddableInput(state, telemetryData);
if (factory) {
factory.telemetry(state, telemetryData);
Copy link
Contributor

Choose a reason for hiding this comment

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

This implementation seems strange to me - telemetry returns an updated telemetryData object, but we are simply discarding and probably assume the passed in object will be mutated.

I really don't like relying on object reference here and mutation the object passed into the function. This is not how reduce is typically implemented - can we make telemetry return a new object with added information instead of mutating the existing one? This can lead to hard to catch bugs.

id: 'dynamicActions',
telemetry: (state: SerializableState, telemetry: Record<string, any>) => {
(state as DynamicActionsState).events.forEach((event: SerializedEvent) => {
if (uiActionsEnhanced.getActionFactory(event.action.factoryId)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Can be shortened to

uiActionsEnhanced.getActionFactory(event.action.factoryId)?.telemetry(event, telemetry);

Copy link
Member Author

Choose a reason for hiding this comment

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

that might assign void to telemetryData

): EnhancementRegistryDefinition => {
return {
id: 'dynamicActions',
telemetry: (state: SerializableState, telemetryData: Record<string, any>) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

No strong opinion, just interested - why did you keep the telemetry API on the client even if it's not used?

Copy link
Member Author

Choose a reason for hiding this comment

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

so we can keep the same persistable state definition type on both sides

@ppisljar
Copy link
Member Author

@elasticmachine merge upstream

@ppisljar
Copy link
Member Author

@elasticmachine merge upstream

@ppisljar
Copy link
Member Author

@elasticmachine merge upstream

@kibanamachine
Copy link
Contributor

kibanamachine commented Sep 18, 2020

💚 Build Succeeded

Build metrics

@kbn/optimizer bundle module count

id value diff baseline
embeddable 95 +3 92
kibanaUtils 190 +1 189
uiActionsEnhanced 278 +2 276
total +6

page load bundle size

id value diff baseline
embeddable 435.1KB +4.6KB 430.6KB
kibanaUtils 471.7KB +1.3KB 470.4KB
uiActionsEnhanced 378.9KB +561.0B 378.3KB
total +6.4KB

distributable file count

id value diff baseline
default 45924 +11 45913
oss 27700 +6 27694
total +17

History

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature:Drilldowns Embeddable panel Drilldowns Feature:Embedding Embedding content via iFrame release_note:skip Skip the PR/issue when compiling release notes v7.10.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants