syndesisio / syndesis-ui

The front end application or UI for Syndesis - a flexible, customizable, cloud-hosted platform that provides core integration capabilities as a service. It leverages Red Hat's existing product architecture using OpenShift Online/Dedicated and Fuse Integration Services.
https://syndesis.io/
14 stars 28 forks source link

create a canonical approach for joining on multiple Observable<T> streams of entities to form Observable composite models #113

Closed jstrachan closed 7 years ago

jstrachan commented 7 years ago

increasingly UIs become more than simple CRUD on a single underlying entity and need to start composing things together from multiple resources.

e.g. on the Integrations page we need to show a list of Integration objects plus we may well want to join with the RuntimeState of each integration (is it started or stopped, how many messages & failures have there been or whatever).

So we may want to combine, say, 2 resources together into a composite so we can show - say - the Integration and its associated metrics in a row.

I wonder whats the best way to do this kind of thing in Angular 2? Subscribe to all the underlying Observables and if anything changes recalculate all the things? I guess its one approach for now - am wondering if we need another abstraction at some point. e.g. to have an 'enriched Foo' collection which we use other observables to enrich each Foo.

Many pages in the fabric8-console require this kind of thing (e.g. combining Deployment, Service and ConfigMap together so we can show the exposeUrl + service link and configure link if there are any associated with a Deployment.

Just wondered if anyone had figured out a nice pattern for this yet?

jstrachan commented 7 years ago

here's a quick prototype to show the kinda thing I had in mind:

a ServiceMapper that turns an Array into a Map<string,Service> https://github.com/jstrachan/ipaas-client/blob/f61330362d6cdaf5c74af7bd304a930d3f1e9da8/src/app/kubernetes-restangular/kubernetes.service.mapper.ts#L6-L6

then the ListPage can expose the map structure (should be an Observable<Map<String,Service>> probably? https://github.com/jstrachan/ipaas-client/blob/f61330362d6cdaf5c74af7bd304a930d3f1e9da8/src/app/functions/list-page/list-page.function.ts#L20-L20

then the actual view can join the Function to Service via name: https://github.com/jstrachan/ipaas-client/blob/f61330362d6cdaf5c74af7bd304a930d3f1e9da8/src/app/functions/list/list.function.ts#L17-L17

then used in a template: https://github.com/jstrachan/ipaas-client/blob/f61330362d6cdaf5c74af7bd304a930d3f1e9da8/src/app/functions/list/list.function.html#L50-L50

I guess a nicer approach would be to use some kind of join/map operation on all the underlying Obserable<Array<T>> values and the combine then into a single Obserable<Array<CompositeObject>> using one of the RxJs join/map/flatMap operations on the various lists.


var Obserable<Functions> functions;
var Obserable<Services> services;
...
joinOrSomething(functions, services).flatMap(functions, services) {
   var map = {};
   var answer  = [];
   services.forEach(s => map[s.name] = s;
   return functions.map(f => {
     // return a composite object joining all the objects together
      return {
         fn: f,
        service: map[f.name]
     }
   });
}

then in a template we can just navigate the properties of the composite object via `c.fn.name` or `c.service.foo` etc
jstrachan commented 7 years ago

ah this looks like the kinda thing to combine multiple Observables into a composite objects http://reactivex.io/documentation/operators/combinelatest.html

jstrachan commented 7 years ago

using combineLatest is much cleaner! https://github.com/jstrachan/ipaas-client/blob/b46b8a8d17783605a501b0b98124bca6ccb48364/src/app/functions/list-page/list-page.function.ts#L24-L24

we can then combine 2 Observable streams to make a new Observable then just have a little RuntimeFunction class and function to combine things together nicely: https://github.com/jstrachan/ipaas-client/blob/b46b8a8d17783605a501b0b98124bca6ccb48364/src/app/functions/model/runtime.function.model.ts#L27-L27

much cleaner, more generic & reusable!

jstrachan commented 7 years ago

guess the only thing to decide is naming conventions for these composite models & converter functions and where to put them? For now added them into a model folder per entity