Compare commits

..

1 Commits

Author SHA1 Message Date
Henry
4865ec5fd5 [API] Renamed TypeRegistry addType function to 'register' 2017-02-21 15:12:38 -08:00
161 changed files with 3065 additions and 2566 deletions

View File

@@ -2261,7 +2261,10 @@ The platform understands the following policy categories (specifiable as the
* `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 (first argument, `parentType`) can contain a given object (second argument, `child`).
* `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.

View File

@@ -320,7 +320,7 @@ define([
+ {
+ "key": "example.todo",
+ "name": "To-Do List",
+ "cssClass": "icon-check",
+ "cssclass": "icon-check",
+ "description": "A list of things that need to be done.",
+ "features": ["creation"]
+ }
@@ -340,7 +340,7 @@ Going through the properties we've defined:
domain objects of this type.
* The `name` of "To-Do List" is the human-readable name for this type, and will
be shown to users.
* The `cssClass` maps to an icon that will be shown for each To-Do List. The icons
* The `cssclass` maps to an icon that will be shown for each To-Do List. The icons
are defined in our [custom open MCT icon set](https://github.com/nasa/openmct/blob/master/platform/commonUI/general/res/sass/_glyphs.scss).
A complete list of available icons will be provided in the future.
* The `description` is also human-readable, and will be used whenever a longer
@@ -416,7 +416,7 @@ define([
{
"key": "example.todo",
"name": "To-Do List",
"cssClass": "icon-check",
"cssclass": "icon-check",
"description": "A list of things that need to be done.",
"features": ["creation"]
}
@@ -425,7 +425,7 @@ define([
+ {
+ "key": "example.todo",
+ "type": "example.todo",
+ "cssClass": "icon-check",
+ "cssclass": "icon-check",
+ "name": "List",
+ "templateUrl": "templates/todo.html",
+ "editable": true
@@ -447,7 +447,7 @@ the domain object type, but could have chosen any unique name.
domain objects of that type. This means that we'll see this view for To-do Lists
that we create, but not for other domain objects (such as Folders.)
* The `cssClass` and `name` properties describe the icon and human-readable name
* The `cssclass` and `name` properties describe the icon and human-readable name
for this view to display in the UI where needed (if multiple views are available
for To-do Lists, the user will be able to choose one.)
@@ -473,7 +473,7 @@ define([
{
"key": "example.todo",
"name": "To-Do List",
"cssClass": "icon-check",
"cssclass": "icon-check",
"description": "A list of things that need to be done.",
"features": ["creation"],
+ "model": {
@@ -488,7 +488,7 @@ define([
{
"key": "example.todo",
"type": "example.todo",
"cssClass": "icon-check",
"cssclass": "icon-check",
"name": "List",
"templateUrl": "templates/todo.html",
"editable": true
@@ -647,7 +647,7 @@ define([
{
"key": "example.todo",
"name": "To-Do List",
"cssClass": "icon-check",
"cssclass": "icon-check",
"description": "A list of things that need to be done.",
"features": ["creation"],
"model": {
@@ -662,7 +662,7 @@ define([
{
"key": "example.todo",
"type": "example.todo",
"cssClass": "icon-check",
"cssclass": "icon-check",
"name": "List",
"templateUrl": "templates/todo.html",
"editable": true
@@ -741,7 +741,7 @@ define([
{
"key": "example.todo",
"name": "To-Do List",
"cssClass": "icon-check",
"cssclass": "icon-check",
"description": "A list of things that need to be done.",
"features": ["creation"],
"model": {
@@ -756,7 +756,7 @@ define([
{
"key": "example.todo",
"type": "example.todo",
"cssClass": "icon-check",
"cssclass": "icon-check",
"name": "List",
"templateUrl": "templates/todo.html",
"editable": true,
@@ -766,7 +766,7 @@ define([
+ "items": [
+ {
+ "text": "Add Task",
+ "cssClass": "icon-plus",
+ "cssclass": "icon-plus",
+ "method": "addTask",
+ "control": "button"
+ }
@@ -775,7 +775,7 @@ define([
+ {
+ "items": [
+ {
+ "cssClass": "icon-trash",
+ "cssclass": "icon-trash",
+ "method": "removeTask",
+ "control": "button"
+ }
@@ -971,7 +971,7 @@ define([
{
"key": "example.todo",
"name": "To-Do List",
"cssClass": "icon-check",
"cssclass": "icon-check",
"description": "A list of things that need to be done.",
"features": ["creation"],
"model": {
@@ -986,7 +986,7 @@ define([
{
"key": "example.todo",
"type": "example.todo",
"cssClass": "icon-check",
"cssclass": "icon-check",
"name": "List",
"templateUrl": "templates/todo.html",
"editable": true,
@@ -996,7 +996,7 @@ define([
"items": [
{
"text": "Add Task",
"cssClass": "icon-plus",
"cssclass": "icon-plus",
"method": "addTask",
"control": "button"
}
@@ -1005,7 +1005,7 @@ define([
{
"items": [
{
"cssClass": "icon-trash",
"cssclass": "icon-trash",
"method": "removeTask",
"control": "button"
}
@@ -1236,7 +1236,7 @@ define([
{
"key": "example.todo",
"name": "To-Do List",
"cssClass": "icon-check",
"cssclass": "icon-check",
"description": "A list of things that need to be done.",
"features": ["creation"],
"model": {
@@ -1248,7 +1248,7 @@ define([
{
"key": "example.todo",
"type": "example.todo",
"cssClass": "icon-check",
"cssclass": "icon-check",
"name": "List",
"templateUrl": "templates/todo.html",
"editable": true,
@@ -1258,7 +1258,7 @@ define([
"items": [
{
"text": "Add Task",
"cssClass": "icon-plus",
"cssclass": "icon-plus",
"method": "addTask",
"control": "button"
}
@@ -1267,7 +1267,7 @@ define([
{
"items": [
{
"cssClass": "icon-trash",
"cssclass": "icon-trash",
"method": "removeTask",
"control": "button"
}
@@ -1374,7 +1374,7 @@ define([
{
"name": "Bar Graph",
"key": "example.bargraph",
"cssClass": "icon-autoflow-tabular",
"cssclass": "icon-autoflow-tabular",
"templateUrl": "templates/bargraph.html",
"needs": [ "telemetry" ],
"delegation": true
@@ -1677,7 +1677,7 @@ define([
{
"name": "Bar Graph",
"key": "example.bargraph",
"cssClass": "icon-autoflow-tabular",
"cssclass": "icon-autoflow-tabular",
"templateUrl": "templates/bargraph.html",
"needs": [ "telemetry" ],
"delegation": true
@@ -1843,7 +1843,7 @@ define([
{
"name": "Bar Graph",
"key": "example.bargraph",
"cssClass": "icon-autoflow-tabular",
"cssclass": "icon-autoflow-tabular",
"templateUrl": "templates/bargraph.html",
"needs": [ "telemetry" ],
"delegation": true,
@@ -2320,7 +2320,7 @@ define([
{
"name": "Spacecraft",
"key": "example.spacecraft",
"cssClass": "icon-object"
"cssclass": "icon-object"
}
],
"roots": [
@@ -2706,18 +2706,18 @@ define([
{
"name": "Spacecraft",
"key": "example.spacecraft",
"cssClass": "icon-object"
"cssclass": "icon-object"
},
+ {
+ "name": "Subsystem",
+ "key": "example.subsystem",
+ "cssClass": "icon-object",
+ "cssclass": "icon-object",
+ "model": { "composition": [] }
+ },
+ {
+ "name": "Measurement",
+ "key": "example.measurement",
+ "cssClass": "icon-telemetry",
+ "cssclass": "icon-telemetry",
+ "model": { "telemetry": {} },
+ "telemetry": {
+ "source": "example.source",
@@ -3031,18 +3031,18 @@ define([
{
"name": "Spacecraft",
"key": "example.spacecraft",
"cssClass": "icon-object"
"cssclass": "icon-object"
},
{
"name": "Subsystem",
"key": "example.subsystem",
"cssClass": "icon-object",
"cssclass": "icon-object",
"model": { "composition": [] }
},
{
"name": "Measurement",
"key": "example.measurement",
"cssClass": "icon-telemetry",
"cssclass": "icon-telemetry",
"model": { "telemetry": {} },
"telemetry": {
"source": "example.source",

View File

@@ -49,7 +49,7 @@ define([
{
"key": "eventGenerator",
"name": "Event Message Generator",
"cssClass": "icon-folder-new",
"cssclass": "icon-folder-new",
"description": "For development use. Creates sample event message data that mimics a live data stream.",
"priority": 10,
"features": "creation",

View File

@@ -36,7 +36,7 @@ define([
"name": "Export Telemetry as CSV",
"implementation": ExportTelemetryAsCSVAction,
"category": "contextual",
"cssClass": "icon-download",
"cssclass": "icon-download",
"depends": [ "exportService" ]
}
]

183
example/generator/bundle.js Normal file
View File

@@ -0,0 +1,183 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
define([
"./src/SinewaveTelemetryProvider",
"./src/SinewaveLimitCapability",
"./src/SinewaveDeltaFormat",
'legacyRegistry'
], function (
SinewaveTelemetryProvider,
SinewaveLimitCapability,
SinewaveDeltaFormat,
legacyRegistry
) {
"use strict";
legacyRegistry.register("example/generator", {
"name": "Sine Wave Generator",
"description": "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.",
"extensions": {
"components": [
{
"implementation": SinewaveTelemetryProvider,
"type": "provider",
"provides": "telemetryService",
"depends": [
"$q",
"$timeout"
]
}
],
"capabilities": [
{
"key": "limit",
"implementation": SinewaveLimitCapability
}
],
"formats": [
{
"key": "example.delta",
"implementation": SinewaveDeltaFormat
}
],
"constants": [
{
"key": "TIME_CONDUCTOR_DOMAINS",
"value": [
{
"key": "time",
"name": "Time"
},
{
"key": "yesterday",
"name": "Yesterday"
},
{
"key": "delta",
"name": "Delta",
"format": "example.delta"
}
],
"priority": -1
}
],
"types": [
{
"key": "generator",
"name": "Sine Wave Generator",
"cssclass": "icon-telemetry",
"description": "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.",
"priority": 10,
"features": "creation",
"model": {
"telemetry": {
"period": 10,
"amplitude": 1,
"offset": 0,
"dataRateInHz": 1
}
},
"telemetry": {
"source": "generator",
"domains": [
{
"key": "utc",
"name": "Time"
},
{
"key": "yesterday",
"name": "Yesterday"
},
{
"key": "delta",
"name": "Delta",
"format": "example.delta"
}
],
"ranges": [
{
"key": "sin",
"name": "Sine"
},
{
"key": "cos",
"name": "Cosine"
}
]
},
"properties": [
{
"name": "Period",
"control": "textfield",
"cssclass": "l-input-sm l-numeric",
"key": "period",
"required": true,
"property": [
"telemetry",
"period"
],
"pattern": "^\\d*(\\.\\d*)?$"
},
{
"name": "Amplitude",
"control": "textfield",
"cssclass": "l-input-sm l-numeric",
"key": "amplitude",
"required": true,
"property": [
"telemetry",
"amplitude"
],
"pattern": "^\\d*(\\.\\d*)?$"
},
{
"name": "Offset",
"control": "textfield",
"cssclass": "l-input-sm l-numeric",
"key": "offset",
"required": true,
"property": [
"telemetry",
"offset"
],
"pattern": "^\\d*(\\.\\d*)?$"
},
{
"name": "Data Rate (hz)",
"control": "textfield",
"cssclass": "l-input-sm l-numeric",
"key": "dataRateInHz",
"required": true,
"property": [
"telemetry",
"dataRateInHz"
],
"pattern": "^\\d*(\\.\\d*)?$"
}
]
}
]
}
});
});

View File

@@ -22,150 +22,163 @@
/*global define*/
define([
"./GeneratorProvider",
"./SinewaveLimitCapability",
"./SinewaveDeltaFormat"
"./src/SinewaveTelemetryProvider",
"./src/SinewaveLimitCapability",
"./src/SinewaveDeltaFormat",
'legacyRegistry'
], function (
GeneratorProvider,
SinewaveTelemetryProvider,
SinewaveLimitCapability,
SinewaveDeltaFormat
SinewaveDeltaFormat,
legacyRegistry
) {
"use strict";
var legacyExtensions = {
"capabilities": [
{
"key": "limit",
"implementation": SinewaveLimitCapability
}
],
"formats": [
{
"key": "example.delta",
"implementation": SinewaveDeltaFormat
}
],
"constants": [
{
"key": "TIME_CONDUCTOR_DOMAINS",
"value": [
{
"key": "time",
"name": "Time"
},
{
"key": "yesterday",
"name": "Yesterday"
},
{
"key": "delta",
"name": "Delta"
}
],
"priority": -1
}
]
}
return function(openmct){
//Register legacy extensions for things not yet supported by the new API
Object.keys(legacyExtensions).forEach(function (type){
var extensionsOfType = legacyExtensions[type];
extensionsOfType.forEach(function (extension) {
openmct.legacyExtension(type, extension)
})
});
openmct.types.addType("generator", {
label: "Sine Wave Generator",
description: "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.",
cssClass: "icon-telemetry",
creatable: true,
form: [
legacyRegistry.register("example/generator", {
"name": "Sine Wave Generator",
"description": "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.",
"extensions": {
"components": [
{
name: "Period",
control: "textfield",
cssClass: "l-input-sm l-numeric",
key: "period",
required: true,
property: [
"telemetry",
"period"
],
pattern: "^\\d*(\\.\\d*)?$"
},
{
name: "Amplitude",
control: "textfield",
cssClass: "l-input-sm l-numeric",
key: "amplitude",
required: true,
property: [
"telemetry",
"amplitude"
],
pattern: "^\\d*(\\.\\d*)?$"
},
{
name: "Offset",
control: "textfield",
cssClass: "l-input-sm l-numeric",
key: "offset",
required: true,
property: [
"telemetry",
"offset"
],
pattern: "^\\d*(\\.\\d*)?$"
},
{
name: "Data Rate (hz)",
control: "textfield",
cssClass: "l-input-sm l-numeric",
key: "dataRateInHz",
required: true,
property: [
"telemetry",
"dataRateInHz"
],
pattern: "^\\d*(\\.\\d*)?$"
"implementation": SinewaveTelemetryProvider,
"type": "provider",
"provides": "telemetryService",
"depends": [
"$q",
"$timeout"
]
}
],
initialize: function (object) {
object.telemetry = {
period: 10,
amplitude: 1,
offset: 0,
dataRateInHz: 1,
domains: [
"capabilities": [
{
"key": "limit",
"implementation": SinewaveLimitCapability
}
],
"formats": [
{
"key": "example.delta",
"implementation": SinewaveDeltaFormat
}
],
"constants": [
{
"key": "TIME_CONDUCTOR_DOMAINS",
"value": [
{
key: "utc",
name: "Time",
format: "utc"
"key": "time",
"name": "Time"
},
{
key: "yesterday",
name: "Yesterday",
format: "utc"
"key": "yesterday",
"name": "Yesterday"
},
{
key: "delta",
name: "Delta",
format: "example.delta"
"key": "delta",
"name": "Delta"
}
],
ranges: [
"priority": -1
}
],
"types": [
{
"key": "generator",
"name": "Sine Wave Generator",
"cssClass": "icon-telemetry",
"description": "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.",
"priority": 10,
"features": "creation",
"model": {
"telemetry": {
"period": 10,
"amplitude": 1,
"offset": 0,
"dataRateInHz": 1
}
},
"telemetry": {
"source": "generator",
"domains": [
{
"key": "utc",
"name": "Time",
"format": "utc"
},
{
"key": "yesterday",
"name": "Yesterday",
"format": "utc"
},
{
"key": "delta",
"name": "Delta",
"format": "example.delta"
}
],
"ranges": [
{
"key": "sin",
"name": "Sine"
},
{
"key": "cos",
"name": "Cosine"
}
]
},
"properties": [
{
key: "sin",
name: "Sine"
"name": "Period",
"control": "textfield",
"cssClass": "l-input-sm l-numeric",
"key": "period",
"required": true,
"property": [
"telemetry",
"period"
],
"pattern": "^\\d*(\\.\\d*)?$"
},
{
key: "cos",
name: "Cosine"
"name": "Amplitude",
"control": "textfield",
"cssClass": "l-input-sm l-numeric",
"key": "amplitude",
"required": true,
"property": [
"telemetry",
"amplitude"
],
"pattern": "^\\d*(\\.\\d*)?$"
},
{
"name": "Offset",
"control": "textfield",
"cssClass": "l-input-sm l-numeric",
"key": "offset",
"required": true,
"property": [
"telemetry",
"offset"
],
"pattern": "^\\d*(\\.\\d*)?$"
},
{
"name": "Data Rate (hz)",
"control": "textfield",
"cssClass": "l-input-sm l-numeric",
"key": "dataRateInHz",
"required": true,
"property": [
"telemetry",
"dataRateInHz"
],
"pattern": "^\\d*(\\.\\d*)?$"
}
]
};
}
});
openmct.telemetry.addProvider(new GeneratorProvider());
};
}
]
}
});
});

View File

@@ -41,10 +41,6 @@ define([
return domainObject.type === 'generator';
};
GeneratorProvider.prototype.supportsRequest =
GeneratorProvider.prototype.supportsSubscribe =
GeneratorProvider.prototype.canProvideTelemetry;
GeneratorProvider.prototype.makeWorkerRequest = function (domainObject, request) {
var props = [
'amplitude',

View File

@@ -19,7 +19,7 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
/*global define,Promise*/
define({
START_TIME: Date.now() - 24 * 60 * 60 * 1000 // Now minus a day.

View File

@@ -19,11 +19,12 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
/*global define,Promise*/
define(
['./SinewaveConstants', 'moment'],
function (SinewaveConstants, moment) {
"use strict";
var START_TIME = SinewaveConstants.START_TIME,
FORMAT_REGEX = /^-?\d+:\d+:\d+$/,

View File

@@ -24,7 +24,6 @@
(function () {
var FIFTEEN_MINUTES = 15 * 60 * 1000;
var handlers = {
subscribe: onSubscribe,
@@ -52,7 +51,6 @@
function onSubscribe(message) {
var data = message.data;
// Keep
var start = Date.now();
var step = 1000 / data.dataRateInHz;
var nextStep = start - (start % step) + step;
@@ -84,11 +82,8 @@
function onRequest(message) {
var data = message.data;
if (data.end == undefined) {
data.end = Date.now();
}
if (data.start == undefined){
data.start = data.end - FIFTEEN_MINUTES;
if (!data.start || !data.end) {
throw new Error('missing start and end!');
}
var now = Date.now();

View File

@@ -49,7 +49,7 @@ define([
{
"key": "imagery",
"name": "Example Imagery",
"cssClass": "icon-image",
"cssclass": "icon-image",
"features": "creation",
"description": "For development use. Creates example imagery data that mimics a live imagery stream.",
"priority": 10,

View File

@@ -31,7 +31,7 @@ define(['../../../platform/features/conductor/core/src/timeSystems/LocalClock'],
this.metadata = {
key: 'test-lad',
mode: 'lad',
cssClass: 'icon-clock',
cssclass: 'icon-clock',
label: 'Latest Available Data',
name: 'Latest available data',
description: 'Monitor real-time streaming data as it comes in. The Time Conductor and displays will automatically advance themselves based on a UTC clock.'

View File

@@ -41,18 +41,18 @@ define([
{
"name":"Mars Science Laboratory",
"key": "msl.curiosity",
"cssClass": "icon-object"
"cssclass": "icon-object"
},
{
"name": "Instrument",
"key": "msl.instrument",
"cssClass": "icon-object",
"cssclass": "icon-object",
"model": {"composition": []}
},
{
"name": "Measurement",
"key": "msl.measurement",
"cssClass": "icon-telemetry",
"cssclass": "icon-telemetry",
"model": {"telemetry": {}},
"telemetry": {
"source": "rems.source",

View File

@@ -81,7 +81,7 @@ define([
{
"key": "plot",
"name": "Example Telemetry Plot",
"cssClass": "icon-telemetry-panel",
"cssclass": "icon-telemetry-panel",
"description": "For development use. A plot for displaying telemetry.",
"priority": 10,
"delegates": [
@@ -129,7 +129,7 @@ define([
{
"name": "Period",
"control": "textfield",
"cssClass": "l-input-sm l-numeric",
"cssclass": "l-input-sm l-numeric",
"key": "period",
"required": true,
"property": [

View File

@@ -63,7 +63,7 @@ define(
* Get the CSS class that defines the icon
* to display in this indicator. This will appear
* as a dataflow icon.
* @returns {string} the cssClass of the dataflow icon
* @returns {string} the cssclass of the dataflow icon
*/
getCssClass: function () {
return "icon-connectivity";

View File

@@ -69,11 +69,6 @@ var gulp = require('gulp'),
}
};
if (process.env.NODE_ENV === 'development') {
options.requirejsOptimize.optimize = 'none';
}
gulp.task('scripts', function () {
var requirejsOptimize = require('gulp-requirejs-optimize');
var replace = require('gulp-replace-task');

View File

@@ -25,32 +25,20 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title></title>
<script src="openmct-tutorial/lib/http.js">
</script>
<script src="bower_components/requirejs/require.js">
</script>
<script src="openmct-tutorial/dictionary-plugin.js">
</script>
<script src="openmct-tutorial/realtime-telemetry-plugin.js">
</script>
<script src="openmct-tutorial/historical-telemetry-plugin.js">
</script>
<script>
require(['openmct'], function (openmct) {
[
'example/imagery',
'example/eventGenerator'
'example/eventGenerator',
'example/generator'
].forEach(
openmct.legacyRegistry.enable.bind(openmct.legacyRegistry)
);
openmct.install(openmct.plugins.MyItems());
openmct.install(openmct.plugins.LocalStorage());
openmct.install(openmct.plugins.Espresso());
openmct.install(openmct.plugins.Generator());
openmct.install(openmct.plugins.UTCTimeSystem());
openmct.install(DictionaryPlugin());
openmct.install(RealtimeTelemetryPlugin());
openmct.install(HistoricalTelemetryPlugin());
openmct.install(openmct.plugins.myItems);
openmct.install(openmct.plugins.localStorage);
openmct.install(openmct.plugins.espresso);
openmct.start();
});
</script>

Submodule openmct-tutorial deleted from 7076a15d3a

View File

@@ -84,11 +84,5 @@ define([
return new Main().run(defaultRegistry);
});
// For now, install conductor by default
openmct.install(openmct.plugins.Conductor({
showConductor: false
}));
return openmct;
});

View File

@@ -226,7 +226,7 @@ define([
"$window"
],
"group": "windowing",
"cssClass": "icon-new-window",
"cssclass": "icon-new-window",
"priority": "preferred"
},
{
@@ -241,7 +241,7 @@ define([
{
"key": "items",
"name": "Items",
"cssClass": "icon-thumbs-strip",
"cssclass": "icon-thumbs-strip",
"description": "Grid of available items",
"template": itemsTemplate,
"uses": [

View File

@@ -43,24 +43,24 @@ define([], function () {
return context.getParent();
}
function preventOrphanNavigation(domainObject) {
function isOrphan(domainObject) {
var parent = getParent(domainObject),
composition = parent.getModel().composition,
id = domainObject.getId();
return !composition || (composition.indexOf(id) === -1);
}
function navigateToParent(domainObject) {
var parent = getParent(domainObject);
parent.useCapability('composition')
.then(function (composees) {
var isOrphan = composees.every(function (c) {
return c.getId() !== domainObject.getId();
});
if (isOrphan) {
parent.getCapability('action').perform('navigate');
}
});
return parent.getCapability('action').perform('navigate');
}
function checkNavigation() {
var navigatedObject = navigationService.getNavigation();
if (navigatedObject.hasCapability('context')) {
if (navigatedObject.hasCapability('context') &&
isOrphan(navigatedObject)) {
if (!navigatedObject.getCapability('editor').isEditContextRoot()) {
preventOrphanNavigation(navigatedObject);
navigateToParent(navigatedObject);
}
}
}

View File

@@ -46,12 +46,12 @@ define(
};
FullscreenAction.prototype.getMetadata = function () {
// We override getMetadata, because the icon cssClass and
// We override getMetadata, because the icon cssclass and
// description need to be determined at run-time
// based on whether or not we are currently
// full screen.
var metadata = Object.create(FullscreenAction);
metadata.cssClass = screenfull.isFullscreen ? "icon-fullscreen-expand" : "icon-fullscreen-collapse";
metadata.cssclass = screenfull.isFullscreen ? "icon-fullscreen-expand" : "icon-fullscreen-collapse";
metadata.description = screenfull.isFullscreen ?
EXIT_FULLSCREEN : ENTER_FULLSCREEN;
metadata.group = "windowing";

View File

@@ -33,7 +33,7 @@ define([
mockContext,
mockActionCapability,
mockEditor,
testParentComposition,
testParentModel,
testId,
mockThrottledFns;
@@ -41,6 +41,7 @@ define([
testId = 'some-identifier';
mockThrottledFns = [];
testParentModel = {};
mockTopic = jasmine.createSpy('topic');
mockThrottle = jasmine.createSpy('throttle');
@@ -54,12 +55,14 @@ define([
mockDomainObject = jasmine.createSpyObj('domainObject', [
'getId',
'getCapability',
'getModel',
'hasCapability'
]);
mockParentObject = jasmine.createSpyObj('domainObject', [
'getId',
'getCapability',
'useCapability'
'getModel',
'hasCapability'
]);
mockContext = jasmine.createSpyObj('context', ['getParent']);
mockActionCapability = jasmine.createSpyObj('action', ['perform']);
@@ -72,7 +75,9 @@ define([
mockThrottledFns.push(mockThrottledFn);
return mockThrottledFn;
});
mockTopic.andReturn(mockMutationTopic);
mockTopic.andCallFake(function (k) {
return k === 'mutation' && mockMutationTopic;
});
mockDomainObject.getId.andReturn(testId);
mockDomainObject.getCapability.andCallFake(function (c) {
return {
@@ -83,13 +88,12 @@ define([
mockDomainObject.hasCapability.andCallFake(function (c) {
return !!mockDomainObject.getCapability(c);
});
mockParentObject.getModel.andReturn(testParentModel);
mockParentObject.getCapability.andCallFake(function (c) {
return {
action: mockActionCapability
}[c];
});
testParentComposition = [];
mockParentObject.useCapability.andReturn(Promise.resolve(testParentComposition));
mockContext.getParent.andReturn(mockParentObject);
mockNavigationService.getNavigation.andReturn(mockDomainObject);
mockEditor.isEditContextRoot.andReturn(false);
@@ -122,9 +126,7 @@ define([
var prefix = isOrphan ? "" : "non-";
describe("for " + prefix + "orphan objects", function () {
beforeEach(function () {
if (!isOrphan) {
testParentComposition.push(mockDomainObject);
}
testParentModel.composition = isOrphan ? [] : [testId];
});
[false, true].forEach(function (isEditRoot) {
@@ -134,31 +136,13 @@ define([
function itNavigatesAsExpected() {
if (isOrphan && !isEditRoot) {
it("navigates to the parent", function () {
var done = false;
waitsFor(function () {
return done;
});
setTimeout(function () {
done = true;
}, 5);
runs(function () {
expect(mockActionCapability.perform)
.toHaveBeenCalledWith('navigate');
});
expect(mockActionCapability.perform)
.toHaveBeenCalledWith('navigate');
});
} else {
it("does nothing", function () {
var done = false;
waitsFor(function () {
return done;
});
setTimeout(function () {
done = true;
}, 5);
runs(function () {
expect(mockActionCapability.perform)
.not.toHaveBeenCalled();
});
expect(mockActionCapability.perform)
.not.toHaveBeenCalled();
});
}
}
@@ -173,6 +157,7 @@ define([
mockNavigationService.addListener.mostRecentCall
.args[0](mockDomainObject);
});
itNavigatesAsExpected();
});

View File

@@ -51,7 +51,7 @@ define(
});
it("provides displayable metadata", function () {
expect(action.getMetadata().cssClass).toBeDefined();
expect(action.getMetadata().cssclass).toBeDefined();
});
});

View File

@@ -163,7 +163,7 @@ define([
],
"description": "Edit",
"category": "view-control",
"cssClass": "major icon-pencil"
"cssclass": "major icon-pencil"
},
{
"key": "properties",
@@ -172,7 +172,7 @@ define([
"view-control"
],
"implementation": PropertiesAction,
"cssClass": "major icon-pencil",
"cssclass": "major icon-pencil",
"name": "Edit Properties...",
"description": "Edit properties of this object.",
"depends": [
@@ -183,7 +183,7 @@ define([
"key": "remove",
"category": "contextual",
"implementation": RemoveAction,
"cssClass": "icon-trash",
"cssclass": "icon-trash",
"name": "Remove",
"description": "Remove this object from its containing object.",
"depends": [
@@ -195,7 +195,7 @@ define([
"category": "save",
"implementation": SaveAndStopEditingAction,
"name": "Save and Finish Editing",
"cssClass": "icon-save labeled",
"cssclass": "icon-save labeled",
"description": "Save changes made to these objects.",
"depends": [
"dialogService",
@@ -207,7 +207,7 @@ define([
"category": "save",
"implementation": SaveAction,
"name": "Save and Continue Editing",
"cssClass": "icon-save labeled",
"cssclass": "icon-save labeled",
"description": "Save changes made to these objects.",
"depends": [
"dialogService",
@@ -219,7 +219,7 @@ define([
"category": "save",
"implementation": SaveAsAction,
"name": "Save As...",
"cssClass": "icon-save labeled",
"cssclass": "icon-save labeled",
"description": "Save changes made to these objects.",
"depends": [
"$injector",
@@ -237,7 +237,7 @@ define([
// Because we use the name as label for edit buttons and mct-control buttons need
// the label to be set to undefined in order to not apply the labeled CSS rule.
"name": undefined,
"cssClass": "icon-x no-label",
"cssclass": "icon-x no-label",
"description": "Discard changes made to these objects.",
"depends": []
}

View File

@@ -25,14 +25,14 @@
<li ng-repeat="createAction in createActions" ng-click="createAction.perform()">
<a ng-mouseover="representation.activeMetadata = createAction.getMetadata()"
ng-mouseleave="representation.activeMetadata = undefined"
class="menu-item-a {{ createAction.getMetadata().cssClass }}">
class="menu-item-a {{ createAction.getMetadata().cssclass }}">
{{createAction.getMetadata().name}}
</a>
</li>
</ul>
</div>
<div class="pane right menu-item-description">
<div class="desc-area icon {{ representation.activeMetadata.cssClass }}"></div>
<div class="desc-area icon {{ representation.activeMetadata.cssclass }}"></div>
<div class="desc-area title">
{{representation.activeMetadata.name}}
</div>

View File

@@ -26,7 +26,7 @@
structure="{
text: saveActions[0].getMetadata().name,
click: actionPerformer(saveActions[0]),
cssClass: 'major ' + saveActions[0].getMetadata().cssClass
cssclass: 'major ' + saveActions[0].getMetadata().cssclass
}">
</mct-control>
</span>
@@ -36,7 +36,7 @@
structure="{
options: saveActionsAsMenuOptions,
click: saveActionMenuClickHandler,
cssClass: 'btn-bar right icon-save no-label major'
cssclass: 'btn-bar right icon-save no-label major'
}">
</mct-control>
</span>
@@ -46,7 +46,7 @@
structure="{
text: currentAction.getMetadata().name,
click: actionPerformer(currentAction),
cssClass: currentAction.getMetadata().cssClass
cssclass: currentAction.getMetadata().cssclass
}">
</mct-control>
</span>

View File

@@ -48,10 +48,9 @@ define(
* Decorate PersistenceCapability to queue persistence calls when a
* transaction is in progress.
*/
TransactionCapabilityDecorator.prototype.getCapabilities = function () {
TransactionCapabilityDecorator.prototype.getCapabilities = function (model) {
var self = this,
capabilities = this.capabilityService.getCapabilities
.apply(this.capabilityService, arguments),
capabilities = this.capabilityService.getCapabilities(model),
persistenceCapability = capabilities.persistence;
capabilities.persistence = function (domainObject) {

View File

@@ -41,7 +41,7 @@ define(
return {
key: action,
name: action.getMetadata().name,
cssClass: action.getMetadata().cssClass
cssclass: action.getMetadata().cssclass
};
}

View File

@@ -51,7 +51,7 @@ define(
function AddAction(type, parent, context, $q, dialogService, policyService) {
this.metadata = {
key: 'add',
cssClass: type.getCssClass(),
cssclass: type.getCssClass(),
name: type.getName(),
type: type.getKey(),
description: type.getDescription(),

View File

@@ -54,7 +54,8 @@ define(
AddActionProvider.prototype.getActions = function (actionContext) {
var context = actionContext || {},
key = context.key,
destination = context.domainObject;
destination = context.domainObject,
self = this;
// We only provide Add actions, and we need a
// domain object to serve as the container for the
@@ -65,16 +66,18 @@ define(
}
// Introduce one create action per type
return ['timeline', 'activity'].map(function (type) {
return this.typeService.listTypes().filter(function (type) {
return self.policyService.allow("creation", type) && self.policyService.allow("composition", destination.getCapability('type'), type);
}).map(function (type) {
return new AddAction(
this.typeService.getType(type),
type,
destination,
context,
this.$q,
this.dialogService,
this.policyService
self.$q,
self.dialogService,
self.policyService
);
}, this);
});
};
return AddActionProvider;

View File

@@ -47,7 +47,7 @@ define(
function CreateAction(type, parent, context) {
this.metadata = {
key: 'create',
cssClass: type.getCssClass(),
cssclass: type.getCssClass(),
name: type.getName(),
type: type.getKey(),
description: type.getDescription(),

View File

@@ -56,16 +56,16 @@ define(
*/
CreateWizard.prototype.getFormStructure = function (includeLocation) {
var sections = [],
domainObject = this.domainObject,
type = this.type,
policyService = this.policyService;
function validateLocation(parent) {
var parentType = parent &&
parent.getCapability('type');
return parentType && policyService.allow(
function validateLocation(locatingObject) {
var locatingType = locatingObject &&
locatingObject.getCapability('type');
return locatingType && policyService.allow(
"composition",
parentType,
domainObject
locatingType,
type
);
}
@@ -91,7 +91,7 @@ define(
if (includeLocation) {
sections.push({
name: 'Location',
cssClass: "grows",
cssclass: "grows",
rows: [{
name: "Save In",
control: "locator",

View File

@@ -28,7 +28,7 @@ define(
describe("The Edit Action controller", function () {
var mockSaveActionMetadata = {
name: "mocked-save-action",
cssClass: "mocked-save-action-css"
cssclass: "mocked-save-action-css"
};
function fakeGetActions(actionContext) {
@@ -86,7 +86,7 @@ define(
expect(menuOptions[1].key).toEqual(mockScope.saveActions[1]);
menuOptions.forEach(function (option) {
expect(option.name).toEqual(mockSaveActionMetadata.name);
expect(option.cssClass).toEqual(mockSaveActionMetadata.cssClass);
expect(option.cssclass).toEqual(mockSaveActionMetadata.cssclass);
});
});

View File

@@ -31,7 +31,9 @@ define(
var mockTypeService,
mockDialogService,
mockPolicyService,
mockTypeMap,
mockCreationPolicy,
mockCompositionPolicy,
mockPolicyMap = {},
mockTypes,
mockDomainObject,
mockQ,
@@ -53,33 +55,49 @@ define(
);
mockType.hasFeature.andReturn(true);
mockType.getName.andReturn(name);
mockType.getKey.andReturn(name);
return mockType;
}
beforeEach(function () {
mockTypeService = jasmine.createSpyObj(
"typeService",
["getType"]
["listTypes"]
);
mockDialogService = jasmine.createSpyObj(
"dialogService",
["getUserInput"]
);
mockPolicyService = jasmine.createSpyObj(
"policyService",
["allow"]
);
mockDialogService = {};
mockPolicyService = {};
mockDomainObject = {};
mockTypes = [
"timeline",
"activity",
"other"
].map(createMockType);
mockTypeMap = {};
mockDomainObject = jasmine.createSpyObj(
"domainObject",
["getCapability"]
);
//Mocking getCapability because AddActionProvider uses the
// type capability of the destination object.
mockDomainObject.getCapability.andReturn({});
mockTypes = ["A", "B", "C"].map(createMockType);
mockTypes.forEach(function (type) {
mockTypeMap[type.getKey()] = type;
mockPolicyMap[type.getName()] = true;
});
mockTypeService.getType.andCallFake(function (key) {
return mockTypeMap[key];
});
mockCreationPolicy = function (type) {
return mockPolicyMap[type.getName()];
};
mockCompositionPolicy = function () {
return true;
};
mockPolicyService.allow.andReturn(true);
mockTypeService.listTypes.andReturn(mockTypes);
provider = new AddActionProvider(
mockQ,
@@ -89,16 +107,29 @@ define(
);
});
it("provides actions for timeline and activity", function () {
var actions = provider.getActions({
it("checks for creatability", function () {
provider.getActions({
key: "add",
domainObject: mockDomainObject
});
expect(actions.length).toBe(2);
expect(actions[0].metadata.type).toBe('timeline');
expect(actions[1].metadata.type).toBe('activity');
// Make sure it was creation which was used to check
expect(mockPolicyService.allow)
.toHaveBeenCalledWith("creation", mockTypes[0]);
});
it("checks for composability of type", function () {
provider.getActions({
key: "add",
domainObject: mockDomainObject
});
expect(mockPolicyService.allow).toHaveBeenCalledWith(
"composition",
jasmine.any(Object),
jasmine.any(Object)
);
expect(mockDomainObject.getCapability).toHaveBeenCalledWith('type');
});
});
}

View File

@@ -138,7 +138,7 @@ define(
expect(metadata.name).toEqual("Test");
expect(metadata.description).toEqual("a test type");
expect(metadata.cssClass).toEqual("icon-telemetry");
expect(metadata.cssclass).toEqual("icon-telemetry");
});
describe("the perform function", function () {

View File

@@ -175,7 +175,7 @@ define(
expect(mockPolicyService.allow).toHaveBeenCalledWith(
'composition',
mockOtherType,
mockDomainObject
mockType
);
});

View File

@@ -19,7 +19,6 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
$output-bourbon-deprecation-warnings: false;
@import "bourbon";
@import "logo-and-bg";

View File

@@ -19,7 +19,7 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<a class="s-button key-{{parameters.action.getMetadata().key}} {{parameters.action.getMetadata().cssClass}}"
<a class="s-button key-{{parameters.action.getMetadata().key}} {{parameters.action.getMetadata().cssclass}}"
ng-class="{ labeled: parameters.labeled }"
title="{{parameters.action.getMetadata().description}}"
ng-click="parameters.action.perform()">

View File

@@ -20,7 +20,7 @@
at runtime from the About dialog for additional information.
-->
<span ng-controller="ViewSwitcherController">
<div class="view-switcher menu-element s-menu-button {{ngModel.selected.cssClass}}"
<div class="view-switcher menu-element s-menu-button {{ngModel.selected.cssclass}}"
ng-if="view.length > 1"
ng-controller="ClickAwayController as toggle">
@@ -33,7 +33,7 @@
<ul>
<li ng-repeat="option in view"
ng-click="ngModel.selected = option; toggle.setState(false)"
class="{{option.cssClass}}">
class="{{option.cssclass}}">
{{option.name}}
</li>
</ul>

View File

@@ -25,7 +25,7 @@
<li ng-repeat="menuAction in menuActions"
ng-click="menuAction.perform()"
title="{{menuAction.getMetadata().description}}"
class="{{menuAction.getMetadata().cssClass}}">
class="{{menuAction.getMetadata().cssclass}}">
{{menuAction.getMetadata().name}}
</li>
</ul>

View File

@@ -19,7 +19,7 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
$output-bourbon-deprecation-warnings: false;
@import "bourbon";
@import "../../../../general/res/sass/_mixins";

View File

@@ -19,7 +19,7 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
$output-bourbon-deprecation-warnings: false;
@import "bourbon";
@import "../../../../general/res/sass/_mixins";

View File

@@ -40,6 +40,9 @@ define([
{
"category": "composition",
"implementation": CompositionPolicy,
"depends": [
"$injector"
],
"message": "Objects of this type cannot contain objects of that type."
},
{

View File

@@ -0,0 +1,77 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
[],
function () {
/**
* Build a table indicating which types are expected to expose
* which capabilities. This supports composition policy (rules
* for which objects can contain which other objects) which
* sometimes is determined based on the presence of capabilities.
* @constructor
* @memberof platform/containment
*/
function CapabilityTable(typeService, capabilityService) {
var self = this;
// Build an initial model for a type
function buildModel(type) {
var model = Object.create(type.getInitialModel() || {});
model.type = type.getKey();
return model;
}
// Get capabilities expected for this type
function getCapabilities(type) {
return capabilityService.getCapabilities(buildModel(type));
}
// Populate the lookup table for this type's capabilities
function addToTable(type) {
var typeKey = type.getKey();
Object.keys(getCapabilities(type)).forEach(function (key) {
self.table[key] = self.table[key] || {};
self.table[key][typeKey] = true;
});
}
// Build the table
this.table = {};
(typeService.listTypes() || []).forEach(addToTable);
}
/**
* Check if a type is expected to expose a specific capability.
* @param {string} typeKey the type identifier
* @param {string} capabilityKey the capability identifier
* @returns {boolean} true if expected to be exposed
*/
CapabilityTable.prototype.hasCapability = function (typeKey, capabilityKey) {
return (this.table[capabilityKey] || {})[typeKey];
};
return CapabilityTable;
}
);

View File

@@ -45,7 +45,9 @@ define(
ComposeActionPolicy.prototype.allowComposition = function (containerObject, selectedObject) {
// Get the object types involved in the compose action
var containerType = containerObject &&
containerObject.getCapability('type');
containerObject.getCapability('type'),
selectedType = selectedObject &&
selectedObject.getCapability('type');
// Get a reference to the policy service if needed...
this.policyService = this.policyService || this.getPolicyService();
@@ -55,7 +57,7 @@ define(
this.policyService.allow(
'composition',
containerType,
selectedObject
selectedType
);
};

View File

@@ -26,8 +26,8 @@
* @namespace platform/containment
*/
define(
[],
function () {
['./ContainmentTable'],
function (ContainmentTable) {
/**
* Defines composition policy as driven by type metadata.
@@ -35,33 +35,21 @@ define(
* @memberof platform/containment
* @implements {Policy.<Type, Type>}
*/
function CompositionPolicy() {
function CompositionPolicy($injector) {
// We're really just wrapping the containment table and rephrasing
// it as a policy decision.
var table;
this.getTable = function () {
return (table = table || new ContainmentTable(
$injector.get('typeService'),
$injector.get('capabilityService')
));
};
}
CompositionPolicy.prototype.allow = function (parentType, child) {
var parentDef = parentType.getDefinition();
// A parent without containment rules can contain anything.
if (!parentDef.contains) {
return true;
}
// If any containment rule matches context type, the candidate
// can contain this type.
return parentDef.contains.some(function (c) {
// Simple containment rules are supported typeKeys.
if (typeof c === 'string') {
return c === child.getCapability('type').getKey();
}
// More complicated rules require context to have all specified
// capabilities.
if (!Array.isArray(c.has)) {
c.has = [c.has];
}
return c.has.every(function (capability) {
return child.hasCapability(capability);
});
});
CompositionPolicy.prototype.allow = function (candidate, context) {
return this.getTable().canContain(candidate, context);
};
return CompositionPolicy;

View File

@@ -0,0 +1,116 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
['./CapabilityTable'],
function (CapabilityTable) {
// Symbolic value for the type table for cases when any type
// is allowed to be contained.
var ANY = true;
/**
* Supports composition policy by maintaining a table of
* domain object types, to determine if they can contain
* other domain object types. This is determined at application
* start time (plug-in support means this cannot be determined
* prior to that, but we don't want to redo these calculations
* every time policy is checked.)
* @constructor
* @memberof platform/containment
*/
function ContainmentTable(typeService, capabilityService) {
var self = this,
types = typeService.listTypes(),
capabilityTable = new CapabilityTable(typeService, capabilityService);
// Add types which have all these capabilities to the set
// of allowed types
function addToSetByCapability(set, has) {
has = Array.isArray(has) ? has : [has];
types.forEach(function (type) {
var typeKey = type.getKey();
set[typeKey] = has.map(function (capabilityKey) {
return capabilityTable.hasCapability(typeKey, capabilityKey);
}).reduce(function (a, b) {
return a && b;
}, true);
});
}
// Add this type (or type description) to the set of allowed types
function addToSet(set, type) {
// Is this a simple case of an explicit type identifier?
if (typeof type === 'string') {
// If so, add it to the set of allowed types
set[type] = true;
} else {
// Otherwise, populate that set based on capabilities
addToSetByCapability(set, (type || {}).has || []);
}
}
// Add to the lookup table for this type
function addToTable(type) {
var key = type.getKey(),
definition = type.getDefinition() || {},
contains = definition.contains;
// Check for defined containment restrictions
if (contains === undefined) {
// If not, accept anything
self.table[key] = ANY;
} else {
// Start with an empty set...
self.table[key] = {};
// ...cast accepted types to array if necessary...
contains = Array.isArray(contains) ? contains : [contains];
// ...and add all containment rules to that set
contains.forEach(function (c) {
addToSet(self.table[key], c);
});
}
}
// Build the table
this.table = {};
types.forEach(addToTable);
}
/**
* Check if domain objects of one type can contain domain
* objects of another type.
* @param {Type} containerType type of the containing domain object
* @param {Type} containedType type of the domain object
* to be contained
* @returns {boolean} true if allowable
*/
ContainmentTable.prototype.canContain = function (containerType, containedType) {
var set = this.table[containerType.getKey()] || {};
// Recognize either the symbolic value for "can contain
// anything", or lookup the specific type from the set.
return (set === ANY) || set[containedType.getKey()];
};
return ContainmentTable;
}
);

View File

@@ -0,0 +1,85 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
["../src/CapabilityTable"],
function (CapabilityTable) {
describe("Composition policy's capability table", function () {
var mockTypeService,
mockCapabilityService,
mockTypes,
table;
beforeEach(function () {
mockTypeService = jasmine.createSpyObj(
'typeService',
['listTypes']
);
mockCapabilityService = jasmine.createSpyObj(
'capabilityService',
['getCapabilities']
);
// Both types can only contain b, let's say
mockTypes = ['a', 'b'].map(function (type) {
var mockType = jasmine.createSpyObj(
'type-' + type,
['getKey', 'getDefinition', 'getInitialModel']
);
mockType.getKey.andReturn(type);
// Return a model to drive apparent capabilities
mockType.getInitialModel.andReturn({ id: type });
return mockType;
});
mockTypeService.listTypes.andReturn(mockTypes);
mockCapabilityService.getCapabilities.andCallFake(function (model) {
var capabilities = {};
capabilities[model.id + '-capability'] = true;
return capabilities;
});
table = new CapabilityTable(
mockTypeService,
mockCapabilityService
);
});
it("provides for lookup of capabilities by type", function () {
// Based on initial model, should report the presence
// of particular capabilities - suffixed above with -capability
expect(table.hasCapability('a', 'a-capability'))
.toBeTruthy();
expect(table.hasCapability('a', 'b-capability'))
.toBeFalsy();
expect(table.hasCapability('a', 'c-capability'))
.toBeFalsy();
expect(table.hasCapability('b', 'a-capability'))
.toBeFalsy();
expect(table.hasCapability('b', 'b-capability'))
.toBeTruthy();
expect(table.hasCapability('b', 'c-capability'))
.toBeFalsy();
});
});
}
);

View File

@@ -79,7 +79,7 @@ define(
expect(mockPolicyService.allow).toHaveBeenCalledWith(
'composition',
mockTypes[0],
mockDomainObjects[1]
mockTypes[1]
);
});

View File

@@ -24,94 +24,60 @@ define(
["../src/CompositionPolicy"],
function (CompositionPolicy) {
describe("Composition policy", function () {
var typeA,
typeB,
typeC,
mockChildObject,
var mockInjector,
mockTypeService,
mockCapabilityService,
mockTypes,
policy;
beforeEach(function () {
typeA = jasmine.createSpyObj(
'type A-- the particular kind',
['getKey', 'getDefinition']
mockInjector = jasmine.createSpyObj('$injector', ['get']);
mockTypeService = jasmine.createSpyObj(
'typeService',
['listTypes']
);
typeA.getKey.andReturn('a');
typeA.getDefinition.andReturn({
contains: ['a']
mockCapabilityService = jasmine.createSpyObj(
'capabilityService',
['getCapabilities']
);
// Both types can only contain b, let's say
mockTypes = ['a', 'b'].map(function (type) {
var mockType = jasmine.createSpyObj(
'type-' + type,
['getKey', 'getDefinition', 'getInitialModel']
);
mockType.getKey.andReturn(type);
mockType.getDefinition.andReturn({
contains: ['b']
});
mockType.getInitialModel.andReturn({});
return mockType;
});
typeB = jasmine.createSpyObj(
'type B-- anything goes',
['getKey', 'getDefinition']
);
typeB.getKey.andReturn('b');
typeB.getDefinition.andReturn({
contains: ['a', 'b']
mockInjector.get.andCallFake(function (name) {
return {
typeService: mockTypeService,
capabilityService: mockCapabilityService
}[name];
});
typeC = jasmine.createSpyObj(
'type C-- distinguishing and interested in telemetry',
['getKey', 'getDefinition']
);
typeC.getKey.andReturn('c');
typeC.getDefinition.andReturn({
contains: [{has: 'telemetry'}]
});
mockTypeService.listTypes.andReturn(mockTypes);
mockCapabilityService.getCapabilities.andReturn({});
mockChildObject = jasmine.createSpyObj(
'childObject',
['getCapability', 'hasCapability']
);
policy = new CompositionPolicy();
policy = new CompositionPolicy(mockInjector);
});
describe('enforces simple containment rules', function () {
it('allows when type matches', function () {
mockChildObject.getCapability.andReturn(typeA);
expect(policy.allow(typeA, mockChildObject))
.toBeTruthy();
expect(policy.allow(typeB, mockChildObject))
.toBeTruthy();
mockChildObject.getCapability.andReturn(typeB);
expect(policy.allow(typeB, mockChildObject))
.toBeTruthy();
});
it('disallows when type doesn\'t match', function () {
mockChildObject.getCapability.andReturn(typeB);
expect(policy.allow(typeA, mockChildObject))
.toBeFalsy();
mockChildObject.getCapability.andReturn(typeC);
expect(policy.allow(typeA, mockChildObject))
.toBeFalsy();
});
});
describe('enforces capability-based containment rules', function () {
it('allows when object has capability', function () {
mockChildObject.hasCapability.andReturn(true);
expect(policy.allow(typeC, mockChildObject))
.toBeTruthy();
expect(mockChildObject.hasCapability)
.toHaveBeenCalledWith('telemetry');
});
it('skips when object doesn\'t have capability', function () {
mockChildObject.hasCapability.andReturn(false);
expect(policy.allow(typeC, mockChildObject))
.toBeFalsy();
expect(mockChildObject.hasCapability)
.toHaveBeenCalledWith('telemetry');
});
// Test basic composition policy here; test more closely at
// the unit level in ContainmentTable for 'has' support, et al
it("enforces containment rules defined by types", function () {
expect(policy.allow(mockTypes[0], mockTypes[1]))
.toBeTruthy();
expect(policy.allow(mockTypes[1], mockTypes[1]))
.toBeTruthy();
expect(policy.allow(mockTypes[1], mockTypes[0]))
.toBeFalsy();
expect(policy.allow(mockTypes[0], mockTypes[0]))
.toBeFalsy();
});
});

View File

@@ -0,0 +1,96 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2016, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
["../src/ContainmentTable"],
function (ContainmentTable) {
describe("Composition policy's containment table", function () {
var mockTypeService,
mockCapabilityService,
mockTypes,
table;
beforeEach(function () {
mockTypeService = jasmine.createSpyObj(
'typeService',
['listTypes']
);
mockCapabilityService = jasmine.createSpyObj(
'capabilityService',
['getCapabilities']
);
// Both types can only contain b, let's say
mockTypes = ['a', 'b', 'c'].map(function (type, index) {
var mockType = jasmine.createSpyObj(
'type-' + type,
['getKey', 'getDefinition', 'getInitialModel']
);
mockType.getKey.andReturn(type);
mockType.getDefinition.andReturn({
// First two contain objects with capability 'b';
// third one defines no containership rules
contains: (index < 2) ? [{ has: 'b' }] : undefined
});
// Return a model to drive apparent capabilities
mockType.getInitialModel.andReturn({ id: type });
return mockType;
});
mockTypeService.listTypes.andReturn(mockTypes);
mockCapabilityService.getCapabilities.andCallFake(function (model) {
var capabilities = {};
capabilities[model.id] = true;
return capabilities;
});
table = new ContainmentTable(
mockTypeService,
mockCapabilityService
);
});
// The plain type case is tested in CompositionPolicySpec,
// so just test for special syntax ('has', or no contains rules) here
it("enforces 'has' containment rules related to capabilities", function () {
expect(table.canContain(mockTypes[0], mockTypes[1]))
.toBeTruthy();
expect(table.canContain(mockTypes[1], mockTypes[1]))
.toBeTruthy();
expect(table.canContain(mockTypes[1], mockTypes[0]))
.toBeFalsy();
expect(table.canContain(mockTypes[0], mockTypes[0]))
.toBeFalsy();
});
it("allows anything when no containership rules are defined", function () {
expect(table.canContain(mockTypes[2], mockTypes[0]))
.toBeTruthy();
expect(table.canContain(mockTypes[2], mockTypes[1]))
.toBeTruthy();
expect(table.canContain(mockTypes[2], mockTypes[2]))
.toBeTruthy();
});
});
}
);

View File

@@ -241,7 +241,7 @@ define([
"property": "name",
"pattern": "\\S+",
"required": true,
"cssClass": "l-input-lg"
"cssclass": "l-input-lg"
},
{
"name": "Notes",
@@ -249,19 +249,19 @@ define([
"property": "notes",
"control": "textarea",
"required": false,
"cssClass": "l-textarea-sm"
"cssclass": "l-textarea-sm"
}
]
},
{
"key": "root",
"name": "Root",
"cssClass": "icon-folder"
"cssclass": "icon-folder"
},
{
"key": "folder",
"name": "Folder",
"cssClass": "icon-folder",
"cssclass": "icon-folder",
"features": "creation",
"description": "Create folders to organize other objects or links to objects.",
"priority": 1000,
@@ -272,11 +272,11 @@ define([
{
"key": "unknown",
"name": "Unknown Type",
"cssClass": "icon-object-unknown"
"cssclass": "icon-object-unknown"
},
{
"name": "Unknown Type",
"cssClass": "icon-object-unknown"
"cssclass": "icon-object-unknown"
}
],
"capabilities": [

View File

@@ -58,7 +58,7 @@ define(
* @property {string} key machine-readable identifier for this action
* @property {string} name human-readable name for this action
* @property {string} description human-readable description
* @property {string} cssClass CSS class for icon
* @property {string} cssclass CSS class for icon
* @property {ActionContext} context the context in which the action
* will be performed.
*/

View File

@@ -53,10 +53,10 @@ define(
*/
function CoreCapabilityProvider(capabilities, $log) {
// Filter by invoking the capability's appliesTo method
function filterCapabilities(model, id) {
function filterCapabilities(model) {
return capabilities.filter(function (capability) {
return capability.appliesTo ?
capability.appliesTo(model, id) :
capability.appliesTo(model) :
true;
});
}
@@ -75,8 +75,8 @@ define(
return result;
}
function getCapabilities(model, id) {
return packageCapabilities(filterCapabilities(model, id));
function getCapabilities(model) {
return packageCapabilities(filterCapabilities(model));
}
return {

View File

@@ -56,12 +56,12 @@ define(
* @method Type#getDescription
*/
/**
* Get the cssClass associated with this type. cssClass is a
* Get the cssclass associated with this type. cssclass is a
* string which will appear as an icon (when
* displayed in an appropriate font) which visually
* distinguish types from one another.
*
* @returns {string} the cssClass for this type
* @returns {string} the cssclass for this type
* @method Type#getCssClass
*/
/**
@@ -145,7 +145,7 @@ define(
};
TypeImpl.prototype.getCssClass = function () {
return this.typeDef.cssClass;
return this.typeDef.cssclass;
};
TypeImpl.prototype.getProperties = function () {

View File

@@ -33,7 +33,7 @@ define(
key: 'test-type',
name: 'Test Type',
description: 'A type, for testing',
cssClass: 'icon-telemetry-panel',
cssclass: 'icon-telemetry-panel',
inherits: ['test-parent-1', 'test-parent-2'],
features: ['test-feature-1'],
properties: [{}],

View File

@@ -30,18 +30,18 @@ define(
testTypeDefinitions = [
{
key: 'basic',
cssClass: "icon-magnify-in",
cssclass: "icon-magnify-in",
name: "Basic Type"
},
{
key: 'multi1',
cssClass: "icon-trash",
cssclass: "icon-trash",
description: "Multi1 Description",
capabilities: ['a1', 'b1']
},
{
key: 'multi2',
cssClass: "icon-magnify-out",
cssclass: "icon-magnify-out",
capabilities: ['a2', 'b2', 'c2']
},
{

View File

@@ -66,7 +66,7 @@ define([
"key": "move",
"name": "Move",
"description": "Move object to another location.",
"cssClass": "icon-move",
"cssclass": "icon-move",
"category": "contextual",
"implementation": MoveAction,
"depends": [
@@ -79,7 +79,7 @@ define([
"key": "copy",
"name": "Duplicate",
"description": "Duplicate object to another location.",
"cssClass": "icon-duplicate",
"cssclass": "icon-duplicate",
"category": "contextual",
"implementation": CopyAction,
"depends": [
@@ -95,7 +95,7 @@ define([
"key": "link",
"name": "Create Link",
"description": "Create Link to object in another location.",
"cssClass": "icon-link",
"cssclass": "icon-link",
"category": "contextual",
"implementation": LinkAction,
"depends": [
@@ -108,7 +108,7 @@ define([
"key": "follow",
"name": "Go To Original",
"description": "Go to the original, un-linked instance of this object.",
"cssClass": "",
"cssclass": "",
"category": "contextual",
"implementation": GoToOriginalAction
},
@@ -116,7 +116,7 @@ define([
"key": "locate",
"name": "Set Primary Location",
"description": "Set a domain object's primary location.",
"cssClass": "",
"cssclass": "",
"category": "contextual",
"implementation": SetPrimaryLocationAction
}

View File

@@ -48,7 +48,7 @@ define(
return this.policyService.allow(
"composition",
parentCandidate.getCapability('type'),
object
object.getCapability('type')
);
};

View File

@@ -52,7 +52,7 @@ define(
return this.policyService.allow(
"composition",
parentCandidate.getCapability('type'),
object
object.getCapability('type')
);
};

View File

@@ -58,7 +58,7 @@ define(
sections: [
{
name: 'Location',
cssClass: "grows",
cssclass: "grows",
rows: [
{
name: label,

View File

@@ -56,7 +56,7 @@ define(
return this.policyService.allow(
"composition",
parentCandidate.getCapability('type'),
object
object.getCapability('type')
);
};

View File

@@ -104,7 +104,7 @@ define(
expect(policyService.allow).toHaveBeenCalledWith(
"composition",
parentCandidate.capabilities.type,
object
object.capabilities.type
);
});

View File

@@ -114,7 +114,7 @@ define(
expect(mockPolicyService.allow).toHaveBeenCalledWith(
"composition",
parentCandidate.capabilities.type,
object
object.capabilities.type
);
});

View File

@@ -124,7 +124,7 @@ define(
expect(policyService.allow).toHaveBeenCalledWith(
"composition",
parentCandidate.capabilities.type,
object
object.capabilities.type
);
});

View File

@@ -136,7 +136,7 @@ define([
],
"category": "contextual",
"name": "Start",
"cssClass": "icon-play",
"cssclass": "icon-play",
"priority": "preferred"
},
{
@@ -147,7 +147,7 @@ define([
],
"category": "contextual",
"name": "Restart at 0",
"cssClass": "icon-refresh",
"cssclass": "icon-refresh",
"priority": "preferred"
}
],
@@ -155,7 +155,7 @@ define([
{
"key": "clock",
"name": "Clock",
"cssClass": "icon-clock",
"cssclass": "icon-clock",
"description": "A UTC-based clock that supports a variety of display formats. Clocks can be added to Display Layouts.",
"priority": 101,
"features": [
@@ -183,7 +183,7 @@ define([
"name": "hh:mm:ss"
}
],
"cssClass": "l-inline"
"cssclass": "l-inline"
},
{
"control": "select",
@@ -197,7 +197,7 @@ define([
"name": "24hr"
}
],
"cssClass": "l-inline"
"cssclass": "l-inline"
}
]
}
@@ -212,7 +212,7 @@ define([
{
"key": "timer",
"name": "Timer",
"cssClass": "icon-timer",
"cssclass": "icon-timer",
"description": "A timer that counts up or down to a datetime. Timers can be started, stopped and reset whenever needed, and support a variety of display formats. Each Timer displays the same value to all users. Timers can be added to Display Layouts.",
"priority": 100,
"features": [

View File

@@ -131,11 +131,11 @@ define(
/**
* Get the CSS class to display the right icon
* for the start/restart button.
* @returns {string} cssClass to display
* @returns {string} cssclass to display
*/
TimerController.prototype.buttonCssClass = function () {
return this.relevantAction ?
this.relevantAction.getMetadata().cssClass : "";
this.relevantAction.getMetadata().cssclass : "";
};
/**

View File

@@ -85,8 +85,8 @@ define(
'timer.restart': mockRestart
}[k]];
});
mockStart.getMetadata.andReturn({ cssClass: "icon-play", name: "Start" });
mockRestart.getMetadata.andReturn({ cssClass: "icon-refresh", name: "Restart" });
mockStart.getMetadata.andReturn({ cssclass: "icon-play", name: "Start" });
mockRestart.getMetadata.andReturn({ cssclass: "icon-refresh", name: "Restart" });
mockScope.domainObject = mockDomainObject;
testModel = {};
@@ -144,7 +144,7 @@ define(
expect(controller.text()).toEqual("0D 00:00:00");
});
it("shows cssClass & name for the applicable start/restart action", function () {
it("shows cssclass & name for the applicable start/restart action", function () {
invokeWatch('domainObject', mockDomainObject);
expect(controller.buttonCssClass()).toEqual("icon-play");
expect(controller.buttonText()).toEqual("Start");

View File

@@ -21,9 +21,11 @@
*****************************************************************************/
define([
"./src/ConductorTelemetryDecorator",
"./src/ConductorRepresenter",
'legacyRegistry'
], function (
ConductorTelemetryDecorator,
ConductorRepresenter,
legacyRegistry
) {
@@ -37,6 +39,16 @@ define([
"openmct"
]
}
],
"components": [
{
"type": "decorator",
"provides": "telemetryService",
"implementation": ConductorTelemetryDecorator,
"depends": [
"openmct"
]
}
]
}
});

View File

@@ -0,0 +1,87 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
function () {
/**
* Decorates the `telemetryService` such that requests are
* mediated by the time conductor. This is a modified version of the
* decorator used in the old TimeConductor that integrates with the
* new TimeConductor API.
*
* @constructor
* @memberof platform/features/conductor
* @implements {TelemetryService}
* @param {platform/features/conductor.TimeConductor} conductor
* the service which exposes the global time conductor
* @param {TelemetryService} telemetryService the decorated service
*/
function ConductorTelemetryDecorator(openmct, telemetryService) {
this.conductor = openmct.conductor;
this.telemetryService = telemetryService;
this.amendRequests = ConductorTelemetryDecorator.prototype.amendRequests.bind(this);
}
function amendRequest(request, bounds, timeSystem) {
request = request || {};
request.start = bounds.start;
request.end = bounds.end;
request.domain = timeSystem.metadata.key;
return request;
}
ConductorTelemetryDecorator.prototype.amendRequests = function (requests) {
var bounds = this.conductor.bounds(),
timeSystem = this.conductor.timeSystem();
return (requests || []).map(function (request) {
return amendRequest(request, bounds, timeSystem);
});
};
ConductorTelemetryDecorator.prototype.requestTelemetry = function (requests) {
return this.telemetryService
.requestTelemetry(this.amendRequests(requests));
};
ConductorTelemetryDecorator.prototype.subscribe = function (callback, requests) {
var unsubscribeFunc = this.telemetryService.subscribe(callback, this.amendRequests(requests)),
conductor = this.conductor,
self = this;
function amendRequests() {
return self.amendRequests(requests);
}
conductor.on('bounds', amendRequests);
return function () {
unsubscribeFunc();
conductor.off('bounds', amendRequests);
};
};
return ConductorTelemetryDecorator;
}
);

View File

@@ -70,9 +70,8 @@ define([
"$location",
"openmct",
"timeConductorViewService",
"formatService",
"DEFAULT_TIMECONDUCTOR_MODE",
"SHOW_TIMECONDUCTOR"
"timeSystems[]",
"formatService"
]
},
{
@@ -151,13 +150,6 @@ define([
"link": "https://github.com/d3/d3/blob/master/LICENSE"
}
],
"constants": [
{
"key": "DEFAULT_TIMECONDUCTOR_MODE",
"value": "realtime",
"priority": "fallback"
}
],
"formats": [
{
"key": "number",

View File

@@ -19,7 +19,6 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
$output-bourbon-deprecation-warnings: false;
@import "bourbon";
@import "../../../../../commonUI/general/res/sass/constants";
@import "../../../../../commonUI/general/res/sass/mixins";

View File

@@ -19,7 +19,6 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
$output-bourbon-deprecation-warnings: false;
@import "bourbon";
@import "../../../../../commonUI/general/res/sass/constants";
@import "../../../../../commonUI/general/res/sass/mixins";

View File

@@ -26,7 +26,7 @@
ng-click="ngModel.selectedKey=key">
<a ng-mouseover="ngModel.activeMetadata = metadata"
ng-mouseleave="ngModel.activeMetadata = undefined"
class="menu-item-a {{metadata.cssClass}}">
class="menu-item-a {{metadata.cssclass}}">
{{metadata.name}}
</a>
</li>
@@ -34,7 +34,7 @@
</div>
<div class="pane right menu-item-description">
<div
class="desc-area ui-symbol icon type-icon {{ngModel.activeMetadata.cssClass}}"></div>
class="desc-area ui-symbol icon type-icon {{ngModel.activeMetadata.cssclass}}"></div>
<div class="desc-area title">
{{ngModel.activeMetadata.name}}
</div>

View File

@@ -1,7 +1,8 @@
<!-- Parent holder for time conductor. follow-mode | fixed-mode -->
<div ng-controller="TimeConductorController as tcController"
class="holder grows flex-elem l-flex-row l-time-conductor {{modeModel.selectedKey}}-mode {{timeSystemModel.selected.metadata.key}}-time-system"
ng-class="{'status-panning': tcController.panning}" ng-show="showTimeConductor">
ng-class="{'status-panning': tcController.panning}">
<div class="flex-elem holder time-conductor-icon">
<div class="hand-little"></div>
<div class="hand-big"></div>

View File

@@ -31,7 +31,7 @@ define(['./TickSource'], function (TickSource) {
this.metadata = {
key: 'local',
mode: 'realtime',
cssClass: 'icon-clock',
cssclass: 'icon-clock',
label: 'Real-time',
name: 'Real-time Mode',
description: 'Monitor real-time streaming data as it comes in. The Time Conductor and displays will automatically advance themselves based on a UTC clock.'

View File

@@ -40,16 +40,7 @@ define(
* @memberof platform.features.conductor
* @constructor
*/
function TimeConductorController(
$scope,
$window,
$location,
openmct,
conductorViewService,
formatService,
DEFAULT_MODE,
SHOW_TIMECONDUCTOR
) {
function TimeConductorController($scope, $window, $location, openmct, conductorViewService, timeSystems, formatService) {
var self = this;
@@ -69,14 +60,10 @@ define(
this.validation = new TimeConductorValidation(this.conductor);
this.formatService = formatService;
//Check if the default mode defined is actually available
if (this.modes[DEFAULT_MODE] === undefined) {
DEFAULT_MODE = 'fixed';
}
this.DEFAULT_MODE = DEFAULT_MODE;
// Construct the provided time system definitions
this.timeSystems = conductorViewService.systems;
this.timeSystems = timeSystems.map(function (timeSystemConstructor) {
return timeSystemConstructor();
});
this.initializeScope();
var searchParams = JSON.parse(JSON.stringify(this.$location.search()));
@@ -107,8 +94,6 @@ define(
//Respond to any subsequent conductor changes
this.conductor.on('bounds', this.changeBounds);
this.conductor.on('timeSystem', this.changeTimeSystem);
this.$scope.showTimeConductor = SHOW_TIMECONDUCTOR;
}
/**
@@ -154,7 +139,7 @@ define(
//Set mode from url if changed
if (searchParams[SEARCH.MODE] === undefined ||
searchParams[SEARCH.MODE] !== this.$scope.modeModel.selectedKey) {
this.setMode(searchParams[SEARCH.MODE] || this.DEFAULT_MODE);
this.setMode(searchParams[SEARCH.MODE] || "fixed");
}
if (searchParams[SEARCH.TIME_SYSTEM] &&

View File

@@ -130,10 +130,8 @@ define(['./TimeConductorController'], function (TimeConductorController) {
mockLocation,
{conductor: mockTimeConductor},
mockConductorViewService,
mockFormatService,
'fixed',
true
mockTimeSystems,
mockFormatService
);
tsListener = getListener(mockTimeConductor.on, "timeSystem");
@@ -246,6 +244,7 @@ define(['./TimeConductorController'], function (TimeConductorController) {
var ts1Metadata;
var ts2Metadata;
var ts3Metadata;
var mockTimeSystemConstructors;
beforeEach(function () {
mode = "realtime";
@@ -277,7 +276,11 @@ define(['./TimeConductorController'], function (TimeConductorController) {
];
//Wrap in mock constructors
mockConductorViewService.systems = mockTimeSystems;
mockTimeSystemConstructors = mockTimeSystems.map(function (mockTimeSystem) {
return function () {
return mockTimeSystem;
};
});
controller = new TimeConductorController(
mockScope,
@@ -285,9 +288,8 @@ define(['./TimeConductorController'], function (TimeConductorController) {
mockLocation,
{conductor: mockTimeConductor},
mockConductorViewService,
mockFormatService,
"fixed",
true
mockTimeSystemConstructors,
mockFormatService
);
});
@@ -432,7 +434,12 @@ define(['./TimeConductorController'], function (TimeConductorController) {
}
};
mockConductorViewService.systems = [timeSystem, otherTimeSystem];
mockTimeSystems.push(function () {
return timeSystem;
});
mockTimeSystems.push(function () {
return otherTimeSystem;
});
urlBounds = {
start: 100,
@@ -460,9 +467,8 @@ define(['./TimeConductorController'], function (TimeConductorController) {
mockLocation,
{conductor: mockTimeConductor},
mockConductorViewService,
mockFormatService,
"fixed",
true
mockTimeSystems,
mockFormatService
);
spyOn(controller, "setMode");

View File

@@ -60,7 +60,7 @@ define(
this.availModes = {
'fixed': {
key: 'fixed',
cssClass: 'icon-calendar',
cssclass: 'icon-calendar',
label: 'Fixed',
name: 'Fixed Timespan Mode',
description: 'Query and explore data that falls between two fixed datetimes.'
@@ -81,7 +81,7 @@ define(
if (timeSystemsForMode('realtime').length > 0) {
var realtimeMode = {
key: 'realtime',
cssClass: 'icon-clock',
cssclass: 'icon-clock',
label: 'Real-time',
name: 'Real-time Mode',
description: 'Monitor real-time streaming data as it comes in. The Time Conductor and displays will automatically advance themselves based on a UTC clock.'
@@ -93,7 +93,7 @@ define(
if (timeSystemsForMode('lad').length > 0) {
var ladMode = {
key: 'lad',
cssClass: 'icon-database',
cssclass: 'icon-database',
label: 'LAD',
name: 'LAD Mode',
description: 'Latest Available Data mode monitors real-time streaming data as it comes in. The Time Conductor and displays will only advance when data becomes available.'

View File

@@ -22,7 +22,7 @@
define([
"./src/UTCTimeSystem",
"legacyRegistry"
'legacyRegistry'
], function (
UTCTimeSystem,
legacyRegistry

View File

@@ -25,7 +25,7 @@ define([
'../../core/src/timeSystems/LocalClock'
], function (TimeSystem, LocalClock) {
var FIFTEEN_MINUTES = 15 * 60 * 1000,
DEFAULT_PERIOD = 100;
DEFAULT_PERIOD = 1000;
/**
* This time system supports UTC dates and provides a ticking clock source.
@@ -38,17 +38,16 @@ define([
/**
* Some metadata, which will be used to identify the time system in
* the UI
* @type {{key: string, name: string, cssClass: string}}
* @type {{key: string, name: string, cssclass: string}}
*/
this.metadata = {
'key': 'utc',
'name': 'UTC',
'cssClass': 'icon-clock'
'cssclass': 'icon-clock'
};
this.fmts = ['utc'];
this.sources = [new LocalClock($timeout, DEFAULT_PERIOD)];
this.defaultValues = undefined;
}
UTCTimeSystem.prototype = Object.create(TimeSystem.prototype);
@@ -65,25 +64,18 @@ define([
return this.sources;
};
UTCTimeSystem.prototype.defaults = function (defaults) {
if (arguments.length > 0) {
this.defaultValues = defaults;
}
UTCTimeSystem.prototype.defaults = function () {
var now = Math.ceil(Date.now() / 1000) * 1000;
var ONE_MINUTE = 60 * 1 * 1000;
var FIFTY_YEARS = 50 * 365 * 24 * 60 * 60 * 1000;
if (this.defaultValues === undefined) {
var now = Math.ceil(Date.now() / 1000) * 1000;
var ONE_MINUTE = 60 * 1 * 1000;
var FIFTY_YEARS = 50 * 365 * 24 * 60 * 60 * 1000;
this.defaultValues = {
key: 'utc-default',
name: 'UTC time system defaults',
deltas: {start: FIFTEEN_MINUTES, end: 0},
bounds: {start: now - FIFTEEN_MINUTES, end: now},
zoom: {min: FIFTY_YEARS, max: ONE_MINUTE}
};
}
return this.defaultValues;
return {
key: 'utc-default',
name: 'UTC time system defaults',
deltas: {start: FIFTEEN_MINUTES, end: 0},
bounds: {start: now - FIFTEEN_MINUTES, end: now},
zoom: {min: FIFTY_YEARS, max: ONE_MINUTE}
};
};
return UTCTimeSystem;

View File

@@ -36,7 +36,7 @@ define([
{
"key": "fixed-display",
"name": "Fixed Position Display",
"cssClass": "icon-box-with-dashed-lines",
"cssclass": "icon-box-with-dashed-lines",
"type": "telemetry.fixed",
"template": fixedTemplate,
"uses": [
@@ -49,28 +49,28 @@ define([
"items": [
{
"method": "add",
"cssClass": "icon-plus",
"cssclass": "icon-plus",
"control": "menu-button",
"text": "Add",
"options": [
{
"name": "Box",
"cssClass": "icon-box",
"cssclass": "icon-box",
"key": "fixed.box"
},
{
"name": "Line",
"cssClass": "icon-line-horz",
"cssclass": "icon-line-horz",
"key": "fixed.line"
},
{
"name": "Text",
"cssClass": "icon-T",
"cssclass": "icon-T",
"key": "fixed.text"
},
{
"name": "Image",
"cssClass": "icon-image",
"cssclass": "icon-image",
"key": "fixed.image"
}
]
@@ -81,50 +81,50 @@ define([
"items": [
{
"method": "order",
"cssClass": "icon-layers",
"cssclass": "icon-layers",
"control": "menu-button",
"title": "Layering",
"description": "Move the selected object above or below other objects",
"options": [
{
"name": "Move to Top",
"cssClass": "icon-arrow-double-up",
"cssclass": "icon-arrow-double-up",
"key": "top"
},
{
"name": "Move Up",
"cssClass": "icon-arrow-up",
"cssclass": "icon-arrow-up",
"key": "up"
},
{
"name": "Move Down",
"cssClass": "icon-arrow-down",
"cssclass": "icon-arrow-down",
"key": "down"
},
{
"name": "Move to Bottom",
"cssClass": "icon-arrow-double-down",
"cssclass": "icon-arrow-double-down",
"key": "bottom"
}
]
},
{
"property": "fill",
"cssClass": "icon-paint-bucket",
"cssclass": "icon-paint-bucket",
"title": "Fill color",
"description": "Set fill color",
"control": "color"
},
{
"property": "stroke",
"cssClass": "icon-line-horz",
"cssclass": "icon-line-horz",
"title": "Border color",
"description": "Set border color",
"control": "color"
},
{
"property": "color",
"cssClass": "icon-T",
"cssclass": "icon-T",
"title": "Text color",
"description": "Set text color",
"mandatory": true,
@@ -132,20 +132,20 @@ define([
},
{
"property": "url",
"cssClass": "icon-image",
"cssclass": "icon-image",
"control": "dialog-button",
"title": "Image Properties",
"description": "Edit image properties",
"dialog": {
"control": "textfield",
"name": "Image URL",
"cssClass": "l-input-lg",
"cssclass": "l-input-lg",
"required": true
}
},
{
"property": "text",
"cssClass": "icon-gear",
"cssclass": "icon-gear",
"control": "dialog-button",
"title": "Text Properties",
"description": "Edit text properties",
@@ -157,14 +157,14 @@ define([
},
{
"method": "showTitle",
"cssClass": "icon-two-parts-both",
"cssclass": "icon-two-parts-both",
"control": "button",
"title": "Show title",
"description": "Show telemetry element title"
},
{
"method": "hideTitle",
"cssClass": "icon-two-parts-one-only",
"cssclass": "icon-two-parts-one-only",
"control": "button",
"title": "Hide title",
"description": "Hide telemetry element title"
@@ -176,7 +176,7 @@ define([
{
"method": "remove",
"control": "button",
"cssClass": "icon-trash"
"cssclass": "icon-trash"
}
]
}
@@ -188,7 +188,7 @@ define([
{
"key": "telemetry.fixed",
"name": "Fixed Position Display",
"cssClass": "icon-box-with-dashed-lines",
"cssclass": "icon-box-with-dashed-lines",
"description": "Collect and display telemetry elements in " +
"alphanumeric format in a simple canvas workspace. " +
"Elements can be positioned and sized. " +
@@ -215,12 +215,12 @@ define([
{
"name": "Horizontal grid (px)",
"control": "textfield",
"cssClass": "l-input-sm l-numeric"
"cssclass": "l-input-sm l-numeric"
},
{
"name": "Vertical grid (px)",
"control": "textfield",
"cssClass": "l-input-sm l-numeric"
"cssclass": "l-input-sm l-numeric"
}
],
"pattern": "^(\\d*[1-9]\\d*)?$",

View File

@@ -41,7 +41,7 @@ define([
{
"name": "Imagery",
"key": "imagery",
"cssClass": "icon-image",
"cssclass": "icon-image",
"template": imageryTemplate,
"priority": "preferred",
"needs": [

View File

@@ -56,7 +56,7 @@ define([
{
"key": "layout",
"name": "Display Layout",
"cssClass": "icon-layout",
"cssclass": "icon-layout",
"type": "layout",
"template": layoutTemplate,
"editable": true,
@@ -65,7 +65,7 @@ define([
{
"key": "fixed",
"name": "Fixed Position",
"cssClass": "icon-box-with-dashed-lines",
"cssclass": "icon-box-with-dashed-lines",
"type": "telemetry.panel",
"template": fixedTemplate,
"uses": [
@@ -77,7 +77,7 @@ define([
"items": [
{
"method": "add",
"cssClass": "icon-plus",
"cssclass": "icon-plus",
"control": "menu-button",
"text": "Add",
"title": "Add",
@@ -85,22 +85,22 @@ define([
"options": [
{
"name": "Box",
"cssClass": "icon-box",
"cssclass": "icon-box",
"key": "fixed.box"
},
{
"name": "Line",
"cssClass": "icon-line-horz",
"cssclass": "icon-line-horz",
"key": "fixed.line"
},
{
"name": "Text",
"cssClass": "icon-T",
"cssclass": "icon-T",
"key": "fixed.text"
},
{
"name": "Image",
"cssClass": "icon-image",
"cssclass": "icon-image",
"key": "fixed.image"
}
]
@@ -111,50 +111,50 @@ define([
"items": [
{
"method": "order",
"cssClass": "icon-layers",
"cssclass": "icon-layers",
"control": "menu-button",
"title": "Layering",
"description": "Move the selected object above or below other objects",
"options": [
{
"name": "Move to Top",
"cssClass": "icon-arrow-double-up",
"cssclass": "icon-arrow-double-up",
"key": "top"
},
{
"name": "Move Up",
"cssClass": "icon-arrow-up",
"cssclass": "icon-arrow-up",
"key": "up"
},
{
"name": "Move Down",
"cssClass": "icon-arrow-down",
"cssclass": "icon-arrow-down",
"key": "down"
},
{
"name": "Move to Bottom",
"cssClass": "icon-arrow-double-down",
"cssclass": "icon-arrow-double-down",
"key": "bottom"
}
]
},
{
"property": "fill",
"cssClass": "icon-paint-bucket",
"cssclass": "icon-paint-bucket",
"title": "Fill color",
"description": "Set fill color",
"control": "color"
},
{
"property": "stroke",
"cssClass": "icon-line-horz",
"cssclass": "icon-line-horz",
"title": "Border color",
"description": "Set border color",
"control": "color"
},
{
"property": "color",
"cssClass": "icon-T",
"cssclass": "icon-T",
"title": "Text color",
"description": "Set text color",
"mandatory": true,
@@ -162,20 +162,20 @@ define([
},
{
"property": "url",
"cssClass": "icon-image",
"cssclass": "icon-image",
"control": "dialog-button",
"title": "Image Properties",
"description": "Edit image properties",
"dialog": {
"control": "textfield",
"name": "Image URL",
"cssClass": "l-input-lg",
"cssclass": "l-input-lg",
"required": true
}
},
{
"property": "text",
"cssClass": "icon-gear",
"cssclass": "icon-gear",
"control": "dialog-button",
"title": "Text Properties",
"description": "Edit text properties",
@@ -187,14 +187,14 @@ define([
},
{
"method": "showTitle",
"cssClass": "icon-two-parts-both",
"cssclass": "icon-two-parts-both",
"control": "button",
"title": "Show title",
"description": "Show telemetry element title"
},
{
"method": "hideTitle",
"cssClass": "icon-two-parts-one-only",
"cssclass": "icon-two-parts-one-only",
"control": "button",
"title": "Hide title",
"description": "Hide telemetry element title"
@@ -206,7 +206,7 @@ define([
{
"method": "remove",
"control": "button",
"cssClass": "icon-trash",
"cssclass": "icon-trash",
"title": "Delete",
"description": "Delete the selected item"
}
@@ -275,7 +275,7 @@ define([
{
"key": "layout",
"name": "Display Layout",
"cssClass": "icon-layout",
"cssclass": "icon-layout",
"description": "Assemble other objects and components together into a reusable screen layout. Working in a simple canvas workspace, simply drag in the objects you want, position and size them. Save your design and view or edit it at any time.",
"priority": 900,
"features": "creation",
@@ -291,12 +291,12 @@ define([
{
"name": "Horizontal grid (px)",
"control": "textfield",
"cssClass": "l-input-sm l-numeric"
"cssclass": "l-input-sm l-numeric"
},
{
"name": "Vertical grid (px)",
"control": "textfield",
"cssClass": "l-input-sm l-numeric"
"cssclass": "l-input-sm l-numeric"
}
],
"key": "layoutGrid",
@@ -307,7 +307,7 @@ define([
{
"key": "telemetry.panel",
"name": "Telemetry Panel",
"cssClass": "icon-telemetry-panel",
"cssclass": "icon-telemetry-panel",
"description": "A panel for collecting telemetry elements.",
"priority": 899,
"delegates": [
@@ -330,12 +330,12 @@ define([
{
"name": "Horizontal grid (px)",
"control": "textfield",
"cssClass": "l-input-sm l-numeric"
"cssclass": "l-input-sm l-numeric"
},
{
"name": "Vertical grid (px)",
"control": "textfield",
"cssClass": "l-input-sm l-numeric"
"cssclass": "l-input-sm l-numeric"
}
],
"pattern": "^(\\d*[1-9]\\d*)?$",

View File

@@ -34,14 +34,13 @@ define(
function LayoutCompositionPolicy() {
}
LayoutCompositionPolicy.prototype.allow = function (parentType, child) {
if (parentType.instanceOf('layout') &&
child.getCapability('type').instanceOf('folder')) {
return false;
}
return true;
LayoutCompositionPolicy.prototype.allow = function (candidate, context) {
var isFolderInLayout =
candidate &&
context &&
candidate.instanceOf('layout') &&
context.instanceOf('folder');
return !isFolderInLayout;
};
return LayoutCompositionPolicy;

View File

@@ -55,7 +55,7 @@ define(
key: "url",
control: "textfield",
name: "Image URL",
"cssClass": "l-input-lg",
"cssclass": "l-input-lg",
required: true
}
]

View File

@@ -24,25 +24,18 @@ define(
["../src/LayoutCompositionPolicy"],
function (LayoutCompositionPolicy) {
describe("Layout's composition policy", function () {
var mockChild,
mockCandidate,
var mockCandidate,
mockContext,
candidateType,
contextType,
policy;
beforeEach(function () {
mockChild = jasmine.createSpyObj(
'childObject',
['getCapability']
);
mockCandidate =
jasmine.createSpyObj('candidateType', ['instanceOf']);
mockContext =
jasmine.createSpyObj('contextType', ['instanceOf']);
mockChild.getCapability.andReturn(mockContext);
mockCandidate.instanceOf.andCallFake(function (t) {
return t === candidateType;
});
@@ -56,19 +49,19 @@ define(
it("disallows folders in layouts", function () {
candidateType = 'layout';
contextType = 'folder';
expect(policy.allow(mockCandidate, mockChild)).toBe(false);
expect(policy.allow(mockCandidate, mockContext)).toBe(false);
});
it("does not disallow folders elsewhere", function () {
candidateType = 'nonlayout';
contextType = 'folder';
expect(policy.allow(mockCandidate, mockChild)).toBe(true);
expect(policy.allow(mockCandidate, mockContext)).toBe(true);
});
it("allows things other than folders in layouts", function () {
candidateType = 'layout';
contextType = 'nonfolder';
expect(policy.allow(mockCandidate, mockChild)).toBe(true);
expect(policy.allow(mockCandidate, mockContext)).toBe(true);
});
});

View File

@@ -36,7 +36,7 @@ define([
{
"key": "example.page",
"name": "Web Page",
"cssClass": "icon-page",
"cssclass": "icon-page",
"description": "Embed a web page or web-based image in a resizeable window component. Can be added to Display Layouts. Note that the URL being embedded must allow iframing.",
"priority": 50,
"features": [
@@ -49,7 +49,7 @@ define([
"control": "textfield",
"pattern": "^(ftp|https?)\\:\\/\\/\\w+(\\.\\w+)*(\\:\\d+)?(\\/\\S*)*$",
"required": true,
"cssClass": "l-input-lg"
"cssclass": "l-input-lg"
}
]
}

View File

@@ -47,7 +47,7 @@ define([
{
"name": "Plot",
"key": "plot",
"cssClass": "icon-sine",
"cssclass": "icon-sine",
"template": plotTemplate,
"needs": [
"telemetry"

View File

@@ -121,7 +121,7 @@
ng-show="plot.isZoomed()"
title="Reset pan/zoom">
</a>
<div class="menu-element s-menu-button menus-to-left {{plot.getMode().cssClass}}"
<div class="menu-element s-menu-button menus-to-left {{plot.getMode().cssclass}}"
ng-if="plot.getModeOptions().length > 1"
ng-controller="ClickAwayController as toggle">
<span class="l-click-area" ng-click="toggle.toggle()"></span>
@@ -130,7 +130,7 @@
<ul>
<li ng-repeat="option in plot.getModeOptions()"
ng-click="plot.setMode(option); toggle.setState(false)"
class="{{option.cssClass}}">
class="{{option.cssclass}}">
{{option.name}}
</li>
</ul>

View File

@@ -217,8 +217,8 @@ define(
if (handle) {
handle.unsubscribe();
handle = undefined;
conductor.off("timeOfInterest", changeTimeOfInterest);
}
conductor.off("timeOfInterest", changeTimeOfInterest);
}
function requery() {
@@ -352,7 +352,7 @@ define(
/**
* Get the current mode that is applicable to this plot. This
* will include key, name, and cssClass fields.
* will include key, name, and cssclass fields.
*/
PlotController.prototype.getMode = function () {
return this.modeOptions.getMode();

View File

@@ -27,13 +27,13 @@ define(
var STACKED = {
key: "stacked",
name: "Stacked",
cssClass: "icon-plot-stacked",
cssclass: "icon-plot-stacked",
Constructor: PlotStackMode
},
OVERLAID = {
key: "overlaid",
name: "Overlaid",
cssClass: "icon-plot-overlay",
cssclass: "icon-plot-overlay",
Constructor: PlotOverlayMode
};
@@ -115,7 +115,7 @@ define(
/**
* Get all mode options available for each plot. Each
* mode contains a `name` and `cssClass` field suitable
* mode contains a `name` and `cssclass` field suitable
* for display in a template.
* @return {Array} the available modes
*/

View File

@@ -36,7 +36,7 @@ define([
{
"key": "static.markup",
"name": "Static Markup",
"cssClass": "icon-pencil",
"cssclass": "icon-pencil",
"description": "Static markup sandbox",
"features": [
"creation"

View File

@@ -22,21 +22,25 @@
define([
"./src/directives/MCTTable",
"./src/controllers/TelemetryTableController",
"./src/controllers/RealtimeTableController",
"./src/controllers/HistoricalTableController",
"./src/controllers/TableOptionsController",
'../../commonUI/regions/src/Region',
'../../commonUI/browse/src/InspectorRegion',
"text!./res/templates/table-options-edit.html",
"text!./res/templates/telemetry-table.html",
"text!./res/templates/rt-table.html",
"text!./res/templates/historical-table.html",
"legacyRegistry"
], function (
MCTTable,
TelemetryTableController,
RealtimeTableController,
HistoricalTableController,
TableOptionsController,
Region,
InspectorRegion,
tableOptionsEditTemplate,
telemetryTableTemplate,
rtTableTemplate,
historicalTableTemplate,
legacyRegistry
) {
/**
@@ -61,9 +65,9 @@ define([
"types": [
{
"key": "table",
"name": "Telemetry Table",
"cssClass": "icon-tabular-realtime",
"description": "A table of values over a given time period. The table will be automatically updated with new values as they become available",
"name": "Historical Telemetry Table",
"cssclass": "icon-tabular",
"description": "A static table of all values over time for all included telemetry elements. Rows are timestamped data values for each telemetry element; columns are data fields. The number of rows is based on the range of your query. New incoming data must be manually re-queried for.",
"priority": 861,
"features": "creation",
"delegates": [
@@ -81,13 +85,42 @@ define([
"views": [
"table"
]
},
{
"key": "rttable",
"name": "Real-time Telemetry Table",
"cssclass": "icon-tabular-realtime",
"description": "A scrolling table of latest values for all included telemetry elements. Rows are timestamped data values for each telemetry element; columns are data fields. New incoming data is automatically added to the view.",
"priority": 860,
"features": "creation",
"delegates": [
"telemetry"
],
"inspector": tableInspector,
"contains": [
{
"has": "telemetry"
}
],
"model": {
"composition": []
},
"views": [
"rt-table",
"scrolling-table"
]
}
],
"controllers": [
{
"key": "TelemetryTableController",
"implementation": TelemetryTableController,
"depends": ["$scope", "$timeout", "openmct"]
"key": "HistoricalTableController",
"implementation": HistoricalTableController,
"depends": ["$scope", "telemetryHandler", "telemetryFormatter", "$timeout", "openmct"]
},
{
"key": "RealtimeTableController",
"implementation": RealtimeTableController,
"depends": ["$scope", "telemetryHandler", "telemetryFormatter", "openmct"]
},
{
"key": "TableOptionsController",
@@ -98,10 +131,21 @@ define([
],
"views": [
{
"name": "Telemetry Table",
"name": "Historical Table",
"key": "table",
"cssClass": "icon-tabular-realtime",
"template": telemetryTableTemplate,
"template": historicalTableTemplate,
"cssclass": "icon-tabular",
"needs": [
"telemetry"
],
"delegation": true,
"editable": false
},
{
"name": "Real-time Table",
"key": "rt-table",
"cssclass": "icon-tabular-realtime",
"template": rtTableTemplate,
"needs": [
"telemetry"
],

View File

@@ -1,14 +1,12 @@
<div ng-controller="TelemetryTableController as tableController"
<div ng-controller="HistoricalTableController as tableController"
ng-class="{'loading': loading}">
<mct-table
headers="headers"
rows="rows"
time-columns="tableController.timeColumns"
format-cell="formatCell"
rows="rows"
enableFilter="true"
enableSort="true"
auto-scroll="autoScroll"
default-sort="defaultSort"
sort-column="defaultSort"
class="tabular-holder has-control-bar">
</mct-table>
</div>

Some files were not shown because too many files have changed in this diff Show More