Compare commits
	
		
			18 Commits
		
	
	
		
			plot-sync
			...
			eagle-spri
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | eca3c57bd8 | ||
|   | 7753703034 | ||
|   | f9060a485d | ||
|   | 39a7f43cd0 | ||
|   | 5103207a70 | ||
|   | 8c2cc90f04 | ||
|   | ce431848b3 | ||
|   | 5726fe6313 | ||
|   | 6145843e86 | ||
|   | 0225cbab6a | ||
|   | e477beb587 | ||
|   | ee5d59024a | ||
|   | 5288dadafb | ||
|   | 7f3cc09cbc | ||
|   | 94fa70abb1 | ||
|   | 12574a1333 | ||
|   | 8c72729a2a | ||
|   | 129ab1791b | 
| @@ -1,146 +0,0 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2017, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
| /*global define*/ | ||||
|  | ||||
| define([ | ||||
|     'legacyRegistry', | ||||
|     '../../platform/commonUI/browse/src/InspectorRegion', | ||||
|     '../../platform/commonUI/regions/src/Region' | ||||
| ], function ( | ||||
|     legacyRegistry, | ||||
|     InspectorRegion, | ||||
|     Region | ||||
| ) { | ||||
|     "use strict"; | ||||
|  | ||||
|     /** | ||||
|      * Add a 'plot options' region part to the inspector region for the | ||||
|      * Telemetry Plot type only. {@link InspectorRegion} is a default region | ||||
|      * implementation that is added automatically to all types. In order to | ||||
|      * customize what appears in the inspector region, you can start from a | ||||
|      * blank slate by using Region, or customize the default inspector | ||||
|      * region by using {@link InspectorRegion}. | ||||
|      */ | ||||
|     var plotInspector = new InspectorRegion(), | ||||
|      /** | ||||
|       * Two region parts are defined here. One that appears only in browse | ||||
|       * mode, and one that appears only in edit mode. For not they both point | ||||
|       * to the same representation, but a different key could be used here to | ||||
|       * include a customized representation for edit mode. | ||||
|       */ | ||||
|         plotOptionsBrowseRegion = new Region({ | ||||
|             name: "plot-options", | ||||
|             title: "Plot Options", | ||||
|             modes: ['browse'], | ||||
|             content: { | ||||
|                 key: "plot-options-browse" | ||||
|             } | ||||
|         }), | ||||
|         plotOptionsEditRegion = new Region({ | ||||
|             name: "plot-options", | ||||
|             title: "Plot Options", | ||||
|             modes: ['edit'], | ||||
|             content: { | ||||
|                 key: "plot-options-browse" | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|     /** | ||||
|      * Both parts are added, and policies of type 'region' will determine | ||||
|      * which is shown based on domain object state. A default policy is | ||||
|      * provided which will check the 'modes' attribute of the region part | ||||
|      * definition. | ||||
|      */ | ||||
|     plotInspector.addRegion(plotOptionsBrowseRegion); | ||||
|     plotInspector.addRegion(plotOptionsEditRegion); | ||||
|  | ||||
|     legacyRegistry.register("example/plotType", { | ||||
|         "name": "Plot Type", | ||||
|         "description": "Example illustrating registration of a new object type", | ||||
|         "extensions": { | ||||
|             "types": [ | ||||
|                 { | ||||
|                     "key": "plot", | ||||
|                     "name": "Example Telemetry Plot", | ||||
|                     "cssClass": "icon-telemetry-panel", | ||||
|                     "description": "For development use. A plot for displaying telemetry.", | ||||
|                     "priority": 10, | ||||
|                     "delegates": [ | ||||
|                         "telemetry" | ||||
|                     ], | ||||
|                     "features": "creation", | ||||
|                     "contains": [ | ||||
|                         { | ||||
|                             "has": "telemetry" | ||||
|                         } | ||||
|                     ], | ||||
|                     "model": { | ||||
|                         "composition": [] | ||||
|                     }, | ||||
|                     "inspector": plotInspector, | ||||
|                     "telemetry": { | ||||
|                         "source": "generator", | ||||
|                         "domains": [ | ||||
|                             { | ||||
|                                 "key": "time", | ||||
|                                 "name": "Time" | ||||
|                             }, | ||||
|                             { | ||||
|                                 "key": "yesterday", | ||||
|                                 "name": "Yesterday" | ||||
|                             }, | ||||
|                             { | ||||
|                                 "key": "delta", | ||||
|                                 "name": "Delta", | ||||
|                                 "format": "example.delta" | ||||
|                             } | ||||
|                         ], | ||||
|                         "ranges": [ | ||||
|                             { | ||||
|                                 "key": "sin", | ||||
|                                 "name": "Sine" | ||||
|                             }, | ||||
|                             { | ||||
|                                 "key": "cos", | ||||
|                                 "name": "Cosine" | ||||
|                             } | ||||
|                         ] | ||||
|                     }, | ||||
|                     "properties": [ | ||||
|                         { | ||||
|                             "name": "Period", | ||||
|                             "control": "textfield", | ||||
|                             "cssClass": "l-input-sm l-numeric", | ||||
|                             "key": "period", | ||||
|                             "required": true, | ||||
|                             "property": [ | ||||
|                                 "telemetry", | ||||
|                                 "period" | ||||
|                             ], | ||||
|                             "pattern": "^\\d*(\\.\\d*)?$" | ||||
|                         } | ||||
|                     ] | ||||
|                 } | ||||
|             ] | ||||
|         } | ||||
|     }); | ||||
| }); | ||||
| @@ -37,14 +37,13 @@ module.exports = function(config) { | ||||
|             {pattern: 'bower_components/**/*.js', included: false}, | ||||
|             {pattern: 'node_modules/d3-*/**/*.js', included: false}, | ||||
|             {pattern: 'node_modules/vue/**/*.js', included: false}, | ||||
|             {pattern: 'src/**/*.js', included: false}, | ||||
|             {pattern: 'src/**/*', included: false}, | ||||
|             {pattern: 'example/**/*.html', included: false}, | ||||
|             {pattern: 'example/**/*.js', included: false}, | ||||
|             {pattern: 'example/**/*.json', included: false}, | ||||
|             {pattern: 'platform/**/*.js', included: false}, | ||||
|             {pattern: 'warp/**/*.js', included: false}, | ||||
|             {pattern: 'platform/**/*.html', included: false}, | ||||
|             {pattern: 'src/**/*.html', included: false}, | ||||
|             'test-main.js' | ||||
|         ], | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "openmct", | ||||
|   "version": "0.12.1-SNAPSHOT", | ||||
|   "version": "0.13.3-SNAPSHOT", | ||||
|   "description": "The Open MCT core platform", | ||||
|   "dependencies": { | ||||
|     "d3-array": "^1.0.2", | ||||
| @@ -28,7 +28,7 @@ | ||||
|     "gulp-jshint-html-reporter": "^0.1.3", | ||||
|     "gulp-rename": "^1.2.2", | ||||
|     "gulp-requirejs-optimize": "^0.3.1", | ||||
|     "gulp-sass": "^2.2.0", | ||||
|     "gulp-sass": "^3.1.0", | ||||
|     "gulp-sourcemaps": "^1.6.0", | ||||
|     "jasmine-core": "^2.3.0", | ||||
|     "jscs-html-reporter": "^0.1.0", | ||||
|   | ||||
| @@ -38,6 +38,7 @@ | ||||
|                   ng-class="{ last:($index + 1) === contextualParents.length }"> | ||||
|                 <mct-representation key="'label'" | ||||
|                                     mct-object="parent" | ||||
|                                     ng-click="parent.getCapability('action').perform('navigate')" | ||||
|                                     class="location-item"> | ||||
|                 </mct-representation> | ||||
|             </span> | ||||
| @@ -49,6 +50,7 @@ | ||||
|                   ng-class="{ last:($index + 1) === primaryParents.length }"> | ||||
|                 <mct-representation key="'label'" | ||||
|                                     mct-object="parent" | ||||
|                                     ng-click="parent.getCapability('action').perform('navigate')" | ||||
|                                     class="location-item"> | ||||
|                 </mct-representation> | ||||
|             </span> | ||||
|   | ||||
| @@ -88,11 +88,15 @@ define( | ||||
|          * @private | ||||
|          */ | ||||
|         ElementsController.prototype.refreshComposition = function (domainObject) { | ||||
|             var selectedObjectComposition = domainObject && domainObject.useCapability('composition'); | ||||
|             var refreshTracker = {}; | ||||
|             this.currentRefresh = refreshTracker; | ||||
|  | ||||
|             var selectedObjectComposition = domainObject && domainObject.useCapability('composition'); | ||||
|             if (selectedObjectComposition) { | ||||
|                 selectedObjectComposition.then(function (composition) { | ||||
|                     this.scope.composition = composition; | ||||
|                     if (this.currentRefresh === refreshTracker) { | ||||
|                         this.scope.composition = composition; | ||||
|                     } | ||||
|                 }.bind(this)); | ||||
|             } else { | ||||
|                 this.scope.composition = []; | ||||
|   | ||||
| @@ -31,11 +31,34 @@ define( | ||||
|                 mockSelection, | ||||
|                 mockDomainObject, | ||||
|                 mockMutationCapability, | ||||
|                 mockCompositionCapability, | ||||
|                 mockCompositionObjects, | ||||
|                 mockComposition, | ||||
|                 mockUnlisten, | ||||
|                 selectable = [], | ||||
|                 controller; | ||||
|  | ||||
|             function mockPromise(value) { | ||||
|                 return { | ||||
|                     then: function (thenFunc) { | ||||
|                         return mockPromise(thenFunc(value)); | ||||
|                     } | ||||
|                 }; | ||||
|             } | ||||
|  | ||||
|             function createDomainObject() { | ||||
|                 return { | ||||
|                     useCapability: function () { | ||||
|                         return mockCompositionCapability; | ||||
|                     } | ||||
|                 }; | ||||
|             } | ||||
|  | ||||
|             beforeEach(function () { | ||||
|                 mockComposition = ["a", "b"]; | ||||
|                 mockCompositionObjects = mockComposition.map(createDomainObject); | ||||
|                 mockCompositionCapability = mockPromise(mockCompositionObjects); | ||||
|  | ||||
|                 mockUnlisten = jasmine.createSpy('unlisten'); | ||||
|                 mockMutationCapability = jasmine.createSpyObj("mutationCapability", [ | ||||
|                     "listen" | ||||
| @@ -45,7 +68,7 @@ define( | ||||
|                     "getCapability", | ||||
|                     "useCapability" | ||||
|                 ]); | ||||
|                 mockDomainObject.useCapability.andCallThrough(); | ||||
|                 mockDomainObject.useCapability.andReturn(mockCompositionCapability); | ||||
|                 mockDomainObject.getCapability.andReturn(mockMutationCapability); | ||||
|  | ||||
|                 mockScope = jasmine.createSpyObj("$scope", ['$on']); | ||||
| @@ -65,7 +88,7 @@ define( | ||||
|                     } | ||||
|                 }; | ||||
|  | ||||
|                 spyOn(ElementsController.prototype, 'refreshComposition'); | ||||
|                 spyOn(ElementsController.prototype, 'refreshComposition').andCallThrough(); | ||||
|  | ||||
|                 controller = new ElementsController(mockScope, mockOpenMCT); | ||||
|             }); | ||||
| @@ -137,6 +160,25 @@ define( | ||||
|  | ||||
|                 expect(mockDomainObject.getCapability).not.toHaveBeenCalledWith('mutation'); | ||||
|             }); | ||||
|  | ||||
|             it("checks concurrent changes to composition", function () { | ||||
|                 var secondMockComposition = ["a", "b", "c"], | ||||
|                     secondMockCompositionObjects = secondMockComposition.map(createDomainObject), | ||||
|                     firstCompositionCallback, | ||||
|                     secondCompositionCallback; | ||||
|  | ||||
|                 spyOn(mockCompositionCapability, "then").andCallThrough(); | ||||
|  | ||||
|                 controller.refreshComposition(mockDomainObject); | ||||
|                 controller.refreshComposition(mockDomainObject); | ||||
|  | ||||
|                 firstCompositionCallback = mockCompositionCapability.then.calls[0].args[0]; | ||||
|                 secondCompositionCallback = mockCompositionCapability.then.calls[1].args[0]; | ||||
|                 secondCompositionCallback(secondMockCompositionObjects); | ||||
|                 firstCompositionCallback(mockCompositionObjects); | ||||
|  | ||||
|                 expect(mockScope.composition).toBe(secondMockCompositionObjects); | ||||
|             }); | ||||
|         }); | ||||
|     } | ||||
| ); | ||||
|   | ||||
| @@ -77,6 +77,14 @@ | ||||
|     position: relative; | ||||
| } | ||||
|  | ||||
| .s-menu { | ||||
|     border-radius: $basicCr; | ||||
|     @include containerSubtle($colorMenuBg, $colorMenuFg); | ||||
|     @include boxShdw($shdwMenu); | ||||
|     @include txtShdw($shdwMenuText); | ||||
|     padding: $interiorMarginSm 0; | ||||
| } | ||||
|  | ||||
| .menu { | ||||
|     border-radius: $basicCr; | ||||
|     @include containerSubtle($colorMenuBg, $colorMenuFg); | ||||
|   | ||||
| @@ -373,10 +373,10 @@ define( | ||||
|          */ | ||||
|         FixedController.prototype.updateView = function (telemetryObject, datum) { | ||||
|             var metadata = this.openmct.telemetry.getMetadata(telemetryObject); | ||||
|             var telemetryKeyToDisplay = this.chooseTelemetryKeyToDisplay(metadata); | ||||
|             var formattedTelemetryValue = this.getFormattedTelemetryValueForKey(telemetryKeyToDisplay, datum, metadata); | ||||
|             var valueMetadata = this.chooseValueMetadataToDisplay(metadata); | ||||
|             var formattedTelemetryValue = this.getFormattedTelemetryValueForKey(valueMetadata, datum); | ||||
|             var limitEvaluator = this.openmct.telemetry.limitEvaluator(telemetryObject); | ||||
|             var alarm = limitEvaluator && limitEvaluator.evaluate(datum, telemetryKeyToDisplay); | ||||
|             var alarm = limitEvaluator && limitEvaluator.evaluate(datum, valueMetadata); | ||||
|  | ||||
|             this.setDisplayedValue( | ||||
|                 telemetryObject, | ||||
| @@ -389,29 +389,28 @@ define( | ||||
|         /** | ||||
|          * @private | ||||
|          */ | ||||
|         FixedController.prototype.getFormattedTelemetryValueForKey = function (telemetryKeyToDisplay, datum, metadata) { | ||||
|             var valueMetadata = metadata.value(telemetryKeyToDisplay); | ||||
|         FixedController.prototype.getFormattedTelemetryValueForKey = function (valueMetadata, datum) { | ||||
|             var formatter = this.openmct.telemetry.getValueFormatter(valueMetadata); | ||||
|  | ||||
|             return formatter.format(datum[valueMetadata.key]); | ||||
|             return formatter.format(datum); | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
|          * @private | ||||
|          */ | ||||
|         FixedController.prototype.chooseTelemetryKeyToDisplay = function (metadata) { | ||||
|         FixedController.prototype.chooseValueMetadataToDisplay = function (metadata) { | ||||
|             // If there is a range value, show that preferentially | ||||
|             var telemetryKeyToDisplay = metadata.valuesForHints(['range'])[0]; | ||||
|             var valueMetadata = metadata.valuesForHints(['range'])[0]; | ||||
|  | ||||
|             // If no range is defined, default to the highest priority non time-domain data. | ||||
|             if (telemetryKeyToDisplay === undefined) { | ||||
|             if (valueMetadata === undefined) { | ||||
|                 var valuesOrderedByPriority = metadata.values(); | ||||
|                 telemetryKeyToDisplay = valuesOrderedByPriority.filter(function (valueMetadata) { | ||||
|                     return !(valueMetadata.hints.domain); | ||||
|                 valueMetadata = valuesOrderedByPriority.filter(function (values) { | ||||
|                     return !(values.hints.domain); | ||||
|                 })[0]; | ||||
|             } | ||||
|  | ||||
|             return telemetryKeyToDisplay.source; | ||||
|             return valueMetadata; | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
|   | ||||
| @@ -106,8 +106,8 @@ define( | ||||
|                     'telemetryFormatter', | ||||
|                     ['format'] | ||||
|                 ); | ||||
|                 mockFormatter.format.andCallFake(function (value) { | ||||
|                     return "Formatted " + value; | ||||
|                 mockFormatter.format.andCallFake(function (valueMetadata) { | ||||
|                     return "Formatted " + valueMetadata.value; | ||||
|                 }); | ||||
|  | ||||
|                 mockDomainObject = jasmine.createSpyObj( | ||||
| @@ -697,7 +697,7 @@ define( | ||||
|                             source: 'range' | ||||
|                         } | ||||
|                     ]); | ||||
|                     var key = controller.chooseTelemetryKeyToDisplay(mockMetadata); | ||||
|                     var key = controller.chooseValueMetadataToDisplay(mockMetadata).source; | ||||
|                     expect(key).toEqual('range'); | ||||
|                 }); | ||||
|  | ||||
| @@ -719,7 +719,7 @@ define( | ||||
|                             } | ||||
|                         } | ||||
|                     ]); | ||||
|                     var key = controller.chooseTelemetryKeyToDisplay(mockMetadata); | ||||
|                     var key = controller.chooseValueMetadataToDisplay(mockMetadata).source; | ||||
|                     expect(key).toEqual('image'); | ||||
|                 }); | ||||
|  | ||||
|   | ||||
							
								
								
									
										269
									
								
								src/api/composition/CompositionAPISpec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										269
									
								
								src/api/composition/CompositionAPISpec.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,269 @@ | ||||
| define([ | ||||
|     './CompositionAPI', | ||||
|     './CompositionCollection' | ||||
| ], function ( | ||||
|     CompositionAPI, | ||||
|     CompositionCollection | ||||
| ) { | ||||
|  | ||||
|     describe('The Composition API', function () { | ||||
|         var publicAPI; | ||||
|         var compositionAPI; | ||||
|         var topicService; | ||||
|         var mutationTopic; | ||||
|  | ||||
|         beforeEach(function () { | ||||
|  | ||||
|             mutationTopic = jasmine.createSpyObj('mutationTopic', [ | ||||
|                 'listen' | ||||
|             ]); | ||||
|             topicService = jasmine.createSpy('topicService'); | ||||
|             topicService.andReturn(mutationTopic); | ||||
|             publicAPI = {}; | ||||
|             publicAPI.objects = jasmine.createSpyObj('ObjectAPI', [ | ||||
|                 'get' | ||||
|             ]); | ||||
|             publicAPI.objects.get.andCallFake(function (identifier) { | ||||
|                 return Promise.resolve({identifier: identifier}); | ||||
|             }); | ||||
|             publicAPI.$injector = jasmine.createSpyObj('$injector', [ | ||||
|                 'get' | ||||
|             ]); | ||||
|             publicAPI.$injector.get.andReturn(topicService); | ||||
|             compositionAPI = new CompositionAPI(publicAPI); | ||||
|         }); | ||||
|  | ||||
|         it('returns falsy if an object does not support composition', function () { | ||||
|             expect(compositionAPI.get({})).toBeFalsy(); | ||||
|         }); | ||||
|  | ||||
|         describe('default composition', function () { | ||||
|             var domainObject; | ||||
|             var composition; | ||||
|  | ||||
|             beforeEach(function () { | ||||
|                 domainObject = { | ||||
|                     name: 'test folder', | ||||
|                     identifier: { | ||||
|                         namespace: 'test', | ||||
|                         key: '1' | ||||
|                     }, | ||||
|                     composition: [ | ||||
|                         { | ||||
|                             namespace: 'test', | ||||
|                             key: 'a' | ||||
|                         } | ||||
|                     ] | ||||
|                 }; | ||||
|                 composition = compositionAPI.get(domainObject); | ||||
|             }); | ||||
|  | ||||
|             it('returns composition collection', function () { | ||||
|                 expect(composition).toBeDefined(); | ||||
|                 expect(composition).toEqual(jasmine.any(CompositionCollection)); | ||||
|             }); | ||||
|  | ||||
|             it('loads composition from domain object', function () { | ||||
|                 var listener = jasmine.createSpy('addListener'); | ||||
|                 var loaded = false; | ||||
|                 composition.on('add', listener); | ||||
|                 composition.load() | ||||
|                     .then(function () { | ||||
|                         loaded = true; | ||||
|                     }); | ||||
|                 waitsFor(function () { | ||||
|                     return loaded; | ||||
|                 }); | ||||
|                 runs(function () { | ||||
|                     expect(listener.calls.length).toBe(1); | ||||
|                     expect(listener).toHaveBeenCalledWith({ | ||||
|                         identifier: {namespace: 'test', key: 'a'} | ||||
|                     }); | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|             // TODO: Implement add/removal in new default provider. | ||||
|             xit('synchronizes changes between instances', function () { | ||||
|                 var otherComposition = compositionAPI.get(domainObject); | ||||
|                 var addListener = jasmine.createSpy('addListener'); | ||||
|                 var removeListener = jasmine.createSpy('removeListener'); | ||||
|                 var otherAddListener = jasmine.createSpy('otherAddListener'); | ||||
|                 var otherRemoveListener = jasmine.createSpy('otherRemoveListener'); | ||||
|                 composition.on('add', addListener); | ||||
|                 composition.on('remove', removeListener); | ||||
|                 otherComposition.on('add', otherAddListener); | ||||
|                 otherComposition.on('remove', otherRemoveListener); | ||||
|                 var loaded = false; | ||||
|                 Promise.all([composition.load(), otherComposition.load()]) | ||||
|                     .then(function () { | ||||
|                         loaded = true; | ||||
|                     }); | ||||
|                 waitsFor(function () { | ||||
|                     return loaded; | ||||
|                 }); | ||||
|                 runs(function () { | ||||
|                     expect(addListener).toHaveBeenCalled(); | ||||
|                     expect(otherAddListener).toHaveBeenCalled(); | ||||
|                     expect(removeListener).not.toHaveBeenCalled(); | ||||
|                     expect(otherRemoveListener).not.toHaveBeenCalled(); | ||||
|  | ||||
|                     var object = addListener.mostRecentCall.args[0]; | ||||
|                     composition.remove(object); | ||||
|                     expect(removeListener).toHaveBeenCalled(); | ||||
|                     expect(otherRemoveListener).toHaveBeenCalled(); | ||||
|  | ||||
|                     addListener.reset(); | ||||
|                     otherAddListener.reset(); | ||||
|                     composition.add(object); | ||||
|                     expect(addListener).toHaveBeenCalled(); | ||||
|                     expect(otherAddListener).toHaveBeenCalled(); | ||||
|  | ||||
|                     removeListener.reset(); | ||||
|                     otherRemoveListener.reset(); | ||||
|                     otherComposition.remove(object); | ||||
|                     expect(removeListener).toHaveBeenCalled(); | ||||
|                     expect(otherRemoveListener).toHaveBeenCalled(); | ||||
|  | ||||
|                     addListener.reset(); | ||||
|                     otherAddListener.reset(); | ||||
|                     otherComposition.add(object); | ||||
|                     expect(addListener).toHaveBeenCalled(); | ||||
|                     expect(otherAddListener).toHaveBeenCalled(); | ||||
|                 }); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         describe('static custom composition', function () { | ||||
|             var customProvider; | ||||
|             var domainObject; | ||||
|             var composition; | ||||
|  | ||||
|             beforeEach(function () { | ||||
|                 // A simple custom provider, returns the same composition for | ||||
|                 // all objects of a given type. | ||||
|                 customProvider = { | ||||
|                     appliesTo: function (object) { | ||||
|                         return object.type === 'custom-object-type'; | ||||
|                     }, | ||||
|                     load: function (object) { | ||||
|                         return Promise.resolve([ | ||||
|                             { | ||||
|                                 namespace: 'custom', | ||||
|                                 key: 'thing' | ||||
|                             } | ||||
|                         ]); | ||||
|                     } | ||||
|                 }; | ||||
|                 domainObject = { | ||||
|                     identifier: { | ||||
|                         namespace: 'test', | ||||
|                         key: '1' | ||||
|                     }, | ||||
|                     type: 'custom-object-type' | ||||
|                 }; | ||||
|                 compositionAPI.addProvider(customProvider); | ||||
|                 composition = compositionAPI.get(domainObject); | ||||
|             }); | ||||
|  | ||||
|             it('supports listening and loading', function () { | ||||
|                 var listener = jasmine.createSpy('addListener'); | ||||
|                 var loaded = false; | ||||
|                 composition.on('add', listener); | ||||
|                 composition.load() | ||||
|                     .then(function () { | ||||
|                         loaded = true; | ||||
|                     }); | ||||
|                 waitsFor(function () { | ||||
|                     return loaded; | ||||
|                 }); | ||||
|                 runs(function () { | ||||
|                     expect(listener.calls.length).toBe(1); | ||||
|                     expect(listener).toHaveBeenCalledWith({ | ||||
|                         identifier: {namespace: 'custom', key: 'thing'} | ||||
|                     }); | ||||
|                 }); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         describe('dynamic custom composition', function () { | ||||
|             var customProvider; | ||||
|             var domainObject; | ||||
|             var composition; | ||||
|  | ||||
|             beforeEach(function () { | ||||
|                 // A dynamic provider, loads an empty composition and exposes | ||||
|                 // listener functions. | ||||
|                 customProvider = jasmine.createSpyObj('dynamicProvider', [ | ||||
|                     'appliesTo', | ||||
|                     'load', | ||||
|                     'on', | ||||
|                     'off' | ||||
|                 ]); | ||||
|  | ||||
|                 customProvider.appliesTo.andReturn('true'); | ||||
|                 customProvider.load.andReturn(Promise.resolve([])); | ||||
|  | ||||
|                 domainObject = { | ||||
|                     identifier: { | ||||
|                         namespace: 'test', | ||||
|                         key: '1' | ||||
|                     }, | ||||
|                     type: 'custom-object-type' | ||||
|                 }; | ||||
|                 compositionAPI.addProvider(customProvider); | ||||
|                 composition = compositionAPI.get(domainObject); | ||||
|             }); | ||||
|  | ||||
|             it('supports listening and loading', function () { | ||||
|                 var addListener = jasmine.createSpy('addListener'); | ||||
|                 var removeListener = jasmine.createSpy('removeListener'); | ||||
|                 var loaded = false; | ||||
|                 composition.on('add', addListener); | ||||
|                 composition.on('remove', removeListener); | ||||
|                 expect(customProvider.on).toHaveBeenCalledWith( | ||||
|                     domainObject, | ||||
|                     'add', | ||||
|                     jasmine.any(Function), | ||||
|                     jasmine.any(CompositionCollection) | ||||
|                 ); | ||||
|                 expect(customProvider.on).toHaveBeenCalledWith( | ||||
|                     domainObject, | ||||
|                     'remove', | ||||
|                     jasmine.any(Function), | ||||
|                     jasmine.any(CompositionCollection) | ||||
|                 ); | ||||
|                 var add = customProvider.on.calls[0].args[2]; | ||||
|                 var remove = customProvider.on.calls[1].args[2]; | ||||
|                 composition.load() | ||||
|                     .then(function () { | ||||
|                         loaded = true; | ||||
|                     }); | ||||
|                 waitsFor(function () { | ||||
|                     return loaded; | ||||
|                 }); | ||||
|                 runs(function () { | ||||
|                     expect(addListener).not.toHaveBeenCalled(); | ||||
|                     expect(removeListener).not.toHaveBeenCalled(); | ||||
|                     add({namespace: 'custom', key: 'thing'}); | ||||
|                 }); | ||||
|                 waitsFor(function () { | ||||
|                     return addListener.calls.length > 0; | ||||
|                 }); | ||||
|                 runs(function () { | ||||
|                     expect(addListener).toHaveBeenCalledWith({ | ||||
|                         identifier: {namespace: 'custom', key: 'thing'} | ||||
|                     }); | ||||
|                     remove(addListener.mostRecentCall.args[0]); | ||||
|                 }); | ||||
|                 waitsFor(function () { | ||||
|                     return removeListener.calls.length > 0; | ||||
|                 }); | ||||
|                 runs(function () { | ||||
|                     expect(removeListener).toHaveBeenCalledWith({ | ||||
|                         identifier: {namespace: 'custom', key: 'thing'} | ||||
|                     }); | ||||
|                 }); | ||||
|             }); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
| @@ -38,7 +38,6 @@ define([ | ||||
|     '../example/msl/bundle', | ||||
|     '../example/notifications/bundle', | ||||
|     '../example/persistence/bundle', | ||||
|     '../example/plotOptions/bundle', | ||||
|     '../example/policy/bundle', | ||||
|     '../example/profiling/bundle', | ||||
|     '../example/scratchpad/bundle', | ||||
|   | ||||
| @@ -166,11 +166,6 @@ | ||||
|                      ng-show="plotHistory.length" | ||||
|                      style="position: absolute; top: 8px; right: 8px;"> | ||||
|  | ||||
|                     <a class="s-button icon-brackets" | ||||
|                         ng-click="plot.syncConductor()" | ||||
|                         title="Synchronize Time Conductor to plot bounds"> | ||||
|                     </a> | ||||
|  | ||||
|                     <a class="s-button icon-arrow-left" | ||||
|                        ng-click="plot.back()" | ||||
|                        title="Restore previous pan/zoom"> | ||||
|   | ||||
| @@ -75,7 +75,6 @@ function ( | ||||
|         this.$scope.$watch('highlights', this.scheduleDraw); | ||||
|         this.$scope.$watch('rectangles', this.scheduleDraw); | ||||
|         this.config.series.forEach(this.onSeriesAdd, this); | ||||
|         window.chart = this; | ||||
|     } | ||||
|  | ||||
|     eventHelpers.extend(MCTChartController.prototype); | ||||
|   | ||||
| @@ -85,6 +85,19 @@ define([ | ||||
|  | ||||
|             this.listenTo(this, 'destroy', this.onDestroy, this); | ||||
|         }, | ||||
|         /** | ||||
|          * Retrieve the persisted series config for a given identifier. | ||||
|          */ | ||||
|         getPersistedSeriesConfig: function (identifier) { | ||||
|             var domainObject = this.get('domainObject'); | ||||
|             if (!domainObject.configuration || !domainObject.configuration.series) { | ||||
|                 return; | ||||
|             } | ||||
|             return domainObject.configuration.series.filter(function (seriesConfig) { | ||||
|                 return seriesConfig.identifier.key === identifier.key && | ||||
|                     seriesConfig.identifier.namespace === identifier.namespace; | ||||
|             })[0]; | ||||
|         }, | ||||
|         /** | ||||
|          * Update the domain object with the given value. | ||||
|          */ | ||||
|   | ||||
| @@ -165,10 +165,13 @@ define([ | ||||
|                 return; | ||||
|             } | ||||
|             var valueMetadata = this.metadata.value(newKey); | ||||
|             if (valueMetadata.format === 'enum') { | ||||
|                 this.set('interpolate', 'stepAfter'); | ||||
|             } else { | ||||
|                 this.set('interpolate', 'linear'); | ||||
|             var persistedConfig = this.get('persistedConfiguration'); | ||||
|             if (!persistedConfig || !persistedConfig.interpolate) { | ||||
|                 if (valueMetadata.format === 'enum') { | ||||
|                     this.set('interpolate', 'stepAfter'); | ||||
|                 } else { | ||||
|                     this.set('interpolate', 'linear'); | ||||
|                 } | ||||
|             } | ||||
|             this.evaluate = function (datum) { | ||||
|                 return this.limitEvaluator.evaluate(datum, valueMetadata); | ||||
| @@ -233,8 +236,6 @@ define([ | ||||
|          * @returns {Promise} | ||||
|          */ | ||||
|         load: function (options) { | ||||
|             this.resetOnAppend = true; | ||||
|  | ||||
|             return this.fetch(options) | ||||
|                 .then(function (res) { | ||||
|                     this.emit('load'); | ||||
|   | ||||
| @@ -41,6 +41,7 @@ define([ | ||||
|             this.palette = new color.ColorPalette(); | ||||
|             this.listenTo(this, 'add', this.onSeriesAdd, this); | ||||
|             this.listenTo(this, 'remove', this.onSeriesRemove, this); | ||||
|             this.listenTo(this.plot, 'change:domainObject', this.trackPersistedConfig, this); | ||||
|  | ||||
|             var domainObject = this.plot.get('domainObject'); | ||||
|             if (domainObject.telemetry) { | ||||
| @@ -49,6 +50,14 @@ define([ | ||||
|                 this.watchTelemetryContainer(domainObject); | ||||
|             } | ||||
|         }, | ||||
|         trackPersistedConfig: function (domainObject) { | ||||
|             domainObject.configuration.series.forEach(function (seriesConfig) { | ||||
|                 var series = this.byIdentifier(seriesConfig.identifier); | ||||
|                 if (series) { | ||||
|                     series.set('persistedConfiguration', seriesConfig); | ||||
|                 } | ||||
|             }, this); | ||||
|         }, | ||||
|         watchTelemetryContainer: function (domainObject) { | ||||
|             var composition = this.openmct.composition.get(domainObject); | ||||
|             this.listenTo(composition, 'add', this.addTelemetryObject, this); | ||||
| @@ -75,6 +84,9 @@ define([ | ||||
|                 seriesConfig = JSON.parse(JSON.stringify(seriesConfig)); | ||||
|             } | ||||
|  | ||||
|             seriesConfig.persistedConfiguration = | ||||
|                 this.plot.getPersistedSeriesConfig(domainObject.identifier); | ||||
|  | ||||
|             this.add(new PlotSeries({ | ||||
|                 model: seriesConfig, | ||||
|                 domainObject: domainObject, | ||||
| @@ -125,12 +137,19 @@ define([ | ||||
|         }, | ||||
|         updateColorPalette: function (newColor, oldColor) { | ||||
|             this.palette.remove(newColor); | ||||
|             var seriesWithColor = this.series.filter(function (series) { | ||||
|             var seriesWithColor = this.filter(function (series) { | ||||
|                 return series.get('color') === newColor; | ||||
|             })[0]; | ||||
|             if (!seriesWithColor) { | ||||
|                 this.palette.return(oldColor); | ||||
|             } | ||||
|         }, | ||||
|         byIdentifier: function (identifier) { | ||||
|             return this.filter(function (series) { | ||||
|                 var seriesIdentifier = series.get('identifier'); | ||||
|                 return seriesIdentifier.namespace === identifier.namespace && | ||||
|                     seriesIdentifier.key === identifier.key; | ||||
|             })[0]; | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|   | ||||
| @@ -48,7 +48,6 @@ define([ | ||||
|  | ||||
|         this.configId = $scope.domainObject.getId(); | ||||
|         this.setUpScope(); | ||||
|         window.config = this; | ||||
|     } | ||||
|  | ||||
|     eventHelpers.extend(PlotOptionsController.prototype); | ||||
|   | ||||
| @@ -33,13 +33,12 @@ define([ | ||||
|      * It supports pan and zoom, implements zoom history, and supports locating | ||||
|      * values near the cursor. | ||||
|      */ | ||||
|     function MCTPlotController($scope, $element, $window, openmct) { | ||||
|     function MCTPlotController($scope, $element, $window) { | ||||
|         this.$scope = $scope; | ||||
|         this.$scope.config = this.config; | ||||
|         this.$scope.plot = this; | ||||
|         this.$element = $element; | ||||
|         this.$window = $window; | ||||
|         this.openmct = openmct; | ||||
|  | ||||
|         this.xScale = new LinearScale(this.config.xAxis.get('displayRange')); | ||||
|         this.yScale = new LinearScale(this.config.yAxis.get('displayRange')); | ||||
| @@ -54,7 +53,6 @@ define([ | ||||
|         this.listenTo(this.$scope, 'plot:clearHistory', this.clear, this); | ||||
|  | ||||
|         this.initialize(); | ||||
|         window.control = this; | ||||
|     } | ||||
|  | ||||
|     MCTPlotController.$inject = ['$scope', '$element', '$window']; | ||||
| @@ -333,13 +331,6 @@ define([ | ||||
|         this.$scope.$emit('user:viewport:change:end'); | ||||
|     }; | ||||
|  | ||||
|  | ||||
|     MCTPlotController.prototype.syncConductor = function () { | ||||
|         var xDisplayRange = this.config.xAxis.get('displayRange'); | ||||
|         this.openmct.time.stopClock(); | ||||
|         this.openmct.time.bounds({start: xDisplayRange.min, end: xDisplayRange.max}); | ||||
|     }; | ||||
|  | ||||
|     MCTPlotController.prototype.destroy = function () { | ||||
|         this.stopListening(); | ||||
|     }; | ||||
|   | ||||
| @@ -33,7 +33,7 @@ define([ | ||||
|         return { | ||||
|             restrict: "E", | ||||
|             template: PlotTemplate, | ||||
|             controller: ['$scope', '$element', '$window', 'openmct', MCTPlotController], | ||||
|             controller: MCTPlotController, | ||||
|             controllerAs: 'mctPlotController', | ||||
|             bindToController: { | ||||
|                 config: "=" | ||||
|   | ||||
| @@ -117,12 +117,6 @@ define([ | ||||
|         this.$scope = $scope; | ||||
|         this.$element = $element; | ||||
|  | ||||
|         if (!window.ticks) { | ||||
|             window.ticks = []; | ||||
|         } | ||||
|  | ||||
|         window.ticks.push(this); | ||||
|  | ||||
|         this.tickCount = 4; | ||||
|         this.tickUpdate = false; | ||||
|         this.listenTo(this.axis, 'change:displayRange', this.updateTicks, this); | ||||
|   | ||||
| @@ -71,7 +71,6 @@ define([ | ||||
|         this.config.series.forEach(this.addSeries, this); | ||||
|  | ||||
|         this.followTimeConductor(); | ||||
|         window.plot = this; | ||||
|     } | ||||
|  | ||||
|     eventHelpers.extend(PlotController.prototype); | ||||
|   | ||||
| @@ -31,7 +31,8 @@ define([ | ||||
|     './summaryWidget/plugin', | ||||
|     './URLIndicatorPlugin/URLIndicatorPlugin', | ||||
|     './telemetryMean/plugin', | ||||
|     './plot/plugin' | ||||
|     './plot/plugin', | ||||
|     './staticRootPlugin/plugin' | ||||
| ], function ( | ||||
|     _, | ||||
|     UTCTimeSystem, | ||||
| @@ -43,7 +44,8 @@ define([ | ||||
|     SummaryWidget, | ||||
|     URLIndicatorPlugin, | ||||
|     TelemetryMean, | ||||
|     PlotPlugin | ||||
|     PlotPlugin, | ||||
|     StaticRootPlugin | ||||
| ) { | ||||
|     var bundleMap = { | ||||
|         CouchDB: 'platform/persistence/couch', | ||||
| @@ -66,6 +68,8 @@ define([ | ||||
|  | ||||
|     plugins.ImportExport = ImportExport; | ||||
|  | ||||
|     plugins.StaticRootPlugin = StaticRootPlugin; | ||||
|  | ||||
|     /** | ||||
|      * A tabular view showing the latest values of multiple telemetry points at | ||||
|      * once. Formatted so that labels and values are aligned. | ||||
|   | ||||
							
								
								
									
										78
									
								
								src/plugins/staticRootPlugin/StaticModelProvider.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/plugins/staticRootPlugin/StaticModelProvider.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | ||||
| define([ | ||||
|     '../../api/objects/object-utils' | ||||
| ], function ( | ||||
|     objectUtils | ||||
| ) { | ||||
|     /** | ||||
|      * Transforms an import json blob into a object map that can be used to | ||||
|      * provide objects.  Rewrites root identifier in import data with provided | ||||
|      * rootIdentifier, and rewrites all child object identifiers so that they | ||||
|      * exist in the same namespace as the rootIdentifier. | ||||
|      */ | ||||
|     function rewriteObjectIdentifiers(importData, rootIdentifier) { | ||||
|         var rootId = importData.rootId; | ||||
|         var objectString = JSON.stringify(importData.openmct); | ||||
|  | ||||
|         Object.keys(importData.openmct).forEach(function (originalId, i) { | ||||
|             var newId; | ||||
|             if (originalId === rootId) { | ||||
|                 newId = objectUtils.makeKeyString(rootIdentifier); | ||||
|             } else { | ||||
|                 newId = objectUtils.makeKeyString({ | ||||
|                     namespace: rootIdentifier.namespace, | ||||
|                     key: i | ||||
|                 }); | ||||
|             } | ||||
|             while (objectString.indexOf(originalId) !== -1) { | ||||
|                 objectString = objectString.replace( | ||||
|                     '"' + originalId + '"', | ||||
|                     '"' + newId + '"' | ||||
|                 ); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         return JSON.parse(objectString); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Convets all objects in an object make from old format objects to new | ||||
|      * format objects. | ||||
|      */ | ||||
|     function convertToNewObjects(oldObjectMap) { | ||||
|         return Object.keys(oldObjectMap) | ||||
|             .reduce(function (newObjectMap, key) { | ||||
|                 newObjectMap[key] = objectUtils.toNewFormat(oldObjectMap[key], key); | ||||
|                 return newObjectMap; | ||||
|             }, {}); | ||||
|     } | ||||
|  | ||||
|     /* Set the root location correctly for a top-level object */ | ||||
|     function setRootLocation(objectMap, rootIdentifier) { | ||||
|         objectMap[objectUtils.makeKeyString(rootIdentifier)].location = 'ROOT'; | ||||
|         return objectMap; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Takes importData (as provided by the ImportExport plugin) and exposes | ||||
|      * an object provider to fetch those objects. | ||||
|      */ | ||||
|     function StaticModelProvider(importData, rootIdentifier) { | ||||
|         var oldFormatObjectMap = rewriteObjectIdentifiers(importData, rootIdentifier); | ||||
|         var newFormatObjectMap = convertToNewObjects(oldFormatObjectMap); | ||||
|         this.objectMap = setRootLocation(newFormatObjectMap, rootIdentifier); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Standard "Get". | ||||
|      */ | ||||
|     StaticModelProvider.prototype.get = function (identifier) { | ||||
|         var keyString = objectUtils.makeKeyString(identifier); | ||||
|         if (this.objectMap[keyString]) { | ||||
|             return this.objectMap[keyString]; | ||||
|         } | ||||
|         throw new Error(keyString + ' not found in import models.'); | ||||
|     }; | ||||
|  | ||||
|     return StaticModelProvider; | ||||
|  | ||||
| }); | ||||
							
								
								
									
										133
									
								
								src/plugins/staticRootPlugin/StaticModelProviderSpec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								src/plugins/staticRootPlugin/StaticModelProviderSpec.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,133 @@ | ||||
| define([ | ||||
|     './StaticModelProvider', | ||||
|     'text!./static-provider-test.json' | ||||
| ], function ( | ||||
|     StaticModelProvider, | ||||
|     testStaticDataText | ||||
| ) { | ||||
|  | ||||
|     describe('StaticModelProvider', function () { | ||||
|  | ||||
|         var staticProvider; | ||||
|  | ||||
|         beforeEach(function () { | ||||
|             var staticData = JSON.parse(testStaticDataText); | ||||
|             staticProvider = new StaticModelProvider(staticData, { | ||||
|                 namespace: 'my-import', | ||||
|                 key: 'root' | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         describe('rootObject', function () { | ||||
|             var rootModel; | ||||
|  | ||||
|             beforeEach(function () { | ||||
|                 rootModel = staticProvider.get({ | ||||
|                     namespace: 'my-import', | ||||
|                     key: 'root' | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|             it('is located at top level', function () { | ||||
|                 expect(rootModel.location).toBe('ROOT'); | ||||
|             }); | ||||
|  | ||||
|             it('has new-format identifier', function () { | ||||
|                 expect(rootModel.identifier).toEqual({ | ||||
|                     namespace: 'my-import', | ||||
|                     key: 'root' | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|             it('has new-format composition', function () { | ||||
|                 expect(rootModel.composition).toContain({ | ||||
|                     namespace: 'my-import', | ||||
|                     key: '1' | ||||
|                 }); | ||||
|                 expect(rootModel.composition).toContain({ | ||||
|                     namespace: 'my-import', | ||||
|                     key: '2' | ||||
|                 }); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         describe('childObjects', function () { | ||||
|             var swg; | ||||
|             var layout; | ||||
|             var fixed; | ||||
|  | ||||
|             beforeEach(function () { | ||||
|                 swg = staticProvider.get({ | ||||
|                     namespace: 'my-import', | ||||
|                     key: '1' | ||||
|                 }); | ||||
|                 layout = staticProvider.get({ | ||||
|                     namespace: 'my-import', | ||||
|                     key: '2' | ||||
|                 }); | ||||
|                 fixed = staticProvider.get({ | ||||
|                     namespace: 'my-import', | ||||
|                     key: '3' | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|             it('match expected ordering', function () { | ||||
|                 // this is a sanity check to make sure the identifiers map in | ||||
|                 // the correct order. | ||||
|                 expect(swg.type).toBe('generator'); | ||||
|                 expect(layout.type).toBe('layout'); | ||||
|                 expect(fixed.type).toBe('telemetry.fixed'); | ||||
|             }); | ||||
|  | ||||
|             it('have new-style identifiers', function () { | ||||
|                 expect(swg.identifier).toEqual({ | ||||
|                     namespace: 'my-import', | ||||
|                     key: '1' | ||||
|                 }); | ||||
|                 expect(layout.identifier).toEqual({ | ||||
|                     namespace: 'my-import', | ||||
|                     key: '2' | ||||
|                 }); | ||||
|                 expect(fixed.identifier).toEqual({ | ||||
|                     namespace: 'my-import', | ||||
|                     key: '3' | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|             it('have new-style composition', function () { | ||||
|                 expect(layout.composition).toContain({ | ||||
|                     namespace: 'my-import', | ||||
|                     key: '1' | ||||
|                 }); | ||||
|                 expect(layout.composition).toContain({ | ||||
|                     namespace: 'my-import', | ||||
|                     key: '3' | ||||
|                 }); | ||||
|                 expect(fixed.composition).toContain({ | ||||
|                     namespace: 'my-import', | ||||
|                     key: '1' | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|             it('rewrites locations', function () { | ||||
|                 expect(swg.location).toBe('my-import:root'); | ||||
|                 expect(layout.location).toBe('my-import:root'); | ||||
|                 expect(fixed.location).toBe('my-import:2'); | ||||
|             }); | ||||
|  | ||||
|             it('rewrites matched identifiers in objects', function () { | ||||
|                 expect(layout.configuration.layout.panels['my-import:1']) | ||||
|                     .toBeDefined(); | ||||
|                 expect(layout.configuration.layout.panels['my-import:3']) | ||||
|                     .toBeDefined(); | ||||
|                 expect(layout.configuration.layout.panels['483c00d4-bb1d-4b42-b29a-c58e06b322a0']) | ||||
|                     .not.toBeDefined(); | ||||
|                 expect(layout.configuration.layout.panels['20273193-f069-49e9-b4f7-b97a87ed755d']) | ||||
|                     .not.toBeDefined(); | ||||
|                 expect(fixed.configuration['fixed-display'].elements[0].id) | ||||
|                     .toBe('my-import:1'); | ||||
|             }); | ||||
|  | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
							
								
								
									
										51
									
								
								src/plugins/staticRootPlugin/plugin.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/plugins/staticRootPlugin/plugin.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| define([ | ||||
|     './StaticModelProvider' | ||||
| ], function ( | ||||
|     StaticModelProvider | ||||
| ) { | ||||
|     /** | ||||
|      * Static Root Plugin: takes an export file and exposes it as a new root | ||||
|      * object. | ||||
|      */ | ||||
|     function StaticRootPlugin(namespace, exportUrl) { | ||||
|  | ||||
|         var rootIdentifier = { | ||||
|             namespace: namespace, | ||||
|             key: 'root' | ||||
|         }; | ||||
|  | ||||
|         var cachedProvider; | ||||
|  | ||||
|         var loadProvider = function () { | ||||
|             return fetch(exportUrl) | ||||
|                 .then(function (response) { | ||||
|                     return response.json(); | ||||
|                 }) | ||||
|                 .then(function (importData) { | ||||
|                     cachedProvider = new StaticModelProvider(importData, rootIdentifier); | ||||
|                     return cachedProvider; | ||||
|                 }); | ||||
|  | ||||
|         }; | ||||
|  | ||||
|         var getProvider = function () { | ||||
|             if (!cachedProvider) { | ||||
|                 cachedProvider = loadProvider(); | ||||
|             } | ||||
|             return Promise.resolve(cachedProvider); | ||||
|         }; | ||||
|  | ||||
|         return function install(openmct) { | ||||
|             openmct.objects.addRoot(rootIdentifier); | ||||
|             openmct.objects.addProvider(namespace, { | ||||
|                 get: function (identifier) { | ||||
|                     return getProvider().then(function (provider) { | ||||
|                         return provider.get(identifier); | ||||
|                     }); | ||||
|                 } | ||||
|             }); | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     return StaticRootPlugin; | ||||
| }); | ||||
							
								
								
									
										1
									
								
								src/plugins/staticRootPlugin/static-provider-test.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/plugins/staticRootPlugin/static-provider-test.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| {"openmct":{"a9122832-4b6e-43ea-8219-5359c14c5de8":{"composition":["483c00d4-bb1d-4b42-b29a-c58e06b322a0","d2ac3ae4-0af2-49fe-81af-adac09936215"],"name":"import-provider-test","type":"folder","notes":"test data for import provider.","modified":1508522673278,"location":"mine","persisted":1508522673278},"483c00d4-bb1d-4b42-b29a-c58e06b322a0":{"telemetry":{"period":10,"amplitude":1,"offset":0,"dataRateInHz":1,"values":[{"key":"utc","name":"Time","format":"utc","hints":{"domain":1,"priority":0},"source":"utc"},{"key":"yesterday","name":"Yesterday","format":"utc","hints":{"domain":2,"priority":1},"source":"yesterday"},{"key":"sin","name":"Sine","hints":{"range":1,"priority":2},"source":"sin"},{"key":"cos","name":"Cosine","hints":{"range":2,"priority":3},"source":"cos"}]},"name":"SWG-10","type":"generator","modified":1508522652874,"location":"a9122832-4b6e-43ea-8219-5359c14c5de8","persisted":1508522652874},"d2ac3ae4-0af2-49fe-81af-adac09936215":{"composition":["483c00d4-bb1d-4b42-b29a-c58e06b322a0","20273193-f069-49e9-b4f7-b97a87ed755d"],"name":"Layout","type":"layout","configuration":{"layout":{"panels":{"483c00d4-bb1d-4b42-b29a-c58e06b322a0":{"position":[0,0],"dimensions":[17,8]},"20273193-f069-49e9-b4f7-b97a87ed755d":{"position":[0,8],"dimensions":[17,1],"hasFrame":false}}}},"modified":1508522745580,"location":"a9122832-4b6e-43ea-8219-5359c14c5de8","persisted":1508522745580},"20273193-f069-49e9-b4f7-b97a87ed755d":{"layoutGrid":[64,16],"composition":["483c00d4-bb1d-4b42-b29a-c58e06b322a0"],"name":"FP Test","type":"telemetry.fixed","configuration":{"fixed-display":{"elements":[{"type":"fixed.telemetry","x":0,"y":0,"id":"483c00d4-bb1d-4b42-b29a-c58e06b322a0","stroke":"transparent","color":"","titled":true,"width":8,"height":2,"useGrid":true,"size":"24px"}]}},"modified":1508522717619,"location":"d2ac3ae4-0af2-49fe-81af-adac09936215","persisted":1508522717619}},"rootId":"a9122832-4b6e-43ea-8219-5359c14c5de8"} | ||||
		Reference in New Issue
	
	Block a user