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

Data middleware for function based widgets #660

Closed
tomdye opened this issue Jan 29, 2020 · 0 comments · Fixed by #672
Closed

Data middleware for function based widgets #660

tomdye opened this issue Jan 29, 2020 · 0 comments · Fixed by #672
Assignees
Labels
area: core Core enhancement New feature or request

Comments

@tomdye
Copy link
Member

tomdye commented Jan 29, 2020

This issue forms the proposal for a data middleware that widgets can use to become data aware and interact with an underlying shared data resource.

Aims

  • Consistent API
  • Share data between widgets
  • Share resources between widgets
  • Silo resources so that they don't affect other widgets
  • Reactive
  • Pagination support
  • Query support
  • Data transform support
  • Fully typed

Data middleware POC achievements

The data middleware should provide the widget with an API to access and interact with the underlying data resource.

passing resource to the middleware

The data middleware will add a resource property to the widget using it. This will allow a resource to be passed to the widget via a simple property. When initialising the data middleware, it should peel the resource off of the widget properties and bind it to the middleware api.

passing a transformer to the middleware

The data middleware will need to provide a means to transform the data it is provided by it's resource in order the pass appropriate data to it's widget. This will be fully typed to ensure that the transformer that is passed via a transform property is suitable for the widget in question. In order to support these typings, we will need to provide a createDataMiddleware function similar to that which icache provides with createIcacheMiddleware.

// when creating a middleware for a DataWidget with this generic
const data = createDataMiddleware<{ foo: string; }>();

// types correctly
<DataWidget transform={(item) => ({ foo: item.firstName })} />

// should show compile error because it does not return `{foo: string}`.
<DataWidget transform={(item) => ({ bar: item.firstName })} />

initialising the data middleware

The data middleware will provide a factory function that is used to initialise the middleware with options. During this initialisation the resource and a transform function where appropriate will be peeled off of the widget properties and bound to the data middleware.

The returned object can be destructured to gain access to the middleware API as described further below. This is how widgets will interact with the underlying data-resource.

When calling data() to initialise the middleware, options can be passed to effect the middleware that is created.

data middleware options

interface DataOptions {
  reset?: boolean;
  resource?: Resource | ResourceWrapper;
  key?: string;
}

interface Options {
  pageNumber: number;
  query: string;
  pageSize: number;
}
reset

When passing this option as true to the data middleware, the passed resource should be reset and created with it's own options. This means that if the widget is passed a shared resource, it will no longer be shared. This will be particularly useful in widgets such as the typeahead where we do not want changes to the query or the page to affect any other widgets elsewhere in the app that are using the same data resource.

resource

By default the middleware will take the resource from the widgets resource property, however, if you wish to override this or to work with more than one resource this will allow a user to create a second data api via the middleware to interact with it.

key

When working with the same resource in multiple places within the same widget we need to specify a key to differentiate them. Otherwise changing the page / query on one resource will have an impact on the other.

middleware api

interface DataMiddleware: {
    getOrRead(options: Options): DataResponse;
    loading(options: Options): boolean;
    failed(options: Options): boolean;
    setOptions(newOptions: Options): void;
    getOptions(): Options;
    readonly resource: ResourceWrapper;
    shared(): ResourceWrapper;
}

getOrRead

The get or read function will take a full options object including any query / pagination / pagesize etc information and will return the appropriate data. This should be a reactive function and cause the calling widget to invalidate when the data becomes available. This will use the underlying data-resource to acquire the data.

loading

We will need a way to discover if a particular data read is loading / in progress. This will enable us to display a loading indicator or progress bar where appropriate. This can be a sync api that returns a boolean to indicate the loading status of a getOrRead. As the options are used for all getOrRead commands, they can be used here too to ensure that the appropriate status is returned.

failed

We will need a way to discover if a getOrRead has failed. This can be achieved by passing the options object to the failed function. It can be a sync api the same as loading and can return a boolean response. An alternative to loading / failed might be to use a status api that returns a response of 'loading' | 'error' | 'complete'. We should decide which of these is more appropriate.

setOptions

The setOptions function will take a set of options and use those to update the options stored in the middleware. This will enable the sharing of control over a resource between two or more widgets, for example a text input controlling the query on a menu.

getOptions

getOptions will return the current options object from the middleware. This will be used along with getOrRead to acquire the appropriate data. These could also be used for display purposes; ie. rendering out the query text.

get resource

The resource getter returns the underlying resource which can in turn be passed onto another data-aware widget. When they initialise their own data middleware with this resource, they will receive their own options layer, thus allowing them to interact with and query the same underlying data-resource via their own parameters.

shared

This function will return a shared resource which can then be passed to another widget. This shared resource will have the same options layer as the original and thus will share the sane query / pageNumber etc. This is particularly useful when passing a shared resource between a set of controls and another widget that renders the results.


A working POC of this proposal can be found here

@tomdye tomdye added area: core Core enhancement New feature or request labels Jan 29, 2020
@matt-gadd matt-gadd changed the title data middleware for function based widgets Data middleware for function based widgets Jan 29, 2020
@tomdye tomdye self-assigned this Jan 29, 2020
@tomdye tomdye mentioned this issue Feb 6, 2020
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: core Core enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant