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

Remove dynamic mapped types from UiActions #87075

Merged
merged 5 commits into from
Jan 5, 2021

Conversation

joshdover
Copy link
Contributor

@joshdover joshdover commented Dec 30, 2020

Summary

This removes the pseudo type safety in the UiActions framework that leveraged declare module to reopen the TriggerContextMapping type. This pattern is not compatible with TS project references (#80508) and is not really type safe anyways. This PR removes this type and simplifies a lot of related code.

Reasons we should feel comfortable removing this:

  • It creates implicit circular dependencies in the type system
  • It leaks types across plugins that are in the same TS project
  • I didn't find a single instance where this type information was actually leveraged by consuming code to catch errors. It appears all calling code already knew the type of action it was calling into (as it should).
  • This pattern must be removed to migrate to TS project references and to the Bazel build tool, neither of which will support circular imports between plugins.

For maintainers

return {
getIconType: () => undefined,
order: 0,
id: action.type,
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'm not sure why this wasn't failing before, but ActionDefintion currently has id marked as a required field, yet this function does provide a default fallback to the type field.

TS was complaining here that this line would be overridden by the ...action spread below which makes sense, so I removed this line. However, that also required me to add the id field to many call sites of this function. I didn't want to change the types, but I think the desired behavior is:

  • ActionDefinition should require either id OR type
  • If id is undefined, createAction should fallback to type. Is that correct?

Copy link
Contributor

Choose a reason for hiding this comment

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

However, that also required me to add the id field to many call sites of this function. I didn't want to change the types, but I think the desired behavior is:

ActionDefinition should require either id OR type
If id is undefined, createAction should fallback to type. Is that correct?

This seems correct, but to not add id in bunch of call sites, why you didn't make id optional for this function lit it was before?
See: https://github.com/elastic/kibana/pull/87075/files?file-filters%5B%5D=.ts&file-filters%5B%5D=.tsx#diff-4960a0b834fad6726535d59e6fc8b2febb31f0669916cbcfe9f19eec00478f46L26

Copy link
Contributor

Choose a reason for hiding this comment

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

in the old implementation this was valid:

createAction({ execute() {} }) 

since both id and type used to be optional.

Josh decided to make id required instead of introducing a union type ActionDefinitionWithId | ActionDefinitionWithType

Comment on lines +33 to +34
ExecutionContext extends object = object,
FactoryContext extends BaseActionFactoryContext = BaseActionFactoryContext
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 switched the order of ExecutionContext and FactoryContext since there were a few use cases where the default for ExecutionContext needed to be overridden but not FactoryContext

@joshdover joshdover added release_note:skip Skip the PR/issue when compiling release notes v7.12.0 v8.0.0 Team:AppServices labels Dec 30, 2020
@joshdover joshdover force-pushed the ui-actions-remove-types branch from fcd5f4d to a27d42e Compare December 30, 2020 19:51
@joshdover joshdover marked this pull request as ready for review December 30, 2020 19:51
@joshdover joshdover requested a review from a team December 30, 2020 19:51
@joshdover joshdover requested review from a team as code owners December 30, 2020 19:51
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-app-services (Team:AppServices)

@joshdover joshdover requested a review from Dosant December 30, 2020 19:51
@joshdover joshdover force-pushed the ui-actions-remove-types branch from a27d42e to be317b3 Compare December 30, 2020 19:55
@botelastic botelastic bot added Feature:Drilldowns Embeddable panel Drilldowns Feature:Embedding Embedding content via iFrame labels Dec 30, 2020
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.

Kibana app stuff LGTM, left one small nit

Copy link
Contributor

@streamich streamich left a comment

Choose a reason for hiding this comment

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

Code changes LGTM.

Copy link
Contributor

@darnautov darnautov left a comment

Choose a reason for hiding this comment

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

ML changes LGTM

@Dosant
Copy link
Contributor

Dosant commented Jan 4, 2021

I understand that we have to do this to unblock typescript project refs effort, but I wouldn't agree with this statement:

I didn't find a single instance where this type information was actually leveraged by consuming code to catch errors. It appears all calling code already knew the type of action it was calling into (as it should).

Some example from top of my head where old system was useful:

1. getTrigger returns type safe triggers

https://github.com/elastic/kibana/blob/master/src/plugins/data/public/actions/select_range_action.ts#L50-L52

uiActions.getTrigger(APPLY_FILTER_TRIGGER).exec({
            filters,
            embeddable: context.embeddable,
            timeFieldName: context.data.timeFieldName,
});

The context shape passed into exec function is typed. In this pr, as I understood, it would only type check that shape extends object.

Same applies for getTriggerCompatibleActions

2. Drilldown definition listed a type safe list of supported triggers.

https://github.com/elastic/kibana/blob/master/x-pack/plugins/ui_actions_enhanced/public/drilldowns/drilldown_definition.ts#L163

Consumers who create their drilldowns had to specify supported triggers, we would caught on type check if they are trying to use not existing trigger. (e.g. typo or older trigger was removed or renamed)

Same for embeddable listing a list of triggers they could emit.

3. We enforced Drilldown's context to be a superset of its triggers' contexts

https://github.com/elastic/kibana/blob/master/x-pack/plugins/ui_actions_enhanced/public/drilldowns/drilldown_definition.ts#L38

Imagine a drilldown type supports both VALUE_CLICK_TRIGGER and RANGE_SELECT_TRIGGER, in such case before this pr we type checked that drilldown's context can handle VALUE_CLICK_TRIGGER_CONTEXT | RANGE_SELECT_TRIGGER_CONTEXT

return {
getIconType: () => undefined,
order: 0,
id: action.type,
Copy link
Contributor

Choose a reason for hiding this comment

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

However, that also required me to add the id field to many call sites of this function. I didn't want to change the types, but I think the desired behavior is:

ActionDefinition should require either id OR type
If id is undefined, createAction should fallback to type. Is that correct?

This seems correct, but to not add id in bunch of call sites, why you didn't make id optional for this function lit it was before?
See: https://github.com/elastic/kibana/pull/87075/files?file-filters%5B%5D=.ts&file-filters%5B%5D=.tsx#diff-4960a0b834fad6726535d59e6fc8b2febb31f0669916cbcfe9f19eec00478f46L26

@mshustov
Copy link
Contributor

mshustov commented Jan 4, 2021

@Dosant as @joshdover is on PTO, I'm going to continue working on the task.

  1. getTrigger returns type safe triggers
    https://github.com/elastic/kibana/blob/master/src/plugins/data/public/actions/select_range_action.ts#L50-L52
    The context shape passed into exec function is typed. In this pr, as I understood, it would only type check that shape extends object.

If I understand correctly, the point was that introduced complexity doesn't justify the effort. Since we do know the type of the action, the type safety can be achieved as simple as

const triggerContext: ApplyGlobalFilterActionContext = {
  filters,
  embeddable: context.embeddable,
  timeFieldName: context.data.timeFieldName,
};
uiActions.getTrigger(APPLY_FILTER_TRIGGER).exec(triggerContext);
  1. Drilldown definition listed a type safe list of supported triggers.
    Consumers who create their drilldowns had to specify supported triggers, we would caught on type check if they are trying to use not existing trigger. (e.g. typo or older trigger was removed or renamed)

A consumer can achieve the same importing TriggerId from a plugin or plugin contract. With the current implementation, a plugin can call uiActions.getTrigger(TRIGGER_NAME).exec(..) without even declaring a dependency on a plugin registering TRIGGER_NAME (note that this plugin might be disabled as well, the type system won't provide any guarantees about that)


Any input on an alternative implementation is appreciated.

@mshustov mshustov requested a review from Dosant January 4, 2021 13:52
@Dosant
Copy link
Contributor

Dosant commented Jan 4, 2021

@restrry,

Any input on an alternative implementation is appreciated.

Unfortunately, don't have any alternatives on my mind.
To be clear: with that note above I wasn't pushing back on this change. My intention was to note, that we have to lose some of benefits of older system (it isn't clear from the pr description).

would appreciate those nit code comments clean up.

Also. Does this mean we have to get rid of this pattern in other places? One other heavily used I am aware of is share plugin and Url generators.

@mshustov
Copy link
Contributor

mshustov commented Jan 4, 2021

@Dosant answered nits.

Does this mean we have to get rid of this pattern in other places? One other heavily used I am aware of is share plugin and Url generators.

Probably, we definitely want to get rid of it in the core code #57588

Copy link
Contributor

@clintandrewhall clintandrewhall left a comment

Choose a reason for hiding this comment

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

Looks straight-forward to me. 👍

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Distributable file count

id before after diff
default 47266 48026 +760

Page load bundle

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

id before after diff
discoverEnhanced 15.7KB 15.4KB -339.0B
embeddable 233.0KB 233.0KB +43.0B
maps 152.7KB 152.8KB +51.0B
uiActions 63.6KB 62.3KB -1.4KB
total -1.6KB

History

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

@mshustov mshustov merged commit 0af8131 into elastic:master Jan 5, 2021
mshustov added a commit to mshustov/kibana that referenced this pull request Jan 5, 2021
* Remove dynamic mapped types from UiActions

* Remove import between data <-> embeddables

* remove outdated comments, export action types from discover_enhanced

* fix notice.txt

Co-authored-by: restrry <[email protected]>
mshustov added a commit that referenced this pull request Jan 5, 2021
* Remove dynamic mapped types from UiActions

* Remove import between data <-> embeddables

* remove outdated comments, export action types from discover_enhanced

* fix notice.txt

Co-authored-by: restrry <[email protected]>

Co-authored-by: Josh Dover <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backported Feature:Drilldowns Embeddable panel Drilldowns Feature:Embedding Embedding content via iFrame release_note:skip Skip the PR/issue when compiling release notes v7.12.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants