mirror of
https://github.com/nasa/openmct.git
synced 2024-12-23 06:52:24 +00:00
2310 lines
131 KiB
Markdown
2310 lines
131 KiB
Markdown
# Open MCT Web Developer Guide
|
||
Victor Woeltjen
|
||
|
||
[victor.woeltjen@nasa.gov](mailto:victor.woeltjen@nasa.gov)
|
||
|
||
September 23, 2015
|
||
Document Version 1.1
|
||
|
||
Date | Version | Summary of Changes | Author
|
||
------------------- | --------- | ----------------------- | ---------------
|
||
April 29, 2015 | 0 | Initial Draft | Victor Woeltjen
|
||
May 12, 2015 | 0.1 | | Victor Woeltjen
|
||
June 4, 2015 | 1.0 | Name Changes | Victor Woeltjen
|
||
September 23, 2015 | 1.1 | Conversion to MarkDown | Andrew Henry
|
||
|
||
# Contents
|
||
1. [Introduction](#Introduction)
|
||
1. [What is Open MCT Web?](#What-is-Open-MCT-Web-)
|
||
2. [Client-Server Relationship](#Client-Server-Relationship)
|
||
|
||
# Introduction
|
||
The purpose of this guide is to familiarize software developers with the Open
|
||
MCT Web platform.
|
||
|
||
## What is Open MCT Web?
|
||
Open MCT Web is a platform for building user interface and display tools,
|
||
developed at the NASA Ames Research Center in collaboration with teams at the
|
||
Jet Propulsion Laboratory. It is written in HTML5, CSS3, and JavaScript, using
|
||
[AngularJS](http://www.angularjs.org) as a framework. Its intended use is to
|
||
create singlepage web applications which integrate data and behavior from a
|
||
variety of sources and domains.
|
||
|
||
Open MCT Web has been developed to support the remote operation of space
|
||
vehicles, so some of its features are specific to that task; however, it is
|
||
flexible enough to be adapted to a variety of other application domains where a
|
||
display tool oriented toward browsing, composing, and visualizing would be
|
||
useful.
|
||
|
||
Open MCT Web provides:
|
||
|
||
* A common user interface paradigm which can be applied to a variety of domains
|
||
and tasks. Open MCT Web is more than a widget toolkit - it provides a standard
|
||
treeontheleft, viewontheright browsing environment which you customize by
|
||
adding new browsable object types, visualizations, and backend adapters.
|
||
* A plugin framework and an extensible API for introducing new application
|
||
features of a variety of types.
|
||
* A set of general-purpose object types and visualizations, as well as some
|
||
visualizations and infrastructure specific to telemetry display.
|
||
|
||
## Client-Server Relationship
|
||
Open MCT Web is client software - it runs entirely in the user’s web browser. As
|
||
such, it is largely “server agnostic”; any web server capable of serving files
|
||
from paths is capable of providing Open MCT Web.
|
||
|
||
While Open MCT Web can be configured to run as a standalone client, this is
|
||
rarely very useful. Instead, it is intended to be used as a display and
|
||
interaction layer for information obtained from a variety of backend services.
|
||
Doing so requires authoring or utilizing adapter plugins which allow Open MCT
|
||
Web to interact with these services.
|
||
|
||
Typically, the pattern here is to provide a known interface that Open MCT Web
|
||
can utilize, and implement it such that it interacts with whatever backend
|
||
provides the relevant information. Examples of backends that can be utilized in
|
||
this fashion include databases for the persistence of usercreated objects, or
|
||
sources of telemetry data.
|
||
|
||
See the [Architecture Guide](../architecture/index.md#Overview) for more details
|
||
on the client-server relationship.
|
||
|
||
## Developing with Open MCT Web
|
||
Building applications with Open MCT Web typically means authoring and utilizing
|
||
a set of plugins which provide applicationspecific details about how Open MCT
|
||
Web should behave.
|
||
|
||
### Technologies
|
||
|
||
Open MCT Web sources are written in JavaScript, with a number of configuration
|
||
files written in JSON. Displayable components are written in HTML5 and CSS3.
|
||
Open MCT Web is built using [AngularJS](http://www.angularjs.org) from Google. A
|
||
good understanding of Angular is recommended for developers working with Open
|
||
MCT Web.
|
||
|
||
### Forking
|
||
Open MCT Web does not currently have a single standalone artifact that can be
|
||
used as a library. Instead, the recommended approach for creating a new
|
||
application is to start by forking/branching Open MCT Web, and then adding new
|
||
features from there. Put another way, Open MCT Web’s source structure is built
|
||
to serve as a template for specific applications.
|
||
|
||
Forking in this manner should not require that you edit Open MCT Web’s sources.
|
||
The preferred approach is to create a new directory (peer to `index.html`)for
|
||
the new application, then add new bundles (as described in the Framework
|
||
chapter) within that directory.
|
||
|
||
To initially clone the Open MCT Web repository:
|
||
`git clone <repository URL> <local repo directory> b openmaster`
|
||
|
||
To create a fork to begin working on a new application using Open MCT Web:
|
||
|
||
cd <local repo directory>
|
||
git checkout openmaster
|
||
git checkout b <new branch name>
|
||
|
||
As a convention used internally, applications built using Open MCT Web have
|
||
master branch names with an identifying prefix. For instance, if building an
|
||
application called “Foo”, the last statement above would look like:
|
||
|
||
git checkout b foomaster
|
||
|
||
This convention is not enforced or understood by Open MCT Web in any way; it is
|
||
mentioned here as a more general recommendation.
|
||
|
||
# Overview
|
||
|
||
Open MCT Web is implemented as a framework component which manages a set of
|
||
other components. These components, called “bundles”, act as containers to group
|
||
sets of related functionality; individual units of functionality are expressed
|
||
within these bundles as "extensions."
|
||
|
||
Extensions declare dependencies on other extensions (either individually or
|
||
categorically), and the framework provides actual extension instances at
|
||
runtime to satisfy these declared dependency. This dependency injection
|
||
approach allows software components which have been authored separately (e.g. as
|
||
plugins) but to collaborate at runtime.
|
||
|
||
Open MCT Web’s framework layer is implemented on top of AngularJS’s [dependency
|
||
injection mechanism](https://docs.angularjs.org/guide/di) and is modelled after
|
||
[OSGi](hhttp://www.osgi.org/) and its [Declarative Services component model]
|
||
(http://wiki.osgi.org/wiki/Declarative_Services). In particular, this is where
|
||
the term "bundle" comes from.
|
||
|
||
## Framework Overview
|
||
|
||
The framework’s role in the application is to manage connections between
|
||
bundles. All applicationspecific behavior is provided by individual bundles, or
|
||
as the result of their collaboration.
|
||
|
||
ADD LINK TO DIAGRAM HERE
|
||
|
||
### Tiers
|
||
While all bundles in a running Open MCT Web instance are effectively peers, it
|
||
is useful to think of them as a tiered architecture, where each tier adds more
|
||
specificity to the application.
|
||
|
||
ADD LINK TO DIAGRAM HERE
|
||
|
||
* __Framework__ : This tier is responsible for wiring together the set of
|
||
configured components (called bundles) together to instantiate the running
|
||
application. It is responsible for mediating between AngularJS (in particular,
|
||
its dependency injection mechanism) and RequireJS (to load scripts at runtime.)
|
||
It additionally interprets bundle definitions (see explanation below, as well as
|
||
further detail in the Framework chapter.) At this tier, we are at our most
|
||
general: We know only that we are a pluginbased application.
|
||
* __Platform__: Components in the Platform tier describe both the general user
|
||
interface and corresponding developerfacing interfaces of Open MCT Web. This
|
||
tier provides the general infrastructure for applications. It is less general
|
||
than the framework tier, insofar as this tier introduces a specific user
|
||
interface paradigm, but it is still non-specific as to what useful features
|
||
will be provided. Although they can be removed or replaced easily, bundles
|
||
provided by the Platform tier generally should not be thought of as optional.
|
||
* __Application__: The application tier consists of components which utilize the
|
||
infrastructure provided by the Platform to provide functionality which will (or
|
||
could) be useful to specific applications built using Open MCT Web. These
|
||
include adapters to specific persistence backends (such as ElasticSearch or
|
||
CouchDB) as well as bundles which describe more userfacing features (such as
|
||
Plot views for visualizing time series data, or Layout objects for
|
||
displaybuilding.) Bundles from this tier can be added or removed without
|
||
compromising basic application functionality, with the caveat that at least one
|
||
persistence adapter needs to be present.
|
||
* __Plugins__: Conceptually, this tier is not so different from the application
|
||
tier; it consists of bundles describing new features, backend adapters, that
|
||
are specific to the application being built on Open MCT Web. It is described as
|
||
a separate tier here because it has one important distinction from the
|
||
application tier: It consists of bundles that are not included with the platform
|
||
(either authored anew for the specific application, or obtained from elsewhere.)
|
||
|
||
Note that bundles in any tier can go off and consult backend services. In
|
||
practice, this responsibility is handled at the Application and/or Plugin tiers;
|
||
Open MCT Web is built to be serveragnostic, so any backend is considered an
|
||
applicationspecific detail.
|
||
|
||
## Platform Overview
|
||
|
||
The "tiered" architecture described in the preceding text describes a way of
|
||
thinking of and categorizing software components of a Open MCT Web application,
|
||
as well as the framework layer’s role in mediating between these components.
|
||
Once the framework layer has wired these software components together, however,
|
||
the application’s logical architecture emerges.
|
||
|
||
### Logical Architecture
|
||
INSERT DIAGRAM HERE
|
||
|
||
* __Templates__: HTML templates written in Angular’s template syntax; see
|
||
the [Angular documentation on templates](https://docs.angularjs.org/guide/templates).
|
||
These describe the page as actually seen by the user. Conceptually, stylesheets
|
||
(controlling the lookandfeel of the rendered templates) belong in this
|
||
grouping as well.
|
||
* __Presentation__: Responsible for providing information to be displayed in
|
||
templates, and managing interactions with the information model. Provides the
|
||
logic and behavior of the user interface itself.
|
||
* __Information model__: Provides a common (within Open MCT Web) set of interfaces
|
||
for dealing with “things” domain objects within the system. Userfacing
|
||
concerns in a Open MCT Web application are expressed as domain objects; examples
|
||
include folders (used to organize other domain objects), layouts (used to build
|
||
displays), or telemetry points (used as handles for streams of remote
|
||
measurements.) These domain objects expose a common set of interfaces to allow
|
||
reusable user interfaces to be built in the presentation and template tiers; the
|
||
specifics of these behaviors are then mapped to interactions with underlying
|
||
services.
|
||
* __Services__: A set of interfaces for dealing with backend services.
|
||
* __Backend__: External to the Open MCT Web client; the underlying persistence
|
||
stores, telemetry streams, and so forth which the Open MCT Web client is being
|
||
used to interact with.
|
||
|
||
### Web Services
|
||
|
||
As mentioned in the Introduction, Open MCT Web is a platform singlepage
|
||
applications which runs entirely in the browser. Most applications will want to
|
||
additionally interact with serverside resources, to (for example) read
|
||
telemetry data or store usercreated objects. This interaction is handled by
|
||
individual bundles using APIs which are supported in browser (such as
|
||
`XMLHttpRequest`, typically wrapped by Angular’s '`$http`.)
|
||
|
||
INSERT DIAGRAM HERE
|
||
|
||
This architectural approach ensures a loose coupling between applications built
|
||
using Open MCT Web and the backends which support them.
|
||
|
||
### Glossary
|
||
|
||
Certain terms are used throughout Open MCT Web with consistent meanings or
|
||
conventions. Other developer documentation, particularly inline documentation,
|
||
may presume an understanding of these terms.
|
||
|
||
* __bundle__: A bundle is a removable, reusable grouping of software elements.
|
||
The application is composed of bundles. Plugins are bundles.
|
||
* __capability__: A JavaScript object which exposes dynamic behavior or
|
||
nonpersistent state associated with a domain object.
|
||
* __category__: A machinereadable identifier for a group that something may
|
||
belong to.
|
||
* __composition__: In the context of a domain object, this refers to the set of
|
||
other domain objects that compose or are contained by that object. A domain
|
||
object's composition is the set of domain objects that should appear immediately
|
||
beneath it in a tree hierarchy. A domain object's composition is described in
|
||
its model as an array of identifiers; its composition capability provides a
|
||
means to retrieve the actual domain object instances associated with these
|
||
identifiers asynchronously.
|
||
* __description__: When used as an object property, this refers to the human
|
||
readable description of a thing; usually a single sentence or short paragraph.
|
||
(Most often used in the context of extensions, domain object models, or other
|
||
similar applicationspecific objects.)
|
||
* __domain object__: A meaningful object to the user; a distinct thing in the
|
||
work support by Open MCT Web. Anything that appears in the lefthand tree is a
|
||
domain object.
|
||
* __extension__: An extension is a unit of functionality exposed to the platform
|
||
in a declarative fashion by a bundle. The term “extension category” is used to
|
||
distinguish types of extensions from specific extension instances.
|
||
* __id__: A string which uniquely identifies a domain object.
|
||
* __key__: When used as an object property, this refers to the machinereadable
|
||
identifier for a specific thing in a set of things. (Most often used in the
|
||
context of extensions or other similar applicationspecific object sets.) This
|
||
term is chosen to avoid attaching ambiguous meanings to “id”.
|
||
* __model__: The persistent state associated with a domain object. A domain
|
||
object's model is a JavaScript object which can be converted to JSON without
|
||
losing information (that is, it contains no methods.)
|
||
* __name__: When used as an object property, this refers to the humanreadable
|
||
name for a thing. (Most often used in the context of extensions, domain object
|
||
models, or other similar applicationspecific objects.)
|
||
* __navigation__: Refers to the current state of the application with respect to
|
||
the user's expressed interest in a specific domain object; e.g. when a user
|
||
clicks on a domain object in the tree, they are navigating to it, and it is
|
||
thereafter considered the navigated object (until the user makes another such
|
||
choice.) This term is used to distinguish navigation from selection, which
|
||
occurs in an editing context.
|
||
* __space__: A machinereadable name used to identify a persistence store.
|
||
Interactions with persistence with generally involve a space parameter in some
|
||
form, to distinguish multiple persistence stores from one another (for cases
|
||
where there are multiple valid persistence locations available.)
|
||
* __source__: A machinereadable name used to identify a source of telemetry
|
||
data. Similar to "space", this allows multiple telemetry sources to operate
|
||
sidebyside without conflicting.
|
||
|
||
# Framework
|
||
|
||
Open MCT Web is built on the [AngularJS framework](http://www.angularjs.org). A
|
||
good understanding of that framework is recommended.
|
||
|
||
Open MCT Web adds an extra layer on top of AngularJS to (a) generalize its
|
||
dependency injection mechanism slightly, particularly to handle manytoone
|
||
relationships; and (b) handle script loading. Combined, these features become a
|
||
plugin mechanism.
|
||
|
||
This framework layer operates on two key concepts:
|
||
|
||
* __Bundle:__ A bundle is a collection of related functionality that can be
|
||
added to the application as a group. More concretely, a bundle is a directory
|
||
containing a JSON file declaring its contents, as well as JavaScript sources,
|
||
HTML templates, and other resources used to support that functionality. (The
|
||
term bundle is borrowed from [OSGi](http://www.osgi.org/) which has also
|
||
inspired many of the concepts used in the framework layer. A familiarity with
|
||
OSGi, particularly Declarative Services, may be useful when working with Open
|
||
MCT Web.)
|
||
* __Extension:__ An extension is an individual unit of functionality. Extensions
|
||
are collected together in bundles, and may interact with other extensions.
|
||
|
||
The framework layer, loaded and initiated from `index.html`, is the main point
|
||
of entry for an application built on Open MCT Web. It is responsible for wiring
|
||
together the application at run time (much of this responsibility is actually
|
||
delegated to Angular); at a highlevel, the framework does this by proceeding
|
||
through four stages:
|
||
|
||
1. __Loading definitions:__ JSON declarations are loaded for all bundles which
|
||
will constitute the application, and wrapped in a useful API for subsequent
|
||
stages.
|
||
2. __Resolving extensions:__ Any scripts which provide implementations for
|
||
extensions exposed by bundles are loaded, using Require.
|
||
3. __Registering extensions__ Resolved extensions are registered with Angular,
|
||
such that they can be used by the application at runtime. This stage includes
|
||
both registration of Angular builtins (directives, controllers, routes,
|
||
constants, and services) as well as registration of nonAngular extensions.
|
||
4. __Bootstrapping__ The Angular application is bootstrapped; at that point,
|
||
Angular takes over and populates the body of the page using the extensions that
|
||
have been registered.
|
||
|
||
## Bundles
|
||
|
||
The basic configurable unit of Open MCT Web is the bundle. This term has been
|
||
used a bit already; now we’ll get to a more formal definition.
|
||
|
||
A bundle is a directory which contains:
|
||
|
||
* A bundle definition; a file named `bundle.json`.
|
||
* Subdirectories for sources, resources, and tests.
|
||
* Optionally, a `README.md` Markdown file describing its contents (this is not
|
||
used by Open MCT Web in any way, but it’s a helpful convention to follow.)
|
||
|
||
The bundle definition is the main point of entry for the bundle. The framework
|
||
looks at this to determine which components need to be loaded and how they
|
||
interact.
|
||
|
||
A plugin in Open MCT Web is a bundle. The platform itself is also decomposed
|
||
into bundles, each of which provides some category of functionality. The
|
||
difference between a _bundle_ and a _plugin_ is purely a matter of the intended
|
||
use; a plugin is just a bundle that is meant to be easily added or removed. When
|
||
developing, it is typically more useful to think in terms of bundles.
|
||
|
||
### Configuring Active Bundles
|
||
|
||
To decide which bundles should be loaded, the framework loads a file named
|
||
`bundles.json` (peer to the `index.html` file which serves the application) to
|
||
determine which bundles should be loaded. This file should contain a single JSON
|
||
array of strings, where each is the path to a bundle. These paths should not
|
||
include bundle.json (this is implicit) or a trailing slash.
|
||
|
||
For instance, if `bundles.json` contained:
|
||
|
||
[
|
||
"example/builtins",
|
||
"example/extensions"
|
||
]
|
||
|
||
...then the Open MCT Web framework would look for bundle definitions at
|
||
`example/builtins/bundle.json` and `example/extensions/bundle.json`, relative
|
||
to the path of `index.html`. No other bundles would be loaded.
|
||
|
||
### Bundle Definition
|
||
|
||
A bundle definition (the `bundle.json` file located within a bundle) contains a
|
||
description of the bundle itself, as well as the information exposed by the
|
||
bundle.
|
||
|
||
This definition is expressed as a single JSON object with the following
|
||
properties (all of which are optional, falling back to reasonable defaults):
|
||
|
||
* `key`: A machinereadable name for the bundle. (Currently used only in
|
||
logging.)
|
||
* `name`: A humanreadable name for the bundle. (Also only used in logging.)
|
||
* `sources`: Names a directory in which source scripts (which will implement
|
||
extensions) are located. Defaults to “src”
|
||
* `resources`: Names a directory in which resource files (such as HTML templates,
|
||
images, CS files, and other nonJavaScript files needed by this bundle) are
|
||
located. Defaults to “res”
|
||
* `libraries`: Names a directory in which thirdparty libraries are located.
|
||
Defaults to “lib”
|
||
* `configuration`: A bundle’s configuration object, which should be formatted as
|
||
would be passed to require.config (see [RequireJS documentation](http://requirejs.org/docs/api.html) );
|
||
note that only paths and shim have been tested.
|
||
* `extensions`: An object containing keyvalue pairs, where keys are extension
|
||
categories, and values are extension definitions. See the section on Extensions
|
||
for more information.
|
||
|
||
For example, the bundle definition for example/policy looks like:
|
||
|
||
{
|
||
"name": "Example Policy",
|
||
"description": "Provides an example of using policies.",
|
||
"sources": "src",
|
||
"extensions": {
|
||
"policies": [
|
||
{
|
||
"implementation": "ExamplePolicy.js",
|
||
"category": "action"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
|
||
### Bundle Directory Structure
|
||
|
||
In addition to the directories defined in the bundle definition, a bundle will
|
||
typically contain other directories not used at runtime. Additionally, some
|
||
useful development scripts (such as the command line build and the test suite)
|
||
expect this directory structure to be in use, and may ignore options chosen by
|
||
`bundle.json`. It is recommended that the directory structure described below be
|
||
used for new bundles.
|
||
|
||
* `src`: Contains JavaScript sources for this bundle. May contain additional
|
||
subdirectories to organize these sources; typically, these subdirectories are
|
||
named to correspond to the extension categories they contain and/or support, but
|
||
this is only a convention.
|
||
* `res`: Contains other files needed by this bundle, such as HTML templates. May
|
||
contain additional subdirectories to organize these sources.
|
||
* `lib`: Contains JavaScript sources from thirdparty libraries. These are
|
||
separated from bundle sources in order to ignore them during code style checking
|
||
from the command line build.
|
||
* `test`: Contains JavaScript sources implementing [Jasmine](http://jasmine.github.io/)
|
||
tests, as well as a file named `suite.json` describing which files to test.
|
||
Should have the same folder structure as the `src` directory; see the section on
|
||
automated testing for more information.
|
||
|
||
For example, the directory structure for bundle `platform/commonUI/about` looks
|
||
like:
|
||
|
||
INSERT DIAGRAM HERE
|
||
|
||
## Extensions
|
||
|
||
While bundles provide groupings of related behaviors, the individual units of
|
||
behavior are called extensions.
|
||
|
||
Extensions belong to categories; an extension category is the machinereadable
|
||
identifier used to identify groups of extensions. In the `extensions` property
|
||
of a bundle definition, the keys are extension categories and the values are
|
||
arrays of extension definitions.
|
||
|
||
### General Extensions
|
||
|
||
Extensions are intended as a generalpurpose mechanism for adding new types of
|
||
functionality to Open MCT Web.
|
||
|
||
An extension category is registered with Angular under the name of the
|
||
extension, plus a suffix of two square brackets; so, an Angular service (or,
|
||
generally, any other extension) can access the full set of registered
|
||
extensions, from all bundles, by including this string (e.g. `types[]` to get
|
||
all type definitions) in a dependency declaration.
|
||
|
||
As a convention, extension categories are given singleword, plural nouns for
|
||
names within Open MCT Web (e.g. `types`.) This convention is not enforced by the
|
||
platform in any way. For extension categories introduced by external plugins, it
|
||
is recommended to prefix the extension category with a vendor identifier (or
|
||
similar) followed by a dot, to avoid collisions.
|
||
|
||
### Extension Definitions
|
||
|
||
The properties used in extension definitions are typically unique to each
|
||
category of extension; a few properties have standard interpretations by the
|
||
platform.
|
||
|
||
* `implementation`: Identifies a JavaScript source file (in the sources
|
||
folder) which implements this extension. This JavaScript file is expected to
|
||
contain an AMD module (see http://requirejs.org/docs/whyamd.html#amd) which
|
||
gives as its result a single constructor function.
|
||
* `depends`: An array of dependencies needed by this extension; these will be
|
||
passed on to Angular’s [dependency injector](https://docs.angularjs.org/guide/di).
|
||
By default, this is treated as an empty array. Note that depends does not make
|
||
sense without `implementation` (since these dependencies will be passed to the
|
||
implementation when it is instantiated.)
|
||
* `priority`: A number or string indicating the priority order (see below) of
|
||
this extension instance. Before an extension category is registered with
|
||
AngularJS, the extensions of this category from all bundles will be concatenated
|
||
into a single array, and then sorted by priority.
|
||
|
||
Extensions do not need to have an implementation. If no implementation is
|
||
provided, consumers of the extension category will receive the extension
|
||
definition as a plain JavaScript object. Otherwise, they will receive the
|
||
partialized (see below) constructor for that implementation, which will
|
||
additionally have all properties from the extension definition attached.
|
||
|
||
#### Partial Construction
|
||
|
||
In general, extensions are intended to be implemented as constructor functions,
|
||
which will be used elsewhere to instantiate new objects of that type. However,
|
||
the Angularsupported method for dependency injection is (effectively)
|
||
constructorstyle injection; so, both declared dependencies and runtime
|
||
arguments are competing for space in a constructor’s arguments.
|
||
|
||
To resolve this, the Open MCT Web framework registers extension instances in a
|
||
partially constructed form. That is, the constructor exposed by the extension’s
|
||
implementation is effectively decomposed into two calls; the first takes the
|
||
dependencies, and returns the constructor in its second form, which takes the
|
||
remaining arguments.
|
||
|
||
This means that, when writing implementations, the constructor function should
|
||
be written to include all declared dependencies, followed by all runtime
|
||
arguments. When using extensions, only the runtime arguments need to be
|
||
provided.
|
||
|
||
#### Priority
|
||
|
||
Within each extension category, registration occurs in priority order. An
|
||
extension's priority may be specified as a `priority` property in its extension
|
||
definition; this may be a number, or a symbolic string. Extensions are
|
||
registered in reverse order (highestpriority first), and symbolic strings are
|
||
mapped to the numeric values as follows:
|
||
|
||
* `fallback`: Negative infinity. Used for extensions that are not intended for
|
||
use (that is, they are meant to be overridden) but are present as an option of
|
||
last resort.
|
||
* `default`: 100. Used for extensions that are expected to be overridden, but
|
||
need a useful default.
|
||
* `none`: 0. Also used if no priority is specified, or if an unknown or
|
||
malformed priority is specified.
|
||
* `optional`: 100. Used for extensions that are meant to be used, but may be
|
||
overridden.
|
||
* `preferred`: 1000. Used for extensions that are specifically intended to be
|
||
used, but still may be overridden in principle.
|
||
* `mandatory`: Positive infinity. Used when an extension should definitely not
|
||
be overridden.
|
||
|
||
These symbolic names are chosen to support usage where many extensions may
|
||
satisfy a given need, but only one may be used; in this case, as a convention it
|
||
should be the lowestordered (highestpriority) extensions available. In other
|
||
cases, a full set (or multielement subset) of extensions may be desired, with a
|
||
specific ordering; in these cases, it is preferable to specify priority
|
||
numerically when declaring extensions, and to understand that extensions will be
|
||
sorted according to these conventions when using them.
|
||
|
||
### Angular Built-ins
|
||
|
||
Several entities supported Angular are expressed and managed as extensions in
|
||
Open MCT Web. Specifically, these extension categories are _directives_,
|
||
_controllers_, _services_, _constants_, _runs_, and _routes_.
|
||
|
||
#### Angular Directives
|
||
|
||
New [directives](https://docs.angularjs.org/guide/directive) may be
|
||
registered as extensions of the directives category. Implementations of
|
||
directives in this category should take only dependencies as arguments, and
|
||
should return a directive definition object.
|
||
|
||
The directive’s name should be provided as a key property of its extension
|
||
definition, in camelcase format.
|
||
|
||
#### Angular Controllers
|
||
|
||
New [controllers](https://docs.angularjs.org/guide/controller) may be registered
|
||
as extensions of the controllers category. The implementation is registered
|
||
directly as the controller; its only constructor arguments are its declared
|
||
dependencies.
|
||
|
||
The directive’s identifier should be provided as a key property of its extension
|
||
definition.
|
||
|
||
|
||
#### Angular Services
|
||
|
||
New [services](https://docs.angularjs.org/guide/services) may be registered as
|
||
extensions of the services category. The implementation is registered via a
|
||
[service call](https://docs.angularjs.org/api/auto/service/$provide#service), so
|
||
it will be instantiated with the new operator.
|
||
|
||
#### Angular Constants
|
||
|
||
Constant values may be registered as extensions of the [constants category](https://docs.angularjs.org/api/ng/type/angular.Module#constant).
|
||
These extensions have no implementation; instead, they should contain a property
|
||
key, which is the name under which the constant will be registered, and a
|
||
property value, which is the constant value that will be registered.
|
||
|
||
#### Angular Runs
|
||
|
||
In some cases, you want to register code to run as soon as the application
|
||
starts; these can be registered as extensions of the [runs category](https://docs.angularjs.org/api/ng/type/angular.Module#run).
|
||
Implementations registered in this category will be invoked (with their declared
|
||
dependencies) when the Open MCT Web application first starts. (Note that, in
|
||
this case, the implementation is better thought of as just a function, as
|
||
opposed to a constructor function.)
|
||
|
||
#### Angular Routes
|
||
|
||
Extensions of category `routes` will be registered with Angular’s [route provider](https://docs.angularjs.org/api/ngRoute/provider/$routeProvider).
|
||
Extensions of this category have no implementations, and need only two
|
||
properties in their definition:
|
||
|
||
* `when`: The value that will be passed as the path argument to
|
||
`$routeProvider.when`; specifically, the string that will appear in the trailing
|
||
part of the URL corresponding to this route. This property may be omitted, in
|
||
which case this extension instance will be treated as the default route.
|
||
* `templateUrl`: A path to the template to render for this route. Specified as a
|
||
path relative to the bundle’s resource directory (`res` by default.)
|
||
|
||
### Composite Services
|
||
|
||
Composite services are described in the [relevant section](../architecture/Framework.md#Composite-Services)
|
||
of the framework guide.
|
||
|
||
A component should include the following properties in its extension definition:
|
||
|
||
* `provides`: The symbolic identifier for the service that will be composed. The
|
||
fullycomposed service will be registered with Angular under this name.
|
||
* `type`: One of `provider`, `aggregator`, or `decorator` (as above)
|
||
|
||
In addition to any declared dependencies, _aggregators_ and _decorators_ both
|
||
receive one more argument (immediately following declared dependencies) that is
|
||
provided by the framework. For an aggregator, this will be an array of all
|
||
providers of the same service (that is, with matching `provides` properties);
|
||
for a decorator, this will be whichever provider, decorator, or aggregator is
|
||
next in the sequence of decorators.
|
||
|
||
Services exposed by the Open MCT Web platform are often declared as composite
|
||
services, as this form is open for a variety of common modifications.
|
||
|
||
# Core API
|
||
|
||
Most of Open MCT Web’s relevant API is provided and/or mediated by the
|
||
framework; that is, much of developing for Open MCT Web is a matter of adding
|
||
extensions which access other parts of the platform by means of dependency
|
||
injection.
|
||
|
||
The core bundle (`platform/core`) introduces a few additional object types meant
|
||
to be passed along by other services.
|
||
|
||
## Domain Objects
|
||
|
||
Domain objects are the most fundamental component of Open MCT Web’s information
|
||
model. A domain object is some distinct thing relevant to a user’s work flow,
|
||
such as a telemetry channel, display, or similar. Open MCT Web is a tool for
|
||
viewing, browsing, manipulating, and otherwise interacting with a graph of
|
||
domain objects.
|
||
|
||
A domain object should be conceived of as the union of the following:
|
||
|
||
* __Identifier__: A machinereadable string that uniquely identifies the domain
|
||
object within this application instance.
|
||
* __Model__: The persistent state of the domain object. A domain object’s model
|
||
is a JavaScript object that can be losslessly converted to JSON.
|
||
* __Capabilities__: Dynamic behavior associated with the domain object.
|
||
Capabilities are JavaScript objects which provide additional methods for
|
||
interacting with the domain objects which expose those capabilities. Not all
|
||
domain objects expose all capabilities.
|
||
|
||
At runtime, a domain object has the following interface:
|
||
|
||
* `getId()`: Get the identifier for this domain object.
|
||
* `getModel()`: Get the plain state associated with this domain object. This
|
||
will return a JavaScript object that can be losslessly converted to JSON. Note
|
||
that the model returned here can be modified directly but should not be;
|
||
instead, use the mutation capability.
|
||
* `getCapability(key)`: Get the specified capability associated with this domain
|
||
object. This will return a JavaScript object whose interface is specific to the
|
||
type of capability being requested. If the requested capability is not exposed
|
||
by this domain object, this will return undefined.
|
||
* `hasCapability(key)`: Shorthand for checking if a domain object exposes the
|
||
requested capability.
|
||
* `useCapability(key, arguments…)`: Shorthand for
|
||
`getCapability(key).invoke(arguments)`, with additional checking between calls.
|
||
If the provided capability has no invoke method, the return value here functions
|
||
as `getCapability`, including returning `undefined` if the capability is not
|
||
exposed.
|
||
|
||
## Actions
|
||
|
||
An `Action` is behavior that can be performed upon/using a `DomainObject`. An
|
||
Action has the following interface:
|
||
|
||
* `perform()`: Do this action. For example, if one had an instance of a
|
||
`RemoveAction`, invoking its perform method would cause the domain object which
|
||
exposed it to be removed from its container.
|
||
* `getMetadata()`: Get metadata associated with this action. Returns an object
|
||
containing:
|
||
* `name`: Humanreadable name.
|
||
* `description`: Humanreadable summary of this action.
|
||
* `glyph`: Single character to be displayed in Open MCT Web’s icon font set.
|
||
* `context`: The context in which this action is being performed (see below)
|
||
|
||
Action instances are typically obtained via a domain object’s `action`
|
||
capability.
|
||
|
||
### Action Contexts
|
||
|
||
An action context is a JavaScript object with the following properties:
|
||
|
||
* `domainObject`: The domain object being acted upon.
|
||
* `selectedObject`: Optional; the selection at the time of action (e.g. the
|
||
dragged object in a draganddrop operation.)
|
||
|
||
## Telemetry
|
||
|
||
Telemetry series data in Open MCT Web is represented by a common interface, and
|
||
packaged in a consistent manner to facilitate passing telemetry updates around
|
||
multiple visualizations.
|
||
|
||
### Telemetry Requests
|
||
|
||
A telemetry request is a JavaScript object containing the following properties:
|
||
|
||
* `source`: A machinereadable identifier for the source of this telemetry. This
|
||
is useful when multiple distinct data sources are in use sidebyside.
|
||
* `key`: A machinereadable identifier for a unique series of telemetry within
|
||
that source.
|
||
* _Note: This API is still under development; additional properties, such as
|
||
start and end time, should be present in future versions of Open MCT Web._
|
||
|
||
Additional properties may be included in telemetry requests which have specific
|
||
interpretations for specific sources.
|
||
|
||
### Telemetry Responses
|
||
|
||
When returned from the `telemetryService` (see [Services](#Services) section),
|
||
telemetry series data will be packaged in a `source > key > TelemetrySeries`
|
||
fashion. That is, telemetry is passed in an object containing keyvalue pairs.
|
||
Keys identify telemetry sources; values are objects containing additional
|
||
keyvalue pairs. In this object, keys identify individual telemetry series (and
|
||
match they `key` property from corresponding requests) and values are
|
||
`TelemetrySeries` objects (see below.)
|
||
|
||
### Telemetry Series
|
||
|
||
A telemetry series is a specific sequence of data, typically associated with a
|
||
specific instrument. Telemetry is modeled as an ordered sequence of domain and
|
||
range values, where domain values must be nondecreasing but range values do
|
||
not. (Typically, domain values are interpreted as UTC timestamps in milliseconds
|
||
relative to the UNIX epoch.) A series must have at least one domain and one
|
||
range, and may have more than one.
|
||
|
||
Telemetry series data in Open MCT Web is expressed via the following
|
||
`TelemetrySeries` interface:
|
||
|
||
* `getPointCount()`: Returns the number of unique points/samples in this series.
|
||
* `getDomainValue(index, [domain])`: Get the domain value at the specified index.
|
||
If a second domain argument is provided, this is taken as a string identifier
|
||
indicating which domain option (of, presumably, multiple) should be returned.
|
||
* `getRangeValue(index, [range])`: Get the domain value at the specified index.
|
||
If a second range argument is provided, this is taken as a string identifier
|
||
indicating which range option (of, presumably, multiple) should be returned.
|
||
|
||
### Telemetry Metadata
|
||
|
||
Domain objects which have associated telemetry also expose metadata about that
|
||
telemetry; this is retrievable via the `getMetadata()` of the telemetry
|
||
capability. This will return a single JavaScript object containing the following
|
||
properties:
|
||
|
||
* `source`: The machinereadable identifier for the source of telemetry data for
|
||
this object.
|
||
* `key`: The machinereadable identifier for the individual telemetry series.
|
||
* `domains`: An array of supported domains (see TelemetrySeries above.) Each
|
||
domain should be expressed as an object which includes:
|
||
* `key`: Machinereadable identifier for this domain, as will be passed
|
||
into a getDomainValue(index, domain) call.
|
||
* `name`: Humanreadable name for this domain.
|
||
* `ranges`: An array of supported ranges; same format as domains.
|
||
|
||
Note that this metadata is also used as the prototype for telemetry requests
|
||
made using this capability.
|
||
|
||
## Types
|
||
A domain object’s type is represented as a Type object, which has the following
|
||
interface:
|
||
* `getKey()`: Get the machinereadable identifier for this type.
|
||
* `getName()`: Get the humanreadable name for this type.
|
||
* `getDescription()`: Get a humanreadable summary of this type.
|
||
* `getGlyph()`: Get the single character to be rendered as an icon for this type
|
||
in Open MCT Web’s custom font set.
|
||
* `getInitialModel()`: Get a domain object model that represents the initial
|
||
state (before user specification of properties) for domain objects of this type.
|
||
* `getDefinition()`: Get the extension definition for this type, as a JavaScript
|
||
object.
|
||
* `instanceOf(type)`: Check if this type is (or inherits from) a specified type.
|
||
This type can be either a string, in which case it is taken to be that type’s
|
||
key, or it may be a Type instance.
|
||
* `hasFeature(feature)`: Returns a boolean value indicating whether or not this
|
||
type supports the specified feature, which is a symbolic string.
|
||
* `getProperties()`: Get all properties associated with this type, expressed as
|
||
an array of TypeProperty instances.
|
||
|
||
### Type Features
|
||
|
||
Features of a domain object type are expressed as symbolic string identifiers.
|
||
They are defined in practice by usage; currently, the Open MCT Web platform only
|
||
uses the creation feature to determine which domain object types should appear
|
||
in the Create menu.
|
||
|
||
### Type Properties
|
||
|
||
Types declare the usereditable properties of their domain object instances in
|
||
order to allow the forms which appear in the Create and Edit Properties dialogs
|
||
to be generated by the platform. A TypeProperty has the following interface:
|
||
|
||
* `getValue(model)`: Get the current value for this property, as it appears in
|
||
the provided domain object model.
|
||
* `setValue(model, value)`: Set a new value for this property in the provided
|
||
domain object model.
|
||
* `getDefinition()`: Get the raw definition for this property as a JavaScript
|
||
object (as it was declared in this type’s extension definition.)
|
||
|
||
#Extension Categories
|
||
|
||
The information in this section is focused on registering new extensions of
|
||
specific types; it does not contain a catalog of the extension instances of
|
||
these categories provided by the platform. Relevant summaries there are provided
|
||
in subsequent sections.
|
||
|
||
## Actions
|
||
|
||
An action is a thing that can be done to or using a domain object, typically as
|
||
initiated by the user.
|
||
|
||
An action’s implementation:
|
||
|
||
* Should take a single `context` argument in its constructor. (See Action
|
||
Contexts, under Core API.)
|
||
* Should provide a method `perform`, which causes the behavior associated with
|
||
the action to occur.
|
||
* May provide a method `getMetadata`, which provides metadata associated with
|
||
the action. If omitted, one will be provided by the platform which includes
|
||
metadata from the action’s extension definition.
|
||
* May provide a static method `appliesTo(context)` (that is, a function
|
||
available as a property of the implementation’s constructor itself), which will
|
||
be used by the platform to filter out actions from contexts in which they are
|
||
inherently inapplicable.
|
||
|
||
An action’s bundle definition (and/or `getMetadata()` return value) may include:
|
||
|
||
* `category`: A string or dearray of strings identifying which category or
|
||
categories an action falls into; used to determine when an action is displayed.
|
||
Categories supported by the platform include:
|
||
* `contextual`: Actions in a context menu.
|
||
* `viewcontrol`: Actions triggered by buttons in the topright of Browse
|
||
view.
|
||
* `key`: A machinereadable identifier for this action.
|
||
* `name`: A humanreadable name for this action (e.g. to show in a menu)
|
||
* `description`: A humanreadable summary of the behavior of this action.
|
||
* `glyph`: A single character which will be rendered in Open MCT Web’s custom
|
||
font set as an icon for this action.
|
||
|
||
## Capabilities
|
||
|
||
Capabilities are exposed by domain objects (e.g. via the `getCapability` method)
|
||
but most commonly originate as extensions of this category.
|
||
|
||
Extension definitions for capabilities should include both an implementation,
|
||
and a property named key whose value should be a string used as a
|
||
machinereadable identifier for that capability, e.g. when passed as the
|
||
argument to a domain object’s `getCapability(key)` call.
|
||
|
||
A capability’s implementation should have methods specific to that capability;
|
||
that is, there is no common format for capability implementations, aside from
|
||
support for invoke via the useCapability shorthand.
|
||
|
||
A capability’s implementation will take a single argument (in addition to any
|
||
declared dependencies), which is the domain object that will expose that
|
||
capability.
|
||
|
||
A capability’s implementation may also expose a static method `appliesTo(model)`
|
||
which should return a boolean value, and will be used by the platform to filter
|
||
down capabilities to those which should be exposed by specific domain objects,
|
||
based on their domain object models.
|
||
|
||
## Controls
|
||
|
||
Controls provide options for the mctcontrol directive.
|
||
|
||
Six standard control types are included in the forms bundle:
|
||
|
||
* `textfield`: An area to enter plain text.
|
||
* `select`: A dropdown list of options.
|
||
* `checkbox`: A box which may be checked/unchecked.
|
||
* `color`: A color picker.
|
||
* `button`: A button.
|
||
* `datetime`: An input for UTC date/time entry; gives result as a UNIX
|
||
timestamp, in milliseconds since start of 1970, UTC.
|
||
|
||
New controls may be added as extensions of the controls category. Extensions of
|
||
this category have two properties:
|
||
|
||
* `key`: The symbolic name for this control (matched against the control field
|
||
in rows of the form structure).
|
||
* `templateUrl`: The URL to the control's Angular template, relative to the
|
||
resources directory of the bundle which exposes the extension.
|
||
|
||
Within the template for a control, the following variables will be included in
|
||
scope:
|
||
|
||
* `ngModel`: The model where form input will be stored. Notably we also need to
|
||
look at field (see below) to determine which field in the model should be
|
||
modified.
|
||
* `ngRequired`: True if input is required.
|
||
* `ngPattern`: The pattern to match against (for text entry.)
|
||
* `options`: The options for this control, as passed from the `options` property
|
||
of an individual row definition.
|
||
* `field`: Name of the field in `ngModel` which will hold the value for this
|
||
control.
|
||
|
||
## Gestures
|
||
|
||
A gesture is a user action which can be taken upon a representation of a domain
|
||
object.
|
||
|
||
Examples of gestures included in the platform are:
|
||
|
||
* `drag`: For representations that can be used to initiate draganddrop
|
||
composition.
|
||
* `drop`: For representations that can be drop targets for draganddrop
|
||
composition.
|
||
* `menu`: For representations that can be used to pop up a context menu.
|
||
|
||
Gesture definitions have a property `key` which is used as a machinereadable
|
||
identifier for the gesture (e.g. `drag`, `drop`, `menu` above.)
|
||
|
||
A gesture’s implementation is instantiated once per representation that uses the
|
||
gesture. This class will receive the jqLitewrapped `mctrepresentation` element
|
||
and the domain object being represented as arguments, and should do any
|
||
necessary "wiring" (e.g. listening for events) during its constructor call. The
|
||
gesture’s implementation may also expose an optional destroy() method which will
|
||
be called when the gesture should be removed, to avoid memory leaks by way of
|
||
unremoved listeners.
|
||
|
||
## Indicators
|
||
|
||
An indicator is an element that should appear in the status area at the bottom
|
||
of a running Open MCT Web client instance.
|
||
|
||
### Standard Indicators
|
||
|
||
Indicators which wish to appear in the common form of an icontext pair should
|
||
provide implementations with the following methods:
|
||
|
||
* `getText()`: Provides the humanreadable text that will be displayed for this
|
||
indicator.
|
||
* `getGlyph()`: Provides a singlecharacter string that will be displayed as an
|
||
icon in Open MCT Web’s custom font set.
|
||
* `getDescription()`: Provides a humanreadable summary of the current state of
|
||
this indicator; will be displayed in a tooltip on hover.
|
||
* `getClass()`: Get a CSS class that will be applied to this indicator.
|
||
* `getTextClass()`: Get a CSS class that will be applied to this indicator’s
|
||
text portion.
|
||
* `getGlyphClass()`: Get a CSS class that will be applied to this indicator’s
|
||
icon portion.
|
||
* `configure()`: If present, a configuration icon will appear to the right of
|
||
this indicator, and clicking it will invoke this method.
|
||
|
||
Note that all methods are optional, and are called directly from an Angular
|
||
template, so they should be appropriate to run during digest cycles.
|
||
|
||
### Custom Indicators
|
||
|
||
Indicators which wish to have an arbitrary appearance (instead of following the
|
||
icontext convention commonly used) may specify a `template` property in their
|
||
extension definition. The value of this property will be used as the `key` for
|
||
an `mctinclude` directive (so should refer to an extension of category
|
||
templates.) This template will be rendered to the status area. Indicators of
|
||
this variety do not need to provide an implementation.
|
||
|
||
## Licenses
|
||
|
||
The extension category `licenses` can be used to add entries into the “Licensing
|
||
information” page, reachable from Open MCT Web’s About dialog.
|
||
|
||
Licenses may have the following properties, all of which are strings:
|
||
|
||
* `name`: Humanreadable name of the licensed component. (e.g. “AngularJS”.)
|
||
* `version`: Humanreadable version of the licensed component. (e.g. “1.2.26”.)
|
||
* `description`: Humanreadable summary of the component.
|
||
* `author`: Name or names of entities to which authorship should be attributed.
|
||
* `copyright`: Copyright text to display for this component.
|
||
* `link`: URL to full license text.
|
||
|
||
## Policies
|
||
|
||
Policies are used to handle decisions made using Open MCT Web’s `policyService`;
|
||
examples of these decisions are determining the applicability of certain
|
||
actions, or checking whether or not a domain object of one type can contain a
|
||
domain object of a different type. See the section on the Policies for an
|
||
overview of Open MCT Web’s policy model.
|
||
|
||
A policy’s extension definition should include:
|
||
|
||
* `category`: The machinereadable identifier for the type of policy decision
|
||
being supported here. For a list of categories supported by the platform, see
|
||
the section on Policies. Plugins may introduce and utilize additional policy
|
||
categories not in that list.
|
||
* `message`: Optional; a humanreadable message describing the policy, intended
|
||
for display in situations where this specific policy has disallowed something.
|
||
|
||
A policy’s implementation should include a single method, `allow(candidate,
|
||
context)`. The specific types used for `candidate` and `context` vary by policy
|
||
category; in general, what is being asked is “is this candidate allowed in this
|
||
context?” This method should return a boolean value.
|
||
|
||
Open MCT Web’s policy model requires consensus; a policy decision is allowed
|
||
when and only when all policies choose to allow it. As such, policies should
|
||
generally be written to reject a certain case, and allow (by returning `true`)
|
||
anything else.
|
||
|
||
## Representations
|
||
|
||
A representation is an Angular template used to display a domain object. The
|
||
`representations` extension category is used to add options for the
|
||
`mctrepresentation` directive.
|
||
|
||
A representation definition should include the following properties:
|
||
|
||
* `key`: The machinereadable name which identifies the representation.
|
||
* `templateUrl`: The path to the representation's Angular template. This path is
|
||
relative to the bundle's resources directory.
|
||
* `uses`: Optional; an array of capability names. Indicates that this
|
||
representation intends to use those capabilities of a domain object (via a
|
||
`useCapability` call), and expects to find the latest results of that
|
||
`useCapability` call in the scope of the presented template (under the same name
|
||
as the capability itself.) Note that, if `useCapability` returns a promise, this
|
||
will be resolved before being placed in the representation’s scope.
|
||
* `gestures`: An array of keys identifying gestures (see the `gestures`
|
||
extension category) which should be available upon this representation. Examples
|
||
of gestures include `drag` (for representations that should act as draggable
|
||
sources for dragdrop operations) and `menu` (for representations which should
|
||
show a domainobjectspecific context menu on rightclick.)
|
||
|
||
### Representation Scope
|
||
|
||
While _representations_ do not have implementations, per se, they do refer to
|
||
Angular templates which need to interact with information (e.g. the domain
|
||
object being represented) provided by the platform. This information is passed
|
||
in through the template’s scope, such that simple representations may be created
|
||
by providing only templates. (More complex representations will need controllers
|
||
which are referenced from templates. See [https://docs.angularjs.org/guide/controller]()
|
||
for more information on controllers in Angular.)
|
||
|
||
A representation’s scope will contain:
|
||
* `domainObject`: The represented domain object.
|
||
* `model`: The domain object’s model.
|
||
* `configuration`: An object containing configuration information for this
|
||
representation (an empty object if there is no saved configuration.) The
|
||
contents of this object are managed entirely by the view/representation which
|
||
receives it.
|
||
* `representation`: An empty object, useful as a “scratch pad” for
|
||
representation state.
|
||
* `ngModel`: An object passed through the ngmodel attribute of the
|
||
mctrepresentation, if any.
|
||
* `parameters`: An object passed through the parameters attribute of the
|
||
mctrepresentation, if any.
|
||
* Any capabilities requested by the uses property of the representation
|
||
definition.
|
||
|
||
## Representers
|
||
|
||
The `representers` extension category is used to add additional behavior to the
|
||
`mctrepresentation` directive. This extension category is intended primarily
|
||
for use internal to the platform.
|
||
|
||
Unlike _representations_, which describe specific ways to represent domain
|
||
objects, representers are used to modify or augment the process of representing
|
||
domain objects in general. For example, support for the _gestures_ extension
|
||
category is added by a representer.
|
||
|
||
A representer needs only provide an implementation. When an `mctrepresentation`
|
||
is linked (see [https://docs.angularjs.org/guide/directive]() or when the domain
|
||
object being represented changes, a new representer of each declared type is
|
||
instantiated. The constructor arguments for a representer are the same as the
|
||
arguments to the link function in an Angular directive: `scope`, the Angular
|
||
scope for this representation; `element`, the jqLitewrapped
|
||
`mctrepresentation` element, and `attrs`, a set of keyvalue pairs of that
|
||
element’s attributes. Representers may wish to populate the scope, attach event
|
||
listeners to the element, etc.
|
||
|
||
This implementation must provide a single method, `destroy()`, which will be
|
||
invoked when the representer is no longer needed.
|
||
|
||
## Roots
|
||
|
||
The extension category `roots` is used to provide rootlevel domain object
|
||
models. Rootlevel domain objects appear at the toplevel of the tree hierarchy.
|
||
For example, the _My Items_ folder is added as an extension of this category.
|
||
|
||
Extensions of this category should have the following properties:
|
||
* `id`: The machinereadable identifier for the domaiwn object being exposed.
|
||
* `model`: The model, as a JSON object, for the domain object being exposed.
|
||
|
||
## Stylesheets
|
||
|
||
The stylesheets extension category is used to add CSS files to style the
|
||
application. Extension definitions for this category should include one
|
||
property:
|
||
|
||
* `stylesheetUrl`: Path and filename, including extension, for the stylesheet to
|
||
include. This path is relative to the bundle’s resources folder (by default,
|
||
`res`)
|
||
|
||
To control the order of CSS files, use priority (see the section on Extension
|
||
Definitions above.)
|
||
|
||
## Templates
|
||
|
||
The `templates` extension category is used to expose Angular templates under
|
||
symbolic identifiers. These can then be utilized using the `mctinclude`
|
||
directive, which behaves similarly to `nginclude`, except that it uses these
|
||
symbolic identifiers instead of paths.
|
||
|
||
A template’s extension definition should include the following properties:
|
||
* `key`: The machinereadable name which identifies this template, matched
|
||
against the value given to the key attribute of the mctinclude directive.
|
||
* `templateUrl`: The path to the relevant Angular template. This path is
|
||
relative to the bundle's resources directory.
|
||
|
||
Note that, when multiple templates are present with the same key, the one with
|
||
the highest priority will be used from mctinclude. This behavior can be used to
|
||
override templates exposed by the platform (to change the logo which appears in
|
||
the bottom right, for instance.)
|
||
|
||
Templates do not have implementations.
|
||
|
||
## Types
|
||
|
||
The types extension category describes types of domain objects which may appear
|
||
within Open MCT Web.
|
||
|
||
A type’s extension definition should have the following properties:
|
||
|
||
* `key`: The machinereadable identifier for this domain object type. Will be
|
||
stored to and matched against the type property of domain object models.
|
||
* `name`: The humanreadable name for this domain object type.
|
||
* `description`: A humanreadable summary of this domain object type.
|
||
* `glyph`: A single character to be rendered as an icon in Open MCT Web’s custom
|
||
font set.
|
||
* `model`: A domain object model, used as the initial state for created domain
|
||
objects of this type (before any properties are specified.)
|
||
* `features`: Optional; an array of strings describing features of this domain
|
||
object type. Currently, only creation is recognized by the platform; this is
|
||
used to determine that this type should appear in the Create menu. More
|
||
generally, this is used to support the hasFeature(...) method of the type
|
||
capability.
|
||
* `properties`: An array describing individual properties of this domain object
|
||
(as should appear in the Create or the Edit Properties dialog.) Each property is
|
||
described by an object containing the following properties:
|
||
* `control`: The key of the control (see mctcontrol and the controls
|
||
extension category) to use for editing this property.
|
||
* `property`: A string which will be used as the name of the property in the
|
||
domain object’s model that the value for this property should be stored
|
||
under. If this value should be stored in an object nested within the domain
|
||
object model, then property should be specified as an array of strings
|
||
identifying these nested objects and, finally, the property itself.
|
||
* other properties as appropriate for a control of this type (each
|
||
property’s definition will also be passed in as the structure for its
|
||
control.) See documentation of mctform for more detail on these properties.
|
||
|
||
Types do not have implementations.
|
||
|
||
## Versions
|
||
The versions extension category is used to introduce line items in Open MCT
|
||
Web’s About dialog. These should have the following properties:
|
||
|
||
* `name`: The name of this line item, as should appear in the lefthand side of
|
||
the list of version information in the About dialog.
|
||
* `value`: The value which should appear to the right of the name in the About
|
||
dialog.
|
||
|
||
To control the ordering of line items within the About dialog, use `priority`.
|
||
(See section on Extension Definitions above.)
|
||
|
||
This extension category does not have implementations.
|
||
|
||
## Views
|
||
|
||
The views extension category is used to determine which options appear to the
|
||
user as available views of domain objects of specific types. A view’s extension
|
||
definition has the same properties as a representation (and views can be
|
||
utilized via mctrepresentation); additionally:
|
||
|
||
* `name`: The humanreadable name for this view type.
|
||
* description: A humanreadable summary of this view type.
|
||
* `glyph`: A single character to be rendered as an icon in Open MCT Web’s custom
|
||
font set.
|
||
* `type`: Optional; if present, this representation is only applicable for
|
||
domain object’s of this type.
|
||
* `needs`: Optional array of strings; if present, this representation is only
|
||
applicable for domain objects which have the capabilities identified by these
|
||
strings.
|
||
* `delegation`: Optional boolean, intended to be used in conjunction with
|
||
`needs`; if present, allow required capabilities to be satisfied by means of
|
||
capability delegation. (See the delegation capability, in the Capabilities
|
||
section.)
|
||
* `toolbar`: Optional; a definition for the toolbar which may appear in a
|
||
toolbar when using this view in Edit mode. This should be specified as a
|
||
structure for mcttoolbar, with additional properties available for each item in
|
||
that toolbar:
|
||
* `property`: A property name. This will refer to a property in the view’s
|
||
current selection; that property on the selected object will be modifiable
|
||
as the `ngmodel` of the displayed control in the toolbar. If the value of
|
||
the property is a function, it will be used as a gettersetter (called with
|
||
no arguments to use as a getter, called with a value to use as a setter.)
|
||
* `method`: A method to invoke (again, on the selected object) from the
|
||
toolbar control. Useful particularly for buttons (which don’t edit a single
|
||
property, necessarily.)
|
||
|
||
### View Scope
|
||
|
||
Views do not have implementations, but do get the same properties in scope that
|
||
are provided for `representations`.
|
||
|
||
When a view is in Edit mode, this scope will additionally contain:
|
||
* `commit()`: A function which can be invoked to mark any changes to the view’s
|
||
configuration as ready to persist.
|
||
* `selection`: An object representing the current selection state.
|
||
|
||
#### Selection State
|
||
|
||
A view’s selection state is, conceptually, a set of JavaScript objects. The
|
||
presence of methods/properties on these objects determine which toolbar controls
|
||
are visible, and what state they manage and/or behavior they invoke.
|
||
|
||
This set may contain up to two different objects: The _view proxy_, which is
|
||
used to make changes to the view as a whole, and the _selected object_, which is
|
||
used to represent some state within the view. (Future versions of Open MCT Web
|
||
may support multiple selected objects.)
|
||
|
||
The `selection` object made available during Edit mode has the following
|
||
methods:
|
||
|
||
* `proxy([object])`: Get (or set, if called with an argument) the current view
|
||
proxy.
|
||
* `select(object)`: Make this object the selected object.
|
||
* `deselect()`: Clear the currently selected object.
|
||
* `get()`: Get the currently selected object. Returns undefined if there is no
|
||
currently selected object.
|
||
* `selected(object)`: Check if the JavaScript object is currently in the
|
||
selection set. Returns true if the object is either the currently selected
|
||
object, or the current view proxy.
|
||
* `all()`: Get an array of all objects in the selection state. Will include
|
||
either or both of the view proxy and selected object.
|
||
|
||
# Directives
|
||
|
||
Open MCT Web defines several Angular directives that are intended for use both
|
||
internally within the platform, and by plugins.
|
||
|
||
## Before Unload
|
||
|
||
The `mctbeforeunload` directive is used to listen for (and prompt for user
|
||
confirmation) of navigation changes in the browser. This includes reloading,
|
||
following links out of Open MCT Web, or changing routes. It is used to hook into
|
||
both `onbeforeunload` event handling as well as route changes from within
|
||
Angular.
|
||
|
||
This directive is useable as an attribute. Its value should be an Angular
|
||
expression. When an action that would trigger an unload and/or route change
|
||
occurs, this Angular expression is evaluated. Its result should be a message to
|
||
display to the user to confirm their navigation change; if this expression
|
||
evaluates to a falsy value, no message will be displayed.
|
||
|
||
## Chart
|
||
|
||
The `mctchart` directive is used to support drawing of simple charts. It is
|
||
present to support the Plot view, and its functionality is limited to the
|
||
functionality that is relevant for that view.
|
||
|
||
This directive is used at the element level and takes one attribute, `draw`,
|
||
which is an Angular expression which will should evaluate to a drawing object.
|
||
This drawing object should contain the following properties:
|
||
|
||
* `dimensions`: The size, in logical coordinates, of the chart area. A
|
||
twoelement array or numbers.
|
||
* `origin`: The position, in logical coordinates, of the lowerleft corner of
|
||
the chart area. A twoelement array or numbers.
|
||
* `lines`: An array of lines (e.g. as a plot line) to draw, where each line is
|
||
expressed as an object containing:
|
||
* `buffer`: A Float32Array containing points in the line, in logical
|
||
coordinates, in sequential x,y pairs.
|
||
* `color`: The color of the line, as a fourelement RGBA array, where
|
||
each element is a number in the range of 0.01.0.
|
||
* `points`: The number of points in the line.
|
||
* `boxes`: An array of rectangles to draw in the chart area. Each is an object
|
||
containing:
|
||
* `start`: The first corner of the rectangle, as a twoelement array of
|
||
numbers, in logical coordinates.
|
||
* `end`: The opposite corner of the rectangle, as a twoelement array of
|
||
numbers, in logical coordinates. color: The color of the line, as a
|
||
fourelement RGBA array, where each element is a number in the range of
|
||
0.01.0.
|
||
|
||
While `mctchart` is intended to support plots specifically, it does perform
|
||
some useful management of canvas objects (e.g. choosing between WebGL and Canvas
|
||
2D APIs for drawing based on browser support) so its usage is recommended when
|
||
its supported drawing primitives are sufficient for other charting tasks.
|
||
|
||
## Container
|
||
|
||
The `mctcontainer` is similar to the `mctinclude` directive insofar as it allows
|
||
templates to be referenced by symbolic keys instead of by URL. Unlike
|
||
`mctinclude`, it supports transclusion.
|
||
|
||
Unlike `mctinclude`, `mctcontainer` accepts a key as a plain string attribute,
|
||
instead of as an Angular expression.
|
||
|
||
## Control
|
||
|
||
The `mctcontrol` directive is used to display user input elements. Several
|
||
controls are included with the platform to wrap default input types. This
|
||
directive is primarily intended for internal use by the `mctform` and
|
||
`mcttoolbar` directives.
|
||
|
||
When using `mctcontrol`, the attributes `ngmodel`, `ngdisabled`,
|
||
`ngrequired`, and `ngpattern` may also be used. These have the usual meaning
|
||
(as they would for an input element) except for `ngmodel`; when used, it will
|
||
actually be `ngModel[field]` (see below) that is twoway bound by this control.
|
||
This allows `mctcontrol` elements to more easily delegate to other
|
||
`mctcontrol` instances, and also facilitates usage for generated forms.
|
||
|
||
This directive supports the following additional attributes, all specified as
|
||
Angular expressions:
|
||
|
||
* `key`: A machinereadable identifier for the specific type of control to
|
||
display.
|
||
* `options`: A set of options to display in this control.
|
||
* `structure`: In practice, contains the definition object which describes this
|
||
form row or toolbar item. Used to pass additional controlspecific parameters.
|
||
* `field`: The field in the `ngModel` under which to read/store the property
|
||
associated with this control.
|
||
|
||
## Drag
|
||
|
||
The `mctdrag` directive is used to support dragbased gestures on HTML
|
||
elements. Note that this is not “drag” in the “draganddrop” sense, but “drag”
|
||
in the more general “mouse down, mouse move, mouse up” sense.
|
||
|
||
This takes the form of three attributes:
|
||
|
||
* `mctdrag`: An Angular expression to evaluate during drag movement.
|
||
* `mctdragdown`: An Angular expression to evaluate when the drag starts.
|
||
* `mctdragup`: An Angular expression to evaluate when the drag ends.
|
||
|
||
In each case, a variable `delta` will be provided to the expression; this is a
|
||
twoelement array or the horizontal and vertical pixel offset of the current
|
||
mouse position relative to the mouse position where dragging began.
|
||
|
||
## Form
|
||
|
||
The `mctform` directive is used to generate forms using a declarative structure,
|
||
and to gather back user input. It is applicable at the element level and
|
||
supports the following attributes:
|
||
|
||
* `ngmodel`: The object which should contain the full form input. Individual
|
||
fields in this model are bound to individual controls; the names used for these
|
||
fields are provided in the form structure (see below).
|
||
* `structure`: The structure of the form; e.g. sections, rows, their names, and
|
||
so forth. The value of this attribute should be an Angular expression.
|
||
* `name`: The name in the containing scope under which to publish form
|
||
"metastate", e.g. `$valid`, `$dirty`, etc. This is as the behavior of `ngform`.
|
||
Passed as plain text in the attribute.
|
||
|
||
### Form Structure
|
||
|
||
Forms in Open MCT Web have a common structure to permit consistent display. A
|
||
form is broken down into sections, which will be displayed in groups; each
|
||
section is broken down into rows, each of which provides a control for a single
|
||
property. Input from this form is twoway bound to the object passed via
|
||
`ngmodel`.
|
||
|
||
A form’s structure is represented by a JavaScript object in the following form:
|
||
|
||
{
|
||
"name": ... title to display for the form, as a string ...,
|
||
"sections": [
|
||
{
|
||
"name": ... title to display for the section ...,
|
||
"rows": [
|
||
{
|
||
"name": ... title to display for this row ...,
|
||
"control": ... symbolic key for the control ...,
|
||
"key": ... field name in ngmodel ...
|
||
"pattern": ... optional, reg exp to match against ...
|
||
"required": ... optional boolean ...
|
||
"options": [
|
||
"name": ... name to display (e.g. in a select) ...,
|
||
"value": ... value to store in the model ...
|
||
]
|
||
},
|
||
... and other rows ...
|
||
]
|
||
},
|
||
... and other sections ...
|
||
]
|
||
}
|
||
|
||
Note that `pattern` may be specified as a string, to simplify storing for
|
||
structures as JSON when necessary. The string should be given in a form
|
||
appropriate to pass to a `RegExp` constructor.
|
||
|
||
### Form Controls
|
||
|
||
A few standard control types are included in the platform/forms bundle:
|
||
|
||
* `textfield`: An area to enter plain text.
|
||
* `select`: A dropdown list of options.
|
||
* `checkbox`: A box which may be checked/unchecked.
|
||
* `color`: A color picker.
|
||
* `button`: A button.
|
||
* `datetime`: An input for UTC date/time entry; gives result as a UNIX
|
||
timestamp, in milliseconds since start of 1970, UTC.
|
||
|
||
##Include
|
||
|
||
The `mctinclude` directive is similar to nginclude, except that it takes a
|
||
symbolic identifier for a template instead of a URL. Additionally, templates
|
||
included via mctinclude will have an isolated scope.
|
||
|
||
The directive should be used at the element level and supports the following
|
||
attributes, all of which are specified as Angular expressions:
|
||
|
||
* `key`: Machinereadable identifier for the template (of extension category
|
||
templates) to be displayed.
|
||
* `ngmodel`: _Optional_; will be passed into the template’s scope as ngModel.
|
||
Intended usage is for twoway bound user input.
|
||
* `parameters`: _Optional_; will be passed into the template’s scope as parameters.
|
||
Intended usage is for templatespecific display parameters.
|
||
|
||
## Representation
|
||
|
||
The `mctrepresentation` directive is used to include templates which
|
||
specifically represent domain objects. Usage is similar to `mctinclude`.
|
||
|
||
The directive should be used at the element level and supports the following
|
||
attributes, all of which are specified as Angular expressions:
|
||
|
||
* `key`: Machinereadable identifier for the representation (of extension
|
||
category representations or views) to be displayed.
|
||
* `mctobject`: The domain object being represented.
|
||
* `ngmodel`: Optional; will be passed into the template’s scope as ngModel.
|
||
Intended usage is for twoway bound user input.
|
||
* `parameters`: Optional; will be passed into the template’s scope as
|
||
parameters. Intended usage is for templatespecific display parameters.
|
||
|
||
## Resize
|
||
|
||
The `mctresize` directive is used to monitor the size of an HTML element. It is
|
||
specified as an attribute whose value is an Angular expression that will be
|
||
evaluated when the size of the HTML element changes. This expression will be
|
||
provided a single variable, `bounds`, which is an object containing two
|
||
properties, `width` and `height`, describing the size in pixels of the element.
|
||
|
||
When using this directive, an attribute `mctresizeinterval` may optionally be
|
||
provided. Its value is an Angular expression describing the number of
|
||
milliseconds to wait before next checking the size of the HTML element; this
|
||
expression is evaluated when the directive is linked and reevaluated whenever
|
||
the size is checked.
|
||
|
||
## Scroll
|
||
|
||
The `mctscrollx` and `mctscrolly` directives are used to both monitor and
|
||
control the horizontal and vertical scroll bar state of an element,
|
||
respectively. They are intended to be used as attributes whose values are
|
||
assignable Angular expressions which twoway bind to the scroll bar state.
|
||
|
||
## Toolbar
|
||
|
||
The `mcttoolbar` directive is used to generate toolbars using a declarative
|
||
structure, and to gather back user input. It is applicable at the element level
|
||
and supports the following attributes:
|
||
|
||
* `ngmodel`: The object which should contain the full toolbar input. Individual
|
||
fields in this model are bound to individual controls; the names used for these
|
||
fields are provided in the form structure (see below).
|
||
* `structure`: The structure of the toolbar; e.g. sections, rows, their names, and
|
||
so forth. The value of this attribute should be an Angular expression.
|
||
* `name`: The name in the containing scope under which to publish form
|
||
"metastate", e.g. `$valid`, `$dirty`, etc. This is as the behavior of
|
||
`ngform`. Passed as plain text in the attribute.
|
||
|
||
Toolbars support the same control options as forms.
|
||
|
||
### Toolbar Structure
|
||
|
||
A toolbar’s structure is defined similarly to forms, except instead of rows
|
||
there are items.
|
||
|
||
{
|
||
"name": ... title to display for the form, as a string ...,
|
||
"sections": [
|
||
{
|
||
"name": ... title to display for the section ...,
|
||
"items": [
|
||
{
|
||
"name": ... title to display for this row ...,
|
||
"control": ... symbolic key for the control ...,
|
||
"key": ... field name in ngmodel ...
|
||
"pattern": ... optional, reg exp to match against ...
|
||
"required": ... optional boolean ...
|
||
"options": [
|
||
"name": ... name to display (e.g. in a select) ...,
|
||
"value": ... value to store in the model ...
|
||
],
|
||
"disabled": ... true if control should be disabled ...
|
||
"size": ... size of the control (for textfields) ...
|
||
"click": ... function to invoke (for buttons) ...
|
||
"glyph": ... glyph to display (for buttons) ...
|
||
"text": ... text within control (for buttons) ...
|
||
},
|
||
... and other rows ...
|
||
]
|
||
},
|
||
... and other sections ...
|
||
]
|
||
}
|
||
|
||
# Services
|
||
|
||
The Open MCT Web platform provides a variety of services which can be retrieved
|
||
and utilized via dependency injection. These services fall into two categories:
|
||
|
||
* _Composite Services_ are defined by a set of components extensions; plugins may
|
||
introduce additional components with matching interfaces to extend or augment
|
||
the functionality of the composed service. (See the Framework section on
|
||
Composite Services.)
|
||
* _Other services_ which are defined as standalone service objects; these can be
|
||
utilized by plugins but are not intended to be modified or augmented.
|
||
|
||
## Composite Services
|
||
|
||
This section describes the composite services exposed by Open MCT Web,
|
||
specifically focusing on their interface and contract.
|
||
|
||
In many cases, the platform will include a provider for a service which consumes
|
||
a specific extension category; for instance, the `actionService` depends on
|
||
`actions[]` and will expose available actions based on the rules defined for
|
||
that extension category.
|
||
|
||
In these cases, it will usually be simpler to add a new extension of a given
|
||
category (e.g. of category `actions`) even when the same behavior could be
|
||
introduced by a service component (e.g. an extension of category `components`
|
||
where `provides` is `actionService`, and `type` is `provider`.)
|
||
|
||
Occasionally, the extension category does not provide enough expressive power to
|
||
achieve a desired result. For instance, the Create menu is populated with
|
||
`create` actions, where one such action exists for each creatable type. Since
|
||
the framework does not provide a declarative means to introduce a new action per
|
||
type declaratively, the platform implements this explicitly in an `actionService`
|
||
component of type `provider`. Plugins may use a similar approach when the normal
|
||
extension mechanism is insufficient to achieve a desired result.
|
||
|
||
### Action Service
|
||
|
||
The `actionService` provides `Action` instances which are applicable in specific
|
||
contexts. See Core API for additional notes on the interface for actions. The
|
||
`actionService` has the following interface:
|
||
|
||
* `getActions(context)`: Returns an array of Action objects which are applicable
|
||
in the specified action context.
|
||
|
||
### Capability Service
|
||
|
||
The capabilityService provides constructors for capabilities which will be
|
||
exposed for a given domain object.
|
||
|
||
The capabilityService has the following interface:
|
||
|
||
* `getCapabilities(model)`: Returns a an object containing keyvalue pairs,
|
||
representing capabilities which should be exposed by the domain object with this
|
||
model. Keys in this object are the capability keys (as used in a
|
||
`getCapability(...)` call) and values are either:
|
||
* Functions, in which case they will be used as constructors, which will
|
||
receive the domain object instance to which the capability applies as their
|
||
sole argument.The resulting object will be provided as the result of a
|
||
domain object’s `getCapability(...)` call. Note that these instances are cached
|
||
by each object, but may be recreated when an object is mutated.
|
||
* Other objects, which will be used directly as the result of a domain
|
||
object’s `getCapability(...)` call.
|
||
|
||
### Dialog Service
|
||
|
||
The `dialogService` provides a means for requesting user input via a modal
|
||
dialog. It has the following interface:
|
||
|
||
* `getUserInput(formStructure, formState)`: Prompt the user to fill out a form.
|
||
The first argument describes the form’s structure (as will be passed to
|
||
mctform) while the second argument contains the initial state of that form.
|
||
This returns a Promise for the state of the form after the user has filled it
|
||
in; this promise will be rejected if the user cancels input.
|
||
* `getUserChoice(dialogStructure)`: Prompt the user to make a single choice from
|
||
a set of options, which (in the platform implementation) will be expressed as
|
||
buttons in the displayed dialog. Returns a Promise for the user’s choice, which
|
||
will be rejected if the user cancels input.
|
||
|
||
### Dialog Structure
|
||
|
||
The object passed as the dialogStructure to getUserChoice should have the
|
||
following properties:
|
||
|
||
* `title`: The title to display at the top of the dialog.
|
||
* `hint`: Short message to display below the title.
|
||
* `template`: Identifying key (as will be passed to mctinclude) for the
|
||
template which will be used to populate the inner area of the dialog.
|
||
* `model`: Model to pass in the ngmodel attribute of mctinclude.
|
||
* `parameters`: Parameters to pass in the parameters attribute of mctinclude.
|
||
* `options`: An array of options describing each button at the bottom. Each
|
||
option may have the following properties:
|
||
* `name`: Humanreadable name to display in the button.
|
||
* `key`: Machinereadable key, to pass as the result of the resolved promise
|
||
when clicked.
|
||
* `description`: Description to show in tooltip on hover.
|
||
|
||
## Domain Object Service
|
||
|
||
The objectService provides domain object instances. It has the following
|
||
interface:
|
||
|
||
* `getObjects(ids)`: For the provided array of domain object identifiers,
|
||
returns a Promise for an object containing keyvalue pairs, where keys are
|
||
domain object identifiers and values are corresponding DomainObject instances.
|
||
Note that the result may contain a superset or subset of the objects requested.
|
||
|
||
## Gesture Service
|
||
|
||
The `gestureService` is used to attach gestures (see extension category
|
||
gestures) to representations. It has the following interface:
|
||
|
||
* `attachGestures(element, domainObject, keys)`: Attach gestures specified by
|
||
the provided gesture keys (an array of strings) to this jqLitewrapped HTML
|
||
element, which represents the specified domainObject. Returns an object with a
|
||
single method `destroy()`, to be invoked when it is time to detach these
|
||
gestures.
|
||
|
||
## Model Service
|
||
|
||
The modelService provides domain object models. It has the following interface:
|
||
|
||
* `getModels(ids)`: For the provided array of domain object identifiers, returns
|
||
a Promise for an object containing keyvalue pairs, where keys are domain object
|
||
identifiers and values are corresponding domain object models. Note that the
|
||
result may contain a superset or subset of the models requested.
|
||
|
||
## Persistence Service
|
||
|
||
The persistenceService provides the ability to load/store JavaScript objects
|
||
(presumably serializing/deserializing to JSON in the process.) This is used
|
||
primarily to store domain object models. It has the following interface:
|
||
|
||
* `listSpaces()`: Returns a Promise for an array of strings identifying the
|
||
different persistence spaces this service supports. Spaces are intended to be
|
||
used to distinguish between different underlying persistence stores, to allow
|
||
these to live side by side.
|
||
* `listObjects()`: Returns a Promise for an array of strings identifying all
|
||
documents stored in this persistence service.
|
||
* `createObject(space, key, value)`: Create a new document in the specified
|
||
persistence space, identified by the specified key, the contents of which shall
|
||
match the specified value. Returns a promise that will be rejected if creation
|
||
fails.
|
||
* `readObject(space, key)`: Read an existing document in the specified
|
||
persistence space, identified by the specified key. Returns a promise for the
|
||
specified document; this promise will resolve to undefined if the document does
|
||
not exist.
|
||
* `updateObject(space, key, value)`: Update an existing document in the
|
||
specified persistence space, identified by the specified key, such that its
|
||
contents match the specified value. Returns a promise that will be rejected if
|
||
the update fails.
|
||
* `deleteObject(space, key)`: Delete an existing document from the specified
|
||
persistence space, identified by the specified key. Returns a promise which will
|
||
be rejected if deletion fails.
|
||
|
||
## Policy Service
|
||
|
||
The policyService may be used to determine whether or not certain behaviors are
|
||
allowed within the application. It has the following interface:
|
||
|
||
* `allow(category, candidate, context, [callback])`: Check if this decision
|
||
should be allowed. Returns a boolean. Its arguments are interpreted as:
|
||
* `category`: A string identifying which kind of decision is being made. See
|
||
the section on Policies for categories supported by the platform; plugins
|
||
may define and utilize policies of additional categories, as well.
|
||
* `candidate`: An object representing the thing which shall or shall not be
|
||
allowed. Usually, this will be an instance of an extension of the category
|
||
defined above. This does need to be the case; additional policies which are
|
||
not specific to any extension may also be defined and consulted using unique
|
||
category identifiers. In this case, the type of the object delivered for the
|
||
candidate may be unique to the policy type.
|
||
* `context`: An object representing the context in which the decision is
|
||
occurring. Its contents are specific to each policy category.
|
||
* `callback`: Optional; a function to call if the policy decision is rejected.
|
||
This function will be called with the message string (which may be
|
||
undefined) of whichever individual policy caused the operation to fail.
|
||
|
||
## Telemetry Service
|
||
|
||
The `telemetryService` is used to acquire telemetry data. See the section on
|
||
Telemetry in Core API for more information on how both the arguments and
|
||
responses of this service are structured.
|
||
|
||
When acquiring telemetry for display, it is recommended that the
|
||
`telemetryHandler` service be used instead of this service. The
|
||
`telemetryHandler` has additional support for subscribing to and requesting
|
||
telemetry data associated with domain objects or groups of domain objects. See
|
||
the [Other Services](#Other-Services) section for more information.
|
||
|
||
The `telemetryService` has the following interface:
|
||
|
||
* `requestTelemetry(requests)`: Issue a request for telemetry, matching the
|
||
specified telemetry requests. Returns a _Promise_ for a telemetry response
|
||
object.
|
||
* `subscribe(callback, requests)`: Subscribe to realtime updates for telemetry,
|
||
matching the specified `requests`. The specified `callback` will be invoked with
|
||
telemetry response objects as they become available. This method returns a
|
||
function which can be invoked to terminate the subscription.
|
||
|
||
## Type Service
|
||
|
||
The `typeService` exposes domain object types. It has the following interface:
|
||
|
||
* `listTypes()`: Returns all domain object types supported in the application,
|
||
as an array of Type instances.
|
||
* `getType(key)`: Returns the `Type` instance identified by the provided key, or
|
||
undefined if no such type exists.
|
||
|
||
## View Service
|
||
|
||
The `viewService` exposes definitions for views of domain objects. It has the
|
||
following interface:
|
||
|
||
* `getViews(domainObject)`: Get an array of extension definitions of category
|
||
`views` which are valid and applicable to the specified `domainObject`.
|
||
|
||
## Other Services
|
||
|
||
### Drag and Drop
|
||
|
||
The `dndService` provides information about the content of an active
|
||
draganddrop gesture within the application. It is intended to complement the
|
||
`DataTransfer` API of HTML5 draganddrop, by providing access to nonserialized
|
||
JavaScript objects being dragged, as well as by permitting inspection during
|
||
drag (which is normally prohibited by browsers for security reasons.)
|
||
|
||
The `dndService` has the following methods:
|
||
|
||
* `setData(key, value)`: Set drag data associated with a given type, specified
|
||
by the `key` argument.
|
||
* `getData(key)`: Get drag data associated with a given type, specified by the
|
||
`key` argument.
|
||
* `removeData(key)`: Clear drag data associated with a given type, specified by
|
||
the `key` argument.
|
||
|
||
# Navigation
|
||
|
||
The navigationService provides information about the current navigation state of
|
||
the application; that is, which object is the user currently viewing? This service merely tracks this
|
||
state and notifies listeners; it does not take immediate action when navigation changes,
|
||
although its listeners might.
|
||
The navigationService has the following methods:
|
||
|
||
* getNavigation(): Get the current navigation state. Returns a DomainObject.
|
||
* setNavigation(domainObject): Set the current navigation state. Returns a
|
||
DomainObject.
|
||
* addListener(callback): Listen for changes in navigation state. The provided
|
||
callback should be a Function which takes a single DomainObject as an
|
||
argument.
|
||
* removeListener(callback): Stop listening for changes in navigation state. The
|
||
provided callback should be a Function which has previously been passed to
|
||
addListener.
|
||
|
||
Now
|
||
|
||
The service now is a function which acts as a simple wrapper for Date.now(). It is
|
||
present mainly so that this functionality may be more easily mocked in tests for scripts which
|
||
use the current time.
|
||
|
||
Telemetry Formatter
|
||
|
||
The telemetryFormatter is a utility for formatting domain and range values read
|
||
from a telemetry series.
|
||
The telemetryFormatter has the following methods:
|
||
|
||
* formatDomainValue(value): Format the provided domain value (which will be
|
||
assumed to be a timestamp) for display; returns a string.
|
||
* formatRangeValue(value): Format the provided range value (a number) for
|
||
display; returns a string.
|
||
|
||
|
||
|
||
51
|
||
Telemetry Handler
|
||
|
||
The telemetryHandler is a utility for retrieving telemetry data associated with
|
||
domain objects; it is particularly useful for dealing with cases where the telemetry capability
|
||
is delegated to contained objects (as occurs in Telemetry Panels.)
|
||
The telemetryHandler has the following methods:
|
||
|
||
* handle(domainObject, callback, [lossless]): Subscribe to and issue
|
||
future requests for telemetry associated with the provided domainObject, invoking the
|
||
provided callback function when streaming data becomes available. Returns a
|
||
TelemetryHandle (see below.)
|
||
|
||
Telemetry Handle
|
||
|
||
A TelemetryHandle has the following methods:
|
||
|
||
* getTelemetryObjects(): Get the domain objects (as a DomainObject[]) that
|
||
have a telemetry capability and are being handled here. Note that these are looked
|
||
up asynchronously, so this method may return an empty array if the initial lookup is not
|
||
yet completed.
|
||
* promiseTelemetryObjects(): As getTelemetryObjects(), but returns a
|
||
Promise that will be fulfilled when the lookup is complete.
|
||
* unsubscribe(): Unsubscribe to streaming telemetry updates associated with this
|
||
handle.
|
||
* getDomainValue(domainObject): Get the most recent domain value received via a
|
||
streaming update for the specified domainObject.
|
||
* getRangeValue(domainObject): Get the most recent range value received via a
|
||
streaming update for the specified domainObject.
|
||
* getMetadata(): Get metadata (as reported by the getMetadata() method of a
|
||
telemetry capability) associated with telemetryproviding domain objects. Returns an
|
||
array, which is in the same order as getTelemetryObjects().
|
||
* request(request, callback): Issue a new request for historical telemetry data.
|
||
The provided callback will be invoked when new data becomes available, which may
|
||
occur multiple times (e.g. if there are multiple domain objects.) It will be invoked with the
|
||
DomainObject for which a new series is available, and the TelemetrySeries itself,
|
||
in that order.
|
||
* getSeries(domainObject): Get the latest TelemetrySeries (as resulted from a
|
||
previous request(...) call) available for this domain object.
|
||
|
||
52
|
||
Models
|
||
|
||
Domain object models in Open MCT Web are JavaScript objects describing the
|
||
persistent state of the domain objects they describe. Their contents include a mix of commonly
|
||
understood metadata attributes; attributes which are recognized by and/or determine the
|
||
applicability of specific extensions; and properties specific to given types.
|
||
|
||
General Metadata
|
||
|
||
Some properties of domain object models have a ubiquitous meaning through Open
|
||
MCT Web and can be utilized directly:
|
||
|
||
* name: The humanreadable name of the domain object.
|
||
|
||
Extension-specific Properties
|
||
|
||
Other properties of domain object models have specific meaning imposed by other
|
||
extensions within the Open MCT Web platform.
|
||
|
||
Capability-specific Properties
|
||
|
||
Some properties either trigger the presence/absence of certain capabilities, or are
|
||
managed by specific capabilities:
|
||
|
||
* composition: An array of domain object identifiers that represents the contents of this
|
||
domain object (e.g. as will appear in the tree hierarchy.) Understood by the
|
||
composition capability; the presence or absence of this property determines the
|
||
presence or absence of that capability.
|
||
* modified: The timestamp (in milliseconds since the UNIX epoch) of the last
|
||
modification made to this domain object. Managed by the mutation capability.
|
||
* persisted: The timestamp (in milliseconds since the UNIX epoch) of the last time
|
||
when changes to this domain object were persisted. Managed by the persistence
|
||
capability.
|
||
* relationships: An object containing keyvalue pairs, where keys are symbolic
|
||
identifiers for relationship types, and values are arrays of domain object identifiers. Used
|
||
by the relationship capability; the presence or absence of this property determines
|
||
the presence or absence of that capability.
|
||
* telemetry: An object which serves as a template for telemetry requests associated
|
||
with this domain object (e.g. specifying source and key; see Telemetry Requests
|
||
53
|
||
under Core API.) Used by the telemetry capability; the presence or absence of this
|
||
property determines the presence or absence of that capability.
|
||
* type: A string identifying the type of this domain object. Used by the type capability.
|
||
|
||
View Configurations
|
||
|
||
Persistent configurations for specific views of domain objects are stored in the domain
|
||
object model under the property configurations. This is an object containing keyvalue
|
||
pairs, where keys identify the view, and values are objects containing viewspecific (and
|
||
viewmanaged) configuration properties.
|
||
|
||
Modifying Models
|
||
|
||
When interacting with a domain object’s model, it is possible to make modifications to it
|
||
directly. Don’t! These changes may not be properly detected by the platform, meaning that
|
||
other representations of the domain object may not be updated, changes may not be saved at
|
||
the expected times, and generally, that unexpected behavior may occur.
|
||
Instead, use the mutation capability.
|
||
|
||
|
||
|
||
54
|
||
Capabilities
|
||
|
||
Dynamic behavior associated with a domain object is expressed as capabilities. A
|
||
capability is a JavaScript object with an interface that is specific to the type of capability in use.
|
||
Often, there is a relationship between capabilities and services. For instance, there is an
|
||
action capability and an actionService, and there is a telemetry capability as well as a
|
||
telemetryService. Typically, the pattern here is that the capability will utilize the service for
|
||
the specific domain object.
|
||
When interacting with domain objects, it is generally preferable to use a capability
|
||
instead of a service when the option is available. Capability interfaces are typically easier to use
|
||
and/or more powerful in these situations. Additionally, this usage provides a more robust
|
||
substitutability mechanism; for instance, one could configure a plugin such that it provided a
|
||
totally new implementation of a given capability which might not invoke the underlying service,
|
||
while user code which interacts with capabilities remains indifferent to this detail.
|
||
|
||
Action
|
||
|
||
The action capability is present for all domain objects. It allows applicable Action
|
||
instances to be retrieved and performed for specific domain objects.
|
||
For example:
|
||
domainObject.getCapability("action").perform("navigate");
|
||
...will initiate a navigate action upon the domain object, if an action with key "navigate" is
|
||
defined.
|
||
|
||
This capability has the following interface:
|
||
|
||
* getActions(context): Get the actions that are applicable in the specified action
|
||
context; the capability will fill in the domainObject field of this context if necessary. If
|
||
context is specified as a string, they will instead be used as the key of the action
|
||
context. Returns an array of Action instances.
|
||
* perform(context): Perform an action. This will find and perform the first matching
|
||
action available for the specified action context, filling in the domainObject field as
|
||
necessary. If context is specified as a string, they will instead be used as the key of
|
||
the action context. Returns a Promise for the result of the action that was performed, or
|
||
undefined if no matching action was found.
|
||
|
||
55
|
||
Composition
|
||
|
||
The composition capability provides access to domain objects that are contained by
|
||
this domain object. While the composition property of a domain object’s model describes
|
||
these contents (by their identifiers), the composition capability provides a means to load the
|
||
corresponding DomainObject instances in the same order. The absence of this property in the
|
||
model will result in the absence of this capability in the domain object.
|
||
This capability has the following interface:
|
||
|
||
* invoke(): Returns a Promise for an array of DomainObject instances.
|
||
|
||
Delegation
|
||
|
||
The delegation capability is used to communicate the intent of a domain object to
|
||
delegate responsibilities, which would normally handled by other capabilities, to the domain
|
||
objects in its composition.
|
||
This capability has the following interface:
|
||
|
||
* getDelegates(key): Returns a Promise for an array of DomainObject instances,
|
||
to which this domain object wishes to delegate the capability with the specified key.
|
||
* invoke(key): Alias of getDelegates(key).
|
||
* doesDelegate(key): Returns true if the domain object does delegate the capability
|
||
with the specified key.
|
||
|
||
The platform implementation of the delegation capability inspects the domain object’s
|
||
type definition for a property delegates, whose value is an array of strings describing which
|
||
capabilities domain objects of that type wish to delegate. If this property is not present, the
|
||
delegation capability will not be present in domain objects of that type.
|
||
|
||
|
||
|
||
|
||
56
|
||
Editor
|
||
|
||
The editor capability is meant primarily for internal use by Edit mode, and helps to
|
||
manage the behavior associated with exiting Edit mode via Save or Cancel. Its interface is not
|
||
intended for general use. However, domainObject.hasCapability(‘editor’) is a
|
||
useful way of determining whether or not we are looking at an object in Edit mode.
|
||
|
||
|
||
Mutation
|
||
|
||
The mutation capability provides a means by which the contents of a domain object’s
|
||
model can be modified. This capability is provided by the platform for all domain objects, and
|
||
has the following interface:
|
||
|
||
* mutate(mutator, [timestamp]): Modify the domain object’s model using the
|
||
specified mutator function. After changes are made, the modified property of the
|
||
model will be updated with the specified timestamp, if one was provided, or with the
|
||
current system time.
|
||
* invoke(...): Alias of mutate.
|
||
|
||
Changes to domain object models should only be made via the mutation capability;
|
||
other platform behavior is likely to break (either by exhibiting undesired behavior, or failing to
|
||
exhibit desired behavior) if models are modified by other means.
|
||
|
||
Mutator Function
|
||
|
||
The mutator argument above is a function which will receive a cloned copy of the
|
||
domain object’s model as a single argument. It may return:
|
||
|
||
* A Promise, in which case the resolved value of the promise will be used to determine
|
||
which of the following forms is used.
|
||
* Boolean false, in which case the mutation is cancelled.
|
||
* A JavaScript object, in which case this object will be used as the new model for this
|
||
domain object.
|
||
57
|
||
* No value (or, equivalently, undefined), in which case the cloned copy (including any
|
||
changes made in place by the mutator function) will be used as the new domain object
|
||
model.
|
||
|
||
Persistence
|
||
|
||
The persistence capability provides a mean for interacting with the underlying
|
||
persistence service which stores this domain object’s model. It has the following interface:
|
||
|
||
* persist(): Store the local version of this domain object, including any changes, to the
|
||
persistence store. Returns a Promise for a boolean value, which will be true when the
|
||
object was successfully persisted.
|
||
* refresh(): Replace this domain object’s model with the most recent version from
|
||
persistence. Returns a Promise which will resolve when the change has completed.
|
||
* getSpace(): Return the string which identifies the persistence space which stores this
|
||
domain object.
|
||
|
||
Relationship
|
||
|
||
The relationship capability provides a means for accessing other domain objects
|
||
with which this domain object has some typed relationship. It has the following interface:
|
||
|
||
* listRelationships(): List all types of relationships exposed by this object. Returns
|
||
an array of strings identifying the types of relationships.
|
||
* getRelatedObjects(relationship): Get all domain objects to which this domain
|
||
object has the specified type of relationship, which is a string identifier (as above.)
|
||
Returns a Promise for an array of DomainObject instances.
|
||
|
||
The platform implementation of the relationship capability is present for domain
|
||
objects which has a relationships property in their model, whose value is an object
|
||
containing keyvalue pairs, where keys are strings identifying relationship types, and values are
|
||
arrays of domain object identifiers.
|
||
|
||
58
|
||
Telemetry
|
||
|
||
The telemetry capability provides a means for accessing telemetry data associated
|
||
with a domain object. It has the following interface:
|
||
|
||
* requestData([request]): Request telemetry data for this specific domain object,
|
||
using telemetry request parameters from the specified request if provided. This
|
||
capability will fill in telemetry request properties asneeded for this domain object.
|
||
Returns a Promise for a TelemetrySeries.
|
||
* subscribe(callback, [request]): Subscribe to telemetry data updates for this
|
||
specific domain object, using telemetry request parameters from the specified request
|
||
if provided. This capability will fill in telemetry request properties asneeded for this
|
||
domain object. The specified callback will be invoked with TelemetrySeries
|
||
instances as they arrive. Returns a function which can be invoked to terminate the
|
||
subscription, or undefined if no subscription could be obtained.
|
||
* getMetadata(): Get metadata associated with this domain object’s telemetry.
|
||
|
||
The platform implementation of the telemetry capability is present for domain objects
|
||
which has a telemetry property in their model and/or type definition; this object will serve as a
|
||
template for telemetry requests made using this object, and will also be returned by
|
||
getMetadata() above.
|
||
|
||
Type
|
||
|
||
The type capability exposes information about the domain object’s type. It has the
|
||
same interface as Type; see Core API.
|
||
|
||
View
|
||
|
||
The view capability exposes views which are applicable to a given domain object. It has
|
||
the following interface:
|
||
|
||
* invoke(): Returns an array of extension definitions for views which are applicable for
|
||
this domain object.
|
||
59
|
||
Actions
|
||
|
||
Actions are reusable processes/behaviors performed by users within the system,
|
||
typically upon domain objects.
|
||
Action Categories
|
||
|
||
The platform understands the following action categories (specifiable as the category
|
||
parameter of an action’s extension definition.)
|
||
|
||
* contextual: Appears in context menus.
|
||
* viewcontrol: Appears in topright area of view (as buttons) in Browse mode
|
||
|
||
Platform Actions
|
||
|
||
The platform defines certain actions which can be utilized by way of a domain object’s
|
||
action capability. Unless otherwise specified, these act upon (and modify) the object
|
||
described by the domainObject property of the action’s context.
|
||
|
||
* cancel: Cancel the current editing action (invoked from Edit mode.)
|
||
* compose: Place an object in another object’s composition. The object to be added
|
||
should be provided as the selectedObject of the action context.
|
||
* edit: Start editing an object (enter Edit mode.)
|
||
* fullscreen: Enter full screen mode.
|
||
* navigate: Make this object the focus of navigation (e.g. highlight it within the tree,
|
||
display a view of it to the right.)
|
||
* properties: Show the “Edit Properties” dialog.
|
||
* remove: Remove this domain object from its parent’s composition. (The parent, in this
|
||
case, is whichever other domain object exposed this object by way of its composition
|
||
capability.)
|
||
* save: Save changes (invoked from Edit mode.)
|
||
* window: Open this object in a new window.
|
||
|
||
|
||
|
||
60
|
||
Policies
|
||
|
||
Policies are consulted to determine when certain behavior in Open MCT Web is allowed.
|
||
Policy questions are assigned to certain categories, which broadly describe the type of decision
|
||
being made; within each category, policies have a candidate (the thing which may or may not be
|
||
allowed) and, optionally, a context (describing, generally, the context in which the decision is
|
||
occurring.)
|
||
The types of objects passed for “candidate” and “context” vary by category; these types
|
||
are documented below.
|
||
Policy Categories
|
||
|
||
The platform understands the following policy categories (specifiable as the category
|
||
parameter of an policy’s extension definition.)
|
||
|
||
* action: Determines whether or not a given action is allowable. The candidate
|
||
argument here is an Action; the context is its action context object.
|
||
* composition: Determines whether or not domain objects of a given type are allowed
|
||
to contain domain objects of another type. The candidate argument here is the
|
||
container’s Type; the context argument is the Type of the object to be contained.
|
||
* view: Determines whether or not a view is applicable for a domain object. The
|
||
candidate argument is the view’s extension definition; the context argument is the
|
||
DomainObject to be viewed.
|
||
|
||
|
||
|
||
|
||
|
||
61
|
||
Build, Test, Deploy
|
||
|
||
Open MCT Web is designed to support a broad variety of build and deployment options.
|
||
The sources can be deployed in the same directory structure used during development. A few
|
||
utilities are included to support development processes.
|
||
|
||
Command-line Build
|
||
|
||
Open MCT Web includes a script for building via command line using Maven 3.0.4
|
||
(https://maven.apache.org/).
|
||
|
||
Invoking mvn clean install will:
|
||
|
||
* Check code style using JSLint. The build will fail if JSLint raises any warnings.
|
||
* Run the test suite (see below.) The build will fail if any tests fail.
|
||
* Populate version info (e.g. commit hash, build time.)
|
||
* Produce a web archive (.war) artifact in the target directory.
|
||
|
||
The produced artifact contains a subset of the repository’s own folder hierarchy, omitting
|
||
tests and example bundles.
|
||
Note that an internet connection is required to run this build, in order to download build
|
||
dependencies.
|
||
|
||
Test Suite
|
||
|
||
Open MCT Web uses Jasmine (http://jasmine.github.io/) for automated testing. The file
|
||
test.html, included at the top level of the source repository, can be run from the browser to
|
||
perform tests for all active bundles, as defined in bundle.json.
|
||
To define tests for a bundle:
|
||
|
||
* Include a directory named test within that bundle.
|
||
* In the test directory, include a file named suite.json. This will identify which scripts
|
||
will be tested.
|
||
* The file suite.json must contain a JSON array of strings, where each string is the
|
||
name of a script to be tested. These names should include any directory paths to the
|
||
script after (but not including) the src folder, and should not include the file’s .js
|
||
extension. (Note that while Open MCT Web’s framework allows a different name to be
|
||
chosen for the src directory, the test runner does not: This directory must be named
|
||
src for the test runner to find it.)
|
||
62
|
||
* For each script to be tested, a corresponding test script should be located in the bundle’s
|
||
test directory. This should include the suffix Spec at the end of the filename (but
|
||
before the .js extension.) This test script should be an AMD module which uses the
|
||
Jasmine API to declare its test behavior. It should declare an AMD dependency on the
|
||
script to be tested, using a relative path.
|
||
|
||
For example, if writing tests for a bundle at example/foo with two scripts:
|
||
* example/foo/src/controllers/FooController.js
|
||
* example/foo/src/directives/FooDirective.js
|
||
|
||
First, these scripts should be identified in example/foo/test/suite.json, e.g. with
|
||
contents:
|
||
[ "controllers/FooController", "directives/FooDirective" ]
|
||
|
||
Then, scripts which describe these tests should be written. For example, test
|
||
example/foo/test/controllers/FooControllerSpec.js could look like:
|
||
|
||
/*global define,Promise,describe,it,expect,beforeEach*/
|
||
|
||
define(
|
||
["../../src/controllers/FooController"],
|
||
function (FooController) {
|
||
"use strict";
|
||
|
||
describe("The foo controller", function () {
|
||
it("does something", function () {
|
||
var controller = new FooController();
|
||
expect(controller.foo()).toEqual("foo");
|
||
});
|
||
});
|
||
}
|
||
);
|
||
|
||
Code Coverage
|
||
|
||
In addition to running tests, the test runner will also capture code coverage information
|
||
using Blanket.JS (http://blanketjs.org/) and display this at the bottom of the screen. Currently,
|
||
only statement coverage is displayed.
|
||
|
||
63
|
||
Deployment
|
||
|
||
Open MCT Web is built to be flexible in terms of the deployment strategies it supports. In
|
||
order to run in the browser, Open MCT Web needs:
|
||
|
||
1. HTTP access to sources/resources for the framework, platform, and all active bundles.
|
||
2. Access to any external services utilized by active bundles. (This means that external
|
||
services need to support HTTP or some other webaccessible interface, like
|
||
WebSockets.)
|
||
|
||
Any HTTP server capable of serving flat files is sufficient for the first point. The
|
||
commandline build also packages Open MCT Web into a .war file for easier deployment on
|
||
containers such as Apache Tomcat.
|
||
The second point may be less flexible, as it depends upon the specific services to be
|
||
utilized by Open MCT Web. Because of this, it is often the set of external services (and the
|
||
manner in which they are exposed) that determine how to deploy Open MCT Web.
|
||
|
||
One important constraint to consider in this context is the browser’s same origin policy. If
|
||
external services are not on the same apparent host and port as the client (from the perspective
|
||
of the browser) then access may be disallowed. There are two workarounds if this occurs:
|
||
* Make the external service appear to be on the same host/port, either by actually
|
||
deploying it there, or by proxying requests to it.
|
||
* Enable CORS (crossorigin resource sharing) on the external service. This is only
|
||
possible if the external service can be configured to support CORS. Care should be
|
||
exercised if choosing this option to ensure that the chosen configuration does not create
|
||
a security vulnerability.
|
||
|
||
Examples of deployment strategies (and the conditions under which they make the most
|
||
sense) include:
|
||
|
||
* If the external services that Open MCT Web will utilize are all running on Apache Tomcat
|
||
(https://tomcat.apache.org/), then it makes sense to run Open MCT Web from the same
|
||
Tomcat instance as a separate web application. The .war artifact produced by the
|
||
command line build facilitates this deployment option. (See
|
||
https://tomcat.apache.org/tomcat8.0doc/deployerhowto.html for general information on
|
||
deploying in Tomcat.)
|
||
* If a variety of external services will be running from a variety of hosts/ports, then it may
|
||
make sense to use a web server that supports proxying, such as the Apache HTTP
|
||
Server (http://httpd.apache.org/). In this configuration, the HTTP server would be
|
||
configured to proxy (or reverse proxy) requests at specific paths to the various external
|
||
services, while providing Open MCT Web as flat files from a different path.
|
||
64
|
||
* If a single server component is being developed to handle all serverside needs of an
|
||
Open MCT Web instance, it can make sense to serve Open MCT Web (as flat files) from
|
||
the same component using an embedded HTTP server such as Nancy
|
||
(http://nancyfx.org/).
|
||
* If no external services are needed (or if the “external services” will just be generating flat
|
||
files to read) it makes sense to utilize a lightweight flat file HTTP server such as Lighttpd
|
||
(http://www.lighttpd.net/). In this configuration, Open MCT Web sources/resources would
|
||
be placed at one path, while the files generated by the external service are placed at
|
||
another path.
|
||
* If all external services support CORS, it may make sense to have an HTTP server that is
|
||
solely responsible for making Open MCT Web sources/resources available, and to have
|
||
Open MCT Web contact these external services directly. Again, lightweight HTTP
|
||
servers such as Lighttpd (http://www.lighttpd.net/) are useful in this circumstance. The
|
||
downside of this option is that additional configuration effort is required, both to enable
|
||
CORS on the external services, and to ensure that Open MCT Web can correctly locate
|
||
these services.
|
||
|
||
Another important consideration is authentication. By design, Open MCT Web does not
|
||
handle user authentication. Instead, this should typically be treated as a deploymenttime
|
||
concern, where authentication is handled by the HTTP server which provides Open MCT Web,
|
||
or an external access management system.
|
||
|
||
Configuration
|
||
|
||
In most of the deployment options above, some level of configuration is likely to be
|
||
needed or desirable to make sure that bundles can reach the external services they need to
|
||
reach. Most commonly this means providing the path or URL to an external service.
|
||
Configurable parameters within Open MCT Web are specified via constants (literally, as
|
||
extensions of the constants category) and accessed via dependency injection by the scripts
|
||
which need them. Reasonable defaults for these constants are provided in the bundle where
|
||
they are used. Plugins are encouraged to follow the same pattern.
|
||
Constants may be specified in any bundle; if multiple constants are specified with the
|
||
same key, the highestpriority one will be used. This allows default values to be overridden by
|
||
specifying constants with higher priority.
|
||
|
||
This permits at least three configuration approaches:
|
||
|
||
* Modify the constants defined in their original bundles when deploying. This is generally
|
||
undesirable due to the amount of manual work required and potential for error, but is
|
||
viable if there are a small number of constants to change.
|
||
* Add a separate configuration bundle which overrides the values of these constants. This
|
||
is particularly appropriate when multiple configurations (e.g. development, test,
|
||
65
|
||
production) need to be managed easily; these can be swapped quickly by changing the
|
||
set of active bundles in bundles.json.
|
||
* Deploy Open MCT Web and its external services in such a fashion that the default paths
|
||
to reach external services are all correct.
|
||
|
||
Configuration Constants
|
||
|
||
The following configuration constants are recognized by Open MCT Web bundles:
|
||
|
||
* CouchDB adapter, platform/persistence/coucb
|
||
○ COUCHDB_PATH: URL or path to the CouchDB database to be used for domain
|
||
object persistence. Should not include a trailing slash.
|
||
* ElasticSearch adapter, platform/persistence/elastic
|
||
○ ELASTIC_ROOT: URL or path to the ElasticSearch instance to be used for
|
||
domain object persistence. Should not include a trailing slash.
|
||
○ ELASTIC_PATH: Path relative to the ElasticSearch instance where domain
|
||
object models should be persisted. Should take the form <index>/<type>.
|
||
66
|
||
|
||
|
||
|