Merge branch 'api-1110' into api-1124b

This commit is contained in:
Victor Woeltjen 2016-09-29 16:43:47 -07:00
commit 434ea5487a
12 changed files with 675 additions and 159 deletions

311
API.md
View File

@ -1,114 +1,285 @@
# Open MCT API # Open MCT API
The Open MCT framework public api can be utilized by building the application (`gulp install`) and then copying the file from `dist/main.js` to your directory The Open MCT framework public api can be utilized by building the application
of choice. (`gulp install`) and then copying the file from `dist/main.js` to your
directory of choice.
Open MCT supports AMD, CommonJS, and standard browser loading; it's easy to use Open MCT supports AMD, CommonJS, and loading via a script tag; it's easy to use
in your project. in your project. The [`openmct`]{@link module:openmct} module is exported
via AMD and CommonJS, and is also exposed as `openmct` in the global scope
if loaded via a script tag.
## Overview ## Overview
Open MCT's goal is to allow you to browse, create, edit, and visualize all of the domain knowledge you need on a daily basis. Open MCT's goal is to allow you to browse, create, edit, and visualize all of
the domain knowledge you need on a daily basis.
To do this, the main building block provided by Open MCT is the domain object-- the temperature sensor on the starboard solar panel, an overlay plot comparing the results of all temperature sensor, the command dictionary for a spacecraft, the individual commands in that dictionary, your "my documents" folder: all of these things are domain objects. To do this, the main building block provided by Open MCT is the _domain object_.
The temperature sensor on the starboard solar panel,
an overlay plot comparing the results of all temperature sensor,
the command dictionary for a spacecraft,
the individual commands in that dictionary, your "my documents" folder:
All of these things are domain objects.
Domain objects have Types-- so a specific instrument temperature sensor is a "Telemetry Point," and turning on a drill for a certain duration of time is an "Activity". Types allow you to form an ontology of knowledge and provide an abstraction for grouping, visualizing, and interpreting data. Domain objects have Types, so a specific instrument temperature sensor is a
"Telemetry Point," and turning on a drill for a certain duration of time is
an "Activity". Types allow you to form an ontology of knowledge and provide
an abstraction for grouping, visualizing, and interpreting data.
And then we have Views. Views allow you to visualize a domain object. Views can apply to specific domain objects; they may also apply to certain types of domain objects, or they may apply to everything. Views are simply a method of visualizing domain objects. And then we have Views. Views allow you to visualize domain objects. Views can
apply to specific domain objects; they may also apply to certain types of
domain objects, or they may apply to everything. Views are simply a method
of visualizing domain objects.
Regions allow you to specify what views are displayed for specific types of domain objects in response to different user actions-- for instance, you may want to display a different view while editing, or you may want to update the toolbar display when objects are selected. Regions allow you to map views to specific user actions. Regions allow you to specify what views are displayed for specific types of
domain objects in response to different user actions. For instance, you may
want to display a different view while editing, or you may want to update the
toolbar display when objects are selected. Regions allow you to map views to
specific user actions.
Domain objects can be mutated and persisted, developers can create custom actions and apply them to domain objects, and many more things can be done. For more information, read on. Domain objects can be mutated and persisted, developers can create custom
actions and apply them to domain objects, and many more things can be done.
For more information, read on!
## The API ## Running Open MCT
### `MCT.Type(options)` Once the [`openmct`](@link module:openmct) module has been loaded, you can
Status: First Draft simply invoke [`start`]{@link module:openmct.MCT#start} to run Open MCT:
Returns a `typeInstance`. `options` is an object supporting the following properties:
* `metadata`: `object` defining metadata used in displaying the object; has the following properties: ```
* `label`: `string`, the human-readible name of the type. used in menus and inspector. openmct.start();
* `glyph`: `string`, the name of the icon to display for this type, used in labels. ```
* `description`: `string`, a human readible description of the object and what it is for.
* `initialize`: `function` which initializes new instances of this type. it is called with an object, should add any default properties to that object.
* `creatable`: `boolean`, if true, this object will be visible in the create menu.
* `form`: `Array` an array of form fields, as defined... somewhere! Generates a property sheet that is visible while editing this object.
### `MCT.type(typeKey, typeInstance)` Generally, however, you will want to configure Open MCT by adding plugins
Status: First Draft before starting it. It is important to install plugins and configure Open MCT
_before_ calling [`start`]{@link module:openmct.MCT#start}; Open MCT is not
designed to be reconfigured once started.
Register a `typeInstance` with a given Type `key` (a `string`). There can only be one `typeInstance` registered per type `key`. typeInstances must be registered before they can be utilized. ## Configuring Open MCT
### `MCT.Objects` The [`openmct`]{@link module:openmct} module (more specifically, the
Status: First Draft [`MCT`]{@link module:openmct.MCT} class, of which `openmct` is an instance)
exposes a variety of methods to allow the application to be configured,
extended, and customized before running.
Allows you to register object providers, which allows you to integrate domain objects from various different sources. Also implements methods for mutation and persistence of objects. See [Object API](src/api/objects/README.md) for more details. Short examples follow; see the linked documentation for further details.
### `MCT.Composition` ### Adding Domain Object Types
Status: First Draft
Objects can contain other objects, and the Composition API allows you to fetch the composition of any given domain object, or implement custom methods for defining composition as necessary. Custom types may be registered via
[`openmct.types`]{@link module:openmct.MCT#types}:
### `MCT.view(region, definition)` ```
Status: First Draft openmct.types.addType('my-type', new openmct.Type({
label: "My Type",
description: "This is a type that I added!"
});
```
Register a view factory for a specific region. View factories receive an instance of a domain object and return a `View` for that object, or return undefined if they do not know how to generate a view for that object. ### Adding Views
* `ViewDefinition`: an object with the following properties: Custom views may be registered based on the region in the application
* `canView(domainObject)`: should return truthy if the view is valid for a given domain object, falsy if it is not capable of generating a view for that object. where they should appear:
* `view(domainObject)`: should instantate and return a `View` for the given object.
* `metadata()`: a function that returns metadata about this view. Optional.
* `View`: an object containing a number of lifecycle methods:
* `view.show(container)`: instantiate a view (a set of dom elements) and attach it to the container.
* `view.destroy(container)`: remove any listeners and expect your dom elements to be destroyed.
For a basic introduction to views & types, check out these tutorials:
* [custom-view](custom-view.html) -- Implementing a custom view with vanilla javascript. * [`openmct.mainViews`]{@link module:openmct.MCT#mainViews} is a registry
* [custom-view-react](custom-view-react.html) -- Implementing a custom view with React. of views of domain objects which should appear in the main viewing area.
* [`openmct.inspectors`]{@link module:openmct.MCT#inspectors} is a registry
of views of domain objects and/or active selections, which should appear in
the Inspector.
* [`openmct.toolbars`]{@link module:openmct.MCT#toolbars} is a registry
of views of domain objects and/or active selections, which should appear in
the toolbar area while editing.
* [`openmct.indicators`]{@link module:openmct.MCT#inspectors} is a registry
of views which should appear in the status area of the application.
### `MCT.conductor` Example:
Status: First Draft
The time conductor is an API that facilitates time synchronization across multiple components. Components that would like to be "time aware" may attach listeners to the time conductor API to allow them to remain synchronized with other components. For more information ont he time conductor API, please look at the API draft here: https://github.com/nasa/openmct/blob/66220b89ca568075f107505ba414de9457dc0427/platform/features/conductor-redux/src/README.md ```
openmct.mainViews.addProvider({
canView: function (domainObject) {
return domainObject.type === 'my-type';
},
view: function (domainObject) {
return new MyView(domainObject);
}
});
```
### `MCT.selection` ### Adding a Root-level Object
Status: First Draft
Tracks the application's selection state (which elements of a view has a user selected?) In many cases, you'd like a certain object (or a certain hierarchy of
objects) to be accessible from the top level of the application (the
tree on the left-hand side of Open MCT.) It is typical to expose a telemetry
dictionary as a hierarchy of telemetry-providing domain objects in this
fashion.
One or more JavaScript objects may be selected at any given time. User code is responsible for any necessary type-checking. To do so, use the [`addRoot`]{@link module:openmct.ObjectAPI#addRoot} method
of the [object API]{@link module:openmct.ObjectAPI}:
The following methods are exposed from this object: ```
openmct.objects.addRoot({
identifier: { key: "my-key", namespace: "my-namespace" }
name: "My Root-level Object",
type: "my-type"
});
```
* `select(value)`: Add `value` to the current selection. You can also remove this root-level object via its identifier:
* `deselect(value)`: Remove `value` from the current selection.
* `selected()`: Get array of all selected objects.
* `clear()`: Deselect all selected objects.
MCT.selection is an EventEmitter; a `change` event is emitted whenever the selection changes. ```
openmct.objects.removeRoot({ key: "my-key", namespace: "my-namespace" });
```
### `MCT.systems` ### Adding Composition Providers
Status: Not Implemented, Needs to be ported from old system.
A registry for different time system definitions. Based upon the previous time format system which utilized the "formats" extension category. The "composition" of a domain object is the list of objects it contains,
as shown (for example) in the tree for browsing. Open MCT provides a
default solution for composition, but there may be cases where you want
to provide the composition of a certain object (or type of object) dynamically.
For instance, you may want to populate a hierarchy under a custom root-level
object based on the contents of a telemetry dictionary.
To do this, you can add a new CompositionProvider:
### `MCT.run([container])` ```
Status: Stable Draft openmct.composition.addProvider({
appliesTo: function (domainObject) {
return domainObject.type === 'my-type';
},
load: function (domainObject) {
return Promise.resolve(myDomainObjects);
}
});
```
Run the MCT application, loading the application into the `container`, a DOM element. If a container is not specified, the application is injected into the body of the page. ### Adding Telemetry Providers
### `MCT.install(plugin)` When connecting to a new telemetry source, you will want to register a new
Status: Stable Draft [telemetry provider]{@link module:openmct.TelemetryAPI~TelemetryProvider}
with the [telemetry API]{@link module:openmct.TelemetryAPI#addProvider}:
Install a plugin in MCT. Must be called before calling `run`. Plugins are functions which are invoked with the `MCT` instance as their first argument, and are expected to use the MCT public API to add functionality. ```
openmct.telemetry.addProvider({
canProvideTelemetry: function (domainObject) {
return domainObject.type === 'my-type';
},
properties: function (domainObject) {
return [
{ key: 'value', name: "Temperature", units: "degC" },
{ key: 'time', name: "UTC" }
];
},
request: function (domainObject, options) {
var telemetryId = domainObject.myTelemetryId;
return myAdapter.request(telemetryId, options.start, options.end);
},
subscribe: function (domainObject, callback) {
var telemetryId = domainObject.myTelemetryId;
myAdapter.subscribe(telemetryId, callback);
return myAdapter.unsubscribe.bind(myAdapter, telemetryId, callback);
}
});
```
For an example of writing a plugin, check out [plugin-example.html](plugin-example.html) The implementations for `request` and `subscribe` can vary depending on the
nature of the endpoint which will provide telemetry. In the example above,
it is assumed that `myAdapter` contains the specific implementations
(HTTP requests, WebSocket connections, etc.) associated with some telemetry
source.
### `MCT.setAssetPath(path)` ## Using Open MCT
Sets the path (absolute or relative) at which the Open MCT static files are being hosted. The default value is '.'. When implementing new features, it is useful and sometimes necessary to
utilize functionality exposed by Open MCT.
Note that this API is transitional and will be removed in a future version. ### Retrieving Composition
To limit which objects are loaded at any given time, the composition of
a domain object must be requested asynchronously:
```
openmct.composition(myObject).load().then(function (childObjects) {
childObjects.forEach(doSomething);
});
```
### Support Common Gestures
Custom views may also want to support common gestures using the
[gesture API]{@link module:openmct.GestureAPI}. For instance, to make
a view (or part of a view) selectable:
```
openmct.gestures.selectable(myHtmlElement, myDomainObject);
```
### Working with Domain Objects
The [object API]{@link module:openmct.ObjectAPI} provides useful methods
for working with domain objects.
To make changes to a domain object, use the
[`mutate`]{@link module:openmct.ObjectAPI#mutate} method:
```
openmct.objects.mutate(myDomainObject, "name", "New name!");
```
Making modifications in this fashion allows other usages of the domain
object to remain up to date using the
[`observe`]{@link module:openmct.ObjectAPI#observe} method:
```
openmct.objects.observe(myDomainObject, "name", function (newName) {
myLabel.textContent = newName;
});
```
### Using Telemetry
Very often in Open MCT, you wish to work with telemetry data (for instance,
to display it in a custom visualization.)
### Synchronizing with the Time Conductor
Views which wish to remain synchronized with the state of Open MCT's
time conductor should utilize
[`openmct.conductor`]{@link module:openmct.TimeConductor}:
```
openmct.conductor.on('bounds', function (newBounds) {
requestTelemetry(newBounds.start, newBounds.end).then(displayTelemetry);
});
```
## Plugins
While you can register new features with Open MCT directly, it is generally
more useful to package these as a plugin. A plugin is a function that takes
[`openmct`]{@link module:openmct} as an argument, and performs configuration
upon `openmct` when invoked.
### Installing Plugins
To install plugins, use the [`install`]{@link module:openmct.MCT#install}
method:
```
openmct.install(myPlugin);
```
The plugin will be invoked to configure Open MCT before it is started.
### Writing Plugins
Plugins configure Open MCT, and should utilize the
[`openmct`]{@link module:openmct} module to do so, as summarized above in
"Configuring Open MCT" and "Using Open MCT" above.
### Distributing Plugins
Hosting or downloading plugins is outside of the scope of this documentation.
We recommend distributing plugins as UMD modules which export a single
function.

View File

@ -38,22 +38,89 @@ define([
] ]
} }; } };
/**
*
* @type {module:openmct.Selection}
* @memberof module:openmct.MCT#
* @name selection
*/
this.selection = new Selection(); this.selection = new Selection();
/** /**
* * MCT's time conductor, which may be used to synchronize view contents
* for telemetry- or time-based views.
* @type {module:openmct.TimeConductor} * @type {module:openmct.TimeConductor}
* @memberof module:openmct.MCT# * @memberof module:openmct.MCT#
* @name conductor * @name conductor
*/ */
this.conductor = new TimeConductor(); this.conductor = new TimeConductor();
/**
* An interface for interacting with the composition of domain objects.
* The composition of a domain object is the list of other domain
* objects it "contains" (for instance, that should be displayed
* beneath it in the tree.)
*
* `composition` may be called as a function, in which case it acts
* as [`composition.get`]{@link module:openmct.CompositionAPI#get}.
*
* @type {module:openmct.CompositionAPI}
* @memberof module:openmct.MCT#
* @name composition
*/
this.composition = api.Composition;
/**
* Registry for views of domain objects which should appear in the
* main viewing area.
*
* @type {module:openmct.ViewRegistry}
* @memberof module:openmct.MCT#
* @name mainViews
*/
/**
* Registry for views which should appear in the Inspector area.
* These views will be chosen based on selection state, so
* providers should be prepared to test arbitrary objects for
* viewability.
*
* @type {module:openmct.ViewRegistry}
* @memberof module:openmct.MCT#
* @name inspectors
*/
/**
* Registry for views which should appear in the status indicator area.
* @type {module:openmct.ViewRegistry}
* @memberof module:openmct.MCT#
* @name indicators
*/
/**
* Registry for views which should appear in the toolbar area while
* editing.
*
* These views will be chosen based on selection state, so
* providers should be prepared to test arbitrary objects for
* viewability.
*
* @type {module:openmct.ViewRegistry}
* @memberof module:openmct.MCT#
* @name toolbars
*/
/**
* Registry for domain object types which may exist within this
* instance of Open MCT.
*
* @type {module:openmct.TypeRegistry}
* @memberof module:openmct.MCT#
* @name types
*/
/**
* Utilities for attaching common behaviors to views.
*
* @type {module:openmct.GestureAPI}
* @memberof module:openmct.MCT#
* @name gestures
*/
this.TimeConductor = this.conductor; // compatibility for prototype this.TimeConductor = this.conductor; // compatibility for prototype
this.on('navigation', this.selection.clear.bind(this.selection)); this.on('navigation', this.selection.clear.bind(this.selection));
} }
@ -71,7 +138,7 @@ define([
* *
* @type {module:openmct.ObjectAPI} * @type {module:openmct.ObjectAPI}
* @memberof module:openmct.MCT# * @memberof module:openmct.MCT#
* @name Objects * @name objects
*/ */
MCT.Objects = api.Objects; MCT.Objects = api.Objects;
@ -81,7 +148,7 @@ define([
* *
* @type {module:openmct.TelemetryAPI} * @type {module:openmct.TelemetryAPI}
* @memberof module:openmct.MCT# * @memberof module:openmct.MCT#
* @name Telemetry * @name telemetry
*/ */
MCT.prototype.legacyExtension = function (category, extension) { MCT.prototype.legacyExtension = function (category, extension) {
@ -102,14 +169,6 @@ define([
}); });
}; };
/**
* Register a new type of view.
*
* @param {string} region the region identifier (see mct.regions)
* @param {module:openmct.ViewProvider} provider the provider for this view
* @method view
* @memberof module:openmct.MCT#
*/
MCT.prototype.view = function (region, definition) { MCT.prototype.view = function (region, definition) {
var viewKey = region + uuid(); var viewKey = region + uuid();
var adaptedViewKey = "adapted-view-" + region; var adaptedViewKey = "adapted-view-" + region;
@ -152,13 +211,6 @@ define([
}); });
}; };
/**
* Register a new [type]{@link module:openmct.Type} of domain object.
* @param {string} key a unique identifier for this type of object
* @param {module:openmct.Type} type the new type
* @memberof module:openmct.MCT#
* @method type
*/
MCT.prototype.type = function (key, type) { MCT.prototype.type = function (key, type) {
var legacyDef = type.toLegacyDefinition(); var legacyDef = type.toLegacyDefinition();
legacyDef.key = key; legacyDef.key = key;

View File

@ -49,6 +49,13 @@ define([], function () {
/** /**
* Check if this provider can supply views for a domain object. * Check if this provider can supply views for a domain object.
*
* When called by Open MCT, this may include additional arguments
* which are on the path to the object to be viewed; for instance,
* when viewing "A Folder" within "My Items", this method will be
* invoked with "A Folder" (as a domain object) as the first argument,
* and "My Items" as the second argument.
*
* @method canView * @method canView
* @memberof module:openmct.ViewProvider# * @memberof module:openmct.ViewProvider#
* @param {module:openmct.DomainObject} domainObject the domain object * @param {module:openmct.DomainObject} domainObject the domain object
@ -58,11 +65,17 @@ define([], function () {
*/ */
/** /**
* Provide a view of this domain object. * Provide a view of this object.
*
* When called by Open MCT, this may include additional arguments
* which are on the path to the object to be viewed; for instance,
* when viewing "A Folder" within "My Items", this method will be
* invoked with "A Folder" (as a domain object) as the first argument,
* and "My Items" as the second argument.
*
* @method view * @method view
* @memberof module:openmct.ViewProvider# * @memberof module:openmct.ViewProvider#
* @param {module:openmct.DomainObject} domainObject the domain object * @param {*} object the object to be viewed
* to be viewed
* @returns {module:openmct.View} a view of this domain object * @returns {module:openmct.View} a view of this domain object
*/ */

View File

@ -19,13 +19,14 @@ define([
}; };
/** /**
* Retrieve the composition (if any) of this domain object. The * An interface for interacting with the composition of domain objects.
* composition of a domain object is the list of other domain objects * The composition of a domain object is the list of other domain objects
* it "contains" (for instance, that should be displayed beneath it * it "contains" (for instance, that should be displayed beneath it
* in the tree.) * in the tree.)
* @method Composition *
* @interface CompositionAPI
* @returns {module:openmct.CompositionCollection} * @returns {module:openmct.CompositionCollection}
* @memberof module:openmct.MCT# * @memberof module:openmct
*/ */
function composition(object) { function composition(object) {
var provider = getProvider(object); var provider = getProvider(object);
@ -35,12 +36,58 @@ define([
} }
return new CompositionCollection(object, provider); return new CompositionCollection(object, provider);
}; }
/**
* Retrieve the composition (if any) of this domain object.
*
* @method get
* @returns {module:openmct.CompositionCollection}
* @memberof module:openmct.CompositionAPI#
*/
composition.get = composition;
/**
* Add a composition provider.
*
* Plugins can add new composition providers to change the loading
* behavior for certain domain objects.
*
* @method addProvider
* @param {module:openmct.CompositionProvider} provider the provider to add
* @memberof module:openmct.CompositionAPI#
*/
composition.addProvider = function (provider) { composition.addProvider = function (provider) {
PROVIDER_REGISTRY.unshift(provider); PROVIDER_REGISTRY.unshift(provider);
}; };
/**
* Add a composition policy. Composition policies may disallow domain
* objects from containing other domain objects.
*
* @method addPolicy
* @param {module:openmct.CompositionAPI~CompositionPolicy} policy
* the policy to add
* @memberof module:openmct.CompositionAPI#
*/
/**
* A composition policy is a function which either allows or disallows
* placing one object in another's composition.
*
* Open MCT's policy model requires consensus, so any one policy may
* reject composition by returning false. As such, policies should
* generally be written to return true in the default case.
*
* @callback CompositionPolicy
* @memberof module:openmct.CompositionAPI~
* @param {module:openmct.DomainObject} containingObject the object which
* would act as a container
* @param {module:openmct.DomainObject} containedObject the object which
* would be contained
* @returns {boolean} false if this composition should be disallowed
*/
composition.addProvider(new DefaultCompositionProvider()); composition.addProvider(new DefaultCompositionProvider());
return composition; return composition;

View File

@ -14,7 +14,7 @@ define([
* by another domain object. It provides methods for loading this * by another domain object. It provides methods for loading this
* list asynchronously, and for modifying this list. * list asynchronously, and for modifying this list.
* *
* @class CompositionCollection * @interface CompositionCollection
* @param {module:openmct.DomainObject} domainObject the domain object * @param {module:openmct.DomainObject} domainObject the domain object
* whose composition will be contained * whose composition will be contained
* @param {module:openmct.CompositionProvider} provider the provider * @param {module:openmct.CompositionProvider} provider the provider
@ -168,13 +168,6 @@ define([
} }
}; };
/**
* Check if this composition can contain this domain object.
* @name canContain
* @memberof module:openmct.CompositionCollection
* @param {module:openmct.DomainObject} the domain object to contain
* @returns {boolean} true if containment is allowed
*/
CompositionCollection.prototype.canContain = function (domainObject) { CompositionCollection.prototype.canContain = function (domainObject) {
return this.provider.canContain(this.domainObject, domainObject); return this.provider.canContain(this.domainObject, domainObject);
}; };

View File

@ -36,8 +36,8 @@ define([
* to check * to check
* @returns {boolean} true if this provider can provide * @returns {boolean} true if this provider can provide
* composition for a given domain object * composition for a given domain object
* @memberof {module:openmct.CompositionProvider#} * @memberof module:openmct.CompositionProvider#
* @name appliesTo * @method appliesTo
*/ */
DefaultCompositionProvider.prototype.appliesTo = function (domainObject) { DefaultCompositionProvider.prototype.appliesTo = function (domainObject) {
return !!domainObject.composition; return !!domainObject.composition;
@ -50,8 +50,8 @@ define([
* for which to load composition * for which to load composition
* @returns {Promise.<Array.<module:openmct.DomainObject>>} a promise for * @returns {Promise.<Array.<module:openmct.DomainObject>>} a promise for
* the domain objects in this composition * the domain objects in this composition
* @memberof {module:openmct.CompositionProvider#} * @memberof module:openmct.CompositionProvider#
* @name load * @method load
*/ */
DefaultCompositionProvider.prototype.load = function (domainObject) { DefaultCompositionProvider.prototype.load = function (domainObject) {
return Promise.all(domainObject.composition.map(ObjectAPI.get)); return Promise.all(domainObject.composition.map(ObjectAPI.get));
@ -87,14 +87,7 @@ define([
); );
}; };
/**
* Check if one domain object can contain another.
* @param {module:openmct.DomainObject} domainObject the domain object
* which will act as the container
* @param {module:openmct.DomainObject} child the domain object to be
* contained
* @returns {boolean} true if this is allowed
*/
DefaultCompositionProvider.prototype.canContain = function (domainObject, child) { DefaultCompositionProvider.prototype.canContain = function (domainObject, child) {
return true; return true;
}; };
@ -102,11 +95,14 @@ define([
/** /**
* Remove a domain object from another domain object's composition. * Remove a domain object from another domain object's composition.
* *
* This method is optional; if not present, adding to a domain object's
* composition using this provider will be disallowed.
*
* @param {module:openmct.DomainObject} domainObject the domain object * @param {module:openmct.DomainObject} domainObject the domain object
* which should have its composition modified * which should have its composition modified
* @param {module:openmct.DomainObject} child the domain object to remove * @param {module:openmct.DomainObject} child the domain object to remove
* @memberof module:openmct.CompositionProvider# * @memberof module:openmct.CompositionProvider#
* @name remove * @method remove
*/ */
DefaultCompositionProvider.prototype.remove = function (domainObject, child) { DefaultCompositionProvider.prototype.remove = function (domainObject, child) {
// TODO: this needs to be synchronized via mutation // TODO: this needs to be synchronized via mutation
@ -118,11 +114,14 @@ define([
/** /**
* Add a domain object to another domain object's composition. * Add a domain object to another domain object's composition.
* *
* This method is optional; if not present, adding to a domain object's
* composition using this provider will be disallowed.
*
* @param {module:openmct.DomainObject} domainObject the domain object * @param {module:openmct.DomainObject} domainObject the domain object
* which should have its composition modified * which should have its composition modified
* @param {module:openmct.DomainObject} child the domain object to add * @param {module:openmct.DomainObject} child the domain object to add
* @memberof module:openmct.CompositionProvider# * @memberof module:openmct.CompositionProvider#
* @name add * @method add
*/ */
DefaultCompositionProvider.prototype.add = function (domainObject, child) { DefaultCompositionProvider.prototype.add = function (domainObject, child) {
// TODO: this needs to be synchronized via mutation // TODO: this needs to be synchronized via mutation

View File

@ -13,7 +13,6 @@ define([
* @param eventEmitter * @param eventEmitter
* @param object * @param object
* @interface MutableObject * @interface MutableObject
* @memberof module:openmct
*/ */
function MutableObject(object) { function MutableObject(object) {
this.object = object; this.object = object;

View File

@ -125,8 +125,8 @@ define([
/** /**
* Add a root-level object. * Add a root-level object.
* @param {module:openmct.Identifier} id the identifier of the root-level * @param {module:openmct.DomainObject} domainObject the root-level object
* object to add. * to add.
* @method addRoot * @method addRoot
* @memberof module:openmct.ObjectAPI# * @memberof module:openmct.ObjectAPI#
*/ */
@ -136,8 +136,8 @@ define([
/** /**
* Remove a root-level object. * Remove a root-level object.
* @param {module:openmct.Identifier} id the identifier of the root-level * @param {module:openmct.ObjectAPI~Identifier} id the identifier of the
* object to remove. * root-level object to remove.
* @method removeRoot * @method removeRoot
* @memberof module:openmct.ObjectAPI# * @memberof module:openmct.ObjectAPI#
*/ */
@ -151,27 +151,58 @@ define([
}; };
/** /**
* Get an interface for observing and mutating this domain object. * Modify a domain object.
* @param {module:openmct.DomainObject} object the object to mutate * @param {module:openmct.DomainObject} object the object to mutate
* @returns {module:openmct.MutableObject} an interface for mutating * @param {string} path the property to modify
* and observing this domain object * @param {*} value the new value for this property
* @method getMutable * @method mutate
* @memberof module:openmct.ObjectAPI#
*/
/**
* Observe changes to a domain object.
* @param {module:openmct.DomainObject} object the object to observe
* @param {string} path the property to observe
* @param {Function} callback a callback to invoke when new values for
* this property are observed
* @method observe
* @memberof module:openmct.ObjectAPI# * @memberof module:openmct.ObjectAPI#
*/ */
Objects.getMutable = function (object) {
return new MutableObject(object);
};
/** /**
* Uniquely identifies a domain object. * Uniquely identifies a domain object.
* *
* @typedef Identifier * @typedef Identifier
* @memberof module:openmct * @memberof module:openmct.ObjectAPI~
* @property {string} namespace the namespace to/from which this domain * @property {string} namespace the namespace to/from which this domain
* object should be loaded/stored. * object should be loaded/stored.
* @property {string} key a unique identifier for the domain object * @property {string} key a unique identifier for the domain object
* within that namespace * within that namespace
*/ */
/**
* A domain object is an entity of relevance to a user's workflow, that
* should appear as a distinct and meaningful object within the user
* interface. Examples of domain objects are folders, telemetry sensors,
* and so forth.
*
* A few common properties are defined for domain objects. Beyond these,
* individual types of domain objects may add more as they see fit.
*
* @property {module:openmct.ObjectAPI~Identifier} identifier a key/namespace pair which
* uniquely identifies this domain object
* @property {string} type the type of domain object
* @property {string} name the human-readable name for this domain object
* @property {string} [creator] the user name of the creator of this domain
* object
* @property {number} [modified] the time, in milliseconds since the UNIX
* epoch, at which this domain object was last modified
* @property {module:openmct.ObjectAPI~Identifier[]} [composition] if
* present, this will be used by the default composition provider
* to load domain objects
* @typedef DomainObject
* @memberof module:openmct
*/
return Objects; return Objects;
}); });

View File

@ -52,11 +52,50 @@ define([
FORMAT_MAP.ascii = FORMAT_MAP.ascii =
FORMAT_MAP.generic; FORMAT_MAP.generic;
/**
* Describes a property which would be found in a datum of telemetry
* associated with a particular domain object.
*
* @typedef TelemetryProperty
* @memberof module:openmct.TelemetryAPI~
* @property {string} key the name of the property in the datum which
* contains this telemetry value
* @property {string} name the human-readable name for this property
* @property {string} [units] the units associated with this property
* @property {boolean} [temporal] true if this property is a timestamp, or
* may be otherwise used to order telemetry in a time-like
* fashion; default is false
* @property {boolean} [numeric] true if the values for this property
* can be interpreted plainly as numbers; default is true
* @property {boolean} [enumerated] true if this property may have only
* certain specific values; default is false
* @property {string} [values] for enumerated states, an ordered list
* of possible values
*/
/**
* Describes and bounds requests for telemetry data.
*
* @typedef TelemetryRequest
* @memberof module:openmct.TelemetryAPI~
* @property {string} sort the key of the property to sort by. This may
* be prefixed with a "+" or a "-" sign to sort in ascending
* or descending order respectively. If no prefix is present,
* ascending order will be used.
* @property {*} start the lower bound for values of the sorting property
* @property {*} end the upper bound for values of the sorting property
* @property {string[]} strategies symbolic identifiers for strategies
* (such as `minmax`) which may be recognized by providers;
* these will be tried in order until an appropriate provider
* is found
*/
/** /**
* An interface for retrieving telemetry data associated with a domain * An interface for retrieving telemetry data associated with a domain
* object. * object.
*
* @interface TelemetryAPI * @interface TelemetryAPI
* @augments module:openmct.TelemetryAPI~TelemetryProvider
* @memberof module:openmct * @memberof module:openmct
*/ */
function TelemetryAPI( function TelemetryAPI(
@ -109,6 +148,13 @@ define([
} }
} }
/**
* A TelemetryFormatter converts telemetry values for purposes of
* display as text.
*
* @interface TelemetryFormatter
* @memberof module:openmct.TelemetryAPI~
*/
function TelemetryFormatter(domainObject) { function TelemetryFormatter(domainObject) {
this.metadata = domainObject.getCapability('telemetry').getMetadata(); this.metadata = domainObject.getCapability('telemetry').getMetadata();
this.formats = {}; this.formats = {};
@ -122,11 +168,21 @@ define([
/** /**
* Retrieve the 'key' from the datum and format it accordingly to * Retrieve the 'key' from the datum and format it accordingly to
* telemetry metadata in domain object. * telemetry metadata in domain object.
*
* @method format
* @memberof module:openmct.TelemetryAPI~TelemetryFormatter#
*/ */
TelemetryFormatter.prototype.format = function (datum, key) { TelemetryFormatter.prototype.format = function (datum, key) {
return this.formats[key](datum); return this.formats[key](datum);
}; };
/**
* A LimitEvaluator may be used to detect when telemetry values
* have exceeded nominal conditions.
*
* @interface LimitEvaluator
* @memberof module:openmct.TelemetryAPI~
*/
function LimitEvaluator(domainObject) { function LimitEvaluator(domainObject) {
this.domainObject = domainObject; this.domainObject = domainObject;
this.evaluator = domainObject.getCapability('limit'); this.evaluator = domainObject.getCapability('limit');
@ -140,6 +196,15 @@ define([
/** TODO: Do we need a telemetry parser, or do we assume telemetry /** TODO: Do we need a telemetry parser, or do we assume telemetry
is numeric by default? */ is numeric by default? */
/**
* Check if any limits have been exceeded.
*
* @param {*} datum a telemetry datum
* @param {string} key the name of the property to be evaluated
* for limit violation
* @returns {string[]} an array of limit exceedance states
* @memberof module:openmct.TelemetryAPI~TelemetryFormatter#
*/
LimitEvaluator.prototype.evaluate = function (datum, key) { LimitEvaluator.prototype.evaluate = function (datum, key) {
return this.evaluator.evaluate(datum, key); return this.evaluator.evaluate(datum, key);
}; };
@ -180,7 +245,7 @@ define([
); );
}; };
function registerProvider(provider) { function registerProvider(provider, strategy) {
// Not yet implemented. // Not yet implemented.
console.log('registering provider', provider); console.log('registering provider', provider);
} }
@ -205,55 +270,111 @@ define([
}, options); }, options);
} }
/**
* Provides telemetry data. To connect to new data sources, new
* TelemetryProvider implementations should be
* [registered]{@link module:openmct.TelemetryAPI#addProvider}.
*
* @interface TelemetryProvider
* @memberof module:openmct.TelemetryAPI~
*/
var Telemetry = { var Telemetry = {
/** /**
* Register a new telemetry provider. * Check if this provider can supply telemetry data associated with
* @method registerProvider * this domain object.
* @memberof module:openmct.TelemetryAPI# *
* @method canProvideTelemetry
* @param {module:openmct.DomainObject} domainObject the object for
* which telemetry would be provided
* @returns {boolean} true if telemetry can be provided
* @memberof module:openmct.TelemetryAPI~TelemetryProvider#
*/ */
registerProvider: registerProvider, canProvideTelemetry: function () {
},
/** /**
* Register a new limit evaluator. * Register a telemetry provider with the telemetry service. This
* @method registerEvaluator * allows you to connect alternative telemetry sources.
* @method addProvider
* @memberof module:openmct.TelemetryAPI# * @memberof module:openmct.TelemetryAPI#
* @param {module:openmct.TelemetryAPI~TelemetryProvider} provider the new
* telemetry provider
* @param {string} [strategy] the request strategy supported by
* this provider. If omitted, this will be used as a
* default provider (when no strategy is requested or no
* matching strategy is found.)
*/ */
registerEvaluator: registerEvaluator, addProvider: registerProvider,
/** /**
* Request historical telemetry data. * Request historical telemetry for a domain object.
* The `options` argument allows you to specify filters
* (start, end, etc.), sort order, and strategies for retrieving
* telemetry (aggregation, latest available, etc.).
*
* @method request * @method request
* @memberof module:openmct.TelemetryAPI# * @memberof module:openmct.TelemetryAPI~TelemetryProvider#
* @param {module:openmct.DomainObject} domainObject the object
* which has associated telemetry
* @param {module:openmct.TelemetryAPI~TelemetryRequest} options
* options for this historical request
* @returns {Promise.<object[]>} a promise for an array of
* telemetry data
*/ */
request: request, request: request,
/** /**
* Subscribe to updates to telemetry data. * Subscribe to realtime telemetry for a specific domain object.
* The callback will be called whenever data is received from a
* realtime provider.
*
* @method subscribe * @method subscribe
* @memberof module:openmct.TelemetryAPI# * @memberof module:openmct.TelemetryAPI~TelemetryProvider#
* @param {module:openmct.DomainObject} domainObject the object
* which has associated telemetry
* @param {Function} callback the callback to invoke with new data, as
* it becomes available
* @param {module:openmct.TelemetryAPI~TelemetryRequest} options
* options for this request
* @returns {Function} a function which may be called to terminate
* the subscription
*/ */
subscribe: subscribe, subscribe: subscribe,
/** /**
* Get metadata associated with telemetry for this domain object. * Get a list of all telemetry properties defined for this
* domain object.
*
* @param {module:openmct.DomainObject} domainObject the domain * @param {module:openmct.DomainObject} domainObject the domain
* object for which to request telemetry * object for which to request telemetry
* @returns {module:openmct.TelemetryAPI~TelemetryMetadata} * @returns {module:openmct.TelemetryAPI~TelemetryProperty[]}
* telemetry metadata * telemetry metadata
* @method getMetadata * @method properties
* @memberof module:openmct.TelemetryAPI# * @memberof module:openmct.TelemetryAPI~TelemetryProvider#
*/ */
getMetadata: function (domainObject) { properties: function (domainObject) {
return domainObject.getCapability('telemetry').getMetadata(); return domainObject.getCapability('telemetry').getMetadata();
}, },
/** /**
* Get a telemetry formatter for this domain object. * Telemetry formatters help you format telemetry values for
* display. Under the covers, they use telemetry metadata to
* interpret your telemetry data, and then they use the format API
* to format that data for display.
*
* This method is optional.
* If a provider does not implement this method, it is presumed
* that all telemetry associated with this domain object can
* be formatted correctly by string coercion.
*
* @param {module:openmct.DomainObject} domainObject the domain * @param {module:openmct.DomainObject} domainObject the domain
* object for which to format telemetry * object for which to format telemetry
* @returns {module:openmct.TelemetryAPI~TelemetryFormatter} * @returns {module:openmct.TelemetryAPI~TelemetryFormatter}
* @method Formatter * @method formatter
* @memberof module:openmct.TelemetryAPI# * @memberof module:openmct.TelemetryAPI~TelemetryProvider#
*/ */
Formatter: function (domainObject) { Formatter: function (domainObject) {
if (!FORMATTER_CACHE.has(domainObject)) { if (!FORMATTER_CACHE.has(domainObject)) {
@ -267,11 +388,17 @@ define([
/** /**
* Get a limit evaluator for this domain object. * Get a limit evaluator for this domain object.
* Limit Evaluators help you evaluate limit and alarm status of individual telemetry datums for display purposes without having to interact directly with the Limit API.
*
* This method is optional.
* If a provider does not implement this method, it is presumed
* that no limits are defined for this domain object's telemetry.
*
* @param {module:openmct.DomainObject} domainObject the domain * @param {module:openmct.DomainObject} domainObject the domain
* object for which to evaluate limits * object for which to evaluate limits
* @returns {module:openmct.TelemetryAPI~LimitEvaluator} * @returns {module:openmct.TelemetryAPI~LimitEvaluator}
* @method LimitEvaluator * @method limitEvaluator
* @memberof module:openmct.TelemetryAPI# * @memberof module:openmct.TelemetryAPI~TelemetryProvider#
*/ */
LimitEvaluator: function (domainObject) { LimitEvaluator: function (domainObject) {
if (!EVALUATOR_CACHE.has(domainObject)) { if (!EVALUATOR_CACHE.has(domainObject)) {

View File

@ -0,0 +1,30 @@
define([], function () {
/**
* A TypeRegistry maintains the definitions for different types
* that domain objects may have.
* @interface TypeRegistry
* @memberof module:openmct
*/
function TypeRegistry() {
}
/**
* Register a new type of view.
*
* @param {string} typeKey a string identifier for this type
* @param {module:openmct.Type} type the type to add
* @method addProvider
* @memberof module:openmct.TypeRegistry#
*/
TypeRegistry.prototype.addType = function (typeKey, type) {
};
return TypeRegistry;
});

28
src/api/ui/GestureAPI.js Normal file
View File

@ -0,0 +1,28 @@
define([], function () {
/**
* Allows support for common user actions to be attached to views.
* @interface GestureAPI
* @memberof module:openmct
*/
function GestureAPI() {
}
/**
* Designate an HTML element as selectable, and associated with a
* particular object.
*
* @param {HTMLElement} htmlElement the element to make selectable
* @param {*} item the object which should become selected when this
* element is clicked.
* @returns {Function} a function to remove selectability from this
* HTML element.
* @method selectable
* @memberof module:openmct.GestureAPI#
*/
GestureAPI.prototype.selectable = function (htmlElement, item) {
};
return GestureAPI;
});

View File

@ -0,0 +1,26 @@
define([], function () {
/**
* A ViewRegistry maintains the definitions for different kinds of views
* that may occur in different places in the user interface.
* @interface ViewRegistry
* @memberof module:openmct
*/
function ViewRegistry() {
}
/**
* Register a new type of view.
*
* @param {module:openmct.ViewProvider} provider the provider for this view
* @method addProvider
* @memberof module:openmct.ViewRegistry#
*/
ViewRegistry.prototype.addProvider = function (provider) {
};
return ViewRegistry;
});