Angular registry of Actions and Views
Summary
-------------
This blueprint establishes features useful for the modularization and extensibility of Horizon actions and views, largely through use of a registry.
Motivation
--------------
1) To provide standardization of views and actions so they can be developed and deployed consistently
2) To ensure that view and action features are reasonably "extensible" by third-parties
3) To ensure that views and actions may be easily repurposed--not just work in a single context
4) To provide a single way for developers to easily achieve the above via an application-level registry
60-second overview: https:/
Description / Background
-------
In Mitaka, we started to address "extensibility" features in Angular. This term is meant to encompass the ability for a Horizon installation to be easily configured to provide more (or less) features without the use of changing source code. For example, if a details display has tabs, it should be easy for a third party to, in their installation or as a plugin, provide additional tabs without altering the Horizon source code. In Mitaka this was partly achieved through the introduction of an "extensibility service" which provided a generic way to manipulate lists (append, remove, replace, etc.) of features. However, there was no framework that used the service automatically, so it was up to the developers of controllers/
There is also an interest in making the features of Horizon modular in the sense that common components, such as user actions or views, could be repurposed so they may be easily configured, tested, deployed, and extended. For example, if we are show user actions on both a list page and a details page, we would want that component to be modular in the sense that the actions make no assumptions about their environment, but instead are passed in a standard set of information, and complete in such a way that any view (e.g. a listing or a details view) can react appropriately for its context. If a user deletes an Instance (an action), the context of that action may react differently: a listing may choose to remove a row, or reload the whole list; a detail of that instance may instead want to present a page indicating the old deleted record. The whole point is that actions should not be coded to work only in a single context, and similarly the contexts in which they are created must be able to accept the completion of actions they do not know about. If a third-party builds a new action outside of core Horizon, the developer would like to know that the context (controller, etc.) that calls their action can reasonably react to it even if it.
Additionally, as we move into a transitionary period where we see the development of new views within Horizon, such as the Searchlight panel, we want to ensure that all views and actions we create are usable in these different presentations.
Description / Solution
-------
A common solution to the kinds of problems stated above is to establish a registry. A registry is an application-level service that collects information that can be accessed throughout the application. The value of a registry is that it provides structure to both the creation and extraction of information.
In this particular case, a primary purpose of a registry is to organize data that is common between resource types. A "resource type" means a distinct kind of entity known to OpenStack; for example, a Server or an Image. Each of these kinds of data contains common information, such as names ("Server," "Servers"), actions ("Edit Image," "Launch Instance"), and views (details views, drawer views in a table). These resource types may be identified by their Heat template identifier, e.g. "OS::Nova::Server" for servers/instances. Also, many of these features, such as actions and views, are the exact kinds of things that we want to be extensible. We want third-parties to easily add actions and views, so having a registry that is aware of these actions and views and automatically applies the extensibility service to them is beneficial to these developers.
Description / Implementation
-------
The steps to achieving this goal have already been started on in Mitaka. The registry concept was introduced as a way of presenting actions. However, there are specific features that need to be adopted to ensure we meet our goals above:
1) Actions separate themselves from any assumptions of scope and context. They assume they are passed one or more items, from which they should only use a minimum of context (e.g. their ID) to operate upon. For example, editing an object should not edit an existing model but instead a model loaded from the API, even if more expensive than reading a scoped object). To meet this implementation, existing actions must not interact with scoped items or manipulate the item they are passed.
2) Actions return promises that, when resolved, provide a standardized set of data. This allows any context can use to understand roughly what has occurred as a result of the action. In this case, an object that provides the following is required:
{ updated: [{type: "OS::Glance:
created: [],
deleted: [],
failed: [] }
The objects in each list must conform to having member 'type' as a Heat name for the resource type affected, and 'id' as the serialized identifier for the object. In most cases the ID will be simply the string of the ID, however, some items may require a different reference, for example, a path for a Swift object. An action-result service should be established that provides convenient methods for both generating and interpreting these promise resolutions.
Multiple objects of any category (e.g. 'deleted,' 'failed') are allowed, and they may be of any type. For example, the result of launching an instance may have created both an instance but also a key pair; deleting images may have affected multiple images; creating a snapshot from a volume may have both created a snapshot and updated a volume.
3) Actions use the registry to associate them to a resource type. This was largely accomplished in Mitaka, but additional fixes/modifications should be accomplished in Newton. There are three types of actions in a resource type in the registry: item actions, which may operate on only one item; batch actions, which may operate on multiple items, and global actions, which can be operated without any existing items at all. Examples: Edit Image is an item action because only works on a single image; Delete Images is a batch action because it can operate on multiple; and Create Image can be run without any existing image having been created.
4) Details views are exposed via the registry. The registry provides for "details" views, which is a collection of views that are presented to a user when they inquire about a single item. It also provides for summary/drawer views, which are views that complement tabular-style displays. In the case of the details views, these are extensible in so far as a resource type can have zero (preferably one) to many of these, and they could be presented for example as tabs on a "details" page. The drawer views, on the other hand, are registered as having only one, as such a summary is meant to be very limited, and thus is simply replaceable (not having multiple drawer views per item).
Part of this is that there is a standard display for details, where all the component parts of the display are driven by the information in the registry. This alleviates the need for any developer to custom-write their own details pages, and ensures that their views will work seamlessly with any updates to the details framework that may come along. In this case, the details will display any item actions for the selected item, and any detail views that have been registered for the selected item.
There will also be a default view that may be registered for those resource types that have no view specified. This is useful in the case that new resource types are being developed but have no specific views built yet.
5) Angular views share the same Django template as their SPA (single-page app) launching point. This may seem trivial, but right now there are a variety of Django templates each establishing an ng-view. This creates problems because to be a capable SPA we need to be able to use Angular's routing as much as possible rather than constantly re-routing through Django. Having a single Django template that defines the Angular ng-view allows any Django routing to produce the appropriate context for the SPA, yet allows Angular routing to intelligently detect and route within the SPA application.
6) A generic "table" view is available to all registered resource types to minimize coding. What this means is that rather than requiring a developer to write the typical "table" view for a panel, we can instead present a table based on information in the registry for a given resource type. Django routes to the general Django template described above, but the path is parsed to determine the type, which the generic controller then uses to provide the table for that resource type.
To effect this we need to be able to register both a list function and the table columns. The hz-dynamic-table directive is used to provide the table features.
7) A developer panel that inspects the registry is available. The purpose of the developer panel is to show each of the registered resource types and allow a developer to see what members have been registered. This allows not only a good check for configuration, but also the means to easily verify that the actions and views function, without even having any pages present. This is a boon to developers who are tasked with building actions especially when coupled with the ability to dynamically create both table and details views.
Description / Proof of Concept
-------
Each of these proofs-of-concept have been demonstrated at https:/
UX
----
The features described here will follow the existing UX guidance provided as for the Angular Image and related work. There are no new complexities introduced by the UI in this functionality.
Testing
----------
All components will be unit-tested at the same coverage and level dictated for the rest of the Angular work.
Outside Dependencies
-------
None.
Doc Impact
---------------
Documentation for the features needs to be written both within the code but also in the general Horizon developer docs.
Blueprint information
- Status:
- Complete
- Approver:
- Rob Cresswell
- Priority:
- High
- Drafter:
- Matt Borland
- Direction:
- Approved
- Assignee:
- Matt Borland
- Definition:
- Approved
- Series goal:
- Accepted for 10.0.0-newton
- Implementation:
-
Implemented
- Milestone target:
-
newton-3
- Started by
- Travis Tripp
- Completed by
- Rob Cresswell
Related branches
Related bugs
Sprints
Whiteboard
Gerrit topic: https:/
Addressed by: https:/
Generic details display framework
Addressed by: https:/
Adding generic table extensibility
Gerrit topic: https:/
Addressed by: https:/
Images tables uses action promises
Gerrit topic: https:/
Addressed by: https:/
Add OS::Nova:
Gerrit topic: https:/
Gerrit topic: https:/
Addressed by: https:/
Adding generic table features
Addressed by: https:/
Developer Registry Resource Browser
Addressed by: https:/
Using registration for auto-generation of Image feature
Addressed by: https:/
WIP: Documentation improvements for registry
Gerrit topic: https:/
Addressed by: https:/
getIdsOfType now returns all ids if type undefined
Addressed by: https:/
Instances: Add angular instances panel
Addressed by: https:/
Modify hz-cell to use params and to accept values
Addressed by: https:/
WIP: Adding hz-property and filter/value retrieval from properties
Addressed by: https:/
WIP: Image uses hz-property for its drawer information
Addressed by: https:/
Register Neutron Floating IP and Security Group names
Addressed by: https:/
WIP: Adding actions and views to Instance
Addressed by: https:/
Adding project name column to ng images
Addressed by: https:/
hz-
Addressed by: https:/
Allow listFunction extra params
Gerrit topic: https:/
Gerrit topic: https:/
Addressed by: https:/
Pass-through API for client side service calls