From 65bf38d5e6f2c7d98f6ff56544d1908f187fed58 Mon Sep 17 00:00:00 2001 From: Charles Hacskaylo Date: Fri, 27 Jan 2017 11:16:06 -0800 Subject: [PATCH 01/38] [Frontend] Add grab affordance styling on hover Fixes #1415 WIP --- .../core/res/sass/_time-conductor-base.scss | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/platform/features/conductor/core/res/sass/_time-conductor-base.scss b/platform/features/conductor/core/res/sass/_time-conductor-base.scss index 629c17f726..f49e8c6669 100644 --- a/platform/features/conductor/core/res/sass/_time-conductor-base.scss +++ b/platform/features/conductor/core/res/sass/_time-conductor-base.scss @@ -346,7 +346,28 @@ content: $i; } .l-axis-holder { + $grabTicksH: 8px; + $grabTicksXSpace: 3px; + $grabTicksYOffset: (($r1H - $grabTicksH) / 2) - 2px; @include cursorGrab(); + &:hover { + $c0: rgba($colorBodyFg, 0.05); + $c2: transparent; // Bg + @include background-image(linear-gradient( + $c0 70%, $c2 100% + )); + svg { + $c1: rgba($colorBodyFg, 0.15); // Line + $angle: 90deg; + @include background-image(linear-gradient($angle, + $c1 1px, $c2 1px, + $c2 100% + )); + background-position: center $grabTicksYOffset; + background-repeat: repeat-x; + background-size: $grabTicksXSpace $grabTicksH; + } + } } } From d1e7e7894e1c02df3cf8c467843e3ac98b4785c9 Mon Sep 17 00:00:00 2001 From: Charles Hacskaylo Date: Fri, 27 Jan 2017 13:58:38 -0800 Subject: [PATCH 02/38] [Frontend] Add grab affordance styling on hover Fixes #1415 --- .../conductor/core/res/sass/_time-conductor-base.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/features/conductor/core/res/sass/_time-conductor-base.scss b/platform/features/conductor/core/res/sass/_time-conductor-base.scss index f49e8c6669..e1dad98dad 100644 --- a/platform/features/conductor/core/res/sass/_time-conductor-base.scss +++ b/platform/features/conductor/core/res/sass/_time-conductor-base.scss @@ -351,13 +351,13 @@ $grabTicksYOffset: (($r1H - $grabTicksH) / 2) - 2px; @include cursorGrab(); &:hover { - $c0: rgba($colorBodyFg, 0.05); + $c0: rgba($colorBodyFg, 0.1); $c2: transparent; // Bg @include background-image(linear-gradient( $c0 70%, $c2 100% )); svg { - $c1: rgba($colorBodyFg, 0.15); // Line + $c1: rgba($colorBodyFg, 0.2); // Line $angle: 90deg; @include background-image(linear-gradient($angle, $c1 1px, $c2 1px, From 784114e2561a95983f9acd6478c98e31e6c45d35 Mon Sep 17 00:00:00 2001 From: Charles Hacskaylo Date: Fri, 27 Jan 2017 14:07:36 -0800 Subject: [PATCH 03/38] [Frontend] Add grab affordance grippys Fixes #1415 --- .../core/res/sass/_time-conductor-base.scss | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/platform/features/conductor/core/res/sass/_time-conductor-base.scss b/platform/features/conductor/core/res/sass/_time-conductor-base.scss index e1dad98dad..96e45ad447 100644 --- a/platform/features/conductor/core/res/sass/_time-conductor-base.scss +++ b/platform/features/conductor/core/res/sass/_time-conductor-base.scss @@ -346,27 +346,27 @@ content: $i; } .l-axis-holder { - $grabTicksH: 8px; - $grabTicksXSpace: 3px; - $grabTicksYOffset: (($r1H - $grabTicksH) / 2) - 2px; + $c0: rgba($colorBodyFg, 0.1); + $c2: transparent; + $grabTicksH: 3px; + $grabTicksXSpace: 4px; + $grabTicksYOffset: 0; @include cursorGrab(); + svg { + $c1: rgba($colorBodyFg, 0.2); + $angle: 90deg; + @include background-image(linear-gradient($angle, + $c1 1px, $c2 1px, + $c2 100% + )); + background-position: center $grabTicksYOffset; + background-repeat: repeat-x; + background-size: $grabTicksXSpace $grabTicksH; + } &:hover { - $c0: rgba($colorBodyFg, 0.1); - $c2: transparent; // Bg @include background-image(linear-gradient( $c0 70%, $c2 100% )); - svg { - $c1: rgba($colorBodyFg, 0.2); // Line - $angle: 90deg; - @include background-image(linear-gradient($angle, - $c1 1px, $c2 1px, - $c2 100% - )); - background-position: center $grabTicksYOffset; - background-repeat: repeat-x; - background-size: $grabTicksXSpace $grabTicksH; - } } } } From af3cbe9ed1cddbdffe757f86af7a00839052c0b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=CC=81s=CC=8C=20Stankovic=CC=8C?= Date: Tue, 7 Feb 2017 23:11:23 +0100 Subject: [PATCH 04/38] [Optimization] Reduce D3 dependency size #1224 --- bower.json | 1 - karma.conf.js | 1 + openmct.js | 22 ++++++++++++++++--- package.json | 10 +++++++++ .../core/src/ui/ConductorAxisController.js | 18 ++++++++------- .../src/ui/ConductorAxisControllerSpec.js | 18 ++++++++------- test-main.js | 22 ++++++++++++++++--- 7 files changed, 69 insertions(+), 23 deletions(-) diff --git a/bower.json b/bower.json index 161ee04186..ed3dbaf899 100644 --- a/bower.json +++ b/bower.json @@ -22,7 +22,6 @@ "eventemitter3": "^1.2.0", "lodash": "3.10.1", "almond": "~0.3.2", - "d3": "~4.1.0", "html2canvas": "^0.4.1" } } diff --git a/karma.conf.js b/karma.conf.js index 84909b42a7..f4bd0a10b5 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -35,6 +35,7 @@ module.exports = function(config) { // By default, files are also included in a script tag. files: [ {pattern: 'bower_components/**/*.js', included: false}, + {pattern: 'node_modules/d3-*/**/*.js', included: false}, {pattern: 'src/**/*.js', included: false}, {pattern: 'example/**/*.js', included: false}, {pattern: 'example/**/*.json', included: false}, diff --git a/openmct.js b/openmct.js index 68151008cd..3084f96a4d 100644 --- a/openmct.js +++ b/openmct.js @@ -38,7 +38,16 @@ requirejs.config({ "uuid": "bower_components/node-uuid/uuid", "zepto": "bower_components/zepto/zepto.min", "lodash": "bower_components/lodash/lodash", - "d3": "bower_components/d3/d3.min" + "d3-selection": "node_modules/d3-selection/build/d3-selection.min", + "d3-scale": "node_modules/d3-scale/build/d3-scale.min", + "d3-axis": "node_modules/d3-axis/build/d3-axis.min", + "d3-array": "node_modules/d3-array/build/d3-array.min", + "d3-collection": "node_modules/d3-collection/build/d3-collection.min", + "d3-color": "node_modules/d3-color/build/d3-color.min", + "d3-format": "node_modules/d3-format/build/d3-format.min", + "d3-interpolate": "node_modules/d3-interpolate/build/d3-interpolate.min", + "d3-time": "node_modules/d3-time/build/d3-time.min", + "d3-time-format": "node_modules/d3-time-format/build/d3-time-format.min", }, "shim": { "angular": { @@ -65,8 +74,15 @@ requirejs.config({ "lodash": { "exports": "lodash" }, - "d3": { - "exports": "d3" + "d3-selection": { + "exports": "d3-selection" + }, + "d3-scale": { + "deps": ["d3-array", "d3-collection", "d3-color", "d3-format", "d3-interpolate", "d3-time", "d3-time-format"], + "exports": "d3-scale" + }, + "d3-axis": { + "exports": "d3-axis" } } }); diff --git a/package.json b/package.json index 65fabeb1f6..55bc7ab667 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,16 @@ "version": "0.12.1-SNAPSHOT", "description": "The Open MCT core platform", "dependencies": { + "d3-array": "^1.0.2", + "d3-axis": "^1.0.4", + "d3-collection": "^1.0.2", + "d3-color": "^1.0.2", + "d3-format": "^1.0.2", + "d3-interpolate": "^1.1.3", + "d3-scale": "^1.0.4", + "d3-selection": "^1.0.3", + "d3-time": "^1.0.4", + "d3-time-format": "^2.0.3", "express": "^4.13.1", "minimist": "^1.1.1", "request": "^2.69.0" diff --git a/platform/features/conductor/core/src/ui/ConductorAxisController.js b/platform/features/conductor/core/src/ui/ConductorAxisController.js index b99eaa0e6e..7d4c2df7da 100644 --- a/platform/features/conductor/core/src/ui/ConductorAxisController.js +++ b/platform/features/conductor/core/src/ui/ConductorAxisController.js @@ -22,9 +22,11 @@ define( [ - "d3" + "d3-selection", + "d3-scale", + "d3-axis" ], - function (d3) { + function (d3Selection, d3Scale, d3Axis) { var PADDING = 1; /** @@ -70,12 +72,12 @@ define( ConductorAxisController.prototype.initialize = function (element) { this.target = element[0].firstChild; var height = this.target.offsetHeight; - var vis = d3.select(this.target) + var vis = d3Selection.select(this.target) .append("svg:svg") .attr("width", "100%") .attr("height", height); - this.xAxis = d3.axisTop(); + this.xAxis = d3Axis.axisTop(); // draw x axis with labels and move to the bottom of the chart area this.axisElement = vis.append("g") @@ -115,10 +117,10 @@ define( var bounds = this.bounds; if (timeSystem.isUTCBased()) { - this.xScale = this.xScale || d3.scaleUtc(); + this.xScale = this.xScale || d3Scale.scaleUtc(); this.xScale.domain([new Date(bounds.start), new Date(bounds.end)]); } else { - this.xScale = this.xScale || d3.scaleLinear(); + this.xScale = this.xScale || d3Scale.scaleLinear(); this.xScale.domain([bounds.start, bounds.end]); } @@ -145,9 +147,9 @@ define( //The D3 scale used depends on the type of time system as d3 // supports UTC out of the box. if (timeSystem.isUTCBased()) { - this.xScale = d3.scaleUtc(); + this.xScale = d3Scale.scaleUtc(); } else { - this.xScale = d3.scaleLinear(); + this.xScale = d3Scale.scaleLinear(); } this.xAxis.scale(this.xScale); diff --git a/platform/features/conductor/core/src/ui/ConductorAxisControllerSpec.js b/platform/features/conductor/core/src/ui/ConductorAxisControllerSpec.js index 2dbbb42c4b..6cc9677a16 100644 --- a/platform/features/conductor/core/src/ui/ConductorAxisControllerSpec.js +++ b/platform/features/conductor/core/src/ui/ConductorAxisControllerSpec.js @@ -23,11 +23,13 @@ define([ './ConductorAxisController', 'zepto', - 'd3' + 'd3-selection', + 'd3-scale' ], function ( ConductorAxisController, $, - d3 + d3Selection, + d3Scale ) { describe("The ConductorAxisController", function () { var controller, @@ -84,8 +86,8 @@ define([ "emit" ]); - spyOn(d3, 'scaleUtc').andCallThrough(); - spyOn(d3, 'scaleLinear').andCallThrough(); + spyOn(d3Scale, 'scaleUtc').andCallThrough(); + spyOn(d3Scale, 'scaleLinear').andCallThrough(); element = $('
'); $(document).find('body').append(element); @@ -122,15 +124,15 @@ define([ mockTimeSystem.isUTCBased.andReturn(true); controller.changeTimeSystem(mockTimeSystem); - expect(d3.scaleUtc).toHaveBeenCalled(); - expect(d3.scaleLinear).not.toHaveBeenCalled(); + expect(d3Scale.scaleUtc).toHaveBeenCalled(); + expect(d3Scale.scaleLinear).not.toHaveBeenCalled(); }); it("uses a linear scale for non-UTC time systems", function () { mockTimeSystem.isUTCBased.andReturn(false); controller.changeTimeSystem(mockTimeSystem); - expect(d3.scaleLinear).toHaveBeenCalled(); - expect(d3.scaleUtc).not.toHaveBeenCalled(); + expect(d3Scale.scaleLinear).toHaveBeenCalled(); + expect(d3Scale.scaleUtc).not.toHaveBeenCalled(); }); it("sets axis domain to time conductor bounds", function () { diff --git a/test-main.js b/test-main.js index b300560588..3f30247742 100644 --- a/test-main.js +++ b/test-main.js @@ -64,7 +64,16 @@ requirejs.config({ "uuid": "bower_components/node-uuid/uuid", "zepto": "bower_components/zepto/zepto.min", "lodash": "bower_components/lodash/lodash", - "d3": "bower_components/d3/d3.min" + "d3-selection": "node_modules/d3-selection/build/d3-selection.min", + "d3-scale": "node_modules/d3-scale/build/d3-scale.min", + "d3-axis": "node_modules/d3-axis/build/d3-axis.min", + "d3-array": "node_modules/d3-array/build/d3-array.min", + "d3-collection": "node_modules/d3-collection/build/d3-collection.min", + "d3-color": "node_modules/d3-color/build/d3-color.min", + "d3-format": "node_modules/d3-format/build/d3-format.min", + "d3-interpolate": "node_modules/d3-interpolate/build/d3-interpolate.min", + "d3-time": "node_modules/d3-time/build/d3-time.min", + "d3-time-format": "node_modules/d3-time-format/build/d3-time-format.min" }, "shim": { @@ -89,8 +98,15 @@ requirejs.config({ "lodash": { "exports": "lodash" }, - "d3": { - "exports": "d3" + "d3-selection": { + "exports": "d3-selection" + }, + "d3-scale": { + "deps": ["d3-array", "d3-collection", "d3-color", "d3-format", "d3-interpolate", "d3-time", "d3-time-format"], + "exports": "d3-scale" + }, + "d3-axis": { + "exports": "d3-axis" } }, From eb91cd33befd0e4e525ea90287de957141e1839d Mon Sep 17 00:00:00 2001 From: Bogdan Date: Sat, 25 Feb 2017 15:05:29 +0200 Subject: [PATCH 05/38] [Copy] Diff between user cancellation and failure --- platform/entanglement/src/actions/AbstractComposeAction.js | 2 ++ platform/entanglement/src/actions/CopyAction.js | 4 ++++ .../entanglement/test/actions/AbstractComposeActionSpec.js | 4 ++-- platform/entanglement/test/actions/CopyActionSpec.js | 4 ++-- platform/entanglement/test/actions/LinkActionSpec.js | 4 ++-- platform/entanglement/test/actions/MoveActionSpec.js | 4 ++-- 6 files changed, 14 insertions(+), 8 deletions(-) diff --git a/platform/entanglement/src/actions/AbstractComposeAction.js b/platform/entanglement/src/actions/AbstractComposeAction.js index 943c2adb0a..4373fe2ca3 100644 --- a/platform/entanglement/src/actions/AbstractComposeAction.js +++ b/platform/entanglement/src/actions/AbstractComposeAction.js @@ -141,6 +141,8 @@ define( currentParent ).then(function (newParentObj) { return composeService.perform(object, newParentObj); + }, function () { + return Promise.reject({ message: "cancelled" }); }); }; diff --git a/platform/entanglement/src/actions/CopyAction.js b/platform/entanglement/src/actions/CopyAction.js index 6388c25b74..0c2e241be2 100644 --- a/platform/entanglement/src/actions/CopyAction.js +++ b/platform/entanglement/src/actions/CopyAction.js @@ -117,6 +117,10 @@ define( } function error(errorDetails) { + if (errorDetails && (errorDetails.message === "cancelled")) { + return; + } + var errorDialog, errorMessage = { title: "Error copying objects.", diff --git a/platform/entanglement/test/actions/AbstractComposeActionSpec.js b/platform/entanglement/test/actions/AbstractComposeActionSpec.js index 80fde42748..1f4b70362e 100644 --- a/platform/entanglement/test/actions/AbstractComposeActionSpec.js +++ b/platform/entanglement/test/actions/AbstractComposeActionSpec.js @@ -157,9 +157,9 @@ define( ); }); - it("waits for location from user", function () { + it("waits for location and handles cancellation by user", function () { expect(locationServicePromise.then) - .toHaveBeenCalledWith(jasmine.any(Function)); + .toHaveBeenCalledWith(jasmine.any(Function), jasmine.any(Function)); }); it("copies object to selected location", function () { diff --git a/platform/entanglement/test/actions/CopyActionSpec.js b/platform/entanglement/test/actions/CopyActionSpec.js index 380d5ebd18..918f73d7f4 100644 --- a/platform/entanglement/test/actions/CopyActionSpec.js +++ b/platform/entanglement/test/actions/CopyActionSpec.js @@ -180,9 +180,9 @@ define( ); }); - it("waits for location from user", function () { + it("waits for location and handles cancellation by user", function () { expect(locationServicePromise.then) - .toHaveBeenCalledWith(jasmine.any(Function)); + .toHaveBeenCalledWith(jasmine.any(Function), jasmine.any(Function)); }); it("copies object to selected location", function () { diff --git a/platform/entanglement/test/actions/LinkActionSpec.js b/platform/entanglement/test/actions/LinkActionSpec.js index f7930bf0dd..d84b993e24 100644 --- a/platform/entanglement/test/actions/LinkActionSpec.js +++ b/platform/entanglement/test/actions/LinkActionSpec.js @@ -133,9 +133,9 @@ define( ); }); - it("waits for location from user", function () { + it("waits for location and handles cancellation by user", function () { expect(locationServicePromise.then) - .toHaveBeenCalledWith(jasmine.any(Function)); + .toHaveBeenCalledWith(jasmine.any(Function), jasmine.any(Function)); }); it("links object to selected location", function () { diff --git a/platform/entanglement/test/actions/MoveActionSpec.js b/platform/entanglement/test/actions/MoveActionSpec.js index bc5398d599..ff65e3f444 100644 --- a/platform/entanglement/test/actions/MoveActionSpec.js +++ b/platform/entanglement/test/actions/MoveActionSpec.js @@ -133,9 +133,9 @@ define( ); }); - it("waits for location from user", function () { + it("waits for location and handles cancellation by user", function () { expect(locationServicePromise.then) - .toHaveBeenCalledWith(jasmine.any(Function)); + .toHaveBeenCalledWith(jasmine.any(Function), jasmine.any(Function)); }); it("moves object to selected location", function () { From da40f4c96e6a0a449488abaf1ddc7d9278e49234 Mon Sep 17 00:00:00 2001 From: Henry Date: Mon, 27 Feb 2017 16:07:56 -0800 Subject: [PATCH 06/38] [Plot] Add current conductor bounds to telemetry requests via the old API. Replaces telemetry decorator. Fixes #1458 --- .../conductor/compatibility/bundle.js | 12 --- .../src/ConductorTelemetryDecorator.js | 87 ------------------- platform/telemetry/src/TelemetryCapability.js | 9 +- .../telemetry/test/TelemetryCapabilitySpec.js | 22 ++++- 4 files changed, 26 insertions(+), 104 deletions(-) delete mode 100644 platform/features/conductor/compatibility/src/ConductorTelemetryDecorator.js diff --git a/platform/features/conductor/compatibility/bundle.js b/platform/features/conductor/compatibility/bundle.js index 7a7a928332..ee945a5b15 100644 --- a/platform/features/conductor/compatibility/bundle.js +++ b/platform/features/conductor/compatibility/bundle.js @@ -21,11 +21,9 @@ *****************************************************************************/ define([ - "./src/ConductorTelemetryDecorator", "./src/ConductorRepresenter", 'legacyRegistry' ], function ( - ConductorTelemetryDecorator, ConductorRepresenter, legacyRegistry ) { @@ -39,16 +37,6 @@ define([ "openmct" ] } - ], - "components": [ - { - "type": "decorator", - "provides": "telemetryService", - "implementation": ConductorTelemetryDecorator, - "depends": [ - "openmct" - ] - } ] } }); diff --git a/platform/features/conductor/compatibility/src/ConductorTelemetryDecorator.js b/platform/features/conductor/compatibility/src/ConductorTelemetryDecorator.js deleted file mode 100644 index 137da59268..0000000000 --- a/platform/features/conductor/compatibility/src/ConductorTelemetryDecorator.js +++ /dev/null @@ -1,87 +0,0 @@ -/***************************************************************************** - * 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; - } -); diff --git a/platform/telemetry/src/TelemetryCapability.js b/platform/telemetry/src/TelemetryCapability.js index 4112b5740b..2ce6fe9cf8 100644 --- a/platform/telemetry/src/TelemetryCapability.js +++ b/platform/telemetry/src/TelemetryCapability.js @@ -139,7 +139,8 @@ define( type = domainObject.getCapability("type"), typeRequest = (type && type.getDefinition().telemetry) || {}, modelTelemetry = domainObject.getModel().telemetry, - fullRequest = Object.create(typeRequest); + fullRequest = Object.create(typeRequest), + bounds; // Add properties from the telemetry field of this // specific domain object. @@ -160,6 +161,12 @@ define( fullRequest.key = domainObject.getId(); } + if (request.start === undefined && request.end === undefined) { + bounds = this.openmct.conductor.bounds(); + fullRequest.start = bounds.start; + fullRequest.end = bounds.end; + } + return fullRequest; }; diff --git a/platform/telemetry/test/TelemetryCapabilitySpec.js b/platform/telemetry/test/TelemetryCapabilitySpec.js index 04d603d0a2..1f5ff32927 100644 --- a/platform/telemetry/test/TelemetryCapabilitySpec.js +++ b/platform/telemetry/test/TelemetryCapabilitySpec.js @@ -97,7 +97,15 @@ define( }); mockAPI = { - telemetry: mockTelemetryAPI + telemetry: mockTelemetryAPI, + conductor: { + bounds: function () { + return { + start: 0, + end: 1 + }; + } + } }; telemetry = new TelemetryCapability( @@ -150,7 +158,9 @@ define( expect(telemetry.getMetadata()).toEqual({ id: "testId", // from domain object source: "testSource", - key: "testKey" + key: "testKey", + start: 0, + end: 1 }); }); @@ -164,7 +174,9 @@ define( expect(telemetry.getMetadata()).toEqual({ id: "testId", // from domain object source: "testSource", // from model - key: "testId" // from domain object + key: "testId", // from domain object + start: 0, + end: 1 }); }); @@ -243,7 +255,9 @@ define( [{ id: "testId", // from domain object source: "testSource", - key: "testKey" + key: "testKey", + start: 0, + end: 1 }] ); From 16b6a70e22b6a7e53529bdddfac3a606b4bea533 Mon Sep 17 00:00:00 2001 From: Charles Hacskaylo Date: Tue, 21 Mar 2017 10:18:29 -0700 Subject: [PATCH 07/38] [Frontend] Cleanups for Inspector Fixes #1266 --- .../commonUI/general/res/sass/_inspector.scss | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/platform/commonUI/general/res/sass/_inspector.scss b/platform/commonUI/general/res/sass/_inspector.scss index 7d30c978af..1928f81169 100644 --- a/platform/commonUI/general/res/sass/_inspector.scss +++ b/platform/commonUI/general/res/sass/_inspector.scss @@ -76,17 +76,18 @@ &:not(.first) { border-top: 1px solid $colorFormLines; } - .form-row { - @include align-items(center); - border: none; - padding: $interiorMarginSm 0; - .label { - min-width: 80px; - } - input[type='text'], - input[type='search'] { - width: 100%; - } + } + .form-row { + @include align-items(center); + border: none !important; + margin-bottom: 0 !important; + padding: $interiorMarginSm 0; + .label { + min-width: 80px; + } + input[type='text'], + input[type='search'] { + width: 100%; } } } From 399b74508406818a22df6bd0cb3d6da66647889b Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 23 Mar 2017 17:18:00 -0700 Subject: [PATCH 08/38] [Persistence] Prevent editing of objects that cannot be saved. Fixes #1483 --- platform/commonUI/edit/bundle.js | 7 +++ .../policies/EditPersistableObjectsPolicy.js | 59 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 platform/commonUI/edit/src/policies/EditPersistableObjectsPolicy.js diff --git a/platform/commonUI/edit/bundle.js b/platform/commonUI/edit/bundle.js index d4e63e063b..24948b97e3 100644 --- a/platform/commonUI/edit/bundle.js +++ b/platform/commonUI/edit/bundle.js @@ -34,6 +34,7 @@ define([ "./src/actions/SaveAsAction", "./src/actions/CancelAction", "./src/policies/EditActionPolicy", + "./src/policies/EditPersistableObjectsPolicy", "./src/policies/EditableLinkPolicy", "./src/policies/EditableMovePolicy", "./src/policies/EditContextualActionPolicy", @@ -72,6 +73,7 @@ define([ SaveAsAction, CancelAction, EditActionPolicy, + EditPersistableObjectsPolicy, EditableLinkPolicy, EditableMovePolicy, EditContextualActionPolicy, @@ -247,6 +249,11 @@ define([ "category": "action", "implementation": EditActionPolicy }, + { + "category": "action", + "implementation": EditPersistableObjectsPolicy, + "depends": ["openmct"] + }, { "category": "action", "implementation": EditContextualActionPolicy, diff --git a/platform/commonUI/edit/src/policies/EditPersistableObjectsPolicy.js b/platform/commonUI/edit/src/policies/EditPersistableObjectsPolicy.js new file mode 100644 index 0000000000..7377aab47b --- /dev/null +++ b/platform/commonUI/edit/src/policies/EditPersistableObjectsPolicy.js @@ -0,0 +1,59 @@ +/***************************************************************************** + * 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/api/objects/object-utils'], + function (objectUtils) { + + /** + * Policy that prevents editing of any object from a provider that does not + * support persistence (ie. the 'save' operation). Editing is prevented + * as a subsequent save would fail, causing the loss of a user's changes. + * @param openmct + * @constructor + */ + function EditPersistableObjectsPolicy(openmct) { + this.openmct = openmct; + } + + EditPersistableObjectsPolicy.prototype.allow = function (action, context) { + var identifier; + var provider; + var domainObject = context.domainObject; + var key = action.getMetadata().key; + var category = (context || {}).category; + + // Use category to selectively block edit from the view. Edit action + // is also invoked during the create process which should be allowed, + // because it may be saved elsewhere + if ((key === 'edit' && category === 'view-control') || key === 'properties') { + identifier = objectUtils.parseKeyString(domainObject.getId()); + provider = this.openmct.objects.getProvider(identifier); + return provider.save !== undefined; + } + + return true; + }; + + return EditPersistableObjectsPolicy; + } +); From 1cb5dd021f7e678d0da2421e2d2fc8f78dce5c18 Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 24 Mar 2017 16:59:30 -0700 Subject: [PATCH 09/38] Modified composition policies to consider object instances instead of types. Fixes #669 --- platform/commonUI/edit/src/creation/CreateWizard.js | 6 ++---- platform/containment/bundle.js | 8 ++++++++ platform/containment/src/ComposeActionPolicy.js | 5 +---- platform/containment/src/CompositionModelPolicy.js | 3 ++- platform/containment/src/CompositionMutabilityPolicy.js | 2 +- platform/containment/src/CompositionPolicy.js | 8 ++++---- platform/entanglement/src/services/CopyService.js | 2 +- platform/entanglement/src/services/LinkService.js | 2 +- platform/entanglement/src/services/MoveService.js | 2 +- platform/features/layout/src/LayoutCompositionPolicy.js | 3 ++- src/adapter/policies/AdapterCompositionPolicy.js | 6 ++---- 11 files changed, 25 insertions(+), 22 deletions(-) diff --git a/platform/commonUI/edit/src/creation/CreateWizard.js b/platform/commonUI/edit/src/creation/CreateWizard.js index 79416ac4b4..2448a10d72 100644 --- a/platform/commonUI/edit/src/creation/CreateWizard.js +++ b/platform/commonUI/edit/src/creation/CreateWizard.js @@ -60,11 +60,9 @@ define( policyService = this.policyService; function validateLocation(parent) { - var parentType = parent && - parent.getCapability('type'); - return parentType && policyService.allow( + return parent && policyService.allow( "composition", - parentType, + parent, domainObject ); } diff --git a/platform/containment/bundle.js b/platform/containment/bundle.js index a64710b974..7bbfff0f3f 100644 --- a/platform/containment/bundle.js +++ b/platform/containment/bundle.js @@ -25,12 +25,14 @@ define([ "./src/CompositionMutabilityPolicy", "./src/CompositionModelPolicy", "./src/ComposeActionPolicy", + "./src/PersistableCompositionPolicy", 'legacyRegistry' ], function ( CompositionPolicy, CompositionMutabilityPolicy, CompositionModelPolicy, ComposeActionPolicy, + PersistableCompositionPolicy, legacyRegistry ) { @@ -59,6 +61,12 @@ define([ "$injector" ], "message": "Objects of this type cannot contain objects of that type." + }, + { + "category": "composition", + "implementation": PersistableCompositionPolicy, + "depends": ["openmct"], + "message": "Change cannot be made to composition of non-persistable object" } ] } diff --git a/platform/containment/src/ComposeActionPolicy.js b/platform/containment/src/ComposeActionPolicy.js index 0a107756af..1a9092772f 100644 --- a/platform/containment/src/ComposeActionPolicy.js +++ b/platform/containment/src/ComposeActionPolicy.js @@ -43,9 +43,6 @@ define( } ComposeActionPolicy.prototype.allowComposition = function (containerObject, selectedObject) { - // Get the object types involved in the compose action - var containerType = containerObject && - containerObject.getCapability('type'); // Get a reference to the policy service if needed... this.policyService = this.policyService || this.getPolicyService(); @@ -54,7 +51,7 @@ define( return containerObject.getId() !== selectedObject.getId() && this.policyService.allow( 'composition', - containerType, + containerObject, selectedObject ); }; diff --git a/platform/containment/src/CompositionModelPolicy.js b/platform/containment/src/CompositionModelPolicy.js index be51e0c040..71d938fa46 100644 --- a/platform/containment/src/CompositionModelPolicy.js +++ b/platform/containment/src/CompositionModelPolicy.js @@ -14,8 +14,9 @@ define( } CompositionModelPolicy.prototype.allow = function (candidate) { + var candidateType = candidate.getCapability('type'); return Array.isArray( - (candidate.getInitialModel() || {}).composition + (candidateType.getInitialModel() || {}).composition ); }; diff --git a/platform/containment/src/CompositionMutabilityPolicy.js b/platform/containment/src/CompositionMutabilityPolicy.js index 71e49d1962..bf554dd3a3 100644 --- a/platform/containment/src/CompositionMutabilityPolicy.js +++ b/platform/containment/src/CompositionMutabilityPolicy.js @@ -37,7 +37,7 @@ define( // Equate creatability with mutability; that is, users // can only modify objects of types they can create, and // vice versa. - return candidate.hasFeature('creation'); + return candidate.getCapability('type').hasFeature('creation'); }; return CompositionMutabilityPolicy; diff --git a/platform/containment/src/CompositionPolicy.js b/platform/containment/src/CompositionPolicy.js index 60d0008fb0..8ece24c5a4 100644 --- a/platform/containment/src/CompositionPolicy.js +++ b/platform/containment/src/CompositionPolicy.js @@ -30,16 +30,16 @@ define( function () { /** - * Defines composition policy as driven by type metadata. + * Determines whether a given object can contain a candidate child object. * @constructor * @memberof platform/containment - * @implements {Policy.} + * @implements {Policy.} */ function CompositionPolicy() { } - CompositionPolicy.prototype.allow = function (parentType, child) { - var parentDef = parentType.getDefinition(); + CompositionPolicy.prototype.allow = function (parent, child) { + var parentDef = parent.getCapability('type').getDefinition(); // A parent without containment rules can contain anything. if (!parentDef.contains) { diff --git a/platform/entanglement/src/services/CopyService.js b/platform/entanglement/src/services/CopyService.js index 2ac29268cd..510e64fb7b 100644 --- a/platform/entanglement/src/services/CopyService.js +++ b/platform/entanglement/src/services/CopyService.js @@ -47,7 +47,7 @@ define( } return this.policyService.allow( "composition", - parentCandidate.getCapability('type'), + parentCandidate, object ); }; diff --git a/platform/entanglement/src/services/LinkService.js b/platform/entanglement/src/services/LinkService.js index 4942f93d35..cd31a9755f 100644 --- a/platform/entanglement/src/services/LinkService.js +++ b/platform/entanglement/src/services/LinkService.js @@ -51,7 +51,7 @@ define( } return this.policyService.allow( "composition", - parentCandidate.getCapability('type'), + parentCandidate, object ); }; diff --git a/platform/entanglement/src/services/MoveService.js b/platform/entanglement/src/services/MoveService.js index 82c3a70371..ac8202eba9 100644 --- a/platform/entanglement/src/services/MoveService.js +++ b/platform/entanglement/src/services/MoveService.js @@ -55,7 +55,7 @@ define( } return this.policyService.allow( "composition", - parentCandidate.getCapability('type'), + parentCandidate, object ); }; diff --git a/platform/features/layout/src/LayoutCompositionPolicy.js b/platform/features/layout/src/LayoutCompositionPolicy.js index a281d2d2ea..7ee7e6e40c 100644 --- a/platform/features/layout/src/LayoutCompositionPolicy.js +++ b/platform/features/layout/src/LayoutCompositionPolicy.js @@ -34,7 +34,8 @@ define( function LayoutCompositionPolicy() { } - LayoutCompositionPolicy.prototype.allow = function (parentType, child) { + LayoutCompositionPolicy.prototype.allow = function (parent, child) { + var parentType = parent.getCapability('type'); if (parentType.instanceOf('layout') && child.getCapability('type').instanceOf('folder')) { diff --git a/src/adapter/policies/AdapterCompositionPolicy.js b/src/adapter/policies/AdapterCompositionPolicy.js index b9d196e6f0..7d0d47e326 100644 --- a/src/adapter/policies/AdapterCompositionPolicy.js +++ b/src/adapter/policies/AdapterCompositionPolicy.js @@ -26,13 +26,11 @@ define([], function () { } AdapterCompositionPolicy.prototype.allow = function ( - parentType, + parent, child ) { - var container = parentType.getInitialModel(); - return this.openmct.composition.checkPolicy( - container, + parent, child ); }; From 529abcc4b00f89d88e5ce3f304da6ed2d0362997 Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 24 Mar 2017 17:00:12 -0700 Subject: [PATCH 10/38] Added composition policy to prevent composition of non-persistable parent, except in the case of a new object in which case the parent may change --- .../src/PersistableCompositionPolicy.js | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 platform/containment/src/PersistableCompositionPolicy.js diff --git a/platform/containment/src/PersistableCompositionPolicy.js b/platform/containment/src/PersistableCompositionPolicy.js new file mode 100644 index 0000000000..d30ade8add --- /dev/null +++ b/platform/containment/src/PersistableCompositionPolicy.js @@ -0,0 +1,61 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ + +/** + * This bundle implements "containment" rules, which determine which objects + * can be contained within which other objects. + * @namespace platform/containment + */ +define( + ['../../../src/api/objects/object-utils'], + function (objectUtils) { + + function PersistableCompositionPolicy(openmct) { + this.openmct = openmct; + } + + /** + * Only allow changes to composition if the changes can be saved. This in + * effect prevents selection of objects from the locator that do not + * support persistence. + * + * @param parent + * @param child + * @returns {boolean} + */ + PersistableCompositionPolicy.prototype.allow = function (parent) { + // If object is in edit mode, allow composition because it is + // part of object creation, and the object may be saved to another + // namespace that does support persistence. The EditPersistableObjectsPolicy + // prevents editing of objects that cannot be persisted, so we can assume that this + // is a new object. + if (!(parent.hasCapability('editor') && parent.getCapability('editor').isEditContextRoot())) { + var identifier = objectUtils.parseKeyString(parent.getId()); + var provider = this.openmct.objects.getProvider(identifier); + return provider.save !== undefined; + } + return true; + }; + + return PersistableCompositionPolicy; + } +); From a59177447b82b504ea401f0d56e1127687be2f06 Mon Sep 17 00:00:00 2001 From: Henry Date: Sun, 26 Mar 2017 17:39:03 -0700 Subject: [PATCH 11/38] [Examples] Modified MSL data source to use a single cached connection. Fixes #1480 --- example/msl/bundle.js | 2 +- example/msl/src/RemsTelemetryServerAdapter.js | 20 +++++-------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/example/msl/bundle.js b/example/msl/bundle.js index e40200d13a..2f9381b4a3 100644 --- a/example/msl/bundle.js +++ b/example/msl/bundle.js @@ -92,7 +92,7 @@ define([ { "key":"rems.adapter", "implementation": RemsTelemetryServerAdapter, - "depends": ["$q", "$http", "$log", "REMS_WS_URL"] + "depends": ["$http", "$log", "REMS_WS_URL"] } ], "components": [ diff --git a/example/msl/src/RemsTelemetryServerAdapter.js b/example/msl/src/RemsTelemetryServerAdapter.js index a6b1858f4d..adfcd618ce 100644 --- a/example/msl/src/RemsTelemetryServerAdapter.js +++ b/example/msl/src/RemsTelemetryServerAdapter.js @@ -42,14 +42,12 @@ define( * @param REMS_WS_URL The location of the REMS telemetry data. * @constructor */ - function RemsTelemetryServerAdapter($q, $http, $log, REMS_WS_URL) { + function RemsTelemetryServerAdapter($http, $log, REMS_WS_URL) { this.localDataURI = module.uri.substring(0, module.uri.lastIndexOf('/') + 1) + LOCAL_DATA; - this.deferreds = {}; this.REMS_WS_URL = REMS_WS_URL; - this.$q = $q; this.$http = $http; this.$log = $log; - this.cache = undefined; + this.promise = undefined; } /** @@ -65,15 +63,10 @@ define( */ RemsTelemetryServerAdapter.prototype.requestHistory = function(request) { var self = this, - id = request.key, - deferred = this.$q.defer(); + id = request.key; function processResponse(response){ var data = []; - /* - * Currently all data is returned for entire history of the mission. Cache response to avoid unnecessary re-queries. - */ - self.cache = response; /* * History data is organised by Sol. Iterate over sols... */ @@ -110,17 +103,15 @@ define( } function packageAndResolve(results){ - deferred.resolve({id: id, values: results}); + return {id: id, values: results}; } - this.$q.when(this.cache || this.$http.get(this.REMS_WS_URL)) + return (this.promise = this.promise || this.$http.get(this.REMS_WS_URL)) .catch(fallbackToLocal) .then(processResponse) .then(filterResults) .then(packageAndResolve); - - return deferred.promise; }; /** @@ -132,7 +123,6 @@ define( * @returns {Promise | Array} that resolves with an Array of {@link RemsTelemetryValue} objects for the request data key. */ RemsTelemetryServerAdapter.prototype.history = function(request) { - var id = request.key; return this.requestHistory(request); }; From 4196da9f52c45aa896bddd5d91144d9daff01a57 Mon Sep 17 00:00:00 2001 From: Henry Date: Sun, 26 Mar 2017 17:52:14 -0700 Subject: [PATCH 12/38] [Example] Update images to be more rovery. Fixes #1484 --- example/imagery/src/ImageTelemetry.js | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/example/imagery/src/ImageTelemetry.js b/example/imagery/src/ImageTelemetry.js index b184f90c4e..fe3f029141 100644 --- a/example/imagery/src/ImageTelemetry.js +++ b/example/imagery/src/ImageTelemetry.js @@ -31,10 +31,25 @@ define( var firstObservedTime = Date.now(), images = [ - "http://www.nasa.gov/393811main_Palomar_ao_bouchez_10s_after_impact_4x3_946-710.png", - "http://www.nasa.gov/393821main_Palomar_ao_bouchez_15s_after_impact_4x3_946-710.png", - "http://www.nasa.gov/images/content/393801main_CfhtVeillet2_4x3_516-387.jpg", - "http://www.nasa.gov/images/content/392790main_1024_768_GeminiNorth_NightBeforeImpact_946-710.jpg" + "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", + "https://www.hq.nasa.gov/alsj/a16/AS16-117-18734.jpg", + "https://www.hq.nasa.gov/alsj/a16/AS16-117-18735.jpg", + "https://www.hq.nasa.gov/alsj/a16/AS16-117-18736.jpg", + "https://www.hq.nasa.gov/alsj/a16/AS16-117-18737.jpg", + "https://www.hq.nasa.gov/alsj/a16/AS16-117-18738.jpg", + "https://www.hq.nasa.gov/alsj/a16/AS16-117-18739.jpg", + "https://www.hq.nasa.gov/alsj/a16/AS16-117-18740.jpg", + "https://www.hq.nasa.gov/alsj/a16/AS16-117-18741.jpg", + "https://www.hq.nasa.gov/alsj/a16/AS16-117-18742.jpg", + "https://www.hq.nasa.gov/alsj/a16/AS16-117-18743.jpg", + "https://www.hq.nasa.gov/alsj/a16/AS16-117-18744.jpg", + "https://www.hq.nasa.gov/alsj/a16/AS16-117-18745.jpg", + "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, From 4e457f1cf00db55708ed0d0220eda77822191b7d Mon Sep 17 00:00:00 2001 From: Henry Date: Sun, 26 Mar 2017 17:02:00 -0700 Subject: [PATCH 13/38] Fixed failing tests, and added new tests --- docs/src/guide/index.md | 2 +- .../edit/test/creation/CreateWizardSpec.js | 3 +- .../policies/EditPersistableObjectsSpec.js | 104 ++++++++++++++++++ .../src/PersistableCompositionPolicy.js | 1 - .../test/ComposeActionPolicySpec.js | 2 +- .../test/CompositionModelPolicySpec.js | 12 +- .../test/CompositionMutabilityPolicySpec.js | 12 +- .../containment/test/CompositionPolicySpec.js | 30 +++-- .../test/PersistableCompositionPolicySpec.js | 85 ++++++++++++++ .../test/services/CopyServiceSpec.js | 2 +- .../test/services/LinkServiceSpec.js | 2 +- .../test/services/MoveServiceSpec.js | 2 +- .../test/LayoutCompositionPolicySpec.js | 12 +- 13 files changed, 245 insertions(+), 24 deletions(-) create mode 100644 platform/commonUI/edit/test/policies/EditPersistableObjectsSpec.js create mode 100644 platform/containment/test/PersistableCompositionPolicySpec.js diff --git a/docs/src/guide/index.md b/docs/src/guide/index.md index 369ad05144..5bf5c34b37 100644 --- a/docs/src/guide/index.md +++ b/docs/src/guide/index.md @@ -2261,7 +2261,7 @@ 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 a given domain object(first argument, `parent`) can contain a candidate child object (second argument, `child`). * `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. diff --git a/platform/commonUI/edit/test/creation/CreateWizardSpec.js b/platform/commonUI/edit/test/creation/CreateWizardSpec.js index 3973afc945..22ed996e8b 100644 --- a/platform/commonUI/edit/test/creation/CreateWizardSpec.js +++ b/platform/commonUI/edit/test/creation/CreateWizardSpec.js @@ -161,6 +161,7 @@ define( 'otherType', ['getKey'] ), + //Create a form structure with location structure = wizard.getFormStructure(true), sections = structure.sections, @@ -174,7 +175,7 @@ define( // can actually contain objects of this type expect(mockPolicyService.allow).toHaveBeenCalledWith( 'composition', - mockOtherType, + mockDomainObj, mockDomainObject ); }); diff --git a/platform/commonUI/edit/test/policies/EditPersistableObjectsSpec.js b/platform/commonUI/edit/test/policies/EditPersistableObjectsSpec.js new file mode 100644 index 0000000000..4615582176 --- /dev/null +++ b/platform/commonUI/edit/test/policies/EditPersistableObjectsSpec.js @@ -0,0 +1,104 @@ +/***************************************************************************** + * 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/policies/EditPersistableObjectsPolicy"], + function (EditPersistableObjectsPolicy) { + + describe("The Edit persistable objects policy", function () { + var mockDomainObject, + mockEditAction, + mockPropertiesAction, + mockOtherAction, + mockAPI, + mockObjectAPI, + testContext, + policy; + + beforeEach(function () { + mockDomainObject = jasmine.createSpyObj( + 'domainObject', + [ + 'getId' + ] + ); + + mockObjectAPI = jasmine.createSpyObj('objectAPI', [ + 'getProvider' + ]); + + mockAPI = { + objects: mockObjectAPI + }; + + mockEditAction = jasmine.createSpyObj('edit', ['getMetadata']); + mockPropertiesAction = jasmine.createSpyObj('properties', ['getMetadata']); + mockOtherAction = jasmine.createSpyObj('other', ['getMetadata']); + + mockEditAction.getMetadata.andReturn({ key: 'edit' }); + mockPropertiesAction.getMetadata.andReturn({ key: 'properties' }); + mockOtherAction.getMetadata.andReturn({key: 'other'}); + + mockDomainObject.getId.andReturn('test:testId'); + + testContext = { + domainObject: mockDomainObject, + category: 'view-control' + }; + + policy = new EditPersistableObjectsPolicy(mockAPI); + }); + + it("Applies to edit action", function () { + mockObjectAPI.getProvider.andReturn({}); + expect(mockObjectAPI.getProvider).not.toHaveBeenCalled(); + + policy.allow(mockEditAction, testContext); + expect(mockObjectAPI.getProvider).toHaveBeenCalled(); + }); + + it("Applies to properties action", function () { + mockObjectAPI.getProvider.andReturn({}); + expect(mockObjectAPI.getProvider).not.toHaveBeenCalled(); + + policy.allow(mockPropertiesAction, testContext); + expect(mockObjectAPI.getProvider).toHaveBeenCalled(); + }); + + it("does not apply to other actions", function () { + mockObjectAPI.getProvider.andReturn({}); + expect(mockObjectAPI.getProvider).not.toHaveBeenCalled(); + + policy.allow(mockOtherAction, testContext); + expect(mockObjectAPI.getProvider).not.toHaveBeenCalled(); + }); + + it("Tests object provider for editability", function () { + mockObjectAPI.getProvider.andReturn({}); + expect(policy.allow(mockEditAction, testContext)).toBe(false); + expect(mockObjectAPI.getProvider).toHaveBeenCalled(); + mockObjectAPI.getProvider.andReturn({save: function () {}}); + expect(policy.allow(mockEditAction, testContext)).toBe(true); + }); + }); + } +); diff --git a/platform/containment/src/PersistableCompositionPolicy.js b/platform/containment/src/PersistableCompositionPolicy.js index d30ade8add..0a1b3c9aa9 100644 --- a/platform/containment/src/PersistableCompositionPolicy.js +++ b/platform/containment/src/PersistableCompositionPolicy.js @@ -37,7 +37,6 @@ define( * Only allow changes to composition if the changes can be saved. This in * effect prevents selection of objects from the locator that do not * support persistence. - * * @param parent * @param child * @returns {boolean} diff --git a/platform/containment/test/ComposeActionPolicySpec.js b/platform/containment/test/ComposeActionPolicySpec.js index b1b0aaff80..f3bcf453c7 100644 --- a/platform/containment/test/ComposeActionPolicySpec.js +++ b/platform/containment/test/ComposeActionPolicySpec.js @@ -78,7 +78,7 @@ define( expect(mockPolicyService.allow).toHaveBeenCalledWith( 'composition', - mockTypes[0], + mockDomainObjects[0], mockDomainObjects[1] ); }); diff --git a/platform/containment/test/CompositionModelPolicySpec.js b/platform/containment/test/CompositionModelPolicySpec.js index 2b733434b7..3165312179 100644 --- a/platform/containment/test/CompositionModelPolicySpec.js +++ b/platform/containment/test/CompositionModelPolicySpec.js @@ -4,19 +4,25 @@ define( function (CompositionModelPolicy) { describe("The composition model policy", function () { - var mockType, + var mockObject, + mockType, policy; beforeEach(function () { mockType = jasmine.createSpyObj('type', ['getInitialModel']); + mockObject = { + getCapability: function () { + return mockType; + } + }; policy = new CompositionModelPolicy(); }); it("only allows composition for types which will have a composition property", function () { mockType.getInitialModel.andReturn({}); - expect(policy.allow(mockType)).toBeFalsy(); + expect(policy.allow(mockObject)).toBeFalsy(); mockType.getInitialModel.andReturn({ composition: [] }); - expect(policy.allow(mockType)).toBeTruthy(); + expect(policy.allow(mockObject)).toBeTruthy(); }); }); diff --git a/platform/containment/test/CompositionMutabilityPolicySpec.js b/platform/containment/test/CompositionMutabilityPolicySpec.js index 9f011aedd9..22a38fa2ec 100644 --- a/platform/containment/test/CompositionMutabilityPolicySpec.js +++ b/platform/containment/test/CompositionMutabilityPolicySpec.js @@ -25,18 +25,24 @@ define( function (CompositionMutabilityPolicy) { describe("The composition mutability policy", function () { - var mockType, + var mockObject, + mockType, policy; beforeEach(function () { mockType = jasmine.createSpyObj('type', ['hasFeature']); + mockObject = { + getCapability: function () { + return mockType; + } + }; policy = new CompositionMutabilityPolicy(); }); it("only allows composition for types which can be created/modified", function () { - expect(policy.allow(mockType)).toBeFalsy(); + expect(policy.allow(mockObject)).toBeFalsy(); mockType.hasFeature.andReturn(true); - expect(policy.allow(mockType)).toBeTruthy(); + expect(policy.allow(mockObject)).toBeTruthy(); expect(mockType.hasFeature).toHaveBeenCalledWith('creation'); }); }); diff --git a/platform/containment/test/CompositionPolicySpec.js b/platform/containment/test/CompositionPolicySpec.js index 23261ef5de..e322836469 100644 --- a/platform/containment/test/CompositionPolicySpec.js +++ b/platform/containment/test/CompositionPolicySpec.js @@ -24,13 +24,18 @@ define( ["../src/CompositionPolicy"], function (CompositionPolicy) { describe("Composition policy", function () { - var typeA, + var mockParentObject, + typeA, typeB, typeC, mockChildObject, policy; beforeEach(function () { + mockParentObject = jasmine.createSpyObj('domainObject', [ + 'getCapability' + ]); + typeA = jasmine.createSpyObj( 'type A-- the particular kind', ['getKey', 'getDefinition'] @@ -70,27 +75,31 @@ define( describe('enforces simple containment rules', function () { it('allows when type matches', function () { + mockParentObject.getCapability.andReturn(typeA); + mockChildObject.getCapability.andReturn(typeA); - expect(policy.allow(typeA, mockChildObject)) + expect(policy.allow(mockParentObject, mockChildObject)) .toBeTruthy(); - expect(policy.allow(typeB, mockChildObject)) + mockParentObject.getCapability.andReturn(typeB); + expect(policy.allow(mockParentObject, mockChildObject)) .toBeTruthy(); mockChildObject.getCapability.andReturn(typeB); - expect(policy.allow(typeB, mockChildObject)) + expect(policy.allow(mockParentObject, mockChildObject)) .toBeTruthy(); }); it('disallows when type doesn\'t match', function () { + mockParentObject.getCapability.andReturn(typeA); mockChildObject.getCapability.andReturn(typeB); - expect(policy.allow(typeA, mockChildObject)) + expect(policy.allow(mockParentObject, mockChildObject)) .toBeFalsy(); mockChildObject.getCapability.andReturn(typeC); - expect(policy.allow(typeA, mockChildObject)) + expect(policy.allow(mockParentObject, mockChildObject)) .toBeFalsy(); }); @@ -98,8 +107,10 @@ define( describe('enforces capability-based containment rules', function () { it('allows when object has capability', function () { + mockParentObject.getCapability.andReturn(typeC); + mockChildObject.hasCapability.andReturn(true); - expect(policy.allow(typeC, mockChildObject)) + expect(policy.allow(mockParentObject, mockChildObject)) .toBeTruthy(); expect(mockChildObject.hasCapability) .toHaveBeenCalledWith('telemetry'); @@ -107,7 +118,10 @@ define( it('skips when object doesn\'t have capability', function () { mockChildObject.hasCapability.andReturn(false); - expect(policy.allow(typeC, mockChildObject)) + + mockParentObject.getCapability.andReturn(typeC); + + expect(policy.allow(mockParentObject, mockChildObject)) .toBeFalsy(); expect(mockChildObject.hasCapability) .toHaveBeenCalledWith('telemetry'); diff --git a/platform/containment/test/PersistableCompositionPolicySpec.js b/platform/containment/test/PersistableCompositionPolicySpec.js new file mode 100644 index 0000000000..56c4ce6575 --- /dev/null +++ b/platform/containment/test/PersistableCompositionPolicySpec.js @@ -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/PersistableCompositionPolicy"], + function (PersistableCompositionPolicy) { + describe("Persistable Composition policy", function () { + var objectAPI; + var mockOpenMCT; + var persistableCompositionPolicy; + var mockParent; + var mockChild; + var mockEditorCapability; + + beforeEach(function () { + objectAPI = jasmine.createSpyObj('objectsAPI', [ + 'getProvider' + ]); + + mockOpenMCT = { + objects: objectAPI + }; + mockParent = jasmine.createSpyObj('domainObject', [ + 'hasCapability', + 'getCapability', + 'getId' + ]); + mockParent.hasCapability.andReturn(true); + mockParent.getId.andReturn('someNamespace:someId'); + mockChild = {}; + mockEditorCapability = jasmine.createSpyObj('domainObject', [ + 'isEditContextRoot' + ]); + mockParent.getCapability.andReturn(mockEditorCapability); + + objectAPI.getProvider.andReturn({ + save: function () {} + }); + persistableCompositionPolicy = new PersistableCompositionPolicy(mockOpenMCT); + }); + + //Parent + // - getCapability ('editor') + // - isEditContextRoot + // - openMct.objects.getProvider + + it("Does not allow composition for objects that are not persistable", function () { + mockEditorCapability.isEditContextRoot.andReturn(false); + expect(persistableCompositionPolicy.allow(mockParent, mockChild)).toBe(true); + objectAPI.getProvider.andReturn({}); + expect(persistableCompositionPolicy.allow(mockParent, mockChild)).toBe(false); + }); + + it("Always allows composition of objects in edit mode to support object creation", function () { + mockEditorCapability.isEditContextRoot.andReturn(true); + expect(persistableCompositionPolicy.allow(mockParent, mockChild)).toBe(true); + expect(objectAPI.getProvider).not.toHaveBeenCalled(); + + mockEditorCapability.isEditContextRoot.andReturn(false); + expect(persistableCompositionPolicy.allow(mockParent, mockChild)).toBe(true); + expect(objectAPI.getProvider).toHaveBeenCalled(); + }); + + }); + } +); diff --git a/platform/entanglement/test/services/CopyServiceSpec.js b/platform/entanglement/test/services/CopyServiceSpec.js index bcd25cf825..fde19e185f 100644 --- a/platform/entanglement/test/services/CopyServiceSpec.js +++ b/platform/entanglement/test/services/CopyServiceSpec.js @@ -103,7 +103,7 @@ define( validate(); expect(policyService.allow).toHaveBeenCalledWith( "composition", - parentCandidate.capabilities.type, + parentCandidate, object ); }); diff --git a/platform/entanglement/test/services/LinkServiceSpec.js b/platform/entanglement/test/services/LinkServiceSpec.js index 6dcd9480b8..6bd294c43b 100644 --- a/platform/entanglement/test/services/LinkServiceSpec.js +++ b/platform/entanglement/test/services/LinkServiceSpec.js @@ -113,7 +113,7 @@ define( validate(); expect(mockPolicyService.allow).toHaveBeenCalledWith( "composition", - parentCandidate.capabilities.type, + parentCandidate, object ); }); diff --git a/platform/entanglement/test/services/MoveServiceSpec.js b/platform/entanglement/test/services/MoveServiceSpec.js index 687559ee56..80fbdf1867 100644 --- a/platform/entanglement/test/services/MoveServiceSpec.js +++ b/platform/entanglement/test/services/MoveServiceSpec.js @@ -123,7 +123,7 @@ define( validate(); expect(policyService.allow).toHaveBeenCalledWith( "composition", - parentCandidate.capabilities.type, + parentCandidate, object ); }); diff --git a/platform/features/layout/test/LayoutCompositionPolicySpec.js b/platform/features/layout/test/LayoutCompositionPolicySpec.js index 7d7abb2bcd..321e1cced5 100644 --- a/platform/features/layout/test/LayoutCompositionPolicySpec.js +++ b/platform/features/layout/test/LayoutCompositionPolicySpec.js @@ -25,6 +25,7 @@ define( function (LayoutCompositionPolicy) { describe("Layout's composition policy", function () { var mockChild, + mockCandidateObj, mockCandidate, mockContext, candidateType, @@ -41,6 +42,11 @@ define( mockContext = jasmine.createSpyObj('contextType', ['instanceOf']); + mockCandidateObj = jasmine.createSpyObj('domainObj', [ + 'getCapability' + ]); + mockCandidateObj.getCapability.andReturn(mockCandidate); + mockChild.getCapability.andReturn(mockContext); mockCandidate.instanceOf.andCallFake(function (t) { @@ -56,19 +62,19 @@ define( it("disallows folders in layouts", function () { candidateType = 'layout'; contextType = 'folder'; - expect(policy.allow(mockCandidate, mockChild)).toBe(false); + expect(policy.allow(mockCandidateObj, mockChild)).toBe(false); }); it("does not disallow folders elsewhere", function () { candidateType = 'nonlayout'; contextType = 'folder'; - expect(policy.allow(mockCandidate, mockChild)).toBe(true); + expect(policy.allow(mockCandidateObj, mockChild)).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(mockCandidateObj, mockChild)).toBe(true); }); }); From 09419398e966f33e97b7bc27278a56cd7148112b Mon Sep 17 00:00:00 2001 From: Henry Date: Mon, 27 Mar 2017 14:53:41 -0700 Subject: [PATCH 14/38] [Telemetry] Added unit tests for addition of bounds and domains to telemetry requests --- platform/telemetry/src/TelemetryCapability.js | 10 ++++- .../telemetry/test/TelemetryCapabilitySpec.js | 39 +++++++++++++++++-- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/platform/telemetry/src/TelemetryCapability.js b/platform/telemetry/src/TelemetryCapability.js index 2ce6fe9cf8..f5c91968b4 100644 --- a/platform/telemetry/src/TelemetryCapability.js +++ b/platform/telemetry/src/TelemetryCapability.js @@ -140,7 +140,8 @@ define( typeRequest = (type && type.getDefinition().telemetry) || {}, modelTelemetry = domainObject.getModel().telemetry, fullRequest = Object.create(typeRequest), - bounds; + bounds, + timeSystem; // Add properties from the telemetry field of this // specific domain object. @@ -167,6 +168,13 @@ define( fullRequest.end = bounds.end; } + if (request.domain === undefined) { + timeSystem = this.openmct.conductor.timeSystem(); + if (timeSystem !== undefined) { + fullRequest.domain = timeSystem.metadata.key; + } + } + return fullRequest; }; diff --git a/platform/telemetry/test/TelemetryCapabilitySpec.js b/platform/telemetry/test/TelemetryCapabilitySpec.js index 1f5ff32927..9345967f7c 100644 --- a/platform/telemetry/test/TelemetryCapabilitySpec.js +++ b/platform/telemetry/test/TelemetryCapabilitySpec.js @@ -104,6 +104,13 @@ define( start: 0, end: 1 }; + }, + timeSystem: function () { + return { + metadata: { + key: 'mockTimeSystem' + } + }; } } }; @@ -141,7 +148,8 @@ define( id: "testId", // from domain object source: "testSource", // from model key: "testKey", // from model - start: 42 // from argument + start: 42, // from argument + domain: 'mockTimeSystem' }]); }); @@ -160,7 +168,8 @@ define( source: "testSource", key: "testKey", start: 0, - end: 1 + end: 1, + domain: 'mockTimeSystem' }); }); @@ -176,7 +185,8 @@ define( source: "testSource", // from model key: "testId", // from domain object start: 0, - end: 1 + end: 1, + domain: 'mockTimeSystem' }); }); @@ -257,7 +267,8 @@ define( source: "testSource", key: "testKey", start: 0, - end: 1 + end: 1, + domain: 'mockTimeSystem' }] ); @@ -274,8 +285,28 @@ define( expect(mockUnsubscribe).not.toHaveBeenCalled(); subscription(); // should be an unsubscribe function expect(mockUnsubscribe).toHaveBeenCalled(); + }); + it("applies time conductor bounds if request bounds not defined", function () { + var fullRequest = telemetry.buildRequest({}); + var mockBounds = mockAPI.conductor.bounds(); + expect(fullRequest.start).toBe(mockBounds.start); + expect(fullRequest.end).toBe(mockBounds.end); + + fullRequest = telemetry.buildRequest({start: 10, end: 20}); + + expect(fullRequest.start).toBe(10); + expect(fullRequest.end).toBe(20); + }); + + it("applies domain from time system if none defined", function () { + var fullRequest = telemetry.buildRequest({}); + var mockTimeSystem = mockAPI.conductor.timeSystem(); + expect(fullRequest.domain).toBe(mockTimeSystem.metadata.key); + + fullRequest = telemetry.buildRequest({domain: 'someOtherDomain'}); + expect(fullRequest.domain).toBe('someOtherDomain'); }); }); } From af622599a55c8d0e4f49d8f82124d3aa11932b58 Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 24 Feb 2017 14:15:55 -0800 Subject: [PATCH 15/38] [Docs] Updated API docs to reflect V1 public API Cleaned up docs. Addresses #1473 --- API.md | 558 ++++++++++++++++++++-------------- src/api/types/TypeRegistry.js | 2 +- 2 files changed, 325 insertions(+), 235 deletions(-) diff --git a/API.md b/API.md index 3c4ef726c5..b51d9038a6 100644 --- a/API.md +++ b/API.md @@ -1,76 +1,150 @@ -# Open MCT API +# Building Applications With Open MCT -The Open MCT framework public api can be utilized by building the application -(`gulp install`) and then copying the file from `dist/main.js` to your -directory of choice. +## Scope and purpose of this document -Open MCT supports AMD, CommonJS, and loading via a script tag; it's easy to use -in your project. The [`openmct`]{@link module:openmct} module is exported -via AMD and CommonJS, and is also exposed as `openmct` in the global scope -if loaded via a script tag. +This document is intended to serve as a reference for developing an application +based on Open MCT. It will provide details of the API functions necessary to extend the +Open MCT platform meet common use cases such as integrating with a telemetry source. -## Overview +The best place to start is with the [Open MCT Tutorials](https://github.com/nasa/openmct-tutorial). +These will walk you through the process of getting up and running with Open MCT, +as well as addressing some common developer use cases. -Open MCT's goal is to allow you to browse, create, edit, and visualize all of -the domain knowledge you need on a daily basis. +## Building From Source -To do this, the main building block provided by Open MCT is the _domain object_. -The temperature sensor on the starboard solar panel, -an overlay plot comparing the results of all temperature sensor, -the command dictionary for a spacecraft, -the individual commands in that dictionary, your "my documents" folder: +The latest version of Open MCT is available from [our GitHub repository](https://github.com/nasa/openmct). +If you have `git`, and `node` installed, you can build Open MCT with the commands +``` +git clone https://github.com/nasa/openmct.git +cd openmct +npm install +``` + +These commands will fetch the Open MCT source from our GitHub repository, and build +a minified version that can be included in your application. The output of the +build process is placed in a `dist` folder under the openmct source directory, +which can be copied out to another location as needed. The contents of this +folder will include a minified javascript file named `openmct.js` as well as +assets such as html, css, and images necessary for the UI. + +## Starting an Open MCT application + +To start a minimally functional Open MCT application, it is necessary to include +the Open MCT distributable, enable some basic plugins, and bootstrap the application. +The tutorials walk through the process of getting Open MCT up and running from scratch, +but provided below is a minimal HTML template that includes Open MCT, installs +some basic plugins, and bootstraps the application. It assumes that Open MCT is +installed under an `openmct` subdirectory, as described in [Building From Source](#building-from-source). + +This approach includes openmct using a simple script tag, resulting in a global +variable named `openmct`. This `openmct` object is used subsequently to make API +calls. + +Open MCT is packaged as a UMD (Universal Module Definition) module, so common +script loaders are also supported. + +```html + + + + Open MCT + + + + + + +``` + +The Open MCT library included above requires certain assets such as html templates, +images, and css. If you installed Open MCT from GitHub as described in the section +on [Building from Source](#building-from-source) then these assets will have been +downloaded along with the Open MCT javascript library. You can specify the +location of these assets by calling `openmct.setAssetPath()`. Typically this will +be the same location as the `openmct.js` library is included from. + +There are some plugins bundled with the application that provide UI, persistence, +and other default configuration which are necessary to be able to do anything with +the application initially. Any of these plugins can, in principle, be replaced with a custom +plugin. The included plugins are documented in the [Included Plugins](#included-plugins) +section. + +## Plugins + +### Defining and Installing a New Plugin + +```javascript +openmct.install(function install(openmctAPI) { + // Do things here + // ... +}); +``` + +New plugins are installed in Open MCT by calling `openmct.install`, and providing +a plugin installation function. This function will be invoked on application +startup with one parameter - the openmct API object. A common approach used in +the Open MCT codebase is to define a plugin as a function that returns this +installation function. This allows configuration to be specified when the plugin is included. + +eg. +```javascript +openmct.install(openmct.plugins.Elasticsearch("http://localhost:8002/openmct")); +``` +This approach can be seen in all of the [plugins provided with Open MCT](https://github.com/nasa/openmct/blob/master/src/plugins/plugins.js). + +## Domain Objects and Identifiers + +_Domain Objects_ are the basic entities that represent domain knowledge in Open MCT. +The temperature sensor on a solar panel, an overlay plot comparing +the results of all temperature sensors, the command dictionary for a spacecraft, +the individual commands in that dictionary, the "My Items" folder: All of these things are domain objects. -Domain objects have Types, so a specific instrument temperature sensor is a -"Telemetry Point," and turning on a drill for a certain duration of time is -an "Activity". Types allow you to form an ontology of knowledge and provide -an abstraction for grouping, visualizing, and interpreting data. +A _Domain Object_ is simply a javascript object with some standard attributes. +An example of a _Domain Object_ is the "My Items" object which is a folder in +which a user can persist any objects that they create. The My Items object +looks like this: -And then we have Views. Views allow you to visualize domain objects. Views can -apply to specific domain objects; they may also apply to certain types of -domain objects, or they may apply to everything. Views are simply a method -of visualizing domain objects. - -Regions allow you to specify what views are displayed for specific types of -domain objects in response to different user actions. For instance, you may -want to display a different view while editing, or you may want to update the -toolbar display when objects are selected. Regions allow you to map views to -specific user actions. - -Domain objects can be mutated and persisted, developers can create custom -actions and apply them to domain objects, and many more things can be done. -For more information, read on! - -## Running Open MCT - -Once the [`openmct`](@link module:openmct) module has been loaded, you can -simply invoke [`start`]{@link module:openmct.MCT#start} to run Open MCT: - - -``` -openmct.start(); +```javascript +{ + identifier: { + namespace: "" + key: "mine" + } + name:"My Items", + type:"folder", + location:"ROOT", + composition: [] +} ``` -Generally, however, you will want to configure Open MCT by adding plugins -before starting it. It is important to install plugins and configure Open MCT -_before_ calling [`start`]{@link module:openmct.MCT#start}; Open MCT is not -designed to be reconfigured once started. +### Object Attributes -## Configuring Open MCT +The main attributes to note are the `identifier`, and `type` attributes. +* `identifier`: A composite key that provides a universally unique identifier for +this object. The `namespace` and `key` are used to identify the object. The `key` +must be unique within the namespace. +* `type`: All objects in Open MCT have a type. Types allow you to form an +ontology of knowledge and provide an abstraction for grouping, visualizing, and +interpreting data. Details on how to define a new object type are provided below. -The [`openmct`]{@link module:openmct} module (more specifically, the -[`MCT`]{@link module:openmct.MCT} class, of which `openmct` is an instance) -exposes a variety of methods to allow the application to be configured, -extended, and customized before running. +Open MCT uses a number of builtin types. Typically you are going to want to +define your own if extending Open MCT. -Short examples follow; see the linked documentation for further details. +### Domain Object Types -### Adding Domain Object Types +Custom types may be registered via the `addType` function on the opencmt Type +registry. -Custom types may be registered via -[`openmct.types`]{@link module:openmct.MCT#types}: - -``` +eg. +```javascript openmct.types.addType('my-type', { label: "My Type", description: "This is a type that I added!", @@ -78,66 +152,98 @@ openmct.types.addType('my-type', { }); ``` -### Adding Views +The `addType` function accepts two arguments: +* A `string` key identifying the type. This key is used when specifying a type +for an object. +* An object type specification. An object type definition supports the following +attributes + * `label`: a `string` naming this object type + * `description`: a `string` specifying a longer-form description of this type + * `initialize`: a `function` which initializes the model for new domain objects + of this type. This can be used for setting default values on an object when + it is instantiated. + * `creatable`: A `boolean` indicating whether users should be allowed to create + this type (default: `false`). This will determine whether the type appears + in the `Create` menu. + * `cssClass`: A `string` specifying a CSS class to apply to each representation + of this object. This is used for specifying an icon to appear next to each + object of this type. -Custom views may be registered based on the region in the application -where they should appear: +The [Open MCT Tutorials](https://github.com/openmct/openmct-tutorial) provide a +step-by-step examples of writing code for Open MCT that includes a [section on +defining a new object type](https://github.com/nasa/openmct-tutorial#step-3---providing-objects). -* [`openmct.mainViews`]{@link module:openmct.MCT#mainViews} is a registry - of views of domain objects which should appear in the main viewing area. -* [`openmct.inspectors`]{@link module:openmct.MCT#inspectors} is a registry - of views of domain objects and/or active selections, which should appear in - the Inspector. -* [`openmct.toolbars`]{@link module:openmct.MCT#toolbars} is a registry - of views of domain objects and/or active selections, which should appear in - the toolbar area while editing. -* [`openmct.indicators`]{@link module:openmct.MCT#inspectors} is a registry - of views which should appear in the status area of the application. +## Root Objects -Example: +In many cases, you'd like a certain object (or a certain hierarchy of objects) +to be accessible from the top level of the application (the tree on the left-hand +side of Open MCT.) For example, it is typical to expose a telemetry dictionary +as a hierarchy of telemetry-providing domain objects in this fashion. -``` -openmct.mainViews.addProvider({ - canView: function (domainObject) { - return domainObject.type === 'my-type'; - }, - view: function (domainObject) { - return new MyView(domainObject); - } -}); +To do so, use the `addRoot` method of the object API. + +eg. +```javascript +openmct.objects.addRoot({ + namespace: "my-namespace", + key: "my-key" + }); ``` -### Adding a Root-level Object - -In many cases, you'd like a certain object (or a certain hierarchy of -objects) to be accessible from the top level of the application (the -tree on the left-hand side of Open MCT.) It is typical to expose a telemetry -dictionary as a hierarchy of telemetry-providing domain objects in this -fashion. - -To do so, use the [`addRoot`]{@link module:openmct.ObjectAPI#addRoot} method -of the [object API]{@link module:openmct.ObjectAPI}: - -``` -openmct.objects.addRoot({ key: "my-key", namespace: "my-namespace" }); -``` +The `addRoot` function takes a single [object identifier](#domain-objects-and-identifiers) +as an argument. Root objects are loaded just like any other objects, i.e. via an object provider. -### Adding Composition Providers +## Object Providers -The "composition" of a domain object is the list of objects it contains, -as shown (for example) in the tree for browsing. Open MCT provides a +An Object Provider is used to build _Domain Objects_, typically retrieved from +some source such as a persistence store or telemetry dictionary. In order to +integrate telemetry from a new source an object provider will need to be created +that can build objects representing telemetry points exposed by the telemetry +source. The API call to define a new object provider is fairly straightforward. +Here's a very simple example: + +```javascript +openmct.objects.addProvider('example.namespace', { + get: function (identifier) { + return Promise.resolve({ + identifier: identifier, + name: 'Example Object', + type: 'example-object-type' + }); + } +}); +``` +The `addProvider` function takes two arguments: + +* `namespace`: A `string` representing the namespace that this object provider +will provide objects for. +* `provider`: An `object` with a single function, `get`. This function accepts an +[Identifier](#domain-objects-and-identifiers) for the object to be provided. +It is expected that the `get` function will return a +[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) +that resolves with the object being requested. + +In future, object providers will support other methods to enable other operations +with persistence stores, such as creating, updating, and deleting objects. + +## Composition Providers + +The _composition_ of a domain object is the list of objects it contains, as shown +(for example) in the tree for browsing. Open MCT provides a [default solution](#default-composition-provider) for composition, but there may be cases where you want to provide the composition of a certain object (or type of object) dynamically. -For instance, you may want to populate a hierarchy under a custom root-level -object based on the contents of a telemetry dictionary. -To do this, you can add a new CompositionProvider: +### Adding Composition Providers -``` +You may want to populate a hierarchy under a custom root-level object based on +the contents of a telemetry dictionary. To do this, you can add a new +Composition Provider: + +```javascript openmct.composition.addProvider({ appliesTo: function (domainObject) { return domainObject.type === 'my-type'; @@ -147,20 +253,27 @@ openmct.composition.addProvider({ } }); ``` +The `addProvider` function accepts a Composition Provider object as its sole +argument. A Composition Provider is a javascript object exposing two functions: +* `appliesTo`: A `function` that accepts a `domainObject` argument, and returns +a `boolean` value indicating whether this composition provider applies to the +given object. +* `load`: A `function` that accepts a `domainObject` as an argument, and returns +a `Promise` that resolves with an array of [Identifier](#domain-objects-and-identifiers). +These identifiers will be used to fetch Domain Objects from an [Object Provider](#object-provider) -#### Default Composition Provider +### Default Composition Provider -The default composition provider applies to any domain object with -a `composition` property. The value of `composition` should be an -array of identifiers, e.g.: +The default composition provider applies to any domain object with a `composition` +property. The value of `composition` should be an array of identifiers, e.g.: -```js +```javascript var domainObject = { name: "My Object", type: 'folder', composition: [ { - key: '412229c3-922c-444b-8624-736d85516247', + id: '412229c3-922c-444b-8624-736d85516247', namespace: 'foo' }, { @@ -171,169 +284,146 @@ var domainObject = { }; ``` -### Adding Telemetry Providers +## Telemetry Providers -When connecting to a new telemetry source, you will want to register a new -[telemetry provider]{@link module:openmct.TelemetryAPI~TelemetryProvider} -with the [telemetry API]{@link module:openmct.TelemetryAPI#addProvider}: +When connecting to a new telemetry source, you will need to register a new +_Telemetry Provider_. A _Telemetry Provider_ retrieves telemetry data from some telemetry +source, and exposes them in a way that can be used by Open MCT. A telemetry +provider typically can support a one off __request__ for a batch of telemetry data, +or it can provide the ability to __subscribe__ to receive new telemetry data when +it becomes available, or both. -``` +```javascript openmct.telemetry.addProvider({ - canProvideTelemetry: function (domainObject) { - return domainObject.type === 'my-type'; + supportsRequest: function (domainObject) { + //... }, - properties: function (domainObject) { - return [ - { key: 'value', name: "Temperature", units: "degC" }, - { key: 'time', name: "UTC" } - ]; + supportsSubscribe: function (domainObject) { + //... }, - request: function (domainObject, options) { - var telemetryId = domainObject.myTelemetryId; - return myAdapter.request(telemetryId, options.start, options.end); + request: function (domainObject, options) { + //... }, - subscribe: function (domainObject, callback) { - var telemetryId = domainObject.myTelemetryId; - myAdapter.subscribe(telemetryId, callback); - return myAdapter.unsubscribe.bind(myAdapter, telemetryId, callback); + subscribe: function (domainObject, callback, options) { + //... } -}); +}) ``` +A telemetry provider is an object with the following functions defined: + +* `supportsRequest`: An __optional__ `function` that accepts a +[Domain Object](#domain-objects-and-identifiers) and returns a `boolean` value +indicating whether or not this provider supports telemetry requests for the +given object. If this returns `true` then a `request` function must be defined. +* `supportsSubscribe`: An __optional__ `function` that accepts a +[Domain Object](#domain-objects-and-identifiers) and returns a `boolean` value +indicating whether or not this provider supports telemetry subscriptions. If this +returns `true` then a `subscribe` function must also be defined. As with `request`, +the return value will typically be conditional, and based on attributes of +`domainObject` such as its identifier. +* `request`: A `function` that returns a `Promise` that will resolve with an `Array` +of telemetry in a single query. This function accepts as arguments a +[Domain Object](#domain-objects-and-identifiers) and an object containing some +[request options](#telemetry-requests). +* `subscribe`: A `function` that accepts a [Domain Object](#domain-objects-and-identifiers), +a callback `function`, and a [telemetry request](#telemetry-requests). The +callback is invoked whenever telemetry is available, and + + The implementations for `request` and `subscribe` can vary depending on the nature of the endpoint which will provide telemetry. In the example above, -it is assumed that `myAdapter` contains the specific implementations -(HTTP requests, WebSocket connections, etc.) associated with some telemetry +it is assumed that `myAdapter` contains the implementation details +(such as HTTP requests, WebSocket connections, etc.) associated with some telemetry source. -## Using Open MCT +For a step-by-step guide to building a telemetry adapter, please see the +[Open MCT Tutorials](https://github.com/larkin/openmct-tutorial). -When implementing new features, it is useful and sometimes necessary to -utilize functionality exposed by Open MCT. - -### Retrieving Composition - -To limit which objects are loaded at any given time, the composition of -a domain object must be requested asynchronously: - -``` -openmct.composition(myObject).load().then(function (childObjects) { - childObjects.forEach(doSomething); -}); +### Telemetry Requests +Telemetry requests support time bounded queries. A call to a _Telemetry Provider_'s +`request` function will include an `options` argument. These are simply javascript +objects with attributes for the request parameters. An example of a telemetry +request object with a start and end time is included below: +```javascript +{ + start: 1487981997240, + end: 1487982897240 +} ``` -### Support Common Gestures +### Telemetry Data -Custom views may also want to support common gestures using the -[gesture API]{@link module:openmct.GestureAPI}. For instance, to make -a view (or part of a view) selectable: +Telemetry data is provided to Open MCT by _[Telemetry Providers](#telemetry-providers)_ +in the form of javascript objects. A collection of telemetry values (for example, +retrieved in response to a `request`) is represented by an `Array` of javascript +objects. These telemetry javascript objects are simply key value pairs. -``` -openmct.gestures.selectable(myHtmlElement, myDomainObject); +Typically a telemetry datum will have some timestamp associated with it. This +time stamp should have a key that corresponds to some time system supported by +Open MCT. If the `UTCTimeSystem` plugin is installed, then the key `utc` can be used. + +An example of a telemetry provider request function that returns a collection of +mock telemtry data is below: + +```javascript +openmct.telemetry.addProvider({ + supportsRequest: function (domainObject) { + return true + }, + request: function (domainObject, options) { + return Promise.resolve([ + { + 'utc': Date.now() - 2000, + 'value': 1, + }, + { + 'utc': Date.now() - 1000, + 'value': 2, + }, + { + 'utc': Date.now(), + 'value': 3, + } + ]); + } +}) ``` -### Working with Domain Objects - -The [object API]{@link module:openmct.ObjectAPI} provides useful methods -for working with domain objects. - -To make changes to a domain object, use the -[`mutate`]{@link module:openmct.ObjectAPI#mutate} method: - -``` -openmct.objects.mutate(myDomainObject, "name", "New name!"); -``` - -Making modifications in this fashion allows other usages of the domain -object to remain up to date using the -[`observe`]{@link module:openmct.ObjectAPI#observe} method: - -``` -openmct.objects.observe(myDomainObject, "name", function (newName) { - myLabel.textContent = newName; -}); -``` - -### Using Telemetry - -Very often in Open MCT, you wish to work with telemetry data (for instance, -to display it in a custom visualization.) - - -### Synchronizing with the Time Conductor - -Views which wish to remain synchronized with the state of Open MCT's -time conductor should utilize -[`openmct.conductor`]{@link module:openmct.TimeConductor}: - -``` -openmct.conductor.on('bounds', function (newBounds) { - requestTelemetry(newBounds.start, newBounds.end).then(displayTelemetry); -}); -``` - -## Plugins - -While you can register new features with Open MCT directly, it is generally -more useful to package these as a plugin. A plugin is a function that takes -[`openmct`]{@link module:openmct} as an argument, and performs configuration -upon `openmct` when invoked. - -### Installing Plugins - -To install plugins, use the [`install`]{@link module:openmct.MCT#install} -method: - -``` -openmct.install(myPlugin); -``` - -The plugin will be invoked to configure Open MCT before it is started. - -### Included Plugins +## Included Plugins Open MCT is packaged along with a few general-purpose plugins: * `openmct.plugins.CouchDB` is an adapter for using CouchDB for persistence of user-created objects. This is a constructor that takes the URL for the CouchDB database as a parameter, e.g. - `openmct.install(new openmct.plugins.CouchDB('http://localhost:5984/openmct'))` +```javascript +openmct.install(openmct.plugins.CouchDB('http://localhost:5984/openmct')) +``` * `openmct.plugins.Elasticsearch` is an adapter for using Elasticsearch for persistence of user-created objects. This is a constructor that takes the URL for the Elasticsearch instance as a - parameter, e.g. - `openmct.install(new openmct.plugins.CouchDB('http://localhost:9200'))`. - Domain objects will be indexed at `/mct/domain_object`. -* `openmct.plugins.espresso` and `openmct.plugins.snow` are two different + parameter. eg. +```javascript +openmct.install(openmct.plugins.CouchDB('http://localhost:9200')) +``` +* `openmct.plugins.Espresso` and `openmct.plugins.Snow` are two different themes (dark and light) available for Open MCT. Note that at least one of these themes must be installed for Open MCT to appear correctly. -* `openmct.plugins.localStorage` provides persistence of user-created +* `openmct.plugins.LocalStorage` provides persistence of user-created objects in browser-local storage. This is particularly useful in development environments. -* `openmct.plugins.myItems` adds a top-level folder named "My Items" +* `openmct.plugins.MyItems` adds a top-level folder named "My Items" when the application is first started, providing a place for a user to store created items. -* `openmct.plugins.utcTimeSystem` provides support for using the time - conductor with UTC time. +* `openmct.plugins.UTCTimeSystem` provides a default time system for Open MCT. Generally, you will want to either install these plugins, or install different plugins that provide persistence and an initial folder -hierarchy. Installation is as described [above](#installing-plugins): +hierarchy. +eg. +```javascript +openmct.install(openmct.plugins.LocalStorage()); +openmct.install(openmct.plugins.MyItems()); ``` -openmct.install(openmct.plugins.localStorage); -openmct.install(openmct.plugins.myItems); -``` - -### Writing Plugins - -Plugins configure Open MCT, and should utilize the -[`openmct`]{@link module:openmct} module to do so, as summarized above in -"Configuring Open MCT" and "Using Open MCT" above. - -### Distributing Plugins - -Hosting or downloading plugins is outside of the scope of this documentation. -We recommend distributing plugins as UMD modules which export a single -function. - diff --git a/src/api/types/TypeRegistry.js b/src/api/types/TypeRegistry.js index 77c7e454c4..ee5a286f00 100644 --- a/src/api/types/TypeRegistry.js +++ b/src/api/types/TypeRegistry.js @@ -44,7 +44,7 @@ define(['./Type'], function (Type) { } /** - * Register a new type of view. + * Register a new object type. * * @param {string} typeKey a string identifier for this type * @param {module:openmct.Type} type the type to add From 4ae35576a5f8c6167ebd5a49da1c656adb6bc62f Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 29 Mar 2017 13:15:46 -0700 Subject: [PATCH 16/38] [Features] Added Autoflow Tabular to open source features. Fixes #1469 --- platform/features/autoflow/plugin.js | 51 +++ .../res/templates/autoflow-tabular.html | 26 ++ .../autoflow/src/AutoflowTableLinker.js | 169 +++++++++ .../autoflow/src/AutoflowTabularController.js | 324 +++++++++++++++++ .../features/autoflow/src/MCTAutoflowTable.js | 60 +++ .../autoflow/test/AutoflowTableLinkerSpec.js | 178 +++++++++ .../test/AutoflowTabularControllerSpec.js | 341 ++++++++++++++++++ .../autoflow/test/MCTAutoflowTableSpec.js | 39 ++ src/plugins/plugins.js | 10 +- 9 files changed, 1196 insertions(+), 2 deletions(-) create mode 100755 platform/features/autoflow/plugin.js create mode 100755 platform/features/autoflow/res/templates/autoflow-tabular.html create mode 100755 platform/features/autoflow/src/AutoflowTableLinker.js create mode 100755 platform/features/autoflow/src/AutoflowTabularController.js create mode 100755 platform/features/autoflow/src/MCTAutoflowTable.js create mode 100755 platform/features/autoflow/test/AutoflowTableLinkerSpec.js create mode 100755 platform/features/autoflow/test/AutoflowTabularControllerSpec.js create mode 100755 platform/features/autoflow/test/MCTAutoflowTableSpec.js diff --git a/platform/features/autoflow/plugin.js b/platform/features/autoflow/plugin.js new file mode 100755 index 0000000000..86affe181a --- /dev/null +++ b/platform/features/autoflow/plugin.js @@ -0,0 +1,51 @@ +define([ + 'text!./res/templates/autoflow-tabular.html', + './src/AutoflowTabularController', + './src/MCTAutoflowTable' +], function ( + autoflowTabularTemplate, + AutoflowTabularController, + MCTAutoflowTable +) { + return function (openmct) { + openmct.legacyRegistry.register("platform/features/autoflow", { + "name": "WARP Telemetry Adapter", + "description": "Retrieves telemetry from the WARP Server and provides related types and views.", + "resources": "res", + "extensions": { + "views": [ + { + "key": "autoflow", + "name": "Autoflow Tabular", + "cssClass": "icon-packet", + "description": "A tabular view of packet contents.", + "template": autoflowTabularTemplate, + "needs": [ + "telemetry" + ], + "delegation": true + } + ], + "controllers": [ + { + "key": "AutoflowTabularController", + "implementation": AutoflowTabularController, + "depends": [ + "$scope", + "$timeout", + "telemetrySubscriber" + ] + } + ], + "directives": [ + { + "key": "mctAutoflowTable", + "implementation": MCTAutoflowTable + } + ] + } + }); + openmct.legacyRegistry.enable("platform/features/autoflow"); + }; +}); + diff --git a/platform/features/autoflow/res/templates/autoflow-tabular.html b/platform/features/autoflow/res/templates/autoflow-tabular.html new file mode 100755 index 0000000000..59e181fc48 --- /dev/null +++ b/platform/features/autoflow/res/templates/autoflow-tabular.html @@ -0,0 +1,26 @@ +
+
+ + +
{{autoflow.updated()}}
+ +
+
+ + +
+
diff --git a/platform/features/autoflow/src/AutoflowTableLinker.js b/platform/features/autoflow/src/AutoflowTableLinker.js new file mode 100755 index 0000000000..0c9e5da5fd --- /dev/null +++ b/platform/features/autoflow/src/AutoflowTableLinker.js @@ -0,0 +1,169 @@ +/*global angular*/ +define( + [], + function () { + + /** + * The link step for the `mct-autoflow-table` directive; + * watches scope and updates the DOM appropriately. + * See documentation in `MCTAutoflowTable.js` for the rationale + * for including this directive, as well as for an explanation + * of which values are placed in scope. + * + * @constructor + * @param {Scope} scope the scope for this usage of the directive + * @param element the jqLite-wrapped element which used this directive + */ + function AutoflowTableLinker(scope, element) { + var objects, // Domain objects at last structure refresh + rows, // Number of rows from last structure refresh + priorClasses = {}, + valueSpans = {}; // Span elements to put data values in + + // Create a new name-value pair in the specified column + function createListItem(domainObject, ul) { + // Create a new li, and spans to go in it. + var li = angular.element('
  • '), + titleSpan = angular.element(''), + valueSpan = angular.element(''); + + // Place spans in the li, and li into the column. + // valueSpan must precede titleSpan in the DOM due to new CSS float approach + li.append(valueSpan).append(titleSpan); + ul.append(li); + + // Style appropriately + li.addClass('l-autoflow-row'); + titleSpan.addClass('l-autoflow-item l'); + valueSpan.addClass('l-autoflow-item r l-obj-val-format'); + + // Set text/tooltip for the name-value row + titleSpan.text(domainObject.getModel().name); + titleSpan.attr("title", domainObject.getModel().name); + + // Keep a reference to the span which will hold the + // data value, to populate in the next refreshValues call + valueSpans[domainObject.getId()] = valueSpan; + + return li; + } + + // Create a new column of name-value pairs in this table. + function createColumn(el) { + // Create a ul + var ul = angular.element('
      '); + + // Add it into the mct-autoflow-table + el.append(ul); + + // Style appropriately + ul.addClass('l-autoflow-col'); + + // Get the current col width and apply at time of column creation + // Important to do this here, as new columns could be created after + // the user has changed the width. + ul.css('width', scope.columnWidth + 'px'); + + // Return it, so some li elements can be added + return ul; + } + + // Change the width of the columns when user clicks the resize button. + function resizeColumn() { + element.find('ul').css('width', scope.columnWidth + 'px'); + } + + // Rebuild the DOM associated with this table. + function rebuild(domainObjects, rowCount) { + var activeColumn; + + // Empty out our cached span elements + valueSpans = {}; + + // Start with an empty DOM beneath this directive + element.html(""); + + // Add DOM elements for each domain object being displayed + // in this table. + domainObjects.forEach(function (object, index) { + // Start a new column if we'd run out of room + if (index % rowCount === 0) { + activeColumn = createColumn(element); + } + // Add the DOM elements for that object to whichever + // column (a `ul` element) is current. + createListItem(object, activeColumn); + }); + } + + // Update spans with values, as made available via the + // `values` attribute of this directive. + function refreshValues() { + // Get the available values + var values = scope.values || {}, + classes = scope.classes || {}; + + // Populate all spans with those values (or clear + // those spans if no value is available) + (objects || []).forEach(function (object) { + var id = object.getId(), + span = valueSpans[id], + value; + + if (span) { + // Look up the value... + value = values[id]; + // ...and convert to empty string if it's undefined + value = value === undefined ? "" : value; + span.attr("data-value", value); + + // Update the span + span.text(value); + span.attr("title", value); + span.removeClass(priorClasses[id]); + span.addClass(classes[id]); + priorClasses[id] = classes[id]; + } + // Also need stale/alert/ok class + // on span + }); + } + + // Refresh the DOM for this table, if necessary + function refreshStructure() { + // Only rebuild if number of rows or set of objects + // has changed; otherwise, our structure is still valid. + if (scope.objects !== objects || + scope.rows !== rows) { + + // Track those values to support future refresh checks + objects = scope.objects; + rows = scope.rows; + + // Rebuild the DOM + rebuild(objects || [], rows || 1); + + // Refresh all data values shown + refreshValues(); + } + } + + // Changing the domain objects in use or the number + // of rows should trigger a structure change (DOM rebuild) + scope.$watch("objects", refreshStructure); + scope.$watch("rows", refreshStructure); + + // When the current column width has been changed, resize the column + scope.$watch('columnWidth', resizeColumn); + + // When the last-updated time ticks, + scope.$watch("updated", refreshValues); + + // Update displayed values when the counter changes. + scope.$watch("counter", refreshValues); + + } + + return AutoflowTableLinker; + } +); diff --git a/platform/features/autoflow/src/AutoflowTabularController.js b/platform/features/autoflow/src/AutoflowTabularController.js new file mode 100755 index 0000000000..3d6901f5a7 --- /dev/null +++ b/platform/features/autoflow/src/AutoflowTabularController.js @@ -0,0 +1,324 @@ + +define( + ['moment'], + function (moment) { + + var ROW_HEIGHT = 16, + SLIDER_HEIGHT = 10, + INITIAL_COLUMN_WIDTH = 225, + MAX_COLUMN_WIDTH = 525, + COLUMN_WIDTH_STEP = 25, + DEBOUNCE_INTERVAL = 100, + DATE_FORMAT = "YYYY-DDD HH:mm:ss.SSS\\Z", + NOT_UPDATED = "No updates", + EMPTY_ARRAY = []; + + /** + * Responsible for supporting the autoflow tabular view. + * Implements the all-over logic which drives that view, + * mediating between template-provided areas, the included + * `mct-autoflow-table` directive, and the underlying + * domain object model. + * @constructor + */ + function AutflowTabularController( + $scope, + $timeout, + telemetrySubscriber + ) { + var filterValue = "", + filterValueLowercase = "", + subscription, + filteredObjects = [], + lastUpdated = {}, + updateText = NOT_UPDATED, + rangeValues = {}, + classes = {}, + limits = {}, + updatePending = false, + lastBounce = Number.NEGATIVE_INFINITY, + columnWidth = INITIAL_COLUMN_WIDTH, + rows = 1, + counter = 0; + + // Trigger an update of the displayed table by incrementing + // the counter that it watches. + function triggerDisplayUpdate() { + counter += 1; + } + + // Check whether or not an object's name matches the + // user-entered filter value. + function filterObject(domainObject) { + return (domainObject.getModel().name || "") + .toLowerCase() + .indexOf(filterValueLowercase) !== -1; + } + + // Comparator for sorting points back into packet order + function compareObject(objectA, objectB) { + var indexA = objectA.getModel().index || 0, + indexB = objectB.getModel().index || 0; + return indexA - indexB; + } + + // Update the list of currently-displayed objects; these + // will be the subset of currently subscribed-to objects + // which match a user-entered filter. + function doUpdateFilteredObjects() { + // Generate the list + filteredObjects = ( + subscription ? + subscription.getTelemetryObjects() : + [] + ).filter(filterObject).sort(compareObject); + + // Clear the pending flag + updatePending = false; + + // Track when this occurred, so that we can wait + // a whole before updating again. + lastBounce = Date.now(); + + triggerDisplayUpdate(); + } + + // Request an update to the list of current objects; this may + // run on a timeout to avoid excessive calls, e.g. while the user + // is typing a filter. + function updateFilteredObjects() { + // Don't do anything if an update is already scheduled + if (!updatePending) { + if (Date.now() > lastBounce + DEBOUNCE_INTERVAL) { + // Update immediately if it's been long enough + doUpdateFilteredObjects(); + } else { + // Otherwise, update later, and track that we have + // an update pending so that subsequent calls can + // be ignored. + updatePending = true; + $timeout(doUpdateFilteredObjects, DEBOUNCE_INTERVAL); + } + } + } + + // Track the latest data values for this domain object + function recordData(telemetryObject) { + // Get latest domain/range values for this object. + var id = telemetryObject.getId(), + domainValue = subscription.getDomainValue(telemetryObject), + rangeValue = subscription.getRangeValue(telemetryObject); + + // Track the most recent timestamp change observed... + if (domainValue !== undefined && domainValue !== lastUpdated[id]) { + lastUpdated[id] = domainValue; + // ... and update the displayable text for that timestamp + updateText = isNaN(domainValue) ? "" : + moment.utc(domainValue).format(DATE_FORMAT); + } + + // Store data values into the rangeValues structure, which + // will be used to populate the table itself. + // Note that we want full precision here. + rangeValues[id] = rangeValue; + + // Update limit states as well + classes[id] = limits[id] && (limits[id].evaluate({ + // This relies on external knowledge that the + // range value of a telemetry point is encoded + // in its datum as "value." + value: rangeValue + }) || {}).cssClass; + } + + + // Look at telemetry objects from the subscription; this is watched + // to detect changes from the subscription. + function subscribedTelemetry() { + return subscription ? + subscription.getTelemetryObjects() : EMPTY_ARRAY; + } + + // Update the data values which will be used to populate the table + function updateValues() { + subscribedTelemetry().forEach(recordData); + triggerDisplayUpdate(); + } + + // Getter-setter function for user-entered filter text. + function filter(value) { + // If value was specified, we're a setter + if (value !== undefined) { + // Store the new value + filterValue = value; + filterValueLowercase = value.toLowerCase(); + // Change which objects appear in the table + updateFilteredObjects(); + } + + // Always act as a getter + return filterValue; + } + + // Update the bounds (width and height) of this view; + // called from the mct-resize directive. Recalculates how + // many rows should appear in the contained table. + function setBounds(bounds) { + var availableSpace = bounds.height - SLIDER_HEIGHT; + rows = Math.max(1, Math.floor(availableSpace / ROW_HEIGHT)); + } + + // Increment the current column width, up to the defined maximum. + // When the max is hit, roll back to the default. + function increaseColumnWidth() { + columnWidth += COLUMN_WIDTH_STEP; + // Cycle down to the initial width instead of exceeding max + columnWidth = columnWidth > MAX_COLUMN_WIDTH ? + INITIAL_COLUMN_WIDTH : columnWidth; + } + + // Get displayable text for last-updated value + function updated() { + return updateText; + } + + // Unsubscribe, if a subscription is active. + function releaseSubscription() { + if (subscription) { + subscription.unsubscribe(); + subscription = undefined; + } + } + + // Update set of telemetry objects managed by this view + function updateTelemetryObjects(telemetryObjects) { + updateFilteredObjects(); + limits = {}; + telemetryObjects.forEach(function (telemetryObject) { + var id = telemetryObject.getId(); + limits[id] = telemetryObject.getCapability('limit'); + }); + } + + // Create a subscription for the represented domain object. + // This will resolve capability delegation as necessary. + function makeSubscription(domainObject) { + // Unsubscribe, if there is an existing subscription + releaseSubscription(); + + // Clear updated timestamp + lastUpdated = {}; + updateText = NOT_UPDATED; + + // Create a new subscription; telemetrySubscriber gets + // to do the meaningful work here. + subscription = domainObject && telemetrySubscriber.subscribe( + domainObject, + updateValues + ); + + // Our set of in-view telemetry objects may have changed, + // so update the set that is being passed down to the table. + updateFilteredObjects(); + } + + // Watch for changes to the set of objects which have telemetry + $scope.$watch(subscribedTelemetry, updateTelemetryObjects); + + // Watch for the represented domainObject (this field will + // be populated by mct-representation) + $scope.$watch("domainObject", makeSubscription); + + // Make sure we unsubscribe when this view is destroyed. + $scope.$on("$destroy", releaseSubscription); + + return { + /** + * Get the number of rows which should be shown in this table. + * @return {number} the number of rows to show + */ + getRows: function () { + return rows; + }, + /** + * Get the objects which should currently be displayed in + * this table. This will be watched, so the return value + * should be stable when this list is unchanging. Only + * objects which match the user-entered filter value should + * be returned here. + * @return {DomainObject[]} the domain objects to include in + * this table. + */ + getTelemetryObjects: function () { + return filteredObjects; + }, + /** + * Set the bounds (width/height) of this autoflow tabular view. + * The template must ensure that these bounds are tracked on + * the table area only. + * @param bounds the bounds; and object with `width` and + * `height` properties, both as numbers, in pixels. + */ + setBounds: setBounds, + /** + * Increments the width of the autoflow column. + * Setting does not yet persist. + */ + increaseColumnWidth: increaseColumnWidth, + /** + * Get-or-set the user-supplied filter value. + * @param {string} [value] the new filter value; omit to use + * as a getter + * @returns {string} the user-supplied filter value + */ + filter: filter, + /** + * Get all range values for use in this table. These will be + * returned as an object of key-value pairs, where keys are + * domain object IDs, and values are the most recently observed + * data values associated with those objects, formatted for + * display. + * @returns {object.} most recent values + */ + rangeValues: function () { + return rangeValues; + }, + /** + * Get CSS classes to apply to specific rows, representing limit + * states and/or stale states. These are returned as key-value + * pairs where keys are domain object IDs, and values are CSS + * classes to display for domain objects with those IDs. + * @returns {object.} CSS classes + */ + classes: function () { + return classes; + }, + /** + * Get the "last updated" text for this view; this will be + * the most recent timestamp observed for any telemetry- + * providing object, formatted for display. + * @returns {string} the time of the most recent update + */ + updated: updated, + /** + * Get the current column width, in pixels. + * @returns {number} column width + */ + columnWidth: function () { + return columnWidth; + }, + /** + * Keep a counter and increment this whenever the display + * should be updated; this will be watched by the + * `mct-autoflow-table`. + * @returns {number} a counter value + */ + counter: function () { + return counter; + } + }; + } + + return AutflowTabularController; + } +); diff --git a/platform/features/autoflow/src/MCTAutoflowTable.js b/platform/features/autoflow/src/MCTAutoflowTable.js new file mode 100755 index 0000000000..dc5c24f42c --- /dev/null +++ b/platform/features/autoflow/src/MCTAutoflowTable.js @@ -0,0 +1,60 @@ + +define( + ["./AutoflowTableLinker"], + function (AutoflowTableLinker) { + + /** + * The `mct-autoflow-table` directive specifically supports + * autoflow tabular views; it is not intended for use outside + * of that view. + * + * This directive is responsible for creating the structure + * of the table in this view, and for updating its values. + * While this is achievable using a regular Angular template, + * this is undesirable from the perspective of performance + * due to the number of watches that can be involved for large + * tables. Instead, this directive will maintain a small number + * of watches, rebuilding table structure only when necessary, + * and updating displayed values in the more common case of + * new data arriving. + * + * @constructor + */ + function MCTAutoflowTable() { + return { + // Only applicable at the element level + restrict: "E", + + // The link function; handles DOM update/manipulation + link: AutoflowTableLinker, + + // Parameters to pass from attributes into scope + scope: { + // Set of domain objects to show in the table + objects: "=", + + // Values for those objects, by ID + values: "=", + + // CSS classes to show for objects, by ID + classes: "=", + + // Number of rows to show before autoflowing + rows: "=", + + // Time of last update; watched to refresh values + updated: "=", + + // Current width of the autoflow column + columnWidth: "=", + + // A counter used to trigger display updates + counter: "=" + } + }; + } + + return MCTAutoflowTable; + + } +); diff --git a/platform/features/autoflow/test/AutoflowTableLinkerSpec.js b/platform/features/autoflow/test/AutoflowTableLinkerSpec.js new file mode 100755 index 0000000000..0ae08db4d8 --- /dev/null +++ b/platform/features/autoflow/test/AutoflowTableLinkerSpec.js @@ -0,0 +1,178 @@ + +define( + ["../src/AutoflowTableLinker"], + function (AutoflowTableLinker) { + + describe("The mct-autoflow-table linker", function () { + var cachedAngular, + mockAngular, + mockScope, + mockElement, + mockElements, + linker; + + // Utility function to generate more mock elements + function createMockElement(html) { + var mockEl = jasmine.createSpyObj( + "element-" + html, + [ + "append", + "addClass", + "removeClass", + "text", + "attr", + "html", + "css", + "find" + ] + ); + mockEl.testHtml = html; + mockEl.append.andReturn(mockEl); + mockElements.push(mockEl); + return mockEl; + } + + function createMockDomainObject(id) { + var mockDomainObject = jasmine.createSpyObj( + "domainObject-" + id, + ["getId", "getModel"] + ); + mockDomainObject.getId.andReturn(id); + mockDomainObject.getModel.andReturn({name: id.toUpperCase()}); + return mockDomainObject; + } + + function fireWatch(watchExpression, value) { + mockScope.$watch.calls.forEach(function (call) { + if (call.args[0] === watchExpression) { + call.args[1](value); + } + }); + } + + // AutoflowTableLinker accesses Angular in the global + // scope, since it is not injectable; we simulate that + // here by adding/removing it to/from the window object. + beforeEach(function () { + mockElements = []; + + mockAngular = jasmine.createSpyObj("angular", ["element"]); + mockScope = jasmine.createSpyObj("scope", ["$watch"]); + mockElement = createMockElement('
      '); + + mockAngular.element.andCallFake(createMockElement); + + if (window.angular !== undefined) { + cachedAngular = window.angular; + } + window.angular = mockAngular; + + linker = new AutoflowTableLinker(mockScope, mockElement); + }); + + afterEach(function () { + if (cachedAngular !== undefined) { + window.angular = cachedAngular; + } else { + delete window.angular; + } + }); + + it("watches for changes in inputs", function () { + expect(mockScope.$watch).toHaveBeenCalledWith( + "objects", + jasmine.any(Function) + ); + expect(mockScope.$watch).toHaveBeenCalledWith( + "rows", + jasmine.any(Function) + ); + expect(mockScope.$watch).toHaveBeenCalledWith( + "counter", + jasmine.any(Function) + ); + }); + + it("changes structure when domain objects change", function () { + // Set up scope + mockScope.rows = 4; + mockScope.objects = ['a', 'b', 'c', 'd', 'e', 'f'] + .map(createMockDomainObject); + + // Fire an update to the set of objects + fireWatch("objects"); + + // Should have rebuilt with two columns of + // four and two rows each; first, by clearing... + expect(mockElement.html).toHaveBeenCalledWith(""); + + // Should have appended two columns... + expect(mockElement.append.calls.length).toEqual(2); + + // ...which should have received two and four rows each + expect(mockElement.append.calls[0].args[0].append.calls.length) + .toEqual(4); + expect(mockElement.append.calls[1].args[0].append.calls.length) + .toEqual(2); + }); + + it("updates values", function () { + var mockSpans; + + mockScope.objects = ['a', 'b', 'c', 'd', 'e', 'f'] + .map(createMockDomainObject); + mockScope.values = { a: 0 }; + + // Fire an update to the set of values + fireWatch("objects"); + fireWatch("updated"); + + // Get all created spans + mockSpans = mockElements.filter(function (mockElem) { + return mockElem.testHtml === ''; + }); + + // First span should be a, should have gotten this value. + // This test detects, in particular, WTD-749 + expect(mockSpans[0].text).toHaveBeenCalledWith('A'); + expect(mockSpans[1].text).toHaveBeenCalledWith(0); + }); + + it("listens for changes in column width", function () { + var mockUL = createMockElement("
        "); + mockElement.find.andReturn(mockUL); + mockScope.columnWidth = 200; + fireWatch("columnWidth", mockScope.columnWidth); + expect(mockUL.css).toHaveBeenCalledWith("width", "200px"); + }); + + it("updates CSS classes", function () { + var mockSpans; + + mockScope.objects = ['a', 'b', 'c', 'd', 'e', 'f'] + .map(createMockDomainObject); + mockScope.values = { a: "a value to find" }; + mockScope.classes = { a: 'class-a' }; + + // Fire an update to the set of values + fireWatch("objects"); + fireWatch("updated"); + + // Figure out which span holds the relevant value... + mockSpans = mockElements.filter(function (mockElem) { + return mockElem.testHtml === ''; + }).filter(function (mockSpan) { + var attrCalls = mockSpan.attr.calls; + return attrCalls.some(function (call) { + return call.args[0] === 'title' && + call.args[1] === mockScope.values.a; + }); + }); + + // ...and make sure it also has had its class applied + expect(mockSpans[0].addClass) + .toHaveBeenCalledWith(mockScope.classes.a); + }); + }); + } +); diff --git a/platform/features/autoflow/test/AutoflowTabularControllerSpec.js b/platform/features/autoflow/test/AutoflowTabularControllerSpec.js new file mode 100755 index 0000000000..14edafab69 --- /dev/null +++ b/platform/features/autoflow/test/AutoflowTabularControllerSpec.js @@ -0,0 +1,341 @@ + +define( + ["../src/AutoflowTabularController"], + function (AutoflowTabularController) { + + describe("The autoflow tabular controller", function () { + var mockScope, + mockTimeout, + mockSubscriber, + mockDomainObject, + mockSubscription, + controller; + + // Fire watches that are registered as functions. + function fireFnWatches() { + mockScope.$watch.calls.forEach(function (call) { + if (typeof call.args[0] === 'function') { + call.args[1](call.args[0]()); + } + }); + } + + beforeEach(function () { + mockScope = jasmine.createSpyObj( + "$scope", + ["$on", "$watch"] + ); + mockTimeout = jasmine.createSpy("$timeout"); + mockSubscriber = jasmine.createSpyObj( + "telemetrySubscriber", + ["subscribe"] + ); + mockDomainObject = jasmine.createSpyObj( + "domainObject", + ["getId", "getModel", "getCapability"] + ); + mockSubscription = jasmine.createSpyObj( + "subscription", + [ + "unsubscribe", + "getTelemetryObjects", + "getDomainValue", + "getRangeValue" + ] + ); + + mockSubscriber.subscribe.andReturn(mockSubscription); + mockDomainObject.getModel.andReturn({name: "something"}); + + controller = new AutoflowTabularController( + mockScope, + mockTimeout, + mockSubscriber + ); + }); + + it("listens for the represented domain object", function () { + expect(mockScope.$watch).toHaveBeenCalledWith( + "domainObject", + jasmine.any(Function) + ); + }); + + it("provides a getter-setter function for filtering", function () { + expect(controller.filter()).toEqual(""); + controller.filter("something"); + expect(controller.filter()).toEqual("something"); + }); + + it("tracks bounds and adjust number of rows accordingly", function () { + // Rows are 15px high, and need room for an 10px slider + controller.setBounds({ width: 700, height: 120 }); + expect(controller.getRows()).toEqual(6); // 110 usable height / 16px + controller.setBounds({ width: 700, height: 240 }); + expect(controller.getRows()).toEqual(14); // 230 usable height / 16px + }); + + it("subscribes to a represented object's telemetry", function () { + // Set up subscription, scope + mockSubscription.getTelemetryObjects + .andReturn([mockDomainObject]); + mockScope.domainObject = mockDomainObject; + + // Invoke the watcher with represented domain object + mockScope.$watch.mostRecentCall.args[1](mockDomainObject); + + // Should have subscribed to it + expect(mockSubscriber.subscribe).toHaveBeenCalledWith( + mockDomainObject, + jasmine.any(Function) + ); + + // Should report objects as reported from subscription + expect(controller.getTelemetryObjects()) + .toEqual([mockDomainObject]); + }); + + it("releases subscriptions on destroy", function () { + // Set up subscription... + mockSubscription.getTelemetryObjects + .andReturn([mockDomainObject]); + mockScope.domainObject = mockDomainObject; + mockScope.$watch.mostRecentCall.args[1](mockDomainObject); + + // Verify precondition + expect(mockSubscription.unsubscribe).not.toHaveBeenCalled(); + + // Make sure we're listening for $destroy + expect(mockScope.$on).toHaveBeenCalledWith( + "$destroy", + jasmine.any(Function) + ); + + // Fire a destroy event + mockScope.$on.mostRecentCall.args[1](); + + // Should have unsubscribed + expect(mockSubscription.unsubscribe).toHaveBeenCalled(); + }); + + it("presents latest values and latest update state", function () { + // Make sure values are available + mockSubscription.getDomainValue.andReturn(402654321123); + mockSubscription.getRangeValue.andReturn(789); + mockDomainObject.getId.andReturn('testId'); + + // Set up subscription... + mockSubscription.getTelemetryObjects + .andReturn([mockDomainObject]); + mockScope.domainObject = mockDomainObject; + mockScope.$watch.mostRecentCall.args[1](mockDomainObject); + + // Fire subscription callback + mockSubscriber.subscribe.mostRecentCall.args[1](); + + // ...and exposed the results for template to consume + expect(controller.updated()).toEqual("1982-278 08:25:21.123Z"); + expect(controller.rangeValues().testId).toEqual(789); + }); + + it("sorts domain objects by index", function () { + var testIndexes = { a: 2, b: 1, c: 3, d: 0 }, + mockDomainObjects = Object.keys(testIndexes).sort().map(function (id) { + var mockDomainObj = jasmine.createSpyObj( + "domainObject", + ["getId", "getModel"] + ); + + mockDomainObj.getId.andReturn(id); + mockDomainObj.getModel.andReturn({ index: testIndexes[id] }); + + return mockDomainObj; + }); + + // Expose those domain objects... + mockSubscription.getTelemetryObjects.andReturn(mockDomainObjects); + mockScope.domainObject = mockDomainObject; + mockScope.$watch.mostRecentCall.args[1](mockDomainObject); + + // Fire subscription callback + mockSubscriber.subscribe.mostRecentCall.args[1](); + + // Controller should expose same objects, but sorted by index from model + expect(controller.getTelemetryObjects()).toEqual([ + mockDomainObjects[3], // d, index=0 + mockDomainObjects[1], // b, index=1 + mockDomainObjects[0], // a, index=2 + mockDomainObjects[2] // c, index=3 + ]); + }); + + it("uses a timeout to throttle update", function () { + // Set up subscription... + mockSubscription.getTelemetryObjects + .andReturn([mockDomainObject]); + mockScope.domainObject = mockDomainObject; + + // Set the object in view; should not need a timeout + mockScope.$watch.mostRecentCall.args[1](mockDomainObject); + expect(mockTimeout.calls.length).toEqual(0); + + // Next call should schedule an update on a timeout + mockScope.$watch.mostRecentCall.args[1](mockDomainObject); + expect(mockTimeout.calls.length).toEqual(1); + + // ...but this last one should not, since existing + // timeout will cover it + mockScope.$watch.mostRecentCall.args[1](mockDomainObject); + expect(mockTimeout.calls.length).toEqual(1); + }); + + it("allows changing column width", function () { + var initialWidth = controller.columnWidth(); + controller.increaseColumnWidth(); + expect(controller.columnWidth()).toBeGreaterThan(initialWidth); + }); + + describe("filter", function () { + var doFilter, + filteredObjects, + filteredObjectNames; + + beforeEach(function () { + var telemetryObjects, + updateFilteredObjects; + + telemetryObjects = [ + 'DEF123', + 'abc789', + '456abc', + '4ab3cdef', + 'hjs[12].*(){}^\\' + ].map(function (objectName, index) { + var mockTelemetryObject = jasmine.createSpyObj( + objectName, + ["getId", "getModel"] + ); + + mockTelemetryObject.getId.andReturn(objectName); + mockTelemetryObject.getModel.andReturn({ + name: objectName, + index: index + }); + + return mockTelemetryObject; + }); + + mockSubscription + .getTelemetryObjects + .andReturn(telemetryObjects); + + // Trigger domainObject change to create subscription. + mockScope.$watch.mostRecentCall.args[1](mockDomainObject); + + updateFilteredObjects = function () { + filteredObjects = controller.getTelemetryObjects(); + filteredObjectNames = filteredObjects.map(function (o) { + return o.getModel().name; + }); + }; + + doFilter = function (term) { + controller.filter(term); + // Filter is debounced so we have to force it to occur. + mockTimeout.mostRecentCall.args[0](); + updateFilteredObjects(); + }; + + updateFilteredObjects(); + }); + + it("initially shows all objects", function () { + expect(filteredObjectNames).toEqual([ + 'DEF123', + 'abc789', + '456abc', + '4ab3cdef', + 'hjs[12].*(){}^\\' + ]); + }); + + it("by blank string matches all objects", function () { + doFilter(''); + expect(filteredObjectNames).toEqual([ + 'DEF123', + 'abc789', + '456abc', + '4ab3cdef', + 'hjs[12].*(){}^\\' + ]); + }); + + it("exactly matches an object name", function () { + doFilter('4ab3cdef'); + expect(filteredObjectNames).toEqual(['4ab3cdef']); + }); + + it("partially matches object names", function () { + doFilter('abc'); + expect(filteredObjectNames).toEqual([ + 'abc789', + '456abc' + ]); + }); + + it("matches case insensitive names", function () { + doFilter('def'); + expect(filteredObjectNames).toEqual([ + 'DEF123', + '4ab3cdef' + ]); + }); + + it("works as expected with special characters", function () { + doFilter('[12]'); + expect(filteredObjectNames).toEqual(['hjs[12].*(){}^\\']); + doFilter('.*'); + expect(filteredObjectNames).toEqual(['hjs[12].*(){}^\\']); + doFilter('.*()'); + expect(filteredObjectNames).toEqual(['hjs[12].*(){}^\\']); + doFilter('.*?'); + expect(filteredObjectNames).toEqual([]); + doFilter('.+'); + expect(filteredObjectNames).toEqual([]); + }); + + it("exposes CSS classes from limits", function () { + var id = mockDomainObject.getId(), + testClass = "some-css-class", + mockLimitCapability = + jasmine.createSpyObj('limit', ['evaluate']); + + mockDomainObject.getCapability.andCallFake(function (key) { + return key === 'limit' && mockLimitCapability; + }); + mockLimitCapability.evaluate + .andReturn({ cssClass: testClass }); + + mockSubscription.getTelemetryObjects + .andReturn([mockDomainObject]); + + fireFnWatches(); + mockSubscriber.subscribe.mostRecentCall.args[1](); + + expect(controller.classes()[id]).toEqual(testClass); + }); + + it("exposes a counter that changes with each update", function () { + var i, prior; + + for (i = 0; i < 10; i += 1) { + prior = controller.counter(); + expect(controller.counter()).toEqual(prior); + mockSubscriber.subscribe.mostRecentCall.args[1](); + expect(controller.counter()).not.toEqual(prior); + } + }); + }); + }); + } +); diff --git a/platform/features/autoflow/test/MCTAutoflowTableSpec.js b/platform/features/autoflow/test/MCTAutoflowTableSpec.js new file mode 100755 index 0000000000..d86777b9b5 --- /dev/null +++ b/platform/features/autoflow/test/MCTAutoflowTableSpec.js @@ -0,0 +1,39 @@ + +define( + ["../src/MCTAutoflowTable"], + function (MCTAutoflowTable) { + + describe("The mct-autoflow-table directive", function () { + var mctAutoflowTable; + + beforeEach(function () { + mctAutoflowTable = new MCTAutoflowTable(); + }); + + // Real functionality is contained/tested in the linker, + // so just check to make sure we're exposing the directive + // appropriately. + it("is applicable at the element level", function () { + expect(mctAutoflowTable.restrict).toEqual("E"); + }); + + it("two-ways binds needed scope variables", function () { + expect(mctAutoflowTable.scope).toEqual({ + objects: "=", + values: "=", + rows: "=", + updated: "=", + classes: "=", + columnWidth: "=", + counter: "=" + }); + }); + + it("provides a link function", function () { + expect(mctAutoflowTable.link).toEqual(jasmine.any(Function)); + }); + + + }); + } +); diff --git a/src/plugins/plugins.js b/src/plugins/plugins.js index 428a7015a5..c1c5962923 100644 --- a/src/plugins/plugins.js +++ b/src/plugins/plugins.js @@ -23,11 +23,13 @@ define([ 'lodash', '../../platform/features/conductor/utcTimeSystem/src/UTCTimeSystem', - '../../example/generator/plugin' + '../../example/generator/plugin', + '../../platform/features/autoflow/plugin' ], function ( _, UTCTimeSystem, - GeneratorPlugin + GeneratorPlugin, + AutoflowPlugin ) { var bundleMap = { CouchDB: 'platform/persistence/couch', @@ -55,6 +57,10 @@ define([ }; }; + plugins.AutoflowView = function () { + return AutoflowPlugin; + }; + var conductorInstalled = false; plugins.Conductor = function (options) { From 8d86ca05da618c1c3ebfa8a84f882e557eaa7bdd Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 30 Mar 2017 11:03:14 -0700 Subject: [PATCH 17/38] [API] Removed API classes from Open MCT prototype. Fixes #1293 --- src/MCT.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/MCT.js b/src/MCT.js index 381d7c36b0..187a62701f 100644 --- a/src/MCT.js +++ b/src/MCT.js @@ -194,15 +194,13 @@ define([ */ this.telemetry = new api.TelemetryAPI(this); - this.TimeConductor = this.conductor; // compatibility for prototype + this.Dialog = api.Dialog; + this.on('navigation', this.selection.clear.bind(this.selection)); } MCT.prototype = Object.create(EventEmitter.prototype); - Object.keys(api).forEach(function (k) { - MCT.prototype[k] = api[k]; - }); MCT.prototype.MCT = MCT; MCT.prototype.legacyExtension = function (category, extension) { From 67eab82bd19114142285564a620a11dcb351a09e Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 31 Mar 2017 12:42:37 -0700 Subject: [PATCH 18/38] [Testing] Begin testing MCT Fixes #1218 --- src/MCTSpec.js | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/MCTSpec.js diff --git a/src/MCTSpec.js b/src/MCTSpec.js new file mode 100644 index 0000000000..2161eecc8f --- /dev/null +++ b/src/MCTSpec.js @@ -0,0 +1,38 @@ +/***************************************************************************** + * 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([ + './MCT', + './plugins/plugins' +], function (MCT, plugins) { + describe("MCT", function () { + var openmct; + + beforeEach(function () { + openmct = new MCT(); + }); + + it("exposes plugins", function () { + expect(openmct.plugins).toEqual(plugins); + }); + }); +}); From c27b37918a677ae9e00de13f0ac4b22b75ec7189 Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 31 Mar 2017 15:39:13 -0700 Subject: [PATCH 19/38] [Time Conductor] Removed caching of UTC Time System defaults which was causing gaps in plots. Fixes #1434 --- .../utcTimeSystem/src/UTCTimeSystem.js | 30 +++++++------------ src/plugins/plugins.js | 8 ----- 2 files changed, 11 insertions(+), 27 deletions(-) diff --git a/platform/features/conductor/utcTimeSystem/src/UTCTimeSystem.js b/platform/features/conductor/utcTimeSystem/src/UTCTimeSystem.js index 422c356512..a933761eac 100644 --- a/platform/features/conductor/utcTimeSystem/src/UTCTimeSystem.js +++ b/platform/features/conductor/utcTimeSystem/src/UTCTimeSystem.js @@ -48,7 +48,6 @@ define([ 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; diff --git a/src/plugins/plugins.js b/src/plugins/plugins.js index 428a7015a5..785c72cd52 100644 --- a/src/plugins/plugins.js +++ b/src/plugins/plugins.js @@ -68,14 +68,6 @@ define([ return ts.metadata.key === options.defaultTimeSystem; }); if (timeSystem !== undefined) { - defaults = timeSystem.defaults(); - - if (options.defaultTimespan !== undefined) { - defaults.deltas.start = options.defaultTimespan; - defaults.bounds.start = defaults.bounds.end - options.defaultTimespan; - timeSystem.defaults(defaults); - } - openmct.conductor.timeSystem(timeSystem, defaults.bounds); } } From f666a7ca09db58bc252620050a6bfa2fd4baaeb8 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 3 Apr 2017 13:29:48 -0700 Subject: [PATCH 20/38] [Web Page] Allow dashes in domains Fixes #1507 --- platform/features/pages/bundle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/features/pages/bundle.js b/platform/features/pages/bundle.js index 9fd12d051d..bc981b77e4 100644 --- a/platform/features/pages/bundle.js +++ b/platform/features/pages/bundle.js @@ -47,7 +47,7 @@ define([ "key": "url", "name": "URL", "control": "textfield", - "pattern": "^(ftp|https?)\\:\\/\\/\\w+(\\.\\w+)*(\\:\\d+)?(\\/\\S*)*$", + "pattern": "^(ftp|https?)\\:\\/\\/[-\\w]+(\\.[-\\w]+)*(\\:\\d+)?(\\/\\S*)*$", "required": true, "cssClass": "l-input-lg" } From c07a372c6e662eca3edeb4c6813e074588d4168a Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 3 Apr 2017 14:23:21 -0700 Subject: [PATCH 21/38] [Web Page] Simplify RegEx https://github.com/nasa/openmct/pull/1508#issuecomment-291271270 --- platform/features/pages/bundle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/features/pages/bundle.js b/platform/features/pages/bundle.js index bc981b77e4..6773f4dd6f 100644 --- a/platform/features/pages/bundle.js +++ b/platform/features/pages/bundle.js @@ -47,7 +47,7 @@ define([ "key": "url", "name": "URL", "control": "textfield", - "pattern": "^(ftp|https?)\\:\\/\\/[-\\w]+(\\.[-\\w]+)*(\\:\\d+)?(\\/\\S*)*$", + "pattern": "^(ftp|https?)\\:\\/\\/", "required": true, "cssClass": "l-input-lg" } From 5f968b50f84b26ed6a296b3080625768f4b8b7ae Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 4 Apr 2017 11:16:24 -0700 Subject: [PATCH 22/38] [Build] Enable coverage of src For #1218 --- karma.conf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/karma.conf.js b/karma.conf.js index 84909b42a7..e862060182 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -53,7 +53,7 @@ module.exports = function(config) { // Preprocess matching files before serving them to the browser. // https://npmjs.org/browse/keyword/karma-preprocessor preprocessors: { - 'src/**/src/**/!(*Spec).js': [ 'coverage' ], + 'src/**/!(*Spec).js': [ 'coverage' ], 'platform/**/src/**/!(*Spec).js': [ 'coverage' ] }, From 6870055033b211026f71d98fe651148bbd373cf7 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 4 Apr 2017 11:19:45 -0700 Subject: [PATCH 23/38] [Testing] Test plugin installation --- src/MCTSpec.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/MCTSpec.js b/src/MCTSpec.js index 2161eecc8f..d2a2027182 100644 --- a/src/MCTSpec.js +++ b/src/MCTSpec.js @@ -26,13 +26,32 @@ define([ ], function (MCT, plugins) { describe("MCT", function () { var openmct; + var mockPlugin; + var mockPlugin2; beforeEach(function () { + mockPlugin = jasmine.createSpy('plugin'); + mockPlugin2 = jasmine.createSpy('plugin'); + openmct = new MCT(); + + openmct.install(mockPlugin); + openmct.install(mockPlugin2); }); it("exposes plugins", function () { expect(openmct.plugins).toEqual(plugins); }); + + describe("when started", function () { + beforeEach(function () { + openmct.start(); + }); + + it("calls plugins for configuration", function () { + expect(mockPlugin).toHaveBeenCalledWith(openmct); + expect(mockPlugin2).toHaveBeenCalledWith(openmct); + }); + }); }); }); From 35c457b7fb12fdb8f9e697804800d007feac5161 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 4 Apr 2017 11:25:35 -0700 Subject: [PATCH 24/38] [Testing] Test MCT.setAssetPath --- src/MCTSpec.js | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/MCTSpec.js b/src/MCTSpec.js index d2a2027182..7742d85db2 100644 --- a/src/MCTSpec.js +++ b/src/MCTSpec.js @@ -43,7 +43,7 @@ define([ expect(openmct.plugins).toEqual(plugins); }); - describe("when started", function () { + describe("start", function () { beforeEach(function () { openmct.start(); }); @@ -53,5 +53,25 @@ define([ expect(mockPlugin2).toHaveBeenCalledWith(openmct); }); }); + + describe("setAssetPath", function () { + var testAssetPath; + + beforeEach(function () { + testAssetPath = "some/path"; + openmct.legacyExtension = jasmine.createSpy('legacyExtension'); + openmct.setAssetPath(testAssetPath); + }); + + it("internally configures the path for assets", function () { + expect(openmct.legacyExtension).toHaveBeenCalledWith( + 'constants', + { + key: "ASSETS_PATH", + value: testAssetPath + } + ); + }); + }); }); }); From b48dd4b63b8d9477881db4a22b3776ab33a47a51 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 4 Apr 2017 11:35:49 -0700 Subject: [PATCH 25/38] [Testing] Test start event on MCT --- src/MCTSpec.js | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/MCTSpec.js b/src/MCTSpec.js index 7742d85db2..2aa1dc0abd 100644 --- a/src/MCTSpec.js +++ b/src/MCTSpec.js @@ -22,27 +22,46 @@ define([ './MCT', - './plugins/plugins' -], function (MCT, plugins) { + './plugins/plugins', + 'legacyRegistry' +], function (MCT, plugins, legacyRegistry) { describe("MCT", function () { var openmct; var mockPlugin; var mockPlugin2; + var mockListener; + var oldBundles; beforeEach(function () { mockPlugin = jasmine.createSpy('plugin'); - mockPlugin2 = jasmine.createSpy('plugin'); + mockPlugin2 = jasmine.createSpy('plugin2'); + mockListener = jasmine.createSpy('listener'); + oldBundles = legacyRegistry.list(); openmct = new MCT(); openmct.install(mockPlugin); openmct.install(mockPlugin2); + openmct.on('start', mockListener); + }); + + // Clean up the dirty singleton. + afterEach(function () { + legacyRegistry.list().forEach(function (bundle) { + if (oldBundles.indexOf(bundle) === -1) { + legacyRegistry.delete(bundle); + } + }); }); it("exposes plugins", function () { expect(openmct.plugins).toEqual(plugins); }); + it("does not issue a start event before started", function () { + expect(mockListener).not.toHaveBeenCalled(); + }); + describe("start", function () { beforeEach(function () { openmct.start(); @@ -52,6 +71,10 @@ define([ expect(mockPlugin).toHaveBeenCalledWith(openmct); expect(mockPlugin2).toHaveBeenCalledWith(openmct); }); + + it("emits a start event", function () { + expect(mockListener).toHaveBeenCalled(); + }); }); describe("setAssetPath", function () { From a867cd6be0c3094ccc12686a254bdccc08ad05a8 Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 31 Mar 2017 15:16:20 -0700 Subject: [PATCH 26/38] Removed contextualization warning. Removed now redundant Contextualize service. Fixes #1498 --- platform/core/bundle.js | 12 +- .../src/capabilities/CompositionCapability.js | 9 +- .../capabilities/InstantiationCapability.js | 10 +- platform/core/src/services/Contextualize.js | 82 -------------- .../capabilities/CompositionCapabilitySpec.js | 9 -- .../InstantiationCapabilitySpec.js | 13 +-- .../core/test/services/ContextualizeSpec.js | 103 ------------------ platform/entanglement/bundle.js | 1 - .../src/services/LocatingObjectDecorator.js | 9 +- .../services/LocatingObjectDecoratorSpec.js | 40 ++----- .../AlternateCompositionCapability.js | 8 +- 11 files changed, 30 insertions(+), 266 deletions(-) delete mode 100644 platform/core/src/services/Contextualize.js delete mode 100644 platform/core/test/services/ContextualizeSpec.js diff --git a/platform/core/bundle.js b/platform/core/bundle.js index 30b2609c92..a25ad3ff1a 100644 --- a/platform/core/bundle.js +++ b/platform/core/bundle.js @@ -49,7 +49,6 @@ define([ "./src/services/Now", "./src/services/Throttle", "./src/services/Topic", - "./src/services/Contextualize", "./src/services/Instantiate", 'legacyRegistry' ], function ( @@ -81,7 +80,6 @@ define([ Now, Throttle, Topic, - Contextualize, Instantiate, legacyRegistry ) { @@ -284,8 +282,7 @@ define([ "key": "composition", "implementation": CompositionCapability, "depends": [ - "$injector", - "contextualize" + "$injector" ] }, { @@ -380,13 +377,6 @@ define([ "$log" ] }, - { - "key": "contextualize", - "implementation": Contextualize, - "depends": [ - "$log" - ] - }, { "key": "instantiate", "implementation": Instantiate, diff --git a/platform/core/src/capabilities/CompositionCapability.js b/platform/core/src/capabilities/CompositionCapability.js index 3f5769005f..c77aea4e86 100644 --- a/platform/core/src/capabilities/CompositionCapability.js +++ b/platform/core/src/capabilities/CompositionCapability.js @@ -24,7 +24,8 @@ * Module defining CompositionCapability. Created by vwoeltje on 11/7/14. */ define( - function () { + ['./ContextualDomainObject'], + function (ContextualDomainObject) { /** * Composition capability. A domain object's composition is the set of @@ -38,13 +39,12 @@ define( * @constructor * @implements {Capability} */ - function CompositionCapability($injector, contextualize, domainObject) { + function CompositionCapability($injector, domainObject) { // Get a reference to the object service from $injector this.injectObjectService = function () { this.objectService = $injector.get("objectService"); }; - this.contextualize = contextualize; this.domainObject = domainObject; } @@ -115,7 +115,6 @@ define( CompositionCapability.prototype.invoke = function () { var domainObject = this.domainObject, model = domainObject.getModel(), - contextualize = this.contextualize, ids; // Then filter out non-existent objects, @@ -125,7 +124,7 @@ define( return ids.filter(function (id) { return objects[id]; }).map(function (id) { - return contextualize(objects[id], domainObject); + return new ContextualDomainObject(objects[id], domainObject); }); } diff --git a/platform/core/src/capabilities/InstantiationCapability.js b/platform/core/src/capabilities/InstantiationCapability.js index 81b2f954e4..6005b8c9bb 100644 --- a/platform/core/src/capabilities/InstantiationCapability.js +++ b/platform/core/src/capabilities/InstantiationCapability.js @@ -21,8 +21,8 @@ *****************************************************************************/ define( - [], - function () { + ['./ContextualDomainObject'], + function (ContextualDomainObject) { /** * Implements the `instantiation` capability. This allows new domain @@ -70,11 +70,7 @@ define( var newObject = this.instantiateFn(model, id); - this.contextualizeFn = this.contextualizeFn || - this.$injector.get("contextualize"); - - - return this.contextualizeFn(newObject, this.domainObject); + return new ContextualDomainObject(newObject, this.domainObject); }; /** diff --git a/platform/core/src/services/Contextualize.js b/platform/core/src/services/Contextualize.js deleted file mode 100644 index ff4571782a..0000000000 --- a/platform/core/src/services/Contextualize.js +++ /dev/null @@ -1,82 +0,0 @@ -/***************************************************************************** - * 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( - ['../capabilities/ContextualDomainObject'], - function (ContextualDomainObject) { - - /** - * Wrap a domain object such that it has a `context` capability - * referring to a specific parent. - * - * Usage: - * - * contextualize(domainObject, parentObject) - * - * Attempting to contextualize an object with a parent that does - * not include that object in its composition may have - * unpredictable results; a warning will be logged if this occurs. - * - * @returns {Function} - * @memberof platform/core - */ - function Contextualize($log) { - function validate(id, parentObject) { - var model = parentObject && parentObject.getModel(), - composition = (model || {}).composition || []; - if (composition.indexOf(id) === -1) { - $log.warn([ - "Attempted to contextualize", - id, - "in", - parentObject && parentObject.getId(), - "but that object does not contain", - id, - "in its composition.", - "Unexpected behavior may follow." - ].join(" ")); - } - } - - /** - * Contextualize this domain object. - * @param {DomainObject} domainObject the domain object - * to wrap with a context - * @param {DomainObject} parentObject the domain object - * which should appear as the contextual parent - */ - return function (domainObject, parentObject) { - // Don't validate while editing; consistency is not - // necessarily expected due to unsaved changes. - var editor = domainObject.getCapability('editor'); - if (!editor || !editor.inEditContext()) { - validate(domainObject.getId(), parentObject); - } - - return new ContextualDomainObject(domainObject, parentObject); - }; - } - - return Contextualize; - } -); - diff --git a/platform/core/test/capabilities/CompositionCapabilitySpec.js b/platform/core/test/capabilities/CompositionCapabilitySpec.js index 0ec32fb881..e95f566aee 100644 --- a/platform/core/test/capabilities/CompositionCapabilitySpec.js +++ b/platform/core/test/capabilities/CompositionCapabilitySpec.js @@ -41,7 +41,6 @@ define( describe("The composition capability", function () { var mockDomainObject, mockInjector, - mockContextualize, mockObjectService, composition; @@ -72,19 +71,11 @@ define( return (name === "objectService") && mockObjectService; } }; - mockContextualize = jasmine.createSpy('contextualize'); - - // Provide a minimal (e.g. no error-checking) implementation - // of contextualize for simplicity - mockContextualize.andCallFake(function (domainObject, parentObject) { - return new ContextualDomainObject(domainObject, parentObject); - }); mockObjectService.getObjects.andReturn(mockPromise([])); composition = new CompositionCapability( mockInjector, - mockContextualize, mockDomainObject ); }); diff --git a/platform/core/test/capabilities/InstantiationCapabilitySpec.js b/platform/core/test/capabilities/InstantiationCapabilitySpec.js index 90c9341fcf..54f0612ea5 100644 --- a/platform/core/test/capabilities/InstantiationCapabilitySpec.js +++ b/platform/core/test/capabilities/InstantiationCapabilitySpec.js @@ -28,7 +28,6 @@ define( var mockInjector, mockIdentifierService, mockInstantiate, - mockContextualize, mockIdentifier, mockNow, mockDomainObject, @@ -37,7 +36,6 @@ define( beforeEach(function () { mockInjector = jasmine.createSpyObj("$injector", ["get"]); mockInstantiate = jasmine.createSpy("instantiate"); - mockContextualize = jasmine.createSpy("contextualize"); mockIdentifierService = jasmine.createSpyObj( 'identifierService', ['parse', 'generate'] @@ -53,8 +51,7 @@ define( mockInjector.get.andCallFake(function (key) { return { - 'instantiate': mockInstantiate, - 'contextualize': mockContextualize + 'instantiate': mockInstantiate }[key]; }); mockIdentifierService.parse.andReturn(mockIdentifier); @@ -85,18 +82,12 @@ define( 'hasCapability' ]), testModel = { someKey: "some value" }; mockInstantiate.andReturn(mockDomainObj); - mockContextualize.andCallFake(function (x) { - return x; - }); - expect(instantiation.instantiate(testModel)) - .toBe(mockDomainObj); + instantiation.instantiate(testModel); expect(mockInstantiate) .toHaveBeenCalledWith({ someKey: "some value", modified: mockNow() }, jasmine.any(String)); - expect(mockContextualize) - .toHaveBeenCalledWith(mockDomainObj, mockDomainObject); }); }); diff --git a/platform/core/test/services/ContextualizeSpec.js b/platform/core/test/services/ContextualizeSpec.js deleted file mode 100644 index 64f929f217..0000000000 --- a/platform/core/test/services/ContextualizeSpec.js +++ /dev/null @@ -1,103 +0,0 @@ -/***************************************************************************** - * 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/services/Contextualize"], - function (Contextualize) { - - var DOMAIN_OBJECT_METHODS = [ - 'getId', - 'getModel', - 'getCapability', - 'hasCapability', - 'useCapability' - ]; - - describe("The 'contextualize' service", function () { - var mockLog, - mockDomainObject, - mockParentObject, - mockEditor, - testParentModel, - contextualize; - - beforeEach(function () { - testParentModel = { composition: ["abc"] }; - - mockLog = jasmine.createSpyObj( - "$log", - ["error", "warn", "info", "debug"] - ); - - mockDomainObject = - jasmine.createSpyObj('domainObject', DOMAIN_OBJECT_METHODS); - mockParentObject = - jasmine.createSpyObj('parentObject', DOMAIN_OBJECT_METHODS); - - mockEditor = - jasmine.createSpyObj('editor', ['inEditContext']); - - mockDomainObject.getId.andReturn("abc"); - mockDomainObject.getModel.andReturn({}); - mockParentObject.getId.andReturn("parent"); - mockParentObject.getModel.andReturn(testParentModel); - - mockEditor.inEditContext.andReturn(false); - mockDomainObject.getCapability.andCallFake(function (c) { - return c === 'editor' && mockEditor; - }); - - contextualize = new Contextualize(mockLog); - }); - - it("attaches a context capability", function () { - var contextualizedObject = - contextualize(mockDomainObject, mockParentObject); - - expect(contextualizedObject.getId()).toEqual("abc"); - expect(contextualizedObject.getCapability("context")) - .toBeDefined(); - expect(contextualizedObject.getCapability("context").getParent()) - .toBe(mockParentObject); - }); - - it("issues a warning if composition does not match", function () { - // Precondition - normally it should not issue a warning - contextualize(mockDomainObject, mockParentObject); - expect(mockLog.warn).not.toHaveBeenCalled(); - - testParentModel.composition = ["xyz"]; - - contextualize(mockDomainObject, mockParentObject); - expect(mockLog.warn).toHaveBeenCalled(); - }); - - it("does not issue warnings for objects being edited", function () { - mockEditor.inEditContext.andReturn(true); - testParentModel.composition = ["xyz"]; - contextualize(mockDomainObject, mockParentObject); - expect(mockLog.warn).not.toHaveBeenCalled(); - }); - - }); - } -); diff --git a/platform/entanglement/bundle.js b/platform/entanglement/bundle.js index 135a31d38b..7cf7322d9f 100644 --- a/platform/entanglement/bundle.js +++ b/platform/entanglement/bundle.js @@ -132,7 +132,6 @@ define([ "provides": "objectService", "implementation": LocatingObjectDecorator, "depends": [ - "contextualize", "$q", "$log" ] diff --git a/platform/entanglement/src/services/LocatingObjectDecorator.js b/platform/entanglement/src/services/LocatingObjectDecorator.js index 25f997d6ba..ca9d42535e 100644 --- a/platform/entanglement/src/services/LocatingObjectDecorator.js +++ b/platform/entanglement/src/services/LocatingObjectDecorator.js @@ -22,7 +22,8 @@ define( - function () { + ['../../../core/src/capabilities/ContextualDomainObject'], + function (ContextualDomainObject) { /** * Ensures that domain objects are loaded with a context capability @@ -31,8 +32,7 @@ define( * @implements {ObjectService} * @memberof platform/entanglement */ - function LocatingObjectDecorator(contextualize, $q, $log, objectService) { - this.contextualize = contextualize; + function LocatingObjectDecorator($q, $log, objectService) { this.$log = $log; this.objectService = objectService; this.$q = $q; @@ -41,7 +41,6 @@ define( LocatingObjectDecorator.prototype.getObjects = function (ids) { var $q = this.$q, $log = this.$log, - contextualize = this.contextualize, objectService = this.objectService, result = {}; @@ -76,7 +75,7 @@ define( return loadObjectInContext(location, exclude) .then(function (parent) { // ...and then contextualize with it! - return contextualize(domainObject, parent); + return new ContextualDomainObject(domainObject, parent); }); } diff --git a/platform/entanglement/test/services/LocatingObjectDecoratorSpec.js b/platform/entanglement/test/services/LocatingObjectDecoratorSpec.js index 01438d1134..bef181172e 100644 --- a/platform/entanglement/test/services/LocatingObjectDecoratorSpec.js +++ b/platform/entanglement/test/services/LocatingObjectDecoratorSpec.js @@ -23,13 +23,13 @@ define( [ - '../../src/services/LocatingObjectDecorator' + '../../src/services/LocatingObjectDecorator', + '../../../core/src/capabilities/ContextualDomainObject' ], - function (LocatingObjectDecorator) { + function (LocatingObjectDecorator, ContextualDomainObject) { describe("LocatingObjectDecorator", function () { - var mockContextualize, - mockQ, + var mockQ, mockLog, mockObjectService, mockCallback, @@ -57,21 +57,12 @@ define( }; testObjects = {}; - mockContextualize = jasmine.createSpy("contextualize"); mockQ = jasmine.createSpyObj("$q", ["when", "all"]); mockLog = jasmine.createSpyObj("$log", ["error", "warn", "info", "debug"]); mockObjectService = jasmine.createSpyObj("objectService", ["getObjects"]); - mockContextualize.andCallFake(function (domainObject, parentObject) { - // Not really what contextualize does, but easy to test! - return { - testObject: domainObject, - testParent: parentObject - }; - }); - mockQ.when.andCallFake(testPromise); mockQ.all.andCallFake(function (promises) { var result = {}; @@ -97,28 +88,21 @@ define( }); decorator = new LocatingObjectDecorator( - mockContextualize, mockQ, mockLog, mockObjectService ); }); - it("contextualizes domain objects by location", function () { + it("contextualizes domain objects", function () { decorator.getObjects(['b', 'c']).then(mockCallback); - expect(mockCallback).toHaveBeenCalledWith({ - b: { - testObject: testObjects.b, - testParent: testObjects.a - }, - c: { - testObject: testObjects.c, - testParent: { - testObject: testObjects.b, - testParent: testObjects.a - } - } - }); + expect(mockCallback).toHaveBeenCalled(); + + var callbackObj = mockCallback.mostRecentCall.args[0]; + expect(testObjects.b.getCapability('context')).not.toBeDefined(); + expect(testObjects.c.getCapability('context')).not.toBeDefined(); + expect(callbackObj.b.getCapability('context')).toBeDefined(); + expect(callbackObj.c.getCapability('context')).toBeDefined(); }); it("warns on cycle detection", function () { diff --git a/src/adapter/capabilities/AlternateCompositionCapability.js b/src/adapter/capabilities/AlternateCompositionCapability.js index f85ef2d57c..4e639424d1 100644 --- a/src/adapter/capabilities/AlternateCompositionCapability.js +++ b/src/adapter/capabilities/AlternateCompositionCapability.js @@ -24,13 +24,13 @@ * Module defining AlternateCompositionCapability. Created by vwoeltje on 11/7/14. */ define([ - '../../api/objects/object-utils' -], function (objectUtils) { + '../../api/objects/object-utils', + '../../../platform/core/src/capabilities/ContextualDomainObject' +], function (objectUtils, ContextualDomainObject) { function AlternateCompositionCapability($injector, domainObject) { this.domainObject = domainObject; this.getDependencies = function () { this.instantiate = $injector.get("instantiate"); - this.contextualize = $injector.get("contextualize"); this.getDependencies = undefined; this.openmct = $injector.get("openmct"); }.bind(this); @@ -74,7 +74,7 @@ define([ var keyString = objectUtils.makeKeyString(child.identifier); var oldModel = objectUtils.toOldFormat(child); var newDO = this.instantiate(oldModel, keyString); - return this.contextualize(newDO, this.domainObject); + return new ContextualDomainObject(newDO, this.domainObject); }; From 59c61e72b81494cbca910fd0c0c29223fbf218ca Mon Sep 17 00:00:00 2001 From: Andrew Henry Date: Wed, 29 Mar 2017 17:15:29 -0700 Subject: [PATCH 27/38] [Features] Added option to specify a type to exclusively apply the Autoflow view to --- platform/features/autoflow/plugin.js | 81 ++++++++++++++-------------- src/plugins/plugins.js | 13 +++-- 2 files changed, 52 insertions(+), 42 deletions(-) diff --git a/platform/features/autoflow/plugin.js b/platform/features/autoflow/plugin.js index 86affe181a..5d17cfbf09 100755 --- a/platform/features/autoflow/plugin.js +++ b/platform/features/autoflow/plugin.js @@ -7,45 +7,48 @@ define([ AutoflowTabularController, MCTAutoflowTable ) { - return function (openmct) { - openmct.legacyRegistry.register("platform/features/autoflow", { - "name": "WARP Telemetry Adapter", - "description": "Retrieves telemetry from the WARP Server and provides related types and views.", - "resources": "res", - "extensions": { - "views": [ - { - "key": "autoflow", - "name": "Autoflow Tabular", - "cssClass": "icon-packet", - "description": "A tabular view of packet contents.", - "template": autoflowTabularTemplate, - "needs": [ - "telemetry" - ], - "delegation": true - } - ], - "controllers": [ - { - "key": "AutoflowTabularController", - "implementation": AutoflowTabularController, - "depends": [ - "$scope", - "$timeout", - "telemetrySubscriber" - ] - } - ], - "directives": [ - { - "key": "mctAutoflowTable", - "implementation": MCTAutoflowTable - } - ] - } - }); - openmct.legacyRegistry.enable("platform/features/autoflow"); + return function (options) { + return function (openmct) { + openmct.legacyRegistry.register("platform/features/autoflow", { + "name": "WARP Telemetry Adapter", + "description": "Retrieves telemetry from the WARP Server and provides related types and views.", + "resources": "res", + "extensions": { + "views": [ + { + "key": "autoflow", + "name": "Autoflow Tabular", + "cssClass": "icon-packet", + "description": "A tabular view of packet contents.", + "template": autoflowTabularTemplate, + "type": options && options.type, + "needs": [ + "telemetry" + ], + "delegation": true + } + ], + "controllers": [ + { + "key": "AutoflowTabularController", + "implementation": AutoflowTabularController, + "depends": [ + "$scope", + "$timeout", + "telemetrySubscriber" + ] + } + ], + "directives": [ + { + "key": "mctAutoflowTable", + "implementation": MCTAutoflowTable + } + ] + } + }); + openmct.legacyRegistry.enable("platform/features/autoflow"); + }; }; }); diff --git a/src/plugins/plugins.js b/src/plugins/plugins.js index c1c5962923..70730a44dc 100644 --- a/src/plugins/plugins.js +++ b/src/plugins/plugins.js @@ -57,9 +57,16 @@ define([ }; }; - plugins.AutoflowView = function () { - return AutoflowPlugin; - }; + /** + * A tabular view showing the latest values of multiple telemetry points at + * once. Formatted so that labels and values are aligned. + * + * @param {Object} [options] Optional settings to apply to the autoflow + * tabular view. Currently supports one option, 'type'. + * @param {string} [options.type] The key of an object type to apply this view + * to exclusively. + */ + plugins.AutoflowView = AutoflowPlugin; var conductorInstalled = false; From 185567cf2947baa9e7e1153771c7b20fc3510e0d Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 5 Apr 2017 14:35:12 -0700 Subject: [PATCH 28/38] [Licenses] Update copyright year to 2017 Fixes #1517 --- LICENSES.md | 2 +- build-docs.sh | 2 +- docs/gendocs.js | 2 +- docs/src/tutorials/index.md | 6 +++--- example/builtins/README.md | 2 +- example/builtins/bundle.js | 2 +- example/builtins/res/templates/example.html | 4 ++-- example/builtins/src/ExampleController.js | 4 ++-- example/builtins/src/ExampleDirective.js | 4 ++-- example/builtins/src/ExampleService.js | 4 ++-- example/composite/bundle.js | 2 +- example/composite/src/SomeAggregator.js | 4 ++-- example/composite/src/SomeDecorator.js | 4 ++-- example/composite/src/SomeOtherDecorator.js | 4 ++-- example/composite/src/SomeOtherExample.js | 4 ++-- example/composite/src/SomeOtherProvider.js | 4 ++-- example/composite/src/SomeProvider.js | 4 ++-- example/eventGenerator/bundle.js | 2 +- example/eventGenerator/src/EventTelemetry.js | 4 ++-- example/eventGenerator/src/EventTelemetryProvider.js | 4 ++-- example/export/ExportTelemetryAsCSVAction.js | 2 +- example/export/bundle.js | 2 +- example/extensions/bundle.js | 2 +- example/extensions/src/SomeExample.js | 4 ++-- example/forms/bundle.js | 2 +- example/forms/res/templates/exampleForm.html | 4 ++-- example/forms/src/ExampleFormController.js | 4 ++-- example/generator/GeneratorProvider.js | 2 +- example/generator/SinewaveConstants.js | 2 +- example/generator/SinewaveDeltaFormat.js | 2 +- example/generator/SinewaveLimitCapability.js | 4 ++-- example/generator/SinewaveTelemetryProvider.js | 2 +- example/generator/SinewaveTelemetrySeries.js | 2 +- example/generator/WorkerInterface.js | 2 +- example/generator/generatorWorker.js | 2 +- example/generator/plugin.js | 2 +- example/identity/bundle.js | 2 +- example/identity/src/ExampleIdentityService.js | 2 +- example/imagery/bundle.js | 2 +- example/imagery/src/ImageTelemetry.js | 2 +- example/imagery/src/ImageTelemetryProvider.js | 2 +- example/mobile/bundle.js | 2 +- example/mobile/res/sass/mobile-example.scss | 2 +- example/msl/bundle.js | 2 +- example/msl/src/MSLDataDictionary.js | 2 +- example/msl/src/RemsTelemetryModelProvider.js | 2 +- example/msl/src/RemsTelemetryProvider.js | 2 +- example/msl/src/RemsTelemetrySeries.js | 2 +- example/msl/src/RemsTelemetryServerAdapter.js | 2 +- example/notifications/bundle.js | 2 +- example/notifications/res/dialog-launch.html | 2 +- example/notifications/res/notification-launch.html | 2 +- example/notifications/src/DialogLaunchController.js | 2 +- example/notifications/src/DialogLaunchIndicator.js | 2 +- example/notifications/src/NotificationLaunchController.js | 2 +- example/notifications/src/NotificationLaunchIndicator.js | 2 +- example/persistence/bundle.js | 2 +- example/persistence/src/BrowserPersistenceProvider.js | 4 ++-- example/plotOptions/bundle.js | 2 +- example/policy/bundle.js | 2 +- example/policy/src/ExamplePolicy.js | 4 ++-- example/profiling/bundle.js | 2 +- example/profiling/src/DigestIndicator.js | 2 +- example/profiling/src/WatchIndicator.js | 4 ++-- example/scratchpad/bundle.js | 2 +- example/scratchpad/src/ScratchPersistenceProvider.js | 2 +- example/taxonomy/bundle.js | 2 +- example/taxonomy/src/ExampleTaxonomyModelProvider.js | 4 ++-- example/worker/bundle.js | 2 +- example/worker/src/FibonacciIndicator.js | 2 +- gulpfile.js | 2 +- index.html | 2 +- karma.conf.js | 2 +- openmct.js | 2 +- platform/commonUI/README.md | 2 +- platform/commonUI/about/bundle.js | 2 +- platform/commonUI/about/res/templates/about-dialog.html | 2 +- platform/commonUI/about/res/templates/about-logo.html | 2 +- platform/commonUI/about/res/templates/app-logo.html | 4 ++-- platform/commonUI/about/res/templates/license-apache.html | 4 ++-- platform/commonUI/about/res/templates/license-mit.html | 4 ++-- .../commonUI/about/res/templates/licenses-export-md.html | 4 ++-- platform/commonUI/about/res/templates/licenses.html | 4 ++-- platform/commonUI/about/res/templates/overlay-about.html | 4 ++-- platform/commonUI/about/src/AboutController.js | 2 +- platform/commonUI/about/src/LicenseController.js | 2 +- platform/commonUI/about/src/LogoController.js | 2 +- platform/commonUI/about/test/AboutControllerSpec.js | 2 +- platform/commonUI/about/test/LicenseControllerSpec.js | 2 +- platform/commonUI/about/test/LogoControllerSpec.js | 2 +- platform/commonUI/browse/bundle.js | 2 +- platform/commonUI/browse/res/templates/back-arrow.html | 2 +- platform/commonUI/browse/res/templates/browse-object.html | 2 +- platform/commonUI/browse/res/templates/browse.html | 2 +- .../browse/res/templates/browse/inspector-region.html | 2 +- .../commonUI/browse/res/templates/browse/object-header.html | 4 ++-- .../browse/res/templates/browse/object-properties.html | 4 ++-- platform/commonUI/browse/res/templates/items/grid-item.html | 2 +- platform/commonUI/browse/res/templates/items/items.html | 4 ++-- platform/commonUI/browse/res/templates/menu-arrow.html | 4 ++-- platform/commonUI/browse/src/BrowseController.js | 2 +- platform/commonUI/browse/src/BrowseObjectController.js | 2 +- platform/commonUI/browse/src/InspectorRegion.js | 2 +- platform/commonUI/browse/src/MenuArrowController.js | 2 +- platform/commonUI/browse/src/PaneController.js | 2 +- platform/commonUI/browse/src/navigation/NavigateAction.js | 2 +- .../commonUI/browse/src/navigation/NavigationService.js | 2 +- .../browse/src/navigation/OrphanNavigationHandler.js | 2 +- platform/commonUI/browse/src/windowing/FullscreenAction.js | 2 +- platform/commonUI/browse/src/windowing/NewTabAction.js | 2 +- platform/commonUI/browse/src/windowing/WindowTitler.js | 2 +- platform/commonUI/browse/test/BrowseControllerSpec.js | 2 +- platform/commonUI/browse/test/BrowseObjectControllerSpec.js | 2 +- platform/commonUI/browse/test/InspectorRegionSpec.js | 2 +- platform/commonUI/browse/test/MenuArrowControllerSpec.js | 2 +- platform/commonUI/browse/test/PaneControllerSpec.js | 2 +- .../commonUI/browse/test/navigation/NavigateActionSpec.js | 2 +- .../browse/test/navigation/NavigationServiceSpec.js | 2 +- .../browse/test/navigation/OrphanNavigationHandlerSpec.js | 2 +- .../commonUI/browse/test/windowing/FullscreenActionSpec.js | 2 +- platform/commonUI/browse/test/windowing/NewTabActionSpec.js | 2 +- platform/commonUI/browse/test/windowing/WindowTitlerSpec.js | 2 +- platform/commonUI/dialog/README.md | 2 +- platform/commonUI/dialog/bundle.js | 2 +- platform/commonUI/dialog/res/templates/dialog.html | 4 ++-- platform/commonUI/dialog/res/templates/message.html | 2 +- .../dialog/res/templates/overlay-blocking-message.html | 4 ++-- platform/commonUI/dialog/res/templates/overlay-dialog.html | 4 ++-- .../commonUI/dialog/res/templates/overlay-message-list.html | 2 +- platform/commonUI/dialog/res/templates/overlay-options.html | 4 ++-- platform/commonUI/dialog/res/templates/overlay.html | 4 ++-- platform/commonUI/dialog/src/DialogService.js | 2 +- platform/commonUI/dialog/src/OverlayService.js | 2 +- platform/commonUI/dialog/test/DialogServiceSpec.js | 2 +- platform/commonUI/dialog/test/OverlayServiceSpec.js | 2 +- platform/commonUI/edit/bundle.js | 2 +- .../commonUI/edit/res/templates/create/create-button.html | 4 ++-- .../commonUI/edit/res/templates/create/create-menu.html | 2 +- platform/commonUI/edit/res/templates/create/locator.html | 2 +- .../commonUI/edit/res/templates/edit-action-buttons.html | 4 ++-- platform/commonUI/edit/res/templates/edit-object.html | 2 +- platform/commonUI/edit/res/templates/elements.html | 4 ++-- platform/commonUI/edit/res/templates/library.html | 4 ++-- platform/commonUI/edit/res/templates/topbar-edit.html | 4 ++-- platform/commonUI/edit/src/actions/CancelAction.js | 2 +- platform/commonUI/edit/src/actions/EditAction.js | 2 +- platform/commonUI/edit/src/actions/EditAndComposeAction.js | 2 +- platform/commonUI/edit/src/actions/PropertiesAction.js | 2 +- platform/commonUI/edit/src/actions/PropertiesDialog.js | 2 +- platform/commonUI/edit/src/actions/RemoveAction.js | 2 +- platform/commonUI/edit/src/actions/SaveAction.js | 2 +- .../commonUI/edit/src/actions/SaveAndStopEditingAction.js | 2 +- platform/commonUI/edit/src/actions/SaveAsAction.js | 2 +- platform/commonUI/edit/src/capabilities/EditorCapability.js | 2 +- .../edit/src/capabilities/TransactionCapabilityDecorator.js | 2 +- .../src/capabilities/TransactionalPersistenceCapability.js | 2 +- .../commonUI/edit/src/controllers/EditActionController.js | 2 +- .../commonUI/edit/src/controllers/EditObjectController.js | 2 +- .../commonUI/edit/src/controllers/EditPanesController.js | 2 +- .../commonUI/edit/src/controllers/ElementsController.js | 2 +- platform/commonUI/edit/src/creation/AddAction.js | 2 +- platform/commonUI/edit/src/creation/AddActionProvider.js | 2 +- platform/commonUI/edit/src/creation/CreateAction.js | 2 +- platform/commonUI/edit/src/creation/CreateActionProvider.js | 2 +- platform/commonUI/edit/src/creation/CreateMenuController.js | 2 +- platform/commonUI/edit/src/creation/CreateWizard.js | 2 +- platform/commonUI/edit/src/creation/CreationPolicy.js | 2 +- platform/commonUI/edit/src/creation/CreationService.js | 2 +- platform/commonUI/edit/src/creation/LocatorController.js | 2 +- platform/commonUI/edit/src/policies/EditActionPolicy.js | 2 +- .../edit/src/policies/EditContextualActionPolicy.js | 2 +- platform/commonUI/edit/src/policies/EditableLinkPolicy.js | 2 +- platform/commonUI/edit/src/policies/EditableMovePolicy.js | 2 +- platform/commonUI/edit/src/policies/EditableViewPolicy.js | 2 +- platform/commonUI/edit/src/representers/EditRepresenter.js | 2 +- platform/commonUI/edit/src/representers/EditToolbar.js | 2 +- .../edit/src/representers/EditToolbarRepresenter.js | 2 +- .../commonUI/edit/src/representers/EditToolbarSelection.js | 2 +- platform/commonUI/edit/src/services/NestedTransaction.js | 2 +- platform/commonUI/edit/src/services/Transaction.js | 2 +- platform/commonUI/edit/src/services/TransactionManager.js | 2 +- platform/commonUI/edit/src/services/TransactionService.js | 2 +- platform/commonUI/edit/test/actions/CancelActionSpec.js | 2 +- platform/commonUI/edit/test/actions/EditActionSpec.js | 2 +- .../commonUI/edit/test/actions/EditAndComposeActionSpec.js | 2 +- platform/commonUI/edit/test/actions/PropertiesActionSpec.js | 2 +- platform/commonUI/edit/test/actions/PropertiesDialogSpec.js | 2 +- platform/commonUI/edit/test/actions/RemoveActionSpec.js | 2 +- platform/commonUI/edit/test/actions/SaveActionSpec.js | 2 +- .../edit/test/actions/SaveAndStopEditingActionSpec.js | 2 +- platform/commonUI/edit/test/actions/SaveAsActionSpec.js | 2 +- .../commonUI/edit/test/capabilities/EditorCapabilitySpec.js | 2 +- .../test/capabilities/TransactionCapabilityDecoratorSpec.js | 2 +- .../capabilities/TransactionalPersistenceCapabilitySpec.js | 2 +- .../edit/test/controllers/EditActionControllerSpec.js | 2 +- .../edit/test/controllers/EditObjectControllerSpec.js | 2 +- .../edit/test/controllers/EditPanesControllerSpec.js | 2 +- .../edit/test/controllers/ElementsControllerSpec.js | 2 +- .../commonUI/edit/test/creation/AddActionProviderSpec.js | 2 +- .../commonUI/edit/test/creation/CreateActionProviderSpec.js | 2 +- platform/commonUI/edit/test/creation/CreateActionSpec.js | 2 +- .../commonUI/edit/test/creation/CreateMenuControllerSpec.js | 2 +- platform/commonUI/edit/test/creation/CreateWizardSpec.js | 2 +- platform/commonUI/edit/test/creation/CreationPolicySpec.js | 2 +- platform/commonUI/edit/test/creation/CreationServiceSpec.js | 2 +- .../commonUI/edit/test/creation/LocatorControllerSpec.js | 2 +- .../commonUI/edit/test/policies/EditActionPolicySpec.js | 2 +- .../edit/test/policies/EditContextualActionPolicySpec.js | 2 +- .../commonUI/edit/test/policies/EditableViewPolicySpec.js | 2 +- .../commonUI/edit/test/representers/EditRepresenterSpec.js | 2 +- .../edit/test/representers/EditToolbarRepresenterSpec.js | 2 +- .../edit/test/representers/EditToolbarSelectionSpec.js | 2 +- platform/commonUI/edit/test/representers/EditToolbarSpec.js | 2 +- .../commonUI/edit/test/services/NestedTransactionSpec.js | 2 +- .../commonUI/edit/test/services/TransactionManagerSpec.js | 2 +- .../commonUI/edit/test/services/TransactionServiceSpec.js | 2 +- platform/commonUI/edit/test/services/TransactionSpec.js | 2 +- platform/commonUI/formats/bundle.js | 2 +- platform/commonUI/formats/src/FormatProvider.js | 2 +- platform/commonUI/formats/src/UTCTimeFormat.js | 2 +- platform/commonUI/formats/test/FormatProviderSpec.js | 2 +- platform/commonUI/formats/test/UTCTimeFormatSpec.js | 2 +- platform/commonUI/general/README.md | 2 +- platform/commonUI/general/bundle.js | 2 +- .../fonts/symbols/icomoon-project-openmct-symbols-12px.json | 2 +- .../fonts/symbols/icomoon-project-openmct-symbols-16px.json | 2 +- .../general/res/fonts/symbols/openmct-symbols-12px.svg | 2 +- .../general/res/fonts/symbols/openmct-symbols-16px.svg | 2 +- platform/commonUI/general/res/sass/_about.scss | 2 +- platform/commonUI/general/res/sass/_animations.scss | 2 +- platform/commonUI/general/res/sass/_archetypes.scss | 2 +- platform/commonUI/general/res/sass/_autoflow.scss | 4 ++-- platform/commonUI/general/res/sass/_badges.scss | 2 +- platform/commonUI/general/res/sass/_constants.scss | 2 +- platform/commonUI/general/res/sass/_effects.scss | 4 ++-- platform/commonUI/general/res/sass/_fixed-position.scss | 4 ++-- platform/commonUI/general/res/sass/_global.scss | 2 +- platform/commonUI/general/res/sass/_icons.scss | 2 +- platform/commonUI/general/res/sass/_iframe.scss | 4 ++-- platform/commonUI/general/res/sass/_inspector.scss | 2 +- platform/commonUI/general/res/sass/_limits.scss | 2 +- platform/commonUI/general/res/sass/_logo-and-bg.scss | 4 ++-- platform/commonUI/general/res/sass/_main.scss | 2 +- platform/commonUI/general/res/sass/_mixins.scss | 2 +- platform/commonUI/general/res/sass/_object-label.scss | 4 ++-- platform/commonUI/general/res/sass/_text.scss | 4 ++-- platform/commonUI/general/res/sass/_views.scss | 2 +- .../commonUI/general/res/sass/controls/_breadcrumb.scss | 2 +- platform/commonUI/general/res/sass/controls/_buttons.scss | 2 +- .../commonUI/general/res/sass/controls/_color-palette.scss | 4 ++-- platform/commonUI/general/res/sass/controls/_controls.scss | 2 +- platform/commonUI/general/res/sass/controls/_lists.scss | 4 ++-- platform/commonUI/general/res/sass/controls/_menus.scss | 2 +- platform/commonUI/general/res/sass/controls/_messages.scss | 2 +- platform/commonUI/general/res/sass/controls/_ticks.scss | 4 ++-- platform/commonUI/general/res/sass/edit/_editor.scss | 2 +- platform/commonUI/general/res/sass/features/_imagery.scss | 2 +- .../commonUI/general/res/sass/forms/_channel-selector.scss | 4 ++-- platform/commonUI/general/res/sass/forms/_datetime.scss | 4 ++-- platform/commonUI/general/res/sass/forms/_elems.scss | 4 ++-- platform/commonUI/general/res/sass/forms/_filter.scss | 4 ++-- platform/commonUI/general/res/sass/forms/_validation.scss | 4 ++-- platform/commonUI/general/res/sass/helpers/_bubbles.scss | 4 ++-- platform/commonUI/general/res/sass/helpers/_splitter.scss | 2 +- .../commonUI/general/res/sass/helpers/_wait-spinner.scss | 2 +- platform/commonUI/general/res/sass/items/_item.scss | 4 ++-- platform/commonUI/general/res/sass/lists/_tabular.scss | 2 +- platform/commonUI/general/res/sass/mobile/_constants.scss | 2 +- platform/commonUI/general/res/sass/mobile/_item.scss | 2 +- platform/commonUI/general/res/sass/mobile/_layout.scss | 2 +- platform/commonUI/general/res/sass/mobile/_mixins.scss | 2 +- platform/commonUI/general/res/sass/mobile/_tree.scss | 2 +- .../commonUI/general/res/sass/mobile/controls/_menus.scss | 2 +- .../commonUI/general/res/sass/mobile/overlay/_overlay.scss | 2 +- .../commonUI/general/res/sass/mobile/search/_search.scss | 2 +- platform/commonUI/general/res/sass/openmct.scss | 4 ++-- platform/commonUI/general/res/sass/overlay/_overlay.scss | 2 +- platform/commonUI/general/res/sass/plots/_plots-main.scss | 2 +- platform/commonUI/general/res/sass/search/_search.scss | 4 ++-- platform/commonUI/general/res/sass/startup-base.scss | 4 ++-- platform/commonUI/general/res/sass/tree/_tree.scss | 2 +- platform/commonUI/general/res/sass/user-environ/_frame.scss | 4 ++-- .../commonUI/general/res/sass/user-environ/_layout.scss | 2 +- .../commonUI/general/res/sass/user-environ/_selecting.scss | 4 ++-- .../commonUI/general/res/sass/user-environ/_tool-bar.scss | 4 ++-- .../commonUI/general/res/sass/user-environ/_top-bar.scss | 4 ++-- platform/commonUI/general/res/templates/bottombar.html | 4 ++-- .../general/res/templates/containers/accordion.html | 2 +- .../general/res/templates/controls/action-button.html | 2 +- .../general/res/templates/controls/action-group.html | 4 ++-- .../commonUI/general/res/templates/controls/breadcrumb.html | 2 +- .../general/res/templates/controls/datetime-field.html | 2 +- .../general/res/templates/controls/datetime-picker.html | 2 +- .../general/res/templates/controls/input-filter.html | 4 ++-- .../commonUI/general/res/templates/controls/selector.html | 4 ++-- .../commonUI/general/res/templates/controls/switcher.html | 4 ++-- .../general/res/templates/controls/time-controller.html | 2 +- platform/commonUI/general/res/templates/indicator.html | 4 ++-- platform/commonUI/general/res/templates/label.html | 2 +- .../commonUI/general/res/templates/menu/context-menu.html | 4 ++-- platform/commonUI/general/res/templates/message-banner.html | 2 +- .../commonUI/general/res/templates/object-inspector.html | 2 +- platform/commonUI/general/res/templates/progress-bar.html | 2 +- platform/commonUI/general/res/templates/subtree.html | 2 +- platform/commonUI/general/res/templates/tree-node.html | 2 +- platform/commonUI/general/res/templates/tree.html | 2 +- platform/commonUI/general/res/templates/tree/wait-node.html | 2 +- platform/commonUI/general/src/SplashScreenManager.js | 2 +- platform/commonUI/general/src/StyleSheetLoader.js | 2 +- .../general/src/controllers/ActionGroupController.js | 2 +- .../commonUI/general/src/controllers/BannerController.js | 2 +- .../commonUI/general/src/controllers/BottomBarController.js | 2 +- .../commonUI/general/src/controllers/ClickAwayController.js | 2 +- .../general/src/controllers/ContextMenuController.js | 2 +- .../general/src/controllers/DateTimeFieldController.js | 2 +- .../general/src/controllers/DateTimePickerController.js | 2 +- .../general/src/controllers/GetterSetterController.js | 2 +- .../general/src/controllers/ObjectInspectorController.js | 2 +- .../commonUI/general/src/controllers/SelectorController.js | 2 +- .../commonUI/general/src/controllers/TimeRangeController.js | 2 +- .../commonUI/general/src/controllers/ToggleController.js | 2 +- .../commonUI/general/src/controllers/TreeNodeController.js | 2 +- .../general/src/controllers/ViewSwitcherController.js | 2 +- .../commonUI/general/src/directives/MCTClickElsewhere.js | 2 +- platform/commonUI/general/src/directives/MCTContainer.js | 2 +- platform/commonUI/general/src/directives/MCTDrag.js | 2 +- platform/commonUI/general/src/directives/MCTPopup.js | 2 +- platform/commonUI/general/src/directives/MCTResize.js | 2 +- platform/commonUI/general/src/directives/MCTScroll.js | 2 +- platform/commonUI/general/src/directives/MCTSplitPane.js | 2 +- platform/commonUI/general/src/directives/MCTSplitter.js | 2 +- platform/commonUI/general/src/directives/MCTTree.js | 2 +- platform/commonUI/general/src/filters/ReverseFilter.js | 2 +- platform/commonUI/general/src/services/Popup.js | 2 +- platform/commonUI/general/src/services/PopupService.js | 2 +- platform/commonUI/general/src/services/UrlService.js | 2 +- platform/commonUI/general/src/ui/ToggleView.js | 2 +- platform/commonUI/general/src/ui/TreeLabelView.js | 2 +- platform/commonUI/general/src/ui/TreeNodeView.js | 2 +- platform/commonUI/general/src/ui/TreeView.js | 2 +- platform/commonUI/general/test/SplashScreenManagerSpec.js | 2 +- platform/commonUI/general/test/StyleSheetLoaderSpec.js | 2 +- .../general/test/controllers/ActionGroupControllerSpec.js | 2 +- .../general/test/controllers/BottomBarControllerSpec.js | 2 +- .../general/test/controllers/ClickAwayControllerSpec.js | 2 +- .../general/test/controllers/ContextMenuControllerSpec.js | 2 +- .../general/test/controllers/DateTimeFieldControllerSpec.js | 2 +- .../test/controllers/DateTimePickerControllerSpec.js | 2 +- .../general/test/controllers/GetterSetterControllerSpec.js | 2 +- .../test/controllers/ObjectInspectorControllerSpec.js | 2 +- .../general/test/controllers/SelectorControllerSpec.js | 2 +- .../general/test/controllers/TimeRangeControllerSpec.js | 2 +- .../general/test/controllers/ToggleControllerSpec.js | 2 +- .../general/test/controllers/TreeNodeControllerSpec.js | 2 +- .../general/test/controllers/ViewSwitcherControllerSpec.js | 2 +- .../general/test/directives/MCTClickElsewhereSpec.js | 2 +- .../commonUI/general/test/directives/MCTContainerSpec.js | 2 +- platform/commonUI/general/test/directives/MCTDragSpec.js | 2 +- platform/commonUI/general/test/directives/MCTPopupSpec.js | 2 +- platform/commonUI/general/test/directives/MCTResizeSpec.js | 2 +- platform/commonUI/general/test/directives/MCTScrollSpec.js | 2 +- .../commonUI/general/test/directives/MCTSplitPaneSpec.js | 2 +- .../commonUI/general/test/directives/MCTSplitterSpec.js | 2 +- platform/commonUI/general/test/directives/MCTTreeSpec.js | 2 +- platform/commonUI/general/test/filters/ReverseFilterSpec.js | 2 +- platform/commonUI/general/test/services/PopupServiceSpec.js | 2 +- platform/commonUI/general/test/services/PopupSpec.js | 2 +- platform/commonUI/general/test/services/UrlServiceSpec.js | 2 +- platform/commonUI/general/test/ui/TreeViewSpec.js | 2 +- platform/commonUI/inspect/bundle.js | 2 +- platform/commonUI/inspect/res/infobubble.html | 4 ++-- platform/commonUI/inspect/res/templates/info-button.html | 2 +- platform/commonUI/inspect/src/InfoConstants.js | 2 +- platform/commonUI/inspect/src/gestures/InfoButtonGesture.js | 2 +- platform/commonUI/inspect/src/gestures/InfoGesture.js | 2 +- platform/commonUI/inspect/src/services/InfoService.js | 2 +- .../commonUI/inspect/test/gestures/InfoButtonGestureSpec.js | 2 +- platform/commonUI/inspect/test/gestures/InfoGestureSpec.js | 2 +- platform/commonUI/inspect/test/services/InfoServiceSpec.js | 2 +- platform/commonUI/mobile/bundle.js | 2 +- platform/commonUI/mobile/src/AgentService.js | 2 +- platform/commonUI/mobile/src/DeviceClassifier.js | 2 +- platform/commonUI/mobile/src/DeviceMatchers.js | 2 +- platform/commonUI/mobile/src/MCTDevice.js | 2 +- platform/commonUI/mobile/test/AgentServiceSpec.js | 2 +- platform/commonUI/mobile/test/DeviceClassifierSpec.js | 2 +- platform/commonUI/mobile/test/DeviceMatchersSpec.js | 2 +- platform/commonUI/mobile/test/MCTDeviceSpec.js | 2 +- platform/commonUI/notification/bundle.js | 2 +- platform/commonUI/notification/src/NotificationIndicator.js | 2 +- .../notification/src/NotificationIndicatorController.js | 2 +- platform/commonUI/notification/src/NotificationService.js | 2 +- .../test/NotificationIndicatorControllerSpec.js | 2 +- .../commonUI/notification/test/NotificationServiceSpec.js | 2 +- platform/commonUI/regions/bundle.js | 2 +- platform/commonUI/regions/src/EditableRegionPolicy.js | 2 +- platform/commonUI/regions/src/InspectorController.js | 2 +- platform/commonUI/regions/src/Region.js | 2 +- platform/commonUI/regions/test/EditableRegionPolicySpec.js | 2 +- platform/commonUI/regions/test/InspectorControllerSpec.js | 2 +- platform/commonUI/regions/test/RegionSpec.js | 2 +- platform/commonUI/themes/espresso/bundle.js | 2 +- platform/commonUI/themes/espresso/res/sass/_constants.scss | 2 +- platform/commonUI/themes/espresso/res/sass/_mixins.scss | 2 +- .../commonUI/themes/espresso/res/sass/theme-espresso.scss | 2 +- platform/commonUI/themes/snow/bundle.js | 2 +- platform/commonUI/themes/snow/res/sass/_constants.scss | 2 +- platform/commonUI/themes/snow/res/sass/_controls.scss | 2 +- platform/commonUI/themes/snow/res/sass/_mixins.scss | 2 +- platform/commonUI/themes/snow/res/sass/theme-snow.scss | 2 +- platform/containment/README.md | 2 +- platform/containment/bundle.js | 2 +- platform/containment/src/ComposeActionPolicy.js | 2 +- platform/containment/src/CompositionMutabilityPolicy.js | 2 +- platform/containment/src/CompositionPolicy.js | 2 +- platform/containment/test/ComposeActionPolicySpec.js | 2 +- .../containment/test/CompositionMutabilityPolicySpec.js | 2 +- platform/containment/test/CompositionPolicySpec.js | 2 +- platform/core/bundle.js | 2 +- platform/core/src/actions/ActionAggregator.js | 2 +- platform/core/src/actions/ActionCapability.js | 2 +- platform/core/src/actions/ActionProvider.js | 2 +- platform/core/src/actions/LoggingActionDecorator.js | 2 +- platform/core/src/capabilities/CompositionCapability.js | 2 +- platform/core/src/capabilities/ContextCapability.js | 2 +- platform/core/src/capabilities/ContextualDomainObject.js | 2 +- platform/core/src/capabilities/CoreCapabilityProvider.js | 2 +- platform/core/src/capabilities/DelegationCapability.js | 2 +- platform/core/src/capabilities/InstantiationCapability.js | 2 +- platform/core/src/capabilities/MutationCapability.js | 2 +- platform/core/src/capabilities/PersistenceCapability.js | 2 +- platform/core/src/capabilities/RelationshipCapability.js | 2 +- platform/core/src/identifiers/Identifier.js | 2 +- platform/core/src/identifiers/IdentifierProvider.js | 2 +- platform/core/src/models/CachingModelDecorator.js | 2 +- platform/core/src/models/MissingModelDecorator.js | 2 +- platform/core/src/models/ModelAggregator.js | 2 +- platform/core/src/models/ModelCacheService.js | 2 +- platform/core/src/models/PersistedModelProvider.js | 2 +- platform/core/src/models/StaticModelProvider.js | 2 +- platform/core/src/objects/DomainObjectImpl.js | 2 +- platform/core/src/objects/DomainObjectProvider.js | 2 +- platform/core/src/services/Instantiate.js | 2 +- platform/core/src/services/Now.js | 2 +- platform/core/src/services/Throttle.js | 2 +- platform/core/src/services/Topic.js | 2 +- platform/core/src/types/MergeModels.js | 2 +- platform/core/src/types/TypeCapability.js | 2 +- platform/core/src/types/TypeImpl.js | 2 +- platform/core/src/types/TypeProperty.js | 2 +- platform/core/src/types/TypePropertyConversion.js | 2 +- platform/core/src/types/TypeProvider.js | 2 +- platform/core/src/views/ViewCapability.js | 2 +- platform/core/src/views/ViewProvider.js | 2 +- platform/core/test/actions/ActionAggregatorSpec.js | 2 +- platform/core/test/actions/ActionCapabilitySpec.js | 2 +- platform/core/test/actions/ActionProviderSpec.js | 2 +- platform/core/test/actions/LoggingActionDecoratorSpec.js | 2 +- .../core/test/capabilities/CompositionCapabilitySpec.js | 2 +- platform/core/test/capabilities/ContextCapabilitySpec.js | 2 +- .../core/test/capabilities/ContextualDomainObjectSpec.js | 2 +- .../core/test/capabilities/CoreCapabilityProviderSpec.js | 2 +- platform/core/test/capabilities/DelegationCapabilitySpec.js | 2 +- .../core/test/capabilities/InstantiationCapabilitySpec.js | 2 +- platform/core/test/capabilities/MetadataCapabilitySpec.js | 2 +- platform/core/test/capabilities/MutationCapabilitySpec.js | 2 +- .../core/test/capabilities/PersistenceCapabilitySpec.js | 2 +- .../core/test/capabilities/RelationshipCapabilitySpec.js | 2 +- platform/core/test/identifiers/IdentifierProviderSpec.js | 2 +- platform/core/test/identifiers/IdentifierSpec.js | 2 +- platform/core/test/models/CachingModelDecoratorSpec.js | 2 +- platform/core/test/models/MissingModelDecoratorSpec.js | 2 +- platform/core/test/models/ModelAggregatorSpec.js | 2 +- platform/core/test/models/ModelCacheServiceSpec.js | 2 +- platform/core/test/models/PersistedModelProviderSpec.js | 2 +- platform/core/test/models/StaticModelProviderSpec.js | 2 +- platform/core/test/objects/DomainObjectProviderSpec.js | 2 +- platform/core/test/objects/DomainObjectSpec.js | 2 +- platform/core/test/runs/TransactingMutationListenerSpec.js | 2 +- platform/core/test/services/InstantiateSpec.js | 2 +- platform/core/test/services/NowSpec.js | 2 +- platform/core/test/services/ThrottleSpec.js | 2 +- platform/core/test/services/TopicSpec.js | 2 +- platform/core/test/types/MergeModelsSpec.js | 2 +- platform/core/test/types/TypeCapabilitySpec.js | 2 +- platform/core/test/types/TypeImplSpec.js | 2 +- platform/core/test/types/TypePropertyConversionSpec.js | 2 +- platform/core/test/types/TypePropertySpec.js | 2 +- platform/core/test/types/TypeProviderSpec.js | 2 +- platform/core/test/views/ViewCapabilitySpec.js | 2 +- platform/core/test/views/ViewProviderSpec.js | 2 +- platform/entanglement/bundle.js | 2 +- platform/entanglement/src/actions/AbstractComposeAction.js | 2 +- platform/entanglement/src/actions/CopyAction.js | 2 +- platform/entanglement/src/actions/GoToOriginalAction.js | 2 +- platform/entanglement/src/actions/LinkAction.js | 2 +- platform/entanglement/src/actions/MoveAction.js | 2 +- .../entanglement/src/actions/SetPrimaryLocationAction.js | 2 +- .../entanglement/src/capabilities/LocationCapability.js | 2 +- platform/entanglement/src/policies/CopyPolicy.js | 2 +- platform/entanglement/src/policies/CrossSpacePolicy.js | 2 +- platform/entanglement/src/policies/MovePolicy.js | 2 +- platform/entanglement/src/services/CopyService.js | 2 +- platform/entanglement/src/services/CopyTask.js | 2 +- platform/entanglement/src/services/LinkService.js | 2 +- .../entanglement/src/services/LocatingCreationDecorator.js | 2 +- .../entanglement/src/services/LocatingObjectDecorator.js | 2 +- platform/entanglement/src/services/LocationService.js | 2 +- platform/entanglement/src/services/MoveService.js | 2 +- platform/entanglement/test/ControlledPromise.js | 2 +- platform/entanglement/test/DomainObjectFactory.js | 2 +- .../entanglement/test/actions/AbstractComposeActionSpec.js | 2 +- platform/entanglement/test/actions/CopyActionSpec.js | 2 +- .../entanglement/test/actions/GoToOriginalActionSpec.js | 2 +- platform/entanglement/test/actions/LinkActionSpec.js | 2 +- platform/entanglement/test/actions/MoveActionSpec.js | 2 +- .../test/actions/SetPrimaryLocationActionSpec.js | 2 +- .../test/capabilities/LocationCapabilitySpec.js | 2 +- platform/entanglement/test/policies/CopyPolicySpec.js | 2 +- platform/entanglement/test/policies/CrossSpacePolicySpec.js | 2 +- platform/entanglement/test/policies/MovePolicySpec.js | 2 +- platform/entanglement/test/services/CopyServiceSpec.js | 2 +- platform/entanglement/test/services/CopyTaskSpec.js | 2 +- platform/entanglement/test/services/LinkServiceSpec.js | 2 +- .../test/services/LocatingCreationDecoratorSpec.js | 2 +- .../test/services/LocatingObjectDecoratorSpec.js | 2 +- platform/entanglement/test/services/LocationServiceSpec.js | 2 +- platform/entanglement/test/services/MockCopyService.js | 2 +- platform/entanglement/test/services/MockLinkService.js | 2 +- platform/entanglement/test/services/MockMoveService.js | 2 +- platform/entanglement/test/services/MoveServiceSpec.js | 2 +- platform/execution/bundle.js | 2 +- platform/execution/src/WorkerService.js | 2 +- platform/execution/test/WorkerServiceSpec.js | 2 +- platform/exporters/ExportService.js | 2 +- platform/exporters/ExportServiceSpec.js | 2 +- platform/exporters/bundle.js | 2 +- platform/features/clock/bundle.js | 2 +- platform/features/clock/res/templates/clock.html | 2 +- platform/features/clock/res/templates/timer.html | 2 +- platform/features/conductor/core/res/sass/_constants.scss | 2 +- .../features/conductor/core/res/sass/_time-of-interest.scss | 2 +- .../conductor/core/res/sass/time-conductor-espresso.scss | 2 +- .../conductor/core/res/sass/time-conductor-snow.scss | 2 +- .../core/res/templates/mode-selector/mode-selector.html | 2 +- .../conductor/core/res/templates/time-of-interest.html | 2 +- platform/features/conductor/core/src/ui/NumberFormat.js | 2 +- platform/features/fixed/bundle.js | 2 +- platform/features/imagery/bundle.js | 2 +- .../features/imagery/src/controllers/ImageryController.js | 2 +- .../features/imagery/src/directives/MCTBackgroundImage.js | 2 +- platform/features/imagery/src/policies/ImageryViewPolicy.js | 2 +- .../imagery/test/controllers/ImageryControllerSpec.js | 2 +- .../imagery/test/directives/MCTBackgroundImageSpec.js | 2 +- .../features/imagery/test/policies/ImageryViewPolicySpec.js | 2 +- platform/features/layout/bundle.js | 2 +- platform/features/layout/res/templates/elements/box.html | 4 ++-- platform/features/layout/res/templates/elements/image.html | 2 +- platform/features/layout/res/templates/elements/line.html | 4 ++-- .../features/layout/res/templates/elements/telemetry.html | 2 +- platform/features/layout/res/templates/elements/text.html | 4 ++-- platform/features/layout/res/templates/fixed.html | 2 +- platform/features/layout/res/templates/frame.html | 4 ++-- platform/features/layout/res/templates/layout.html | 4 ++-- platform/features/layout/src/FixedController.js | 2 +- platform/features/layout/src/FixedDragHandle.js | 2 +- platform/features/layout/src/FixedProxy.js | 2 +- platform/features/layout/src/LayoutCompositionPolicy.js | 2 +- platform/features/layout/src/LayoutController.js | 2 +- platform/features/layout/src/LayoutDrag.js | 2 +- platform/features/layout/src/elements/AccessorMutator.js | 2 +- platform/features/layout/src/elements/BoxProxy.js | 2 +- platform/features/layout/src/elements/ElementFactory.js | 2 +- platform/features/layout/src/elements/ElementProxies.js | 2 +- platform/features/layout/src/elements/ElementProxy.js | 2 +- platform/features/layout/src/elements/ImageProxy.js | 2 +- platform/features/layout/src/elements/LineHandle.js | 2 +- platform/features/layout/src/elements/LineProxy.js | 2 +- platform/features/layout/src/elements/ResizeHandle.js | 2 +- platform/features/layout/src/elements/TelemetryProxy.js | 2 +- platform/features/layout/src/elements/TextProxy.js | 2 +- platform/features/layout/test/FixedControllerSpec.js | 2 +- platform/features/layout/test/FixedDragHandleSpec.js | 2 +- platform/features/layout/test/FixedProxySpec.js | 2 +- .../features/layout/test/LayoutCompositionPolicySpec.js | 2 +- platform/features/layout/test/LayoutControllerSpec.js | 2 +- platform/features/layout/test/LayoutDragSpec.js | 2 +- .../features/layout/test/elements/AccessorMutatorSpec.js | 2 +- platform/features/layout/test/elements/BoxProxySpec.js | 2 +- .../features/layout/test/elements/ElementFactorySpec.js | 2 +- .../features/layout/test/elements/ElementProxiesSpec.js | 2 +- platform/features/layout/test/elements/ElementProxySpec.js | 2 +- platform/features/layout/test/elements/ImageProxySpec.js | 2 +- platform/features/layout/test/elements/LineHandleSpec.js | 2 +- platform/features/layout/test/elements/LineProxySpec.js | 2 +- platform/features/layout/test/elements/ResizeHandleSpec.js | 2 +- .../features/layout/test/elements/TelemetryProxySpec.js | 2 +- platform/features/layout/test/elements/TextProxySpec.js | 2 +- platform/features/my-items/bundle.js | 2 +- platform/features/pages/bundle.js | 2 +- platform/features/pages/res/iframe.html | 4 ++-- platform/features/pages/src/EmbeddedPageController.js | 2 +- platform/features/pages/test/EmbeddedPageControllerSpec.js | 2 +- platform/features/plot/bundle.js | 2 +- .../features/plot/res/templates/plot-options-browse.html | 4 ++-- platform/features/plot/res/templates/plot.html | 2 +- platform/features/plot/src/Canvas2DChart.js | 2 +- platform/features/plot/src/GLChart.js | 2 +- platform/features/plot/src/MCTChart.js | 2 +- platform/features/plot/src/PlotController.js | 2 +- platform/features/plot/src/PlotOptionsController.js | 2 +- platform/features/plot/src/PlotOptionsForm.js | 2 +- platform/features/plot/src/SubPlot.js | 2 +- platform/features/plot/src/SubPlotFactory.js | 2 +- platform/features/plot/src/elements/PlotAxis.js | 2 +- platform/features/plot/src/elements/PlotLimitTracker.js | 2 +- platform/features/plot/src/elements/PlotLine.js | 2 +- platform/features/plot/src/elements/PlotLineBuffer.js | 2 +- platform/features/plot/src/elements/PlotPalette.js | 2 +- platform/features/plot/src/elements/PlotPanZoomStack.js | 2 +- .../features/plot/src/elements/PlotPanZoomStackGroup.js | 2 +- platform/features/plot/src/elements/PlotPosition.js | 2 +- platform/features/plot/src/elements/PlotPreparer.js | 2 +- platform/features/plot/src/elements/PlotSeriesWindow.js | 2 +- .../features/plot/src/elements/PlotTelemetryFormatter.js | 2 +- platform/features/plot/src/elements/PlotTickGenerator.js | 2 +- platform/features/plot/src/elements/PlotUpdater.js | 2 +- platform/features/plot/src/modes/PlotModeOptions.js | 2 +- platform/features/plot/src/modes/PlotOverlayMode.js | 2 +- platform/features/plot/src/modes/PlotStackMode.js | 2 +- platform/features/plot/src/policies/PlotViewPolicy.js | 2 +- platform/features/plot/src/services/ExportImageService.js | 2 +- platform/features/plot/test/Canvas2DChartSpec.js | 2 +- platform/features/plot/test/GLChartSpec.js | 2 +- platform/features/plot/test/MCTChartSpec.js | 2 +- platform/features/plot/test/PlotControllerSpec.js | 2 +- platform/features/plot/test/PlotOptionsControllerSpec.js | 2 +- platform/features/plot/test/PlotOptionsFormSpec.js | 2 +- platform/features/plot/test/SubPlotFactorySpec.js | 2 +- platform/features/plot/test/SubPlotSpec.js | 2 +- platform/features/plot/test/elements/PlotAxisSpec.js | 2 +- .../features/plot/test/elements/PlotLimitTrackerSpec.js | 2 +- platform/features/plot/test/elements/PlotLineBufferSpec.js | 2 +- platform/features/plot/test/elements/PlotLineSpec.js | 2 +- platform/features/plot/test/elements/PlotPaletteSpec.js | 2 +- .../plot/test/elements/PlotPanZoomStackGroupSpec.js | 2 +- .../features/plot/test/elements/PlotPanZoomStackSpec.js | 2 +- platform/features/plot/test/elements/PlotPositionSpec.js | 2 +- platform/features/plot/test/elements/PlotPreparerSpec.js | 2 +- .../features/plot/test/elements/PlotSeriesWindowSpec.js | 2 +- .../plot/test/elements/PlotTelemetryFormatterSpec.js | 2 +- .../features/plot/test/elements/PlotTickGeneratorSpec.js | 2 +- platform/features/plot/test/elements/PlotUpdaterSpec.js | 2 +- platform/features/plot/test/modes/PlotModeOptionsSpec.js | 2 +- platform/features/plot/test/modes/PlotOverlayModeSpec.js | 2 +- platform/features/plot/test/modes/PlotStackModeSpec.js | 2 +- platform/features/plot/test/policies/PlotViewPolicySpec.js | 2 +- .../features/plot/test/services/ExportImageServiceSpec.js | 2 +- platform/features/static-markup/bundle.js | 2 +- platform/features/static-markup/res/markup.html | 2 +- platform/features/table/bundle.js | 2 +- platform/features/table/res/sass/table.scss | 2 +- .../features/table/res/templates/table-options-edit.html | 4 ++-- platform/features/table/res/templates/telemetry-table.html | 2 +- platform/features/table/src/TableConfiguration.js | 2 +- platform/features/table/src/TelemetryCollection.js | 2 +- .../table/src/controllers/TableOptionsController.js | 2 +- .../table/src/controllers/TelemetryTableController.js | 2 +- platform/features/table/src/directives/MCTTable.js | 2 +- platform/features/table/test/TableConfigurationSpec.js | 2 +- platform/features/table/test/TelemetryCollectionSpec.js | 2 +- .../table/test/controllers/MCTTableControllerSpec.js | 2 +- .../table/test/controllers/TableOptionsControllerSpec.js | 2 +- .../table/test/controllers/TelemetryTableControllerSpec.js | 2 +- platform/features/timeline/bundle.js | 2 +- platform/features/timeline/res/sass/_activities.scss | 2 +- .../features/timeline/res/sass/_constants-espresso.scss | 4 ++-- platform/features/timeline/res/sass/_constants-snow.scss | 4 ++-- platform/features/timeline/res/sass/_constants.scss | 2 +- platform/features/timeline/res/sass/_timeline-thematic.scss | 2 +- platform/features/timeline/res/sass/_timelines.scss | 2 +- platform/features/timeline/res/sass/timeline-espresso.scss | 2 +- platform/features/timeline/res/sass/timeline-snow.scss | 2 +- platform/features/timeline/res/sass/timeline.scss | 2 +- platform/features/timeline/res/templates/legend-item.html | 2 +- .../timeline/res/templates/resource-graph-labels.html | 2 +- .../timeline/res/templates/tabular-swimlane-cols-data.html | 2 +- platform/features/timeline/res/templates/values.html | 2 +- platform/features/timeline/src/chart/Canvas2DChart.js | 2 +- platform/features/timeline/src/chart/GLChart.js | 2 +- platform/features/timeline/src/chart/MCTTimelineChart.js | 2 +- platform/features/timeline/test/chart/Canvas2DChartSpec.js | 2 +- platform/features/timeline/test/chart/GLChartSpec.js | 2 +- .../features/timeline/test/chart/MCTTimelineChartSpec.js | 2 +- platform/forms/README.md | 2 +- platform/forms/bundle.js | 2 +- platform/forms/res/templates/controls/button.html | 2 +- platform/forms/res/templates/controls/checkbox.html | 2 +- platform/forms/res/templates/controls/color.html | 2 +- platform/forms/res/templates/controls/composite.html | 2 +- platform/forms/res/templates/controls/datetime.html | 2 +- platform/forms/res/templates/controls/dialog.html | 4 ++-- platform/forms/res/templates/controls/menu-button.html | 4 ++-- platform/forms/res/templates/controls/radio.html | 2 +- platform/forms/res/templates/controls/select.html | 2 +- platform/forms/res/templates/controls/textarea.html | 2 +- platform/forms/res/templates/controls/textfield.html | 2 +- platform/forms/res/templates/form.html | 4 ++-- platform/forms/res/templates/toolbar.html | 4 ++-- platform/forms/src/MCTControl.js | 2 +- platform/forms/src/MCTForm.js | 2 +- platform/forms/src/MCTToolbar.js | 2 +- platform/forms/src/controllers/ColorController.js | 2 +- platform/forms/src/controllers/CompositeController.js | 2 +- platform/forms/src/controllers/DateTimeController.js | 2 +- platform/forms/src/controllers/DialogButtonController.js | 2 +- platform/forms/src/controllers/FormController.js | 2 +- platform/forms/test/MCTControlSpec.js | 2 +- platform/forms/test/MCTFormSpec.js | 2 +- platform/forms/test/MCTToolbarSpec.js | 2 +- platform/forms/test/controllers/ColorControllerSpec.js | 2 +- platform/forms/test/controllers/CompositeControllerSpec.js | 2 +- platform/forms/test/controllers/DateTimeControllerSpec.js | 2 +- .../forms/test/controllers/DialogButtonControllerSpec.js | 2 +- platform/forms/test/controllers/FormControllerSpec.js | 2 +- platform/framework/README.md | 2 +- platform/framework/bundle.js | 2 +- platform/framework/src/Constants.js | 2 +- platform/framework/src/FrameworkInitializer.js | 2 +- platform/framework/src/FrameworkLayer.js | 2 +- platform/framework/src/LogLevel.js | 2 +- platform/framework/src/Main.js | 2 +- platform/framework/src/bootstrap/ApplicationBootstrapper.js | 2 +- platform/framework/src/load/Bundle.js | 2 +- platform/framework/src/load/BundleLoader.js | 2 +- platform/framework/src/load/Extension.js | 2 +- platform/framework/src/register/CustomRegistrars.js | 2 +- platform/framework/src/register/ExtensionRegistrar.js | 2 +- platform/framework/src/register/ExtensionSorter.js | 2 +- platform/framework/src/register/PartialConstructor.js | 2 +- platform/framework/src/register/ServiceCompositor.js | 2 +- platform/framework/src/resolve/BundleResolver.js | 2 +- platform/framework/src/resolve/ExtensionResolver.js | 2 +- platform/framework/src/resolve/ImplementationLoader.js | 2 +- platform/framework/src/resolve/RequireConfigurator.js | 2 +- platform/framework/test/FrameworkInitializerSpec.js | 2 +- platform/framework/test/LogLevelSpec.js | 2 +- .../framework/test/bootstrap/ApplicationBootstrapperSpec.js | 2 +- platform/framework/test/load/BundleLoaderSpec.js | 2 +- platform/framework/test/load/BundleSpec.js | 2 +- platform/framework/test/load/ExtensionSpec.js | 2 +- platform/framework/test/register/CustomRegistrarsSpec.js | 2 +- platform/framework/test/register/ExtensionRegistrarSpec.js | 2 +- platform/framework/test/register/ExtensionSorterSpec.js | 2 +- platform/framework/test/register/PartialConstructorSpec.js | 2 +- platform/framework/test/register/ServiceCompositorSpec.js | 2 +- platform/framework/test/resolve/BundleResolverSpec.js | 2 +- platform/framework/test/resolve/ExtensionResolverSpec.js | 2 +- platform/framework/test/resolve/ImplementationLoaderSpec.js | 2 +- platform/framework/test/resolve/RequireConfiguratorSpec.js | 2 +- platform/identity/bundle.js | 2 +- platform/identity/src/IdentityAggregator.js | 2 +- platform/identity/src/IdentityCreationDecorator.js | 2 +- platform/identity/src/IdentityIndicator.js | 2 +- platform/identity/src/IdentityProvider.js | 2 +- platform/identity/test/IdentityAggregatorSpec.js | 2 +- platform/identity/test/IdentityCreationDecoratorSpec.js | 2 +- platform/identity/test/IdentityIndicatorSpec.js | 2 +- platform/identity/test/IdentityProviderSpec.js | 2 +- platform/persistence/aggregator/bundle.js | 2 +- .../persistence/aggregator/src/PersistenceAggregator.js | 2 +- .../aggregator/test/PersistenceAggregatorSpec.js | 2 +- platform/persistence/couch/bundle.js | 2 +- platform/persistence/couch/src/CouchDocument.js | 2 +- platform/persistence/couch/src/CouchIndicator.js | 2 +- platform/persistence/couch/src/CouchPersistenceProvider.js | 2 +- platform/persistence/couch/test/CouchDocumentSpec.js | 2 +- platform/persistence/couch/test/CouchIndicatorSpec.js | 2 +- .../persistence/couch/test/CouchPersistenceProviderSpec.js | 2 +- platform/persistence/elastic/bundle.js | 2 +- platform/persistence/elastic/src/ElasticIndicator.js | 2 +- .../persistence/elastic/src/ElasticPersistenceProvider.js | 2 +- platform/persistence/elastic/src/ElasticSearchProvider.js | 2 +- platform/persistence/elastic/test/ElasticIndicatorSpec.js | 2 +- .../elastic/test/ElasticPersistenceProviderSpec.js | 2 +- .../persistence/elastic/test/ElasticSearchProviderSpec.js | 2 +- platform/persistence/local/bundle.js | 2 +- platform/persistence/local/src/LocalStorageIndicator.js | 2 +- .../local/src/LocalStoragePersistenceProvider.js | 2 +- .../persistence/local/test/LocalStorageIndicatorSpec.js | 2 +- .../local/test/LocalStoragePersistenceProviderSpec.js | 2 +- platform/persistence/queue/README.md | 2 +- platform/persistence/queue/bundle.js | 2 +- .../queue/res/templates/persistence-failure-dialog.html | 4 ++-- .../persistence/queue/src/PersistenceFailureConstants.js | 2 +- .../persistence/queue/src/PersistenceFailureController.js | 2 +- platform/persistence/queue/src/PersistenceFailureDialog.js | 2 +- platform/persistence/queue/src/PersistenceFailureHandler.js | 2 +- platform/persistence/queue/src/PersistenceQueue.js | 2 +- platform/persistence/queue/src/PersistenceQueueHandler.js | 2 +- platform/persistence/queue/src/PersistenceQueueImpl.js | 2 +- .../persistence/queue/src/QueuingPersistenceCapability.js | 2 +- .../queue/src/QueuingPersistenceCapabilityDecorator.js | 2 +- .../queue/test/PersistenceFailureConstantsSpec.js | 2 +- .../queue/test/PersistenceFailureControllerSpec.js | 2 +- .../persistence/queue/test/PersistenceFailureDialogSpec.js | 2 +- .../persistence/queue/test/PersistenceFailureHandlerSpec.js | 2 +- .../persistence/queue/test/PersistenceQueueHandlerSpec.js | 2 +- platform/persistence/queue/test/PersistenceQueueImplSpec.js | 2 +- platform/persistence/queue/test/PersistenceQueueSpec.js | 2 +- .../queue/test/QueuingPersistenceCapabilityDecoratorSpec.js | 2 +- .../queue/test/QueuingPersistenceCapabilitySpec.js | 2 +- platform/policy/README.md | 2 +- platform/policy/bundle.js | 2 +- platform/policy/src/PolicyActionDecorator.js | 2 +- platform/policy/src/PolicyProvider.js | 2 +- platform/policy/src/PolicyViewDecorator.js | 2 +- platform/policy/test/PolicyActionDecoratorSpec.js | 2 +- platform/policy/test/PolicyProviderSpec.js | 2 +- platform/policy/test/PolicyViewDecoratorSpec.js | 2 +- platform/representation/README.md | 2 +- platform/representation/bundle.js | 2 +- platform/representation/src/MCTInclude.js | 2 +- platform/representation/src/MCTRepresentation.js | 2 +- platform/representation/src/TemplateLinker.js | 2 +- platform/representation/src/TemplatePrefetcher.js | 2 +- platform/representation/src/actions/ContextMenuAction.js | 2 +- platform/representation/src/gestures/ContextMenuGesture.js | 2 +- platform/representation/src/gestures/DragGesture.js | 2 +- platform/representation/src/gestures/DropGesture.js | 2 +- platform/representation/src/gestures/GestureConstants.js | 2 +- platform/representation/src/gestures/GestureProvider.js | 2 +- platform/representation/src/gestures/GestureRepresenter.js | 2 +- platform/representation/src/services/DndService.js | 2 +- platform/representation/test/MCTIncludeSpec.js | 2 +- platform/representation/test/MCTRepresentationSpec.js | 2 +- platform/representation/test/TemplateLinkerSpec.js | 2 +- platform/representation/test/TemplatePrefetcherSpec.js | 2 +- .../representation/test/actions/ContextMenuActionSpec.js | 2 +- .../representation/test/gestures/ContextMenuGestureSpec.js | 2 +- platform/representation/test/gestures/DragGestureSpec.js | 2 +- platform/representation/test/gestures/DropGestureSpec.js | 2 +- .../representation/test/gestures/GestureProviderSpec.js | 2 +- .../representation/test/gestures/GestureRepresenterSpec.js | 2 +- platform/representation/test/services/DndServiceSpec.js | 2 +- platform/search/bundle.js | 2 +- platform/search/res/templates/search-item.html | 2 +- platform/search/res/templates/search-menu.html | 4 ++-- platform/search/res/templates/search.html | 4 ++-- platform/search/src/controllers/SearchController.js | 2 +- platform/search/src/controllers/SearchMenuController.js | 2 +- platform/search/src/services/GenericSearchProvider.js | 2 +- platform/search/src/services/GenericSearchWorker.js | 2 +- platform/search/src/services/SearchAggregator.js | 2 +- platform/search/test/controllers/SearchControllerSpec.js | 2 +- .../search/test/controllers/SearchMenuControllerSpec.js | 2 +- platform/search/test/services/GenericSearchProviderSpec.js | 2 +- platform/search/test/services/GenericSearchWorkerSpec.js | 2 +- platform/search/test/services/SearchAggregatorSpec.js | 2 +- platform/status/bundle.js | 2 +- platform/status/src/StatusCapability.js | 2 +- platform/status/src/StatusConstants.js | 2 +- platform/status/src/StatusRepresenter.js | 2 +- platform/status/src/StatusService.js | 2 +- platform/status/test/StatusCapabilitySpec.js | 2 +- platform/status/test/StatusRepresenterSpec.js | 2 +- platform/status/test/StatusServiceSpec.js | 2 +- platform/telemetry/bundle.js | 2 +- platform/telemetry/src/TelemetryAggregator.js | 2 +- platform/telemetry/src/TelemetryCapability.js | 2 +- platform/telemetry/src/TelemetryController.js | 2 +- platform/telemetry/src/TelemetryDelegator.js | 2 +- platform/telemetry/src/TelemetryFormatter.js | 2 +- platform/telemetry/src/TelemetryHandle.js | 2 +- platform/telemetry/src/TelemetryHandler.js | 2 +- platform/telemetry/src/TelemetryQueue.js | 2 +- platform/telemetry/src/TelemetrySubscriber.js | 2 +- platform/telemetry/src/TelemetrySubscription.js | 2 +- platform/telemetry/src/TelemetryTable.js | 2 +- platform/telemetry/test/TelemetryAggregatorSpec.js | 2 +- platform/telemetry/test/TelemetryCapabilitySpec.js | 2 +- platform/telemetry/test/TelemetryControllerSpec.js | 2 +- platform/telemetry/test/TelemetryDelegatorSpec.js | 2 +- platform/telemetry/test/TelemetryFormatterSpec.js | 2 +- platform/telemetry/test/TelemetryHandleSpec.js | 2 +- platform/telemetry/test/TelemetryHandlerSpec.js | 2 +- platform/telemetry/test/TelemetryQueueSpec.js | 2 +- platform/telemetry/test/TelemetrySubscriberSpec.js | 2 +- platform/telemetry/test/TelemetrySubscriptionSpec.js | 2 +- platform/telemetry/test/TelemetryTableSpec.js | 2 +- scripts/migrate-for-jshint.js | 2 +- scripts/migrate-templates.js | 2 +- scripts/rebundle-template.txt | 2 +- src/BundleRegistry.js | 2 +- src/BundleRegistrySpec.js | 2 +- src/MCT.js | 2 +- src/MCTSpec.js | 2 +- src/adapter/actions/ActionDialogDecorator.js | 2 +- src/adapter/bundle.js | 2 +- src/adapter/capabilities/APICapabilityDecorator.js | 2 +- src/adapter/capabilities/AdapterCapability.js | 2 +- src/adapter/capabilities/AlternateCompositionCapability.js | 2 +- src/adapter/capabilities/synchronizeMutationCapability.js | 2 +- src/adapter/controllers/AdaptedViewController.js | 2 +- src/adapter/directives/MCTView.js | 2 +- src/adapter/directives/Region.js | 2 +- src/adapter/policies/AdaptedViewPolicy.js | 2 +- src/adapter/policies/AdapterCompositionPolicy.js | 2 +- src/adapter/runs/AlternateCompositionInitializer.js | 2 +- src/adapter/services/Instantiate.js | 2 +- src/adapter/services/MissingModelCompatibilityDecorator.js | 2 +- src/adapter/templates/adapted-view-template.html | 2 +- src/api/TimeConductor.js | 2 +- src/api/TimeConductorSpec.js | 2 +- src/api/api.js | 2 +- src/api/composition/CompositionAPI.js | 2 +- src/api/composition/CompositionCollection.js | 2 +- src/api/composition/DefaultCompositionProvider.js | 2 +- src/api/objects/LegacyObjectAPIInterceptor.js | 2 +- src/api/objects/MutableObject.js | 2 +- src/api/objects/ObjectAPI.js | 2 +- src/api/objects/RootObjectProvider.js | 2 +- src/api/objects/RootRegistry.js | 2 +- src/api/objects/bundle.js | 2 +- src/api/objects/object-utils.js | 2 +- src/api/objects/objectEventEmitter.js | 2 +- src/api/objects/test/RootObjectProviderSpec.js | 2 +- src/api/objects/test/RootRegistrySpec.js | 2 +- src/api/telemetry/LegacyTelemetryProvider.js | 2 +- src/api/telemetry/TelemetryAPI.js | 2 +- src/api/telemetry/TelemetryMetadataManager.js | 2 +- src/api/telemetry/TelemetryValueFormatter.js | 2 +- src/api/telemetry/bundle.js | 2 +- src/api/types/Type.js | 2 +- src/api/types/TypeRegistry.js | 2 +- src/api/ui/Dialog.js | 2 +- src/api/ui/GestureAPI.js | 2 +- src/defaultRegistry.js | 2 +- src/legacyRegistry.js | 2 +- src/legacyRegistrySpec.js | 2 +- src/plugins/plugins.js | 2 +- src/selection/ContextManager.js | 2 +- src/selection/HoverGesture.js | 2 +- src/selection/SelectGesture.js | 2 +- src/selection/Selection.js | 2 +- src/start.frag | 2 +- src/ui/ViewRegistry.js | 2 +- test-main.js | 2 +- 948 files changed, 1039 insertions(+), 1039 deletions(-) diff --git a/LICENSES.md b/LICENSES.md index 94a7fecf13..b95375aefd 100644 --- a/LICENSES.md +++ b/LICENSES.md @@ -1,6 +1,6 @@ # Open MCT Licenses -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, 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. diff --git a/build-docs.sh b/build-docs.sh index 22e87949bf..6738cbc8be 100755 --- a/build-docs.sh +++ b/build-docs.sh @@ -1,7 +1,7 @@ #!/bin/bash #***************************************************************************** -#* Open MCT, Copyright (c) 2014-2016, United States Government +#* Open MCT, Copyright (c) 2014-2017, United States Government #* as represented by the Administrator of the National Aeronautics and Space #* Administration. All rights reserved. #* diff --git a/docs/gendocs.js b/docs/gendocs.js index 8d257625d0..b96b2c997e 100644 --- a/docs/gendocs.js +++ b/docs/gendocs.js @@ -1,5 +1,5 @@ /***************************************************************************** - * Open MCT, Copyright (c) 2014-2016, United States Government + * Open MCT, Copyright (c) 2014-2017, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * diff --git a/docs/src/tutorials/index.md b/docs/src/tutorials/index.md index e8f4417890..c60e05a0f3 100644 --- a/docs/src/tutorials/index.md +++ b/docs/src/tutorials/index.md @@ -156,7 +156,7 @@ has been finalized. #### Before ```html

        Hello, world! I am the default route.

        My controller has told me: "{{phrase}}"

        - \ No newline at end of file + diff --git a/example/builtins/src/ExampleController.js b/example/builtins/src/ExampleController.js index 621b8bf819..95a2d4fc8f 100644 --- a/example/builtins/src/ExampleController.js +++ b/example/builtins/src/ExampleController.js @@ -1,5 +1,5 @@ /***************************************************************************** - * Open MCT, Copyright (c) 2014-2016, United States Government + * Open MCT, Copyright (c) 2014-2017, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * @@ -39,4 +39,4 @@ define( return ExampleController; } -); \ No newline at end of file +); diff --git a/example/builtins/src/ExampleDirective.js b/example/builtins/src/ExampleDirective.js index 877436ed7b..2624f0b317 100644 --- a/example/builtins/src/ExampleDirective.js +++ b/example/builtins/src/ExampleDirective.js @@ -1,5 +1,5 @@ /***************************************************************************** - * Open MCT, Copyright (c) 2014-2016, United States Government + * Open MCT, Copyright (c) 2014-2017, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * @@ -63,4 +63,4 @@ define( return ExampleDirective; } -); \ No newline at end of file +); diff --git a/example/builtins/src/ExampleService.js b/example/builtins/src/ExampleService.js index 2ffa07a947..d719151596 100644 --- a/example/builtins/src/ExampleService.js +++ b/example/builtins/src/ExampleService.js @@ -1,5 +1,5 @@ /***************************************************************************** - * Open MCT, Copyright (c) 2014-2016, United States Government + * Open MCT, Copyright (c) 2014-2017, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * @@ -43,4 +43,4 @@ define( return ExampleService; } -); \ No newline at end of file +); diff --git a/example/composite/bundle.js b/example/composite/bundle.js index 21ab3dfa8a..c432ca8148 100644 --- a/example/composite/bundle.js +++ b/example/composite/bundle.js @@ -1,5 +1,5 @@ /***************************************************************************** - * Open MCT, Copyright (c) 2014-2016, United States Government + * Open MCT, Copyright (c) 2014-2017, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * diff --git a/example/composite/src/SomeAggregator.js b/example/composite/src/SomeAggregator.js index b8db9ead77..e922c7f412 100644 --- a/example/composite/src/SomeAggregator.js +++ b/example/composite/src/SomeAggregator.js @@ -1,5 +1,5 @@ /***************************************************************************** - * Open MCT, Copyright (c) 2014-2016, United States Government + * Open MCT, Copyright (c) 2014-2017, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * @@ -47,4 +47,4 @@ define( return SomeAggregator; } -); \ No newline at end of file +); diff --git a/example/composite/src/SomeDecorator.js b/example/composite/src/SomeDecorator.js index 3fb7c0698c..33be63b31d 100644 --- a/example/composite/src/SomeDecorator.js +++ b/example/composite/src/SomeDecorator.js @@ -1,5 +1,5 @@ /***************************************************************************** - * Open MCT, Copyright (c) 2014-2016, United States Government + * Open MCT, Copyright (c) 2014-2017, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * @@ -45,4 +45,4 @@ define( return SomeDecorator; } -); \ No newline at end of file +); diff --git a/example/composite/src/SomeOtherDecorator.js b/example/composite/src/SomeOtherDecorator.js index caaf6a2bc4..14cc5050da 100644 --- a/example/composite/src/SomeOtherDecorator.js +++ b/example/composite/src/SomeOtherDecorator.js @@ -1,5 +1,5 @@ /***************************************************************************** - * Open MCT, Copyright (c) 2014-2016, United States Government + * Open MCT, Copyright (c) 2014-2017, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * @@ -45,4 +45,4 @@ define( return SomeOtherDecorator; } -); \ No newline at end of file +); diff --git a/example/composite/src/SomeOtherExample.js b/example/composite/src/SomeOtherExample.js index 5118011198..2bda95e686 100644 --- a/example/composite/src/SomeOtherExample.js +++ b/example/composite/src/SomeOtherExample.js @@ -1,5 +1,5 @@ /***************************************************************************** - * Open MCT, Copyright (c) 2014-2016, United States Government + * Open MCT, Copyright (c) 2014-2017, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * @@ -43,4 +43,4 @@ define( return SomeOtherExample; } -); \ No newline at end of file +); diff --git a/example/composite/src/SomeOtherProvider.js b/example/composite/src/SomeOtherProvider.js index 1cd9e358c8..f08761d424 100644 --- a/example/composite/src/SomeOtherProvider.js +++ b/example/composite/src/SomeOtherProvider.js @@ -1,5 +1,5 @@ /***************************************************************************** - * Open MCT, Copyright (c) 2014-2016, United States Government + * Open MCT, Copyright (c) 2014-2017, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * @@ -45,4 +45,4 @@ define( return SomeOtherProvider; } -); \ No newline at end of file +); diff --git a/example/composite/src/SomeProvider.js b/example/composite/src/SomeProvider.js index eafef10244..a8fdbb2dcf 100644 --- a/example/composite/src/SomeProvider.js +++ b/example/composite/src/SomeProvider.js @@ -1,5 +1,5 @@ /***************************************************************************** - * Open MCT, Copyright (c) 2014-2016, United States Government + * Open MCT, Copyright (c) 2014-2017, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * @@ -45,4 +45,4 @@ define( return SomeProvider; } -); \ No newline at end of file +); diff --git a/example/eventGenerator/bundle.js b/example/eventGenerator/bundle.js index 425de02157..16a5512e66 100644 --- a/example/eventGenerator/bundle.js +++ b/example/eventGenerator/bundle.js @@ -1,5 +1,5 @@ /***************************************************************************** - * Open MCT, Copyright (c) 2014-2016, United States Government + * Open MCT, Copyright (c) 2014-2017, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * diff --git a/example/eventGenerator/src/EventTelemetry.js b/example/eventGenerator/src/EventTelemetry.js index 31bda1f3f8..781723657c 100644 --- a/example/eventGenerator/src/EventTelemetry.js +++ b/example/eventGenerator/src/EventTelemetry.js @@ -1,5 +1,5 @@ /***************************************************************************** - * Open MCT, Copyright (c) 2014-2016, United States Government + * Open MCT, Copyright (c) 2014-2017, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * @@ -60,4 +60,4 @@ define( return EventTelemetry; } -); \ No newline at end of file +); diff --git a/example/eventGenerator/src/EventTelemetryProvider.js b/example/eventGenerator/src/EventTelemetryProvider.js index b2de59ad8e..1768984ba0 100644 --- a/example/eventGenerator/src/EventTelemetryProvider.js +++ b/example/eventGenerator/src/EventTelemetryProvider.js @@ -1,5 +1,5 @@ /***************************************************************************** - * Open MCT, Copyright (c) 2014-2016, United States Government + * Open MCT, Copyright (c) 2014-2017, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * @@ -118,4 +118,4 @@ define( return EventTelemetryProvider; } -); \ No newline at end of file +); diff --git a/example/export/ExportTelemetryAsCSVAction.js b/example/export/ExportTelemetryAsCSVAction.js index 111b869d94..f638ae7bcd 100644 --- a/example/export/ExportTelemetryAsCSVAction.js +++ b/example/export/ExportTelemetryAsCSVAction.js @@ -1,5 +1,5 @@ /***************************************************************************** - * Open MCT, Copyright (c) 2014-2016, United States Government + * Open MCT, Copyright (c) 2014-2017, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * diff --git a/example/export/bundle.js b/example/export/bundle.js index bcafee4050..75e1937153 100644 --- a/example/export/bundle.js +++ b/example/export/bundle.js @@ -1,5 +1,5 @@ /***************************************************************************** - * Open MCT, Copyright (c) 2014-2016, United States Government + * Open MCT, Copyright (c) 2014-2017, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * diff --git a/example/extensions/bundle.js b/example/extensions/bundle.js index bf52f9092f..aaf65cc697 100644 --- a/example/extensions/bundle.js +++ b/example/extensions/bundle.js @@ -1,5 +1,5 @@ /***************************************************************************** - * Open MCT, Copyright (c) 2014-2016, United States Government + * Open MCT, Copyright (c) 2014-2017, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * diff --git a/example/extensions/src/SomeExample.js b/example/extensions/src/SomeExample.js index 925c3fc5e1..baaf523d7c 100644 --- a/example/extensions/src/SomeExample.js +++ b/example/extensions/src/SomeExample.js @@ -1,5 +1,5 @@ /***************************************************************************** - * Open MCT, Copyright (c) 2014-2016, United States Government + * Open MCT, Copyright (c) 2014-2017, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * @@ -49,4 +49,4 @@ define( return SomeExample; } -); \ No newline at end of file +); diff --git a/example/forms/bundle.js b/example/forms/bundle.js index f9e32db2cb..b2c4150fcc 100644 --- a/example/forms/bundle.js +++ b/example/forms/bundle.js @@ -1,5 +1,5 @@ /***************************************************************************** - * Open MCT, Copyright (c) 2014-2016, United States Government + * Open MCT, Copyright (c) 2014-2017, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * diff --git a/example/forms/res/templates/exampleForm.html b/example/forms/res/templates/exampleForm.html index a315d7c9c9..f1f58d32bc 100644 --- a/example/forms/res/templates/exampleForm.html +++ b/example/forms/res/templates/exampleForm.html @@ -1,5 +1,5 @@ - \ No newline at end of file +
        diff --git a/platform/commonUI/about/res/templates/license-apache.html b/platform/commonUI/about/res/templates/license-apache.html index 044813a425..953ecec943 100644 --- a/platform/commonUI/about/res/templates/license-apache.html +++ b/platform/commonUI/about/res/templates/license-apache.html @@ -1,5 +1,5 @@

        Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

        The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

        -

        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

        \ No newline at end of file +

        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

        diff --git a/platform/commonUI/about/res/templates/licenses-export-md.html b/platform/commonUI/about/res/templates/licenses-export-md.html index 4982c49a39..edc760bfc8 100644 --- a/platform/commonUI/about/res/templates/licenses-export-md.html +++ b/platform/commonUI/about/res/templates/licenses-export-md.html @@ -1,5 +1,5 @@