finos / vuu

Vuu - an open source view server and html 5 based UI system
https://vuu.finos.org
Apache License 2.0
44 stars 27 forks source link

Implement Layout management #333

Open heswell opened 2 years ago

heswell commented 2 years ago

Vuu layouts are described by JSON documents. When a user logs in, a rest call to server returns the latest layout json. The Shell uses that to construct the UI. Every change the user makes to the layout or components hosted within a layout are saved back to the server, these include

We would like to implement a full UI for layout management, this might include

### Tasks
- [ ] Add layout menu items to context menu of main application tabs
- [ ] Implement Save Layout dialog
- [ ] Implement layout browse panel to be displayed from left nav
- [ ] define restful API for create/update/get Layout
- [ ] implement saving/loading etc, using new API
- [ ] create reference implementation of a restful service for layout persistence

Questions

cfisher-scottlogic commented 1 year ago

Scott Logic are contributing to this issue and our internal tracking of associated work can be found on our fork.

At the moment we are doing the following work:

Tasks

...

  1. [ ] Implement Save Layout dialog
  2. [ ] Implement layout browse panel to be displayed from left nav
  3. [ ] define restful API for create/update/get Layout
  4. [ ] implement saving/loading etc, using new API ...
heswell commented 1 year ago

Refactoring the layout service.

The current rest service saves a complete history of changes applied to the application json. This can be browsed and older versions of the application layout re-loaded. We should probably implement something similar at the layout level, too. Right now, we don't have any designs around how we would view these.

As the application json will be quite simple now, we can add typescript typings. The layouts are trickier, as they store Component props - the typing would be driven by the components included - not impossible to type, but more complex. Would be very useful for layouts authored by hand.

As we work on the json , we should think about how a versioning scheme might work. If an updated version of a component is released, for example, and that component is included in one or more layouts, how will we manage the upgrade process. My ideal scenario would be that we are able to prompt the user - "a newer version of this feature is available do you want to upgrade". If they agree, we update the json and load a newer version of that component (all components are 'features' and loaded dynamically, so this shouldn't be too hard. Any issue and we can revert. This won't be trivial, but this work on layouts gives us a good opportunity to think through how we might approach this.

heswell commented 1 year ago

work in progress ...

Introduction of the new layout management system, with support for saving and loading individual layouts, will need careful management to avoid breaking existing installations. The existing UI layout handling is described below, followed by a solution for introducing the new system in a backward-compatible way. The challenge is that the new system requires the use of a new set of REST service endpoints to handle layouts and those new REST endpoints will not necessarily be available to all deployments. Until such time as a new REST service is bundled with the default VUU deployment we need to maintain support for the existing mechanism.

How Vuu handles UI layout now

In the image below, the dashed rectangle represents the dynamic portion of the UI, the chrome above and to the left is statically defined.

Screenshot 2023-09-04 at 11 40 50

2) changing persistent attributes of a component - any component may opt to persist some or all props that are set at runtime. The DataTable is a good example, props will be persisted in any of the following scenarios:

Layout operations are accomplished by dispatching layout actions. The layout action dispatcher is provided by the LayoutProvider, so available to any component. Support for layout manipulation is baked into the Vuu layout components , no application specific code is required to enable this, other than to wrap the app in a LayoutProvider and handle the onLayoutChange callback prop. This callback is provided explicitly so that the layout can be persisted. The Vuu Shell takes care of both of these. For saving component props, it is the responsibility of component authors to ensure that props are saved when necessary. The Feature is the basic unit of component deployment within Vuu, so in the sample app, the DataTable is deployed as a VuuTable Feature. Features have access to a persistence API (through ViewContext). When this persistence API is used , props are saved into an application level store, keyed by the component id. A 'save' layout action is also dispatched whenever props are saved, triggering serialisation of the UI to JSON and posting that JSON to a REST endpoint. When the application UI is serialised to JSON, the layout structure is serialised directly from the React component tree (the virtual dom). For each Feature embedded within the layout, any saved props are pulled from the global prop store and included in the JSON. Features represent the leaf-level entities in the persisted JSON, so the representation of the UI is at quite a coarse level - the JSON serialisation does not extend down to low-level UI components like form controls etc. This would be both unnecessary and inefficient.

The JSON that gets saved in these scenario is the entire JSON for the dynamic portion of the UI. In the sample app, the dynamic portion of the UI is the main tabbed area, including the layouts associated with those tabs. If the user has five tabs at this level (i.e. five layouts) then all five get serialised and saved when any one is manipulated.

How Vuu will manage UI layout with the new layout system

Using useLayoutConfig, the Shell will retrieve application layout for logged-in user as above. This layout will describe ONLY the list of Layouts to be displayed This will be basically a list of Labels for the Layout tabs, the unique URL for each layout and the identity of the current open layout (the selected tab). We may eventually store other metadata in this application level JSON - application-level settings changed by the user for example. Importantly, this JSON will not include the json description of the layouts themselves.

Once the application json is loaded, the Shell will identify the active layout, then request the layout JSON for that layout. Using both the application level json and the json for the open layout, the UI can be rendered. Any manipulation of the layout at runtime within this layout will be handled as described above, the difference being that only a single layout will ever be processed, not the entire set of tabbed layouts. If the user switches to a different layout (or uses new layout UI to reload a saved layout), the json for that layout will be retrieved on the fly from the REST endpoint, the UI will be constructed from that JSON and rendered within the tabbed view. There will be some new code here, most of which can be constructed from existing functionality.

When the user switches between layout tabs, the question will arise, do we entirely discard a layout when the user opens a different layout. That means discarding all components within that layout, which in turn means unsubscribing from any Vuu server subscriptions. Right now there is an optimisation in effect that allows us to keep server subscriptions alive but suspended when switching away from a layout. This makes switching back to a previously opened layout very fast. To be decided.

How both the above can be supported

The Shell will load the application level json for the logged-in user, as in both the scenarios above. The application json served by the new REST service will carry a version attribute (maybe "layout.version" : 2 ?). If this version attribute is not present, the application json will be handled entirely as per existing implementation. If the version is present, we handle the layout json with a new code path,