ManageIQ / manageiq-design

Design documents and UX mockups for ManageIQ
https://manageiq.github.io/manageiq-design
11 stars 15 forks source link

[RFC] UI-API and decorators #43

Open skateman opened 6 years ago

skateman commented 6 years ago

The concept of a data-driven API is not enough to be able to render both a fully featured and fully API-driven UI. We already have some API features that have been only added for the sake of presentation in the UI. Of course implementing all of those in the API would cause a huge bloat and code maintenance issues.

Let’s take for example the explorer trees on the left side of the screen. They are fully JSON-driven, however, it is not possible to retrieve them from the API effectively. The same goes for the report data on the GTL screens.

We had some discussions about this with other UI team members and we were thinking about creating a UI-API that can provide the required data for the presentation layer. There are already some pieces of this in the current codebase for some trees and for report data. Eventually, this UI-API needs to be somehow plugged into the current API codebase. So I think we should end up with an API plugin (or maybe more than one) that is responsible for things that are only related to the presentation.

This is how I got to the assets (images, icons) that are related to resources (VMs, containers, services, etc). Right now, the SUI renders just a few types of resources and determines their vendor/OS icons in a very primitive way. However, not all of the resources have these attributes and it’s not always trivial how to retrieve the asset for a given resource type. That’s the reason why we introduced model decorators for the OPS UI.

They are all instances of SimpleDelegator from the stdlib and bound to an ActiveRecord model. Each of them defines methods for retrieving additional data required for the presentation (currently icons, images and quadicons but more to come). For some simple cases it’s just a bunch of one-liners returning strings, but sometimes there’s more complex logic behind them. They operate perfectly with the STI, so if the given record doesn’t have a decorator, but its STI parent does, it will automagically use the parent’s decorator.

Of course we could move most of these to the JS, however, that might overtax the API. Imagine the situation when we don’t know what kind of resource types will we get back from an API request. Until the response arrives, we don’t know which decorator to use and our methods for determining the icon/image/quadicon might depend on additional data that is not implicitly available. So, it’s highly possible that we would have to fire multiple requests because we don’t know what to ask for and the API doesn’t know what to send us.

Getting back to the UI-API-plugin concept, the data provided by the decorators is essential for rendering parts of the UI. If we want to be fully API-driven, they should be accessible from the API if needed.

Fryguy commented 6 years ago

@chessbyte @abellotti Would like your thoughts here.

abellotti commented 6 years ago

had some comments there: https://github.com/ManageIQ/manageiq/issues/17675

"Interesting discussion, my initial thinking is Model & API are the data layers, and feel this should stay that way. It sounds like we need a data -> presentation mapping layer, the above decorators can still be moved out but would be consumed by that layer, not the Model/API one. Model/API saying this is type X, or Y, (text prefix string, class, etc) mapping layer saying for X we need Decorator dX, etc. UI can then fetch the appropriate decorators (probably prefetched/cached) needed in the mapping layer for the presentation side of things. Maybe extending what SUI had, but supporting Decorators above and honoring provider plugins hierarchies. my 2 cents."

skateman commented 6 years ago

ping @martinpovolny, @himdel

abellotti commented 5 years ago

ping @gtanzillo to decorate or not decorate (i.e. exposing decorate as a relationship in API so accessible via attributes=decorate.\<something>,...) Looks like this stuff is already wired up in our model app/models/application_record.rb in MIQ. Accessible via \<model_instance>.decorator.\<something>.

martinpovolny commented 5 years ago

It sounds like we need a data -> presentation mapping layer

The requirements on the UI sometimes mean that to present entity A one needs to query a number of other entities. And doing that from the UI is not performant nor practical.

Other part of the problem is that as we are trying to transition from server-side Rails app to separate UI that consumes API we have situation where the same information is needed in one context over the API and in other context in the legacy part in the Rails app.

Curretly such logic can be present in the models or can be implemented in the controller.

When such logic is in the models we face an expected push back from the core developers. But when he logic is in the controller then we have no way to access it throught the API.

We know about these problems from the beginning of the work on the API and I tried to express it at various ocassions.

One way to address that was the UI-API idea (that was not met positively outside the UI group). Another way to approach the problem is the idea of decorators.

In either case we need presentation related information and logic served through some API from the server.

What we really need to avoid is moving the logic to the client. The reasons not to move the logic to the client are:

a) practical: we are not able to replace large parts of the UI at one, so we always have parts that are the classical Rails app and parts that go throught the API. So if we wanted to move those parts to the client, they would end up being duplicate on both ends most likely for several releases of ManageIQ increasing the maintanance cost.

b) efficiency: the presentation depends on the data from other entities and in various cases from different entities. Doing the calculations on the client and fetching all the entities involved would be super slow. Too many HTTP request. A good example is a quadicon where all kinds of data might or might not be needed to properly calculate the graphical presentation. For a VM quadicon one might need information about Host, Provider, Hardware, Network, Policy... Another example are the textual summaries.

cben commented 5 years ago

c) validations & permissions: backend can enforce restrictions that are hard or impossible to leave to client side.

Basically, no opinion, just wanted to mention this for completeness.

skateman commented 5 years ago

@abellotti @gtanzillo any update on this?