mirror of
https://github.com/nasa/openmct.git
synced 2025-04-08 03:44:24 +00:00
Merge pull request #1600 from nasa/imagery-updates
[Imagery] Update metadata for images
This commit is contained in:
commit
e75d1f62ec
1
API.md
1
API.md
@ -372,6 +372,7 @@ Known hints:
|
||||
|
||||
* `domain`: Indicates that the value represents the "input" of a datum. Values with a `domain` hint will be used for the x-axis of a plot, and tables will render columns for these values first.
|
||||
* `range`: Indicates that the value is the "output" of a datum. Values with a `range` hint will be used as the y-axis on a plot, and tables will render columns for these values after the `domain` values.
|
||||
* `image`: Indicates that the value may be interpreted as the URL to an image file, in which case appropriate views will be made available.
|
||||
|
||||
##### The Time Conductor and Telemetry
|
||||
|
||||
|
@ -1,80 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, 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/ImageTelemetryProvider",
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
ImageTelemetryProvider,
|
||||
legacyRegistry
|
||||
) {
|
||||
"use strict";
|
||||
|
||||
legacyRegistry.register("example/imagery", {
|
||||
"name": "Imagery",
|
||||
"description": "Example of a component that produces image telemetry.",
|
||||
"extensions": {
|
||||
"components": [
|
||||
{
|
||||
"implementation": ImageTelemetryProvider,
|
||||
"type": "provider",
|
||||
"provides": "telemetryService",
|
||||
"depends": [
|
||||
"$q",
|
||||
"$timeout"
|
||||
]
|
||||
}
|
||||
],
|
||||
"types": [
|
||||
{
|
||||
"key": "imagery",
|
||||
"name": "Example Imagery",
|
||||
"cssClass": "icon-image",
|
||||
"features": "creation",
|
||||
"description": "For development use. Creates example imagery data that mimics a live imagery stream.",
|
||||
"priority": 10,
|
||||
"model": {
|
||||
"telemetry": {}
|
||||
},
|
||||
"telemetry": {
|
||||
"source": "imagery",
|
||||
"domains": [
|
||||
{
|
||||
"name": "Time",
|
||||
"key": "time",
|
||||
"format": "utc"
|
||||
}
|
||||
],
|
||||
"ranges": [
|
||||
{
|
||||
"name": "Image",
|
||||
"key": "url",
|
||||
"format": "imageUrl"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
@ -19,18 +19,15 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define,Promise*/
|
||||
|
||||
/**
|
||||
* Module defining ImageTelemetry. Created by vwoeltje on 06/22/15.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
define([
|
||||
|
||||
var firstObservedTime = Date.now(),
|
||||
images = [
|
||||
], function(
|
||||
|
||||
) {
|
||||
function ImageryPlugin() {
|
||||
|
||||
var IMAGE_SAMPLES = [
|
||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18731.jpg",
|
||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18732.jpg",
|
||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18733.jpg",
|
||||
@ -49,33 +46,67 @@ define(
|
||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18746.jpg",
|
||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18747.jpg",
|
||||
"https://www.hq.nasa.gov/alsj/a16/AS16-117-18748.jpg"
|
||||
];
|
||||
|
||||
].map(function (url, index) {
|
||||
return {
|
||||
timestamp: firstObservedTime + 1000 * index,
|
||||
url: url
|
||||
};
|
||||
return function install(openmct) {
|
||||
openmct.types.addType('example.imagery', {
|
||||
key: 'example.imagery',
|
||||
name: 'Example Imagery',
|
||||
cssClass: 'icon-image',
|
||||
description: 'For development use. Creates example imagery ' +
|
||||
'data that mimics a live imagery stream.',
|
||||
creatable: true,
|
||||
initialize: function (object) {
|
||||
object.telemetry = {
|
||||
values: [
|
||||
{
|
||||
name: 'Time',
|
||||
key: 'utc',
|
||||
format: 'utc',
|
||||
hints: {
|
||||
domain: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Image',
|
||||
key: 'url',
|
||||
format: 'image',
|
||||
hints: {
|
||||
image: 1
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
openmct.telemetry.addProvider({
|
||||
supportsSubscribe: function (domainObject) {
|
||||
return domainObject.type === 'example.imagery';
|
||||
},
|
||||
subscribe: function (domainObject, callback) {
|
||||
var index = 0,
|
||||
end = IMAGE_SAMPLES.length,
|
||||
interval;
|
||||
|
||||
/**
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function ImageTelemetry() {
|
||||
return {
|
||||
getPointCount: function () {
|
||||
return Math.floor((Date.now() - firstObservedTime) / 1000);
|
||||
},
|
||||
getDomainValue: function (i, domain) {
|
||||
return images[i % images.length].timestamp;
|
||||
},
|
||||
getRangeValue: function (i, range) {
|
||||
return images[i % images.length].url;
|
||||
interval = setInterval(function () {
|
||||
if (index >= end) {
|
||||
index = 0;
|
||||
}
|
||||
callback({
|
||||
utc: Date.now(),
|
||||
url: IMAGE_SAMPLES[index]
|
||||
});
|
||||
index += 1;
|
||||
}, 1000);
|
||||
|
||||
return function (interval) {
|
||||
clearInterval(interval);
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return ImageTelemetry;
|
||||
});
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
return ImageryPlugin;
|
||||
});
|
@ -1,115 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, 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,Promise*/
|
||||
|
||||
/**
|
||||
* Module defining ImageTelemetryProvider. Created by vwoeltje on 06/22/15.
|
||||
*/
|
||||
define(
|
||||
["./ImageTelemetry"],
|
||||
function (ImageTelemetry) {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function ImageTelemetryProvider($q, $timeout) {
|
||||
var subscriptions = [];
|
||||
|
||||
//
|
||||
function matchesSource(request) {
|
||||
return request.source === "imagery";
|
||||
}
|
||||
|
||||
// Used internally; this will be repacked by doPackage
|
||||
function generateData(request) {
|
||||
return {
|
||||
key: request.key,
|
||||
telemetry: new ImageTelemetry()
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
function doPackage(results) {
|
||||
var packaged = {};
|
||||
results.forEach(function (result) {
|
||||
packaged[result.key] = result.telemetry;
|
||||
});
|
||||
// Format as expected (sources -> keys -> telemetry)
|
||||
return { imagery: packaged };
|
||||
}
|
||||
|
||||
function requestTelemetry(requests) {
|
||||
return $timeout(function () {
|
||||
return doPackage(requests.filter(matchesSource).map(generateData));
|
||||
}, 0);
|
||||
}
|
||||
|
||||
function handleSubscriptions() {
|
||||
subscriptions.forEach(function (subscription) {
|
||||
var requests = subscription.requests;
|
||||
subscription.callback(doPackage(
|
||||
requests.filter(matchesSource).map(generateData)
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
function startGenerating() {
|
||||
$timeout(function () {
|
||||
handleSubscriptions();
|
||||
if (subscriptions.length > 0) {
|
||||
startGenerating();
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function subscribe(callback, requests) {
|
||||
var subscription = {
|
||||
callback: callback,
|
||||
requests: requests
|
||||
};
|
||||
|
||||
function unsubscribe() {
|
||||
subscriptions = subscriptions.filter(function (s) {
|
||||
return s !== subscription;
|
||||
});
|
||||
}
|
||||
|
||||
subscriptions.push(subscription);
|
||||
|
||||
if (subscriptions.length === 1) {
|
||||
startGenerating();
|
||||
}
|
||||
|
||||
return unsubscribe;
|
||||
}
|
||||
|
||||
return {
|
||||
requestTelemetry: requestTelemetry,
|
||||
subscribe: subscribe
|
||||
};
|
||||
}
|
||||
|
||||
return ImageTelemetryProvider;
|
||||
}
|
||||
);
|
@ -32,7 +32,6 @@
|
||||
|
||||
require(['openmct'], function (openmct) {
|
||||
[
|
||||
'example/imagery',
|
||||
'example/eventGenerator',
|
||||
'example/styleguide'
|
||||
].forEach(
|
||||
@ -42,6 +41,7 @@
|
||||
openmct.install(openmct.plugins.LocalStorage());
|
||||
openmct.install(openmct.plugins.Espresso());
|
||||
openmct.install(openmct.plugins.Generator());
|
||||
openmct.install(openmct.plugins.ExampleImagery());
|
||||
openmct.install(openmct.plugins.UTCTimeSystem());
|
||||
openmct.time.clock('local', {start: -THIRTY_MINUTES, end: 0});
|
||||
openmct.time.timeSystem('utc');
|
||||
|
@ -53,7 +53,10 @@ define([
|
||||
"policies": [
|
||||
{
|
||||
"category": "view",
|
||||
"implementation": ImageryViewPolicy
|
||||
"implementation": ImageryViewPolicy,
|
||||
"depends": [
|
||||
"openmct"
|
||||
]
|
||||
}
|
||||
],
|
||||
"controllers": [
|
||||
@ -62,7 +65,7 @@ define([
|
||||
"implementation": ImageryController,
|
||||
"depends": [
|
||||
"$scope",
|
||||
"telemetryHandler"
|
||||
"openmct"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
@ -34,10 +34,8 @@
|
||||
<div class="l-image-main-controlbar flex-elem l-flex-row">
|
||||
<div class="left flex-elem grows">
|
||||
<a class="s-button show-thumbs sm hidden icon-thumbs-strip"
|
||||
ng-click="showThumbsBubble = (showThumbsBubble)? false:true"></a>
|
||||
<span class="l-timezone">{{imagery.getZone()}}</span>
|
||||
ng-click="showThumbsBubble = (showThumbsBubble) ? false:true"></a>
|
||||
<span class="l-time">{{imagery.getTime()}}</span>
|
||||
<span class="l-date">{{imagery.getDate()}}</span>
|
||||
</div>
|
||||
<div class="right flex-elem">
|
||||
<a class="s-button pause-play"
|
||||
|
@ -28,74 +28,74 @@ define(
|
||||
['moment'],
|
||||
function (moment) {
|
||||
|
||||
var DATE_FORMAT = "YYYY-MM-DD",
|
||||
TIME_FORMAT = "HH:mm:ss.SSS";
|
||||
|
||||
/**
|
||||
* Controller for the "Imagery" view of a domain object which
|
||||
* provides image telemetry.
|
||||
* @constructor
|
||||
* @memberof platform/features/imagery
|
||||
*/
|
||||
function ImageryController($scope, telemetryHandler) {
|
||||
var self = this;
|
||||
function ImageryController($scope, openmct) {
|
||||
this.$scope = $scope;
|
||||
this.openmct = openmct;
|
||||
this.date = "";
|
||||
this.time = "";
|
||||
this.zone = "";
|
||||
this.imageUrl = "";
|
||||
|
||||
function releaseSubscription() {
|
||||
if (self.handle) {
|
||||
self.handle.unsubscribe();
|
||||
self.handle = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function updateValuesCallback() {
|
||||
return self.updateValues();
|
||||
}
|
||||
|
||||
// Create a new subscription; telemetrySubscriber gets
|
||||
// to do the meaningful work here.
|
||||
function subscribe(domainObject) {
|
||||
releaseSubscription();
|
||||
self.date = "";
|
||||
self.time = "";
|
||||
self.zone = "";
|
||||
self.imageUrl = "";
|
||||
self.handle = domainObject && telemetryHandler.handle(
|
||||
domainObject,
|
||||
updateValuesCallback,
|
||||
true // Lossless
|
||||
);
|
||||
}
|
||||
|
||||
$scope.filters = {
|
||||
this.$scope.filters = {
|
||||
brightness: 100,
|
||||
contrast: 100
|
||||
};
|
||||
|
||||
this.subscribe = this.subscribe.bind(this);
|
||||
this.stopListening = this.stopListening.bind(this);
|
||||
this.updateValues = this.updateValues.bind(this);
|
||||
|
||||
// Subscribe to telemetry when a domain object becomes available
|
||||
$scope.$watch('domainObject', subscribe);
|
||||
this.subscribe(this.$scope.domainObject);
|
||||
|
||||
// Unsubscribe when the plot is destroyed
|
||||
$scope.$on("$destroy", releaseSubscription);
|
||||
this.$scope.$on("$destroy", this.stopListening);
|
||||
}
|
||||
|
||||
// Update displayable values to reflect latest image telemetry
|
||||
ImageryController.prototype.updateValues = function () {
|
||||
var imageObject =
|
||||
this.handle && this.handle.getTelemetryObjects()[0],
|
||||
timestamp,
|
||||
m;
|
||||
if (imageObject && !this.isPaused) {
|
||||
timestamp = this.handle.getDomainValue(imageObject);
|
||||
m = timestamp !== undefined ?
|
||||
moment.utc(timestamp) :
|
||||
undefined;
|
||||
this.date = m ? m.format(DATE_FORMAT) : "";
|
||||
this.time = m ? m.format(TIME_FORMAT) : "";
|
||||
this.zone = m ? "UTC" : "";
|
||||
this.imageUrl = this.handle.getRangeValue(imageObject);
|
||||
ImageryController.prototype.subscribe = function (domainObject) {
|
||||
this.date = "";
|
||||
this.imageUrl = "";
|
||||
this.openmct.objects.get(domainObject.getId())
|
||||
.then(function (object) {
|
||||
this.domainObject = object;
|
||||
var metadata = this.openmct
|
||||
.telemetry
|
||||
.getMetadata(this.domainObject);
|
||||
var timeKey = this.openmct.time.timeSystem().key;
|
||||
this.timeFormat = this.openmct
|
||||
.telemetry
|
||||
.getValueFormatter(metadata.value(timeKey));
|
||||
this.imageFormat = this.openmct
|
||||
.telemetry
|
||||
.getValueFormatter(metadata.valuesForHints(['image'])[0]);
|
||||
this.unsubscribe = this.openmct.telemetry
|
||||
.subscribe(this.domainObject, this.updateValues);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
ImageryController.prototype.stopListening = function () {
|
||||
if (this.unsubscribe) {
|
||||
this.unsubscribe();
|
||||
delete this.unsubscribe;
|
||||
}
|
||||
};
|
||||
|
||||
// Update displayable values to reflect latest image telemetry
|
||||
ImageryController.prototype.updateValues = function (datum) {
|
||||
if (this.isPaused) {
|
||||
this.nextDatum = datum;
|
||||
return;
|
||||
}
|
||||
this.time = this.timeFormat.format(datum);
|
||||
this.imageUrl = this.imageFormat.format(datum);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the time portion (hours, minutes, seconds) of the
|
||||
* timestamp associated with the incoming image telemetry.
|
||||
@ -105,25 +105,6 @@ define(
|
||||
return this.time;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the date portion (month, year) of the
|
||||
* timestamp associated with the incoming image telemetry.
|
||||
* @returns {string} the date
|
||||
*/
|
||||
ImageryController.prototype.getDate = function () {
|
||||
return this.date;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the time zone for the displayed time/date corresponding
|
||||
* to the timestamp associated with the incoming image
|
||||
* telemetry.
|
||||
* @returns {string} the time
|
||||
*/
|
||||
ImageryController.prototype.getZone = function () {
|
||||
return this.zone;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the URL of the image telemetry to display.
|
||||
* @returns {string} URL for telemetry image
|
||||
@ -141,8 +122,10 @@ define(
|
||||
ImageryController.prototype.paused = function (state) {
|
||||
if (arguments.length > 0 && state !== this.isPaused) {
|
||||
this.isPaused = state;
|
||||
// Switch to latest image
|
||||
this.updateValues();
|
||||
if (this.nextDatum) {
|
||||
this.updateValues(this.nextDatum);
|
||||
delete this.nextDatum;
|
||||
}
|
||||
}
|
||||
return this.isPaused;
|
||||
};
|
||||
|
@ -20,39 +20,40 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
function () {
|
||||
|
||||
/**
|
||||
* Policy preventing the Imagery view from being made available for
|
||||
* domain objects which do not have associated image telemetry.
|
||||
* @implements {Policy.<View, DomainObject>}
|
||||
* @constructor
|
||||
*/
|
||||
function ImageryViewPolicy() {
|
||||
}
|
||||
|
||||
function hasImageTelemetry(domainObject) {
|
||||
var telemetry = domainObject &&
|
||||
domainObject.getCapability('telemetry'),
|
||||
metadata = telemetry ? telemetry.getMetadata() : {},
|
||||
ranges = metadata.ranges || [];
|
||||
|
||||
return ranges.some(function (range) {
|
||||
return range.format === 'imageUrl' ||
|
||||
range.format === 'image';
|
||||
});
|
||||
}
|
||||
|
||||
ImageryViewPolicy.prototype.allow = function (view, domainObject) {
|
||||
if (view.key === 'imagery') {
|
||||
return hasImageTelemetry(domainObject);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
return ImageryViewPolicy;
|
||||
define([
|
||||
'../../../../../src/api/objects/object-utils'
|
||||
], function (
|
||||
objectUtils
|
||||
) {
|
||||
/**
|
||||
* Policy preventing the Imagery view from being made available for
|
||||
* domain objects which do not have associated image telemetry.
|
||||
* @implements {Policy.<View, DomainObject>}
|
||||
* @constructor
|
||||
*/
|
||||
function ImageryViewPolicy(openmct) {
|
||||
this.openmct = openmct;
|
||||
}
|
||||
);
|
||||
|
||||
ImageryViewPolicy.prototype.hasImageTelemetry = function (domainObject) {
|
||||
var newDO = objectUtils.toNewFormat(
|
||||
domainObject.getModel(),
|
||||
domainObject.getId()
|
||||
);
|
||||
|
||||
var metadata = this.openmct.telemetry.getMetadata(newDO);
|
||||
var values = metadata.valuesForHints(['image']);
|
||||
return values.length >= 1;
|
||||
};
|
||||
|
||||
ImageryViewPolicy.prototype.allow = function (view, domainObject) {
|
||||
if (view.key === 'imagery') {
|
||||
return this.hasImageTelemetry(domainObject);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
return ImageryViewPolicy;
|
||||
});
|
||||
|
||||
|
@ -25,60 +25,92 @@ define(
|
||||
function (ImageryController) {
|
||||
|
||||
describe("The Imagery controller", function () {
|
||||
var mockScope,
|
||||
mockTelemetryHandler,
|
||||
mockHandle,
|
||||
mockDomainObject,
|
||||
var $scope,
|
||||
openmct,
|
||||
oldDomainObject,
|
||||
newDomainObject,
|
||||
unsubscribe,
|
||||
callback,
|
||||
metadata,
|
||||
prefix,
|
||||
controller;
|
||||
|
||||
function invokeWatch(expr, value) {
|
||||
mockScope.$watch.calls.forEach(function (call) {
|
||||
if (call.args[0] === expr) {
|
||||
call.args[1](value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj('$scope', ['$on', '$watch']);
|
||||
mockTelemetryHandler = jasmine.createSpyObj(
|
||||
'telemetryHandler',
|
||||
['handle']
|
||||
);
|
||||
mockHandle = jasmine.createSpyObj(
|
||||
'handle',
|
||||
[
|
||||
'getDomainValue',
|
||||
'getRangeValue',
|
||||
'getTelemetryObjects',
|
||||
'unsubscribe'
|
||||
]
|
||||
);
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
$scope = jasmine.createSpyObj('$scope', ['$on', '$watch']);
|
||||
oldDomainObject = jasmine.createSpyObj(
|
||||
'domainObject',
|
||||
['getId', 'getModel', 'getCapability']
|
||||
['getId']
|
||||
);
|
||||
newDomainObject = { name: 'foo' };
|
||||
|
||||
mockTelemetryHandler.handle.andReturn(mockHandle);
|
||||
mockHandle.getTelemetryObjects.andReturn([mockDomainObject]);
|
||||
oldDomainObject.getId.andReturn('testID');
|
||||
openmct = {
|
||||
objects: jasmine.createSpyObj('objectAPI', [
|
||||
'get'
|
||||
]),
|
||||
time: jasmine.createSpyObj('timeAPI', [
|
||||
'timeSystem'
|
||||
]),
|
||||
telemetry: jasmine.createSpyObj('telemetryAPI', [
|
||||
'subscribe',
|
||||
'getValueFormatter',
|
||||
'getMetadata'
|
||||
])
|
||||
};
|
||||
metadata = jasmine.createSpyObj('metadata', [
|
||||
'value',
|
||||
'valuesForHints'
|
||||
]);
|
||||
prefix = "formatted ";
|
||||
unsubscribe = jasmine.createSpy('unsubscribe');
|
||||
openmct.telemetry.subscribe.andReturn(unsubscribe);
|
||||
openmct.time.timeSystem.andReturn({
|
||||
key: 'testKey'
|
||||
});
|
||||
$scope.domainObject = oldDomainObject;
|
||||
openmct.objects.get.andReturn(Promise.resolve(newDomainObject));
|
||||
openmct.telemetry.getMetadata.andReturn(metadata);
|
||||
openmct.telemetry.getValueFormatter.andCallFake(function (property) {
|
||||
var formatter =
|
||||
jasmine.createSpyObj("formatter-" + property, ['format']);
|
||||
var isTime = (property === "timestamp");
|
||||
formatter.format.andCallFake(function (datum) {
|
||||
return (isTime ? prefix : "") + datum[property];
|
||||
});
|
||||
return formatter;
|
||||
});
|
||||
metadata.value.andReturn("timestamp");
|
||||
metadata.valuesForHints.andReturn(["value"]);
|
||||
|
||||
controller = new ImageryController(
|
||||
mockScope,
|
||||
mockTelemetryHandler
|
||||
controller = new ImageryController($scope, openmct);
|
||||
|
||||
waitsFor(function () {
|
||||
return openmct.telemetry.subscribe.calls.length > 0;
|
||||
}, 100);
|
||||
|
||||
runs(function () {
|
||||
callback =
|
||||
openmct.telemetry.subscribe.mostRecentCall.args[1];
|
||||
});
|
||||
});
|
||||
|
||||
it("subscribes to telemetry", function () {
|
||||
expect(openmct.telemetry.subscribe).toHaveBeenCalledWith(
|
||||
newDomainObject,
|
||||
jasmine.any(Function)
|
||||
);
|
||||
invokeWatch('domainObject', mockDomainObject);
|
||||
});
|
||||
|
||||
it("unsubscribes when scope is destroyed", function () {
|
||||
expect(mockHandle.unsubscribe).not.toHaveBeenCalled();
|
||||
expect(unsubscribe).not.toHaveBeenCalled();
|
||||
|
||||
// Find the $destroy listener and call it
|
||||
mockScope.$on.calls.forEach(function (call) {
|
||||
$scope.$on.calls.forEach(function (call) {
|
||||
if (call.args[0] === '$destroy') {
|
||||
call.args[1]();
|
||||
}
|
||||
});
|
||||
expect(mockHandle.unsubscribe).toHaveBeenCalled();
|
||||
expect(unsubscribe).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("exposes the latest telemetry values", function () {
|
||||
@ -88,24 +120,15 @@ define(
|
||||
nextTimestamp = 1434600259456, // 4:05.456
|
||||
nextUrl = "some/other/url";
|
||||
|
||||
mockHandle.getDomainValue.andReturn(testTimestamp);
|
||||
mockHandle.getRangeValue.andReturn(testUrl);
|
||||
// Call back with telemetry data
|
||||
callback({ timestamp: testTimestamp, value: testUrl });
|
||||
|
||||
// Call the subscription listener
|
||||
mockTelemetryHandler.handle.mostRecentCall.args[1]();
|
||||
|
||||
expect(controller.getTime()).toEqual("04:04:18.123");
|
||||
expect(controller.getDate()).toEqual("2015-06-18");
|
||||
expect(controller.getZone()).toEqual("UTC");
|
||||
expect(controller.getTime()).toEqual(prefix + testTimestamp);
|
||||
expect(controller.getImageUrl()).toEqual(testUrl);
|
||||
|
||||
mockHandle.getDomainValue.andReturn(nextTimestamp);
|
||||
mockHandle.getRangeValue.andReturn(nextUrl);
|
||||
mockTelemetryHandler.handle.mostRecentCall.args[1]();
|
||||
callback({ timestamp: nextTimestamp, value: nextUrl });
|
||||
|
||||
expect(controller.getTime()).toEqual("04:04:19.456");
|
||||
expect(controller.getDate()).toEqual("2015-06-18");
|
||||
expect(controller.getZone()).toEqual("UTC");
|
||||
expect(controller.getTime()).toEqual(prefix + nextTimestamp);
|
||||
expect(controller.getImageUrl()).toEqual(nextUrl);
|
||||
});
|
||||
|
||||
@ -116,46 +139,26 @@ define(
|
||||
nextTimestamp = 1434600259456, // 4:05.456
|
||||
nextUrl = "some/other/url";
|
||||
|
||||
// As above, but pause in between. Expect details
|
||||
// not to change this time
|
||||
// Call back with telemetry data
|
||||
callback({ timestamp: testTimestamp, value: testUrl });
|
||||
|
||||
mockHandle.getDomainValue.andReturn(testTimestamp);
|
||||
mockHandle.getRangeValue.andReturn(testUrl);
|
||||
|
||||
// Call the subscription listener
|
||||
mockTelemetryHandler.handle.mostRecentCall.args[1]();
|
||||
|
||||
expect(controller.getTime()).toEqual("04:04:18.123");
|
||||
expect(controller.getDate()).toEqual("2015-06-18");
|
||||
expect(controller.getZone()).toEqual("UTC");
|
||||
expect(controller.getTime()).toEqual(prefix + testTimestamp);
|
||||
expect(controller.getImageUrl()).toEqual(testUrl);
|
||||
|
||||
expect(controller.paused()).toBeFalsy();
|
||||
controller.paused(true); // Pause!
|
||||
expect(controller.paused()).toBeTruthy();
|
||||
|
||||
mockHandle.getDomainValue.andReturn(nextTimestamp);
|
||||
mockHandle.getRangeValue.andReturn(nextUrl);
|
||||
mockTelemetryHandler.handle.mostRecentCall.args[1]();
|
||||
callback({ timestamp: nextTimestamp, value: nextUrl });
|
||||
|
||||
expect(controller.getTime()).toEqual("04:04:18.123");
|
||||
expect(controller.getDate()).toEqual("2015-06-18");
|
||||
expect(controller.getZone()).toEqual("UTC");
|
||||
expect(controller.getTime()).toEqual(prefix + testTimestamp);
|
||||
expect(controller.getImageUrl()).toEqual(testUrl);
|
||||
});
|
||||
|
||||
it("initially shows an empty string for date/time", function () {
|
||||
// Call the subscription listener while domain/range
|
||||
// values are still undefined
|
||||
mockHandle.getDomainValue.andReturn(undefined);
|
||||
mockHandle.getRangeValue.andReturn(undefined);
|
||||
mockTelemetryHandler.handle.mostRecentCall.args[1]();
|
||||
|
||||
// Should have empty strings for date/time/zone
|
||||
// Do not invoke callback...
|
||||
expect(controller.getTime()).toEqual("");
|
||||
expect(controller.getDate()).toEqual("");
|
||||
expect(controller.getZone()).toEqual("");
|
||||
expect(controller.getImageUrl()).toBeUndefined();
|
||||
expect(controller.getImageUrl()).toEqual("");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -26,14 +26,17 @@ define(
|
||||
|
||||
describe("Imagery view policy", function () {
|
||||
var testView,
|
||||
openmct,
|
||||
mockDomainObject,
|
||||
mockTelemetry,
|
||||
testMetadata,
|
||||
mockMetadata,
|
||||
policy;
|
||||
|
||||
beforeEach(function () {
|
||||
testView = { key: "imagery" };
|
||||
testMetadata = {};
|
||||
mockMetadata = jasmine.createSpyObj('metadata', [
|
||||
"valuesForHints"
|
||||
]);
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
'domainObject',
|
||||
['getId', 'getModel', 'getCapability']
|
||||
@ -45,30 +48,33 @@ define(
|
||||
mockDomainObject.getCapability.andCallFake(function (c) {
|
||||
return c === 'telemetry' ? mockTelemetry : undefined;
|
||||
});
|
||||
mockTelemetry.getMetadata.andReturn(testMetadata);
|
||||
mockDomainObject.getId.andReturn("some-id");
|
||||
mockDomainObject.getModel.andReturn({ name: "foo" });
|
||||
mockTelemetry.getMetadata.andReturn(mockMetadata);
|
||||
mockMetadata.valuesForHints.andReturn(["bar"]);
|
||||
|
||||
policy = new ImageryViewPolicy();
|
||||
openmct = { telemetry: mockTelemetry };
|
||||
|
||||
policy = new ImageryViewPolicy(openmct);
|
||||
});
|
||||
|
||||
it("checks for hints indicating image telemetry", function () {
|
||||
policy.allow(testView, mockDomainObject);
|
||||
expect(mockMetadata.valuesForHints)
|
||||
.toHaveBeenCalledWith(["image"]);
|
||||
});
|
||||
|
||||
it("allows the imagery view for domain objects with image telemetry", function () {
|
||||
testMetadata.ranges = [{ key: "foo", format: "imageUrl" }];
|
||||
expect(policy.allow(testView, mockDomainObject)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("disallows the imagery view for domain objects without image telemetry", function () {
|
||||
testMetadata.ranges = [{ key: "foo", format: "somethingElse" }];
|
||||
expect(policy.allow(testView, mockDomainObject)).toBeFalsy();
|
||||
});
|
||||
|
||||
it("disallows the imagery view for domain objects without telemetry", function () {
|
||||
testMetadata.ranges = [{ key: "foo", format: "imageUrl" }];
|
||||
mockDomainObject.getCapability.andReturn(undefined);
|
||||
mockMetadata.valuesForHints.andReturn([]);
|
||||
expect(policy.allow(testView, mockDomainObject)).toBeFalsy();
|
||||
});
|
||||
|
||||
it("allows other views", function () {
|
||||
testView.key = "somethingElse";
|
||||
testMetadata.ranges = [{ key: "foo", format: "somethingElse" }];
|
||||
expect(policy.allow(testView, mockDomainObject)).toBeTruthy();
|
||||
});
|
||||
|
||||
|
@ -34,7 +34,6 @@ define([
|
||||
'../example/extensions/bundle',
|
||||
'../example/forms/bundle',
|
||||
'../example/identity/bundle',
|
||||
'../example/imagery/bundle',
|
||||
'../example/mobile/bundle',
|
||||
'../example/msl/bundle',
|
||||
'../example/notifications/bundle',
|
||||
|
@ -25,13 +25,15 @@ define([
|
||||
'./utcTimeSystem/plugin',
|
||||
'../../example/generator/plugin',
|
||||
'../../platform/features/autoflow/plugin',
|
||||
'./timeConductor/plugin'
|
||||
'./timeConductor/plugin',
|
||||
'../../example/imagery/plugin'
|
||||
], function (
|
||||
_,
|
||||
UTCTimeSystem,
|
||||
GeneratorPlugin,
|
||||
AutoflowPlugin,
|
||||
TimeConductorPlugin
|
||||
TimeConductorPlugin,
|
||||
ExampleImagery
|
||||
) {
|
||||
var bundleMap = {
|
||||
CouchDB: 'platform/persistence/couch',
|
||||
@ -113,5 +115,7 @@ define([
|
||||
return GeneratorPlugin;
|
||||
};
|
||||
|
||||
plugins.ExampleImagery = ExampleImagery;
|
||||
|
||||
return plugins;
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user