prismatic-io / spectral

Prismatic's typescript library for custom components
https://prismatic.io/docs/spectral/custom-component-library
35 stars 2 forks source link

Support componentized polling triggers #275

Closed pattra closed 1 week ago

pattra commented 3 weeks ago

Summary

This PR allows component authors to create pollingTriggers that are optionally attached to an existing component action.

While in the context of a polling trigger's perform function, the dev will have access four new primitives:

  1. context.polling.invokeAction(actionParams): Invokes the pollAction, with type hinting for the action params
  2. context.polling.getState(): Retrieves the contents of instanceState.__prismaticInternal.polling
  3. context.polling.setState(newState): Sets the contents of instanceState.__prismaticInternal.polling. Will stomp current contents.
  4. context.polling.reinvokeFlow(data, config): A wrapper around axios.post that calls context.invokeUrl. Can be used for complex pagination cases.

Code example

import {
  getPaginationFromResults,
  shouldReinvoke
} from "./somewhere";

type MyPaginationType = {
  limit?: number;
  page?: number;
};

const myPollingTrigger = pollingTrigger({
  pollAction: listProducts,
  perform: async (context, payload, params) => {
    const pollState: MyPaginationType = context.polling.getState();

    // Params will hint on both trigger inputs & associated action inputs
    const limit = pollState.limit ?? params.limit;
    const pageToFetch = pollState.page ?? params.page;

    // Will hint only on action inputs
    const results = context.polling.invokeAction({
      ...params,
      page: pageToFetch,
    });

    const newPollState = getPaginationFromResults(results);
    context.polling.setState(newPollState);

    if (shouldReinvoke(results)) {
      // if they don't want to use internalState, they could modify
      // the body or params here and then handle that in the perform.
      context.polling.reinvokeFlow();
    }

    return Promise.resolve({ payload: { ...payload, body: { data: results } });
  },
});