Compare commits
	
		
			25 Commits
		
	
	
		
			condition-
			...
			mct4102_v2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 6ac9eebab3 | ||
|   | 04ece72679 | ||
|   | 80b4ccd562 | ||
|   | 880c3a8850 | ||
|   | 72b609f527 | ||
|   | 7c883aea96 | ||
|   | a7ed38b7ee | ||
|   | 1049ac38ff | ||
|   | 2f435facd4 | ||
|   | 121eeac27c | ||
|   | b67b13912e | ||
|   | 0cb884563a | ||
|   | 4942e27a89 | ||
|   | e84a3bfe97 | ||
|   | fdc1499339 | ||
|   | ae224ae567 | ||
|   | 48c22369a1 | ||
|   | 6506077f4d | ||
|   | 48322d46fd | ||
|   | 7616610f2c | ||
|   | b1b4266ff3 | ||
|   | 42b0148f93 | ||
|   | 9461ad8edd | ||
|   | 40055ba955 | ||
|   | 9cb85ad176 | 
							
								
								
									
										33
									
								
								.github/workflows/codeql-analysis.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								.github/workflows/codeql-analysis.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
|  | ||||
| name: "CodeQL" | ||||
|  | ||||
| on: | ||||
|   push: | ||||
|     branches: [ master ] | ||||
|   schedule: | ||||
|     - cron: '28 21 * * 3' | ||||
|  | ||||
| jobs: | ||||
|   analyze: | ||||
|     name: Analyze | ||||
|     runs-on: ubuntu-latest | ||||
|     permissions: | ||||
|       actions: read | ||||
|       contents: read | ||||
|       security-events: write | ||||
|  | ||||
|     steps: | ||||
|     - name: Checkout repository | ||||
|       uses: actions/checkout@v2 | ||||
|  | ||||
|     # Initializes the CodeQL tools for scanning. | ||||
|     - name: Initialize CodeQL | ||||
|       uses: github/codeql-action/init@v1 | ||||
|       with: | ||||
|         languages: javascript | ||||
|  | ||||
|     - name: Autobuild | ||||
|       uses: github/codeql-action/autobuild@v1 | ||||
|  | ||||
|     - name: Perform CodeQL Analysis | ||||
|       uses: github/codeql-action/analyze@v1 | ||||
| @@ -28,6 +28,15 @@ define([ | ||||
|                         domain: 2 | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     key: "cos", | ||||
|                     name: "Cosine", | ||||
|                     unit: "deg", | ||||
|                     formatString: '%0.2f', | ||||
|                     hints: { | ||||
|                         domain: 3 | ||||
|                     } | ||||
|                 }, | ||||
|                 // Need to enable "LocalTimeSystem" plugin to make use of this | ||||
|                 // { | ||||
|                 //     key: "local", | ||||
| @@ -109,6 +118,100 @@ define([ | ||||
|                     } | ||||
|                 } | ||||
|             ] | ||||
|         }, | ||||
|         'example.spectral-generator': { | ||||
|             values: [ | ||||
|                 { | ||||
|                     key: "name", | ||||
|                     name: "Name", | ||||
|                     format: "string" | ||||
|                 }, | ||||
|                 { | ||||
|                     key: "utc", | ||||
|                     name: "Time", | ||||
|                     format: "utc", | ||||
|                     hints: { | ||||
|                         domain: 1 | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     key: "wavelength", | ||||
|                     name: "Wavelength", | ||||
|                     unit: "Hz", | ||||
|                     formatString: '%0.2f', | ||||
|                     hints: { | ||||
|                         domain: 2, | ||||
|                         spectralAttribute: true | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     key: "cos", | ||||
|                     name: "Cosine", | ||||
|                     unit: "deg", | ||||
|                     formatString: '%0.2f', | ||||
|                     hints: { | ||||
|                         range: 2, | ||||
|                         spectralAttribute: true | ||||
|                     } | ||||
|                 } | ||||
|             ] | ||||
|         }, | ||||
|         'example.spectral-aggregate-generator': { | ||||
|             values: [ | ||||
|                 { | ||||
|                     key: "name", | ||||
|                     name: "Name", | ||||
|                     format: "string" | ||||
|                 }, | ||||
|                 { | ||||
|                     key: "utc", | ||||
|                     name: "Time", | ||||
|                     format: "utc", | ||||
|                     hints: { | ||||
|                         domain: 1 | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     key: "ch1", | ||||
|                     name: "Channel 1", | ||||
|                     format: "string", | ||||
|                     hints: { | ||||
|                         range: 1 | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     key: "ch2", | ||||
|                     name: "Channel 2", | ||||
|                     format: "string", | ||||
|                     hints: { | ||||
|                         range: 2 | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     key: "ch3", | ||||
|                     name: "Channel 3", | ||||
|                     format: "string", | ||||
|                     hints: { | ||||
|                         range: 3 | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     key: "ch4", | ||||
|                     name: "Channel 4", | ||||
|                     format: "string", | ||||
|                     hints: { | ||||
|                         range: 4 | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     key: "ch5", | ||||
|                     name: "Channel 5", | ||||
|                     format: "string", | ||||
|                     hints: { | ||||
|                         range: 5 | ||||
|                     } | ||||
|                 } | ||||
|             ] | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|   | ||||
							
								
								
									
										86
									
								
								example/generator/SpectralAggregateGeneratorProvider.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								example/generator/SpectralAggregateGeneratorProvider.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2021, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define([ | ||||
|  | ||||
| ], function ( | ||||
|  | ||||
| ) { | ||||
|  | ||||
|     function SpectralAggregateGeneratorProvider() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     function pointForTimestamp(timestamp, count, name) { | ||||
|         return { | ||||
|             name: name, | ||||
|             utc: String(Math.floor(timestamp / count) * count), | ||||
|             ch1: String(Math.floor(timestamp / count) % 1), | ||||
|             ch2: String(Math.floor(timestamp / count) % 2), | ||||
|             ch3: String(Math.floor(timestamp / count) % 3), | ||||
|             ch4: String(Math.floor(timestamp / count) % 4), | ||||
|             ch5: String(Math.floor(timestamp / count) % 5) | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     SpectralAggregateGeneratorProvider.prototype.supportsSubscribe = function (domainObject) { | ||||
|         return domainObject.type === 'example.spectral-aggregate-generator'; | ||||
|     }; | ||||
|  | ||||
|     SpectralAggregateGeneratorProvider.prototype.subscribe = function (domainObject, callback) { | ||||
|         var count = 5000; | ||||
|  | ||||
|         var interval = setInterval(function () { | ||||
|             var now = Date.now(); | ||||
|             var datum = pointForTimestamp(now, count, domainObject.name); | ||||
|             callback(datum); | ||||
|         }, count); | ||||
|  | ||||
|         return function () { | ||||
|             clearInterval(interval); | ||||
|         }; | ||||
|     }; | ||||
|  | ||||
|     SpectralAggregateGeneratorProvider.prototype.supportsRequest = function (domainObject, options) { | ||||
|         return domainObject.type === 'example.spectral-aggregate-generator'; | ||||
|     }; | ||||
|  | ||||
|     SpectralAggregateGeneratorProvider.prototype.request = function (domainObject, options) { | ||||
|         var start = options.start; | ||||
|         var end = Math.min(Date.now(), options.end); // no future values | ||||
|         var count = 5000; | ||||
|         if (options.strategy === 'latest' || options.size === 1) { | ||||
|             start = end; | ||||
|         } | ||||
|  | ||||
|         var data = []; | ||||
|         while (start <= end && data.length < 5000) { | ||||
|             data.push(pointForTimestamp(start, count, domainObject.name)); | ||||
|             start += count; | ||||
|         } | ||||
|  | ||||
|         return Promise.resolve(data); | ||||
|     }; | ||||
|  | ||||
|     return SpectralAggregateGeneratorProvider; | ||||
|  | ||||
| }); | ||||
							
								
								
									
										104
									
								
								example/generator/SpectralGeneratorProvider.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								example/generator/SpectralGeneratorProvider.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2021, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define([ | ||||
|     './WorkerInterface' | ||||
| ], function ( | ||||
|     WorkerInterface | ||||
| ) { | ||||
|  | ||||
|     var REQUEST_DEFAULTS = { | ||||
|         amplitude: 1, | ||||
|         wavelength: 1, | ||||
|         period: 10, | ||||
|         offset: 0, | ||||
|         dataRateInHz: 1, | ||||
|         randomness: 0, | ||||
|         phase: 0 | ||||
|     }; | ||||
|  | ||||
|     function SpectralGeneratorProvider() { | ||||
|         this.workerInterface = new WorkerInterface(); | ||||
|     } | ||||
|  | ||||
|     SpectralGeneratorProvider.prototype.canProvideTelemetry = function (domainObject) { | ||||
|         return domainObject.type === 'example.spectral-generator'; | ||||
|     }; | ||||
|  | ||||
|     SpectralGeneratorProvider.prototype.supportsRequest = | ||||
|         SpectralGeneratorProvider.prototype.supportsSubscribe = | ||||
|             SpectralGeneratorProvider.prototype.canProvideTelemetry; | ||||
|  | ||||
|     SpectralGeneratorProvider.prototype.makeWorkerRequest = function (domainObject, request) { | ||||
|         var props = [ | ||||
|             'amplitude', | ||||
|             'wavelength', | ||||
|             'period', | ||||
|             'offset', | ||||
|             'dataRateInHz', | ||||
|             'phase', | ||||
|             'randomness' | ||||
|         ]; | ||||
|  | ||||
|         request = request || {}; | ||||
|  | ||||
|         var workerRequest = {}; | ||||
|  | ||||
|         props.forEach(function (prop) { | ||||
|             if (domainObject.telemetry && Object.prototype.hasOwnProperty.call(domainObject.telemetry, prop)) { | ||||
|                 workerRequest[prop] = domainObject.telemetry[prop]; | ||||
|             } | ||||
|  | ||||
|             if (request && Object.prototype.hasOwnProperty.call(request, prop)) { | ||||
|                 workerRequest[prop] = request[prop]; | ||||
|             } | ||||
|  | ||||
|             if (!Object.prototype.hasOwnProperty.call(workerRequest, prop)) { | ||||
|                 workerRequest[prop] = REQUEST_DEFAULTS[prop]; | ||||
|             } | ||||
|  | ||||
|             workerRequest[prop] = Number(workerRequest[prop]); | ||||
|         }); | ||||
|  | ||||
|         workerRequest.name = domainObject.name; | ||||
|  | ||||
|         return workerRequest; | ||||
|     }; | ||||
|  | ||||
|     SpectralGeneratorProvider.prototype.request = function (domainObject, request) { | ||||
|         var workerRequest = this.makeWorkerRequest(domainObject, request); | ||||
|         workerRequest.start = request.start; | ||||
|         workerRequest.end = request.end; | ||||
|         workerRequest.spectra = true; | ||||
|  | ||||
|         return this.workerInterface.request(workerRequest); | ||||
|     }; | ||||
|  | ||||
|     SpectralGeneratorProvider.prototype.subscribe = function (domainObject, callback) { | ||||
|         var workerRequest = this.makeWorkerRequest(domainObject, {}); | ||||
|         workerRequest.spectra = true; | ||||
|  | ||||
|         return this.workerInterface.subscribe(workerRequest, callback); | ||||
|     }; | ||||
|  | ||||
|     return SpectralGeneratorProvider; | ||||
| }); | ||||
| @@ -54,23 +54,39 @@ | ||||
|         var start = Date.now(); | ||||
|         var step = 1000 / data.dataRateInHz; | ||||
|         var nextStep = start - (start % step) + step; | ||||
|         let work; | ||||
|         console.log('dataRate', data); | ||||
|         if (data.spectra) { | ||||
|             work = function (now) { | ||||
|                 while (nextStep < now) { | ||||
|                     const messageCopy = Object.create(message); | ||||
|                     message.data.start = nextStep - (60 * 1000); | ||||
|                     message.data.end = nextStep; | ||||
|                     onRequest(messageCopy); | ||||
|                     nextStep += step; | ||||
|                 } | ||||
|  | ||||
|         function work(now) { | ||||
|             while (nextStep < now) { | ||||
|                 self.postMessage({ | ||||
|                     id: message.id, | ||||
|                     data: { | ||||
|                         name: data.name, | ||||
|                         utc: nextStep, | ||||
|                         yesterday: nextStep - 60 * 60 * 24 * 1000, | ||||
|                         sin: sin(nextStep, data.period, data.amplitude, data.offset, data.phase, data.randomness), | ||||
|                         cos: cos(nextStep, data.period, data.amplitude, data.offset, data.phase, data.randomness) | ||||
|                     } | ||||
|                 }); | ||||
|                 nextStep += step; | ||||
|             } | ||||
|                 return nextStep; | ||||
|             }; | ||||
|         } else { | ||||
|             work = function (now) { | ||||
|                 while (nextStep < now) { | ||||
|                     self.postMessage({ | ||||
|                         id: message.id, | ||||
|                         data: { | ||||
|                             name: data.name, | ||||
|                             utc: nextStep, | ||||
|                             yesterday: nextStep - 60 * 60 * 24 * 1000, | ||||
|                             sin: sin(nextStep, data.period, data.amplitude, data.offset, data.phase, data.randomness), | ||||
|                             wavelength: wavelength(start, nextStep), | ||||
|                             cos: cos(nextStep, data.period, data.amplitude, data.offset, data.phase, data.randomness) | ||||
|                         } | ||||
|                     }); | ||||
|                     nextStep += step; | ||||
|                 } | ||||
|  | ||||
|             return nextStep; | ||||
|                 return nextStep; | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         subscriptions[message.id] = work; | ||||
| @@ -111,13 +127,21 @@ | ||||
|                 utc: nextStep, | ||||
|                 yesterday: nextStep - 60 * 60 * 24 * 1000, | ||||
|                 sin: sin(nextStep, period, amplitude, offset, phase, randomness), | ||||
|                 wavelength: wavelength(start, nextStep), | ||||
|                 cos: cos(nextStep, period, amplitude, offset, phase, randomness) | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         self.postMessage({ | ||||
|             id: message.id, | ||||
|             data: data | ||||
|             data: request.spectra ? { | ||||
|                 wavelength: data.map((item) => { | ||||
|                     return item.wavelength; | ||||
|                 }), | ||||
|                 cos: data.map((item) => { | ||||
|                     return item.cos; | ||||
|                 }) | ||||
|             } : data | ||||
|         }); | ||||
|     } | ||||
|  | ||||
| @@ -131,6 +155,10 @@ | ||||
|             * Math.sin(phase + (timestamp / period / 1000 * Math.PI * 2)) + (amplitude * Math.random() * randomness) + offset; | ||||
|     } | ||||
|  | ||||
|     function wavelength(start, nextStep) { | ||||
|         return (nextStep - start) / 10; | ||||
|     } | ||||
|  | ||||
|     function sendError(error, message) { | ||||
|         self.postMessage({ | ||||
|             error: error.name + ': ' + error.message, | ||||
|   | ||||
| @@ -24,11 +24,15 @@ define([ | ||||
|     "./GeneratorProvider", | ||||
|     "./SinewaveLimitProvider", | ||||
|     "./StateGeneratorProvider", | ||||
|     "./SpectralGeneratorProvider", | ||||
|     "./SpectralAggregateGeneratorProvider", | ||||
|     "./GeneratorMetadataProvider" | ||||
| ], function ( | ||||
|     GeneratorProvider, | ||||
|     SinewaveLimitProvider, | ||||
|     StateGeneratorProvider, | ||||
|     SpectralGeneratorProvider, | ||||
|     SpectralAggregateGeneratorProvider, | ||||
|     GeneratorMetadataProvider | ||||
| ) { | ||||
|  | ||||
| @@ -61,6 +65,37 @@ define([ | ||||
|  | ||||
|         openmct.telemetry.addProvider(new StateGeneratorProvider()); | ||||
|  | ||||
|         openmct.types.addType("example.spectral-generator", { | ||||
|             name: "Spectral Generator", | ||||
|             description: "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.", | ||||
|             cssClass: "icon-generator-telemetry", | ||||
|             creatable: true, | ||||
|             initialize: function (object) { | ||||
|                 object.telemetry = { | ||||
|                     period: 10, | ||||
|                     amplitude: 1, | ||||
|                     wavelength: 1, | ||||
|                     frequency: 1, | ||||
|                     offset: 0, | ||||
|                     dataRateInHz: 1, | ||||
|                     phase: 0, | ||||
|                     randomness: 0 | ||||
|                 }; | ||||
|             } | ||||
|         }); | ||||
|         openmct.telemetry.addProvider(new SpectralGeneratorProvider()); | ||||
|  | ||||
|         openmct.types.addType("example.spectral-aggregate-generator", { | ||||
|             name: "Spectral Aggregate Generator", | ||||
|             description: "For development use. Generates example streaming telemetry data using a simple state algorithm.", | ||||
|             cssClass: "icon-generator-telemetry", | ||||
|             creatable: true, | ||||
|             initialize: function (object) { | ||||
|                 object.telemetry = {}; | ||||
|             } | ||||
|         }); | ||||
|         openmct.telemetry.addProvider(new SpectralAggregateGeneratorProvider()); | ||||
|  | ||||
|         openmct.types.addType("generator", { | ||||
|             name: "Sine Wave Generator", | ||||
|             description: "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.", | ||||
|   | ||||
| @@ -1,8 +1,7 @@ | ||||
| { | ||||
|   "name": "openmct", | ||||
|   "version": "1.7.7-SNAPSHOT", | ||||
|   "version": "1.7.8-SNAPSHOT", | ||||
|   "description": "The Open MCT core platform", | ||||
|   "dependencies": {}, | ||||
|   "devDependencies": { | ||||
|     "angular": ">=1.8.0", | ||||
|     "angular-route": "1.4.14", | ||||
| @@ -41,13 +40,13 @@ | ||||
|     "jsdoc": "^3.3.2", | ||||
|     "karma": "6.3.4", | ||||
|     "karma-chrome-launcher": "3.1.0", | ||||
|     "karma-firefox-launcher": "2.1.1", | ||||
|     "karma-cli": "2.0.0", | ||||
|     "karma-coverage": "2.0.3", | ||||
|     "karma-coverage-istanbul-reporter": "3.0.3", | ||||
|     "karma-junit-reporter": "2.0.1", | ||||
|     "karma-firefox-launcher": "2.1.1", | ||||
|     "karma-html-reporter": "0.2.7", | ||||
|     "karma-jasmine": "4.0.1", | ||||
|     "karma-junit-reporter": "2.0.1", | ||||
|     "karma-sourcemap-loader": "0.3.8", | ||||
|     "karma-webpack": "4.0.2", | ||||
|     "location-bar": "^3.0.1", | ||||
| @@ -62,6 +61,7 @@ | ||||
|     "node-bourbon": "^4.2.3", | ||||
|     "node-sass": "^4.14.1", | ||||
|     "painterro": "^1.2.56", | ||||
|     "plotly.js": "^2.5.0", | ||||
|     "printj": "^1.2.1", | ||||
|     "raw-loader": "^0.5.1", | ||||
|     "request": "^2.69.0", | ||||
|   | ||||
| @@ -30,8 +30,8 @@ define([ | ||||
|  | ||||
|     return function ImportExportPlugin() { | ||||
|         return function (openmct) { | ||||
|             ExportAsJSONAction.appliesTo = function (context) { | ||||
|                 return openmct.$injector.get('policyService') | ||||
|             ExportAsJSONAction.prototype.appliesTo = function (context) { | ||||
|                 return this.openmct.$injector.get('policyService') | ||||
|                     .allow("creation", context.domainObject.getCapability("type") | ||||
|                     ); | ||||
|             }; | ||||
|   | ||||
| @@ -29,7 +29,7 @@ define( | ||||
|     ], | ||||
|     function (ExportAsJSONAction, domainObjectFactory, MCT, AdapterCapability) { | ||||
|  | ||||
|         xdescribe("The export JSON action", function () { | ||||
|         describe("The export JSON action", function () { | ||||
|  | ||||
|             var context, | ||||
|                 action, | ||||
| @@ -102,7 +102,7 @@ define( | ||||
|                 expect(action).toBeDefined(); | ||||
|             }); | ||||
|  | ||||
|             it("doesn't export non-creatable objects in tree", function () { | ||||
|             xit("doesn't export non-creatable objects in tree", function () { | ||||
|                 var nonCreatableType = { | ||||
|                     hasFeature: | ||||
|                         function (feature) { | ||||
| @@ -149,7 +149,7 @@ define( | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|             it("can export self-containing objects", function () { | ||||
|             xit("can export self-containing objects", function () { | ||||
|                 var parent = domainObjectFactory({ | ||||
|                     name: 'parent', | ||||
|                     model: { | ||||
| @@ -191,7 +191,7 @@ define( | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|             it("exports links to external objects as new objects", function () { | ||||
|             xit("exports links to external objects as new objects", function () { | ||||
|                 var parent = domainObjectFactory({ | ||||
|                     name: 'parent', | ||||
|                     model: { | ||||
|   | ||||
| @@ -27,7 +27,7 @@ define( | ||||
|     ], | ||||
|     function (ImportAsJSONAction, domainObjectFactory) { | ||||
|  | ||||
|         xdescribe("The import JSON action", function () { | ||||
|         describe("The import JSON action", function () { | ||||
|  | ||||
|             var context = {}; | ||||
|             var action, | ||||
| @@ -146,7 +146,7 @@ define( | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|             it("can import self-containing objects", function () { | ||||
|             xit("can import self-containing objects", function () { | ||||
|                 var compDomainObject = domainObjectFactory({ | ||||
|                     name: 'compObject', | ||||
|                     model: { name: 'compObject'}, | ||||
| @@ -198,7 +198,7 @@ define( | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|             it("assigns new ids to each imported object", function () { | ||||
|             xit("assigns new ids to each imported object", function () { | ||||
|                 dialogService.getUserInput.and.returnValue(Promise.resolve( | ||||
|                     { | ||||
|                         selectFile: { | ||||
|   | ||||
| @@ -141,6 +141,7 @@ const NON_STYLEABLE_CONTAINER_TYPES = [ | ||||
| const NON_STYLEABLE_LAYOUT_ITEM_TYPES = [ | ||||
|     'line-view', | ||||
|     'box-view', | ||||
|     'ellipse-view', | ||||
|     'image-view' | ||||
| ]; | ||||
|  | ||||
| @@ -321,7 +322,7 @@ export default { | ||||
|             if (item) { | ||||
|                 const type = this.openmct.types.get(item.type); | ||||
|                 if (type && type.definition) { | ||||
|                     creatable = (type.definition.creatable === true); | ||||
|                     creatable = (type.definition.creatable !== undefined && (type.definition.creatable === 'true' || type.definition.creatable === true)); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|   | ||||
| @@ -230,7 +230,7 @@ describe('the plugin', function () { | ||||
|         }; | ||||
|         const staticStyle = { | ||||
|             "style": { | ||||
|                 "backgroundColor": "#717171", | ||||
|                 "backgroundColor": "#666666", | ||||
|                 "border": "1px solid #00ffff" | ||||
|             } | ||||
|         }; | ||||
| @@ -238,7 +238,7 @@ describe('the plugin', function () { | ||||
|             "conditionId": "39584410-cbf9-499e-96dc-76f27e69885d", | ||||
|             "style": { | ||||
|                 "isStyleInvisible": "", | ||||
|                 "backgroundColor": "#717171", | ||||
|                 "backgroundColor": "#666666", | ||||
|                 "border": "1px solid #ffff00" | ||||
|             } | ||||
|         }; | ||||
| @@ -250,7 +250,7 @@ describe('the plugin', function () { | ||||
|                 "configuration": { | ||||
|                     "items": [ | ||||
|                         { | ||||
|                             "fill": "#717171", | ||||
|                             "fill": "#666666", | ||||
|                             "stroke": "", | ||||
|                             "x": 1, | ||||
|                             "y": 1, | ||||
| @@ -259,12 +259,22 @@ describe('the plugin', function () { | ||||
|                             "type": "box-view", | ||||
|                             "id": "89b88746-d325-487b-aec4-11b79afff9e8" | ||||
|                         }, | ||||
|                         { | ||||
|                             "fill": "#666666", | ||||
|                             "stroke": "", | ||||
|                             "x": 1, | ||||
|                             "y": 1, | ||||
|                             "width": 10, | ||||
|                             "height": 5, | ||||
|                             "type": "ellipse-view", | ||||
|                             "id": "19b88746-d325-487b-aec4-11b79afff9z8" | ||||
|                         }, | ||||
|                         { | ||||
|                             "x": 18, | ||||
|                             "y": 9, | ||||
|                             "x2": 23, | ||||
|                             "y2": 4, | ||||
|                             "stroke": "#717171", | ||||
|                             "stroke": "#666666", | ||||
|                             "type": "line-view", | ||||
|                             "id": "57d49a28-7863-43bd-9593-6570758916f0" | ||||
|                         }, | ||||
| @@ -299,12 +309,12 @@ describe('the plugin', function () { | ||||
|                 "y": 9, | ||||
|                 "x2": 23, | ||||
|                 "y2": 4, | ||||
|                 "stroke": "#717171", | ||||
|                 "stroke": "#666666", | ||||
|                 "type": "line-view", | ||||
|                 "id": "57d49a28-7863-43bd-9593-6570758916f0" | ||||
|             }; | ||||
|             boxLayoutItem = { | ||||
|                 "fill": "#717171", | ||||
|                 "fill": "#666666", | ||||
|                 "stroke": "", | ||||
|                 "x": 1, | ||||
|                 "y": 1, | ||||
|   | ||||
| @@ -29,9 +29,10 @@ const styleProps = { | ||||
|         noneValue: NONE_VALUE, | ||||
|         applicableForType: type => { | ||||
|             return !type ? true : (type === 'text-view' | ||||
|                                       || type === 'telemetry-view' | ||||
|                                       || type === 'box-view' | ||||
|                                       || type === 'subobject-view'); | ||||
|                                             || type === 'telemetry-view' | ||||
|                                             || type === 'box-view' | ||||
|                                             || type === 'ellipse-view' | ||||
|                                             || type === 'subobject-view'); | ||||
|         } | ||||
|     }, | ||||
|     border: { | ||||
| @@ -41,6 +42,7 @@ const styleProps = { | ||||
|             return !type ? true : (type === 'text-view' | ||||
|                                             || type === 'telemetry-view' | ||||
|                                             || type === 'box-view' | ||||
|                                             || type === 'ellipse-view' | ||||
|                                             || type === 'image-view' | ||||
|                                             || type === 'line-view' | ||||
|                                             || type === 'subobject-view'); | ||||
|   | ||||
| @@ -149,6 +149,7 @@ define(['lodash'], function (_) { | ||||
|                         return type === 'text-view' | ||||
|                             || type === 'telemetry-view' | ||||
|                             || type === 'box-view' | ||||
|                             || type === 'ellipse-view' | ||||
|                             || type === 'image-view' | ||||
|                             || type === 'line-view' | ||||
|                             || type === 'subobject-view'; | ||||
| @@ -180,6 +181,10 @@ define(['lodash'], function (_) { | ||||
|                                     "name": "Box", | ||||
|                                     "class": "icon-box-round-corners" | ||||
|                                 }, | ||||
|                                 { | ||||
|                                     "name": "Ellipse", | ||||
|                                     "class": "icon-circle" | ||||
|                                 }, | ||||
|                                 { | ||||
|                                     "name": "Line", | ||||
|                                     "class": "icon-line-horz" | ||||
| @@ -745,7 +750,7 @@ define(['lodash'], function (_) { | ||||
|                         if (toolbar.remove.length === 0) { | ||||
|                             toolbar.remove = [getRemoveButton(selectedParent, selectionPath, selectedObjects)]; | ||||
|                         } | ||||
|                     } else if (layoutItem.type === 'box-view') { | ||||
|                     } else if (layoutItem.type === 'box-view' || layoutItem.type === 'ellipse-view') { | ||||
|                         if (toolbar.position.length === 0) { | ||||
|                             toolbar.position = [ | ||||
|                                 getStackOrder(selectedParent, selectionPath), | ||||
|   | ||||
| @@ -43,7 +43,7 @@ import conditionalStylesMixin from '../mixins/objectStyles-mixin'; | ||||
| export default { | ||||
|     makeDefinition() { | ||||
|         return { | ||||
|             fill: '#717171', | ||||
|             fill: '#666666', | ||||
|             stroke: '', | ||||
|             x: 1, | ||||
|             y: 1, | ||||
|   | ||||
| @@ -76,6 +76,7 @@ import uuid from 'uuid'; | ||||
| import SubobjectView from './SubobjectView.vue'; | ||||
| import TelemetryView from './TelemetryView.vue'; | ||||
| import BoxView from './BoxView.vue'; | ||||
| import EllipseView from './EllipseView.vue'; | ||||
| import TextView from './TextView.vue'; | ||||
| import LineView from './LineView.vue'; | ||||
| import ImageView from './ImageView.vue'; | ||||
| @@ -112,6 +113,7 @@ const ITEM_TYPE_VIEW_MAP = { | ||||
|     'subobject-view': SubobjectView, | ||||
|     'telemetry-view': TelemetryView, | ||||
|     'box-view': BoxView, | ||||
|     'ellipse-view': EllipseView, | ||||
|     'line-view': LineView, | ||||
|     'text-view': TextView, | ||||
|     'image-view': ImageView | ||||
|   | ||||
| @@ -28,19 +28,19 @@ | ||||
| > | ||||
|     <div | ||||
|         class="c-frame-edit__handle c-frame-edit__handle--nw" | ||||
|         @mousedown="startResize([1,1], [-1,-1], $event)" | ||||
|         @mousedown.left="startResize([1,1], [-1,-1], $event)" | ||||
|     ></div> | ||||
|     <div | ||||
|         class="c-frame-edit__handle c-frame-edit__handle--ne" | ||||
|         @mousedown="startResize([0,1], [1,-1], $event)" | ||||
|         @mousedown.left="startResize([0,1], [1,-1], $event)" | ||||
|     ></div> | ||||
|     <div | ||||
|         class="c-frame-edit__handle c-frame-edit__handle--sw" | ||||
|         @mousedown="startResize([1,0], [-1,1], $event)" | ||||
|         @mousedown.left="startResize([1,0], [-1,1], $event)" | ||||
|     ></div> | ||||
|     <div | ||||
|         class="c-frame-edit__handle c-frame-edit__handle--se" | ||||
|         @mousedown="startResize([0,0], [1,1], $event)" | ||||
|         @mousedown.left="startResize([0,0], [1,1], $event)" | ||||
|     ></div> | ||||
| </div> | ||||
| </template> | ||||
|   | ||||
							
								
								
									
										122
									
								
								src/plugins/displayLayout/components/EllipseView.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								src/plugins/displayLayout/components/EllipseView.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | ||||
| /***************************************************************************** | ||||
| * Open MCT, Copyright (c) 2014-2021, 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. | ||||
| *****************************************************************************/ | ||||
|  | ||||
| <template> | ||||
| <layout-frame | ||||
|     :item="item" | ||||
|     :grid-size="gridSize" | ||||
|     :is-editing="isEditing" | ||||
|     @move="(gridDelta) => $emit('move', gridDelta)" | ||||
|     @endMove="() => $emit('endMove')" | ||||
| > | ||||
|     <div | ||||
|         class="c-ellipse-view u-style-receiver js-style-receiver" | ||||
|         :class="[styleClass]" | ||||
|         :style="style" | ||||
|     ></div> | ||||
| </layout-frame> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import LayoutFrame from './LayoutFrame.vue'; | ||||
| import conditionalStylesMixin from '../mixins/objectStyles-mixin'; | ||||
|  | ||||
| export default { | ||||
|     makeDefinition() { | ||||
|         return { | ||||
|             fill: '#666666', | ||||
|             stroke: '', | ||||
|             x: 1, | ||||
|             y: 1, | ||||
|             width: 10, | ||||
|             height: 10 | ||||
|         }; | ||||
|     }, | ||||
|     components: { | ||||
|         LayoutFrame | ||||
|     }, | ||||
|     mixins: [conditionalStylesMixin], | ||||
|     inject: ['openmct'], | ||||
|     props: { | ||||
|         item: { | ||||
|             type: Object, | ||||
|             required: true | ||||
|         }, | ||||
|         gridSize: { | ||||
|             type: Array, | ||||
|             required: true, | ||||
|             validator: (arr) => arr && arr.length === 2 | ||||
|                     && arr.every(el => typeof el === 'number') | ||||
|         }, | ||||
|         index: { | ||||
|             type: Number, | ||||
|             required: true | ||||
|         }, | ||||
|         initSelect: Boolean, | ||||
|         isEditing: { | ||||
|             type: Boolean, | ||||
|             required: true | ||||
|         } | ||||
|     }, | ||||
|     computed: { | ||||
|         style() { | ||||
|             if (this.itemStyle) { | ||||
|                 return this.itemStyle; | ||||
|             } else { | ||||
|                 return { | ||||
|                     backgroundColor: this.item.fill, | ||||
|                     border: this.item.stroke ? '1px solid ' + this.item.stroke : '' | ||||
|                 }; | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     watch: { | ||||
|         index(newIndex) { | ||||
|             if (!this.context) { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             this.context.index = newIndex; | ||||
|         }, | ||||
|         item(newItem) { | ||||
|             if (!this.context) { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             this.context.layoutItem = newItem; | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.context = { | ||||
|             layoutItem: this.item, | ||||
|             index: this.index | ||||
|         }; | ||||
|         this.removeSelectable = this.openmct.selection.selectable( | ||||
|             this.$el, this.context, this.initSelect); | ||||
|     }, | ||||
|     destroyed() { | ||||
|         if (this.removeSelectable) { | ||||
|             this.removeSelectable(); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
| </script> | ||||
| @@ -96,7 +96,7 @@ export default { | ||||
|             y: 10, | ||||
|             x2: 10, | ||||
|             y2: 5, | ||||
|             stroke: '#717171' | ||||
|             stroke: '#666666' | ||||
|         }; | ||||
|     }, | ||||
|     mixins: [conditionalStylesMixin], | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| .c-box-view { | ||||
| .c-box-view, | ||||
| .c-ellipse-view { | ||||
|     border-width: $drawingObjBorderW !important; | ||||
|     display: flex; | ||||
|     align-items: stretch; | ||||
| @@ -8,6 +9,10 @@ | ||||
|     } | ||||
| } | ||||
|  | ||||
| .c-ellipse-view { | ||||
|     border-radius: 50%; | ||||
| } | ||||
|  | ||||
| .c-line-view { | ||||
|     &.c-frame { | ||||
|         box-shadow: none !important; | ||||
|   | ||||
| @@ -186,7 +186,7 @@ describe('the plugin', function () { | ||||
|                 'configuration': { | ||||
|                     'items': [ | ||||
|                         { | ||||
|                             'fill': '#717171', | ||||
|                             'fill': '#666666', | ||||
|                             'stroke': '', | ||||
|                             'x': 1, | ||||
|                             'y': 1, | ||||
| @@ -195,12 +195,22 @@ describe('the plugin', function () { | ||||
|                             'type': 'box-view', | ||||
|                             'id': '89b88746-d325-487b-aec4-11b79afff9e8' | ||||
|                         }, | ||||
|                         { | ||||
|                             'fill': '#666666', | ||||
|                             'stroke': '', | ||||
|                             'x': 1, | ||||
|                             'y': 1, | ||||
|                             'width': 10, | ||||
|                             'height': 10, | ||||
|                             'type': 'ellipse-view', | ||||
|                             'id': '19b88746-d325-487b-aec4-11b79afff9z8' | ||||
|                         }, | ||||
|                         { | ||||
|                             'x': 18, | ||||
|                             'y': 9, | ||||
|                             'x2': 23, | ||||
|                             'y2': 4, | ||||
|                             'stroke': '#717171', | ||||
|                             'stroke': '#666666', | ||||
|                             'type': 'line-view', | ||||
|                             'id': '57d49a28-7863-43bd-9593-6570758916f0' | ||||
|                         }, | ||||
| @@ -341,7 +351,7 @@ describe('the plugin', function () { | ||||
|         it('provides controls including separators', () => { | ||||
|             const displayLayoutToolbar = openmct.toolbars.get(selection); | ||||
|  | ||||
|             expect(displayLayoutToolbar.length).toBe(9); | ||||
|             expect(displayLayoutToolbar.length).toBe(7); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
|   | ||||
| @@ -103,10 +103,13 @@ export function validateNotebookStorageObject() { | ||||
|  | ||||
|     let valid = false; | ||||
|     if (notebookStorage) { | ||||
|         Object.entries(notebookStorage).forEach(([key, value]) => { | ||||
|         const oldInvalidKeys = ['notebookMeta', 'page', 'section']; | ||||
|         valid = Object.entries(notebookStorage).every(([key, value]) => { | ||||
|             const validKey = key !== undefined && key !== null; | ||||
|             const validValue = value !== undefined && value !== null; | ||||
|             valid = validKey && validValue; | ||||
|             const hasOldInvalidKeys = oldInvalidKeys.includes(key); | ||||
|  | ||||
|             return validKey && validValue && !hasOldInvalidKeys; | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -89,13 +89,4 @@ ColorPalette.prototype.getNextColor = function () { | ||||
|     return this.availableColors.shift(); | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @param {number} index the index of the color to return.  An index | ||||
|  * value larger than the size of the index will wrap around. | ||||
|  * @returns {Color} | ||||
|  */ | ||||
| ColorPalette.prototype.getColor = function (index) { | ||||
|     return this.colors[index % this.colors.length]; | ||||
| }; | ||||
|  | ||||
| export default ColorPalette; | ||||
|   | ||||
| @@ -19,13 +19,17 @@ | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| import { SPECTRAL_AGGREGATE_KEY } from './spectralAggregatePlot/SpectralAggregateConstants'; | ||||
| import PlotViewProvider from './PlotViewProvider'; | ||||
| import SpectralPlotViewProvider from './spectralPlot/SpectralPlotViewProvider'; | ||||
| import SpectralAggregatePlotViewProvider from './spectralAggregatePlot/SpectralAggregatePlotViewProvider'; | ||||
| import OverlayPlotViewProvider from './overlayPlot/OverlayPlotViewProvider'; | ||||
| import StackedPlotViewProvider from './stackedPlot/StackedPlotViewProvider'; | ||||
| import PlotsInspectorViewProvider from './inspector/PlotsInspectorViewProvider'; | ||||
| import OverlayPlotCompositionPolicy from './overlayPlot/OverlayPlotCompositionPolicy'; | ||||
| import StackedPlotCompositionPolicy from './stackedPlot/StackedPlotCompositionPolicy'; | ||||
| import SpectralPlotCompositionPolicy from './spectralPlot/SpectralPlotCompositionPolicy'; | ||||
| import SpectralAggregatePlotCompositionPolicy from './spectralAggregatePlot/SpectralAggregatePlotCompositionPolicy'; | ||||
|  | ||||
| export default function () { | ||||
|     return function install(openmct) { | ||||
| @@ -59,13 +63,46 @@ export default function () { | ||||
|             }, | ||||
|             priority: 890 | ||||
|         }); | ||||
|         openmct.types.addType('telemetry.plot.spectral', { | ||||
|             key: "telemetry.plot.spectral", | ||||
|             name: "Spectral Plot", | ||||
|             cssClass: "icon-plot-stacked", | ||||
|             description: "View Spectra on Y Axes with non-time domain on the X axis. Can be added to Display Layouts.", | ||||
|             creatable: true, | ||||
|             initialize: function (domainObject) { | ||||
|                 domainObject.composition = []; | ||||
|                 domainObject.configuration = {}; | ||||
|             }, | ||||
|             priority: 890 | ||||
|         }); | ||||
|  | ||||
|         openmct.types.addType(SPECTRAL_AGGREGATE_KEY, { | ||||
|             key: SPECTRAL_AGGREGATE_KEY, | ||||
|             name: "Spectral Aggregate Plot", | ||||
|             cssClass: "icon-plot-stacked", | ||||
|             description: "View Spectra on Y Axes with non-time domain on the X axis. Can be added to Display Layouts.", | ||||
|             creatable: true, | ||||
|             initialize: function (domainObject) { | ||||
|                 domainObject.composition = []; | ||||
|                 domainObject.configuration = { | ||||
|                     plotType: 'bar' | ||||
|                 }; | ||||
|             }, | ||||
|             priority: 891 | ||||
|         }); | ||||
|  | ||||
|         openmct.objectViews.addProvider(new StackedPlotViewProvider(openmct)); | ||||
|         openmct.objectViews.addProvider(new OverlayPlotViewProvider(openmct)); | ||||
|         openmct.objectViews.addProvider(new PlotViewProvider(openmct)); | ||||
|         openmct.objectViews.addProvider(new SpectralPlotViewProvider(openmct)); | ||||
|         openmct.objectViews.addProvider(new SpectralAggregatePlotViewProvider(openmct)); | ||||
|  | ||||
|         openmct.inspectorViews.addProvider(new PlotsInspectorViewProvider(openmct)); | ||||
|  | ||||
|         openmct.composition.addPolicy(new OverlayPlotCompositionPolicy(openmct).allow); | ||||
|         openmct.composition.addPolicy(new StackedPlotCompositionPolicy(openmct).allow); | ||||
|         openmct.composition.addPolicy(new SpectralPlotCompositionPolicy(openmct).allow); | ||||
|         openmct.composition.addPolicy(new SpectralAggregatePlotCompositionPolicy(openmct).allow); | ||||
|     }; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -24,10 +24,12 @@ import {createMouseEvent, createOpenMct, resetApplicationState, spyOnBuiltins} f | ||||
| import PlotVuePlugin from "./plugin"; | ||||
| import Vue from "vue"; | ||||
| import StackedPlot from "./stackedPlot/StackedPlot.vue"; | ||||
| // import SpectralPlot from "./spectralPlot/SpectralPlot.vue"; | ||||
| import configStore from "./configuration/configStore"; | ||||
| import EventEmitter from "EventEmitter"; | ||||
| import PlotOptions from "./inspector/PlotOptions.vue"; | ||||
| import PlotConfigurationModel from "./configuration/PlotConfigurationModel"; | ||||
| import { SPECTRAL_AGGREGATE_VIEW, SPECTRAL_AGGREGATE_KEY } from './spectralAggregatePlot/SpectralAggregateConstants'; | ||||
|  | ||||
| describe("the plugin", function () { | ||||
|     let element; | ||||
| @@ -312,6 +314,38 @@ describe("the plugin", function () { | ||||
|             let plotView = applicableViews.find((viewProvider) => viewProvider.key === "plot-stacked"); | ||||
|             expect(plotView).toBeDefined(); | ||||
|         }); | ||||
|  | ||||
|         it("provides a spectral plot view for objects with telemetry", () => { | ||||
|             const testTelemetryObject = { | ||||
|                 id: "test-object", | ||||
|                 type: "telemetry.plot.spectral", | ||||
|                 telemetry: { | ||||
|                     values: [{ | ||||
|                         key: "a-very-fine-key" | ||||
|                     }] | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             const applicableViews = openmct.objectViews.get(testTelemetryObject, mockObjectPath); | ||||
|             let plotView = applicableViews.find((viewProvider) => viewProvider.key === "plot-spectral"); | ||||
|             expect(plotView).toBeDefined(); | ||||
|         }); | ||||
|  | ||||
|         it("provides a spectral aggregate plot view for objects with telemetry", () => { | ||||
|             const testTelemetryObject = { | ||||
|                 id: "test-object", | ||||
|                 type: SPECTRAL_AGGREGATE_KEY, | ||||
|                 telemetry: { | ||||
|                     values: [{ | ||||
|                         key: "lots-of-aggregate-telemetry" | ||||
|                     }] | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             const applicableViews = openmct.objectViews.get(testTelemetryObject, mockObjectPath); | ||||
|             let plotView = applicableViews.find((viewProvider) => viewProvider.key === SPECTRAL_AGGREGATE_VIEW); | ||||
|             expect(plotView).toBeDefined(); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe("The single plot view", () => { | ||||
| @@ -462,6 +496,146 @@ describe("the plugin", function () { | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     /* | ||||
|     * disabling this until we develop the plot view | ||||
|     describe("The spectral plot view", () => { | ||||
|         let testTelemetryObject; | ||||
|         // eslint-disable-next-line no-unused-vars | ||||
|         let testTelemetryObject2; | ||||
|         // eslint-disable-next-line no-unused-vars | ||||
|         let config; | ||||
|         let spectralPlotObject; | ||||
|         let component; | ||||
|         let mockComposition; | ||||
|         // eslint-disable-next-line no-unused-vars | ||||
|         let plotViewComponentObject; | ||||
|  | ||||
|         beforeEach(() => { | ||||
|             const getFunc = openmct.$injector.get; | ||||
|             spyOn(openmct.$injector, "get") | ||||
|                 .withArgs("exportImageService").and.returnValue({ | ||||
|                     exportPNG: () => {}, | ||||
|                     exportJPG: () => {} | ||||
|                 }) | ||||
|                 .and.callFake(getFunc); | ||||
|  | ||||
|             spectralPlotObject = { | ||||
|                 identifier: { | ||||
|                     namespace: "", | ||||
|                     key: "test-spectral-plot" | ||||
|                 }, | ||||
|                 type: "telemetry.plot.spectral", | ||||
|                 name: "Test Spectral Plot" | ||||
|             }; | ||||
|  | ||||
|             testTelemetryObject = { | ||||
|                 identifier: { | ||||
|                     namespace: "", | ||||
|                     key: "test-object" | ||||
|                 }, | ||||
|                 type: "test-object", | ||||
|                 name: "Test Object", | ||||
|                 telemetry: { | ||||
|                     values: [{ | ||||
|                         key: "utc", | ||||
|                         format: "utc", | ||||
|                         name: "Time", | ||||
|                         hints: { | ||||
|                             domain: 1 | ||||
|                         } | ||||
|                     }, { | ||||
|                         key: "some-key", | ||||
|                         name: "Some attribute", | ||||
|                         hints: { | ||||
|                             range: 1 | ||||
|                         } | ||||
|                     }, { | ||||
|                         key: "some-other-key", | ||||
|                         name: "Another attribute", | ||||
|                         hints: { | ||||
|                             range: 2 | ||||
|                         } | ||||
|                     }] | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             testTelemetryObject2 = { | ||||
|                 identifier: { | ||||
|                     namespace: "", | ||||
|                     key: "test-object2" | ||||
|                 }, | ||||
|                 type: "test-object", | ||||
|                 name: "Test Object2", | ||||
|                 telemetry: { | ||||
|                     values: [{ | ||||
|                         key: "utc", | ||||
|                         format: "utc", | ||||
|                         name: "Time", | ||||
|                         hints: { | ||||
|                             domain: 1 | ||||
|                         } | ||||
|                     }, { | ||||
|                         key: "wavelength", | ||||
|                         name: "Wavelength", | ||||
|                         hints: { | ||||
|                             range: 1 | ||||
|                         } | ||||
|                     }, { | ||||
|                         key: "some-other-key2", | ||||
|                         name: "Another attribute2", | ||||
|                         hints: { | ||||
|                             range: 2 | ||||
|                         } | ||||
|                     }] | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             mockComposition = new EventEmitter(); | ||||
|             mockComposition.load = () => { | ||||
|                 mockComposition.emit('add', testTelemetryObject); | ||||
|  | ||||
|                 return [testTelemetryObject]; | ||||
|             }; | ||||
|  | ||||
|             spyOn(openmct.composition, 'get').and.returnValue(mockComposition); | ||||
|  | ||||
|             let viewContainer = document.createElement("div"); | ||||
|             child.append(viewContainer); | ||||
|             component = new Vue({ | ||||
|                 el: viewContainer, | ||||
|                 components: { | ||||
|                     SpectralPlot | ||||
|                 }, | ||||
|                 provide: { | ||||
|                     openmct: openmct, | ||||
|                     domainObject: spectralPlotObject, | ||||
|                     composition: openmct.composition.get(spectralPlotObject) | ||||
|                 }, | ||||
|                 template: "<spectral-plot></spectral-plot>" | ||||
|             }); | ||||
|  | ||||
|             cleanupFirst.push(() => { | ||||
|                 component.$destroy(); | ||||
|                 component = undefined; | ||||
|             }); | ||||
|  | ||||
|             return telemetryPromise | ||||
|                 .then(Vue.nextTick()) | ||||
|                 .then(() => { | ||||
|                     plotViewComponentObject = component.$root.$children[0]; | ||||
|                     const configId = openmct.objects.makeKeyString(testTelemetryObject.identifier); | ||||
|                     config = configStore.get(configId); | ||||
|                 }); | ||||
|         }); | ||||
|  | ||||
|         it("Renders a collapsed legend for every telemetry", () => { | ||||
|             let legend = element.querySelectorAll(".plot-wrapper-collapsed-legend .plot-series-name"); | ||||
|             expect(legend.length).toBe(1); | ||||
|             expect(legend[0].innerHTML).toEqual("Test Object"); | ||||
|         }); | ||||
|  | ||||
|     }); */ | ||||
|  | ||||
|     describe("The stacked plot view", () => { | ||||
|         let testTelemetryObject; | ||||
|         let testTelemetryObject2; | ||||
| @@ -990,4 +1164,39 @@ describe("the plugin", function () { | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe("the spectral plot", () => { | ||||
|         const mockObject = { | ||||
|             name: 'A Very Nice Spectral Plot', | ||||
|             key: 'telemetry.plot.spectral', | ||||
|             creatable: true | ||||
|         }; | ||||
|  | ||||
|         it('defines a spectral plot object type with the correct key', () => { | ||||
|             const objectDef = openmct.types.get('telemetry.plot.spectral').definition; | ||||
|             expect(objectDef.key).toEqual(mockObject.key); | ||||
|         }); | ||||
|  | ||||
|         it('is creatable', () => { | ||||
|             const objectDef = openmct.types.get('telemetry.plot.spectral').definition; | ||||
|             expect(objectDef.creatable).toEqual(mockObject.creatable); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe("the aggregate spectral plot", () => { | ||||
|         const mockObject = { | ||||
|             name: 'An Even Nicer Aggregate Spectral Plot', | ||||
|             key: SPECTRAL_AGGREGATE_KEY, | ||||
|             creatable: true | ||||
|         }; | ||||
|  | ||||
|         it('defines a spectral plot object type with the correct key', () => { | ||||
|             const objectDef = openmct.types.get(SPECTRAL_AGGREGATE_KEY).definition; | ||||
|             expect(objectDef.key).toEqual(mockObject.key); | ||||
|         }); | ||||
|  | ||||
|         it('is creatable', () => { | ||||
|             const objectDef = openmct.types.get(SPECTRAL_AGGREGATE_KEY).definition; | ||||
|             expect(objectDef.creatable).toEqual(mockObject.creatable); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
|   | ||||
| @@ -0,0 +1,10 @@ | ||||
| export const CONFIGURATION_CHANGED = 'configurationChanged'; | ||||
| export const HOVER_VALUES_CHANGED = 'hoverValuesChanged'; | ||||
| export const HOVER_VALUES_CLEARED = 'hoverValuesCleared'; | ||||
| export const LEGEND_EXPANDED = 'plot-legends-expanded'; | ||||
| export const REALTIME_POLL_INTERVAL_IN_MS = 5000; | ||||
|  | ||||
| export const SPECTRAL_AGGREGATE_VIEW = 'plot.spectral.aggregate.view'; | ||||
| export const SPECTRAL_AGGREGATE_KEY = 'telemetry.plot.spectral.aggregate'; | ||||
| export const SUBSCRIBE = 'subscribe'; | ||||
| export const UNSUBSCRIBE = 'unsubscribe'; | ||||
							
								
								
									
										289
									
								
								src/plugins/plot/spectralAggregatePlot/SpectralAggregatePlot.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										289
									
								
								src/plugins/plot/spectralAggregatePlot/SpectralAggregatePlot.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,289 @@ | ||||
| <template> | ||||
| <div ref="plotWrapper" | ||||
|      class="has-local-controls" | ||||
|      :class="{ 's-unsynced' : isZoomed }" | ||||
| > | ||||
|     <div v-if="isZoomed" | ||||
|          class="l-state-indicators" | ||||
|     > | ||||
|         <span class="l-state-indicators__alert-no-lad t-object-alert t-alert-unsynced icon-alert-triangle" | ||||
|               title="This plot is not currently displaying the latest data. Reset pan/zoom to view latest data." | ||||
|         ></span> | ||||
|     </div> | ||||
|     <div ref="plot" | ||||
|          class="c-spectral-aggregate-plot__plot" | ||||
|     ></div> | ||||
|     <div ref="localControl" | ||||
|          class="gl-plot__local-controls h-local-controls h-local-controls--overlay-content c-local-controls--show-on-hover" | ||||
|     > | ||||
|         <button v-if="data.length" | ||||
|                 class="c-button icon-reset" | ||||
|                 :disabled="!isZoomed" | ||||
|                 title="Reset pan/zoom" | ||||
|                 @click="reset()" | ||||
|         > | ||||
|         </button> | ||||
|     </div> | ||||
| </div> | ||||
| </template> | ||||
| <script> | ||||
| import Plotly from 'plotly.js/dist/plotly'; | ||||
| import { HOVER_VALUES_CLEARED, HOVER_VALUES_CHANGED, SUBSCRIBE, UNSUBSCRIBE } from './SpectralAggregateConstants'; | ||||
|  | ||||
| const PLOT_PADDING_IN_PERCENT = 1; | ||||
| const MULTI_AXES_X_PADDING_PERCENT = { | ||||
|     LEFT: 8, | ||||
|     RIGHT: 94 | ||||
| }; | ||||
|  | ||||
| export default { | ||||
|     inject: ['openmct', 'domainObject'], | ||||
|     props: [ | ||||
|         'data', | ||||
|         'legendExpanded', | ||||
|         'plotAxisTitle' | ||||
|     ], | ||||
|     data() { | ||||
|         return { | ||||
|             isZoomed: false, | ||||
|             primaryYAxisRange: { | ||||
|                 min: '', | ||||
|                 max: '' | ||||
|             }, | ||||
|             xAxisRange: { | ||||
|                 min: '', | ||||
|                 max: '' | ||||
|             } | ||||
|         }; | ||||
|     }, | ||||
|     watch: { | ||||
|         data: { | ||||
|             immediate: false, | ||||
|             handler: 'updateData' | ||||
|         }, | ||||
|         legendExpanded: { | ||||
|             immediate: false, | ||||
|             handler: 'updatePlot' | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         Plotly.newPlot(this.$refs.plot, Array.from(this.data), this.getLayout(), { | ||||
|             responsive: true, | ||||
|             displayModeBar: false | ||||
|         }); | ||||
|         this.registerListeners(); | ||||
|     }, | ||||
|     beforeDestroy() { | ||||
|         this.$refs.plot.removeAllListeners(); | ||||
|  | ||||
|         if (this.plotResizeObserver) { | ||||
|             this.plotResizeObserver.unobserve(this.$refs.plotWrapper); | ||||
|             clearTimeout(this.resizeTimer); | ||||
|         } | ||||
|     }, | ||||
|     methods: { | ||||
|         getAxisMinMax(axis) { | ||||
|             const min = axis.autoSize | ||||
|                 ? '' | ||||
|                 : axis.min; | ||||
|             const max = axis.autoSize | ||||
|                 ? '' | ||||
|                 : axis.max; | ||||
|  | ||||
|             return { | ||||
|                 min, | ||||
|                 max | ||||
|             }; | ||||
|         }, | ||||
|         getAxisPadding(min, max) { | ||||
|             return (Math.abs(max - min) * PLOT_PADDING_IN_PERCENT / 100) || 0; | ||||
|         }, | ||||
|         getLayout() { | ||||
|             const yAxesMeta = this.getYAxisMeta(); | ||||
|             const primaryYaxis = this.getYaxisLayout(yAxesMeta['1']); | ||||
|             const xAxisDomain = this.getXAxisDomain(yAxesMeta); | ||||
|  | ||||
|             return { | ||||
|                 // hovermode: 'closest', | ||||
|                 // hoverdistance: -1, | ||||
|                 autosize: true, | ||||
|                 showlegend: false, | ||||
|                 font: { | ||||
|                     family: 'Helvetica Neue, Helvetica, Arial, sans-serif', | ||||
|                     size: '12px', | ||||
|                     color: '#666' | ||||
|                 }, | ||||
|                 xaxis: { | ||||
|                     domain: xAxisDomain, | ||||
|                     // hoverformat: '.2r', | ||||
|                     range: [this.xAxisRange.min, this.xAxisRange.max], | ||||
|                     title: this.plotAxisTitle.xAxisTitle | ||||
|                     // zeroline: false | ||||
|                 }, | ||||
|                 yaxis: primaryYaxis, | ||||
|                 margin: { | ||||
|                     l: 40, | ||||
|                     r: 10, | ||||
|                     b: 40, | ||||
|                     t: 20 | ||||
|                 }, | ||||
|                 paper_bgcolor: 'transparent', | ||||
|                 plot_bgcolor: 'transparent' | ||||
|             }; | ||||
|         }, | ||||
|         getYAxisMeta() { | ||||
|             const yAxisMeta = {}; | ||||
|  | ||||
|             this.data.forEach(d => { | ||||
|                 const yAxisMetadata = d.yAxisMetadata; | ||||
|                 const range = '1'; | ||||
|                 const side = 'left'; | ||||
|                 const name = ''; | ||||
|                 const unit = yAxisMetadata.units; | ||||
|  | ||||
|                 yAxisMeta[range] = { | ||||
|                     range, | ||||
|                     side, | ||||
|                     name, | ||||
|                     unit | ||||
|                 }; | ||||
|             }); | ||||
|  | ||||
|             return yAxisMeta; | ||||
|         }, | ||||
|         getXAxisDomain(yAxisMeta) { | ||||
|             let leftPaddingPerc = 0; | ||||
|             let rightPaddingPerc = 100; | ||||
|             let rightSide = yAxisMeta && Object.values(yAxisMeta).filter((axisMeta => axisMeta.side === 'right')); | ||||
|             let leftSide = yAxisMeta && Object.values(yAxisMeta).filter((axisMeta => axisMeta.side === 'left')); | ||||
|             if (yAxisMeta && rightSide.length > 1) { | ||||
|                 rightPaddingPerc = MULTI_AXES_X_PADDING_PERCENT.RIGHT; | ||||
|             } | ||||
|  | ||||
|             if (yAxisMeta && leftSide.length > 1) { | ||||
|                 leftPaddingPerc = MULTI_AXES_X_PADDING_PERCENT.LEFT; | ||||
|             } | ||||
|  | ||||
|             return [leftPaddingPerc / 100, rightPaddingPerc / 100]; | ||||
|         }, | ||||
|         getYaxisLayout(yAxisMeta) { | ||||
|             if (!yAxisMeta) { | ||||
|                 return {}; | ||||
|             } | ||||
|  | ||||
|             const { name, range, side = 'left', unit } = yAxisMeta; | ||||
|             const title = `${name} ${unit ? '(' + unit + ')' : ''}`; | ||||
|             const yaxis = { | ||||
|                 // hoverformat: '.2r', | ||||
|                 // showgrid: true, | ||||
|                 title | ||||
|                 // zeroline: false | ||||
|             }; | ||||
|  | ||||
|             let yAxistype = this.primaryYAxisRange; | ||||
|             if (range === '1') { | ||||
|                 yaxis.range = [yAxistype.min, yAxistype.max]; | ||||
|  | ||||
|                 return yaxis; | ||||
|             } | ||||
|  | ||||
|             yaxis.range = [yAxistype.min, yAxistype.max]; | ||||
|             yaxis.anchor = side.toLowerCase() === 'left' | ||||
|                 ? 'free' | ||||
|                 : 'x'; | ||||
|             yaxis.showline = side.toLowerCase() === 'left'; | ||||
|             yaxis.side = side.toLowerCase(); | ||||
|             yaxis.overlaying = 'y'; | ||||
|             yaxis.position = 0.01; | ||||
|  | ||||
|             return yaxis; | ||||
|         }, | ||||
|         handleHover(isHovered, itemValues) { | ||||
|             return () => { | ||||
|                 this.updateLocalControlPosition(isHovered); | ||||
|  | ||||
|                 const eventName = isHovered ? HOVER_VALUES_CHANGED : HOVER_VALUES_CLEARED; | ||||
|                 this.$emit(eventName, { itemValues }); | ||||
|             }; | ||||
|         }, | ||||
|         registerListeners() { | ||||
|             this.$refs.plot.on('plotly_hover', this.handleHover.bind(this, true)); | ||||
|             this.$refs.plot.on('plotly_unhover', this.handleHover.bind(this, false)); | ||||
|             this.$refs.plot.on('plotly_relayout', this.zoom); | ||||
|             this.resizeTimer = false; | ||||
|             if (window.ResizeObserver) { | ||||
|                 this.plotResizeObserver = new ResizeObserver(() => { | ||||
|                     // debounce and trigger window resize so that plotly can resize the plot | ||||
|                     clearTimeout(this.resizeTimer); | ||||
|                     this.resizeTimer = setTimeout(() => { | ||||
|                         window.dispatchEvent(new Event('resize')); | ||||
|                     }, 250); | ||||
|                 }); | ||||
|                 this.plotResizeObserver.observe(this.$refs.plotWrapper); | ||||
|             } | ||||
|         }, | ||||
|         reset() { | ||||
|             this.updatePlot(); | ||||
|  | ||||
|             this.isZoomed = false; | ||||
|             this.$emit(SUBSCRIBE); | ||||
|         }, | ||||
|         updateData() { | ||||
|             this.updatePlot(); | ||||
|         }, | ||||
|         updateLocalControlPosition() { | ||||
|             const localControl = this.$refs.localControl; | ||||
|             localControl.style.display = 'none'; | ||||
|  | ||||
|             const plot = this.$refs.plot; | ||||
|             const bgLayer = this.$el.querySelector('.bglayer'); | ||||
|  | ||||
|             const plotBoundingRect = plot.getBoundingClientRect(); | ||||
|             const bgLayerBoundingRect = bgLayer.getBoundingClientRect(); | ||||
|  | ||||
|             const top = bgLayerBoundingRect.top - plotBoundingRect.top + 5; | ||||
|             const left = bgLayerBoundingRect.left - plotBoundingRect.left + 5; | ||||
|  | ||||
|             localControl.style.top = `${top}px`; | ||||
|             localControl.style.left = `${left}px`; | ||||
|             localControl.style.display = 'block'; | ||||
|         }, | ||||
|         updatePlot() { | ||||
|             if (!this.$refs || !this.$refs.plot) { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             Plotly.react(this.$refs.plot, Array.from(this.data), this.getLayout()); | ||||
|         }, | ||||
|         zoom(eventData) { | ||||
|             const autorange = eventData['xaxis.autorange']; | ||||
|             const { autosize } = eventData; | ||||
|  | ||||
|             if (autosize || autorange) { | ||||
|                 this.isZoomed = false; | ||||
|                 this.reset(); | ||||
|  | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             this.isZoomed = true; | ||||
|             this.$emit(UNSUBSCRIBE); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
|     .c-spectral-aggregate-plot__plot { | ||||
|         height: 100%; | ||||
|     } | ||||
|  | ||||
|     .c-spectral-aggregate-plot-view .gl-plot__local-controls { | ||||
|         top: 25px; | ||||
|     } | ||||
|  | ||||
|     .has-local-controls { | ||||
|         border: 1px solid transparent; | ||||
|     } | ||||
| </style> | ||||
|  | ||||
| @@ -0,0 +1,58 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2021, 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| import { SPECTRAL_AGGREGATE_KEY } from './SpectralAggregateConstants'; | ||||
| export default function SpectralAggregatePlotCompositionPolicy(openmct) { | ||||
|     function hasAggregateDomainAndRange(metadata) { | ||||
|         const rangeValues = metadata.valuesForHints(['domain']); | ||||
|         const domainValues = metadata.valuesForHints(['range']); | ||||
|  | ||||
|         return rangeValues.length > 0 | ||||
|         || domainValues.length > 0; | ||||
|     } | ||||
|  | ||||
|     function hasSpectralAggregateTelemetry(domainObject) { | ||||
|         if (!Object.prototype.hasOwnProperty.call(domainObject, 'telemetry')) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         let metadata = openmct.telemetry.getMetadata(domainObject); | ||||
|  | ||||
|         return metadata.values().length > 0 && hasAggregateDomainAndRange(metadata); | ||||
|     } | ||||
|  | ||||
|     function hasNoChildren(parentObject) { | ||||
|         return parentObject.composition && parentObject.composition.length < 1; | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         allow: function (parent, child) { | ||||
|             if ((parent.type === SPECTRAL_AGGREGATE_KEY) | ||||
|                 && ((child.type !== 'telemetry.plot.overlay') && (hasSpectralAggregateTelemetry(child) === false) || (hasNoChildren(parent) === false)) | ||||
|             ) { | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             return true; | ||||
|         } | ||||
|     }; | ||||
| } | ||||
| @@ -0,0 +1,376 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2021, 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| import SpectralAggregatePlotCompositionPolicy from "./SpectralAggregatePlotCompositionPolicy"; | ||||
| import { createOpenMct } from "utils/testing"; | ||||
|  | ||||
| describe("The spectral aggregation plot composition policy", () => { | ||||
|     let openmct; | ||||
|     const mockNonSpectralMetaData = { | ||||
|         "period": 10, | ||||
|         "amplitude": 1, | ||||
|         "offset": 0, | ||||
|         "dataRateInHz": 1, | ||||
|         "phase": 0, | ||||
|         "randomness": 0, | ||||
|         valuesForHints: () => { | ||||
|             return [ | ||||
|                 { | ||||
|                     "key": "sin", | ||||
|                     "name": "Sine", | ||||
|                     "unit": "Hz", | ||||
|                     "formatString": "%0.2f", | ||||
|                     "hints": { | ||||
|                         "range": 1, | ||||
|                         "priority": 4 | ||||
|                     }, | ||||
|                     "source": "sin" | ||||
|                 }, | ||||
|                 { | ||||
|                     "key": "cos", | ||||
|                     "name": "Cosine", | ||||
|                     "unit": "deg", | ||||
|                     "formatString": "%0.2f", | ||||
|                     "hints": { | ||||
|                         "range": 2, | ||||
|                         "priority": 5 | ||||
|                     }, | ||||
|                     "source": "cos" | ||||
|                 } | ||||
|             ]; | ||||
|         }, | ||||
|         values: [ | ||||
|             { | ||||
|                 "key": "name", | ||||
|                 "name": "Name", | ||||
|                 "format": "string", | ||||
|                 "source": "name", | ||||
|                 "hints": { | ||||
|                     "priority": 0 | ||||
|                 } | ||||
|             }, | ||||
|             { | ||||
|                 "key": "utc", | ||||
|                 "name": "Time", | ||||
|                 "format": "utc", | ||||
|                 "hints": { | ||||
|                     "domain": 1, | ||||
|                     "priority": 1 | ||||
|                 }, | ||||
|                 "source": "utc" | ||||
|             }, | ||||
|             { | ||||
|                 "key": "yesterday", | ||||
|                 "name": "Yesterday", | ||||
|                 "format": "utc", | ||||
|                 "hints": { | ||||
|                     "domain": 2, | ||||
|                     "priority": 2 | ||||
|                 }, | ||||
|                 "source": "yesterday" | ||||
|             }, | ||||
|             { | ||||
|                 "key": "cos", | ||||
|                 "name": "Cosine", | ||||
|                 "unit": "deg", | ||||
|                 "formatString": "%0.2f", | ||||
|                 "hints": { | ||||
|                     "domain": 3, | ||||
|                     "priority": 3 | ||||
|                 }, | ||||
|                 "source": "cos" | ||||
|             }, | ||||
|             { | ||||
|                 "key": "sin", | ||||
|                 "name": "Sine", | ||||
|                 "unit": "Hz", | ||||
|                 "formatString": "%0.2f", | ||||
|                 "hints": { | ||||
|                     "range": 1, | ||||
|                     "priority": 4 | ||||
|                 }, | ||||
|                 "source": "sin" | ||||
|             }, | ||||
|             { | ||||
|                 "key": "cos", | ||||
|                 "name": "Cosine", | ||||
|                 "unit": "deg", | ||||
|                 "formatString": "%0.2f", | ||||
|                 "hints": { | ||||
|                     "range": 2, | ||||
|                     "priority": 5 | ||||
|                 }, | ||||
|                 "source": "cos" | ||||
|             } | ||||
|         ] | ||||
|     }; | ||||
|     const mockGoodSpectralMetaData = { | ||||
|         "period": 10, | ||||
|         "amplitude": 1, | ||||
|         "offset": 0, | ||||
|         "dataRateInHz": 1, | ||||
|         "phase": 0, | ||||
|         "randomness": 0, | ||||
|         "wavelength": 0, | ||||
|         valuesForHints: () => { | ||||
|             return [ | ||||
|                 { | ||||
|                     "key": "sin", | ||||
|                     "name": "Sine", | ||||
|                     "unit": "Hz", | ||||
|                     "formatString": "%0.2f", | ||||
|                     "hints": { | ||||
|                         "range": 1, | ||||
|                         "priority": 4 | ||||
|                     }, | ||||
|                     "source": "sin" | ||||
|                 }, | ||||
|                 { | ||||
|                     "key": "cos", | ||||
|                     "name": "Cosine", | ||||
|                     "unit": "deg", | ||||
|                     "formatString": "%0.2f", | ||||
|                     "hints": { | ||||
|                         "range": 2, | ||||
|                         "priority": 5 | ||||
|                     }, | ||||
|                     "source": "cos" | ||||
|                 } | ||||
|             ]; | ||||
|         }, | ||||
|         values: [ | ||||
|             { | ||||
|                 "key": "name", | ||||
|                 "name": "Name", | ||||
|                 "format": "string", | ||||
|                 "source": "name", | ||||
|                 "hints": { | ||||
|                     "priority": 0 | ||||
|                 } | ||||
|             }, | ||||
|             { | ||||
|                 "key": "utc", | ||||
|                 "name": "Time", | ||||
|                 "format": "utc", | ||||
|                 "hints": { | ||||
|                     "domain": 1, | ||||
|                     "priority": 1 | ||||
|                 }, | ||||
|                 "source": "utc" | ||||
|             }, | ||||
|             { | ||||
|                 "key": "yesterday", | ||||
|                 "name": "Yesterday", | ||||
|                 "format": "utc", | ||||
|                 "hints": { | ||||
|                     "domain": 2, | ||||
|                     "priority": 2 | ||||
|                 }, | ||||
|                 "source": "yesterday" | ||||
|             }, | ||||
|             { | ||||
|                 "key": "cos", | ||||
|                 "name": "Cosine", | ||||
|                 "unit": "deg", | ||||
|                 "formatString": "%0.2f", | ||||
|                 "hints": { | ||||
|                     "domain": 3, | ||||
|                     "priority": 3 | ||||
|                 }, | ||||
|                 "source": "cos" | ||||
|             }, | ||||
|             { | ||||
|                 "key": "sin", | ||||
|                 "name": "Sine", | ||||
|                 "unit": "Hz", | ||||
|                 "formatString": "%0.2f", | ||||
|                 "hints": { | ||||
|                     "range": 1, | ||||
|                     "spectralAttribute": true | ||||
|                 }, | ||||
|                 "source": "sin" | ||||
|             }, | ||||
|             { | ||||
|                 "key": "cos", | ||||
|                 "name": "Cosine", | ||||
|                 "unit": "deg", | ||||
|                 "formatString": "%0.2f", | ||||
|                 "hints": { | ||||
|                     "range": 2, | ||||
|                     "priority": 5 | ||||
|                 }, | ||||
|                 "source": "cos" | ||||
|             } | ||||
|         ] | ||||
|     }; | ||||
|  | ||||
|     beforeEach(() => { | ||||
|         openmct = createOpenMct(); | ||||
|         const mockTypeDef = { | ||||
|             telemetry: mockGoodSpectralMetaData | ||||
|         }; | ||||
|         const mockTypeService = { | ||||
|             getType: () => { | ||||
|                 return { | ||||
|                     typeDef: mockTypeDef | ||||
|                 }; | ||||
|             } | ||||
|         }; | ||||
|         openmct.$injector = { | ||||
|             get: () => { | ||||
|                 return mockTypeService; | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         openmct.telemetry.isTelemetryObject = function (domainObject) { | ||||
|             return true; | ||||
|         }; | ||||
|     }); | ||||
|  | ||||
|     it("exists", () => { | ||||
|         expect(SpectralAggregatePlotCompositionPolicy(openmct).allow).toBeDefined(); | ||||
|     }); | ||||
|  | ||||
|     it("allow composition only for telemetry that provides/supports spectral data", () => { | ||||
|         const parent = { | ||||
|             "composition": [], | ||||
|             "configuration": {}, | ||||
|             "name": "Some Spectral Aggregate Plot", | ||||
|             "type": "telemetry.plot.spectral.aggregate", | ||||
|             "location": "mine", | ||||
|             "modified": 1631005183584, | ||||
|             "persisted": 1631005183502, | ||||
|             "identifier": { | ||||
|                 "namespace": "", | ||||
|                 "key": "b78e7e23-f2b8-4776-b1f0-3ff778f5c8a9" | ||||
|             } | ||||
|         }; | ||||
|         const child = { | ||||
|             "telemetry": { | ||||
|                 "period": 10, | ||||
|                 "amplitude": 1, | ||||
|                 "offset": 0, | ||||
|                 "dataRateInHz": 1, | ||||
|                 "phase": 0, | ||||
|                 "randomness": 0 | ||||
|             }, | ||||
|             "name": "Unnamed Sine Wave Generator", | ||||
|             "type": "generator", | ||||
|             "location": "mine", | ||||
|             "modified": 1630399715531, | ||||
|             "persisted": 1630399715531, | ||||
|             "identifier": { | ||||
|                 "namespace": "", | ||||
|                 "key": "21d61f2d-6d2d-4bea-8b0a-7f59fd504c6c" | ||||
|             } | ||||
|         }; | ||||
|         expect(SpectralAggregatePlotCompositionPolicy(openmct).allow(parent, child)).toEqual(true); | ||||
|     }); | ||||
|  | ||||
|     it("disallows composition for telemetry that contain anything else", () => { | ||||
|         const mockTypeDef = { | ||||
|             telemetry: mockNonSpectralMetaData | ||||
|         }; | ||||
|         const mockTypeService = { | ||||
|             getType: () => { | ||||
|                 return { | ||||
|                     typeDef: mockTypeDef | ||||
|                 }; | ||||
|             } | ||||
|         }; | ||||
|         openmct.$injector = { | ||||
|             get: () => { | ||||
|                 return mockTypeService; | ||||
|             } | ||||
|         }; | ||||
|         const parent = { | ||||
|             "composition": [], | ||||
|             "configuration": {}, | ||||
|             "name": "Some Spectral Aggregate Plot", | ||||
|             "type": "telemetry.plot.spectral.aggregate", | ||||
|             "location": "mine", | ||||
|             "modified": 1631005183584, | ||||
|             "persisted": 1631005183502, | ||||
|             "identifier": { | ||||
|                 "namespace": "", | ||||
|                 "key": "b78e7e23-f2b8-4776-b1f0-3ff778f5c8a9" | ||||
|             } | ||||
|         }; | ||||
|         const child = { | ||||
|             "telemetry": { | ||||
|                 "period": 10, | ||||
|                 "amplitude": 1, | ||||
|                 "offset": 0, | ||||
|                 "dataRateInHz": 1, | ||||
|                 "phase": 0, | ||||
|                 "randomness": 0 | ||||
|             }, | ||||
|             "name": "Unnamed Sine Wave Generator", | ||||
|             "type": "generator", | ||||
|             "location": "mine", | ||||
|             "modified": 1630399715531, | ||||
|             "persisted": 1630399715531, | ||||
|             "identifier": { | ||||
|                 "namespace": "", | ||||
|                 "key": "21d61f2d-6d2d-4bea-8b0a-7f59fd504c6c" | ||||
|             } | ||||
|         }; | ||||
|         expect(SpectralAggregatePlotCompositionPolicy(openmct).allow(parent, child)).toEqual(false); | ||||
|     }); | ||||
|  | ||||
|     it("passthrough for composition for non spectral aggregate plots", () => { | ||||
|         const parent = { | ||||
|             "composition": [], | ||||
|             "configuration": {}, | ||||
|             "name": "Some Stacked Plot", | ||||
|             "type": "telemetry.plot.stacked", | ||||
|             "location": "mine", | ||||
|             "modified": 1631005183584, | ||||
|             "persisted": 1631005183502, | ||||
|             "identifier": { | ||||
|                 "namespace": "", | ||||
|                 "key": "b78e7e23-f2b8-4776-b1f0-3ff778f5c8a9" | ||||
|             } | ||||
|         }; | ||||
|         const child = { | ||||
|             "telemetry": { | ||||
|                 "period": 10, | ||||
|                 "amplitude": 1, | ||||
|                 "offset": 0, | ||||
|                 "dataRateInHz": 1, | ||||
|                 "phase": 0, | ||||
|                 "randomness": 0 | ||||
|             }, | ||||
|             "name": "Unnamed Sine Wave Generator", | ||||
|             "type": "generator", | ||||
|             "location": "mine", | ||||
|             "modified": 1630399715531, | ||||
|             "persisted": 1630399715531, | ||||
|             "identifier": { | ||||
|                 "namespace": "", | ||||
|                 "key": "21d61f2d-6d2d-4bea-8b0a-7f59fd504c6c" | ||||
|             } | ||||
|         }; | ||||
|         expect(SpectralAggregatePlotCompositionPolicy(openmct).allow(parent, child)).toEqual(true); | ||||
|     }); | ||||
| }); | ||||
|  | ||||
| @@ -0,0 +1,76 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2021, 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| import SpectralAggregateView from './SpectralAggregateView.vue'; | ||||
| import { SPECTRAL_AGGREGATE_KEY, SPECTRAL_AGGREGATE_VIEW } from './SpectralAggregateConstants'; | ||||
| import Vue from 'vue'; | ||||
|  | ||||
| export default function SpectralAggregatePlotViewProvider(openmct) { | ||||
|     function isCompactView(objectPath) { | ||||
|         return objectPath.find(object => object.type === 'time-strip'); | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         key: SPECTRAL_AGGREGATE_VIEW, | ||||
|         name: 'Spectral Aggregate Plot', | ||||
|         cssClass: 'icon-telemetry', | ||||
|         canView(domainObject, objectPath) { | ||||
|             return domainObject && domainObject.type === SPECTRAL_AGGREGATE_KEY; | ||||
|         }, | ||||
|  | ||||
|         canEdit(domainObject, objectPath) { | ||||
|             return domainObject && domainObject.type === SPECTRAL_AGGREGATE_KEY; | ||||
|         }, | ||||
|  | ||||
|         view: function (domainObject, objectPath) { | ||||
|             let component; | ||||
|  | ||||
|             return { | ||||
|                 show: function (element) { | ||||
|                     let isCompact = isCompactView(objectPath); | ||||
|                     component = new Vue({ | ||||
|                         el: element, | ||||
|                         components: { | ||||
|                             SpectralAggregateView | ||||
|                         }, | ||||
|                         provide: { | ||||
|                             openmct, | ||||
|                             domainObject | ||||
|                         }, | ||||
|                         data() { | ||||
|                             return { | ||||
|                                 options: { | ||||
|                                     compact: isCompact | ||||
|                                 } | ||||
|                             }; | ||||
|                         }, | ||||
|                         template: '<spectral-aggregate-view :options="options"></spectral-aggregate-view>' | ||||
|                     }); | ||||
|                 }, | ||||
|                 destroy: function () { | ||||
|                     component.$destroy(); | ||||
|                     component = undefined; | ||||
|                 } | ||||
|             }; | ||||
|         } | ||||
|     }; | ||||
| } | ||||
							
								
								
									
										332
									
								
								src/plugins/plot/spectralAggregatePlot/SpectralAggregateView.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										332
									
								
								src/plugins/plot/spectralAggregatePlot/SpectralAggregateView.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,332 @@ | ||||
| <!-- | ||||
|  Open MCT, Copyright (c) 2014-2021, 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. | ||||
| --> | ||||
|  | ||||
| <template> | ||||
| <div class="c-spectral-aggregate-plot-view gl-plot plot-legend-bottom" | ||||
|      :class="{'plot-legend-expanded': legendExpanded, 'plot-legend-collapsed': !legendExpanded }" | ||||
| > | ||||
|     <SpectralAggregatePlot ref="spectralAggregatePlot" | ||||
|                            class="c-spectral-aggregate-plot__plot-wrapper" | ||||
|                            :data="visibleData" | ||||
|                            :plot-axis-title="plotAxisTitle" | ||||
|                            :legend-expanded="legendExpanded" | ||||
|     /> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import * as SPECTRAL_AGGREGATE from './SpectralAggregateConstants'; | ||||
| import ColorPalette from '../lib/ColorPalette'; | ||||
| import objectUtils from 'objectUtils'; | ||||
| import SpectralAggregatePlot from './SpectralAggregatePlot.vue'; | ||||
|  | ||||
| export default { | ||||
|     components: { | ||||
|         SpectralAggregatePlot | ||||
|     }, | ||||
|     inject: ['openmct', 'domainObject'], | ||||
|     data() { | ||||
|         return { | ||||
|             colorMapping: {}, | ||||
|             composition: {}, | ||||
|             currentDomainObject: this.domainObject, | ||||
|             isRealTime: (this.openmct.time.clock() !== undefined), | ||||
|             spectralAggregateTypes: {}, | ||||
|             subscriptions: [], | ||||
|             telemetryObjects: {}, | ||||
|             trace: [], | ||||
|             legendExpanded: false | ||||
|         }; | ||||
|     }, | ||||
|     computed: { | ||||
|         activeClock() { | ||||
|             return this.openmct.time.activeClock; | ||||
|         }, | ||||
|         plotAxisTitle() { | ||||
|             const { xAxisMetadata = {}, yAxisMetadata = {} } = this.trace[0] || {}; | ||||
|             const xAxisUnit = xAxisMetadata.units ? `(${xAxisMetadata.units})` : ''; | ||||
|             const yAxisUnit = yAxisMetadata.units ? `(${yAxisMetadata.units})` : ''; | ||||
|  | ||||
|             return { | ||||
|                 xAxisTitle: `${xAxisMetadata.name || ''} ${xAxisUnit}`, | ||||
|                 yAxisTitle: `${yAxisMetadata.name || ''} ${yAxisUnit}` | ||||
|             }; | ||||
|         }, | ||||
|         visibleData() { | ||||
|             return this.trace.filter((trace) => trace.hidden !== true); | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.colorPalette = new ColorPalette(); | ||||
|         this.loadComposition(); | ||||
|  | ||||
|         this.openmct.time.on('bounds', this.refreshData); | ||||
|         this.openmct.time.on('clock', this.clockChanged); | ||||
|  | ||||
|         this.$refs.spectralAggregatePlot.$on(SPECTRAL_AGGREGATE.SUBSCRIBE, this.subscribeToAll); | ||||
|         this.$refs.spectralAggregatePlot.$on(SPECTRAL_AGGREGATE.UNSUBSCRIBE, this.removeAllSubscriptions); | ||||
|  | ||||
|         this.unobserve = this.openmct.objects.observe(this.currentDomainObject, '*', this.updateDomainObject); | ||||
|     }, | ||||
|     beforeDestroy() { | ||||
|         this.$refs.spectralAggregatePlot.$off(); | ||||
|         this.openmct.time.off('bounds', this.refreshData); | ||||
|         this.openmct.time.off('clock', this.clockChanged); | ||||
|  | ||||
|         this.removeAllSubscriptions(); | ||||
|         this.unobserve(); | ||||
|  | ||||
|         if (!this.composition) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         this.composition.off('add', this.addTelemetryObject); | ||||
|         this.composition.off('remove', this.removeTelemetryObject); | ||||
|     }, | ||||
|     methods: { | ||||
|         addColorForTelemetry(key) { | ||||
|             const color = this.colorPalette.getNextColor().asHexString(); | ||||
|             this.colorMapping[key] = color; | ||||
|  | ||||
|             return color; | ||||
|         }, | ||||
|         addSpectralAggregateType(key, name, timestamp, color) { | ||||
|             this.$set(this.spectralAggregateTypes, key, { | ||||
|                 name, | ||||
|                 timestamp, | ||||
|                 color | ||||
|             }); | ||||
|         }, | ||||
|         addTelemetryObject(telemetryObject) { | ||||
|             const key = objectUtils.makeKeyString(telemetryObject.identifier); | ||||
|  | ||||
|             if (!this.colorMapping[key]) { | ||||
|                 this.addColorForTelemetry(key); | ||||
|             } | ||||
|  | ||||
|             this.telemetryObjects[key] = telemetryObject; | ||||
|  | ||||
|             this.requestDataFor(telemetryObject); | ||||
|             this.subscribeToObject(telemetryObject); | ||||
|         }, | ||||
|         addTrace(trace, key) { | ||||
|             if (!this.trace.length) { | ||||
|                 this.trace = this.trace.concat([trace]); | ||||
|  | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             let isInTrace = false; | ||||
|             const newTrace = this.trace.map((currentTrace, index) => { | ||||
|                 if (currentTrace.key !== key) { | ||||
|                     return currentTrace; | ||||
|                 } | ||||
|  | ||||
|                 isInTrace = true; | ||||
|  | ||||
|                 return trace; | ||||
|             }); | ||||
|  | ||||
|             this.trace = isInTrace ? newTrace : newTrace.concat([trace]); | ||||
|             this.updateTraceVisibility(); | ||||
|         }, | ||||
|         clockChanged() { | ||||
|             this.isRealTime = this.openmct.time.clock() !== undefined; | ||||
|  | ||||
|             this.removeAllSubscriptions(); | ||||
|             this.subscribeToAll(); | ||||
|         }, | ||||
|         getAxisMetadata(telemetryObject) { | ||||
|             const metadata = this.openmct.telemetry.getMetadata(telemetryObject); | ||||
|             const yAxisMetadata = metadata.valuesForHints(['range'])[0]; | ||||
|             const xAxisMetadata = metadata.valueMetadatas.filter((valueMetadata => { | ||||
|                 return valueMetadata.key !== 'name' && !this.openmct.time.getAllTimeSystems().find((timeSystem) => timeSystem.key === valueMetadata.key); | ||||
|             })); | ||||
|  | ||||
|             return { | ||||
|                 xAxisMetadata, | ||||
|                 yAxisMetadata | ||||
|             }; | ||||
|         }, | ||||
|         getOptions(telemetryObject) { | ||||
|             const { start, end } = this.openmct.time.bounds(); | ||||
|  | ||||
|             return { | ||||
|                 averages: 0, | ||||
|                 end, | ||||
|                 start, | ||||
|                 startTime: null, | ||||
|                 spectra: true | ||||
|             }; | ||||
|         }, | ||||
|         loadComposition() { | ||||
|             this.composition = this.openmct.composition.get(this.currentDomainObject); | ||||
|  | ||||
|             if (!this.composition) { | ||||
|                 this.addTelemetryObject(this.currentDomainObject); | ||||
|  | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             this.composition.on('add', this.addTelemetryObject); | ||||
|             this.composition.on('remove', this.removeTelemetryObject); | ||||
|             this.composition.load(); | ||||
|         }, | ||||
|         refreshData(bounds, isTick) { | ||||
|             if (!isTick) { | ||||
|                 this.colorPalette.reset(); | ||||
|                 const telemetryObjects = Object.values(this.telemetryObjects); | ||||
|                 telemetryObjects.forEach(this.requestDataFor); | ||||
|             } | ||||
|         }, | ||||
|         removeAllSubscriptions() { | ||||
|             this.subscriptions.forEach(subscription => subscription.unsubscribe()); | ||||
|             this.subscriptions = []; | ||||
|         }, | ||||
|         removeTelemetryObject(identifier) { | ||||
|             const key = objectUtils.makeKeyString(identifier); | ||||
|             delete this.telemetryObjects[key]; | ||||
|             this.$delete(this.spectralAggregateTypes, key); | ||||
|  | ||||
|             this.subscriptions.forEach(subscription => { | ||||
|                 if (subscription.key !== key) { | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                 subscription.unsubscribe(); | ||||
|                 delete this.subscriptions[key]; | ||||
|             }); | ||||
|  | ||||
|             this.trace = this.trace.filter(t => t.key !== key); | ||||
|         }, | ||||
|         processData(telemetryObject, data, axisMetadata) { | ||||
|             const key = objectUtils.makeKeyString(telemetryObject.identifier); | ||||
|  | ||||
|             const formattedTimestamp = 'N/A'; | ||||
|  | ||||
|             const color = this.colorMapping[key]; | ||||
|             const spectralAggregateValue = this.spectralAggregateTypes[key]; | ||||
|             if (!spectralAggregateValue) { | ||||
|                 this.addSpectralAggregateType(key, telemetryObject.name, formattedTimestamp, color); | ||||
|             } | ||||
|  | ||||
|             if (data.message) { | ||||
|                 this.openmct.notifications.alert(data.message); | ||||
|             } | ||||
|  | ||||
|             let xValues = []; | ||||
|             let yValues = []; | ||||
|             axisMetadata.xAxisMetadata.forEach((metadata) => { | ||||
|                 xValues.push(metadata.name); | ||||
|                 if (data[metadata.key]) { | ||||
|                     yValues.push(data[metadata.key]); | ||||
|                 } else { | ||||
|                     yValues.push(''); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|             const trace = { | ||||
|                 key, | ||||
|                 name: telemetryObject.name, | ||||
|                 x: xValues, | ||||
|                 y: yValues, | ||||
|                 xAxisMetadata: axisMetadata.xAxisMetadata, | ||||
|                 yAxisMetadata: axisMetadata.yAxisMetadata, | ||||
|                 type: 'bar' | ||||
|             }; | ||||
|  | ||||
|             this.addTrace(trace, key); | ||||
|         }, | ||||
|         requestDataFor(telemetryObject) { | ||||
|             const axisMetadata = this.getAxisMetadata(telemetryObject); | ||||
|             this.openmct.telemetry.request(telemetryObject, this.getOptions(telemetryObject)) | ||||
|                 .then(data => { | ||||
|                     data.forEach((datum) => { | ||||
|                         this.processData(telemetryObject, datum, axisMetadata); | ||||
|                     }); | ||||
|                 }); | ||||
|         }, | ||||
|         subscribeToObject(telemetryObject) { | ||||
|             const key = objectUtils.makeKeyString(telemetryObject.identifier); | ||||
|             const found = Object.values(this.subscriptions).findIndex(objectKey => objectKey === key); | ||||
|             if (found > -1) { | ||||
|                 this.subscriptions[found].unsubscribe(); | ||||
|                 delete this.subscriptions[found]; | ||||
|             } | ||||
|  | ||||
|             const options = this.getOptions(telemetryObject); | ||||
|             const axisMetadata = this.getAxisMetadata(telemetryObject); | ||||
|             const unsubscribe = this.openmct.telemetry.subscribe(telemetryObject, | ||||
|                 data => this.processData(telemetryObject, data, axisMetadata) | ||||
|                 , options); | ||||
|  | ||||
|             this.subscriptions.push({ | ||||
|                 key, | ||||
|                 unsubscribe | ||||
|             }); | ||||
|         }, | ||||
|         subscribeToAll() { | ||||
|             this.colorPalette.reset(); | ||||
|             const telemetryObjects = Object.values(this.telemetryObjects); | ||||
|             telemetryObjects.forEach(this.subscribeToObject); | ||||
|         }, | ||||
|         updateDomainObject(newDomainObject) { | ||||
|             this.currentDomainObject = newDomainObject; | ||||
|         }, | ||||
|         updateTraceVisibility() { | ||||
|             // We create a copy here to improve performance since visibleData - a computed property - is dependent on this.trace. | ||||
|             this.trace = this.trace.map((currentTrace, index) => { | ||||
|                 currentTrace.hidden = this.spectralAggregateTypes[currentTrace.key].hidden === true; | ||||
|  | ||||
|                 return currentTrace; | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
|  | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
|     .c-spectral-aggregate-plot { | ||||
|         > * + * { | ||||
|             margin-top: 5px; | ||||
|         } | ||||
|  | ||||
|         &-view { | ||||
|             display: flex; | ||||
|             flex-direction: column; | ||||
|             overflow: hidden; | ||||
|         } | ||||
|  | ||||
|         &__plot-wrapper { | ||||
|             flex: 1 1 auto; | ||||
|             min-height: 300px; | ||||
|             min-width: 300px; | ||||
|         } | ||||
|  | ||||
|         &__legend-wrapper { | ||||
|             flex: 0 1 auto; | ||||
|             overflow: auto; | ||||
|             padding-right: 5px; | ||||
|         } | ||||
|     } | ||||
| </style> | ||||
| @@ -0,0 +1,36 @@ | ||||
| export default function SpectralPlotCompositionPolicy(openmct) { | ||||
|     function hasSpectralDomainAndRange(metadata) { | ||||
|         const rangeValues = metadata.valuesForHints(['range']); | ||||
|         const domainValues = metadata.valuesForHints(['domain']); | ||||
|         const containsSomeSpectralData = domainValues.some(value => { | ||||
|             return ((value.key === 'wavelength') || (value.key === 'frequency')); | ||||
|         }); | ||||
|  | ||||
|         return rangeValues.length > 0 | ||||
|         && domainValues.length > 0 | ||||
|         && containsSomeSpectralData; | ||||
|     } | ||||
|  | ||||
|     function hasSpectralTelemetry(domainObject) { | ||||
|         if (!Object.prototype.hasOwnProperty.call(domainObject, 'telemetry')) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         let metadata = openmct.telemetry.getMetadata(domainObject); | ||||
|  | ||||
|         return metadata.values().length > 0 && hasSpectralDomainAndRange(metadata); | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         allow: function (parent, child) { | ||||
|  | ||||
|             if ((parent.type === 'telemetry.plot.spectral') | ||||
|                 && ((child.type !== 'telemetry.plot.overlay') && (hasSpectralTelemetry(child) === false)) | ||||
|             ) { | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             return true; | ||||
|         } | ||||
|     }; | ||||
| } | ||||
							
								
								
									
										75
									
								
								src/plugins/plot/spectralPlot/SpectralPlotViewProvider.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/plugins/plot/spectralPlot/SpectralPlotViewProvider.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2021, 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| import SpectralView from './SpectralView.vue'; | ||||
| import Vue from 'vue'; | ||||
|  | ||||
| export default function SpectralPlotViewProvider(openmct) { | ||||
|     function isCompactView(objectPath) { | ||||
|         return objectPath.find(object => object.type === 'time-strip'); | ||||
|     } | ||||
|  | ||||
|     return { | ||||
|         key: 'plot-spectral', | ||||
|         name: 'Spectral Plot', | ||||
|         cssClass: 'icon-telemetry', | ||||
|         canView(domainObject, objectPath) { | ||||
|             return domainObject && domainObject.type === 'telemetry.plot.spectral'; | ||||
|         }, | ||||
|  | ||||
|         canEdit(domainObject, objectPath) { | ||||
|             return domainObject && domainObject.type === 'telemetry.plot.spectral'; | ||||
|         }, | ||||
|  | ||||
|         view: function (domainObject, objectPath) { | ||||
|             let component; | ||||
|  | ||||
|             return { | ||||
|                 show: function (element) { | ||||
|                     let isCompact = isCompactView(objectPath); | ||||
|                     component = new Vue({ | ||||
|                         el: element, | ||||
|                         components: { | ||||
|                             SpectralView | ||||
|                         }, | ||||
|                         provide: { | ||||
|                             openmct, | ||||
|                             domainObject | ||||
|                         }, | ||||
|                         data() { | ||||
|                             return { | ||||
|                                 options: { | ||||
|                                     compact: isCompact | ||||
|                                 } | ||||
|                             }; | ||||
|                         }, | ||||
|                         template: '<spectral-view :options="options"></spectral-view>' | ||||
|                     }); | ||||
|                 }, | ||||
|                 destroy: function () { | ||||
|                     component.$destroy(); | ||||
|                     component = undefined; | ||||
|                 } | ||||
|             }; | ||||
|         } | ||||
|     }; | ||||
| } | ||||
							
								
								
									
										13
									
								
								src/plugins/plot/spectralPlot/SpectralView.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/plugins/plot/spectralPlot/SpectralView.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| <template> | ||||
| <div> | ||||
|  | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|  | ||||
| export default { | ||||
|     inject: ['openmct', 'domainObject'] | ||||
| }; | ||||
|  | ||||
| </script> | ||||
| @@ -154,6 +154,7 @@ $glyph-icon-flag: '\e92a'; | ||||
| $glyph-icon-eye-disabled: '\e92b'; | ||||
| $glyph-icon-notebook-page: '\e92c'; | ||||
| $glyph-icon-unlocked: '\e92d'; | ||||
| $glyph-icon-circle: '\e92e'; | ||||
| $glyph-icon-arrows-right-left: '\ea00'; | ||||
| $glyph-icon-arrows-up-down: '\ea01'; | ||||
| $glyph-icon-bullet: '\ea02'; | ||||
| @@ -257,6 +258,7 @@ $glyph-icon-conditional: '\eb27'; | ||||
| $glyph-icon-condition-widget: '\eb28'; | ||||
| $glyph-icon-alphanumeric: '\eb29'; | ||||
| $glyph-icon-image-telemetry: '\eb2a'; | ||||
| $glyph-icon-telemetry-aggregate: '\eb2b'; | ||||
|  | ||||
| /************************** GLYPHS AS DATA URI */ | ||||
| // Only objects have been converted, for use in Create menu and folder views | ||||
|   | ||||
| @@ -85,6 +85,7 @@ | ||||
| .icon-eye-disabled {  @include glyphBefore($glyph-icon-eye-disabled); } | ||||
| .icon-notebook-page {  @include glyphBefore($glyph-icon-notebook-page); } | ||||
| .icon-unlocked {  @include glyphBefore($glyph-icon-unlocked); } | ||||
| .icon-circle {  @include glyphBefore($glyph-icon-circle); } | ||||
| .icon-arrows-right-left {  @include glyphBefore($glyph-icon-arrows-right-left); } | ||||
| .icon-arrows-up-down {  @include glyphBefore($glyph-icon-arrows-up-down); } | ||||
| .icon-bullet {  @include glyphBefore($glyph-icon-bullet); } | ||||
| @@ -188,6 +189,7 @@ | ||||
| .icon-condition-widget {  @include glyphBefore($glyph-icon-condition-widget); } | ||||
| .icon-alphanumeric {  @include glyphBefore($glyph-icon-alphanumeric); } | ||||
| .icon-image-telemetry {  @include glyphBefore($glyph-icon-image-telemetry); } | ||||
| .icon-telemetry-aggregate {  @include glyphBefore($glyph-icon-telemetry-aggregate); } | ||||
|  | ||||
| /************************** 12 PX CLASSES */ | ||||
| // TODO: sync with 16px redo as of 10/25/18 | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|   "metadata": { | ||||
|     "name": "Open MCT Symbols 16px", | ||||
|     "lastOpened": 0, | ||||
|     "created": 1621648023886 | ||||
|     "created": 1629996145999 | ||||
|   }, | ||||
|   "iconSets": [ | ||||
|     { | ||||
| @@ -375,13 +375,21 @@ | ||||
|           "code": 59693, | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 197, | ||||
|           "id": 169, | ||||
|           "name": "icon-circle", | ||||
|           "prevSize": 24, | ||||
|           "code": 59694, | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 27, | ||||
|           "id": 105, | ||||
|           "name": "icon-arrows-right-left", | ||||
|           "prevSize": 24, | ||||
|           "code": 59904, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 26, | ||||
| @@ -389,7 +397,7 @@ | ||||
|           "name": "icon-arrows-up-down", | ||||
|           "prevSize": 24, | ||||
|           "code": 59905, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 68, | ||||
| @@ -397,7 +405,7 @@ | ||||
|           "name": "icon-bullet", | ||||
|           "prevSize": 24, | ||||
|           "code": 59906, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 150, | ||||
| @@ -405,7 +413,7 @@ | ||||
|           "prevSize": 24, | ||||
|           "code": 59907, | ||||
|           "name": "icon-calendar", | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 45, | ||||
| @@ -413,7 +421,7 @@ | ||||
|           "name": "icon-chain-links", | ||||
|           "prevSize": 24, | ||||
|           "code": 59908, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 73, | ||||
| @@ -421,7 +429,7 @@ | ||||
|           "name": "icon-download", | ||||
|           "prevSize": 24, | ||||
|           "code": 59909, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 39, | ||||
| @@ -429,7 +437,7 @@ | ||||
|           "name": "icon-duplicate", | ||||
|           "prevSize": 24, | ||||
|           "code": 59910, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 50, | ||||
| @@ -437,7 +445,7 @@ | ||||
|           "name": "icon-folder-new", | ||||
|           "prevSize": 24, | ||||
|           "code": 59911, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 138, | ||||
| @@ -445,7 +453,7 @@ | ||||
|           "name": "icon-fullscreen-collapse", | ||||
|           "prevSize": 24, | ||||
|           "code": 59912, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 139, | ||||
| @@ -453,7 +461,7 @@ | ||||
|           "name": "icon-fullscreen-expand", | ||||
|           "prevSize": 24, | ||||
|           "code": 59913, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 122, | ||||
| @@ -461,7 +469,7 @@ | ||||
|           "name": "icon-layers", | ||||
|           "prevSize": 24, | ||||
|           "code": 59914, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 151, | ||||
| @@ -469,7 +477,7 @@ | ||||
|           "name": "icon-line-horz", | ||||
|           "prevSize": 24, | ||||
|           "code": 59915, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 100, | ||||
| @@ -477,7 +485,7 @@ | ||||
|           "name": "icon-magnify", | ||||
|           "prevSize": 24, | ||||
|           "code": 59916, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 99, | ||||
| @@ -485,7 +493,7 @@ | ||||
|           "name": "icon-magnify-in", | ||||
|           "prevSize": 24, | ||||
|           "code": 59917, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 101, | ||||
| @@ -493,7 +501,7 @@ | ||||
|           "name": "icon-magnify-out-v2", | ||||
|           "prevSize": 24, | ||||
|           "code": 59918, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 103, | ||||
| @@ -501,7 +509,7 @@ | ||||
|           "name": "icon-menu", | ||||
|           "prevSize": 24, | ||||
|           "code": 59919, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 124, | ||||
| @@ -509,7 +517,7 @@ | ||||
|           "name": "icon-move", | ||||
|           "prevSize": 24, | ||||
|           "code": 59920, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 7, | ||||
| @@ -517,7 +525,7 @@ | ||||
|           "name": "icon-new-window", | ||||
|           "prevSize": 24, | ||||
|           "code": 59921, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 63, | ||||
| @@ -525,7 +533,7 @@ | ||||
|           "name": "icon-paint-bucket-v2", | ||||
|           "prevSize": 24, | ||||
|           "code": 59922, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 15, | ||||
| @@ -533,7 +541,7 @@ | ||||
|           "name": "icon-pencil", | ||||
|           "prevSize": 24, | ||||
|           "code": 59923, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 54, | ||||
| @@ -541,7 +549,7 @@ | ||||
|           "name": "icon-pencil-edit-in-place", | ||||
|           "prevSize": 24, | ||||
|           "code": 59924, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 40, | ||||
| @@ -549,7 +557,7 @@ | ||||
|           "name": "icon-play", | ||||
|           "prevSize": 24, | ||||
|           "code": 59925, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 125, | ||||
| @@ -557,7 +565,7 @@ | ||||
|           "name": "icon-pause", | ||||
|           "prevSize": 24, | ||||
|           "code": 59926, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 119, | ||||
| @@ -565,7 +573,7 @@ | ||||
|           "name": "icon-plot-resource", | ||||
|           "prevSize": 24, | ||||
|           "code": 59927, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 48, | ||||
| @@ -573,7 +581,7 @@ | ||||
|           "name": "icon-pointer-left", | ||||
|           "prevSize": 24, | ||||
|           "code": 59928, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 47, | ||||
| @@ -581,7 +589,7 @@ | ||||
|           "name": "icon-pointer-right", | ||||
|           "prevSize": 24, | ||||
|           "code": 59929, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 85, | ||||
| @@ -589,7 +597,7 @@ | ||||
|           "name": "icon-refresh", | ||||
|           "prevSize": 24, | ||||
|           "code": 59930, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 55, | ||||
| @@ -597,7 +605,7 @@ | ||||
|           "name": "icon-save", | ||||
|           "prevSize": 24, | ||||
|           "code": 59931, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 56, | ||||
| @@ -605,7 +613,7 @@ | ||||
|           "name": "icon-save-as", | ||||
|           "prevSize": 24, | ||||
|           "code": 59932, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 58, | ||||
| @@ -613,7 +621,7 @@ | ||||
|           "name": "icon-sine", | ||||
|           "prevSize": 24, | ||||
|           "code": 59933, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 113, | ||||
| @@ -621,7 +629,7 @@ | ||||
|           "name": "icon-font", | ||||
|           "prevSize": 24, | ||||
|           "code": 59934, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 41, | ||||
| @@ -629,7 +637,7 @@ | ||||
|           "name": "icon-thumbs-strip", | ||||
|           "prevSize": 24, | ||||
|           "code": 59935, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 146, | ||||
| @@ -637,7 +645,7 @@ | ||||
|           "name": "icon-two-parts-both", | ||||
|           "prevSize": 24, | ||||
|           "code": 59936, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 145, | ||||
| @@ -645,7 +653,7 @@ | ||||
|           "name": "icon-two-parts-one-only", | ||||
|           "prevSize": 24, | ||||
|           "code": 59937, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 82, | ||||
| @@ -653,7 +661,7 @@ | ||||
|           "name": "icon-resync", | ||||
|           "prevSize": 24, | ||||
|           "code": 59938, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 86, | ||||
| @@ -661,7 +669,7 @@ | ||||
|           "name": "icon-reset", | ||||
|           "prevSize": 24, | ||||
|           "code": 59939, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 61, | ||||
| @@ -669,7 +677,7 @@ | ||||
|           "name": "icon-x-in-circle", | ||||
|           "prevSize": 24, | ||||
|           "code": 59940, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 84, | ||||
| @@ -677,7 +685,7 @@ | ||||
|           "name": "icon-brightness", | ||||
|           "prevSize": 24, | ||||
|           "code": 59941, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 83, | ||||
| @@ -685,7 +693,7 @@ | ||||
|           "name": "icon-contrast", | ||||
|           "prevSize": 24, | ||||
|           "code": 59942, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 87, | ||||
| @@ -693,7 +701,7 @@ | ||||
|           "name": "icon-expand", | ||||
|           "prevSize": 24, | ||||
|           "code": 59943, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 89, | ||||
| @@ -701,7 +709,7 @@ | ||||
|           "name": "icon-list-view", | ||||
|           "prevSize": 24, | ||||
|           "code": 59944, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 133, | ||||
| @@ -709,7 +717,7 @@ | ||||
|           "name": "icon-grid-snap-to", | ||||
|           "prevSize": 24, | ||||
|           "code": 59945, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 132, | ||||
| @@ -717,7 +725,7 @@ | ||||
|           "name": "icon-grid-snap-no", | ||||
|           "prevSize": 24, | ||||
|           "code": 59946, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 94, | ||||
| @@ -725,7 +733,7 @@ | ||||
|           "name": "icon-frame-show", | ||||
|           "prevSize": 24, | ||||
|           "code": 59947, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 95, | ||||
| @@ -733,7 +741,7 @@ | ||||
|           "name": "icon-frame-hide", | ||||
|           "prevSize": 24, | ||||
|           "code": 59948, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 97, | ||||
| @@ -741,7 +749,7 @@ | ||||
|           "name": "icon-import", | ||||
|           "prevSize": 24, | ||||
|           "code": 59949, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 96, | ||||
| @@ -749,7 +757,7 @@ | ||||
|           "name": "icon-export", | ||||
|           "prevSize": 24, | ||||
|           "code": 59950, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 194, | ||||
| @@ -757,7 +765,7 @@ | ||||
|           "name": "icon-font-size", | ||||
|           "prevSize": 24, | ||||
|           "code": 59951, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 163, | ||||
| @@ -765,7 +773,7 @@ | ||||
|           "name": "icon-clear-data", | ||||
|           "prevSize": 24, | ||||
|           "code": 59952, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 173, | ||||
| @@ -773,7 +781,7 @@ | ||||
|           "name": "icon-history", | ||||
|           "prevSize": 24, | ||||
|           "code": 59953, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 181, | ||||
| @@ -781,7 +789,7 @@ | ||||
|           "name": "icon-arrow-up-to-parent", | ||||
|           "prevSize": 24, | ||||
|           "code": 59954, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 184, | ||||
| @@ -789,7 +797,7 @@ | ||||
|           "name": "icon-crosshair-in-circle", | ||||
|           "prevSize": 24, | ||||
|           "code": 59955, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 185, | ||||
| @@ -797,7 +805,7 @@ | ||||
|           "name": "icon-target", | ||||
|           "prevSize": 24, | ||||
|           "code": 59956, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 187, | ||||
| @@ -805,7 +813,7 @@ | ||||
|           "name": "icon-items-collapse", | ||||
|           "prevSize": 24, | ||||
|           "code": 59957, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 188, | ||||
| @@ -813,7 +821,7 @@ | ||||
|           "name": "icon-items-expand", | ||||
|           "prevSize": 24, | ||||
|           "code": 59958, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 190, | ||||
| @@ -821,7 +829,7 @@ | ||||
|           "name": "icon-3-dots", | ||||
|           "prevSize": 24, | ||||
|           "code": 59959, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 193, | ||||
| @@ -829,7 +837,7 @@ | ||||
|           "name": "icon-grid-on", | ||||
|           "prevSize": 24, | ||||
|           "code": 59960, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 192, | ||||
| @@ -837,7 +845,7 @@ | ||||
|           "name": "icon-grid-off", | ||||
|           "prevSize": 24, | ||||
|           "code": 59961, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 191, | ||||
| @@ -845,7 +853,7 @@ | ||||
|           "name": "icon-camera", | ||||
|           "prevSize": 24, | ||||
|           "code": 59962, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 196, | ||||
| @@ -853,7 +861,7 @@ | ||||
|           "name": "icon-folders-collapse", | ||||
|           "prevSize": 24, | ||||
|           "code": 59963, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 144, | ||||
| @@ -861,7 +869,7 @@ | ||||
|           "name": "icon-activity", | ||||
|           "prevSize": 24, | ||||
|           "code": 60160, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 104, | ||||
| @@ -869,7 +877,7 @@ | ||||
|           "name": "icon-activity-mode", | ||||
|           "prevSize": 24, | ||||
|           "code": 60161, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 137, | ||||
| @@ -877,7 +885,7 @@ | ||||
|           "name": "icon-autoflow-tabular", | ||||
|           "prevSize": 24, | ||||
|           "code": 60162, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 115, | ||||
| @@ -885,7 +893,7 @@ | ||||
|           "name": "icon-clock", | ||||
|           "prevSize": 24, | ||||
|           "code": 60163, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 2, | ||||
| @@ -893,7 +901,7 @@ | ||||
|           "name": "icon-database", | ||||
|           "prevSize": 24, | ||||
|           "code": 60164, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 3, | ||||
| @@ -901,7 +909,7 @@ | ||||
|           "name": "icon-database-query", | ||||
|           "prevSize": 24, | ||||
|           "code": 60165, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 67, | ||||
| @@ -909,7 +917,7 @@ | ||||
|           "name": "icon-dataset", | ||||
|           "prevSize": 24, | ||||
|           "code": 60166, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 59, | ||||
| @@ -917,7 +925,7 @@ | ||||
|           "name": "icon-datatable", | ||||
|           "prevSize": 24, | ||||
|           "code": 60167, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 136, | ||||
| @@ -925,7 +933,7 @@ | ||||
|           "name": "icon-dictionary", | ||||
|           "prevSize": 24, | ||||
|           "code": 60168, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 51, | ||||
| @@ -933,7 +941,7 @@ | ||||
|           "name": "icon-folder", | ||||
|           "prevSize": 24, | ||||
|           "code": 60169, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 147, | ||||
| @@ -941,7 +949,7 @@ | ||||
|           "name": "icon-image", | ||||
|           "prevSize": 24, | ||||
|           "code": 60170, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 4, | ||||
| @@ -949,7 +957,7 @@ | ||||
|           "name": "icon-layout", | ||||
|           "prevSize": 24, | ||||
|           "code": 60171, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 24, | ||||
| @@ -957,7 +965,7 @@ | ||||
|           "name": "icon-object", | ||||
|           "prevSize": 24, | ||||
|           "code": 60172, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 52, | ||||
| @@ -965,7 +973,7 @@ | ||||
|           "name": "icon-object-unknown", | ||||
|           "prevSize": 24, | ||||
|           "code": 60173, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 105, | ||||
| @@ -973,7 +981,7 @@ | ||||
|           "name": "icon-packet", | ||||
|           "prevSize": 24, | ||||
|           "code": 60174, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 126, | ||||
| @@ -981,7 +989,7 @@ | ||||
|           "name": "icon-page", | ||||
|           "prevSize": 24, | ||||
|           "code": 60175, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 130, | ||||
| @@ -989,7 +997,7 @@ | ||||
|           "name": "icon-plot-overlay", | ||||
|           "prevSize": 24, | ||||
|           "code": 60176, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 80, | ||||
| @@ -997,7 +1005,7 @@ | ||||
|           "name": "icon-plot-stacked", | ||||
|           "prevSize": 24, | ||||
|           "code": 60177, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 134, | ||||
| @@ -1005,7 +1013,7 @@ | ||||
|           "name": "icon-session", | ||||
|           "prevSize": 24, | ||||
|           "code": 60178, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 109, | ||||
| @@ -1013,7 +1021,7 @@ | ||||
|           "name": "icon-tabular", | ||||
|           "prevSize": 24, | ||||
|           "code": 60179, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 107, | ||||
| @@ -1021,7 +1029,7 @@ | ||||
|           "name": "icon-tabular-lad", | ||||
|           "prevSize": 24, | ||||
|           "code": 60180, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 106, | ||||
| @@ -1029,7 +1037,7 @@ | ||||
|           "name": "icon-tabular-lad-set", | ||||
|           "prevSize": 24, | ||||
|           "code": 60181, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 70, | ||||
| @@ -1037,7 +1045,7 @@ | ||||
|           "name": "icon-tabular-realtime", | ||||
|           "prevSize": 24, | ||||
|           "code": 60182, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 60, | ||||
| @@ -1045,7 +1053,7 @@ | ||||
|           "name": "icon-tabular-scrolling", | ||||
|           "prevSize": 24, | ||||
|           "code": 60183, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 131, | ||||
| @@ -1053,7 +1061,7 @@ | ||||
|           "name": "icon-telemetry", | ||||
|           "prevSize": 24, | ||||
|           "code": 60184, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 108, | ||||
| @@ -1061,7 +1069,7 @@ | ||||
|           "name": "icon-timeline", | ||||
|           "prevSize": 24, | ||||
|           "code": 60185, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 81, | ||||
| @@ -1069,7 +1077,7 @@ | ||||
|           "name": "icon-timer", | ||||
|           "prevSize": 24, | ||||
|           "code": 60186, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 69, | ||||
| @@ -1077,7 +1085,7 @@ | ||||
|           "name": "icon-topic", | ||||
|           "prevSize": 24, | ||||
|           "code": 60187, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 79, | ||||
| @@ -1085,7 +1093,7 @@ | ||||
|           "name": "icon-box-with-dashed-lines-v2", | ||||
|           "prevSize": 24, | ||||
|           "code": 60188, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 90, | ||||
| @@ -1093,7 +1101,7 @@ | ||||
|           "name": "icon-summary-widget", | ||||
|           "prevSize": 24, | ||||
|           "code": 60189, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 92, | ||||
| @@ -1101,7 +1109,7 @@ | ||||
|           "name": "icon-notebook", | ||||
|           "prevSize": 24, | ||||
|           "code": 60190, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 168, | ||||
| @@ -1109,7 +1117,7 @@ | ||||
|           "name": "icon-tabs-view", | ||||
|           "prevSize": 24, | ||||
|           "code": 60191, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 117, | ||||
| @@ -1117,7 +1125,7 @@ | ||||
|           "name": "icon-flexible-layout", | ||||
|           "prevSize": 24, | ||||
|           "code": 60192, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 166, | ||||
| @@ -1125,7 +1133,7 @@ | ||||
|           "name": "icon-generator-sine", | ||||
|           "prevSize": 24, | ||||
|           "code": 60193, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 167, | ||||
| @@ -1133,7 +1141,7 @@ | ||||
|           "name": "icon-generator-event", | ||||
|           "prevSize": 24, | ||||
|           "code": 60194, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 165, | ||||
| @@ -1141,7 +1149,7 @@ | ||||
|           "name": "icon-gauge-v2", | ||||
|           "prevSize": 24, | ||||
|           "code": 60195, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 170, | ||||
| @@ -1149,7 +1157,7 @@ | ||||
|           "name": "icon-spectra", | ||||
|           "prevSize": 24, | ||||
|           "code": 60196, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 171, | ||||
| @@ -1157,7 +1165,7 @@ | ||||
|           "name": "icon-telemetry-spectra", | ||||
|           "prevSize": 24, | ||||
|           "code": 60197, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 172, | ||||
| @@ -1165,7 +1173,7 @@ | ||||
|           "name": "icon-pushbutton", | ||||
|           "prevSize": 24, | ||||
|           "code": 60198, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 174, | ||||
| @@ -1173,7 +1181,7 @@ | ||||
|           "name": "icon-conditional", | ||||
|           "prevSize": 24, | ||||
|           "code": 60199, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 178, | ||||
| @@ -1181,7 +1189,7 @@ | ||||
|           "name": "icon-condition-widget", | ||||
|           "prevSize": 24, | ||||
|           "code": 60200, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 180, | ||||
| @@ -1189,7 +1197,7 @@ | ||||
|           "name": "icon-alphanumeric", | ||||
|           "prevSize": 24, | ||||
|           "code": 60201, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 183, | ||||
| @@ -1197,7 +1205,15 @@ | ||||
|           "name": "icon-image-telemetry", | ||||
|           "prevSize": 24, | ||||
|           "code": 60202, | ||||
|           "tempChar": "" | ||||
|           "tempChar": "" | ||||
|         }, | ||||
|         { | ||||
|           "order": 198, | ||||
|           "id": 170, | ||||
|           "name": "icon-telemetry-aggregate", | ||||
|           "prevSize": 24, | ||||
|           "code": 60203, | ||||
|           "tempChar": "" | ||||
|         } | ||||
|       ], | ||||
|       "id": 0, | ||||
| @@ -2000,6 +2016,26 @@ | ||||
|             ] | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           "id": 169, | ||||
|           "paths": [ | ||||
|             "M1024 512c0 282.77-229.23 512-512 512s-512-229.23-512-512c0-282.77 229.23-512 512-512s512 229.23 512 512z" | ||||
|           ], | ||||
|           "attrs": [ | ||||
|             {} | ||||
|           ], | ||||
|           "isMulticolor": false, | ||||
|           "isMulticolor2": false, | ||||
|           "grid": 16, | ||||
|           "tags": [ | ||||
|             "icon-circle" | ||||
|           ], | ||||
|           "colorPermutations": { | ||||
|             "12552552551": [ | ||||
|               {} | ||||
|             ] | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           "id": 105, | ||||
|           "paths": [ | ||||
| @@ -3784,6 +3820,32 @@ | ||||
|               {} | ||||
|             ] | ||||
|           } | ||||
|         }, | ||||
|         { | ||||
|           "id": 170, | ||||
|           "paths": [ | ||||
|             "M78 395.44c14-41.44 37.48-100.8 69.2-148.36 38.62-57.78 82.38-87.080 130.14-87.080s91.5 29.3 130 87.080c31.72 47.56 55.14 106.92 69.2 148.36 30.88 90.96 63.12 134.98 78 146.54 14.94-11.56 47.2-55.58 78-146.54 14-41.44 37.48-100.8 69.22-148.36q27.8-41.7 59.12-63.5c-75.7-111.377-201.81-183.58-344.783-183.58-0.034 0-0.068 0-0.103 0l0.006-0c-229.76 0-416 186.24-416 416-0 0.071-0 0.156-0 0.24 0 39.119 5.396 76.977 15.484 112.871l-0.704-2.931c16.78-21.74 40.4-63.34 63.22-130.74z", | ||||
|             "M754 436.56c-14 41.44-37.48 100.8-69.2 148.36-38.56 57.78-82.32 87.080-130 87.080s-91.5-29.3-130-87.080c-31.72-47.56-55.14-106.92-69.2-148.36-30.88-90.96-63.14-134.98-78-146.54-14.94 11.56-47.2 55.58-78 146.54-14.38 41.44-37.8 100.8-69.6 148.36q-27.8 41.7-59.12 63.5c75.7 111.378 201.81 183.58 344.783 183.58 0.119 0 0.237-0 0.356-0l-0.019 0c229.76 0 416-186.24 416-416 0-0.071 0-0.156 0-0.24 0-39.119-5.396-76.977-15.484-112.871l0.704 2.931c-16.78 21.74-40.4 63.34-63.22 130.74z", | ||||
|             "M921.56 334.62c4.098 24.449 6.44 52.617 6.44 81.332 0 0.017-0 0.034-0 0.051l0-0.003c0 0.095 0 0.208 0 0.32 0 282.593-229.087 511.68-511.68 511.68-0.113 0-0.225-0-0.338-0l0.018 0c-0.014 0-0.031 0-0.048 0-28.716 0-56.884-2.342-84.325-6.845l2.993 0.405c72.483 63.623 168.109 102.44 272.802 102.44 0.203 0 0.406-0 0.61-0l-0.031 0c229.76 0 416-186.24 416-416 0-0.172 0-0.375 0-0.578 0-104.692-38.817-200.319-102.844-273.271l0.404 0.47z" | ||||
|           ], | ||||
|           "attrs": [ | ||||
|             {}, | ||||
|             {}, | ||||
|             {} | ||||
|           ], | ||||
|           "isMulticolor": false, | ||||
|           "isMulticolor2": false, | ||||
|           "grid": 16, | ||||
|           "tags": [ | ||||
|             "icon-telemetry-aggregate" | ||||
|           ], | ||||
|           "colorPermutations": { | ||||
|             "12552552551": [ | ||||
|               {}, | ||||
|               {}, | ||||
|               {} | ||||
|             ] | ||||
|           } | ||||
|         } | ||||
|       ], | ||||
|       "invisible": false, | ||||
|   | ||||
| @@ -53,6 +53,7 @@ | ||||
| <glyph unicode="" glyph-name="icon-eye-disabled" d="M209.46 223.32q-7.46 9.86-14.26 20.28c-14.737 21.984-27.741 47.184-37.759 73.847l-0.841 2.553c11.078 29.259 24.068 54.443 39.51 77.869l-0.91-1.469c23.221 34.963 50.705 64.8 82.207 89.793l0.793 0.607c57.663 45.719 130.179 75.053 209.311 79.947l1.069 0.053 114.48 140.88c-27.366 5.017-58.869 7.898-91.041 7.92h-0.019c-245.8 0-452.2-168-510.8-395.6 21.856-82.93 60.906-154.847 113.325-214.773l-0.525 0.613zM814.76 416.92q7.52-10 14.44-20.52c14.737-21.984 27.741-47.184 37.759-73.847l0.841-2.553c-10.859-29.216-23.863-54.416-39.447-77.748l0.847 1.348c-23.221-34.963-50.705-64.8-82.207-89.793l-0.793-0.607c-57.762-45.834-130.437-75.216-209.743-80.049l-1.057-0.051-114.46-140.86c27.346-4.988 58.817-7.84 90.955-7.84 0.037 0 0.074 0 0.111 0h-0.005c245.8 0 452.2 168 510.8 395.6-21.856 82.93-60.906 154.847-113.325 214.773l0.525-0.613zM832 832l-832-1024h192l832 1024h-192z" /> | ||||
| <glyph unicode="" glyph-name="icon-notebook-page" d="M830 770h-830l-4-702c0-106.6 87.4-194 194-194h640c106.6 0 194 87.4 194 194v508c0 106.8-87.4 194-194 194zM832 386l-384-384-192 192v256l192-192 384 384v-256z" /> | ||||
| <glyph unicode="" glyph-name="icon-unlocked" d="M768 832c-141.339-0.114-255.886-114.661-256-255.989v-128.011h-448c-35.301-0.113-63.887-28.699-64-63.989v-512.011c0.113-35.301 28.699-63.887 63.989-64h638.011c35.301 0.113 63.887 28.699 64 63.989v512.011c-0.113 35.301-28.699 63.887-63.989 64h-62.011v128c0 70.692 57.308 128 128 128s128-57.308 128-128v0-128h128v128c-0.114 141.339-114.661 255.886-255.989 256h-0.011z" /> | ||||
| <glyph unicode="" glyph-name="icon-circle" d="M1024 320c0-282.77-229.23-512-512-512s-512 229.23-512 512c0 282.77 229.23 512 512 512s512-229.23 512-512z" /> | ||||
| <glyph unicode="" glyph-name="icon-arrows-right-left" d="M1024 320l-448-512v1024zM448 832l-448-512 448-512z" /> | ||||
| <glyph unicode="" glyph-name="icon-arrows-up-down" d="M512 832l512-448h-1024zM0 256l512-448 512 448z" /> | ||||
| <glyph unicode="" glyph-name="icon-bullet" d="M832 80c0-44-36-80-80-80h-480c-44 0-80 36-80 80v480c0 44 36 80 80 80h480c44 0 80-36 80-80v-480z" /> | ||||
| @@ -156,4 +157,5 @@ | ||||
| <glyph unicode="" glyph-name="icon-condition-widget" d="M832 832h-640c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h640c105.6 0 192 86.4 192 192v640c0 105.6-86.4 192-192 192zM512 64l-384 256 384 256 384-256z" /> | ||||
| <glyph unicode="" glyph-name="icon-alphanumeric" d="M535.6 301.4c-8.4-1.6-17.2-3-26.2-4s-18.2-2.4-27.2-4c-10.196-1.861-18.808-4.010-27.21-6.633l1.61 0.433c-8.609-2.674-16.105-6.348-22.89-10.987l0.29 0.187c-6.693-4.517-12.283-10.107-16.663-16.585l-0.137-0.215c-4.6-6.8-7.4-15.6-8.8-26s-0.4-18.4 2.4-25.2c2.746-6.688 7.224-12.195 12.881-16.122l0.119-0.078c5.967-4.053 13.057-6.94 20.704-8.161l0.296-0.039c7.592-1.527 16.319-2.4 25.25-2.4 0.123 0 0.246 0 0.369 0h-0.019c22.2 0 39.6 3.6 52.6 11s23.2 16.2 30.2 26.4c6.273 8.873 11.271 19.191 14.426 30.285l0.174 0.715c1.853 6.809 3.601 15.41 4.855 24.169l0.145 1.231 5.2 41.6c-5.4-4.217-11.723-7.564-18.583-9.689l-0.417-0.111c-6.489-2.241-14.362-4.255-22.444-5.662l-0.956-0.138zM1024 448v192h-152l24 192h-192l-24-192h-256l24 192h-192l-24-192h-232v-192h208l-32-256h-176v-192h152l-24-192h192l24 192h256l-24-192h192l24 192h232v192h-208l32 256zM702.8 420.2l-26.4-211.8c-2.231-15.809-3.537-34.122-3.6-52.727v-0.073c0-16.8 2.2-29.4 6.4-37.8h-113.4c-1.342 5.556-2.338 12.122-2.781 18.84l-0.019 0.36c-0.261 3.524-0.409 7.634-0.409 11.778 0 2.962 0.076 5.907 0.226 8.832l-0.017-0.41c-18.663-17.401-41.395-30.694-66.597-38.289l-1.203-0.311c-22.627-6.956-48.639-10.974-75.586-11h-0.014c-0.764-0.011-1.666-0.018-2.569-0.018-18.098 0-35.598 2.563-52.156 7.345l1.325-0.328c-15.991 4.512-29.851 12.090-41.545 22.122l0.145-0.122c-11.233 9.982-19.792 22.733-24.624 37.192l-0.176 0.608c-5.2 15.2-6.4 33.4-3.8 54.4s9.4 42.2 19.4 57.2c9.524 14.399 21.535 26.346 35.532 35.512l0.468 0.288c13.387 8.662 28.922 15.533 45.512 19.765l1.088 0.235c13.436 3.792 30.801 7.554 48.47 10.41l2.93 0.39c17 2.6 33.8 4.6 50.4 6.2 16.628 1.527 31.69 4.070 46.349 7.643l-2.149-0.443c13 3 23.6 7.6 31.6 13.6s12.6 15 13.6 26.4 0.8 21.8-2.4 28.8c-2.849 6.902-7.542 12.56-13.468 16.517l-0.132 0.083c-6.217 4.011-13.604 6.78-21.543 7.774l-0.257 0.026c-7.897 1.277-17 2.007-26.274 2.007-0.537 0-1.073-0.002-1.609-0.007l0.082 0.001c-22 0-40-4.6-53.8-14.2s-23-25.2-28-47.2h-111.8c4.8 26.2 14.2 48 27.8 65.4 13.475 16.978 29.89 30.968 48.574 41.377l0.826 0.423c18.192 10.038 39.297 17.806 61.619 22.175l1.381 0.225c20.488 4.162 44.053 6.563 68.171 6.6h0.029c21.8-0.005 43.239-1.532 64.222-4.479l-2.422 0.279c20.641-2.809 39.324-8.783 56.401-17.461l-1.001 0.461c15.909-8.108 28.858-20.031 37.967-34.601l0.233-0.399c9-15 12.2-34.8 9-59.6z" /> | ||||
| <glyph unicode="" glyph-name="icon-image-telemetry" d="M512 832c-282.8 0-512-229.2-512-512s229.2-512 512-512 512 229.2 512 512-229.2 512-512 512zM783.6 48.4c-69.581-69.675-165.757-112.776-272-112.776-212.298 0-384.4 172.102-384.4 384.4s172.102 384.4 384.4 384.4c212.298 0 384.4-172.102 384.4-384.4 0-0.008 0-0.017 0-0.025v0.001c0.001-0.264 0.001-0.575 0.001-0.887 0-105.769-42.964-201.503-112.391-270.703l-0.010-0.010zM704 448l-128-128-192 192-192-192c0-176.731 143.269-320 320-320s320 143.269 320 320v0z" /> | ||||
| <glyph unicode="" glyph-name="icon-telemetry-aggregate" d="M78 436.56c14 41.44 37.48 100.8 69.2 148.36 38.62 57.78 82.38 87.080 130.14 87.080s91.5-29.3 130-87.080c31.72-47.56 55.14-106.92 69.2-148.36 30.88-90.96 63.12-134.98 78-146.54 14.94 11.56 47.2 55.58 78 146.54 14 41.44 37.48 100.8 69.22 148.36q27.8 41.7 59.12 63.5c-75.7 111.377-201.81 183.58-344.783 183.58-0.034 0-0.068 0-0.103 0h0.006c-229.76 0-416-186.24-416-416 0-0.071 0-0.156 0-0.24 0-39.119 5.396-76.977 15.484-112.871l-0.704 2.931c16.78 21.74 40.4 63.34 63.22 130.74zM754 395.44c-14-41.44-37.48-100.8-69.2-148.36-38.56-57.78-82.32-87.080-130-87.080s-91.5 29.3-130 87.080c-31.72 47.56-55.14 106.92-69.2 148.36-30.88 90.96-63.14 134.98-78 146.54-14.94-11.56-47.2-55.58-78-146.54-14.38-41.44-37.8-100.8-69.6-148.36q-27.8-41.7-59.12-63.5c75.7-111.378 201.81-183.58 344.783-183.58 0.119 0 0.237 0 0.356 0h-0.019c229.76 0 416 186.24 416 416 0 0.071 0 0.156 0 0.24 0 39.119-5.396 76.977-15.484 112.871l0.704-2.931c-16.78-21.74-40.4-63.34-63.22-130.74zM921.56 497.38c4.098-24.449 6.44-52.617 6.44-81.332 0-0.017 0-0.034 0-0.051v0.003c0-0.095 0-0.208 0-0.32 0-282.593-229.087-511.68-511.68-511.68-0.113 0-0.225 0-0.338 0h0.018c-0.014 0-0.031 0-0.048 0-28.716 0-56.884 2.342-84.325 6.845l2.993-0.405c72.483-63.623 168.109-102.44 272.802-102.44 0.203 0 0.406 0 0.61 0h-0.031c229.76 0 416 186.24 416 416 0 0.172 0 0.375 0 0.578 0 104.692-38.817 200.319-102.844 273.271l0.404-0.47z" /> | ||||
| </font></defs></svg> | ||||
| Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 61 KiB | 
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -53,7 +53,7 @@ | ||||
|             class="l-shell__pane-tree" | ||||
|             handle="after" | ||||
|             label="Browse" | ||||
|             collapsable | ||||
|             hide-param="hideTree" | ||||
|             @start-resizing="onStartResizing" | ||||
|             @end-resizing="onEndResizing" | ||||
|         > | ||||
| @@ -104,7 +104,7 @@ | ||||
|             class="l-shell__pane-inspector l-pane--holds-multipane" | ||||
|             handle="before" | ||||
|             label="Inspect" | ||||
|             collapsable | ||||
|             hide-param="hideInspector" | ||||
|             @start-resizing="onStartResizing" | ||||
|             @end-resizing="onEndResizing" | ||||
|         > | ||||
|   | ||||
							
								
								
									
										171
									
								
								src/ui/layout/LayoutSpec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								src/ui/layout/LayoutSpec.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,171 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2021, 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| import { | ||||
|     createOpenMct, | ||||
|     resetApplicationState | ||||
| } from 'utils/testing'; | ||||
| import Vue from 'vue'; | ||||
| import Layout from './Layout.vue'; | ||||
|  | ||||
| describe('Open MCT Layout:', () => { | ||||
|     let openmct; | ||||
|     let element; | ||||
|     let components; | ||||
|  | ||||
|     beforeEach((done) => { | ||||
|         openmct = createOpenMct(); | ||||
|         openmct.on('start', done); | ||||
|  | ||||
|         // to silence error from BrowseBar.vue | ||||
|         spyOn(openmct.objectViews, 'get') | ||||
|             .and.callFake(() => []); | ||||
|  | ||||
|         openmct.startHeadless(); | ||||
|     }); | ||||
|  | ||||
|     afterEach(() => { | ||||
|         return resetApplicationState(openmct); | ||||
|     }); | ||||
|  | ||||
|     describe('the pane:', () => { | ||||
|         it('is displayed on layout load', async () => { | ||||
|             await createLayout(); | ||||
|             await Vue.nextTick(); | ||||
|  | ||||
|             Object.entries(components).forEach(([name, component]) => { | ||||
|                 expect( | ||||
|                     component.pane | ||||
|                 ).toBeTruthy(); | ||||
|  | ||||
|                 expect( | ||||
|                     isCollapsed(component.pane) | ||||
|                 ).toBeFalse(); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         it('is collapsed on layout load if specified by a hide param', async () => { | ||||
|             setHideParams(); | ||||
|  | ||||
|             await createLayout(); | ||||
|             await Vue.nextTick(); | ||||
|  | ||||
|             Object.entries(components).forEach(([name, component]) => { | ||||
|                 expect( | ||||
|                     isCollapsed(component.pane) | ||||
|                 ).toBeTrue(); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         it('on toggle collapses if expanded', async () => { | ||||
|             await createLayout(); | ||||
|             toggleCollapseButtons(); | ||||
|             await Vue.nextTick(); | ||||
|  | ||||
|             Object.entries(components).forEach(([name, component]) => { | ||||
|                 expect( | ||||
|                     openmct.router.getSearchParam(component.param) | ||||
|                 ).toEqual('true'); | ||||
|  | ||||
|                 expect( | ||||
|                     isCollapsed(component.pane) | ||||
|                 ).toBeTrue(); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         it('on toggle expands if collapsed', async () => { | ||||
|             setHideParams(); | ||||
|  | ||||
|             await createLayout(); | ||||
|             toggleExpandButtons(); | ||||
|             await Vue.nextTick(); | ||||
|  | ||||
|             Object.entries(components).forEach(([name, component]) => { | ||||
|                 expect( | ||||
|                     openmct.router.getSearchParam(component.param) | ||||
|                 ).not.toEqual('true'); | ||||
|  | ||||
|                 expect( | ||||
|                     isCollapsed(component.pane) | ||||
|                 ).toBeFalse(); | ||||
|             }); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     async function createLayout() { | ||||
|         const el = document.createElement('div'); | ||||
|         const child = document.createElement('div'); | ||||
|         el.appendChild(child); | ||||
|  | ||||
|         element = await new Vue({ | ||||
|             el, | ||||
|             components: { | ||||
|                 Layout | ||||
|             }, | ||||
|             provide: { | ||||
|                 openmct | ||||
|             }, | ||||
|             template: `<Layout ref="layout"/>` | ||||
|         }).$mount().$el; | ||||
|  | ||||
|         setComponents(); | ||||
|     } | ||||
|  | ||||
|     function setComponents() { | ||||
|         components = { | ||||
|             tree: { | ||||
|                 param: 'hideTree', | ||||
|                 pane: element.querySelector('.l-shell__pane-tree'), | ||||
|                 collapseButton: element.querySelector('.l-shell__pane-tree .l-pane__collapse-button'), | ||||
|                 expandButton: element.querySelector('.l-shell__pane-tree .l-pane__expand-button') | ||||
|             }, | ||||
|             inspector: { | ||||
|                 param: 'hideInspector', | ||||
|                 pane: element.querySelector('.l-shell__pane-inspector'), | ||||
|                 collapseButton: element.querySelector('.l-shell__pane-inspector .l-pane__collapse-button'), | ||||
|                 expandButton: element.querySelector('.l-shell__pane-inspector .l-pane__expand-button') | ||||
|             } | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     function isCollapsed(el) { | ||||
|         return el.classList.contains('l-pane--collapsed'); | ||||
|     } | ||||
|  | ||||
|     function setHideParams() { | ||||
|         Object.entries(components).forEach(([name, component]) => { | ||||
|             openmct.router.setSearchParam(component.param, true); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     function toggleCollapseButtons() { | ||||
|         Object.entries(components).forEach(([name, component]) => { | ||||
|             component.collapseButton.click(); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     function toggleExpandButtons() { | ||||
|         Object.entries(components).forEach(([name, component]) => { | ||||
|             component.expandButton.click(); | ||||
|         }); | ||||
|     } | ||||
| }); | ||||
| @@ -41,10 +41,6 @@ | ||||
|  | ||||
| <script> | ||||
| const COLLAPSE_THRESHOLD_PX = 40; | ||||
| const HIDE_TREE_PARAM = 'hideTree'; | ||||
| const HIDE_INSPECTOR_PARAM = 'hideInspector'; | ||||
| const PANE_INSPECTOR = 'Inspect'; | ||||
| const PANE_TREE = 'Browse'; | ||||
|  | ||||
| export default { | ||||
|     inject: ['openmct'], | ||||
| @@ -56,13 +52,13 @@ export default { | ||||
|                 return ['', 'before', 'after'].indexOf(value) !== -1; | ||||
|             } | ||||
|         }, | ||||
|         collapsable: { | ||||
|             type: Boolean, | ||||
|             default: false | ||||
|         }, | ||||
|         label: { | ||||
|             type: String, | ||||
|             default: '' | ||||
|         }, | ||||
|         hideParam: { | ||||
|             type: String, | ||||
|             default: '' | ||||
|         } | ||||
|     }, | ||||
|     data() { | ||||
| @@ -71,6 +67,11 @@ export default { | ||||
|             resizing: false | ||||
|         }; | ||||
|     }, | ||||
|     computed: { | ||||
|         collapsable() { | ||||
|             return this.hideParam && this.hideParam.length; | ||||
|         } | ||||
|     }, | ||||
|     beforeMount() { | ||||
|         this.type = this.$parent.type; | ||||
|         this.styleProp = (this.type === 'horizontal') ? 'width' : 'height'; | ||||
| @@ -78,39 +79,25 @@ export default { | ||||
|     async mounted() { | ||||
|         await this.$nextTick(); | ||||
|         // Hide tree and/or inspector pane if specified in URL | ||||
|         this.handleHideUrl(); | ||||
|         this.openmct.router.on('change:params', this.handleHideUrl); | ||||
|     }, | ||||
|     beforeDestroy() { | ||||
|         this.openmct.router.off('change:params', this.handleHideUrl); | ||||
|         if (this.collapsable) { | ||||
|             this.handleHideUrl(); | ||||
|         } | ||||
|     }, | ||||
|     methods: { | ||||
|         toggleCollapse: function (e) { | ||||
|             let target = this.label === PANE_TREE ? HIDE_TREE_PARAM : HIDE_INSPECTOR_PARAM; | ||||
|             this.collapsed = !this.collapsed; | ||||
|             if (this.collapsed) { | ||||
|                 this.handleCollapse(); | ||||
|                 this.addHideParam(target); | ||||
|             } else { | ||||
|                 this.handleExpand(); | ||||
|                 this.removeHideParam(target); | ||||
|                 this.removeHideParam(this.hideParam); | ||||
|             } else { | ||||
|                 this.handleCollapse(); | ||||
|                 this.addHideParam(this.hideParam); | ||||
|             } | ||||
|         }, | ||||
|         handleHideUrl: function () { | ||||
|             if (!this.collapsable) { | ||||
|                 return; | ||||
|             } | ||||
|             const hideParam = this.openmct.router.getSearchParam(this.hideParam); | ||||
|  | ||||
|             let hideTreeParam = this.openmct.router.getSearchParam(HIDE_TREE_PARAM); | ||||
|             let hideInspectorParam = this.openmct.router.getSearchParam(HIDE_INSPECTOR_PARAM); | ||||
|             let hideTree = hideTreeParam === 'true' && this.label === PANE_TREE; | ||||
|             let hideInspector = hideInspectorParam === 'true' && this.label === PANE_INSPECTOR; | ||||
|             if (hideTree || hideInspector) { | ||||
|                 this.collapsed = true; | ||||
|             if (hideParam === 'true') { | ||||
|                 this.handleCollapse(); | ||||
|             } else { | ||||
|                 this.collapsed = false; | ||||
|                 this.handleExpand(); | ||||
|             } | ||||
|         }, | ||||
|         addHideParam: function (target) { | ||||
| @@ -122,11 +109,13 @@ export default { | ||||
|         handleCollapse: function () { | ||||
|             this.currentSize = (this.dragCollapse === true) ? this.initial : this.$el.style[this.styleProp]; | ||||
|             this.$el.style[this.styleProp] = ''; | ||||
|             this.collapsed = true; | ||||
|         }, | ||||
|         handleExpand: function () { | ||||
|             this.$el.style[this.styleProp] = this.currentSize; | ||||
|             delete this.currentSize; | ||||
|             delete this.dragCollapse; | ||||
|             this.collapsed = false; | ||||
|         }, | ||||
|         trackSize: function () { | ||||
|             if (!this.dragCollapse === true) { | ||||
|   | ||||
| @@ -1,90 +0,0 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2021, 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. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| import { | ||||
|     createOpenMct, | ||||
|     resetApplicationState | ||||
| } from 'utils/testing'; | ||||
|  | ||||
| describe("the pane", () => { | ||||
|     let openmct; | ||||
|     let appHolder; | ||||
|     let element; | ||||
|     let child; | ||||
|     let resolveFunction; | ||||
|  | ||||
|     beforeEach((done) => { | ||||
|         openmct = createOpenMct(); | ||||
|  | ||||
|         appHolder = document.createElement('div'); | ||||
|         appHolder.style.width = '640px'; | ||||
|         appHolder.style.height = '480px'; | ||||
|  | ||||
|         openmct = createOpenMct(); | ||||
|         openmct.install(openmct.plugins.MyItems()); | ||||
|         openmct.install(openmct.plugins.LocalTimeSystem()); | ||||
|         openmct.install(openmct.plugins.UTCTimeSystem()); | ||||
|  | ||||
|         element = document.createElement('div'); | ||||
|         child = document.createElement('div'); | ||||
|         element.appendChild(child); | ||||
|  | ||||
|         openmct.on('start', done); | ||||
|         openmct.start(appHolder); | ||||
|  | ||||
|         document.body.append(appHolder); | ||||
|  | ||||
|     }); | ||||
|  | ||||
|     afterEach(() => { | ||||
|         return resetApplicationState(openmct); | ||||
|     }); | ||||
|     it('toggling tree will toggle tree hide params', (done) => { | ||||
|         document.querySelector('.l-shell__pane-tree .l-pane__collapse-button').click(); | ||||
|         expect(openmct.router.getSearchParam('hideTree')).toBe('true'); | ||||
|         done(); | ||||
|     }); | ||||
|  | ||||
|     it('tree pane collapses when adding hide tree param in URL', () => { | ||||
|         openmct.router.setSearchParam('hideTree', 'true'); | ||||
|         expect(document.querySelector('.l-shell__pane-tree.l-pane--collapsed')).toBeDefined(); | ||||
|     }); | ||||
|  | ||||
|     it('inspector pane collapses when adding hide inspector param in URL', () => { | ||||
|         openmct.router.setSearchParam('hideInspector', 'true'); | ||||
|         expect(document.querySelector('.l-shell__pane-inspector.l-pane--collapsed')).toBeDefined(); | ||||
|     }); | ||||
|  | ||||
|     it('toggle inspector pane will toggle inspector hide param', (done) => { | ||||
|         // There's a short delay on addubg the param. | ||||
|         resolveFunction = () => { | ||||
|             setTimeout(() => { | ||||
|                 expect(openmct.router.getSearchParam('hideInspector')).toBe('true'); | ||||
|                 done(); | ||||
|             }, 500); | ||||
|         }; | ||||
|  | ||||
|         openmct.router.on('change:params', resolveFunction); | ||||
|         document.querySelector('.l-shell__pane-inspector .l-pane__collapse-button').click(); | ||||
|     }); | ||||
|  | ||||
| }); | ||||
		Reference in New Issue
	
	Block a user