mirror of
https://github.com/nasa/openmct.git
synced 2025-01-04 12:24:10 +00:00
Merge branch 'master' into open199
This commit is contained in:
commit
30e6980dc6
@ -62,7 +62,7 @@ define(
|
|||||||
// so it's not checked for here, just formatted for display
|
// so it's not checked for here, just formatted for display
|
||||||
// differently.
|
// differently.
|
||||||
return (i + offset) * 1000 + firstTime * 1000 -
|
return (i + offset) * 1000 + firstTime * 1000 -
|
||||||
(domain === 'yesterday' ? ONE_DAY : 0);
|
(domain === 'yesterday' ? (ONE_DAY * 1000) : 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
generatorData.getRangeValue = function (i, range) {
|
generatorData.getRangeValue = function (i, range) {
|
||||||
|
@ -97,7 +97,7 @@
|
|||||||
"provides": "actionService",
|
"provides": "actionService",
|
||||||
"type": "provider",
|
"type": "provider",
|
||||||
"implementation": "actions/ActionProvider.js",
|
"implementation": "actions/ActionProvider.js",
|
||||||
"depends": [ "actions[]" ]
|
"depends": [ "actions[]", "$log" ]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"provides": "actionService",
|
"provides": "actionService",
|
||||||
|
@ -39,9 +39,11 @@ define(
|
|||||||
* @imeplements {ActionService}
|
* @imeplements {ActionService}
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function ActionProvider(actions) {
|
function ActionProvider(actions, $log) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
this.$log = $log;
|
||||||
|
|
||||||
// Build up look-up tables
|
// Build up look-up tables
|
||||||
this.actions = actions;
|
this.actions = actions;
|
||||||
this.actionsByKey = {};
|
this.actionsByKey = {};
|
||||||
@ -74,6 +76,7 @@ define(
|
|||||||
var context = (actionContext || {}),
|
var context = (actionContext || {}),
|
||||||
category = context.category,
|
category = context.category,
|
||||||
key = context.key,
|
key = context.key,
|
||||||
|
$log = this.$log,
|
||||||
candidates;
|
candidates;
|
||||||
|
|
||||||
// Instantiate an action; invokes the constructor and
|
// Instantiate an action; invokes the constructor and
|
||||||
@ -103,12 +106,31 @@ define(
|
|||||||
// appliesTo method of given actions (if defined), and
|
// appliesTo method of given actions (if defined), and
|
||||||
// instantiate those applicable actions.
|
// instantiate those applicable actions.
|
||||||
function createIfApplicable(actions, context) {
|
function createIfApplicable(actions, context) {
|
||||||
return (actions || []).filter(function (Action) {
|
function isApplicable(Action) {
|
||||||
return Action.appliesTo ?
|
return Action.appliesTo ? Action.appliesTo(context) : true;
|
||||||
Action.appliesTo(context) : true;
|
}
|
||||||
}).map(function (Action) {
|
|
||||||
|
function instantiate(Action) {
|
||||||
|
try {
|
||||||
return instantiateAction(Action, context);
|
return instantiateAction(Action, context);
|
||||||
});
|
} catch (e) {
|
||||||
|
$log.error([
|
||||||
|
"Could not instantiate action",
|
||||||
|
Action.key,
|
||||||
|
"due to:",
|
||||||
|
e.message
|
||||||
|
].join(" "));
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isDefined(action) {
|
||||||
|
return action !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (actions || []).filter(isApplicable)
|
||||||
|
.map(instantiate)
|
||||||
|
.filter(isDefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match actions to the provided context by comparing "key"
|
// Match actions to the provided context by comparing "key"
|
||||||
|
@ -156,6 +156,13 @@ define(
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the default model for an object of this type. Note that
|
||||||
|
* this method returns a clone of the original model, so if using this
|
||||||
|
* method heavily, consider caching the result to optimize performance.
|
||||||
|
*
|
||||||
|
* @return {object} The default model for an object of this type.
|
||||||
|
*/
|
||||||
TypeImpl.prototype.getInitialModel = function () {
|
TypeImpl.prototype.getInitialModel = function () {
|
||||||
return JSON.parse(JSON.stringify(this.typeDef.model || {}));
|
return JSON.parse(JSON.stringify(this.typeDef.model || {}));
|
||||||
};
|
};
|
||||||
|
@ -30,7 +30,8 @@ define(
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
describe("The action provider", function () {
|
describe("The action provider", function () {
|
||||||
var actions,
|
var mockLog,
|
||||||
|
actions,
|
||||||
actionProvider;
|
actionProvider;
|
||||||
|
|
||||||
function SimpleAction() {
|
function SimpleAction() {
|
||||||
@ -62,6 +63,10 @@ define(
|
|||||||
MetadataAction.key = "metadata";
|
MetadataAction.key = "metadata";
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
|
mockLog = jasmine.createSpyObj(
|
||||||
|
'$log',
|
||||||
|
['error', 'warn', 'info', 'debug']
|
||||||
|
);
|
||||||
actions = [
|
actions = [
|
||||||
SimpleAction,
|
SimpleAction,
|
||||||
CategorizedAction,
|
CategorizedAction,
|
||||||
@ -137,6 +142,42 @@ define(
|
|||||||
expect(provided[0].getMetadata()).toEqual("custom metadata");
|
expect(provided[0].getMetadata()).toEqual("custom metadata");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("when actions throw errors during instantiation", function () {
|
||||||
|
var errorText,
|
||||||
|
provided;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
errorText = "some error text";
|
||||||
|
|
||||||
|
function BadAction() {
|
||||||
|
throw new Error(errorText);
|
||||||
|
}
|
||||||
|
|
||||||
|
provided = new ActionProvider(
|
||||||
|
[ SimpleAction, BadAction ],
|
||||||
|
mockLog
|
||||||
|
).getActions();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("logs an error", function () {
|
||||||
|
expect(mockLog.error)
|
||||||
|
.toHaveBeenCalledWith(jasmine.any(String));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("reports the error's message", function () {
|
||||||
|
expect(
|
||||||
|
mockLog.error.mostRecentCall.args[0].indexOf(errorText)
|
||||||
|
).not.toEqual(-1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("still provides valid actions", function () {
|
||||||
|
expect(provided.length).toEqual(1);
|
||||||
|
expect(provided[0].perform()).toEqual("simple");
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
@ -102,6 +102,8 @@ define(
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("provides a fresh initial model each time", function () {
|
it("provides a fresh initial model each time", function () {
|
||||||
|
var model = type.getInitialModel();
|
||||||
|
model.someKey = "some other value";
|
||||||
expect(type.getInitialModel().someKey).toEqual("some value");
|
expect(type.getInitialModel().someKey).toEqual("some value");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -122,6 +122,14 @@ define(
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AbstractComposeAction.appliesTo = function (context) {
|
||||||
|
var applicableObject =
|
||||||
|
context.selectedObject || context.domainObject;
|
||||||
|
|
||||||
|
return !!(applicableObject &&
|
||||||
|
applicableObject.hasCapability('context'));
|
||||||
|
};
|
||||||
|
|
||||||
return AbstractComposeAction;
|
return AbstractComposeAction;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -131,6 +131,9 @@ define(
|
|||||||
return AbstractComposeAction.prototype.perform.call(this)
|
return AbstractComposeAction.prototype.perform.call(this)
|
||||||
.then(success, error, notification);
|
.then(success, error, notification);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
CopyAction.appliesTo = AbstractComposeAction.appliesTo;
|
||||||
|
|
||||||
return CopyAction;
|
return CopyAction;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -35,14 +35,15 @@ define(
|
|||||||
* @memberof platform/entanglement
|
* @memberof platform/entanglement
|
||||||
*/
|
*/
|
||||||
function LinkAction(locationService, linkService, context) {
|
function LinkAction(locationService, linkService, context) {
|
||||||
return new AbstractComposeAction(
|
AbstractComposeAction.apply(
|
||||||
locationService,
|
this,
|
||||||
linkService,
|
[locationService, linkService, context, "Link"]
|
||||||
context,
|
|
||||||
"Link"
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LinkAction.prototype = Object.create(AbstractComposeAction.prototype);
|
||||||
|
LinkAction.appliesTo = AbstractComposeAction.appliesTo;
|
||||||
|
|
||||||
return LinkAction;
|
return LinkAction;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -35,14 +35,16 @@ define(
|
|||||||
* @memberof platform/entanglement
|
* @memberof platform/entanglement
|
||||||
*/
|
*/
|
||||||
function MoveAction(locationService, moveService, context) {
|
function MoveAction(locationService, moveService, context) {
|
||||||
return new AbstractComposeAction(
|
AbstractComposeAction.apply(
|
||||||
locationService,
|
this,
|
||||||
moveService,
|
[locationService, moveService, context, "Move"]
|
||||||
context,
|
|
||||||
"Move"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MoveAction.prototype = Object.create(AbstractComposeAction.prototype);
|
||||||
|
MoveAction.appliesTo = AbstractComposeAction.appliesTo;
|
||||||
|
|
||||||
return MoveAction;
|
return MoveAction;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -94,6 +94,28 @@ define(
|
|||||||
composeService = new MockCopyService();
|
composeService = new MockCopyService();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("are only applicable to domain objects with a context", function () {
|
||||||
|
var noContextObject = domainObjectFactory({
|
||||||
|
name: 'selectedObject',
|
||||||
|
model: { name: 'selectedObject' },
|
||||||
|
capabilities: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(AbstractComposeAction.appliesTo({
|
||||||
|
selectedObject: selectedObject
|
||||||
|
})).toBe(true);
|
||||||
|
expect(AbstractComposeAction.appliesTo({
|
||||||
|
domainObject: selectedObject
|
||||||
|
})).toBe(true);
|
||||||
|
|
||||||
|
expect(AbstractComposeAction.appliesTo({
|
||||||
|
selectedObject: noContextObject
|
||||||
|
})).toBe(false);
|
||||||
|
expect(AbstractComposeAction.appliesTo({
|
||||||
|
domainObject: noContextObject
|
||||||
|
})).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
describe("with context from context-action", function () {
|
describe("with context from context-action", function () {
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
|
@ -78,6 +78,8 @@ define(
|
|||||||
cachedObjects = [],
|
cachedObjects = [],
|
||||||
updater,
|
updater,
|
||||||
lastBounds,
|
lastBounds,
|
||||||
|
lastRange,
|
||||||
|
lastDomain,
|
||||||
handle;
|
handle;
|
||||||
|
|
||||||
// Populate the scope with axis information (specifically, options
|
// Populate the scope with axis information (specifically, options
|
||||||
@ -120,16 +122,16 @@ define(
|
|||||||
// Reinstantiate the plot updater (e.g. because we have a
|
// Reinstantiate the plot updater (e.g. because we have a
|
||||||
// new subscription.) This will clear the plot.
|
// new subscription.) This will clear the plot.
|
||||||
function recreateUpdater() {
|
function recreateUpdater() {
|
||||||
updater = new PlotUpdater(
|
var domain = $scope.axes[0].active.key,
|
||||||
handle,
|
range = $scope.axes[1].active.key,
|
||||||
($scope.axes[0].active || {}).key,
|
duration = PLOT_FIXED_DURATION;
|
||||||
($scope.axes[1].active || {}).key,
|
|
||||||
PLOT_FIXED_DURATION
|
updater = new PlotUpdater(handle, domain, range, duration);
|
||||||
);
|
lastDomain = domain;
|
||||||
self.limitTracker = new PlotLimitTracker(
|
lastRange = range;
|
||||||
handle,
|
|
||||||
($scope.axes[1].active || {}).key
|
self.limitTracker = new PlotLimitTracker(handle, range);
|
||||||
);
|
|
||||||
// Keep any externally-provided bounds
|
// Keep any externally-provided bounds
|
||||||
if (lastBounds) {
|
if (lastBounds) {
|
||||||
setBasePanZoom(lastBounds);
|
setBasePanZoom(lastBounds);
|
||||||
@ -201,22 +203,39 @@ define(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function requery() {
|
||||||
|
self.pending = true;
|
||||||
|
releaseSubscription();
|
||||||
|
subscribe($scope.domainObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDomainFormat() {
|
||||||
|
var domainAxis = $scope.axes[0];
|
||||||
|
plotTelemetryFormatter
|
||||||
|
.setDomainFormat(domainAxis.active.format);
|
||||||
|
}
|
||||||
|
|
||||||
|
function domainRequery(newDomain) {
|
||||||
|
if (newDomain !== lastDomain) {
|
||||||
|
updateDomainFormat();
|
||||||
|
requery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function rangeRequery(newRange) {
|
||||||
|
if (newRange !== lastRange) {
|
||||||
|
requery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Respond to a display bounds change (requery for data)
|
// Respond to a display bounds change (requery for data)
|
||||||
function changeDisplayBounds(event, bounds) {
|
function changeDisplayBounds(event, bounds) {
|
||||||
var domainAxis = $scope.axes[0];
|
var domainAxis = $scope.axes[0];
|
||||||
|
|
||||||
domainAxis.chooseOption(bounds.domain);
|
domainAxis.chooseOption(bounds.domain);
|
||||||
plotTelemetryFormatter
|
updateDomainFormat();
|
||||||
.setDomainFormat(domainAxis.active.format);
|
|
||||||
|
|
||||||
self.pending = true;
|
|
||||||
releaseSubscription();
|
|
||||||
subscribe($scope.domainObject);
|
|
||||||
setBasePanZoom(bounds);
|
setBasePanZoom(bounds);
|
||||||
}
|
requery();
|
||||||
|
|
||||||
function updateDomainFormat(format) {
|
|
||||||
plotTelemetryFormatter.setDomainFormat(format);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.modeOptions = new PlotModeOptions([], subPlotFactory);
|
this.modeOptions = new PlotModeOptions([], subPlotFactory);
|
||||||
@ -237,6 +256,10 @@ define(
|
|||||||
new PlotAxis("ranges", [], AXIS_DEFAULTS[1])
|
new PlotAxis("ranges", [], AXIS_DEFAULTS[1])
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Watch for changes to the selected axis
|
||||||
|
$scope.$watch("axes[0].active.key", domainRequery);
|
||||||
|
$scope.$watch("axes[1].active.key", rangeRequery);
|
||||||
|
|
||||||
// Subscribe to telemetry when a domain object becomes available
|
// Subscribe to telemetry when a domain object becomes available
|
||||||
$scope.$watch('domainObject', subscribe);
|
$scope.$watch('domainObject', subscribe);
|
||||||
|
|
||||||
|
@ -53,6 +53,14 @@ define(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fireWatch(expr, value) {
|
||||||
|
mockScope.$watch.calls.forEach(function (call) {
|
||||||
|
if (call.args[0] === expr) {
|
||||||
|
call.args[1].apply(null, [value]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
mockScope = jasmine.createSpyObj(
|
mockScope = jasmine.createSpyObj(
|
||||||
@ -263,6 +271,20 @@ define(
|
|||||||
]);
|
]);
|
||||||
expect(mockHandle.request.calls.length).toEqual(2);
|
expect(mockHandle.request.calls.length).toEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("requeries when user changes domain selection", function () {
|
||||||
|
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||||
|
expect(mockHandle.request.calls.length).toEqual(1);
|
||||||
|
fireWatch("axes[0].active.key", 'someNewKey');
|
||||||
|
expect(mockHandle.request.calls.length).toEqual(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("requeries when user changes range selection", function () {
|
||||||
|
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||||
|
expect(mockHandle.request.calls.length).toEqual(1);
|
||||||
|
fireWatch("axes[1].active.key", 'someNewKey');
|
||||||
|
expect(mockHandle.request.calls.length).toEqual(2);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -285,11 +285,17 @@ define(
|
|||||||
* domain objects returned by `getTelemetryObjects()`.
|
* domain objects returned by `getTelemetryObjects()`.
|
||||||
*
|
*
|
||||||
* @param {DomainObject} domainObject the object of interest
|
* @param {DomainObject} domainObject the object of interest
|
||||||
|
* @param {string} [key] the symbolic identifier of the domain
|
||||||
|
* to look up; if omitted, the value for this object's
|
||||||
|
* default domain will be used
|
||||||
* @returns the most recent domain value observed
|
* @returns the most recent domain value observed
|
||||||
*/
|
*/
|
||||||
TelemetrySubscription.prototype.getDomainValue = function (domainObject) {
|
TelemetrySubscription.prototype.getDomainValue = function (domainObject, key) {
|
||||||
var id = domainObject.getId();
|
var id = domainObject.getId(),
|
||||||
return (this.latestValues[id] || {}).domain;
|
latestValue = this.latestValues[id];
|
||||||
|
return latestValue && (key ?
|
||||||
|
latestValue.datum[key] :
|
||||||
|
latestValue.domain);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -302,11 +308,17 @@ define(
|
|||||||
* domain objects returned by `getTelemetryObjects()`.
|
* domain objects returned by `getTelemetryObjects()`.
|
||||||
*
|
*
|
||||||
* @param {DomainObject} domainObject the object of interest
|
* @param {DomainObject} domainObject the object of interest
|
||||||
|
* @param {string} [key] the symbolic identifier of the range
|
||||||
|
* to look up; if omitted, the value for this object's
|
||||||
|
* default range will be used
|
||||||
* @returns the most recent range value observed
|
* @returns the most recent range value observed
|
||||||
*/
|
*/
|
||||||
TelemetrySubscription.prototype.getRangeValue = function (domainObject) {
|
TelemetrySubscription.prototype.getRangeValue = function (domainObject, key) {
|
||||||
var id = domainObject.getId();
|
var id = domainObject.getId(),
|
||||||
return (this.latestValues[id] || {}).range;
|
latestValue = this.latestValues[id];
|
||||||
|
return latestValue && (key ?
|
||||||
|
latestValue.datum[key] :
|
||||||
|
latestValue.range);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user