elastic / kibana

Your window into the Elastic Stack
https://www.elastic.co/products/kibana
Other
19.71k stars 8.13k forks source link

[uiActions] make trigger action registry async #191642

Open nreese opened 2 weeks ago

nreese commented 2 weeks ago

The current trigger action registry takes the parameters triggerId: string, action: ActionDefinition<any>. This requires that the action is included in the page load bundle.

Instead, the registry should take the parameters triggerId: string, actionId: string, getAction: () => Promise(ActionDefinition<any>). An example of a registry with an async getter is the react embeddable registry.

Current registry example

Below is an example of an existing action. The action is from maps plugin and is used to synchronize map movement in a dashboard. Notice in the action how the author has to be careful to async import isCompatible and execute implementations to avoid bloating page load bundle. This very error prone and many times, actions are a source of page load bloat. Even with care, the action definition itself is still included in the page load bundle.

Example trigger action registration
plugins.uiActions.addTriggerAction(CONTEXT_MENU_TRIGGER, synchronizeMovementAction);
Example action
export const synchronizeMovementAction = createAction<EmbeddableApiContext>({
  id: SYNCHRONIZE_MOVEMENT_ACTION,
  type: SYNCHRONIZE_MOVEMENT_ACTION,
  order: 21,
  getDisplayName: () => {
    return i18n.translate('xpack.maps.synchronizeMovementAction.title', {
      defaultMessage: 'Synchronize map movement',
    });
  },
  getDisplayNameTooltip: () => {
    return i18n.translate('xpack.maps.synchronizeMovementAction.tooltipContent', {
      defaultMessage:
        'Synchronize maps, so that if you zoom and pan in one map, the movement is reflected in other maps',
    });
  },
  getIconType: () => {
    return 'crosshairs';
  },
  isCompatible: async ({ embeddable }: EmbeddableApiContext) => {
    if (!isApiCompatible(embeddable)) return false;
    const { isCompatible } = await import('./is_compatible');
    return isCompatible(embeddable);
  },
  execute: async () => {
    const { openModal } = await import('./modal');
    openModal();
  },
});

Proposed registry example

Instead, the registry should take an async getter so that the action is not included in the page load bundle and instead is only loaded when the trigger or action id is required.

Example trigger action registration
plugins.uiActions.addTriggerAction(CONTEXT_MENU_TRIGGER, SYNCHRONIZE_MOVEMENT_ACTION, async () => {
  const { synchronizeMovementAction } = await import(
     './actions/synchronize_movement_action'
  );
  return synchronizeMovementAction;
});
elasticmachine commented 2 weeks ago

Pinging @elastic/appex-sharedux (Team:SharedUX)