From 1c5101eca60dde69b2d8c9c8ca353ed3f12ee06b Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 22 Oct 2015 11:30:57 -0700 Subject: [PATCH 01/79] [Time Conductor] Add DateAggregator Add DateAggregator, to allow composite services to expose different ways of parsing/formatting dates. nasa/openmctweb#182. --- .../general/src/services/DateAggregator.js | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 platform/commonUI/general/src/services/DateAggregator.js diff --git a/platform/commonUI/general/src/services/DateAggregator.js b/platform/commonUI/general/src/services/DateAggregator.js new file mode 100644 index 0000000000..3c2762d1bd --- /dev/null +++ b/platform/commonUI/general/src/services/DateAggregator.js @@ -0,0 +1,116 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ +/*global define*/ + +define([ + +], function ( +) { + "use strict"; + + /** + * Formats dates for display and parses dates from user input, + * varying by a chosen time system. + * + * Time systems are typically domain keys from telemetry metadata. + * If omitted/left undefined, the time system is presumed to be UTC time, + * with its numeric interpretation being milliseconds since the + * start of 1970. + * + * @interface DateService + */ + + /** + * Check if the provided text can be parsed into a numeric + * representation of a time in the specified time system. + * @method validate + * @memberof DateService# + * @param {string} text the text to validate + * @param {string} [key] a key identifying the time system + * @returns {boolean} true if the text can be parsed + */ + + /** + * Parse the provided into a numeric representation of a time + * in the specified time system. + * + * Behavior of this method for invalid text is undefined; use + * the `validate` method to check for validity first. + * + * @method parse + * @memberof DateService# + * @param {string} text the text to parse + * @param {string} [key] a key identifying the time system + * @returns {number} a numeric representation of the date/time + */ + + /** + * Format the provided numeric representation of a time + * into a human-readable string appropriate for that time system. + * + * If the time system is not recognized, the return value will be + * `undefined`. + * + * @method format + * @memberof DateService# + * @param {number} value the time value to format + * @param {string} [key] a key identifying the time system + * @returns {string} a human-readable representation of the date/time + */ + + /** + * Composites multiple DateService implementations such that + * they can be used as one. + * @memberof platform/commonUI/general + * @constructor + */ + function DateAggregator(dateProviders) { + this.dateProviders = dateProviders; + } + + DateAggregator.prototype.validate = function (text, key) { + return this.dateProviders.some(function (provider) { + return provider.validate(text, key); + }); + }; + + DateAggregator.prototype.format = function (value, key) { + var i, text; + for (i = 0; i < this.dateProviders.length; i += 1) { + text = this.dateProviders[i].format(value, key); + if (text !== undefined) { + return text; + } + } + }; + + DateAggregator.prototype.parse = function (text, key) { + var i; + for (i = 0; i < this.dateProviders.length; i += 1) { + if (this.dateProviders[i].validate(text, key)) { + return this.dateProviders[i].parse(text, key); + } + } + }; + + return DateAggregator; +}); From 6b42d3bf4b5bf1856994acdbb128e6fb781760fd Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 22 Oct 2015 11:43:42 -0700 Subject: [PATCH 02/79] [Time Conductor] Test DateAggregator --- .../test/services/DateAggregatorSpec.js | 94 +++++++++++++++++++ platform/commonUI/general/test/suite.json | 1 + 2 files changed, 95 insertions(+) create mode 100644 platform/commonUI/general/test/services/DateAggregatorSpec.js diff --git a/platform/commonUI/general/test/services/DateAggregatorSpec.js b/platform/commonUI/general/test/services/DateAggregatorSpec.js new file mode 100644 index 0000000000..ba55bc907a --- /dev/null +++ b/platform/commonUI/general/test/services/DateAggregatorSpec.js @@ -0,0 +1,94 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ +/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/ + + +define( + ["../../src/services/DateAggregator"], + function (DateAggregator) { + 'use strict'; + + var DATE_SERVICE_METHODS = [ "format", "validate", "parse" ]; + + describe("DateAggregator", function () { + var mockProviders, + dateAggregator; + + beforeEach(function () { + mockProviders = [ 'a', 'b', 'c', undefined ].map(function (k, i) { + var mockProvider = jasmine.createSpyObj( + 'provider-' + k, + DATE_SERVICE_METHODS + ); + + mockProvider.format.andCallFake(function (value, key) { + return key === k ? + ("Formatted " + value + " for " + k) : + undefined; + }); + + mockProvider.parse.andCallFake(function (text, key) { + return key === k ? i : undefined; + }); + + mockProvider.validate.andCallFake(function (text, key) { + return key === k; + }); + + return mockProvider; + }); + + dateAggregator = new DateAggregator(mockProviders); + }); + + it("formats dates using the first provider which gives a result", function () { + expect(dateAggregator.format(42, "a")) + .toEqual("Formatted 42 for a"); + expect(dateAggregator.format(12321, "b")) + .toEqual("Formatted 12321 for b"); + expect(dateAggregator.format(1977, "c")) + .toEqual("Formatted 1977 for c"); + expect(dateAggregator.format(0)) + .toEqual("Formatted 0 for undefined"); + }); + + it("parses dates using the first provider which validates", function () { + expect(dateAggregator.parse("x", "a")).toEqual(0); + expect(dateAggregator.parse("x", "b")).toEqual(1); + expect(dateAggregator.parse("x", "c")).toEqual(2); + expect(dateAggregator.parse("x")).toEqual(3); + }); + + it("validates across all providers", function () { + expect(dateAggregator.validate("x", "a")).toBeTruthy(); + expect(dateAggregator.validate("x", "b")).toBeTruthy(); + expect(dateAggregator.validate("x", "c")).toBeTruthy(); + expect(dateAggregator.validate("x")).toBeTruthy(); + expect(dateAggregator.validate("x", "z")).toBeFalsy(); + + mockProviders[3].validate.andReturn(false); + expect(dateAggregator.validate("x")).toBeFalsy(); + }); + + }); + } +); diff --git a/platform/commonUI/general/test/suite.json b/platform/commonUI/general/test/suite.json index 0d19fbb9e4..3ab06212d4 100644 --- a/platform/commonUI/general/test/suite.json +++ b/platform/commonUI/general/test/suite.json @@ -17,6 +17,7 @@ "directives/MCTPopup", "directives/MCTResize", "directives/MCTScroll", + "services/DateAggregator", "services/Popup", "services/PopupService", "services/UrlService", From 794231143ecbd484951060f27d329dfda075c1fa Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 22 Oct 2015 11:55:38 -0700 Subject: [PATCH 03/79] [Time Conductor] Add spec for UTCDateProvider Add test cases for UTCDateProvider, which will provide default date/time formatting/parsing. --- .../general/src/services/UTCDateProvider.js | 51 ++++++++++++++ .../test/services/UTCDateProviderSpec.js | 67 +++++++++++++++++++ platform/commonUI/general/test/suite.json | 1 + 3 files changed, 119 insertions(+) create mode 100644 platform/commonUI/general/src/services/UTCDateProvider.js create mode 100644 platform/commonUI/general/test/services/UTCDateProviderSpec.js diff --git a/platform/commonUI/general/src/services/UTCDateProvider.js b/platform/commonUI/general/src/services/UTCDateProvider.js new file mode 100644 index 0000000000..54fcbf4737 --- /dev/null +++ b/platform/commonUI/general/src/services/UTCDateProvider.js @@ -0,0 +1,51 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ +/*global define*/ + +define([ + 'moment' +], function ( + moment +) { + "use strict"; + + /** + * Composites multiple DateService implementations such that + * they can be used as one. + * @memberof platform/commonUI/general + * @constructor + * @implements {DateService} + */ + function UTCDateProvider() { + } + + UTCDateProvider.prototype.validate = function (text, key) { + }; + + UTCDateProvider.prototype.format = function (value, key) { + }; + + UTCDateProvider.prototype.parse = function (text, key) { + }; + + return UTCDateProvider; +}); diff --git a/platform/commonUI/general/test/services/UTCDateProviderSpec.js b/platform/commonUI/general/test/services/UTCDateProviderSpec.js new file mode 100644 index 0000000000..1a1873030d --- /dev/null +++ b/platform/commonUI/general/test/services/UTCDateProviderSpec.js @@ -0,0 +1,67 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ +/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/ + + +define( + ["../../src/services/UTCDateProvider", "moment"], + function (UTCDateProvider, moment) { + 'use strict'; + + describe("UTCDateProvider", function () { + var testDate, testTimestamp, dateProvider; + + beforeEach(function () { + testDate = "1977-05-25 17:30:00"; + testTimestamp = moment.utc(testDate).valueOf(); + dateProvider = new UTCDateProvider(); + }); + + it("distinguishes valid dates from invalid dates", function () { + expect(dateProvider.validate(testDate)) + .toBeTruthy(); + expect(dateProvider.validate("2015-garbage :00:00")) + .toBeFalsy(); + }); + + it("parses dates to their numeric representations", function () { + expect(dateProvider.parse(testDate)).toEqual(testTimestamp); + }); + + it("formats to text representing UTC date/times", function () { + var formatted = dateProvider.format(testTimestamp); + expect(formatted).toEqual(jasmine.any(String)); + // Use moment to verify that formatted value is equal + // to the original date/time + expect(moment.utc(formatted).valueOf()).toEqual(testTimestamp); + }); + + it("does not handle defined keys", function () { + expect(dateProvider.validate(testDate, 'someKey')) + .toBeFalsy(); + expect(dateProvider.format(testTimestamp, 'someKey')) + .toBeUndefined(); + }); + + }); + } +); diff --git a/platform/commonUI/general/test/suite.json b/platform/commonUI/general/test/suite.json index 3ab06212d4..9f80aaabc2 100644 --- a/platform/commonUI/general/test/suite.json +++ b/platform/commonUI/general/test/suite.json @@ -18,6 +18,7 @@ "directives/MCTResize", "directives/MCTScroll", "services/DateAggregator", + "services/UTCDateProvider", "services/Popup", "services/PopupService", "services/UrlService", From c882b2d4c3c14b93a147aba7ed5c47c4d544ece2 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 22 Oct 2015 12:08:34 -0700 Subject: [PATCH 04/79] [Time Conductor] Implement date provider Implement UTCDateProvider sufficient to pass spec. --- .../general/src/services/UTCDateProvider.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/platform/commonUI/general/src/services/UTCDateProvider.js b/platform/commonUI/general/src/services/UTCDateProvider.js index 54fcbf4737..38b6c61b8b 100644 --- a/platform/commonUI/general/src/services/UTCDateProvider.js +++ b/platform/commonUI/general/src/services/UTCDateProvider.js @@ -28,6 +28,14 @@ define([ ) { "use strict"; + var DATE_FORMAT = "YYYY-MM-DD HH:mm:ss", + DATE_FORMATS = [ + DATE_FORMAT, + "YYYY-MM-DD HH:mm:ss", + "YYYY-MM-DD HH:mm", + "YYYY-MM-DD" + ]; + /** * Composites multiple DateService implementations such that * they can be used as one. @@ -39,12 +47,17 @@ define([ } UTCDateProvider.prototype.validate = function (text, key) { + return key === undefined && moment.utc(text, DATE_FORMATS).isValid(); }; UTCDateProvider.prototype.format = function (value, key) { + return key === undefined ? + moment.utc(value).format(DATE_FORMAT) : + undefined; }; UTCDateProvider.prototype.parse = function (text, key) { + return key === undefined && moment.utc(text, DATE_FORMATS).valueOf(); }; return UTCDateProvider; From 0d47b7c47dc8bd186e024587f4b70b505330611b Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 22 Oct 2015 12:10:12 -0700 Subject: [PATCH 05/79] [Time Conductor] Expose dateService in bundle definition --- platform/commonUI/general/bundle.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/platform/commonUI/general/bundle.json b/platform/commonUI/general/bundle.json index 1aa0b1dfc1..a69c810195 100644 --- a/platform/commonUI/general/bundle.json +++ b/platform/commonUI/general/bundle.json @@ -15,6 +15,19 @@ "depends": [ "$document", "$window" ] } ], + "components": [ + { + "type": "aggregator", + "provides": "dateService", + "implementation": "services/DateAggregator.js" + }, + { + "type": "provider", + "provides": "dateService", + "implementation": "services/UTCDateProvider.js", + "priority": "fallback" + } + ], "runs": [ { "implementation": "StyleSheetLoader.js", From 117470068a01951c90151a7c8fe8fe942d42c357 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 22 Oct 2015 12:17:08 -0700 Subject: [PATCH 06/79] [Time Conductor] Use dateService from TimeRangeController --- platform/commonUI/general/bundle.json | 2 +- .../src/controllers/TimeRangeController.js | 17 +++++++++------ .../controllers/TimeRangeControllerSpec.js | 21 ++++++++++++++++++- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/platform/commonUI/general/bundle.json b/platform/commonUI/general/bundle.json index a69c810195..05c86cbcf7 100644 --- a/platform/commonUI/general/bundle.json +++ b/platform/commonUI/general/bundle.json @@ -66,7 +66,7 @@ { "key": "TimeRangeController", "implementation": "controllers/TimeRangeController.js", - "depends": [ "$scope", "now" ] + "depends": [ "$scope", "dateService", "now" ] }, { "key": "DateTimePickerController", diff --git a/platform/commonUI/general/src/controllers/TimeRangeController.js b/platform/commonUI/general/src/controllers/TimeRangeController.js index d4fb21be08..9ec95bac23 100644 --- a/platform/commonUI/general/src/controllers/TimeRangeController.js +++ b/platform/commonUI/general/src/controllers/TimeRangeController.js @@ -30,23 +30,28 @@ define( TICK_SPACING_PX = 150; /** + * Controller used by the `time-controller` template. * @memberof platform/commonUI/general * @constructor */ - function TimeConductorController($scope, now) { + function TimeRangeController($scope, dateService, now) { var tickCount = 2, innerMinimumSpan = 1000, // 1 second outerMinimumSpan = 1000 * 60 * 60, // 1 hour initialDragValue; + function timeSystemKey() { + return ($scope.parameters || {}).domain; + } + function formatTimestamp(ts) { - return moment.utc(ts).format(DATE_FORMAT); + return dateService.format(ts, timeSystemKey()); } function parseTimestamp(text) { - var m = moment.utc(text, DATE_FORMAT); - if (m.isValid()) { - return m.valueOf(); + var key = timeSystemKey(); + if (dateService.validate(text, key)) { + return dateService.parse(text, key); } else { throw new Error("Could not parse " + text); } @@ -297,6 +302,6 @@ define( $scope.$watch("boundsModel.end", updateEndFromText); } - return TimeConductorController; + return TimeRangeController; } ); diff --git a/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js b/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js index 91d3ecb9db..30cddab922 100644 --- a/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js +++ b/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js @@ -33,6 +33,7 @@ define( describe("The TimeRangeController", function () { var mockScope, + mockDateService, mockNow, controller; @@ -57,8 +58,26 @@ define( "$scope", [ "$apply", "$watch", "$watchCollection" ] ); + mockDateService = jasmine.createSpyObj( + "dateService", + [ "validate", "format", "parse" ] + ); + mockDateService.validate.andCallFake(function (text) { + return moment.utc(text).isValid(); + }); + mockDateService.parse.andCallFake(function (text) { + return moment.utc(text).valueOf(); + }); + mockDateService.format.andCallFake(function (value) { + return moment.utc(value).format("YYYY-MM-DD HH:mm:ss"); + }); mockNow = jasmine.createSpy('now'); - controller = new TimeRangeController(mockScope, mockNow); + + controller = new TimeRangeController( + mockScope, + mockDateService, + mockNow + ); }); it("watches the model that was passed in", function () { From 950578f09b9762c8a60a1c199c7f61d2a31529ed Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 22 Oct 2015 12:20:15 -0700 Subject: [PATCH 07/79] [Time Conductor] Hide datetime pickers for non-UTC domains --- .../general/res/templates/controls/time-controller.html | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/platform/commonUI/general/res/templates/controls/time-controller.html b/platform/commonUI/general/res/templates/controls/time-controller.html index 300e56c381..e0d7804b3b 100644 --- a/platform/commonUI/general/res/templates/controls/time-controller.html +++ b/platform/commonUI/general/res/templates/controls/time-controller.html @@ -29,7 +29,10 @@ ng-model="boundsModel.start" ng-class="{ error: !boundsModel.startValid }"> - + +
- +
From c0fda5b5729116798392f7060fad7ad10b86bcc7 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 22 Oct 2015 12:41:46 -0700 Subject: [PATCH 08/79] [Time Conductor] Add JSDoc Add typedefs relevant to the date aggregator; in particular, document properties used to determine how to format timestamps associated with a telemetry point. --- .../general/src/services/DateAggregator.js | 4 +- platform/telemetry/src/TelemetryCapability.js | 58 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/platform/commonUI/general/src/services/DateAggregator.js b/platform/commonUI/general/src/services/DateAggregator.js index 3c2762d1bd..ee01929b27 100644 --- a/platform/commonUI/general/src/services/DateAggregator.js +++ b/platform/commonUI/general/src/services/DateAggregator.js @@ -31,7 +31,9 @@ define([ * Formats dates for display and parses dates from user input, * varying by a chosen time system. * - * Time systems are typically domain keys from telemetry metadata. + * Time systems are typically specified as `system` properties + * of domains in {@link TelemetryDomainMetadata}. + * * If omitted/left undefined, the time system is presumed to be UTC time, * with its numeric interpretation being milliseconds since the * start of 1970. diff --git a/platform/telemetry/src/TelemetryCapability.js b/platform/telemetry/src/TelemetryCapability.js index 1fbd12a691..d89b3cd3bf 100644 --- a/platform/telemetry/src/TelemetryCapability.js +++ b/platform/telemetry/src/TelemetryCapability.js @@ -36,6 +36,64 @@ define( getRangeValue: ZERO }; + /** + * Provides metadata about telemetry associated with a + * given domain object. + * + * @typedef TelemetryMetadata + * @property {string} source the machine-readable identifier for + * the source of telemetry data for this object; used by + * {@link TelemetryService} implementations to determine + * whether or not they provide data for this object. + * @property {string} key the machine-readable identifier for + * telemetry data associated with this specific object, + * within that `source`. + * @property {TelemetryDomainMetadata[]} domains supported domain + * options for telemetry data associated with this object, + * to use in interpreting a {@link TelemetrySeries} + * @property {TelemetryRangeMetadata[]} ranges supported range + * options for telemetry data associated with this object, + * to use in interpreting a {@link TelemetrySeries} + */ + + /** + * Provides metadata about range options within a telemetry series. + * Range options describe distinct properties within any given datum + * of a telemetry series; for instance, a telemetry series containing + * both raw and uncalibrated values may provide separate ranges for + * each. + * + * @typedef TelemetryRangeMetadata + * @property {string} key machine-readable identifier for this range + * @property {string} name human-readable name for this range + * @property {string} [units] human-readable units for this range + * @property {string} [format] data format for this range; usually, + * one of `number`, or `string`. If `undefined`, + * should presume to be a `number`. Custom formats + * may be indicated here. + */ + + /** + * Provides metadata about domain options within a telemetry series. + * Domain options describe distinct properties within any given datum + * of a telemtry series; for instance, a telemetry series containing + * both spacecraft event time and earth received times may provide + * separate domains for each. + * + * Domains are typically used to represent timestamps in a telemetry + * series, but more generally may express any property which will + * have unique values for each datum in a series. It is this property + * which makes domains distinct from ranges, as it makes these values + * appropriate and meaningful for use to sort and bound a series. + * + * @typedef TelemetryDomainMetadata + * @property {string} key machine-readable identifier for this range + * @property {string} name human-readable name for this range + * @property {string} [system] machine-readable identifier for the + * time/date system associated with this domain; + * used by {@link DateService} + */ + /** * A telemetry capability provides a means of requesting telemetry * for a specific object, and for unwrapping the response (to get From 9bc4327c597261ead0c7becf35d3cebfbddc2752 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 22 Oct 2015 12:51:10 -0700 Subject: [PATCH 09/79] [Time Conductor] Add non-time-like domain Add a non-time-like domain to sine wave generator telemetry, to support integration of custom domain formatting into time conductor. --- example/generator/bundle.json | 10 ++++ example/generator/src/SinewaveDateProvider.js | 55 +++++++++++++++++++ .../generator/src/SinewaveTelemetrySeries.js | 3 + 3 files changed, 68 insertions(+) create mode 100644 example/generator/src/SinewaveDateProvider.js diff --git a/example/generator/bundle.json b/example/generator/bundle.json index cdb4736957..fc18f31193 100644 --- a/example/generator/bundle.json +++ b/example/generator/bundle.json @@ -8,6 +8,11 @@ "type": "provider", "provides": "telemetryService", "depends": [ "$q", "$timeout" ] + }, + { + "implementation": "SinewaveDateProvider.js", + "type": "provider", + "provides": "dateService" } ], "capabilities": [ @@ -38,6 +43,11 @@ { "key": "yesterday", "name": "Yesterday" + }, + { + "key": "index", + "name": "Index", + "system": "generator.index" } ], "ranges": [ diff --git a/example/generator/src/SinewaveDateProvider.js b/example/generator/src/SinewaveDateProvider.js new file mode 100644 index 0000000000..9b819a8796 --- /dev/null +++ b/example/generator/src/SinewaveDateProvider.js @@ -0,0 +1,55 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ +/*global define*/ + +define([ +], function ( +) { + "use strict"; + + /** + * Provides date-time formatting for the Sine Wave Generator's + * `index` domain; demonstrates how to support domains which should + * not necessarily be formatted as UTC dates. + * @memberof example/generator + * @constructor + * @implements {DateService} + */ + function SinewaveDateProvider() { + } + + SinewaveDateProvider.prototype.validate = function (text, key) { + return key === 'generator.index' && /^#\d+$/.test(text); + }; + + SinewaveDateProvider.prototype.format = function (value, key) { + return key === 'generator.index' ? + ('#' + Math.floor(value)) : + undefined; + }; + + SinewaveDateProvider.prototype.parse = function (text, key) { + return key === 'generator.index' && parseInt(key.substring(1), 10); + }; + + return SinewaveDateProvider; +}); diff --git a/example/generator/src/SinewaveTelemetrySeries.js b/example/generator/src/SinewaveTelemetrySeries.js index 1e84034766..17084a07da 100644 --- a/example/generator/src/SinewaveTelemetrySeries.js +++ b/example/generator/src/SinewaveTelemetrySeries.js @@ -58,6 +58,9 @@ define( }; generatorData.getDomainValue = function (i, domain) { + if (domain === 'index') { + return i; + } return (i + offset) * 1000 + firstTime * 1000 - (domain === 'yesterday' ? ONE_DAY : 0); }; From e8d7093eb57393f2c9e58925fa3c48b29987e54e Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 22 Oct 2015 13:07:04 -0700 Subject: [PATCH 10/79] [Time Conductor] Use time systems from time conductor --- example/generator/bundle.json | 12 ++++++++++ .../src/controllers/TimeRangeController.js | 4 ++-- platform/features/conductor/bundle.json | 4 ++-- .../res/templates/time-conductor.html | 1 + .../conductor/src/ConductorRepresenter.js | 23 +++++++++++-------- .../src/ConductorTelemetryDecorator.js | 2 +- .../features/conductor/src/TimeConductor.js | 20 ++++++++-------- 7 files changed, 42 insertions(+), 24 deletions(-) diff --git a/example/generator/bundle.json b/example/generator/bundle.json index fc18f31193..b2050e07e9 100644 --- a/example/generator/bundle.json +++ b/example/generator/bundle.json @@ -73,6 +73,18 @@ } ] } + ], + "constants": [ + { + "key": "TIME_CONDUCTOR_DOMAINS", + "value": [ + { "key": "time", "name": "Time" }, + { "key": "yesterday", "name": "Yesterday" }, + { "key": "index", "name": "Index", "system": "generator.index" } + ], + "priority": -1, + "comment": "Placeholder; to be replaced by inspection of available domains." + } ] } } diff --git a/platform/commonUI/general/src/controllers/TimeRangeController.js b/platform/commonUI/general/src/controllers/TimeRangeController.js index 9ec95bac23..5f2f0fa3e6 100644 --- a/platform/commonUI/general/src/controllers/TimeRangeController.js +++ b/platform/commonUI/general/src/controllers/TimeRangeController.js @@ -41,7 +41,7 @@ define( initialDragValue; function timeSystemKey() { - return ($scope.parameters || {}).domain; + return ($scope.parameters || {}).system; } function formatTimestamp(ts) { @@ -57,7 +57,7 @@ define( } } - // From 0.0-1.0 to "0%"-"1%" + // From 0.0-1.0 to "0%"-"100%" function toPercent(p) { return (100 * p) + "%"; } diff --git a/platform/features/conductor/bundle.json b/platform/features/conductor/bundle.json index de903cfb93..10d3f32665 100644 --- a/platform/features/conductor/bundle.json +++ b/platform/features/conductor/bundle.json @@ -36,9 +36,9 @@ { "key": "TIME_CONDUCTOR_DOMAINS", "value": [ - { "key": "time", "name": "Time" }, - { "key": "yesterday", "name": "Yesterday" } + { "key": "time", "name": "Time" } ], + "priority": "fallback", "comment": "Placeholder; to be replaced by inspection of available domains." } ] diff --git a/platform/features/conductor/res/templates/time-conductor.html b/platform/features/conductor/res/templates/time-conductor.html index 4126652d5b..16cc6296c8 100644 --- a/platform/features/conductor/res/templates/time-conductor.html +++ b/platform/features/conductor/res/templates/time-conductor.html @@ -1,4 +1,5 @@ ", + "", "" ].join(''), THROTTLE_MS = 200, @@ -74,11 +77,12 @@ define( broadcastBounds; // Combine start/end times into a single object - function bounds(start, end) { + function bounds() { + var domain = conductor.domain(); return { start: conductor.displayStart(), end: conductor.displayEnd(), - domain: conductor.domain() + domain: domain && domain.key }; } @@ -97,12 +101,10 @@ define( } function updateDomain(value) { - conductor.domain(value); - repScope.$broadcast('telemetry:display:bounds', bounds( - conductor.displayStart(), - conductor.displayEnd(), - conductor.domain() - )); + var newDomain = conductor.domain(value); + conductorScope.parameters.system = + newDomain && newDomain.system; + repScope.$broadcast('telemetry:display:bounds', bounds()); } // telemetry domain metadata -> option for a select control @@ -130,7 +132,8 @@ define( { outer: bounds(), inner: bounds() }; conductorScope.ngModel.options = conductor.domainOptions().map(makeOption); - conductorScope.ngModel.domain = conductor.domain(); + conductorScope.ngModel.domain = (conductor.domain() || {}).key; + conductorScope.parameters = {}; conductorScope .$watch('ngModel.conductor.inner.start', updateConductorInner); diff --git a/platform/features/conductor/src/ConductorTelemetryDecorator.js b/platform/features/conductor/src/ConductorTelemetryDecorator.js index ab2d958d7e..f359199ce2 100644 --- a/platform/features/conductor/src/ConductorTelemetryDecorator.js +++ b/platform/features/conductor/src/ConductorTelemetryDecorator.js @@ -51,7 +51,7 @@ define( request = request || {}; request.start = start; request.end = end; - request.domain = domain; + request.domain = domain && domain.key; return request; } diff --git a/platform/features/conductor/src/TimeConductor.js b/platform/features/conductor/src/TimeConductor.js index 0fa0403fd9..400cb06f97 100644 --- a/platform/features/conductor/src/TimeConductor.js +++ b/platform/features/conductor/src/TimeConductor.js @@ -43,7 +43,7 @@ define( function TimeConductor(start, end, domains) { this.range = { start: start, end: end }; this.domains = domains; - this.activeDomain = domains[0].key; + this.activeDomain = domains[0]; } /** @@ -73,7 +73,7 @@ define( /** * Get available domain options which can be used to bound time * selection. - * @returns {TelemetryDomain[]} available domains + * @returns {TelemetryDomainMetadata[]} available domains */ TimeConductor.prototype.domainOptions = function () { return this.domains; @@ -82,19 +82,21 @@ define( /** * Get or set (if called with an argument) the active domain. * @param {string} [key] the key identifying the domain choice - * @returns {TelemetryDomain} the active telemetry domain + * @returns {TelemetryDomainMetadata} the active telemetry domain */ TimeConductor.prototype.domain = function (key) { - function matchesKey(domain) { - return domain.key === key; - } + var i; if (arguments.length > 0) { - if (!this.domains.some(matchesKey)) { - throw new Error("Unknown domain " + key); + for (i = 0; i < this.domains.length; i += 1) { + if (this.domains[i].key === key) { + return (this.activeDomain = this.domains[i]); + } } - this.activeDomain = key; + + throw new Error("Unknown domain " + key); } + return this.activeDomain; }; From 4ff03b081dac5d7e6dcec577eae7acd74d0674e0 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 22 Oct 2015 13:08:33 -0700 Subject: [PATCH 11/79] [Time Conductor] Suppress date picker for non-UTC time systems --- .../general/res/templates/controls/time-controller.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/commonUI/general/res/templates/controls/time-controller.html b/platform/commonUI/general/res/templates/controls/time-controller.html index e0d7804b3b..87b6c682b2 100644 --- a/platform/commonUI/general/res/templates/controls/time-controller.html +++ b/platform/commonUI/general/res/templates/controls/time-controller.html @@ -30,7 +30,7 @@ ng-class="{ error: !boundsModel.startValid }"> @@ -55,7 +55,7 @@ ng-class="{ error: !boundsModel.endValid }"> From 552435b009e828aab2b9f3494fbce950dff73804 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 22 Oct 2015 15:20:12 -0700 Subject: [PATCH 12/79] [Time Conductor] Add bundle for time handling --- platform/time/bundle.json | 18 ++++++ platform/time/src/TimeAggregator.js | 57 +++++++++++++++++++ platform/time/src/UTCTimeProvider.js | 44 ++++++++++++++ platform/time/src/UTCTimeSystem.js | 85 ++++++++++++++++++++++++++++ 4 files changed, 204 insertions(+) create mode 100644 platform/time/bundle.json create mode 100644 platform/time/src/TimeAggregator.js create mode 100644 platform/time/src/UTCTimeProvider.js create mode 100644 platform/time/src/UTCTimeSystem.js diff --git a/platform/time/bundle.json b/platform/time/bundle.json new file mode 100644 index 0000000000..9ab4fb1e97 --- /dev/null +++ b/platform/time/bundle.json @@ -0,0 +1,18 @@ +{ + "name": "Time services bundle", + "description": "Defines interfaces and provides default implementations for handling different time systems.", + "extensions": { + "components": [ + { + "provides": "timeService", + "type": "aggregator", + "implementation": "TimeAggregator.js" + }, + { + "provides": "timeService", + "type": "provider", + "implementation": "UTCTimeProvider.js" + } + ] + } +} diff --git a/platform/time/src/TimeAggregator.js b/platform/time/src/TimeAggregator.js new file mode 100644 index 0000000000..f3e0d5cfc3 --- /dev/null +++ b/platform/time/src/TimeAggregator.js @@ -0,0 +1,57 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ +/*global define*/ + +define([ + +], function ( + +) { + "use strict"; + + function TimeAggregator(timeProviders) { + var systemMap = {}, + systemKeys = []; + + timeProviders.forEach(function (provider) { + provider.systems().forEach(function (key) { + if (!systemMap[key]) { + systemMap[key] = provider.system(key); + systemKeys.push(key); + } + }); + }); + + this.systemMap = systemMap; + this.systemKeys = systemKeys; + } + + TimeAggregator.prototype.systems = function () { + return this.systemKeys; + }; + + TimeAggregator.prototype.system = function (key) { + return this.systemMap[key || 'utc']; + }; + + return TimeAggregator; +}); diff --git a/platform/time/src/UTCTimeProvider.js b/platform/time/src/UTCTimeProvider.js new file mode 100644 index 0000000000..36c266c621 --- /dev/null +++ b/platform/time/src/UTCTimeProvider.js @@ -0,0 +1,44 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ +/*global define*/ + +define([ + './UTCTimeSystem' +], function ( + UTCTimeSystem +) { + "use strict"; + + function UTCTimeProvider(now) { + this.utcTimeSystem = new UTCTimeSystem(now); + } + + UTCTimeProvider.prototype.systems = function () { + return [ 'utc' ]; + }; + + UTCTimeProvider.prototype.system = function (key) { + return key === 'utc' ? this.utcTimeSystem : undefined; + }; + + return UTCTimeProvider; +}); diff --git a/platform/time/src/UTCTimeSystem.js b/platform/time/src/UTCTimeSystem.js new file mode 100644 index 0000000000..22c3488b50 --- /dev/null +++ b/platform/time/src/UTCTimeSystem.js @@ -0,0 +1,85 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ +/*global define*/ + +define([ + 'moment' +], function ( + moment +) { + "use strict"; + + var DATE_FORMAT = "YYYY-MM-DD HH:mm:ss", + DATE_FORMATS = [ + DATE_FORMAT, + "YYYY-MM-DD HH:mm:ss", + "YYYY-MM-DD HH:mm", + "YYYY-MM-DD" + ], + SECOND = 1000, + MINUTE = 60 * SECOND, + HOUR = 60 * MINUTE, + DAY = 24 * HOUR, + WEEK = 7 * DAY, + MONTH_APPROX = 30 * DAY, + YEAR = 365 * DAY, + INCREMENTS = [ + SECOND, + MINUTE, + HOUR, + DAY, + WEEK, + MONTH_APPROX, + YEAR + ], + DEFAULT_INCREMENT = 3; + + + function UTCTimeSystem(now) { + this.nowFn = now; + } + + UTCTimeSystem.prototype.format = function (value) { + return moment.utc(value).format(DATE_FORMAT); + }; + + UTCTimeSystem.prototype.parse = function (text) { + return moment.utc(text, DATE_FORMATS).valueOf(); + }; + + UTCTimeSystem.prototype.validate = function (text) { + return moment.utc(text, DATE_FORMATS).isValid(); + }; + + UTCTimeSystem.prototype.now = function () { + return this.nowFn(); + }; + + UTCTimeSystem.prototype.increment = function (scale) { + var index = (scale || 0) + DEFAULT_INCREMENT; + index = Math.max(index, 0); + index = Math.min(index, INCREMENTS.length - 1); + return INCREMENTS[index]; + }; + + return UTCTimeSystem; +}); From 5e9f38dadd87bf38330df2bbafe34edcb0afc18e Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 22 Oct 2015 15:20:54 -0700 Subject: [PATCH 13/79] [Time Conductor] Add dependency to UTCTimeProvider --- platform/time/bundle.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/time/bundle.json b/platform/time/bundle.json index 9ab4fb1e97..9e831b5723 100644 --- a/platform/time/bundle.json +++ b/platform/time/bundle.json @@ -11,7 +11,8 @@ { "provides": "timeService", "type": "provider", - "implementation": "UTCTimeProvider.js" + "implementation": "UTCTimeProvider.js", + "depends": [ "now" ] } ] } From 1e71df5ce9cb9636a41ff2564ece27dad01b607e Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 22 Oct 2015 15:26:22 -0700 Subject: [PATCH 14/79] [Time Conductor] Implement timeService in sinewave telemetry Switch from initial dateService interface to more practical timeService interface. --- example/generator/bundle.json | 4 +- ...ateProvider.js => SinewaveTimeProvider.js} | 23 ++++---- example/generator/src/SinewaveTimeSystem.js | 55 +++++++++++++++++++ 3 files changed, 67 insertions(+), 15 deletions(-) rename example/generator/src/{SinewaveDateProvider.js => SinewaveTimeProvider.js} (73%) create mode 100644 example/generator/src/SinewaveTimeSystem.js diff --git a/example/generator/bundle.json b/example/generator/bundle.json index b2050e07e9..6a182e6a7a 100644 --- a/example/generator/bundle.json +++ b/example/generator/bundle.json @@ -10,9 +10,9 @@ "depends": [ "$q", "$timeout" ] }, { - "implementation": "SinewaveDateProvider.js", + "implementation": "SinewaveTimeProvider.js", "type": "provider", - "provides": "dateService" + "provides": "timeService" } ], "capabilities": [ diff --git a/example/generator/src/SinewaveDateProvider.js b/example/generator/src/SinewaveTimeProvider.js similarity index 73% rename from example/generator/src/SinewaveDateProvider.js rename to example/generator/src/SinewaveTimeProvider.js index 9b819a8796..2f2bcc2391 100644 --- a/example/generator/src/SinewaveDateProvider.js +++ b/example/generator/src/SinewaveTimeProvider.js @@ -22,7 +22,9 @@ /*global define*/ define([ + './SinewaveTimeSystem' ], function ( + SinewaveTimeSystem ) { "use strict"; @@ -32,24 +34,19 @@ define([ * not necessarily be formatted as UTC dates. * @memberof example/generator * @constructor - * @implements {DateService} + * @implements {TimeService} */ - function SinewaveDateProvider() { + function SinewaveTimeProvider() { + this.indexTimeSystem = new SinewaveTimeSystem(); } - SinewaveDateProvider.prototype.validate = function (text, key) { - return key === 'generator.index' && /^#\d+$/.test(text); + SinewaveTimeProvider.prototype.systems = function () { + return [ 'generator.index' ]; }; - SinewaveDateProvider.prototype.format = function (value, key) { - return key === 'generator.index' ? - ('#' + Math.floor(value)) : - undefined; + SinewaveTimeProvider.prototype.system = function (key) { + return key === 'generator.index' ? this.indexTimeSystem : undefined; }; - SinewaveDateProvider.prototype.parse = function (text, key) { - return key === 'generator.index' && parseInt(key.substring(1), 10); - }; - - return SinewaveDateProvider; + return SinewaveTimeProvider; }); diff --git a/example/generator/src/SinewaveTimeSystem.js b/example/generator/src/SinewaveTimeSystem.js new file mode 100644 index 0000000000..c248de4bfd --- /dev/null +++ b/example/generator/src/SinewaveTimeSystem.js @@ -0,0 +1,55 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ +/*global define*/ + +define([ + './SinewaveTelemetrySeries' +], function ( + SinewaveTelemetrySeries +) { + "use strict"; + + function SinewaveTimeSystem(now) { + } + + SinewaveTimeSystem.prototype.format = function (value) { + return ('#' + Math.floor(value)); + }; + + SinewaveTimeSystem.prototype.parse = function (text) { + return parseInt(text.substring(1), 10); + }; + + SinewaveTimeSystem.prototype.validate = function (text) { + return (/^#\d+$/).test(text); + }; + + SinewaveTimeSystem.prototype.now = function () { + return new SinewaveTelemetrySeries().getPointCount(); + }; + + SinewaveTimeSystem.prototype.increment = function (scale) { + return Math.pow(10, (scale || 0) + 1); + }; + + return SinewaveTimeSystem; +}); From a154c9c8708580cc376adceb3777ef312858b6ac Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 22 Oct 2015 15:51:12 -0700 Subject: [PATCH 15/79] [Time Conductor] Use timeService from control --- bundles.json | 1 + example/generator/src/SinewaveTimeSystem.js | 4 +- platform/commonUI/general/bundle.json | 2 +- .../templates/controls/time-controller.html | 2 +- .../src/controllers/TimeRangeController.js | 41 ++++++++++++++----- 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/bundles.json b/bundles.json index a0f7edd7a8..3c2eb90340 100644 --- a/bundles.json +++ b/bundles.json @@ -26,6 +26,7 @@ "platform/policy", "platform/entanglement", "platform/search", + "platform/time", "example/imagery", "example/eventGenerator", diff --git a/example/generator/src/SinewaveTimeSystem.js b/example/generator/src/SinewaveTimeSystem.js index c248de4bfd..24a9e35e62 100644 --- a/example/generator/src/SinewaveTimeSystem.js +++ b/example/generator/src/SinewaveTimeSystem.js @@ -44,11 +44,11 @@ define([ }; SinewaveTimeSystem.prototype.now = function () { - return new SinewaveTelemetrySeries().getPointCount(); + return new SinewaveTelemetrySeries({}).getPointCount(); }; SinewaveTimeSystem.prototype.increment = function (scale) { - return Math.pow(10, (scale || 0) + 1); + return Math.max(Math.pow(10, (scale || 0) + 1), 1); }; return SinewaveTimeSystem; diff --git a/platform/commonUI/general/bundle.json b/platform/commonUI/general/bundle.json index 05c86cbcf7..c0f5141694 100644 --- a/platform/commonUI/general/bundle.json +++ b/platform/commonUI/general/bundle.json @@ -66,7 +66,7 @@ { "key": "TimeRangeController", "implementation": "controllers/TimeRangeController.js", - "depends": [ "$scope", "dateService", "now" ] + "depends": [ "$scope", "timeService", "now" ] }, { "key": "DateTimePickerController", diff --git a/platform/commonUI/general/res/templates/controls/time-controller.html b/platform/commonUI/general/res/templates/controls/time-controller.html index 87b6c682b2..5b41beeebf 100644 --- a/platform/commonUI/general/res/templates/controls/time-controller.html +++ b/platform/commonUI/general/res/templates/controls/time-controller.html @@ -102,7 +102,7 @@
diff --git a/platform/commonUI/general/src/controllers/TimeRangeController.js b/platform/commonUI/general/src/controllers/TimeRangeController.js index 5f2f0fa3e6..27efeeb3fc 100644 --- a/platform/commonUI/general/src/controllers/TimeRangeController.js +++ b/platform/commonUI/general/src/controllers/TimeRangeController.js @@ -34,24 +34,20 @@ define( * @memberof platform/commonUI/general * @constructor */ - function TimeRangeController($scope, dateService, now) { + function TimeRangeController($scope, timeService, now) { var tickCount = 2, innerMinimumSpan = 1000, // 1 second outerMinimumSpan = 1000 * 60 * 60, // 1 hour - initialDragValue; - - function timeSystemKey() { - return ($scope.parameters || {}).system; - } + initialDragValue, + timeSystem = timeService.system(); // Start with default function formatTimestamp(ts) { - return dateService.format(ts, timeSystemKey()); + return timeSystem.format(ts); } function parseTimestamp(text) { - var key = timeSystemKey(); - if (dateService.validate(text, key)) { - return dateService.parse(text, key); + if (timeSystem.validate(text)) { + return timeSystem.parse(text); } else { throw new Error("Could not parse " + text); } @@ -270,6 +266,30 @@ define( } } + function reinitializeBounds(now, increment) { + var end = Math.ceil(now / increment) * increment, + start = end - increment; + $scope.ngModel.outer.start = start; + $scope.ngModel.outer.end = end; + $scope.ngModel.inner.start = start; + $scope.ngModel.inner.end = end; + $scope.boundsModel = {}; + updateViewFromModel(); + } + + function updateTimeSystem(key) { + timeSystem = timeService.system(key) || timeService.system(); + + // One second / one hour in UTC; should be + // similarly useful in other time systems. + innerMinimumSpan = timeSystem.increment(-3); + outerMinimumSpan = timeSystem.increment(-1); + reinitializeBounds( + timeSystem.now(), + timeSystem.increment() + ); + } + function updateStartFromPicker(value) { updateOuterStart(value); updateBoundsText($scope.ngModel); @@ -300,6 +320,7 @@ define( $scope.$watch("ngModel.outer.end", updateEndFromPicker); $scope.$watch("boundsModel.start", updateStartFromText); $scope.$watch("boundsModel.end", updateEndFromText); + $scope.$watch("parameters.system", updateTimeSystem); } return TimeRangeController; From 16e4c327095d9a61dbd2b698bea32a2b8050de20 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 22 Oct 2015 16:05:09 -0700 Subject: [PATCH 16/79] [Time Conductor] Remove now dependency, fix domain switch Remove dependency on now (current time can be retrieved via timeService); fix domain-switching behavior such that changes to time systems are reflected in changes to default bounds. --- platform/commonUI/general/bundle.json | 2 +- .../general/src/controllers/TimeRangeController.js | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/platform/commonUI/general/bundle.json b/platform/commonUI/general/bundle.json index c0f5141694..30057dcff1 100644 --- a/platform/commonUI/general/bundle.json +++ b/platform/commonUI/general/bundle.json @@ -66,7 +66,7 @@ { "key": "TimeRangeController", "implementation": "controllers/TimeRangeController.js", - "depends": [ "$scope", "timeService", "now" ] + "depends": [ "$scope", "timeService" ] }, { "key": "DateTimePickerController", diff --git a/platform/commonUI/general/src/controllers/TimeRangeController.js b/platform/commonUI/general/src/controllers/TimeRangeController.js index 27efeeb3fc..321698c1b9 100644 --- a/platform/commonUI/general/src/controllers/TimeRangeController.js +++ b/platform/commonUI/general/src/controllers/TimeRangeController.js @@ -34,7 +34,7 @@ define( * @memberof platform/commonUI/general * @constructor */ - function TimeRangeController($scope, timeService, now) { + function TimeRangeController($scope, timeService) { var tickCount = 2, innerMinimumSpan = 1000, // 1 second outerMinimumSpan = 1000 * 60 * 60, // 1 hour @@ -91,7 +91,7 @@ define( } function defaultBounds() { - var t = now(); + var t = timeSystem.now(); return { start: t - 24 * 3600 * 1000, // One day end: t @@ -122,8 +122,6 @@ define( } function updateViewFromModel(ngModel) { - var t = now(); - ngModel = ngModel || {}; ngModel.outer = ngModel.outer || defaultBounds(); ngModel.inner = ngModel.inner || copyBounds(ngModel.outer); @@ -274,7 +272,7 @@ define( $scope.ngModel.inner.start = start; $scope.ngModel.inner.end = end; $scope.boundsModel = {}; - updateViewFromModel(); + updateViewFromModel($scope.ngModel); } function updateTimeSystem(key) { From b4dd95490c6ee216c23855b87c0749024678767f Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 22 Oct 2015 16:07:21 -0700 Subject: [PATCH 17/79] [Time Conductor] Don't treat defaults as invalid --- .../commonUI/general/src/controllers/TimeRangeController.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/commonUI/general/src/controllers/TimeRangeController.js b/platform/commonUI/general/src/controllers/TimeRangeController.js index 321698c1b9..550ea49175 100644 --- a/platform/commonUI/general/src/controllers/TimeRangeController.js +++ b/platform/commonUI/general/src/controllers/TimeRangeController.js @@ -109,6 +109,9 @@ define( ngModel.outer[property]) { $scope.boundsModel[property] = formatTimestamp(ngModel.outer[property]); + // Never want to flag machine-generated text + // as invalid here. + $scope.boundsModel[property + 'Valid'] = true; } } catch (e) { // User-entered text is invalid, so leave it be From 67cf8d8cee1daf1ec7df41c595ff2e59861516d8 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 22 Oct 2015 16:24:55 -0700 Subject: [PATCH 18/79] [Time Conductor] Support index domain from sine wave --- example/generator/src/SinewaveTelemetrySeries.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/example/generator/src/SinewaveTelemetrySeries.js b/example/generator/src/SinewaveTelemetrySeries.js index 17084a07da..529d4e80a2 100644 --- a/example/generator/src/SinewaveTelemetrySeries.js +++ b/example/generator/src/SinewaveTelemetrySeries.js @@ -49,6 +49,11 @@ define( Math.max(Math.floor(request.start / 1000), firstTime), offset = requestStart - firstTime; + if (request.domain === 'index') { + offset = Math.floor(request.start || 0); + count = Math.ceil(request.end || endTime); + } + if (request.size !== undefined) { offset = Math.max(offset, count - request.size); } @@ -59,7 +64,7 @@ define( generatorData.getDomainValue = function (i, domain) { if (domain === 'index') { - return i; + return i + offset; } return (i + offset) * 1000 + firstTime * 1000 - (domain === 'yesterday' ? ONE_DAY : 0); From 111b3bac09a841235274cc8564dc6425f31a0b65 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 22 Oct 2015 16:27:21 -0700 Subject: [PATCH 19/79] [Time Conductor] Remove dateService Replaced by timeService --- platform/commonUI/general/bundle.json | 13 -- .../general/src/services/DateAggregator.js | 118 ------------------ .../general/src/services/UTCDateProvider.js | 64 ---------- .../test/services/DateAggregatorSpec.js | 94 -------------- .../test/services/UTCDateProviderSpec.js | 67 ---------- platform/commonUI/general/test/suite.json | 2 - 6 files changed, 358 deletions(-) delete mode 100644 platform/commonUI/general/src/services/DateAggregator.js delete mode 100644 platform/commonUI/general/src/services/UTCDateProvider.js delete mode 100644 platform/commonUI/general/test/services/DateAggregatorSpec.js delete mode 100644 platform/commonUI/general/test/services/UTCDateProviderSpec.js diff --git a/platform/commonUI/general/bundle.json b/platform/commonUI/general/bundle.json index 30057dcff1..a4d4008f3d 100644 --- a/platform/commonUI/general/bundle.json +++ b/platform/commonUI/general/bundle.json @@ -15,19 +15,6 @@ "depends": [ "$document", "$window" ] } ], - "components": [ - { - "type": "aggregator", - "provides": "dateService", - "implementation": "services/DateAggregator.js" - }, - { - "type": "provider", - "provides": "dateService", - "implementation": "services/UTCDateProvider.js", - "priority": "fallback" - } - ], "runs": [ { "implementation": "StyleSheetLoader.js", diff --git a/platform/commonUI/general/src/services/DateAggregator.js b/platform/commonUI/general/src/services/DateAggregator.js deleted file mode 100644 index ee01929b27..0000000000 --- a/platform/commonUI/general/src/services/DateAggregator.js +++ /dev/null @@ -1,118 +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. - *****************************************************************************/ -/*global define*/ - -define([ - -], function ( -) { - "use strict"; - - /** - * Formats dates for display and parses dates from user input, - * varying by a chosen time system. - * - * Time systems are typically specified as `system` properties - * of domains in {@link TelemetryDomainMetadata}. - * - * If omitted/left undefined, the time system is presumed to be UTC time, - * with its numeric interpretation being milliseconds since the - * start of 1970. - * - * @interface DateService - */ - - /** - * Check if the provided text can be parsed into a numeric - * representation of a time in the specified time system. - * @method validate - * @memberof DateService# - * @param {string} text the text to validate - * @param {string} [key] a key identifying the time system - * @returns {boolean} true if the text can be parsed - */ - - /** - * Parse the provided into a numeric representation of a time - * in the specified time system. - * - * Behavior of this method for invalid text is undefined; use - * the `validate` method to check for validity first. - * - * @method parse - * @memberof DateService# - * @param {string} text the text to parse - * @param {string} [key] a key identifying the time system - * @returns {number} a numeric representation of the date/time - */ - - /** - * Format the provided numeric representation of a time - * into a human-readable string appropriate for that time system. - * - * If the time system is not recognized, the return value will be - * `undefined`. - * - * @method format - * @memberof DateService# - * @param {number} value the time value to format - * @param {string} [key] a key identifying the time system - * @returns {string} a human-readable representation of the date/time - */ - - /** - * Composites multiple DateService implementations such that - * they can be used as one. - * @memberof platform/commonUI/general - * @constructor - */ - function DateAggregator(dateProviders) { - this.dateProviders = dateProviders; - } - - DateAggregator.prototype.validate = function (text, key) { - return this.dateProviders.some(function (provider) { - return provider.validate(text, key); - }); - }; - - DateAggregator.prototype.format = function (value, key) { - var i, text; - for (i = 0; i < this.dateProviders.length; i += 1) { - text = this.dateProviders[i].format(value, key); - if (text !== undefined) { - return text; - } - } - }; - - DateAggregator.prototype.parse = function (text, key) { - var i; - for (i = 0; i < this.dateProviders.length; i += 1) { - if (this.dateProviders[i].validate(text, key)) { - return this.dateProviders[i].parse(text, key); - } - } - }; - - return DateAggregator; -}); diff --git a/platform/commonUI/general/src/services/UTCDateProvider.js b/platform/commonUI/general/src/services/UTCDateProvider.js deleted file mode 100644 index 38b6c61b8b..0000000000 --- a/platform/commonUI/general/src/services/UTCDateProvider.js +++ /dev/null @@ -1,64 +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. - *****************************************************************************/ -/*global define*/ - -define([ - 'moment' -], function ( - moment -) { - "use strict"; - - var DATE_FORMAT = "YYYY-MM-DD HH:mm:ss", - DATE_FORMATS = [ - DATE_FORMAT, - "YYYY-MM-DD HH:mm:ss", - "YYYY-MM-DD HH:mm", - "YYYY-MM-DD" - ]; - - /** - * Composites multiple DateService implementations such that - * they can be used as one. - * @memberof platform/commonUI/general - * @constructor - * @implements {DateService} - */ - function UTCDateProvider() { - } - - UTCDateProvider.prototype.validate = function (text, key) { - return key === undefined && moment.utc(text, DATE_FORMATS).isValid(); - }; - - UTCDateProvider.prototype.format = function (value, key) { - return key === undefined ? - moment.utc(value).format(DATE_FORMAT) : - undefined; - }; - - UTCDateProvider.prototype.parse = function (text, key) { - return key === undefined && moment.utc(text, DATE_FORMATS).valueOf(); - }; - - return UTCDateProvider; -}); diff --git a/platform/commonUI/general/test/services/DateAggregatorSpec.js b/platform/commonUI/general/test/services/DateAggregatorSpec.js deleted file mode 100644 index ba55bc907a..0000000000 --- a/platform/commonUI/general/test/services/DateAggregatorSpec.js +++ /dev/null @@ -1,94 +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. - *****************************************************************************/ -/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/ - - -define( - ["../../src/services/DateAggregator"], - function (DateAggregator) { - 'use strict'; - - var DATE_SERVICE_METHODS = [ "format", "validate", "parse" ]; - - describe("DateAggregator", function () { - var mockProviders, - dateAggregator; - - beforeEach(function () { - mockProviders = [ 'a', 'b', 'c', undefined ].map(function (k, i) { - var mockProvider = jasmine.createSpyObj( - 'provider-' + k, - DATE_SERVICE_METHODS - ); - - mockProvider.format.andCallFake(function (value, key) { - return key === k ? - ("Formatted " + value + " for " + k) : - undefined; - }); - - mockProvider.parse.andCallFake(function (text, key) { - return key === k ? i : undefined; - }); - - mockProvider.validate.andCallFake(function (text, key) { - return key === k; - }); - - return mockProvider; - }); - - dateAggregator = new DateAggregator(mockProviders); - }); - - it("formats dates using the first provider which gives a result", function () { - expect(dateAggregator.format(42, "a")) - .toEqual("Formatted 42 for a"); - expect(dateAggregator.format(12321, "b")) - .toEqual("Formatted 12321 for b"); - expect(dateAggregator.format(1977, "c")) - .toEqual("Formatted 1977 for c"); - expect(dateAggregator.format(0)) - .toEqual("Formatted 0 for undefined"); - }); - - it("parses dates using the first provider which validates", function () { - expect(dateAggregator.parse("x", "a")).toEqual(0); - expect(dateAggregator.parse("x", "b")).toEqual(1); - expect(dateAggregator.parse("x", "c")).toEqual(2); - expect(dateAggregator.parse("x")).toEqual(3); - }); - - it("validates across all providers", function () { - expect(dateAggregator.validate("x", "a")).toBeTruthy(); - expect(dateAggregator.validate("x", "b")).toBeTruthy(); - expect(dateAggregator.validate("x", "c")).toBeTruthy(); - expect(dateAggregator.validate("x")).toBeTruthy(); - expect(dateAggregator.validate("x", "z")).toBeFalsy(); - - mockProviders[3].validate.andReturn(false); - expect(dateAggregator.validate("x")).toBeFalsy(); - }); - - }); - } -); diff --git a/platform/commonUI/general/test/services/UTCDateProviderSpec.js b/platform/commonUI/general/test/services/UTCDateProviderSpec.js deleted file mode 100644 index 1a1873030d..0000000000 --- a/platform/commonUI/general/test/services/UTCDateProviderSpec.js +++ /dev/null @@ -1,67 +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. - *****************************************************************************/ -/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/ - - -define( - ["../../src/services/UTCDateProvider", "moment"], - function (UTCDateProvider, moment) { - 'use strict'; - - describe("UTCDateProvider", function () { - var testDate, testTimestamp, dateProvider; - - beforeEach(function () { - testDate = "1977-05-25 17:30:00"; - testTimestamp = moment.utc(testDate).valueOf(); - dateProvider = new UTCDateProvider(); - }); - - it("distinguishes valid dates from invalid dates", function () { - expect(dateProvider.validate(testDate)) - .toBeTruthy(); - expect(dateProvider.validate("2015-garbage :00:00")) - .toBeFalsy(); - }); - - it("parses dates to their numeric representations", function () { - expect(dateProvider.parse(testDate)).toEqual(testTimestamp); - }); - - it("formats to text representing UTC date/times", function () { - var formatted = dateProvider.format(testTimestamp); - expect(formatted).toEqual(jasmine.any(String)); - // Use moment to verify that formatted value is equal - // to the original date/time - expect(moment.utc(formatted).valueOf()).toEqual(testTimestamp); - }); - - it("does not handle defined keys", function () { - expect(dateProvider.validate(testDate, 'someKey')) - .toBeFalsy(); - expect(dateProvider.format(testTimestamp, 'someKey')) - .toBeUndefined(); - }); - - }); - } -); diff --git a/platform/commonUI/general/test/suite.json b/platform/commonUI/general/test/suite.json index 9f80aaabc2..0d19fbb9e4 100644 --- a/platform/commonUI/general/test/suite.json +++ b/platform/commonUI/general/test/suite.json @@ -17,8 +17,6 @@ "directives/MCTPopup", "directives/MCTResize", "directives/MCTScroll", - "services/DateAggregator", - "services/UTCDateProvider", "services/Popup", "services/PopupService", "services/UrlService", From c45bf454752d178c491fcd8c8a578e757a9a6266 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 26 Oct 2015 09:45:01 -0700 Subject: [PATCH 20/79] [Time Conductor] Remove non-format-like methods ...from UTCTimeSystem, and rename to UTCTimeFormat. Per code review feedback from nasa/openmctweb#182. --- platform/time/bundle.json | 6 +++ .../{UTCTimeSystem.js => UTCTimeFormat.js} | 41 +++---------------- 2 files changed, 12 insertions(+), 35 deletions(-) rename platform/time/src/{UTCTimeSystem.js => UTCTimeFormat.js} (63%) diff --git a/platform/time/bundle.json b/platform/time/bundle.json index 9e831b5723..164341c9b0 100644 --- a/platform/time/bundle.json +++ b/platform/time/bundle.json @@ -14,6 +14,12 @@ "implementation": "UTCTimeProvider.js", "depends": [ "now" ] } + ], + "formats": [ + { + "key": "utc", + "implementation": "UTCTimeFormat.js" + } ] } } diff --git a/platform/time/src/UTCTimeSystem.js b/platform/time/src/UTCTimeFormat.js similarity index 63% rename from platform/time/src/UTCTimeSystem.js rename to platform/time/src/UTCTimeFormat.js index 22c3488b50..43028d7e97 100644 --- a/platform/time/src/UTCTimeSystem.js +++ b/platform/time/src/UTCTimeFormat.js @@ -34,52 +34,23 @@ define([ "YYYY-MM-DD HH:mm:ss", "YYYY-MM-DD HH:mm", "YYYY-MM-DD" - ], - SECOND = 1000, - MINUTE = 60 * SECOND, - HOUR = 60 * MINUTE, - DAY = 24 * HOUR, - WEEK = 7 * DAY, - MONTH_APPROX = 30 * DAY, - YEAR = 365 * DAY, - INCREMENTS = [ - SECOND, - MINUTE, - HOUR, - DAY, - WEEK, - MONTH_APPROX, - YEAR - ], - DEFAULT_INCREMENT = 3; + ]; - function UTCTimeSystem(now) { - this.nowFn = now; + function UTCTimeFormat() { } - UTCTimeSystem.prototype.format = function (value) { + UTCTimeFormat.prototype.format = function (value) { return moment.utc(value).format(DATE_FORMAT); }; - UTCTimeSystem.prototype.parse = function (text) { + UTCTimeFormat.prototype.parse = function (text) { return moment.utc(text, DATE_FORMATS).valueOf(); }; - UTCTimeSystem.prototype.validate = function (text) { + UTCTimeFormat.prototype.validate = function (text) { return moment.utc(text, DATE_FORMATS).isValid(); }; - UTCTimeSystem.prototype.now = function () { - return this.nowFn(); - }; - - UTCTimeSystem.prototype.increment = function (scale) { - var index = (scale || 0) + DEFAULT_INCREMENT; - index = Math.max(index, 0); - index = Math.min(index, INCREMENTS.length - 1); - return INCREMENTS[index]; - }; - - return UTCTimeSystem; + return UTCTimeFormat; }); From 322d1c8389b59fbbcb20a739c61270d435ea5418 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 26 Oct 2015 09:54:57 -0700 Subject: [PATCH 21/79] [Time Conductor] Add formatProvider ...to handle lookup of extensions of category 'formats' --- platform/time/src/FormatProvider.js | 51 +++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 platform/time/src/FormatProvider.js diff --git a/platform/time/src/FormatProvider.js b/platform/time/src/FormatProvider.js new file mode 100644 index 0000000000..9e09591de0 --- /dev/null +++ b/platform/time/src/FormatProvider.js @@ -0,0 +1,51 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ +/*global define*/ + +define([ + +], function ( + +) { + "use strict"; + + function FormatProvider(formats) { + var formatMap = {}; + + function addToMap(Format) { + var key = Format.key; + if (key && !formatMap[key]) { + formatMap[key] = new Format(); + } + } + + formats.forEach(addToMap); + this.formatMap = formatMap; + } + + FormatProvider.getFormat = function (key) { + return this.formatMap[key]; + }; + + return FormatProvider; + +}); From f8ee244475a04d23d9a97d5df0e6ba82bcabcdd2 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 26 Oct 2015 09:56:37 -0700 Subject: [PATCH 22/79] [Time Conductor] Expose FormatProvider --- platform/time/bundle.json | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/platform/time/bundle.json b/platform/time/bundle.json index 164341c9b0..a93e6f0de3 100644 --- a/platform/time/bundle.json +++ b/platform/time/bundle.json @@ -4,15 +4,10 @@ "extensions": { "components": [ { - "provides": "timeService", - "type": "aggregator", - "implementation": "TimeAggregator.js" - }, - { - "provides": "timeService", + "provides": "formatService", "type": "provider", - "implementation": "UTCTimeProvider.js", - "depends": [ "now" ] + "implementation": "FormatProvider.js", + "depends": "formats[]" } ], "formats": [ From 0f34d38451c67bf2fbc4f54b994159ea3ac335cc Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 26 Oct 2015 09:57:14 -0700 Subject: [PATCH 23/79] [Time Conductor] Remove obsolete formatting classes --- platform/time/src/TimeAggregator.js | 57 ---------------------------- platform/time/src/UTCTimeProvider.js | 44 --------------------- 2 files changed, 101 deletions(-) delete mode 100644 platform/time/src/TimeAggregator.js delete mode 100644 platform/time/src/UTCTimeProvider.js diff --git a/platform/time/src/TimeAggregator.js b/platform/time/src/TimeAggregator.js deleted file mode 100644 index f3e0d5cfc3..0000000000 --- a/platform/time/src/TimeAggregator.js +++ /dev/null @@ -1,57 +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. - *****************************************************************************/ -/*global define*/ - -define([ - -], function ( - -) { - "use strict"; - - function TimeAggregator(timeProviders) { - var systemMap = {}, - systemKeys = []; - - timeProviders.forEach(function (provider) { - provider.systems().forEach(function (key) { - if (!systemMap[key]) { - systemMap[key] = provider.system(key); - systemKeys.push(key); - } - }); - }); - - this.systemMap = systemMap; - this.systemKeys = systemKeys; - } - - TimeAggregator.prototype.systems = function () { - return this.systemKeys; - }; - - TimeAggregator.prototype.system = function (key) { - return this.systemMap[key || 'utc']; - }; - - return TimeAggregator; -}); diff --git a/platform/time/src/UTCTimeProvider.js b/platform/time/src/UTCTimeProvider.js deleted file mode 100644 index 36c266c621..0000000000 --- a/platform/time/src/UTCTimeProvider.js +++ /dev/null @@ -1,44 +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. - *****************************************************************************/ -/*global define*/ - -define([ - './UTCTimeSystem' -], function ( - UTCTimeSystem -) { - "use strict"; - - function UTCTimeProvider(now) { - this.utcTimeSystem = new UTCTimeSystem(now); - } - - UTCTimeProvider.prototype.systems = function () { - return [ 'utc' ]; - }; - - UTCTimeProvider.prototype.system = function (key) { - return key === 'utc' ? this.utcTimeSystem : undefined; - }; - - return UTCTimeProvider; -}); From aa23d358cc91c5e503a6cf53c8211bd89582b1e0 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 26 Oct 2015 10:03:49 -0700 Subject: [PATCH 24/79] [Time Conductor] Use formatService instead of timeService --- platform/commonUI/general/bundle.json | 2 +- .../src/controllers/TimeRangeController.js | 30 +++++++------------ 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/platform/commonUI/general/bundle.json b/platform/commonUI/general/bundle.json index a4d4008f3d..800fa8e5ea 100644 --- a/platform/commonUI/general/bundle.json +++ b/platform/commonUI/general/bundle.json @@ -53,7 +53,7 @@ { "key": "TimeRangeController", "implementation": "controllers/TimeRangeController.js", - "depends": [ "$scope", "timeService" ] + "depends": [ "$scope", "formatService", "now" ] }, { "key": "DateTimePickerController", diff --git a/platform/commonUI/general/src/controllers/TimeRangeController.js b/platform/commonUI/general/src/controllers/TimeRangeController.js index 550ea49175..97bb05e71f 100644 --- a/platform/commonUI/general/src/controllers/TimeRangeController.js +++ b/platform/commonUI/general/src/controllers/TimeRangeController.js @@ -26,7 +26,7 @@ define( function (moment) { "use strict"; - var DATE_FORMAT = "YYYY-MM-DD HH:mm:ss", + var DEFAULT_FORMAT = "utc", TICK_SPACING_PX = 150; /** @@ -34,20 +34,20 @@ define( * @memberof platform/commonUI/general * @constructor */ - function TimeRangeController($scope, timeService) { + function TimeRangeController($scope, formatService, now) { var tickCount = 2, innerMinimumSpan = 1000, // 1 second outerMinimumSpan = 1000 * 60 * 60, // 1 hour initialDragValue, - timeSystem = timeService.system(); // Start with default + formatter = formatService.getFormat(DEFAULT_FORMAT); function formatTimestamp(ts) { - return timeSystem.format(ts); + return formatter.format(ts); } function parseTimestamp(text) { - if (timeSystem.validate(text)) { - return timeSystem.parse(text); + if (formatter.validate(text)) { + return formatter.parse(text); } else { throw new Error("Could not parse " + text); } @@ -91,7 +91,7 @@ define( } function defaultBounds() { - var t = timeSystem.now(); + var t = now(); return { start: t - 24 * 3600 * 1000, // One day end: t @@ -278,17 +278,9 @@ define( updateViewFromModel($scope.ngModel); } - function updateTimeSystem(key) { - timeSystem = timeService.system(key) || timeService.system(); - - // One second / one hour in UTC; should be - // similarly useful in other time systems. - innerMinimumSpan = timeSystem.increment(-3); - outerMinimumSpan = timeSystem.increment(-1); - reinitializeBounds( - timeSystem.now(), - timeSystem.increment() - ); + function updateFormat(key) { + formatter = formatService.getFormat(key) || + formatService.getFormat(DEFAULT_FORMAT); } function updateStartFromPicker(value) { @@ -321,7 +313,7 @@ define( $scope.$watch("ngModel.outer.end", updateEndFromPicker); $scope.$watch("boundsModel.start", updateStartFromText); $scope.$watch("boundsModel.end", updateEndFromText); - $scope.$watch("parameters.system", updateTimeSystem); + $scope.$watch("parameters.format", updateFormat); } return TimeRangeController; From ed9a5b0890d59a311c8337c4f77a1e5e013f8fa6 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 26 Oct 2015 10:05:46 -0700 Subject: [PATCH 25/79] [Time Conductor] Roll back changes to example telemetry In particular, remove the timeService implementation; this is made obsolete by a switch to a simpler format-based approach. --- example/generator/bundle.json | 22 -------- .../generator/src/SinewaveTelemetrySeries.js | 8 --- example/generator/src/SinewaveTimeProvider.js | 52 ------------------ example/generator/src/SinewaveTimeSystem.js | 55 ------------------- 4 files changed, 137 deletions(-) delete mode 100644 example/generator/src/SinewaveTimeProvider.js delete mode 100644 example/generator/src/SinewaveTimeSystem.js diff --git a/example/generator/bundle.json b/example/generator/bundle.json index 6a182e6a7a..cdb4736957 100644 --- a/example/generator/bundle.json +++ b/example/generator/bundle.json @@ -8,11 +8,6 @@ "type": "provider", "provides": "telemetryService", "depends": [ "$q", "$timeout" ] - }, - { - "implementation": "SinewaveTimeProvider.js", - "type": "provider", - "provides": "timeService" } ], "capabilities": [ @@ -43,11 +38,6 @@ { "key": "yesterday", "name": "Yesterday" - }, - { - "key": "index", - "name": "Index", - "system": "generator.index" } ], "ranges": [ @@ -73,18 +63,6 @@ } ] } - ], - "constants": [ - { - "key": "TIME_CONDUCTOR_DOMAINS", - "value": [ - { "key": "time", "name": "Time" }, - { "key": "yesterday", "name": "Yesterday" }, - { "key": "index", "name": "Index", "system": "generator.index" } - ], - "priority": -1, - "comment": "Placeholder; to be replaced by inspection of available domains." - } ] } } diff --git a/example/generator/src/SinewaveTelemetrySeries.js b/example/generator/src/SinewaveTelemetrySeries.js index 529d4e80a2..1e84034766 100644 --- a/example/generator/src/SinewaveTelemetrySeries.js +++ b/example/generator/src/SinewaveTelemetrySeries.js @@ -49,11 +49,6 @@ define( Math.max(Math.floor(request.start / 1000), firstTime), offset = requestStart - firstTime; - if (request.domain === 'index') { - offset = Math.floor(request.start || 0); - count = Math.ceil(request.end || endTime); - } - if (request.size !== undefined) { offset = Math.max(offset, count - request.size); } @@ -63,9 +58,6 @@ define( }; generatorData.getDomainValue = function (i, domain) { - if (domain === 'index') { - return i + offset; - } return (i + offset) * 1000 + firstTime * 1000 - (domain === 'yesterday' ? ONE_DAY : 0); }; diff --git a/example/generator/src/SinewaveTimeProvider.js b/example/generator/src/SinewaveTimeProvider.js deleted file mode 100644 index 2f2bcc2391..0000000000 --- a/example/generator/src/SinewaveTimeProvider.js +++ /dev/null @@ -1,52 +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. - *****************************************************************************/ -/*global define*/ - -define([ - './SinewaveTimeSystem' -], function ( - SinewaveTimeSystem -) { - "use strict"; - - /** - * Provides date-time formatting for the Sine Wave Generator's - * `index` domain; demonstrates how to support domains which should - * not necessarily be formatted as UTC dates. - * @memberof example/generator - * @constructor - * @implements {TimeService} - */ - function SinewaveTimeProvider() { - this.indexTimeSystem = new SinewaveTimeSystem(); - } - - SinewaveTimeProvider.prototype.systems = function () { - return [ 'generator.index' ]; - }; - - SinewaveTimeProvider.prototype.system = function (key) { - return key === 'generator.index' ? this.indexTimeSystem : undefined; - }; - - return SinewaveTimeProvider; -}); diff --git a/example/generator/src/SinewaveTimeSystem.js b/example/generator/src/SinewaveTimeSystem.js deleted file mode 100644 index 24a9e35e62..0000000000 --- a/example/generator/src/SinewaveTimeSystem.js +++ /dev/null @@ -1,55 +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. - *****************************************************************************/ -/*global define*/ - -define([ - './SinewaveTelemetrySeries' -], function ( - SinewaveTelemetrySeries -) { - "use strict"; - - function SinewaveTimeSystem(now) { - } - - SinewaveTimeSystem.prototype.format = function (value) { - return ('#' + Math.floor(value)); - }; - - SinewaveTimeSystem.prototype.parse = function (text) { - return parseInt(text.substring(1), 10); - }; - - SinewaveTimeSystem.prototype.validate = function (text) { - return (/^#\d+$/).test(text); - }; - - SinewaveTimeSystem.prototype.now = function () { - return new SinewaveTelemetrySeries({}).getPointCount(); - }; - - SinewaveTimeSystem.prototype.increment = function (scale) { - return Math.max(Math.pow(10, (scale || 0) + 1), 1); - }; - - return SinewaveTimeSystem; -}); From 741fc574421c0c5c6a499adc06d54084b4208e2e Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 26 Oct 2015 10:39:51 -0700 Subject: [PATCH 26/79] [Time Conductor] Add alternate domain Begin adding a more timelike alternately-formatted domain to sine waves; the 'delta' can be expressed as UTC timestamps but will be formatted for display as a time relative to when sine wave generation began. --- example/generator/bundle.json | 11 +++ example/generator/src/SinewaveConstants.js | 26 +++++++ example/generator/src/SinewaveDeltaFormat.js | 68 +++++++++++++++++++ .../generator/src/SinewaveTelemetrySeries.js | 9 ++- 4 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 example/generator/src/SinewaveConstants.js create mode 100644 example/generator/src/SinewaveDeltaFormat.js diff --git a/example/generator/bundle.json b/example/generator/bundle.json index cdb4736957..aba210982c 100644 --- a/example/generator/bundle.json +++ b/example/generator/bundle.json @@ -16,6 +16,12 @@ "implementation": "SinewaveLimitCapability.js" } ], + "format": [ + { + "key": "example.delta", + "implementation": "SinewaveDeltaFormat.js" + } + ], "types": [ { "key": "generator", @@ -38,6 +44,11 @@ { "key": "yesterday", "name": "Yesterday" + }, + { + "key": "delta", + "name": "Delta", + "format": "example.delta" } ], "ranges": [ diff --git a/example/generator/src/SinewaveConstants.js b/example/generator/src/SinewaveConstants.js new file mode 100644 index 0000000000..29136ebb99 --- /dev/null +++ b/example/generator/src/SinewaveConstants.js @@ -0,0 +1,26 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ +/*global define,Promise*/ + +define({ + START_TIME: Date.now() - 24 * 60 * 60 * 1000 // Now minus a day. +}); diff --git a/example/generator/src/SinewaveDeltaFormat.js b/example/generator/src/SinewaveDeltaFormat.js new file mode 100644 index 0000000000..026e1b2ba3 --- /dev/null +++ b/example/generator/src/SinewaveDeltaFormat.js @@ -0,0 +1,68 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ +/*global define,Promise*/ + +define( + ['./SinewaveConstants', 'moment'], + function (SinewaveConstants, moment) { + "use strict"; + + var START_TIME = SinewaveConstants.START_TIME, + NUMBER_REGEX = /^\d+$/, + SECOND = 1000, + MINUTE = SECOND * 60, + HOUR = MINUTE * 60; + + function SinewaveDeltaFormat() { + } + + function twoDigit(v) { + return v >= 10 ? String(v) : ('0' + v); + } + + SinewaveDeltaFormat.prototype.format = function (value) { + var delta = value - START_TIME, + seconds = Math.floor(delta / SECOND) % 60, + minutes = Math.floor(delta / MINUTE) % 60, + hours = Math.floor(delta / HOUR); + return [ hours, minutes, seconds ].map(twoDigit).join(":"); + }; + + SinewaveDeltaFormat.prototype.validate = function (text) { + var parts = text.split(":"); + return parts.length === 3 && parts.every(function (part) { + return NUMBER_REGEX.test(part); + }); + }; + + SinewaveDeltaFormat.prototype.parse = function (text) { + var parts = text.split(":"); + return [ HOUR, MINUTE, SECOND ].map(function (sz, i) { + return parseInt(parts[i], 10) * sz; + }).reduce(function (a, b) { + return a + b; + }, 0); + }; + + return SinewaveDeltaFormat; + } +); diff --git a/example/generator/src/SinewaveTelemetrySeries.js b/example/generator/src/SinewaveTelemetrySeries.js index 1e84034766..f4e3f45293 100644 --- a/example/generator/src/SinewaveTelemetrySeries.js +++ b/example/generator/src/SinewaveTelemetrySeries.js @@ -25,12 +25,12 @@ * Module defining SinewaveTelemetry. Created by vwoeltje on 11/12/14. */ define( - [], - function () { + ['./SinewaveConstants'], + function (SinewaveConstants) { "use strict"; var ONE_DAY = 60 * 60 * 24, - firstObservedTime = Math.floor(Date.now() / 1000) - ONE_DAY; + firstObservedTime = SinewaveConstants.START_TIME; /** * @@ -58,6 +58,9 @@ define( }; generatorData.getDomainValue = function (i, domain) { + // delta uses the same numeric values as the default domain, + // so it's not checked for here, just formatted for display + // differently. return (i + offset) * 1000 + firstTime * 1000 - (domain === 'yesterday' ? ONE_DAY : 0); }; From 86c61f75430d098bc2e40f32f1a2d87dc48c05ec Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 09:41:32 -0700 Subject: [PATCH 27/79] [Time Conductor] Fix extension definition ...for FormatProvider. Depends should be an array. --- platform/time/bundle.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/time/bundle.json b/platform/time/bundle.json index a93e6f0de3..738ce1bb63 100644 --- a/platform/time/bundle.json +++ b/platform/time/bundle.json @@ -7,7 +7,7 @@ "provides": "formatService", "type": "provider", "implementation": "FormatProvider.js", - "depends": "formats[]" + "depends": [ "formats[]" ] } ], "formats": [ From c6b7121cf0201c3d2ad60518fe8017ce371052bd Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 09:45:17 -0700 Subject: [PATCH 28/79] [Time Conductor] Expose getFormat correctly ...as an instance method of FormatProvider --- platform/time/src/FormatProvider.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/time/src/FormatProvider.js b/platform/time/src/FormatProvider.js index 9e09591de0..27da9784fb 100644 --- a/platform/time/src/FormatProvider.js +++ b/platform/time/src/FormatProvider.js @@ -42,7 +42,7 @@ define([ this.formatMap = formatMap; } - FormatProvider.getFormat = function (key) { + FormatProvider.prototype.getFormat = function (key) { return this.formatMap[key]; }; From df6cd8f4034c226d816aeacfe3016d45d6be3561 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 09:50:59 -0700 Subject: [PATCH 29/79] [Time Conductor] Expose domain options ...for example telemetry, to test domain selection. --- example/generator/bundle.json | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/example/generator/bundle.json b/example/generator/bundle.json index aba210982c..1f821bb6bf 100644 --- a/example/generator/bundle.json +++ b/example/generator/bundle.json @@ -22,6 +22,17 @@ "implementation": "SinewaveDeltaFormat.js" } ], + "constants": [ + { + "key": "TIME_CONDUCTOR_DOMAINS", + "value": [ + { "key": "time", "name": "Time" }, + { "key": "yesterday", "name": "Yesterday" }, + { "key": "delta", "name": "Delta" } + ], + "priority": -1 + } + ], "types": [ { "key": "generator", From b928b7d3f2bc367f6bde0738f5f27cf8dd76a8a7 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 09:54:09 -0700 Subject: [PATCH 30/79] [Time Conductor] Fix time calculation in example telemetry --- example/generator/src/SinewaveTelemetrySeries.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/generator/src/SinewaveTelemetrySeries.js b/example/generator/src/SinewaveTelemetrySeries.js index f4e3f45293..fa47f8f59a 100644 --- a/example/generator/src/SinewaveTelemetrySeries.js +++ b/example/generator/src/SinewaveTelemetrySeries.js @@ -30,7 +30,7 @@ define( "use strict"; var ONE_DAY = 60 * 60 * 24, - firstObservedTime = SinewaveConstants.START_TIME; + firstObservedTime = Math.floor(SinewaveConstants.START_TIME / 1000); /** * From 2056f3aed012871b37698bf35b68b380992a173e Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 10:00:35 -0700 Subject: [PATCH 31/79] [Time Conductor] Update property name Renamed system to format per code review feedback, nasa/openmctweb#204 --- platform/features/conductor/src/ConductorRepresenter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/features/conductor/src/ConductorRepresenter.js b/platform/features/conductor/src/ConductorRepresenter.js index 900b121111..2eaa86b85b 100644 --- a/platform/features/conductor/src/ConductorRepresenter.js +++ b/platform/features/conductor/src/ConductorRepresenter.js @@ -102,8 +102,8 @@ define( function updateDomain(value) { var newDomain = conductor.domain(value); - conductorScope.parameters.system = - newDomain && newDomain.system; + conductorScope.parameters.format = + newDomain && newDomain.format; repScope.$broadcast('telemetry:display:bounds', bounds()); } From b627de45ba816533e85fde08e7c0756ec3b1ee30 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 10:01:24 -0700 Subject: [PATCH 32/79] [Time Conductor] Fix bundle definition ...such that the delta domain exposes its format, and its format is exposed correctly under the formats extension category. Supports testing of time conductor support for alternative time formatting. --- example/generator/bundle.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/generator/bundle.json b/example/generator/bundle.json index 1f821bb6bf..7cf1c7b6f2 100644 --- a/example/generator/bundle.json +++ b/example/generator/bundle.json @@ -16,7 +16,7 @@ "implementation": "SinewaveLimitCapability.js" } ], - "format": [ + "formats": [ { "key": "example.delta", "implementation": "SinewaveDeltaFormat.js" @@ -28,7 +28,7 @@ "value": [ { "key": "time", "name": "Time" }, { "key": "yesterday", "name": "Yesterday" }, - { "key": "delta", "name": "Delta" } + { "key": "delta", "name": "Delta", "format": "example.delta" } ], "priority": -1 } From 3bdaae292e606b57b61c6739323c609eca82f7f4 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 10:27:29 -0700 Subject: [PATCH 33/79] [Time Conductor] Parse deltas relative to generation start --- example/generator/src/SinewaveDeltaFormat.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/example/generator/src/SinewaveDeltaFormat.js b/example/generator/src/SinewaveDeltaFormat.js index 026e1b2ba3..1006e4b31d 100644 --- a/example/generator/src/SinewaveDeltaFormat.js +++ b/example/generator/src/SinewaveDeltaFormat.js @@ -40,11 +40,13 @@ define( } SinewaveDeltaFormat.prototype.format = function (value) { - var delta = value - START_TIME, + var delta = Math.abs(value - START_TIME), + negative = value < START_TIME, seconds = Math.floor(delta / SECOND) % 60, minutes = Math.floor(delta / MINUTE) % 60, hours = Math.floor(delta / HOUR); - return [ hours, minutes, seconds ].map(twoDigit).join(":"); + return (negative ? "-" : "") + + [ hours, minutes, seconds ].map(twoDigit).join(":"); }; SinewaveDeltaFormat.prototype.validate = function (text) { @@ -60,7 +62,7 @@ define( return parseInt(parts[i], 10) * sz; }).reduce(function (a, b) { return a + b; - }, 0); + }, SinewaveConstants.START_TIME); }; return SinewaveDeltaFormat; From 82b321b3f9ce1ca89a2c6e991c9ef91f4b14fd4a Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 10:27:54 -0700 Subject: [PATCH 34/79] [Time Conductor] Update displayed text when format changes --- .../src/controllers/TimeRangeController.js | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/platform/commonUI/general/src/controllers/TimeRangeController.js b/platform/commonUI/general/src/controllers/TimeRangeController.js index 97bb05e71f..ce53b7b1e7 100644 --- a/platform/commonUI/general/src/controllers/TimeRangeController.js +++ b/platform/commonUI/general/src/controllers/TimeRangeController.js @@ -267,20 +267,15 @@ define( } } - function reinitializeBounds(now, increment) { - var end = Math.ceil(now / increment) * increment, - start = end - increment; - $scope.ngModel.outer.start = start; - $scope.ngModel.outer.end = end; - $scope.ngModel.inner.start = start; - $scope.ngModel.inner.end = end; - $scope.boundsModel = {}; - updateViewFromModel($scope.ngModel); - } - function updateFormat(key) { formatter = formatService.getFormat(key) || formatService.getFormat(DEFAULT_FORMAT); + + // Assume that start/end are still valid, but clear + // the displayed text for bounds, since this will + // now be formatted differently. + $scope.boundsModel = {}; + updateViewFromModel($scope.ngModel); } function updateStartFromPicker(value) { From 3fe386fcd60e8f9a221c5cdb41487d10ef1c1c9e Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 11:21:44 -0700 Subject: [PATCH 35/79] [Time Conductor] Use formatService from telemetryFormatter --- platform/telemetry/bundle.json | 5 +++-- platform/telemetry/src/TelemetryFormatter.js | 21 ++++++++++---------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/platform/telemetry/bundle.json b/platform/telemetry/bundle.json index 69b32b54c7..79cf4d503a 100644 --- a/platform/telemetry/bundle.json +++ b/platform/telemetry/bundle.json @@ -37,7 +37,8 @@ "services": [ { "key": "telemetryFormatter", - "implementation": "TelemetryFormatter.js" + "implementation": "TelemetryFormatter.js", + "depends": [ "formatService" ] }, { "key": "telemetrySubscriber", @@ -63,4 +64,4 @@ } ] } -} \ No newline at end of file +} diff --git a/platform/telemetry/src/TelemetryFormatter.js b/platform/telemetry/src/TelemetryFormatter.js index bbd4cf100c..125d92710c 100644 --- a/platform/telemetry/src/TelemetryFormatter.js +++ b/platform/telemetry/src/TelemetryFormatter.js @@ -22,14 +22,13 @@ /*global define,moment*/ define( - ['moment'], - function (moment) { + [], + function () { "use strict"; // Date format to use for domain values; in particular, // use day-of-year instead of month/day - var DATE_FORMAT = "YYYY-DDD HH:mm:ss", - VALUE_FORMAT_DIGITS = 3; + var VALUE_FORMAT_DIGITS = 3; /** * The TelemetryFormatter is responsible for formatting (as text @@ -38,21 +37,23 @@ define( * @memberof platform/telemetry * @constructor */ - function TelemetryFormatter() { + function TelemetryFormatter(formatService) { + this.formatService = formatService; } /** * Format a domain value. - * @param {number} v the domain value; a timestamp + * @param {number} v the domain value; usually, a timestamp * in milliseconds since start of 1970 - * @param {string} [key] the key which identifies the - * domain; if unspecified or unknown, this will - * be treated as a standard timestamp. + * @param {string} [key] a key which identifies the format + * to use * @returns {string} a textual representation of the * data and time, suitable for display. */ TelemetryFormatter.prototype.formatDomainValue = function (v, key) { - return isNaN(v) ? "" : moment.utc(v).format(DATE_FORMAT); + var formatter = this.formatService.getFormat(key) || + this.formatService.getFormat('utc'); + return isNaN(v) ? "" : formatter.format(v); }; /** From 0bd1d53d2570192131b6f0011160ea12aa020138 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 11:22:19 -0700 Subject: [PATCH 36/79] [Time Conductor] Update plot to support different formats ...for telemetry domain values. --- platform/features/plot/src/PlotController.js | 24 ++++++++- platform/features/plot/src/SubPlot.js | 6 +-- .../features/plot/src/elements/PlotAxis.js | 10 ++++ .../src/elements/PlotTelemetryFormatter.js | 53 +++++++++++++++++++ .../plot/src/elements/PlotTickGenerator.js | 12 ++++- 5 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 platform/features/plot/src/elements/PlotTelemetryFormatter.js diff --git a/platform/features/plot/src/PlotController.js b/platform/features/plot/src/PlotController.js index 19aee9ca11..2aef3e3418 100644 --- a/platform/features/plot/src/PlotController.js +++ b/platform/features/plot/src/PlotController.js @@ -31,10 +31,19 @@ define( "./elements/PlotPalette", "./elements/PlotAxis", "./elements/PlotLimitTracker", + "./elements/PlotTelemetryFormatter", "./modes/PlotModeOptions", "./SubPlotFactory" ], - function (PlotUpdater, PlotPalette, PlotAxis, PlotLimitTracker, PlotModeOptions, SubPlotFactory) { + function ( + PlotUpdater, + PlotPalette, + PlotAxis, + PlotLimitTracker, + PlotTelemetryFormatter, + PlotModeOptions, + SubPlotFactory + ) { "use strict"; var AXIS_DEFAULTS = [ @@ -62,7 +71,10 @@ define( PLOT_FIXED_DURATION ) { var self = this, - subPlotFactory = new SubPlotFactory(telemetryFormatter), + plotTelemetryFormatter = + new PlotTelemetryFormatter(telemetryFormatter), + subPlotFactory = + new SubPlotFactory(plotTelemetryFormatter), cachedObjects = [], updater, lastBounds, @@ -189,6 +201,11 @@ define( releaseSubscription(); subscribe($scope.domainObject); setBasePanZoom(bounds); + $scope.axes[0].choose(bounds.domain); + } + + function updateDomainFormat(format) { + plotTelemetryFormatter.setDomainFormat(format); } this.modeOptions = new PlotModeOptions([], subPlotFactory); @@ -205,6 +222,9 @@ define( // Subscribe to telemetry when a domain object becomes available $scope.$watch('domainObject', subscribe); + // Reformat timestamps when needed + $scope.$watch('axes[0].active.format', updateDomainFormat); + // Respond to external bounds changes $scope.$on("telemetry:display:bounds", changeDisplayBounds); diff --git a/platform/features/plot/src/SubPlot.js b/platform/features/plot/src/SubPlot.js index dfcaadf352..051f95f2a8 100644 --- a/platform/features/plot/src/SubPlot.js +++ b/platform/features/plot/src/SubPlot.js @@ -121,9 +121,9 @@ define( // Utility, for map/forEach loops. Index 0 is domain, // index 1 is range. function formatValue(v, i) { - return (i ? - formatter.formatRangeValue : - formatter.formatDomainValue)(v); + return i ? + formatter.formatRangeValue(v) : + formatter.formatDomainValue(v); } this.hoverCoordinates = this.mousePosition && diff --git a/platform/features/plot/src/elements/PlotAxis.js b/platform/features/plot/src/elements/PlotAxis.js index 25795fd347..cee7acef8a 100644 --- a/platform/features/plot/src/elements/PlotAxis.js +++ b/platform/features/plot/src/elements/PlotAxis.js @@ -80,6 +80,16 @@ define( this.options = options; } + PlotAxis.prototype.choose = function (key) { + var i; + for (i = 0; i < this.options.length; i += 1) { + if (this.options[i].key === key) { + this.active = this.options[i]; + return; + } + } + }; + return PlotAxis; } diff --git a/platform/features/plot/src/elements/PlotTelemetryFormatter.js b/platform/features/plot/src/elements/PlotTelemetryFormatter.js new file mode 100644 index 0000000000..abe916e99d --- /dev/null +++ b/platform/features/plot/src/elements/PlotTelemetryFormatter.js @@ -0,0 +1,53 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ +/*global define*/ + +define( + [], + function () { + 'use strict'; + + function PlotTelemetryFormatter(telemetryFormatter) { + this.telemetryFormatter = telemetryFormatter; + } + + PlotTelemetryFormatter.prototype.setDomainFormat = function (key) { + this.domainFormat = key; + }; + + PlotTelemetryFormatter.prototype.setRangeFormat = function (key) { + this.rangeFormat = key; + }; + + PlotTelemetryFormatter.prototype.formatDomainValue = function (value) { + return this.telemetryFormatter + .formatDomainValue(value, this.domainFormat); + }; + + PlotTelemetryFormatter.prototype.formatRangeValue = function (value) { + return this.telemetryFormatter + .formatRangeValue(value, this.rangeFormat); + }; + + return PlotTelemetryFormatter; + } +); diff --git a/platform/features/plot/src/elements/PlotTickGenerator.js b/platform/features/plot/src/elements/PlotTickGenerator.js index f759b6bcd6..8fa957fae7 100644 --- a/platform/features/plot/src/elements/PlotTickGenerator.js +++ b/platform/features/plot/src/elements/PlotTickGenerator.js @@ -43,6 +43,14 @@ define( this.formatter = formatter; } + // For phantomjs compatibility, for headless testing + // (Function.prototype.bind unsupported) + function bind(fn, thisObj) { + return fn.bind ? fn.bind(thisObj) : function () { + return fn.apply(thisObj, arguments); + }; + } + // Generate ticks; interpolate from start up to // start + span in count steps, using the provided // formatter to represent each value. @@ -72,7 +80,7 @@ define( panZoom.origin[0], panZoom.dimensions[0], count, - this.formatter.formatDomainValue + bind(this.formatter.formatDomainValue, this.formatter) ); }; @@ -87,7 +95,7 @@ define( panZoom.origin[1], panZoom.dimensions[1], count, - this.formatter.formatRangeValue + bind(this.formatter.formatRangeValue, this.formatter) ); }; From b375ede2172d0b307239cf5d8ec2b21c2d422b30 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 11:39:23 -0700 Subject: [PATCH 37/79] [Time Conductor] Recognize domain changes in plot --- platform/features/plot/src/PlotController.js | 34 ++++++-- .../features/plot/src/elements/PlotAxis.js | 81 +++++++++++++------ 2 files changed, 86 insertions(+), 29 deletions(-) diff --git a/platform/features/plot/src/PlotController.js b/platform/features/plot/src/PlotController.js index 2aef3e3418..75339b2133 100644 --- a/platform/features/plot/src/PlotController.js +++ b/platform/features/plot/src/PlotController.js @@ -83,10 +83,9 @@ define( // Populate the scope with axis information (specifically, options // available for each axis.) function setupAxes(metadatas) { - $scope.axes = [ - new PlotAxis("domain", metadatas, AXIS_DEFAULTS[0]), - new PlotAxis("range", metadatas, AXIS_DEFAULTS[1]) - ]; + $scope.axes.forEach(function (axis) { + axis.updateMetadata(metadatas); + }); } // Trigger an update of a specific subplot; @@ -142,6 +141,7 @@ define( self.pending = false; if (handle) { setupModes(handle.getTelemetryObjects()); + setupAxes(handle.getMetadata()); } if (updater) { updater.update(); @@ -168,6 +168,15 @@ define( } } + // Requery for data entirely + function replot() { + if (handle) { + recreateUpdater(); + requestTelemetry(); + } + } + + // Create a new subscription; telemetrySubscriber gets // to do the meaningful work here. function subscribe(domainObject) { @@ -197,11 +206,15 @@ define( // Respond to a display bounds change (requery for data) function changeDisplayBounds(event, bounds) { + var domainAxis = $scope.axes[0]; + domainAxis.chooseOption(bounds.domain); + plotTelemetryFormatter + .setDomainFormat(domainAxis.active.format); + self.pending = true; releaseSubscription(); subscribe($scope.domainObject); setBasePanZoom(bounds); - $scope.axes[0].choose(bounds.domain); } function updateDomainFormat(format) { @@ -219,6 +232,17 @@ define( self.pending = true; + // Initialize axes; will get repopulated when telemetry + // metadata becomes available. + $scope.axes = [ + new PlotAxis("domain", [], AXIS_DEFAULTS[0]), + new PlotAxis("range", [], AXIS_DEFAULTS[1]) + ]; + + // Request new data whenever domain selection changes; + // ordering and bounding of data may change. + $scope.$watch("axes[0].active.key", replot); + // Subscribe to telemetry when a domain object becomes available $scope.$watch('domainObject', subscribe); diff --git a/platform/features/plot/src/elements/PlotAxis.js b/platform/features/plot/src/elements/PlotAxis.js index cee7acef8a..127e52f9c0 100644 --- a/platform/features/plot/src/elements/PlotAxis.js +++ b/platform/features/plot/src/elements/PlotAxis.js @@ -46,21 +46,9 @@ define( * */ function PlotAxis(axisType, metadatas, defaultValue) { - var keys = {}, - options = []; - - // Look through all metadata objects and assemble a list - // of all possible domain or range options - function buildOptionsForMetadata(m) { - (m[axisType] || []).forEach(function (option) { - if (!keys[option.key]) { - keys[option.key] = true; - options.push(option); - } - }); - } - - (metadatas || []).forEach(buildOptionsForMetadata); + this.axisType = axisType; + this.defaultValue = defaultValue; + this.optionKeys = {}; /** * The currently chosen option for this axis. An @@ -68,7 +56,7 @@ define( * directly form the plot template. * @memberof platform/features/plot.PlotAxis# */ - this.active = options[0] || defaultValue; + this.active = defaultValue; /** * The set of options applicable for this axis; @@ -77,17 +65,62 @@ define( * human-readable names respectively) * @memberof platform/features/plot.PlotAxis# */ - this.options = options; + this.options = []; + + // Initialize options from metadata objects + this.updateMetadata(metadatas); } - PlotAxis.prototype.choose = function (key) { - var i; - for (i = 0; i < this.options.length; i += 1) { - if (this.options[i].key === key) { - this.active = this.options[i]; - return; - } + + /** + * Update axis options to reflect current metadata. + * @memberof platform/features/plot.PlotAxis + */ + PlotAxis.prototype.updateMetadata = function (metadatas) { + var axisType = this.axisType, + optionKeys = this.optionKeys, + newOptions = {}, + toAdd = []; + + function isValid(option) { + return option && optionKeys[option.key]; } + + metadatas.forEach(function (m) { + (m[axisType + 's'] || []).forEach(function (option) { + var key = option.key; + if (!optionKeys[key] && !newOptions[key]) { + toAdd.push(option); + } + newOptions[option.key] = true; + }); + }); + + optionKeys = this.optionKeys = newOptions; + + // General approach here is to avoid changing object + // instances unless something has really changed, since + // Angular is watching; don't want to trigger extra digests. + if (!this.options.every(isValid)) { + this.options = this.options.filter(isValid); + } + + if (toAdd.length > 0) { + this.options = this.options.concat(toAdd); + } + + if (!isValid(this.active)) { + this.active = this.options[0] || this.defaultValue; + } + }; + + PlotAxis.prototype.chooseOption = function (key) { + var self = this; + this.options.forEach(function (option) { + if (option.key === key) { + self.active = option; + } + }); }; return PlotAxis; From caee1f520fd59e55914a12406da789531a83044e Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 11:46:41 -0700 Subject: [PATCH 38/79] [Time Conductor] Remove unused watches from plot --- platform/features/plot/src/PlotController.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/platform/features/plot/src/PlotController.js b/platform/features/plot/src/PlotController.js index 75339b2133..0fdcf9e3eb 100644 --- a/platform/features/plot/src/PlotController.js +++ b/platform/features/plot/src/PlotController.js @@ -176,7 +176,6 @@ define( } } - // Create a new subscription; telemetrySubscriber gets // to do the meaningful work here. function subscribe(domainObject) { @@ -207,6 +206,7 @@ define( // Respond to a display bounds change (requery for data) function changeDisplayBounds(event, bounds) { var domainAxis = $scope.axes[0]; + domainAxis.chooseOption(bounds.domain); plotTelemetryFormatter .setDomainFormat(domainAxis.active.format); @@ -239,16 +239,9 @@ define( new PlotAxis("range", [], AXIS_DEFAULTS[1]) ]; - // Request new data whenever domain selection changes; - // ordering and bounding of data may change. - $scope.$watch("axes[0].active.key", replot); - // Subscribe to telemetry when a domain object becomes available $scope.$watch('domainObject', subscribe); - // Reformat timestamps when needed - $scope.$watch('axes[0].active.format', updateDomainFormat); - // Respond to external bounds changes $scope.$on("telemetry:display:bounds", changeDisplayBounds); From 9723c650160cf34b9b68f2af76481378718bd38b Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 12:09:50 -0700 Subject: [PATCH 39/79] [Time Conductor] Retain domain selection in plot Avoid various cases where domain selection is temporarily overwritten due to transient plot state (e.g. because no telemetry metadata is yet available due to asynchronous retrieval of delegates.) --- platform/features/plot/src/PlotController.js | 30 +++++++++----------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/platform/features/plot/src/PlotController.js b/platform/features/plot/src/PlotController.js index 0fdcf9e3eb..517682f9b4 100644 --- a/platform/features/plot/src/PlotController.js +++ b/platform/features/plot/src/PlotController.js @@ -136,6 +136,13 @@ define( } } + function getUpdater() { + if (!updater) { + recreateUpdater(); + } + return updater; + } + // Handle new telemetry data in this plot function updateValues() { self.pending = false; @@ -143,27 +150,23 @@ define( setupModes(handle.getTelemetryObjects()); setupAxes(handle.getMetadata()); } - if (updater) { - updater.update(); - self.modeOptions.getModeHandler().plotTelemetry(updater); - } - if (self.limitTracker) { - self.limitTracker.update(); - } + getUpdater().update(); + self.modeOptions.getModeHandler().plotTelemetry(updater); + self.limitTracker.update(); self.update(); } // Display new historical data as it becomes available function addHistoricalData(domainObject, series) { self.pending = false; - updater.addHistorical(domainObject, series); + getUpdater().addHistorical(domainObject, series); self.modeOptions.getModeHandler().plotTelemetry(updater); self.update(); } // Issue a new request for historical telemetry function requestTelemetry() { - if (handle && updater) { + if (handle) { handle.request({}, addHistoricalData); } } @@ -171,7 +174,7 @@ define( // Requery for data entirely function replot() { if (handle) { - recreateUpdater(); + updater = undefined; requestTelemetry(); } } @@ -187,12 +190,7 @@ define( updateValues, true // Lossless ); - if (handle) { - setupModes(handle.getTelemetryObjects()); - setupAxes(handle.getMetadata()); - recreateUpdater(); - requestTelemetry(); - } + replot(); } // Release the current subscription (called when scope is destroyed) From 6b805183b0e1a5f38becba622b4ae18475508c27 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 12:35:15 -0700 Subject: [PATCH 40/79] [Time Conductor] Parse negative values ...in example telemetry --- example/generator/src/SinewaveDeltaFormat.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/example/generator/src/SinewaveDeltaFormat.js b/example/generator/src/SinewaveDeltaFormat.js index 1006e4b31d..19f3e631f9 100644 --- a/example/generator/src/SinewaveDeltaFormat.js +++ b/example/generator/src/SinewaveDeltaFormat.js @@ -27,7 +27,7 @@ define( "use strict"; var START_TIME = SinewaveConstants.START_TIME, - NUMBER_REGEX = /^\d+$/, + FORMAT_REGEX = /^-?\d+:\d+:\d+$/, SECOND = 1000, MINUTE = SECOND * 60, HOUR = MINUTE * 60; @@ -50,19 +50,17 @@ define( }; SinewaveDeltaFormat.prototype.validate = function (text) { - var parts = text.split(":"); - return parts.length === 3 && parts.every(function (part) { - return NUMBER_REGEX.test(part); - }); + return FORMAT_REGEX.test(text); }; SinewaveDeltaFormat.prototype.parse = function (text) { - var parts = text.split(":"); + var negative = text[0] === "-", + parts = text.replace("-", "").split(":"); return [ HOUR, MINUTE, SECOND ].map(function (sz, i) { return parseInt(parts[i], 10) * sz; }).reduce(function (a, b) { return a + b; - }, SinewaveConstants.START_TIME); + }, 0) * (negative ? -1 : 1) + START_TIME; }; return SinewaveDeltaFormat; From e5ebbdaf7f90cd84c217b53d55ccd905ab80270d Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 12:37:53 -0700 Subject: [PATCH 41/79] [Time Conductor] Use domain formats in scrolling list --- platform/features/scrolling/src/DomainColumn.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/features/scrolling/src/DomainColumn.js b/platform/features/scrolling/src/DomainColumn.js index a55b4001d5..3824098118 100644 --- a/platform/features/scrolling/src/DomainColumn.js +++ b/platform/features/scrolling/src/DomainColumn.js @@ -54,7 +54,8 @@ define( DomainColumn.prototype.getValue = function (domainObject, datum) { return { text: this.telemetryFormatter.formatDomainValue( - datum[this.domainMetadata.key] + datum[this.domainMetadata.key], + this.domainMetadata.format ) }; }; From 71618ce4b9367f6f3708f0783832d382b6ee8d17 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 12:40:14 -0700 Subject: [PATCH 42/79] [Time Conductor] Hide date-picker for non-UTC formats --- .../general/res/templates/controls/time-controller.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/commonUI/general/res/templates/controls/time-controller.html b/platform/commonUI/general/res/templates/controls/time-controller.html index 5b41beeebf..e7468bc556 100644 --- a/platform/commonUI/general/res/templates/controls/time-controller.html +++ b/platform/commonUI/general/res/templates/controls/time-controller.html @@ -30,7 +30,7 @@ ng-class="{ error: !boundsModel.startValid }"> @@ -55,7 +55,7 @@ ng-class="{ error: !boundsModel.endValid }"> From 6784c6567ba0f54f4e8bed1c2558ec9914c9f339 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 12:56:08 -0700 Subject: [PATCH 43/79] [Time Conductor] Add date-time field Add mct-control which includes both the date-time picker and its corresponding text entry area, per code review feedback from nasa/openmctweb#204. --- platform/commonUI/general/bundle.json | 9 +++ .../templates/controls/datetime-field.html | 20 +++++ .../controllers/DateTimeFieldController.js | 76 +++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 platform/commonUI/general/res/templates/controls/datetime-field.html create mode 100644 platform/commonUI/general/src/controllers/DateTimeFieldController.js diff --git a/platform/commonUI/general/bundle.json b/platform/commonUI/general/bundle.json index 800fa8e5ea..853f97936d 100644 --- a/platform/commonUI/general/bundle.json +++ b/platform/commonUI/general/bundle.json @@ -60,6 +60,11 @@ "implementation": "controllers/DateTimePickerController.js", "depends": [ "$scope", "now" ] }, + { + "key": "DateTimeFieldController", + "implementation": "controllers/DateTimePickerController.js", + "depends": [ "$scope", "formatService" ] + }, { "key": "TreeNodeController", "implementation": "controllers/TreeNodeController.js", @@ -242,6 +247,10 @@ { "key": "datetime-picker", "templateUrl": "templates/controls/datetime-picker.html" + }, + { + "key": "datetime-field", + "templateUrl": "templates/controls/datetime-field.html" } ], "licenses": [ diff --git a/platform/commonUI/general/res/templates/controls/datetime-field.html b/platform/commonUI/general/res/templates/controls/datetime-field.html new file mode 100644 index 0000000000..6ba8cbf901 --- /dev/null +++ b/platform/commonUI/general/res/templates/controls/datetime-field.html @@ -0,0 +1,20 @@ + + + + + + +
+ + +
+
+
diff --git a/platform/commonUI/general/src/controllers/DateTimeFieldController.js b/platform/commonUI/general/src/controllers/DateTimeFieldController.js new file mode 100644 index 0000000000..5c48cc2453 --- /dev/null +++ b/platform/commonUI/general/src/controllers/DateTimeFieldController.js @@ -0,0 +1,76 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ +/*global define,Promise*/ + +define( + [], + function () { + 'use strict'; + + var DEFAULT_FORMAT = 'utc'; + + /** + * Controller to support the date-time entry field. + * + * Accepts a `format` property in the `structure` attribute + * which allows a date/time to be specified via its symbolic + * key (as will be used to look up said format from the + * `formatService`.) + * + * {@see FormatService} + * @constructor + * @memberof platform/commonUI/general + */ + function DateTimeFieldController($scope, formatService) { + var formatter = formatService.getFormat(DEFAULT_FORMAT); + + function setFormat(format) { + formatter = formatService.getFormat(format) || + formatService.getFormat(DEFAULT_FORMAT); + } + + function updateFromModel(value) { + // Only reformat if the value is different from user + // input (to avoid reformatting valid input while typing.) + if (!formatter.validate($scope.textValue) || + formatter.parse($scope.textValue) !== value) { + $scope.textValue = formatter.format(value); + $scope.textInvalid = false; + } + } + + function updateFromView(textValue) { + $scope.textInvalid = !formatter.validate(textValue); + if (!$scope.textInvalid) { + $scope.ngModel[$scope.field] = + formatter.parse(textValue); + } + } + + $scope.$watch('structure.format', setFormat); + $scope.$watch('ngModel[field]', updateFromModel); + $scope.$watch('textValue', updateFromView); + } + + return DateTimeFieldController; + } +); From e5d4376f061876d8cb16241974e2bd0be8725029 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 13:01:27 -0700 Subject: [PATCH 44/79] [Time Conductor] Use date time field ...from template for time controller. --- .../templates/controls/time-controller.html | 54 +++++-------------- 1 file changed, 13 insertions(+), 41 deletions(-) diff --git a/platform/commonUI/general/res/templates/controls/time-controller.html b/platform/commonUI/general/res/templates/controls/time-controller.html index e7468bc556..e44a9ff77c 100644 --- a/platform/commonUI/general/res/templates/controls/time-controller.html +++ b/platform/commonUI/general/res/templates/controls/time-controller.html @@ -22,52 +22,24 @@
C - - - - - - - - -
- - -
-
-
+ + + to - - - - - - - -
- - -
-
-
  + +  
From 18cdaf1b5358f0352538a7502f01901cf5f26715 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 13:03:04 -0700 Subject: [PATCH 45/79] [Time Conductor] Fix extension definition For date time field controller; refer to correct implementation. --- platform/commonUI/general/bundle.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/commonUI/general/bundle.json b/platform/commonUI/general/bundle.json index 853f97936d..eee42ef4cd 100644 --- a/platform/commonUI/general/bundle.json +++ b/platform/commonUI/general/bundle.json @@ -62,7 +62,7 @@ }, { "key": "DateTimeFieldController", - "implementation": "controllers/DateTimePickerController.js", + "implementation": "controllers/DateTimeFieldController.js", "depends": [ "$scope", "formatService" ] }, { From 9dce3a04cc4e2929072ffe2698e586b525cb38cd Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 13:07:58 -0700 Subject: [PATCH 46/79] [Time Conductor] Remove obsolete code Remove code related to handling text input from TimeRangeController; moved into DateTimeFieldController. --- .../src/controllers/TimeRangeController.js | 79 ++----------------- 1 file changed, 7 insertions(+), 72 deletions(-) diff --git a/platform/commonUI/general/src/controllers/TimeRangeController.js b/platform/commonUI/general/src/controllers/TimeRangeController.js index ce53b7b1e7..55881b94d6 100644 --- a/platform/commonUI/general/src/controllers/TimeRangeController.js +++ b/platform/commonUI/general/src/controllers/TimeRangeController.js @@ -102,42 +102,15 @@ define( return { start: bounds.start, end: bounds.end }; } - function updateBoundsTextForProperty(ngModel, property) { - try { - if (!$scope.boundsModel[property] || - parseTimestamp($scope.boundsModel[property]) !== - ngModel.outer[property]) { - $scope.boundsModel[property] = - formatTimestamp(ngModel.outer[property]); - // Never want to flag machine-generated text - // as invalid here. - $scope.boundsModel[property + 'Valid'] = true; - } - } catch (e) { - // User-entered text is invalid, so leave it be - // until they fix it. - } - } - - function updateBoundsText(ngModel) { - updateBoundsTextForProperty(ngModel, 'start'); - updateBoundsTextForProperty(ngModel, 'end'); - } - function updateViewFromModel(ngModel) { ngModel = ngModel || {}; ngModel.outer = ngModel.outer || defaultBounds(); ngModel.inner = ngModel.inner || copyBounds(ngModel.outer); - // First, dates for the date pickers for outer bounds - updateBoundsText(ngModel); - - // Then various updates for the inner span - updateViewForInnerSpanFromModel(ngModel); - // Stick it back is scope (in case we just set defaults) $scope.ngModel = ngModel; + updateViewForInnerSpanFromModel(ngModel); updateTicks(); } @@ -157,7 +130,8 @@ define( } function toMillis(pixels) { - var span = $scope.ngModel.outer.end - $scope.ngModel.outer.start; + var span = + $scope.ngModel.outer.end - $scope.ngModel.outer.start; return (pixels / $scope.spanWidth) * span; } @@ -245,47 +219,12 @@ define( updateTicks(); } - function updateStartFromText(value) { - try { - updateOuterStart(parseTimestamp(value)); - updateBoundsTextForProperty($scope.ngModel, 'end'); - $scope.boundsModel.startValid = true; - } catch (e) { - $scope.boundsModel.startValid = false; - return; - } - } - - function updateEndFromText(value) { - try { - updateOuterEnd(parseTimestamp(value)); - updateBoundsTextForProperty($scope.ngModel, 'start'); - $scope.boundsModel.endValid = true; - } catch (e) { - $scope.boundsModel.endValid = false; - return; - } - } - function updateFormat(key) { formatter = formatService.getFormat(key) || formatService.getFormat(DEFAULT_FORMAT); - // Assume that start/end are still valid, but clear - // the displayed text for bounds, since this will - // now be formatted differently. - $scope.boundsModel = {}; - updateViewFromModel($scope.ngModel); - } - - function updateStartFromPicker(value) { - updateOuterStart(value); - updateBoundsText($scope.ngModel); - } - - function updateEndFromPicker(value) { - updateOuterEnd(value); - updateBoundsText($scope.ngModel); + updateViewForInnerSpanFromModel($scope.ngModel); + updateTicks(); } $scope.startLeftDrag = startLeftDrag; @@ -295,19 +234,15 @@ define( $scope.rightDrag = rightDrag; $scope.middleDrag = middleDrag; - $scope.state = false; $scope.ticks = []; - $scope.boundsModel = {}; // Initialize scope to defaults updateViewFromModel($scope.ngModel); $scope.$watchCollection("ngModel", updateViewFromModel); $scope.$watch("spanWidth", updateSpanWidth); - $scope.$watch("ngModel.outer.start", updateStartFromPicker); - $scope.$watch("ngModel.outer.end", updateEndFromPicker); - $scope.$watch("boundsModel.start", updateStartFromText); - $scope.$watch("boundsModel.end", updateEndFromText); + $scope.$watch("ngModel.outer.start", updateOuterStart); + $scope.$watch("ngModel.outer.end", updateOuterEnd); $scope.$watch("parameters.format", updateFormat); } From cc8a7e513fb1096efe8c5a7d4bad05b749016272 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 13:11:04 -0700 Subject: [PATCH 47/79] [Time Conductor] Rename bundle Rename platform/time to platform/commonUI/formatting; nothing particularly specific to time about these interfaces, and removal of non-formatting-related methods makes this essentially a UI concern. --- bundles.json | 2 +- platform/{time => commonUI/formatting}/bundle.json | 0 platform/{time => commonUI/formatting}/src/FormatProvider.js | 0 platform/{time => commonUI/formatting}/src/UTCTimeFormat.js | 0 4 files changed, 1 insertion(+), 1 deletion(-) rename platform/{time => commonUI/formatting}/bundle.json (100%) rename platform/{time => commonUI/formatting}/src/FormatProvider.js (100%) rename platform/{time => commonUI/formatting}/src/UTCTimeFormat.js (100%) diff --git a/bundles.json b/bundles.json index 3c2eb90340..d6159cfe18 100644 --- a/bundles.json +++ b/bundles.json @@ -6,6 +6,7 @@ "platform/commonUI/browse", "platform/commonUI/edit", "platform/commonUI/dialog", + "platform/commonUI/formatting", "platform/commonUI/general", "platform/commonUI/inspect", "platform/commonUI/mobile", @@ -26,7 +27,6 @@ "platform/policy", "platform/entanglement", "platform/search", - "platform/time", "example/imagery", "example/eventGenerator", diff --git a/platform/time/bundle.json b/platform/commonUI/formatting/bundle.json similarity index 100% rename from platform/time/bundle.json rename to platform/commonUI/formatting/bundle.json diff --git a/platform/time/src/FormatProvider.js b/platform/commonUI/formatting/src/FormatProvider.js similarity index 100% rename from platform/time/src/FormatProvider.js rename to platform/commonUI/formatting/src/FormatProvider.js diff --git a/platform/time/src/UTCTimeFormat.js b/platform/commonUI/formatting/src/UTCTimeFormat.js similarity index 100% rename from platform/time/src/UTCTimeFormat.js rename to platform/commonUI/formatting/src/UTCTimeFormat.js From 920c83771d0422d51a0a0655191128a5ea06bb5e Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 14:05:55 -0700 Subject: [PATCH 48/79] [Time Conductor] Update spec ...for TimeRangeController to reflect separation of date-time inputs into a separate control. Additionally, removed unused function. --- .../src/controllers/TimeRangeController.js | 8 -- .../controllers/TimeRangeControllerSpec.js | 86 +++---------------- 2 files changed, 14 insertions(+), 80 deletions(-) diff --git a/platform/commonUI/general/src/controllers/TimeRangeController.js b/platform/commonUI/general/src/controllers/TimeRangeController.js index 55881b94d6..85fad1100c 100644 --- a/platform/commonUI/general/src/controllers/TimeRangeController.js +++ b/platform/commonUI/general/src/controllers/TimeRangeController.js @@ -45,14 +45,6 @@ define( return formatter.format(ts); } - function parseTimestamp(text) { - if (formatter.validate(text)) { - return formatter.parse(text); - } else { - throw new Error("Could not parse " + text); - } - } - // From 0.0-1.0 to "0%"-"100%" function toPercent(p) { return (100 * p) + "%"; diff --git a/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js b/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js index 30cddab922..3c39efdb74 100644 --- a/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js +++ b/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js @@ -33,8 +33,9 @@ define( describe("The TimeRangeController", function () { var mockScope, - mockDateService, + mockFormatService, mockNow, + mockFormat, controller; function fireWatch(expr, value) { @@ -58,24 +59,26 @@ define( "$scope", [ "$apply", "$watch", "$watchCollection" ] ); - mockDateService = jasmine.createSpyObj( - "dateService", + mockFormatService = jasmine.createSpyObj( + "formatService", + [ "getFormat" ] + ); + mockFormat = jasmine.createSpyObj( + "format", [ "validate", "format", "parse" ] ); - mockDateService.validate.andCallFake(function (text) { - return moment.utc(text).isValid(); - }); - mockDateService.parse.andCallFake(function (text) { - return moment.utc(text).valueOf(); - }); - mockDateService.format.andCallFake(function (value) { + + mockFormatService.getFormat.andReturn(mockFormat); + + mockFormat.format.andCallFake(function (value) { return moment.utc(value).format("YYYY-MM-DD HH:mm:ss"); }); + mockNow = jasmine.createSpy('now'); controller = new TimeRangeController( mockScope, - mockDateService, + mockFormatService, mockNow ); }); @@ -186,67 +189,6 @@ define( .toBeGreaterThan(mockScope.ngModel.inner.start); }); - describe("by typing", function () { - it("updates models", function () { - var newStart = "1977-05-25 17:30:00", - newEnd = "2015-12-18 03:30:00"; - - mockScope.boundsModel.start = newStart; - fireWatch("boundsModel.start", newStart); - expect(mockScope.ngModel.outer.start) - .toEqual(moment.utc(newStart).valueOf()); - expect(mockScope.boundsModel.startValid) - .toBeTruthy(); - - mockScope.boundsModel.end = newEnd; - fireWatch("boundsModel.end", newEnd); - expect(mockScope.ngModel.outer.end) - .toEqual(moment.utc(newEnd).valueOf()); - expect(mockScope.boundsModel.endValid) - .toBeTruthy(); - }); - - it("displays error state", function () { - var newStart = "Not a date", - newEnd = "Definitely not a date", - oldStart = mockScope.ngModel.outer.start, - oldEnd = mockScope.ngModel.outer.end; - - mockScope.boundsModel.start = newStart; - fireWatch("boundsModel.start", newStart); - expect(mockScope.ngModel.outer.start) - .toEqual(oldStart); - expect(mockScope.boundsModel.startValid) - .toBeFalsy(); - - mockScope.boundsModel.end = newEnd; - fireWatch("boundsModel.end", newEnd); - expect(mockScope.ngModel.outer.end) - .toEqual(oldEnd); - expect(mockScope.boundsModel.endValid) - .toBeFalsy(); - }); - - it("does not modify user input", function () { - // Don't want the controller "fixing" bad or - // irregularly-formatted input out from under - // the user's fingertips. - var newStart = "Not a date", - newEnd = "2015-3-3 01:02:04", - oldStart = mockScope.ngModel.outer.start, - oldEnd = mockScope.ngModel.outer.end; - - mockScope.boundsModel.start = newStart; - fireWatch("boundsModel.start", newStart); - expect(mockScope.boundsModel.start) - .toEqual(newStart); - - mockScope.boundsModel.end = newEnd; - fireWatch("boundsModel.end", newEnd); - expect(mockScope.boundsModel.end) - .toEqual(newEnd); - }); - }); }); From f30a2dd791716e9791179b0288a665b88e63675b Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 15:37:08 -0700 Subject: [PATCH 49/79] [Time Conductor] Update telemetryFormatter spec --- .../telemetry/test/TelemetryFormatterSpec.js | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/platform/telemetry/test/TelemetryFormatterSpec.js b/platform/telemetry/test/TelemetryFormatterSpec.js index 22f1579059..23c7b95fd4 100644 --- a/platform/telemetry/test/TelemetryFormatterSpec.js +++ b/platform/telemetry/test/TelemetryFormatterSpec.js @@ -27,16 +27,35 @@ define( "use strict"; describe("The telemetry formatter", function () { - var formatter; + var mockFormatService, + mockFormat, + formatter; beforeEach(function () { - formatter = new TelemetryFormatter(); + mockFormatService = + jasmine.createSpyObj("formatService", ["getFormat"]); + mockFormat = jasmine.createSpyObj("format", [ + "validate", + "parse", + "format" + ]); + mockFormatService.getFormat.andReturn(mockFormat); + formatter = new TelemetryFormatter(mockFormatService); }); - it("formats domains using YYYY-DDD style", function () { - expect(formatter.formatDomainValue(402513731000)).toEqual( - "1982-276 17:22:11" - ); + it("formats domains using the formatService", function () { + var testValue = 12321, testResult = "some result"; + mockFormat.format.andReturn(testResult); + + expect(formatter.formatDomainValue(testValue)) + .toEqual(testResult); + expect(mockFormat.format).toHaveBeenCalledWith(testValue); + }); + + it("passes format keys to the formatService", function () { + formatter.formatDomainValue(12321, "someKey"); + expect(mockFormatService.getFormat) + .toHaveBeenCalledWith("someKey"); }); it("formats ranges as values", function () { @@ -44,4 +63,4 @@ define( }); }); } -); \ No newline at end of file +); From 5ff2e6b652521228cd8831f38352106d32e21059 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 15:39:20 -0700 Subject: [PATCH 50/79] [Time Conductor] Simplify passing in of axis type ...in PlotAxis. Also avoids triggering failures of existing tests. --- platform/features/plot/src/PlotController.js | 4 ++-- platform/features/plot/src/elements/PlotAxis.js | 2 +- platform/features/plot/test/elements/PlotAxisSpec.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/features/plot/src/PlotController.js b/platform/features/plot/src/PlotController.js index 517682f9b4..6d90325b85 100644 --- a/platform/features/plot/src/PlotController.js +++ b/platform/features/plot/src/PlotController.js @@ -233,8 +233,8 @@ define( // Initialize axes; will get repopulated when telemetry // metadata becomes available. $scope.axes = [ - new PlotAxis("domain", [], AXIS_DEFAULTS[0]), - new PlotAxis("range", [], AXIS_DEFAULTS[1]) + new PlotAxis("domains", [], AXIS_DEFAULTS[0]), + new PlotAxis("ranges", [], AXIS_DEFAULTS[1]) ]; // Subscribe to telemetry when a domain object becomes available diff --git a/platform/features/plot/src/elements/PlotAxis.js b/platform/features/plot/src/elements/PlotAxis.js index 127e52f9c0..ff48af6e99 100644 --- a/platform/features/plot/src/elements/PlotAxis.js +++ b/platform/features/plot/src/elements/PlotAxis.js @@ -87,7 +87,7 @@ define( } metadatas.forEach(function (m) { - (m[axisType + 's'] || []).forEach(function (option) { + (m[axisType] || []).forEach(function (option) { var key = option.key; if (!optionKeys[key] && !newOptions[key]) { toAdd.push(option); diff --git a/platform/features/plot/test/elements/PlotAxisSpec.js b/platform/features/plot/test/elements/PlotAxisSpec.js index cd4a82b3b9..f4419096e4 100644 --- a/platform/features/plot/test/elements/PlotAxisSpec.js +++ b/platform/features/plot/test/elements/PlotAxisSpec.js @@ -80,4 +80,4 @@ define( }); } -); \ No newline at end of file +); From ce5a650d8cb0c1ad6acb737f3d525c3f06ed6b83 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 15:40:34 -0700 Subject: [PATCH 51/79] [Time Conductor] Update TimeConductor spec ...to reflect that whole domain metadata, not just key, is exposed. --- platform/features/conductor/test/TimeConductorSpec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/features/conductor/test/TimeConductorSpec.js b/platform/features/conductor/test/TimeConductorSpec.js index c9336a93b0..ee1d2f56b7 100644 --- a/platform/features/conductor/test/TimeConductorSpec.js +++ b/platform/features/conductor/test/TimeConductorSpec.js @@ -59,12 +59,12 @@ define( }); it("exposes the current domain choice", function () { - expect(conductor.domain()).toEqual(testDomains[0].key); + expect(conductor.domain()).toEqual(testDomains[0]); }); it("allows the domain choice to be changed", function () { conductor.domain(testDomains[1].key); - expect(conductor.domain()).toEqual(testDomains[1].key); + expect(conductor.domain()).toEqual(testDomains[1]); }); it("throws an error on attempts to set an invalid domain", function () { From 60e97eb94a996dc0300b39ff13f1477c155df6b0 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 15:43:31 -0700 Subject: [PATCH 52/79] [Time Conductor] Update ConductorRepresenter spec ...to reflect that TimeConductor exposes whole domain metadata, not just key. --- platform/features/conductor/test/ConductorRepresenterSpec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/features/conductor/test/ConductorRepresenterSpec.js b/platform/features/conductor/test/ConductorRepresenterSpec.js index 5d78c8a720..cd7d3a4f91 100644 --- a/platform/features/conductor/test/ConductorRepresenterSpec.js +++ b/platform/features/conductor/test/ConductorRepresenterSpec.js @@ -129,7 +129,7 @@ define( it("exposes conductor state in scope", function () { mockConductor.displayStart.andReturn(1977); mockConductor.displayEnd.andReturn(1984); - mockConductor.domain.andReturn('d'); + mockConductor.domain.andReturn({ key: 'd' }); representer.represent(testViews[0], {}); expect(mockNewScope.ngModel.conductor).toEqual({ @@ -219,7 +219,7 @@ define( representer.represent(testViews[0], null); expect(mockNewScope.ngModel.domain) - .toEqual(mockConductor.domain()); + .toEqual(mockConductor.domain().key); }); it("exposes domain options in scope", function () { From 2ee53b17db09528fdb12e45c8644dd70aadd2d33 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 15:46:18 -0700 Subject: [PATCH 53/79] [Time Conductor] Update ConductorTelemetryDecorator spec ...to reflect that TimeConductor exposes whole domain metadata, not just key. --- .../conductor/test/ConductorTelemetryDecoratorSpec.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/features/conductor/test/ConductorTelemetryDecoratorSpec.js b/platform/features/conductor/test/ConductorTelemetryDecoratorSpec.js index 6e768419c1..26cdb2677b 100644 --- a/platform/features/conductor/test/ConductorTelemetryDecoratorSpec.js +++ b/platform/features/conductor/test/ConductorTelemetryDecoratorSpec.js @@ -77,7 +77,7 @@ define( mockConductor.displayStart.andReturn(42); mockConductor.displayEnd.andReturn(1977); - mockConductor.domain.andReturn("testDomain"); + mockConductor.domain.andReturn({ key: "testDomain" }); decorator = new ConductorTelemetryDecorator( mockConductorService, @@ -104,7 +104,7 @@ define( }); it("with domain selection", function () { - expect(request.domain).toEqual(mockConductor.domain()); + expect(request.domain).toEqual(mockConductor.domain().key); }); }); @@ -127,7 +127,7 @@ define( }); it("with domain selection", function () { - expect(request.domain).toEqual(mockConductor.domain()); + expect(request.domain).toEqual(mockConductor.domain().key); }); }); From bd8bbc6e8f31f181f8780d74cc8acf431bd970e8 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 15:52:11 -0700 Subject: [PATCH 54/79] [Time Conductor] Update PlotController spec ...and add check to updateValues in PlotController, to reflect changes made to restore support for domain switching. --- platform/features/plot/src/PlotController.js | 8 ++++---- platform/features/plot/test/PlotControllerSpec.js | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/platform/features/plot/src/PlotController.js b/platform/features/plot/src/PlotController.js index 6d90325b85..d6acdb6a5c 100644 --- a/platform/features/plot/src/PlotController.js +++ b/platform/features/plot/src/PlotController.js @@ -149,11 +149,11 @@ define( if (handle) { setupModes(handle.getTelemetryObjects()); setupAxes(handle.getMetadata()); + getUpdater().update(); + self.modeOptions.getModeHandler().plotTelemetry(updater); + self.limitTracker.update(); + self.update(); } - getUpdater().update(); - self.modeOptions.getModeHandler().plotTelemetry(updater); - self.limitTracker.update(); - self.update(); } // Display new historical data as it becomes available diff --git a/platform/features/plot/test/PlotControllerSpec.js b/platform/features/plot/test/PlotControllerSpec.js index dcae177920..addbdf5032 100644 --- a/platform/features/plot/test/PlotControllerSpec.js +++ b/platform/features/plot/test/PlotControllerSpec.js @@ -169,8 +169,9 @@ define( mockDomainObject ]); - // Make an object available + // Make an object available; invoke handler's callback mockScope.$watch.mostRecentCall.args[1](mockDomainObject); + mockHandler.handle.mostRecentCall.args[1](); expect(controller.getModeOptions().length).toEqual(1); @@ -181,8 +182,9 @@ define( mockDomainObject ]); - // Make an object available + // Make an object available; invoke handler's callback mockScope.$watch.mostRecentCall.args[1](mockDomainObject); + mockHandler.handle.mostRecentCall.args[1](); expect(controller.getModeOptions().length).toEqual(2); }); From 8ba112498bb3234f0f26f9151b07b3d8542267e9 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 15:57:44 -0700 Subject: [PATCH 55/79] [Time Conductor] Add test case for formats Add test case to TimeRangeController to reflect that it responds to changes in format selection. --- .../general/test/controllers/TimeRangeControllerSpec.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js b/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js index 3c39efdb74..4b0f3de9e6 100644 --- a/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js +++ b/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js @@ -191,6 +191,13 @@ define( }); + it("watches for changes in format selection", function () { + expect(mockFormatService.getFormat) + .not.toHaveBeenCalledWith('test-format'); + fireWatch("parameters.format", 'test-format'); + expect(mockFormatService.getFormat) + .toHaveBeenCalledWith('test-format'); + }); }); From 55745d281f85dec31dc37fac9ca1e9c8354643ee Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 16:18:13 -0700 Subject: [PATCH 56/79] [Time Conductor] Update PlotAxis spec ...to reflect ability to change domain selection without reinstantiation, supporting integration of domain-driven formatting of X axis values in a plot. --- .../features/plot/src/elements/PlotAxis.js | 2 +- .../plot/test/elements/PlotAxisSpec.js | 38 ++++++++++++++++--- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/platform/features/plot/src/elements/PlotAxis.js b/platform/features/plot/src/elements/PlotAxis.js index ff48af6e99..29e67d1976 100644 --- a/platform/features/plot/src/elements/PlotAxis.js +++ b/platform/features/plot/src/elements/PlotAxis.js @@ -92,7 +92,7 @@ define( if (!optionKeys[key] && !newOptions[key]) { toAdd.push(option); } - newOptions[option.key] = true; + newOptions[key] = true; }); }); diff --git a/platform/features/plot/test/elements/PlotAxisSpec.js b/platform/features/plot/test/elements/PlotAxisSpec.js index f4419096e4..f06f0c69cc 100644 --- a/platform/features/plot/test/elements/PlotAxisSpec.js +++ b/platform/features/plot/test/elements/PlotAxisSpec.js @@ -30,7 +30,12 @@ define( "use strict"; describe("A plot axis", function () { - var testMetadatas = [ + var testMetadatas, + testDefault, + axis; + + beforeEach(function () { + testMetadatas = [ { tests: [ { key: "t0", name: "T0" }, @@ -52,13 +57,14 @@ define( { key: "t6", name: "T6" } ] } - ], - testDefault = { key: "test", name: "Test" }, - controller = new PlotAxis("tests", testMetadatas, testDefault); + ]; + testDefault = { key: "test", name: "Test" }; + axis = new PlotAxis("tests", testMetadatas, testDefault); + }); it("pulls out a list of domain or range options", function () { // Should have filtered out duplicates, etc - expect(controller.options).toEqual([ + expect(axis.options).toEqual([ { key: "t0", name: "T0" }, { key: "t1", name: "T1" }, { key: "t2", name: "T2" }, @@ -70,7 +76,7 @@ define( }); it("chooses the first option as a default", function () { - expect(controller.active).toEqual({ key: "t0", name: "T0" }); + expect(axis.active).toEqual({ key: "t0", name: "T0" }); }); it("falls back to a provided default if no options are present", function () { @@ -78,6 +84,26 @@ define( .toEqual(testDefault); }); + it("allows options to be chosen by key", function () { + axis.chooseOption("t3"); + expect(axis.active).toEqual({ key: "t3", name: "T3" }); + }); + + it("reflects changes to applicable metadata", function () { + axis.updateMetadata([ testMetadatas[1] ]); + expect(axis.options).toEqual([ + { key: "t0", name: "T0" }, + { key: "t2", name: "T2" } + ]); + }); + + it("returns the same array instance for unchanged metadata", function () { + // ...to avoid triggering extra digest cycles. + var oldInstance = axis.options; + axis.updateMetadata(testMetadatas); + expect(axis.options).toBe(oldInstance); + }); + }); } ); From 9e8152719f2f371efad52682b11753ecea830033 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 17:12:03 -0700 Subject: [PATCH 57/79] [Time Conductor] Add spec Add spec for DateTimeFieldController, bringing over test cases removed from TimeRangeController. --- .../DateTimeFieldControllerSpec.js | 176 ++++++++++++++++++ platform/commonUI/general/test/suite.json | 1 + 2 files changed, 177 insertions(+) create mode 100644 platform/commonUI/general/test/controllers/DateTimeFieldControllerSpec.js diff --git a/platform/commonUI/general/test/controllers/DateTimeFieldControllerSpec.js b/platform/commonUI/general/test/controllers/DateTimeFieldControllerSpec.js new file mode 100644 index 0000000000..0d6ab6eeb1 --- /dev/null +++ b/platform/commonUI/general/test/controllers/DateTimeFieldControllerSpec.js @@ -0,0 +1,176 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ +/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/ + +define( + ["../../src/controllers/DateTimeFieldController", "moment"], + function (DateTimeFieldController, moment) { + 'use strict'; + + var TEST_FORMAT = "YYYY-MM-DD HH:mm:ss"; + + describe("The DateTimeFieldController", function () { + var mockScope, + mockFormatService, + mockFormat, + controller; + + function fireWatch(expr, value) { + mockScope.$watch.calls.forEach(function (call) { + if (call.args[0] === expr) { + call.args[1](value); + } + }); + } + + beforeEach(function () { + mockScope = jasmine.createSpyObj('$scope', ['$watch']); + mockFormatService = + jasmine.createSpyObj('formatService', ['getFormat']); + mockFormat = jasmine.createSpyObj('format', [ + 'parse', + 'validate', + 'format' + ]); + + mockFormatService.getFormat.andReturn(mockFormat); + + mockFormat.validate.andCallFake(function (text) { + return moment.utc(text, TEST_FORMAT).isValid(); + }); + mockFormat.parse.andCallFake(function (text) { + return moment.utc(text, TEST_FORMAT).valueOf(); + }); + mockFormat.format.andCallFake(function (value) { + return moment.utc(value).format(TEST_FORMAT); + }); + + mockScope.ngModel = { testField: 12321 }; + mockScope.field = "testField"; + mockScope.structure = { format: "someFormat" }; + + controller = new DateTimeFieldController( + mockScope, + mockFormatService + ); + }); + + it("updates models from user-entered text", function () { + var newText = "1977-05-25 17:30:00"; + + mockScope.textValue = newText; + fireWatch("textValue", newText); + expect(mockScope.ngModel.testField) + .toEqual(mockFormat.parse(newText)); + expect(mockScope.textInvalid).toBeFalsy(); + }); + + it("updates text from model values", function () { + var testTime = mockFormat.parse("1977-05-25 17:30:00"); + mockScope.ngModel.testField = testTime; + fireWatch("ngModel[field]", testTime); + expect(mockScope.textValue).toEqual("1977-05-25 17:30:00"); + }); + + describe("when user input is invalid", function () { + var newText, oldValue; + + beforeEach(function () { + newText = "Not a date"; + oldValue = mockScope.ngModel.testField; + mockScope.textValue = newText; + fireWatch("textValue", newText); + }); + + it("displays error state", function () { + expect(mockScope.textInvalid).toBeTruthy(); + }); + + it("does not modify model state", function () { + expect(mockScope.ngModel.testField).toEqual(oldValue); + }); + + it("does not modify user input", function () { + expect(mockScope.textValue).toEqual(newText); + }); + }); + + it("does not modify valid but irregular user input", function () { + // Don't want the controller "fixing" bad or + // irregularly-formatted input out from under + // the user's fingertips. + var newText = "2015-3-3 01:02:04", + oldValue = mockScope.ngModel.testField; + + mockFormat.validate.andReturn(true); + mockFormat.parse.andReturn(42); + mockScope.textValue = newText; + fireWatch("textValue", newText); + + expect(mockScope.textValue).toEqual(newText); + expect(mockScope.ngModel.testField).toEqual(42); + expect(mockScope.ngModel.testField).not.toEqual(oldValue); + }); + + it("obtains a format from the format service", function () { + fireWatch('structure.format', mockScope.structure.format); + expect(mockFormatService.getFormat) + .toHaveBeenCalledWith(mockScope.structure.format); + }); + + describe("using the obtained format", function () { + var testValue = 1234321, + testText = "some text"; + + beforeEach(function () { + mockFormat.validate.andReturn(true); + mockFormat.parse.andReturn(testValue); + mockFormat.format.andReturn(testText); + }); + + it("parses user input", function () { + var newText = "some other new text"; + mockScope.textValue = newText; + fireWatch("textValue", newText); + expect(mockFormat.parse).toHaveBeenCalledWith(newText); + expect(mockScope.ngModel.testField).toEqual(testValue); + }); + + it("validates user input", function () { + var newText = "some other new text"; + mockScope.textValue = newText; + fireWatch("textValue", newText); + expect(mockFormat.validate).toHaveBeenCalledWith(newText); + }); + + it("formats model data for display", function () { + var newValue = 42; + mockScope.ngModel.testField = newValue; + fireWatch("ngModel[field]", newValue); + expect(mockFormat.format).toHaveBeenCalledWith(newValue); + expect(mockScope.textValue).toEqual(testText); + }); + }); + + }); + } +); diff --git a/platform/commonUI/general/test/suite.json b/platform/commonUI/general/test/suite.json index 0d19fbb9e4..ec91a114e6 100644 --- a/platform/commonUI/general/test/suite.json +++ b/platform/commonUI/general/test/suite.json @@ -3,6 +3,7 @@ "controllers/BottomBarController", "controllers/ClickAwayController", "controllers/ContextMenuController", + "controllers/DateTimeFieldController", "controllers/DateTimePickerController", "controllers/GetterSetterController", "controllers/SelectorController", From 15a5c593fa555507e15a48239644eef9013ce704 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 17:25:08 -0700 Subject: [PATCH 58/79] [Time Conductor] Add spec for formatter Add spec to telemetryFormatter wrapper used by plot to isolate changes to domain/range formats. --- .../elements/PlotTelemetryFormatterSpec.js | 70 +++++++++++++++++++ platform/features/plot/test/suite.json | 1 + 2 files changed, 71 insertions(+) create mode 100644 platform/features/plot/test/elements/PlotTelemetryFormatterSpec.js diff --git a/platform/features/plot/test/elements/PlotTelemetryFormatterSpec.js b/platform/features/plot/test/elements/PlotTelemetryFormatterSpec.js new file mode 100644 index 0000000000..0031a0c813 --- /dev/null +++ b/platform/features/plot/test/elements/PlotTelemetryFormatterSpec.js @@ -0,0 +1,70 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ +/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/ + +define( + ["../../src/elements/PlotTelemetryFormatter"], + function (PlotTelemetryFormatter) { + 'use strict'; + + describe("The PlotTelemetryFormatter", function () { + var mockFormatter, + formatter; + + beforeEach(function () { + mockFormatter = jasmine.createSpyObj( + 'telemetryFormatter', + ['formatDomainValue', 'formatRangeValue'] + ); + formatter = new PlotTelemetryFormatter(mockFormatter); + }); + + describe("using domain & range format keys", function () { + var rangeFormat = "someRangeFormat", + domainFormat = "someDomainFormat"; + + beforeEach(function () { + formatter.setRangeFormat(rangeFormat); + formatter.setDomainFormat(domainFormat); + }); + + it("includes format in formatDomainValue calls", function () { + mockFormatter.formatDomainValue.andReturn("formatted!"); + expect(formatter.formatDomainValue(12321)) + .toEqual("formatted!"); + expect(mockFormatter.formatDomainValue) + .toHaveBeenCalledWith(12321, domainFormat); + }); + + it("includes format in formatRangeValue calls", function () { + mockFormatter.formatRangeValue.andReturn("formatted!"); + expect(formatter.formatRangeValue(12321)) + .toEqual("formatted!"); + expect(mockFormatter.formatRangeValue) + .toHaveBeenCalledWith(12321, rangeFormat); + }); + + }); + + }); + } +); diff --git a/platform/features/plot/test/suite.json b/platform/features/plot/test/suite.json index 323d53b6b3..92dfcb1e8a 100644 --- a/platform/features/plot/test/suite.json +++ b/platform/features/plot/test/suite.json @@ -14,6 +14,7 @@ "elements/PlotPosition", "elements/PlotPreparer", "elements/PlotSeriesWindow", + "elements/PlotTelemetryFormatter", "elements/PlotTickGenerator", "elements/PlotUpdater", "modes/PlotModeOptions", From 8a3f77d7843e1d2f23a92c13cadcbcc6cdbe27f5 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 17:26:08 -0700 Subject: [PATCH 59/79] [Time Conductor] Simplify bundle name --- bundles.json | 2 +- platform/commonUI/{formatting => formats}/bundle.json | 0 platform/commonUI/{formatting => formats}/src/FormatProvider.js | 0 platform/commonUI/{formatting => formats}/src/UTCTimeFormat.js | 0 4 files changed, 1 insertion(+), 1 deletion(-) rename platform/commonUI/{formatting => formats}/bundle.json (100%) rename platform/commonUI/{formatting => formats}/src/FormatProvider.js (100%) rename platform/commonUI/{formatting => formats}/src/UTCTimeFormat.js (100%) diff --git a/bundles.json b/bundles.json index d6159cfe18..48429bdf88 100644 --- a/bundles.json +++ b/bundles.json @@ -6,7 +6,7 @@ "platform/commonUI/browse", "platform/commonUI/edit", "platform/commonUI/dialog", - "platform/commonUI/formatting", + "platform/commonUI/formats", "platform/commonUI/general", "platform/commonUI/inspect", "platform/commonUI/mobile", diff --git a/platform/commonUI/formatting/bundle.json b/platform/commonUI/formats/bundle.json similarity index 100% rename from platform/commonUI/formatting/bundle.json rename to platform/commonUI/formats/bundle.json diff --git a/platform/commonUI/formatting/src/FormatProvider.js b/platform/commonUI/formats/src/FormatProvider.js similarity index 100% rename from platform/commonUI/formatting/src/FormatProvider.js rename to platform/commonUI/formats/src/FormatProvider.js diff --git a/platform/commonUI/formatting/src/UTCTimeFormat.js b/platform/commonUI/formats/src/UTCTimeFormat.js similarity index 100% rename from platform/commonUI/formatting/src/UTCTimeFormat.js rename to platform/commonUI/formats/src/UTCTimeFormat.js From c89aa026b0b8e537d20307d76527a79b48bd90b6 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 17:31:02 -0700 Subject: [PATCH 60/79] [Time Conductor] Add JSDoc for Format interface --- .../commonUI/formats/src/FormatProvider.js | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/platform/commonUI/formats/src/FormatProvider.js b/platform/commonUI/formats/src/FormatProvider.js index 27da9784fb..c5690ca8aa 100644 --- a/platform/commonUI/formats/src/FormatProvider.js +++ b/platform/commonUI/formats/src/FormatProvider.js @@ -28,6 +28,41 @@ define([ ) { "use strict"; + /** + * An object used to convert between numeric values and text values, + * typically used to display these values to the user and to convert + * user input to a numeric format, particularly for time formats. + * @interface {Format} + */ + + /** + * Parse text (typically user input) to a numeric value. + * Behavior is undefined when the text cannot be parsed; + * `validate` should be called first if the text may be invalid. + * @method parse + * @memberof Format# + * @param {string} text the text to parse + * @returns {number} the parsed numeric value + */ + + /** + * Determine whether or not some text (typically user input) can + * be parsed to a numeric value by this format. + * @method validate + * @memberof Format# + * @param {string} text the text to parse + * @returns {boolean} true if the text can be parsed + */ + + /** + * Convert a numeric value to a text value for display using + * this format. + * @method format + * @memberof Format# + * @param {number} value the numeric value to format + * @returns {string} the text representation of the value + */ + function FormatProvider(formats) { var formatMap = {}; From 60ba80d3070d35b8e89d9e9bfbeee9028450c844 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 17:33:41 -0700 Subject: [PATCH 61/79] [Time Conductor] Add empty specs ...to platform/commonUI/formats bundle, introduced to support formatting of non-UTC time domains for time conductor. --- .../formats/test/FormatProviderSpec.js | 33 +++++++++++++++++++ .../formats/test/UTCTimeFormatSpec.js | 33 +++++++++++++++++++ platform/commonUI/formats/test/suite.json | 4 +++ 3 files changed, 70 insertions(+) create mode 100644 platform/commonUI/formats/test/FormatProviderSpec.js create mode 100644 platform/commonUI/formats/test/UTCTimeFormatSpec.js create mode 100644 platform/commonUI/formats/test/suite.json diff --git a/platform/commonUI/formats/test/FormatProviderSpec.js b/platform/commonUI/formats/test/FormatProviderSpec.js new file mode 100644 index 0000000000..5c86596f76 --- /dev/null +++ b/platform/commonUI/formats/test/FormatProviderSpec.js @@ -0,0 +1,33 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ +/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/ + +define( + ['../src/FormatProvider'], + function (FormatProvider) { + 'use strict'; + + describe("The FormatProvider", function () { + + }); + } +); diff --git a/platform/commonUI/formats/test/UTCTimeFormatSpec.js b/platform/commonUI/formats/test/UTCTimeFormatSpec.js new file mode 100644 index 0000000000..0f1efaddb3 --- /dev/null +++ b/platform/commonUI/formats/test/UTCTimeFormatSpec.js @@ -0,0 +1,33 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ +/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/ + +define( + ['../src/UTCTimeFormat'], + function (UTCTimeFormat) { + 'use strict'; + + describe("The UTCTimeFormat", function () { + + }); + } +); diff --git a/platform/commonUI/formats/test/suite.json b/platform/commonUI/formats/test/suite.json new file mode 100644 index 0000000000..06c88fac8b --- /dev/null +++ b/platform/commonUI/formats/test/suite.json @@ -0,0 +1,4 @@ +[ + "FormatProvider", + "UTCTimeFormat" +] From e80d094174069ef77d195ef91d0e2189f48152a5 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 17:39:16 -0700 Subject: [PATCH 62/79] [Time Conductor] Add test cases ...to cover UTCTimeFormat. --- .../formats/test/UTCTimeFormatSpec.js | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/platform/commonUI/formats/test/UTCTimeFormatSpec.js b/platform/commonUI/formats/test/UTCTimeFormatSpec.js index 0f1efaddb3..57f84fed87 100644 --- a/platform/commonUI/formats/test/UTCTimeFormatSpec.js +++ b/platform/commonUI/formats/test/UTCTimeFormatSpec.js @@ -22,12 +22,35 @@ /*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/ define( - ['../src/UTCTimeFormat'], - function (UTCTimeFormat) { + ['../src/UTCTimeFormat', 'moment'], + function (UTCTimeFormat, moment) { 'use strict'; describe("The UTCTimeFormat", function () { + var format; + beforeEach(function () { + format = new UTCTimeFormat(); + }); + + it("formats UTC timestamps", function () { + var timestamp = 12345670000, + formatted = format.format(timestamp); + expect(formatted).toEqual(jasmine.any(String)); + expect(moment.utc(formatted).valueOf()).toEqual(timestamp); + }); + + it("validates time inputs", function () { + expect(format.validate("1977-05-25 11:21:22")).toBeTruthy(); + expect(format.validate("garbage text")).toBeFalsy(); + }); + + it("parses valid input", function () { + var text = "1977-05-25 11:21:22", + parsed = format.parse(text); + expect(parsed).toEqual(jasmine.any(Number)); + expect(parsed).toEqual(moment.utc(text).valueOf()); + }); }); } ); From 00c00191223c1294485c0e16afaed8f9ff83cd44 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 27 Oct 2015 17:44:55 -0700 Subject: [PATCH 63/79] [Time Conductor] Add test cases ...to cover FormatProvider. --- .../formats/test/FormatProviderSpec.js | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/platform/commonUI/formats/test/FormatProviderSpec.js b/platform/commonUI/formats/test/FormatProviderSpec.js index 5c86596f76..63b415711b 100644 --- a/platform/commonUI/formats/test/FormatProviderSpec.js +++ b/platform/commonUI/formats/test/FormatProviderSpec.js @@ -26,7 +26,35 @@ define( function (FormatProvider) { 'use strict'; + var KEYS = [ 'a', 'b', 'c' ]; + describe("The FormatProvider", function () { + var mockFormats, + mockFormatInstances, + provider; + + beforeEach(function () { + mockFormatInstances = KEYS.map(function (k) { + return jasmine.createSpyObj( + 'format-' + k, + [ 'parse', 'validate', 'format' ] + ); + }); + // Return constructors + mockFormats = KEYS.map(function (k, i) { + function MockFormat() { return mockFormatInstances[i]; } + MockFormat.key = k; + return MockFormat; + }); + provider = new FormatProvider(mockFormats); + }); + + it("looks up formats by key", function () { + KEYS.forEach(function (k, i) { + expect(provider.getFormat(k)) + .toEqual(mockFormatInstances[i]); + }); + }); }); } From 0ad22f68427b94d20f65d92419ae70df937094ea Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 28 Oct 2015 08:29:56 -0700 Subject: [PATCH 64/79] [Time Conductor] Add JSDoc to new bundle Add JSDoc to platform/commonUI/formats, introduced to support different time formats from the time conductor. nasa/openmctweb#182. --- .../commonUI/formats/src/FormatProvider.js | 22 +++++++++++++++++++ .../commonUI/formats/src/UTCTimeFormat.js | 8 +++++++ 2 files changed, 30 insertions(+) diff --git a/platform/commonUI/formats/src/FormatProvider.js b/platform/commonUI/formats/src/FormatProvider.js index c5690ca8aa..e72dd52b68 100644 --- a/platform/commonUI/formats/src/FormatProvider.js +++ b/platform/commonUI/formats/src/FormatProvider.js @@ -63,6 +63,28 @@ define([ * @returns {string} the text representation of the value */ + /** + * Provides access to `Format` objects which can be used to + * convert values between human-readable text and numeric + * representations. + * @interface FormatService + */ + + /** + * Look up a format by its symbolic identifier. + * @param {string} key the identifier for this format + * @returns {Format} the format, or `undefined` if no such format + * is known. + */ + + /** + * Provides formats from the `formats` extension category. + * @constructor + * @implements {FormatService} + * @memberof platform/commonUI/formats + * @param {Array.} format constructors, + * from the `formats` extension category. + */ function FormatProvider(formats) { var formatMap = {}; diff --git a/platform/commonUI/formats/src/UTCTimeFormat.js b/platform/commonUI/formats/src/UTCTimeFormat.js index 43028d7e97..f20e1cade9 100644 --- a/platform/commonUI/formats/src/UTCTimeFormat.js +++ b/platform/commonUI/formats/src/UTCTimeFormat.js @@ -37,6 +37,14 @@ define([ ]; + /** + * Formatter for UTC timestamps. Interprets numeric values as + * milliseconds since the start of 1970. + * + * @implements {Format} + * @constructor + * @memberof platform/commonUI/formats + */ function UTCTimeFormat() { } From 0541f6edfa6fd47164bb497f13b7311f65ad75c2 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 28 Oct 2015 08:47:04 -0700 Subject: [PATCH 65/79] [Time Conductor] Add JSDoc to plot Add JSDoc to scripts/methods added to the Plot plug-in to support integration of custom formats for timestamps. --- .../features/plot/src/elements/PlotAxis.js | 9 ++++++++- .../src/elements/PlotTelemetryFormatter.js | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/platform/features/plot/src/elements/PlotAxis.js b/platform/features/plot/src/elements/PlotAxis.js index 29e67d1976..e2f7809c64 100644 --- a/platform/features/plot/src/elements/PlotAxis.js +++ b/platform/features/plot/src/elements/PlotAxis.js @@ -74,7 +74,8 @@ define( /** * Update axis options to reflect current metadata. - * @memberof platform/features/plot.PlotAxis + * @param {TelemetryMetadata[]} metadata objects describing + * applicable telemetry */ PlotAxis.prototype.updateMetadata = function (metadatas) { var axisType = this.axisType, @@ -114,6 +115,12 @@ define( } }; + /** + * Change the domain/range selection for this axis. If the + * provided `key` is not recognized as an option, no change + * will occur. + * @param {string} key the identifier for the domain/range + */ PlotAxis.prototype.chooseOption = function (key) { var self = this; this.options.forEach(function (option) { diff --git a/platform/features/plot/src/elements/PlotTelemetryFormatter.js b/platform/features/plot/src/elements/PlotTelemetryFormatter.js index abe916e99d..de2a86c4a1 100644 --- a/platform/features/plot/src/elements/PlotTelemetryFormatter.js +++ b/platform/features/plot/src/elements/PlotTelemetryFormatter.js @@ -26,14 +26,33 @@ define( function () { 'use strict'; + /** + * Wraps a `TelemetryFormatter` to provide formats for domain and + * range values; provides a single place to track domain/range + * formats within a plot, allowing other plot elements to simply + * request that values be formatted. + * @constructor + * @memberof platform/features/plot + * @implements {platform/telemetry.TelemetryFormatter} + * @param {TelemetryFormatter} telemetryFormatter the formatter + * to wrap. + */ function PlotTelemetryFormatter(telemetryFormatter) { this.telemetryFormatter = telemetryFormatter; } + /** + * Specify the format to use for domain values. + * @param {string} key the format's identifier + */ PlotTelemetryFormatter.prototype.setDomainFormat = function (key) { this.domainFormat = key; }; + /** + * Specify the format to use for range values. + * @param {string} key the format's identifier + */ PlotTelemetryFormatter.prototype.setRangeFormat = function (key) { this.rangeFormat = key; }; From 90389ea910d9b8971602b573fe194e994c7ecefa Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 28 Oct 2015 09:56:50 -0700 Subject: [PATCH 66/79] [Time Conductor] Increase test specificity Explicitly check for boolean values (not just truthy/falsy values) per feedback from code review, nasa/openmctweb#204. --- platform/commonUI/formats/test/UTCTimeFormatSpec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/commonUI/formats/test/UTCTimeFormatSpec.js b/platform/commonUI/formats/test/UTCTimeFormatSpec.js index 57f84fed87..d55a8a9507 100644 --- a/platform/commonUI/formats/test/UTCTimeFormatSpec.js +++ b/platform/commonUI/formats/test/UTCTimeFormatSpec.js @@ -41,8 +41,8 @@ define( }); it("validates time inputs", function () { - expect(format.validate("1977-05-25 11:21:22")).toBeTruthy(); - expect(format.validate("garbage text")).toBeFalsy(); + expect(format.validate("1977-05-25 11:21:22")).toBe(true); + expect(format.validate("garbage text")).toBe(false); }); it("parses valid input", function () { From b6d08726fb16c1a708046b882035ab2e2565ac30 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 30 Oct 2015 09:34:23 -0700 Subject: [PATCH 67/79] [Time Conductor] Remove duplicate format --- platform/commonUI/formats/src/UTCTimeFormat.js | 1 - 1 file changed, 1 deletion(-) diff --git a/platform/commonUI/formats/src/UTCTimeFormat.js b/platform/commonUI/formats/src/UTCTimeFormat.js index f20e1cade9..b035fed99f 100644 --- a/platform/commonUI/formats/src/UTCTimeFormat.js +++ b/platform/commonUI/formats/src/UTCTimeFormat.js @@ -31,7 +31,6 @@ define([ var DATE_FORMAT = "YYYY-MM-DD HH:mm:ss", DATE_FORMATS = [ DATE_FORMAT, - "YYYY-MM-DD HH:mm:ss", "YYYY-MM-DD HH:mm", "YYYY-MM-DD" ]; From 101e3bb34640edde4e0a90cc68eb378c0787d7a5 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 30 Oct 2015 13:04:29 -0700 Subject: [PATCH 68/79] [Time Conductor] Remove checks for undefined domain Per code review, nasa/openmctweb#204 --- platform/features/conductor/src/ConductorRepresenter.js | 5 ++--- .../features/conductor/src/ConductorTelemetryDecorator.js | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/platform/features/conductor/src/ConductorRepresenter.js b/platform/features/conductor/src/ConductorRepresenter.js index 2eaa86b85b..2d1bec36d8 100644 --- a/platform/features/conductor/src/ConductorRepresenter.js +++ b/platform/features/conductor/src/ConductorRepresenter.js @@ -78,11 +78,10 @@ define( // Combine start/end times into a single object function bounds() { - var domain = conductor.domain(); return { start: conductor.displayStart(), end: conductor.displayEnd(), - domain: domain && domain.key + domain: conductor.domain().key }; } @@ -132,7 +131,7 @@ define( { outer: bounds(), inner: bounds() }; conductorScope.ngModel.options = conductor.domainOptions().map(makeOption); - conductorScope.ngModel.domain = (conductor.domain() || {}).key; + conductorScope.ngModel.domain = conductor.domain().key; conductorScope.parameters = {}; conductorScope diff --git a/platform/features/conductor/src/ConductorTelemetryDecorator.js b/platform/features/conductor/src/ConductorTelemetryDecorator.js index f359199ce2..ce5b249eaf 100644 --- a/platform/features/conductor/src/ConductorTelemetryDecorator.js +++ b/platform/features/conductor/src/ConductorTelemetryDecorator.js @@ -51,7 +51,7 @@ define( request = request || {}; request.start = start; request.end = end; - request.domain = domain && domain.key; + request.domain = domain.key; return request; } From 5a1d774b471b1c1d078caae61dceda29cfd0b494 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 30 Oct 2015 13:05:37 -0700 Subject: [PATCH 69/79] [Time Conductor] Rename default domain To UTC, instead of just Time. --- platform/features/conductor/bundle.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/features/conductor/bundle.json b/platform/features/conductor/bundle.json index 10d3f32665..c37f15d97b 100644 --- a/platform/features/conductor/bundle.json +++ b/platform/features/conductor/bundle.json @@ -36,7 +36,7 @@ { "key": "TIME_CONDUCTOR_DOMAINS", "value": [ - { "key": "time", "name": "Time" } + { "key": "time", "name": "UTC", "format": "utc" } ], "priority": "fallback", "comment": "Placeholder; to be replaced by inspection of available domains." From 6db7f056dc9a17d0a9a791125ae9689d439328bd Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 30 Oct 2015 13:11:13 -0700 Subject: [PATCH 70/79] [Time Conductor] Warn about unknown formats --- platform/commonUI/formats/bundle.json | 2 +- platform/commonUI/formats/src/FormatProvider.js | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/platform/commonUI/formats/bundle.json b/platform/commonUI/formats/bundle.json index 738ce1bb63..8f9b23d5f5 100644 --- a/platform/commonUI/formats/bundle.json +++ b/platform/commonUI/formats/bundle.json @@ -7,7 +7,7 @@ "provides": "formatService", "type": "provider", "implementation": "FormatProvider.js", - "depends": [ "formats[]" ] + "depends": [ "formats[]", "$log" ] } ], "formats": [ diff --git a/platform/commonUI/formats/src/FormatProvider.js b/platform/commonUI/formats/src/FormatProvider.js index e72dd52b68..421d9bfd39 100644 --- a/platform/commonUI/formats/src/FormatProvider.js +++ b/platform/commonUI/formats/src/FormatProvider.js @@ -85,7 +85,7 @@ define([ * @param {Array.} format constructors, * from the `formats` extension category. */ - function FormatProvider(formats) { + function FormatProvider(formats, $log) { var formatMap = {}; function addToMap(Format) { @@ -97,10 +97,15 @@ define([ formats.forEach(addToMap); this.formatMap = formatMap; + this.$log = $log; } FormatProvider.prototype.getFormat = function (key) { - return this.formatMap[key]; + var format = this.formatMap[key]; + if (!format) { + this.$log.warn("No format found for " + key); + } + return format; }; return FormatProvider; From 4f9a65a5fee87ae3fd7a34c25d5f0d7063441500 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 30 Oct 2015 13:17:53 -0700 Subject: [PATCH 71/79] [Time Conductor] Use default format ...from TelemetryFormatter, and log when a requested format is unavailable. --- platform/commonUI/formats/bundle.json | 6 ++++++ platform/telemetry/bundle.json | 2 +- platform/telemetry/src/TelemetryFormatter.js | 12 ++++++++---- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/platform/commonUI/formats/bundle.json b/platform/commonUI/formats/bundle.json index 8f9b23d5f5..798bcc7369 100644 --- a/platform/commonUI/formats/bundle.json +++ b/platform/commonUI/formats/bundle.json @@ -15,6 +15,12 @@ "key": "utc", "implementation": "UTCTimeFormat.js" } + ], + "constants": [ + { + "key": "DEFAULT_TIME_FORMAT", + "value": "utc" + } ] } } diff --git a/platform/telemetry/bundle.json b/platform/telemetry/bundle.json index 79cf4d503a..bb21ccaa35 100644 --- a/platform/telemetry/bundle.json +++ b/platform/telemetry/bundle.json @@ -38,7 +38,7 @@ { "key": "telemetryFormatter", "implementation": "TelemetryFormatter.js", - "depends": [ "formatService" ] + "depends": [ "formatService", "DEFAULT_TIME_FORMAT", "$log" ] }, { "key": "telemetrySubscriber", diff --git a/platform/telemetry/src/TelemetryFormatter.js b/platform/telemetry/src/TelemetryFormatter.js index 125d92710c..1aa24b644d 100644 --- a/platform/telemetry/src/TelemetryFormatter.js +++ b/platform/telemetry/src/TelemetryFormatter.js @@ -37,8 +37,10 @@ define( * @memberof platform/telemetry * @constructor */ - function TelemetryFormatter(formatService) { + function TelemetryFormatter(formatService, defaultFormatKey, $log) { this.formatService = formatService; + this.defaultFormat = formatService.getFormat(defaultFormatKey); + this.$log = $log; } /** @@ -51,9 +53,11 @@ define( * data and time, suitable for display. */ TelemetryFormatter.prototype.formatDomainValue = function (v, key) { - var formatter = this.formatService.getFormat(key) || - this.formatService.getFormat('utc'); - return isNaN(v) ? "" : formatter.format(v); + var formatter = (key === undefined) ? + this.defaultFormat : + this.formatService.getFormat(key); + + return isNaN(v) ? "" : formatter ? formatter.format(v) : String(v); }; /** From 7f571415dcff130ffcb9a9f5190a77d3da1782a5 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 30 Oct 2015 13:28:01 -0700 Subject: [PATCH 72/79] [Time Conductor] Change format handling Use default format when no format is specified, and throw an error when a specified format is unrecognized, from both date-time field controller and time range controller. --- platform/commonUI/general/bundle.json | 4 ++-- .../src/controllers/DateTimeFieldController.js | 13 ++++++++----- .../src/controllers/TimeRangeController.js | 17 +++++++++++------ 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/platform/commonUI/general/bundle.json b/platform/commonUI/general/bundle.json index eee42ef4cd..09e523d105 100644 --- a/platform/commonUI/general/bundle.json +++ b/platform/commonUI/general/bundle.json @@ -53,7 +53,7 @@ { "key": "TimeRangeController", "implementation": "controllers/TimeRangeController.js", - "depends": [ "$scope", "formatService", "now" ] + "depends": [ "$scope", "formatService", "DEFAULT_TIME_FORMAT", "now" ] }, { "key": "DateTimePickerController", @@ -63,7 +63,7 @@ { "key": "DateTimeFieldController", "implementation": "controllers/DateTimeFieldController.js", - "depends": [ "$scope", "formatService" ] + "depends": [ "$scope", "formatService", "DEFAULT_TIME_FORMAT" ] }, { "key": "TreeNodeController", diff --git a/platform/commonUI/general/src/controllers/DateTimeFieldController.js b/platform/commonUI/general/src/controllers/DateTimeFieldController.js index 5c48cc2453..950dcc21e2 100644 --- a/platform/commonUI/general/src/controllers/DateTimeFieldController.js +++ b/platform/commonUI/general/src/controllers/DateTimeFieldController.js @@ -26,7 +26,8 @@ define( function () { 'use strict'; - var DEFAULT_FORMAT = 'utc'; + var UNRECOGNIZED_FORMAT_ERROR = + "Unrecognized format for date-time field."; /** * Controller to support the date-time entry field. @@ -40,12 +41,14 @@ define( * @constructor * @memberof platform/commonUI/general */ - function DateTimeFieldController($scope, formatService) { - var formatter = formatService.getFormat(DEFAULT_FORMAT); + function DateTimeFieldController($scope, formatService, defaultFormat) { + var formatter = formatService.getFormat(defaultFormat); function setFormat(format) { - formatter = formatService.getFormat(format) || - formatService.getFormat(DEFAULT_FORMAT); + formatter = formatService.getFormat(format || defaultFormat); + if (!formatter) { + throw new Error(UNRECOGNIZED_FORMAT_ERROR); + } } function updateFromModel(value) { diff --git a/platform/commonUI/general/src/controllers/TimeRangeController.js b/platform/commonUI/general/src/controllers/TimeRangeController.js index 85fad1100c..fd30d3a231 100644 --- a/platform/commonUI/general/src/controllers/TimeRangeController.js +++ b/platform/commonUI/general/src/controllers/TimeRangeController.js @@ -26,20 +26,22 @@ define( function (moment) { "use strict"; - var DEFAULT_FORMAT = "utc", - TICK_SPACING_PX = 150; + var TICK_SPACING_PX = 150, + UNRECOGNIZED_FORMAT_ERROR = + "Unrecognized format for time range control."; + /** * Controller used by the `time-controller` template. * @memberof platform/commonUI/general * @constructor */ - function TimeRangeController($scope, formatService, now) { + function TimeRangeController($scope, formatService, defaultFormat, now) { var tickCount = 2, innerMinimumSpan = 1000, // 1 second outerMinimumSpan = 1000 * 60 * 60, // 1 hour initialDragValue, - formatter = formatService.getFormat(DEFAULT_FORMAT); + formatter = formatService.getFormat(defaultFormat); function formatTimestamp(ts) { return formatter.format(ts); @@ -212,8 +214,11 @@ define( } function updateFormat(key) { - formatter = formatService.getFormat(key) || - formatService.getFormat(DEFAULT_FORMAT); + formatter = formatService.getFormat(key || defaultFormat); + + if (!formatter) { + throw new Error(UNRECOGNIZED_FORMAT_ERROR); + } updateViewForInnerSpanFromModel($scope.ngModel); updateTicks(); From f42498ab60fd923dcb5502bd1b46f980e8ffa7fa Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 30 Oct 2015 13:53:33 -0700 Subject: [PATCH 73/79] [Time Conductor] Update specs ...to reflect changes to how unspecified versus unknown formats are handled. --- platform/commonUI/formats/test/FormatProviderSpec.js | 11 ++++++++++- .../test/controllers/DateTimeFieldControllerSpec.js | 7 +++++++ .../test/controllers/TimeRangeControllerSpec.js | 9 +++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/platform/commonUI/formats/test/FormatProviderSpec.js b/platform/commonUI/formats/test/FormatProviderSpec.js index 63b415711b..2a102909cc 100644 --- a/platform/commonUI/formats/test/FormatProviderSpec.js +++ b/platform/commonUI/formats/test/FormatProviderSpec.js @@ -30,6 +30,7 @@ define( describe("The FormatProvider", function () { var mockFormats, + mockLog, mockFormatInstances, provider; @@ -40,13 +41,14 @@ define( [ 'parse', 'validate', 'format' ] ); }); + mockLog = jasmine.createSpyObj('$log', ['error', 'warn']); // Return constructors mockFormats = KEYS.map(function (k, i) { function MockFormat() { return mockFormatInstances[i]; } MockFormat.key = k; return MockFormat; }); - provider = new FormatProvider(mockFormats); + provider = new FormatProvider(mockFormats, mockLog); }); it("looks up formats by key", function () { @@ -56,6 +58,13 @@ define( }); }); + it("warns about unknown formats", function () { + provider.getFormat('a'); // known format + expect(mockLog.warn).not.toHaveBeenCalled(); + provider.getFormat('some-unknown-format'); + expect(mockLog.warn).toHaveBeenCalledWith(jasmine.any(String)); + }); + }); } ); diff --git a/platform/commonUI/general/test/controllers/DateTimeFieldControllerSpec.js b/platform/commonUI/general/test/controllers/DateTimeFieldControllerSpec.js index 0d6ab6eeb1..8f516ece5d 100644 --- a/platform/commonUI/general/test/controllers/DateTimeFieldControllerSpec.js +++ b/platform/commonUI/general/test/controllers/DateTimeFieldControllerSpec.js @@ -137,6 +137,13 @@ define( .toHaveBeenCalledWith(mockScope.structure.format); }); + it("throws an error for unknown formats", function () { + mockFormatService.getFormat.andReturn(undefined); + expect(function () { + fireWatch("structure.format", "some-format"); + }).toThrow(); + }); + describe("using the obtained format", function () { var testValue = 1234321, testText = "some text"; diff --git a/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js b/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js index 4b0f3de9e6..85e77e4889 100644 --- a/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js +++ b/platform/commonUI/general/test/controllers/TimeRangeControllerSpec.js @@ -34,6 +34,7 @@ define( describe("The TimeRangeController", function () { var mockScope, mockFormatService, + testDefaultFormat, mockNow, mockFormat, controller; @@ -63,6 +64,7 @@ define( "formatService", [ "getFormat" ] ); + testDefaultFormat = 'utc'; mockFormat = jasmine.createSpyObj( "format", [ "validate", "format", "parse" ] @@ -79,6 +81,7 @@ define( controller = new TimeRangeController( mockScope, mockFormatService, + testDefaultFormat, mockNow ); }); @@ -199,6 +202,12 @@ define( .toHaveBeenCalledWith('test-format'); }); + it("throws an error for unknown formats", function () { + mockFormatService.getFormat.andReturn(undefined); + expect(function () { + fireWatch("parameters.format", "some-format"); + }).toThrow(); + }); }); } From b12bb55495e7e608cf718c89810ffa3b795edaa9 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 30 Oct 2015 13:57:21 -0700 Subject: [PATCH 74/79] [Time Conductor] Update text on format change ...in a date-time field. --- .../src/controllers/DateTimeFieldController.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/platform/commonUI/general/src/controllers/DateTimeFieldController.js b/platform/commonUI/general/src/controllers/DateTimeFieldController.js index 950dcc21e2..40e80a99b2 100644 --- a/platform/commonUI/general/src/controllers/DateTimeFieldController.js +++ b/platform/commonUI/general/src/controllers/DateTimeFieldController.js @@ -44,13 +44,6 @@ define( function DateTimeFieldController($scope, formatService, defaultFormat) { var formatter = formatService.getFormat(defaultFormat); - function setFormat(format) { - formatter = formatService.getFormat(format || defaultFormat); - if (!formatter) { - throw new Error(UNRECOGNIZED_FORMAT_ERROR); - } - } - function updateFromModel(value) { // Only reformat if the value is different from user // input (to avoid reformatting valid input while typing.) @@ -69,6 +62,14 @@ define( } } + function setFormat(format) { + formatter = formatService.getFormat(format || defaultFormat); + if (!formatter) { + throw new Error(UNRECOGNIZED_FORMAT_ERROR); + } + updateFromModel($scope.ngModel[$scope.field]); + } + $scope.$watch('structure.format', setFormat); $scope.$watch('ngModel[field]', updateFromModel); $scope.$watch('textValue', updateFromView); From 796d6b800aa76bd71ceb31f5ecef1fa95068d9d2 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 30 Oct 2015 14:08:11 -0700 Subject: [PATCH 75/79] [Time Conductor] Add JSDoc for params --- .../general/src/controllers/DateTimeFieldController.js | 5 +++++ .../commonUI/general/src/controllers/TimeRangeController.js | 6 ++++++ platform/telemetry/src/TelemetryFormatter.js | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/platform/commonUI/general/src/controllers/DateTimeFieldController.js b/platform/commonUI/general/src/controllers/DateTimeFieldController.js index 40e80a99b2..7b58834aa5 100644 --- a/platform/commonUI/general/src/controllers/DateTimeFieldController.js +++ b/platform/commonUI/general/src/controllers/DateTimeFieldController.js @@ -40,6 +40,11 @@ define( * {@see FormatService} * @constructor * @memberof platform/commonUI/general + * @param $scope the Angular scope for this controller + * @param {FormatService} formatService the service to user to format + * domain values + * @param {string} defaultFormat the format to request when no + * format has been otherwise specified */ function DateTimeFieldController($scope, formatService, defaultFormat) { var formatter = formatService.getFormat(defaultFormat); diff --git a/platform/commonUI/general/src/controllers/TimeRangeController.js b/platform/commonUI/general/src/controllers/TimeRangeController.js index fd30d3a231..b0ef5efe70 100644 --- a/platform/commonUI/general/src/controllers/TimeRangeController.js +++ b/platform/commonUI/general/src/controllers/TimeRangeController.js @@ -35,6 +35,12 @@ define( * Controller used by the `time-controller` template. * @memberof platform/commonUI/general * @constructor + * @param $scope the Angular scope for this controller + * @param {FormatService} formatService the service to user to format + * domain values + * @param {string} defaultFormat the format to request when no + * format has been otherwise specified + * @param {Function} now a function to return current system time */ function TimeRangeController($scope, formatService, defaultFormat, now) { var tickCount = 2, diff --git a/platform/telemetry/src/TelemetryFormatter.js b/platform/telemetry/src/TelemetryFormatter.js index 1aa24b644d..cff80cf355 100644 --- a/platform/telemetry/src/TelemetryFormatter.js +++ b/platform/telemetry/src/TelemetryFormatter.js @@ -36,6 +36,11 @@ define( * the range (usually value) of a data series. * @memberof platform/telemetry * @constructor + * @param {FormatService} formatService the service to user to format + * domain values + * @param {string} defaultFormatKey the format to request when no + * format has been otherwise specified + * @param $log Angular's `$log`, to log warnings */ function TelemetryFormatter(formatService, defaultFormatKey, $log) { this.formatService = formatService; From a1d765f2712a83d6026a852d34c2041f7a5c301d Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 2 Nov 2015 12:23:13 -0800 Subject: [PATCH 76/79] [Time Conductor] Throw errors for unknown formats Per code review, nasa/openmctweb#204 --- platform/commonUI/formats/bundle.json | 2 +- platform/commonUI/formats/src/FormatProvider.js | 5 ++--- platform/commonUI/formats/test/FormatProviderSpec.js | 12 +++++------- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/platform/commonUI/formats/bundle.json b/platform/commonUI/formats/bundle.json index 798bcc7369..99925657b2 100644 --- a/platform/commonUI/formats/bundle.json +++ b/platform/commonUI/formats/bundle.json @@ -7,7 +7,7 @@ "provides": "formatService", "type": "provider", "implementation": "FormatProvider.js", - "depends": [ "formats[]", "$log" ] + "depends": [ "formats[]" ] } ], "formats": [ diff --git a/platform/commonUI/formats/src/FormatProvider.js b/platform/commonUI/formats/src/FormatProvider.js index 421d9bfd39..bcc0e64157 100644 --- a/platform/commonUI/formats/src/FormatProvider.js +++ b/platform/commonUI/formats/src/FormatProvider.js @@ -85,7 +85,7 @@ define([ * @param {Array.} format constructors, * from the `formats` extension category. */ - function FormatProvider(formats, $log) { + function FormatProvider(formats) { var formatMap = {}; function addToMap(Format) { @@ -97,13 +97,12 @@ define([ formats.forEach(addToMap); this.formatMap = formatMap; - this.$log = $log; } FormatProvider.prototype.getFormat = function (key) { var format = this.formatMap[key]; if (!format) { - this.$log.warn("No format found for " + key); + throw new Error("FormatProvider: No format found for " + key); } return format; }; diff --git a/platform/commonUI/formats/test/FormatProviderSpec.js b/platform/commonUI/formats/test/FormatProviderSpec.js index 2a102909cc..4f68c106f7 100644 --- a/platform/commonUI/formats/test/FormatProviderSpec.js +++ b/platform/commonUI/formats/test/FormatProviderSpec.js @@ -41,14 +41,13 @@ define( [ 'parse', 'validate', 'format' ] ); }); - mockLog = jasmine.createSpyObj('$log', ['error', 'warn']); // Return constructors mockFormats = KEYS.map(function (k, i) { function MockFormat() { return mockFormatInstances[i]; } MockFormat.key = k; return MockFormat; }); - provider = new FormatProvider(mockFormats, mockLog); + provider = new FormatProvider(mockFormats); }); it("looks up formats by key", function () { @@ -58,11 +57,10 @@ define( }); }); - it("warns about unknown formats", function () { - provider.getFormat('a'); // known format - expect(mockLog.warn).not.toHaveBeenCalled(); - provider.getFormat('some-unknown-format'); - expect(mockLog.warn).toHaveBeenCalledWith(jasmine.any(String)); + it("throws an error about unknown formats", function () { + expect(function () { + provider.getFormat('some-unknown-format'); + }).toThrow(); }); }); From cecc52f0a9f385979eb4ed9d65136dc69761a925 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 2 Nov 2015 12:28:46 -0800 Subject: [PATCH 77/79] [Time Conductor] Update formatService usages ...to remove checks for unknown formats. --- .../general/src/controllers/DateTimeFieldController.js | 6 ------ .../general/src/controllers/TimeRangeController.js | 9 +-------- platform/telemetry/bundle.json | 2 +- platform/telemetry/src/TelemetryFormatter.js | 6 ++---- 4 files changed, 4 insertions(+), 19 deletions(-) diff --git a/platform/commonUI/general/src/controllers/DateTimeFieldController.js b/platform/commonUI/general/src/controllers/DateTimeFieldController.js index 7b58834aa5..b87268dc5a 100644 --- a/platform/commonUI/general/src/controllers/DateTimeFieldController.js +++ b/platform/commonUI/general/src/controllers/DateTimeFieldController.js @@ -26,9 +26,6 @@ define( function () { 'use strict'; - var UNRECOGNIZED_FORMAT_ERROR = - "Unrecognized format for date-time field."; - /** * Controller to support the date-time entry field. * @@ -69,9 +66,6 @@ define( function setFormat(format) { formatter = formatService.getFormat(format || defaultFormat); - if (!formatter) { - throw new Error(UNRECOGNIZED_FORMAT_ERROR); - } updateFromModel($scope.ngModel[$scope.field]); } diff --git a/platform/commonUI/general/src/controllers/TimeRangeController.js b/platform/commonUI/general/src/controllers/TimeRangeController.js index b0ef5efe70..cdcdb7f8d0 100644 --- a/platform/commonUI/general/src/controllers/TimeRangeController.js +++ b/platform/commonUI/general/src/controllers/TimeRangeController.js @@ -26,9 +26,7 @@ define( function (moment) { "use strict"; - var TICK_SPACING_PX = 150, - UNRECOGNIZED_FORMAT_ERROR = - "Unrecognized format for time range control."; + var TICK_SPACING_PX = 150; /** @@ -221,11 +219,6 @@ define( function updateFormat(key) { formatter = formatService.getFormat(key || defaultFormat); - - if (!formatter) { - throw new Error(UNRECOGNIZED_FORMAT_ERROR); - } - updateViewForInnerSpanFromModel($scope.ngModel); updateTicks(); } diff --git a/platform/telemetry/bundle.json b/platform/telemetry/bundle.json index bb21ccaa35..d264a1d6c0 100644 --- a/platform/telemetry/bundle.json +++ b/platform/telemetry/bundle.json @@ -38,7 +38,7 @@ { "key": "telemetryFormatter", "implementation": "TelemetryFormatter.js", - "depends": [ "formatService", "DEFAULT_TIME_FORMAT", "$log" ] + "depends": [ "formatService", "DEFAULT_TIME_FORMAT" ] }, { "key": "telemetrySubscriber", diff --git a/platform/telemetry/src/TelemetryFormatter.js b/platform/telemetry/src/TelemetryFormatter.js index cff80cf355..dd434d4ac3 100644 --- a/platform/telemetry/src/TelemetryFormatter.js +++ b/platform/telemetry/src/TelemetryFormatter.js @@ -40,12 +40,10 @@ define( * domain values * @param {string} defaultFormatKey the format to request when no * format has been otherwise specified - * @param $log Angular's `$log`, to log warnings */ - function TelemetryFormatter(formatService, defaultFormatKey, $log) { + function TelemetryFormatter(formatService, defaultFormatKey) { this.formatService = formatService; this.defaultFormat = formatService.getFormat(defaultFormatKey); - this.$log = $log; } /** @@ -62,7 +60,7 @@ define( this.defaultFormat : this.formatService.getFormat(key); - return isNaN(v) ? "" : formatter ? formatter.format(v) : String(v); + return isNaN(v) ? "" : formatter.format(v); }; /** From 2d1faeba8c755518f1fe13c3caafa1ae354a05af Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 2 Nov 2015 12:30:18 -0800 Subject: [PATCH 78/79] [Time Conductor] Update FormatService JSDoc --- platform/commonUI/formats/src/FormatProvider.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platform/commonUI/formats/src/FormatProvider.js b/platform/commonUI/formats/src/FormatProvider.js index bcc0e64157..e6d38fbcee 100644 --- a/platform/commonUI/formats/src/FormatProvider.js +++ b/platform/commonUI/formats/src/FormatProvider.js @@ -72,9 +72,11 @@ define([ /** * Look up a format by its symbolic identifier. + * @method getFormat + * @memberof FormatService# * @param {string} key the identifier for this format - * @returns {Format} the format, or `undefined` if no such format - * is known. + * @returns {Format} the format + * @throws {Error} errors when the requested format is unrecognized */ /** From 8d65335786aeb84ea1b4c43bad7566703d3be7d4 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 2 Nov 2015 12:31:40 -0800 Subject: [PATCH 79/79] [Time Conductor] Remove check for domain existence --- platform/features/conductor/src/ConductorRepresenter.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/platform/features/conductor/src/ConductorRepresenter.js b/platform/features/conductor/src/ConductorRepresenter.js index 2d1bec36d8..3b9cb58be4 100644 --- a/platform/features/conductor/src/ConductorRepresenter.js +++ b/platform/features/conductor/src/ConductorRepresenter.js @@ -101,8 +101,7 @@ define( function updateDomain(value) { var newDomain = conductor.domain(value); - conductorScope.parameters.format = - newDomain && newDomain.format; + conductorScope.parameters.format = newDomain.format; repScope.$broadcast('telemetry:display:bounds', bounds()); }