Compare commits
	
		
			17 Commits
		
	
	
		
			v1.2-RC1
			...
			disable-ed
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 80c9f4602c | ||
|   | 36a7df0708 | ||
|   | 79ff690d4b | ||
|   | f56a4c9ddc | ||
|   | d8cfaeada4 | ||
|   | 6b65ceb2c5 | ||
|   | 24f3687552 | ||
|   | 07464ab417 | ||
|   | 42236e9069 | ||
|   | b2d03bb4be | ||
|   | 2bf349065a | ||
|   | a93601d1f0 | ||
|   | 1a6c8c64a3 | ||
|   | 854d9d43fe | ||
|   | 0c4e46a1ca | ||
|   | 551bfcb4a8 | ||
|   | 39a78df42f | 
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -37,7 +37,4 @@ protractor/logs | ||||
| # npm-debug log | ||||
| npm-debug.log | ||||
|  | ||||
| # karma reports | ||||
| report.*.json | ||||
|  | ||||
| package-lock.json | ||||
|   | ||||
| @@ -28,16 +28,6 @@ define([ | ||||
|                         domain: 2 | ||||
|                     } | ||||
|                 }, | ||||
|                 // Need to enable "LocalTimeSystem" plugin to make use of this | ||||
|                 // { | ||||
|                 //     key: "local", | ||||
|                 //     name: "Time", | ||||
|                 //     format: "local-format", | ||||
|                 //     source: "utc", | ||||
|                 //     hints: { | ||||
|                 //         domain: 3 | ||||
|                 //     } | ||||
|                 // }, | ||||
|                 { | ||||
|                     key: "sin", | ||||
|                     name: "Sine", | ||||
| @@ -71,15 +61,6 @@ define([ | ||||
|                         domain: 1 | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     key: "local", | ||||
|                     name: "Time", | ||||
|                     format: "utc", | ||||
|                     source: "utc", | ||||
|                     hints: { | ||||
|                         domain: 2 | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     key: "state", | ||||
|                     source: "value", | ||||
|   | ||||
							
								
								
									
										45
									
								
								index.html
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								index.html
									
									
									
									
									
								
							| @@ -34,8 +34,8 @@ | ||||
|     <body> | ||||
|     </body> | ||||
|     <script> | ||||
|         const THIRTY_SECONDS = 30 * 1000; | ||||
|         const THIRTY_MINUTES = THIRTY_SECONDS * 60; | ||||
|         const FIVE_MINUTES = 5 * 60 * 1000; | ||||
|         const THIRTY_MINUTES = 30 * 60 * 1000; | ||||
|  | ||||
|         [ | ||||
|             'example/eventGenerator' | ||||
| @@ -63,39 +63,7 @@ | ||||
|                     bounds: { | ||||
|                         start: Date.now() - THIRTY_MINUTES, | ||||
|                         end: Date.now() | ||||
|                     }, | ||||
|                     // commonly used bounds can be stored in history | ||||
|                     // bounds (start and end) can accept either a milliseconds number | ||||
|                     // or a callback function returning a milliseconds number | ||||
|                     // a function is useful for invoking Date.now() at exact moment of preset selection | ||||
|                     presets: [ | ||||
|                         { | ||||
|                             label: 'Last Day', | ||||
|                             bounds: { | ||||
|                                 start: () => Date.now() - 1000 * 60 * 60 * 24, | ||||
|                                 end: () => Date.now() | ||||
|                             } | ||||
|                         }, | ||||
|                         { | ||||
|                             label: 'Last 2 hours', | ||||
|                             bounds: { | ||||
|                                 start: () => Date.now() - 1000 * 60 * 60 * 2, | ||||
|                                 end: () => Date.now() | ||||
|                             } | ||||
|                         }, | ||||
|                         { | ||||
|                             label: 'Last hour', | ||||
|                             bounds: { | ||||
|                                 start: () => Date.now() - 1000 * 60 * 60, | ||||
|                                 end: () => Date.now() | ||||
|                             } | ||||
|                         } | ||||
|                     ], | ||||
|                     // maximum recent bounds to retain in conductor history | ||||
|                     records: 10, | ||||
|                     // maximum duration between start and end bounds | ||||
|                     // for utc-based time systems this is in milliseconds | ||||
|                     limit: 1000 * 60 * 60 * 24 | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     name: "Realtime", | ||||
| @@ -103,7 +71,7 @@ | ||||
|                     clock: 'local', | ||||
|                     clockOffsets: { | ||||
|                         start: - THIRTY_MINUTES, | ||||
|                         end: THIRTY_SECONDS | ||||
|                         end: FIVE_MINUTES | ||||
|                     } | ||||
|                 } | ||||
|             ] | ||||
| @@ -113,10 +81,7 @@ | ||||
|         openmct.install(openmct.plugins.LADTable()); | ||||
|         openmct.install(openmct.plugins.Filters(['table', 'telemetry.plot.overlay'])); | ||||
|         openmct.install(openmct.plugins.ObjectMigration()); | ||||
|         openmct.install(openmct.plugins.ClearData( | ||||
|             ['table', 'telemetry.plot.overlay', 'telemetry.plot.stacked'], | ||||
|             {indicator: true} | ||||
|         )); | ||||
|         openmct.install(openmct.plugins.ClearData(['table', 'telemetry.plot.overlay', 'telemetry.plot.stacked'])); | ||||
|         openmct.start(); | ||||
|     </script> | ||||
| </html> | ||||
|   | ||||
| @@ -23,7 +23,7 @@ | ||||
| /*global module,process*/ | ||||
|  | ||||
| const devMode = process.env.NODE_ENV !== 'production'; | ||||
| const browsers = [process.env.NODE_ENV === 'debug' ? 'ChromeDebugging' : 'FirefoxHeadless']; | ||||
| const browsers = [process.env.NODE_ENV === 'debug' ? 'ChromeDebugging' : 'ChromeHeadless']; | ||||
| const coverageEnabled = process.env.COVERAGE === 'true'; | ||||
| const reporters = ['progress', 'html']; | ||||
|  | ||||
| @@ -95,7 +95,6 @@ module.exports = (config) => { | ||||
|             stats: 'errors-only', | ||||
|             logLevel: 'warn' | ||||
|         }, | ||||
|         singleRun: true, | ||||
|         browserNoActivityTimeout: 90000 | ||||
|         singleRun: true | ||||
|     }); | ||||
| } | ||||
|   | ||||
| @@ -41,7 +41,6 @@ | ||||
|     "jsdoc": "^3.3.2", | ||||
|     "karma": "^2.0.3", | ||||
|     "karma-chrome-launcher": "^2.2.0", | ||||
|     "karma-firefox-launcher": "^1.3.0", | ||||
|     "karma-cli": "^1.0.1", | ||||
|     "karma-coverage": "^1.1.2", | ||||
|     "karma-coverage-istanbul-reporter": "^2.1.1", | ||||
| @@ -60,7 +59,7 @@ | ||||
|     "moment-timezone": "0.5.28", | ||||
|     "node-bourbon": "^4.2.3", | ||||
|     "node-sass": "^4.9.2", | ||||
|     "painterro": "^1.0.35", | ||||
|     "painterro": "^0.2.65", | ||||
|     "printj": "^1.2.1", | ||||
|     "raw-loader": "^0.5.1", | ||||
|     "request": "^2.69.0", | ||||
|   | ||||
| @@ -31,13 +31,13 @@ | ||||
|     </mct-form> | ||||
| </div> | ||||
| <div class="c-overlay__button-bar"> | ||||
|     <button class='c-button c-button--major' | ||||
|     <a class='c-button c-button--major' | ||||
|        ng-class="{ disabled: !createForm.$valid }" | ||||
|        ng-click="ngModel.confirm()"> | ||||
|         OK | ||||
|     </button> | ||||
|     <button class='c-button  ' | ||||
|     </a> | ||||
|     <a class='c-button  ' | ||||
|        ng-click="ngModel.cancel()"> | ||||
|         Cancel | ||||
|     </button> | ||||
|     </a> | ||||
| </div> | ||||
|   | ||||
| @@ -31,13 +31,13 @@ | ||||
|         </mct-include> | ||||
|     </div> | ||||
|     <div class="c-overlay__button-bar"> | ||||
|         <button ng-repeat="option in ngModel.dialog.options" | ||||
|         <a ng-repeat="option in ngModel.dialog.options" | ||||
|            href='' | ||||
|            class="s-button lg" | ||||
|            title="{{option.description}}" | ||||
|            ng-click="ngModel.confirm(option.key)" | ||||
|            ng-class="{ major: $first, subtle: !$first }"> | ||||
|             {{option.name}} | ||||
|         </button> | ||||
|         </a> | ||||
|     </div> | ||||
| </mct-container> | ||||
|   | ||||
| @@ -24,7 +24,7 @@ | ||||
|     <div class="c-overlay__outer"> | ||||
|         <button ng-click="ngModel.cancel()" | ||||
|            ng-if="ngModel.cancel" | ||||
|            class="c-click-icon c-overlay__close-button icon-x"></button> | ||||
|            class="c-click-icon c-overlay__close-button icon-x-in-circle"></button> | ||||
|         <div class="c-overlay__contents" ng-transclude></div> | ||||
|     </div> | ||||
| </div> | ||||
|   | ||||
| @@ -36,6 +36,8 @@ define( | ||||
|         } | ||||
|  | ||||
|         EditPersistableObjectsPolicy.prototype.allow = function (action, context) { | ||||
|             var identifier; | ||||
|             var provider; | ||||
|             var domainObject = context.domainObject; | ||||
|             var key = action.getMetadata().key; | ||||
|             var category = (context || {}).category; | ||||
| @@ -44,8 +46,9 @@ define( | ||||
|             // is also invoked during the create process which should be allowed, | ||||
|             // because it may be saved elsewhere | ||||
|             if ((key === 'edit' && category === 'view-control') || key === 'properties') { | ||||
|                 let newStyleObject = objectUtils.toNewFormat(domainObject, domainObject.getId()); | ||||
|                 return this.openmct.objects.isPersistable(newStyleObject); | ||||
|                 identifier = objectUtils.parseKeyString(domainObject.getId()); | ||||
|                 provider = this.openmct.objects.getProvider(identifier); | ||||
|                 return provider.save !== undefined; | ||||
|             } | ||||
|  | ||||
|             return true; | ||||
|   | ||||
| @@ -43,7 +43,7 @@ define( | ||||
|                 ); | ||||
|  | ||||
|                 mockObjectAPI = jasmine.createSpyObj('objectAPI', [ | ||||
|                     'isPersistable' | ||||
|                     'getProvider' | ||||
|                 ]); | ||||
|  | ||||
|                 mockAPI = { | ||||
| @@ -69,31 +69,34 @@ define( | ||||
|             }); | ||||
|  | ||||
|             it("Applies to edit action", function () { | ||||
|                 expect(mockObjectAPI.isPersistable).not.toHaveBeenCalled(); | ||||
|                 mockObjectAPI.getProvider.and.returnValue({}); | ||||
|                 expect(mockObjectAPI.getProvider).not.toHaveBeenCalled(); | ||||
|  | ||||
|                 policy.allow(mockEditAction, testContext); | ||||
|                 expect(mockObjectAPI.isPersistable).toHaveBeenCalled(); | ||||
|                 expect(mockObjectAPI.getProvider).toHaveBeenCalled(); | ||||
|             }); | ||||
|  | ||||
|             it("Applies to properties action", function () { | ||||
|                 expect(mockObjectAPI.isPersistable).not.toHaveBeenCalled(); | ||||
|                 mockObjectAPI.getProvider.and.returnValue({}); | ||||
|                 expect(mockObjectAPI.getProvider).not.toHaveBeenCalled(); | ||||
|  | ||||
|                 policy.allow(mockPropertiesAction, testContext); | ||||
|                 expect(mockObjectAPI.isPersistable).toHaveBeenCalled(); | ||||
|                 expect(mockObjectAPI.getProvider).toHaveBeenCalled(); | ||||
|             }); | ||||
|  | ||||
|             it("does not apply to other actions", function () { | ||||
|                 expect(mockObjectAPI.isPersistable).not.toHaveBeenCalled(); | ||||
|                 mockObjectAPI.getProvider.and.returnValue({}); | ||||
|                 expect(mockObjectAPI.getProvider).not.toHaveBeenCalled(); | ||||
|  | ||||
|                 policy.allow(mockOtherAction, testContext); | ||||
|                 expect(mockObjectAPI.isPersistable).not.toHaveBeenCalled(); | ||||
|                 expect(mockObjectAPI.getProvider).not.toHaveBeenCalled(); | ||||
|             }); | ||||
|  | ||||
|             it("Tests object provider for editability", function () { | ||||
|                 mockObjectAPI.isPersistable.and.returnValue(false); | ||||
|                 mockObjectAPI.getProvider.and.returnValue({}); | ||||
|                 expect(policy.allow(mockEditAction, testContext)).toBe(false); | ||||
|                 expect(mockObjectAPI.isPersistable).toHaveBeenCalled(); | ||||
|                 mockObjectAPI.isPersistable.and.returnValue(true); | ||||
|                 expect(mockObjectAPI.getProvider).toHaveBeenCalled(); | ||||
|                 mockObjectAPI.getProvider.and.returnValue({save: function () {}}); | ||||
|                 expect(policy.allow(mockEditAction, testContext)).toBe(true); | ||||
|             }); | ||||
|         }); | ||||
|   | ||||
| @@ -19,13 +19,7 @@ | ||||
|  this source code distribution or the Licensing information page available | ||||
|  at runtime from the About dialog for additional information. | ||||
| --> | ||||
| <div class="c-object-label" | ||||
|      ng-class="{ 'is-missing': model.status === 'missing' }" | ||||
| > | ||||
|     <div class="c-object-label__type-icon {{type.getCssClass()}}" | ||||
|          ng-class="{ 'l-icon-link':location.isLink() }" | ||||
|     > | ||||
|         <span class="is-missing__indicator" title="This item is missing"></span> | ||||
|     </div> | ||||
| <div class="c-object-label"> | ||||
|     <div class="c-object-label__type-icon {{type.getCssClass()}}" ng-class="{ 'l-icon-link':location.isLink() }"></div> | ||||
|     <div class='c-object-label__name'>{{model.name}}</div> | ||||
| </div> | ||||
|   | ||||
| @@ -48,8 +48,9 @@ define( | ||||
|             // prevents editing of objects that cannot be persisted, so we can assume that this | ||||
|             // is a new object. | ||||
|             if (!(parent.hasCapability('editor') && parent.getCapability('editor').isEditContextRoot())) { | ||||
|                 let newStyleObject = objectUtils.toNewFormat(parent, parent.getId()); | ||||
|                 return this.openmct.objects.isPersistable(newStyleObject); | ||||
|                 var identifier = objectUtils.parseKeyString(parent.getId()); | ||||
|                 var provider = this.openmct.objects.getProvider(identifier); | ||||
|                 return provider.save !== undefined; | ||||
|             } | ||||
|             return true; | ||||
|         }; | ||||
|   | ||||
| @@ -33,7 +33,7 @@ define( | ||||
|  | ||||
|             beforeEach(function () { | ||||
|                 objectAPI = jasmine.createSpyObj('objectsAPI', [ | ||||
|                     'isPersistable' | ||||
|                     'getProvider' | ||||
|                 ]); | ||||
|  | ||||
|                 mockOpenMCT = { | ||||
| @@ -51,6 +51,10 @@ define( | ||||
|                     'isEditContextRoot' | ||||
|                 ]); | ||||
|                 mockParent.getCapability.and.returnValue(mockEditorCapability); | ||||
|  | ||||
|                 objectAPI.getProvider.and.returnValue({ | ||||
|                     save: function () {} | ||||
|                 }); | ||||
|                 persistableCompositionPolicy = new PersistableCompositionPolicy(mockOpenMCT); | ||||
|             }); | ||||
|  | ||||
| @@ -61,22 +65,19 @@ define( | ||||
|  | ||||
|             it("Does not allow composition for objects that are not persistable", function () { | ||||
|                 mockEditorCapability.isEditContextRoot.and.returnValue(false); | ||||
|                 objectAPI.isPersistable.and.returnValue(true); | ||||
|                 expect(persistableCompositionPolicy.allow(mockParent, mockChild)).toBe(true); | ||||
|                 objectAPI.isPersistable.and.returnValue(false); | ||||
|                 objectAPI.getProvider.and.returnValue({}); | ||||
|                 expect(persistableCompositionPolicy.allow(mockParent, mockChild)).toBe(false); | ||||
|             }); | ||||
|  | ||||
|             it("Always allows composition of objects in edit mode to support object creation", function () { | ||||
|                 mockEditorCapability.isEditContextRoot.and.returnValue(true); | ||||
|                 objectAPI.isPersistable.and.returnValue(true); | ||||
|                 expect(persistableCompositionPolicy.allow(mockParent, mockChild)).toBe(true); | ||||
|                 expect(objectAPI.isPersistable).not.toHaveBeenCalled(); | ||||
|                 expect(objectAPI.getProvider).not.toHaveBeenCalled(); | ||||
|  | ||||
|                 mockEditorCapability.isEditContextRoot.and.returnValue(false); | ||||
|                 objectAPI.isPersistable.and.returnValue(true); | ||||
|                 expect(persistableCompositionPolicy.allow(mockParent, mockChild)).toBe(true); | ||||
|                 expect(objectAPI.isPersistable).toHaveBeenCalled(); | ||||
|                 expect(objectAPI.getProvider).toHaveBeenCalled(); | ||||
|             }); | ||||
|  | ||||
|         }); | ||||
|   | ||||
| @@ -297,8 +297,7 @@ define([ | ||||
|                             "persistenceService", | ||||
|                             "identifierService", | ||||
|                             "notificationService", | ||||
|                             "$q", | ||||
|                             "openmct" | ||||
|                             "$q" | ||||
|                         ] | ||||
|                     }, | ||||
|                     { | ||||
|   | ||||
| @@ -20,8 +20,8 @@ | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| define(["objectUtils"], | ||||
|     function (objectUtils) { | ||||
| define( | ||||
|     function () { | ||||
|  | ||||
|         /** | ||||
|          * Defines the `persistence` capability, used to trigger the | ||||
| @@ -47,7 +47,6 @@ define(["objectUtils"], | ||||
|             identifierService, | ||||
|             notificationService, | ||||
|             $q, | ||||
|             openmct, | ||||
|             domainObject | ||||
|         ) { | ||||
|             // Cache modified timestamp | ||||
| @@ -59,7 +58,6 @@ define(["objectUtils"], | ||||
|             this.persistenceService = persistenceService; | ||||
|             this.notificationService = notificationService; | ||||
|             this.$q = $q; | ||||
|             this.openmct = openmct; | ||||
|         } | ||||
|  | ||||
|         /** | ||||
| @@ -68,7 +66,7 @@ define(["objectUtils"], | ||||
|          */ | ||||
|         function rejectIfFalsey(value, $q) { | ||||
|             if (!value) { | ||||
|                 return Promise.reject("Error persisting object"); | ||||
|                 return $q.reject("Error persisting object"); | ||||
|             } else { | ||||
|                 return value; | ||||
|             } | ||||
| @@ -100,7 +98,7 @@ define(["objectUtils"], | ||||
|                 dismissable: true | ||||
|             }); | ||||
|  | ||||
|             return Promise.reject(error); | ||||
|             return $q.reject(error); | ||||
|         } | ||||
|  | ||||
|         /** | ||||
| @@ -112,16 +110,34 @@ define(["objectUtils"], | ||||
|          */ | ||||
|         PersistenceCapability.prototype.persist = function () { | ||||
|             var self = this, | ||||
|                 domainObject = this.domainObject; | ||||
|                 domainObject = this.domainObject, | ||||
|                 model = domainObject.getModel(), | ||||
|                 modified = model.modified, | ||||
|                 persisted = model.persisted, | ||||
|                 persistenceService = this.persistenceService, | ||||
|                 persistenceFn = persisted !== undefined ? | ||||
|                     this.persistenceService.updateObject : | ||||
|                     this.persistenceService.createObject; | ||||
|  | ||||
|             let newStyleObject = objectUtils.toNewFormat(domainObject.getModel(), domainObject.getId()); | ||||
|             return this.openmct.objects | ||||
|                 .save(newStyleObject) | ||||
|                 .then(function (result) { | ||||
|                     return rejectIfFalsey(result, self.$q); | ||||
|                 }).catch(function (error) { | ||||
|                     return notifyOnError(error, domainObject, self.notificationService, self.$q); | ||||
|                 }); | ||||
|             if (persisted !== undefined && persisted === modified) { | ||||
|                 return this.$q.when(true); | ||||
|             } | ||||
|  | ||||
|             // Update persistence timestamp... | ||||
|             domainObject.useCapability("mutation", function (m) { | ||||
|                 m.persisted = modified; | ||||
|             }, modified); | ||||
|  | ||||
|             // ...and persist | ||||
|             return persistenceFn.apply(persistenceService, [ | ||||
|                 this.getSpace(), | ||||
|                 this.getKey(), | ||||
|                 domainObject.getModel() | ||||
|             ]).then(function (result) { | ||||
|                 return rejectIfFalsey(result, self.$q); | ||||
|             }).catch(function (error) { | ||||
|                 return notifyOnError(error, domainObject, self.notificationService, self.$q); | ||||
|             }); | ||||
|         }; | ||||
|  | ||||
|         /** | ||||
|   | ||||
| @@ -19,6 +19,7 @@ | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| /** | ||||
|  * PersistenceCapabilitySpec. Created by vwoeltje on 11/6/14. | ||||
|  */ | ||||
| @@ -39,8 +40,7 @@ define( | ||||
|                 model, | ||||
|                 SPACE = "some space", | ||||
|                 persistence, | ||||
|                 mockOpenMCT, | ||||
|                 mockNewStyleDomainObject; | ||||
|                 happyPromise; | ||||
|  | ||||
|             function asPromise(value, doCatch) { | ||||
|                 return (value || {}).then ? value : { | ||||
| @@ -56,6 +56,7 @@ define( | ||||
|             } | ||||
|  | ||||
|             beforeEach(function () { | ||||
|                 happyPromise = asPromise(true); | ||||
|                 model = { someKey: "some value", name: "domain object"}; | ||||
|  | ||||
|                 mockPersistenceService = jasmine.createSpyObj( | ||||
| @@ -93,23 +94,12 @@ define( | ||||
|                     }, | ||||
|                     useCapability: jasmine.createSpy() | ||||
|                 }; | ||||
|  | ||||
|                 mockNewStyleDomainObject = Object.assign({}, model); | ||||
|                 mockNewStyleDomainObject.identifier = { | ||||
|                     namespace: "", | ||||
|                     key: id | ||||
|                 } | ||||
|  | ||||
|                 // Simulate mutation capability | ||||
|                 mockDomainObject.useCapability.and.callFake(function (capability, mutator) { | ||||
|                     if (capability === 'mutation') { | ||||
|                         model = mutator(model) || model; | ||||
|                     } | ||||
|                 }); | ||||
|  | ||||
|                 mockOpenMCT = {}; | ||||
|                 mockOpenMCT.objects = jasmine.createSpyObj('Object API', ['save']); | ||||
|  | ||||
|                 mockIdentifierService.parse.and.returnValue(mockIdentifier); | ||||
|                 mockIdentifier.getSpace.and.returnValue(SPACE); | ||||
|                 mockIdentifier.getKey.and.returnValue(key); | ||||
| @@ -120,28 +110,51 @@ define( | ||||
|                     mockIdentifierService, | ||||
|                     mockNofificationService, | ||||
|                     mockQ, | ||||
|                     mockOpenMCT, | ||||
|                     mockDomainObject | ||||
|                 ); | ||||
|             }); | ||||
|  | ||||
|             describe("successful persistence", function () { | ||||
|                 beforeEach(function () { | ||||
|                     mockOpenMCT.objects.save.and.returnValue(Promise.resolve(true)); | ||||
|                     mockPersistenceService.updateObject.and.returnValue(happyPromise); | ||||
|                     mockPersistenceService.createObject.and.returnValue(happyPromise); | ||||
|                 }); | ||||
|                 it("creates unpersisted objects with the persistence service", function () { | ||||
|                     // Verify precondition; no call made during constructor | ||||
|                     expect(mockOpenMCT.objects.save).not.toHaveBeenCalled(); | ||||
|                     expect(mockPersistenceService.createObject).not.toHaveBeenCalled(); | ||||
|  | ||||
|                     persistence.persist(); | ||||
|  | ||||
|                     expect(mockOpenMCT.objects.save).toHaveBeenCalledWith(mockNewStyleDomainObject); | ||||
|                     expect(mockPersistenceService.createObject).toHaveBeenCalledWith( | ||||
|                         SPACE, | ||||
|                         key, | ||||
|                         model | ||||
|                     ); | ||||
|                 }); | ||||
|  | ||||
|                 it("updates previously persisted objects with the persistence service", function () { | ||||
|                     // Verify precondition; no call made during constructor | ||||
|                     expect(mockPersistenceService.updateObject).not.toHaveBeenCalled(); | ||||
|  | ||||
|                     model.persisted = 12321; | ||||
|                     persistence.persist(); | ||||
|  | ||||
|                     expect(mockPersistenceService.updateObject).toHaveBeenCalledWith( | ||||
|                         SPACE, | ||||
|                         key, | ||||
|                         model | ||||
|                     ); | ||||
|                 }); | ||||
|  | ||||
|                 it("reports which persistence space an object belongs to", function () { | ||||
|                     expect(persistence.getSpace()).toEqual(SPACE); | ||||
|                 }); | ||||
|  | ||||
|                 it("updates persisted timestamp on persistence", function () { | ||||
|                     model.modified = 12321; | ||||
|                     persistence.persist(); | ||||
|                     expect(model.persisted).toEqual(12321); | ||||
|                 }); | ||||
|                 it("refreshes the domain object model from persistence", function () { | ||||
|                     var refreshModel = {someOtherKey: "some other value"}; | ||||
|                     model.persisted = 1; | ||||
| @@ -152,37 +165,30 @@ define( | ||||
|  | ||||
|                 it("does not trigger error notification on successful" + | ||||
|                     " persistence", function () { | ||||
|                     let rejected = false; | ||||
|                     return persistence.persist() | ||||
|                         .catch(() => rejected = true) | ||||
|                         .then(() => { | ||||
|                             expect(rejected).toBe(false); | ||||
|                             expect(mockNofificationService.error).not.toHaveBeenCalled(); | ||||
|                         }); | ||||
|                     persistence.persist(); | ||||
|                     expect(mockQ.reject).not.toHaveBeenCalled(); | ||||
|                     expect(mockNofificationService.error).not.toHaveBeenCalled(); | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|             describe("unsuccessful persistence", function () { | ||||
|                 var sadPromise = { | ||||
|                     then: function (callback) { | ||||
|                         return asPromise(callback(0), true); | ||||
|                     } | ||||
|                 }; | ||||
|                 beforeEach(function () { | ||||
|                     mockOpenMCT.objects.save.and.returnValue(Promise.resolve(false)); | ||||
|                     mockPersistenceService.createObject.and.returnValue(sadPromise); | ||||
|                 }); | ||||
|                 it("rejects on falsey persistence result", function () { | ||||
|                     let rejected = false; | ||||
|                     return persistence.persist() | ||||
|                         .catch(() => rejected = true) | ||||
|                         .then(() => { | ||||
|                             expect(rejected).toBe(true); | ||||
|                         }); | ||||
|                     persistence.persist(); | ||||
|                     expect(mockQ.reject).toHaveBeenCalled(); | ||||
|                 }); | ||||
|  | ||||
|                 it("notifies user on persistence failure", function () { | ||||
|                     let rejected = false; | ||||
|                     return persistence.persist() | ||||
|                         .catch(() => rejected = true) | ||||
|                         .then(() => { | ||||
|                             expect(rejected).toBe(true); | ||||
|                             expect(mockNofificationService.error).toHaveBeenCalled(); | ||||
|                         }); | ||||
|                     persistence.persist(); | ||||
|                     expect(mockQ.reject).toHaveBeenCalled(); | ||||
|                     expect(mockNofificationService.error).toHaveBeenCalled(); | ||||
|                 }); | ||||
|             }); | ||||
|         }); | ||||
|   | ||||
| @@ -29,9 +29,9 @@ | ||||
|                        type="text" tabindex="10000" | ||||
|                        ng-model="ngModel.input" | ||||
|                        ng-keyup="controller.search()"/> | ||||
|                 <button class="c-search__clear-input clear-icon icon-x-in-circle" | ||||
|                 <a class="c-search__clear-input clear-icon icon-x-in-circle" | ||||
|                    ng-class="{show: !(ngModel.input === '' || ngModel.input === undefined)}" | ||||
|                    ng-click="ngModel.input = ''; controller.search()"></button> | ||||
|                    ng-click="ngModel.input = ''; controller.search()"></a> | ||||
|                 <!-- To prevent double triggering of clicks on click away, render | ||||
|                    non-clickable version of the button when menu active--> | ||||
|                 <a ng-if="!toggle.isActive()" class="menu-icon context-available" | ||||
| @@ -45,16 +45,16 @@ | ||||
|                 </mct-include> | ||||
|             </div> | ||||
|  | ||||
|             <button class="c-button c-search__btn-cancel" | ||||
|             <a class="c-button c-search__btn-cancel" | ||||
|                ng-show="!(ngModel.input === '' || ngModel.input === undefined)" | ||||
|                ng-click="ngModel.input = ''; ngModel.checkAll = true; menuController.checkAll(); controller.search()"> | ||||
|                 Cancel</button> | ||||
|                 Cancel</a> | ||||
|         </div> | ||||
|  | ||||
|         <div class="active-filter-display flex-elem holder" | ||||
|              ng-class="{invisible: ngModel.filtersString === '' || ngModel.filtersString === undefined || !ngModel.search}"> | ||||
|             <button class="clear-filters icon-x-in-circle s-icon-button" | ||||
|                ng-click="ngModel.checkAll = true; menuController.checkAll()"></button>Filtered by: {{ ngModel.filtersString }} | ||||
|             <a class="clear-filters icon-x-in-circle s-icon-button" | ||||
|                ng-click="ngModel.checkAll = true; menuController.checkAll()"></a>Filtered by: {{ ngModel.filtersString }} | ||||
|         </div> | ||||
|  | ||||
|         <div class="flex-elem holder results-msg" ng-model="ngModel" ng-show="!loading && ngModel.search"> | ||||
| @@ -72,7 +72,7 @@ | ||||
|                                 ng-model="ngModel" | ||||
|                                 class="l-flex-row flex-elem grows"> | ||||
|             </mct-representation> | ||||
|             <button class="load-more-button s-button vsm" ng-if="controller.areMore()" ng-click="controller.loadMore()">More Results</button> | ||||
|             <a class="load-more-button s-button vsm" ng-if="controller.areMore()" ng-click="controller.loadMore()">More Results</a> | ||||
|         </div> | ||||
|     </div> | ||||
| </div> | ||||
|   | ||||
| @@ -25,11 +25,10 @@ define([ | ||||
| ], function ( | ||||
|     utils | ||||
| ) { | ||||
|     function ObjectServiceProvider(eventEmitter, objectService, instantiate, topic, $injector) { | ||||
|     function ObjectServiceProvider(eventEmitter, objectService, instantiate, topic) { | ||||
|         this.eventEmitter = eventEmitter; | ||||
|         this.objectService = objectService; | ||||
|         this.instantiate = instantiate; | ||||
|         this.$injector = $injector; | ||||
|  | ||||
|         this.generalTopic = topic('mutation'); | ||||
|         this.bridgeEventBuses(); | ||||
| @@ -69,53 +68,16 @@ define([ | ||||
|         removeGeneralTopicListener = this.generalTopic.listen(handleLegacyMutation); | ||||
|     }; | ||||
|  | ||||
|     ObjectServiceProvider.prototype.create = async function (object) { | ||||
|         let model = utils.toOldFormat(object); | ||||
|     ObjectServiceProvider.prototype.save = function (object) { | ||||
|         var key = object.key; | ||||
|  | ||||
|         return this.getPersistenceService().createObject( | ||||
|             this.getSpace(utils.makeKeyString(object.identifier)), | ||||
|             object.identifier.key, | ||||
|             model | ||||
|         ); | ||||
|     } | ||||
|     ObjectServiceProvider.prototype.update = async function (object) { | ||||
|         let model = utils.toOldFormat(object); | ||||
|  | ||||
|         return this.getPersistenceService().updateObject( | ||||
|             this.getSpace(utils.makeKeyString(object.identifier)), | ||||
|             object.identifier.key, | ||||
|             model | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get the space in which this domain object is persisted; | ||||
|      * this is useful when, for example, decided which space a | ||||
|      * newly-created domain object should be persisted to (by | ||||
|      * default, this should be the space of its containing | ||||
|      * object.) | ||||
|      * | ||||
|      * @returns {string} the name of the space which should | ||||
|      *          be used to persist this object | ||||
|      */ | ||||
|     ObjectServiceProvider.prototype.getSpace = function (keystring) { | ||||
|         return this.getIdentifierService().parse(keystring).getSpace(); | ||||
|         return object.getCapability('persistence') | ||||
|             .persist() | ||||
|             .then(function () { | ||||
|                 return utils.toNewFormat(object, key); | ||||
|             }); | ||||
|     }; | ||||
|  | ||||
|     ObjectServiceProvider.prototype.getIdentifierService = function () { | ||||
|         if (this.identifierService === undefined) { | ||||
|             this.identifierService = this.$injector.get('identifierService'); | ||||
|         } | ||||
|         return this.identifierService; | ||||
|     }; | ||||
|  | ||||
|     ObjectServiceProvider.prototype.getPersistenceService = function () { | ||||
|         if (this.persistenceService === undefined) { | ||||
|             this.persistenceService = this.$injector.get('persistenceService'); | ||||
|         } | ||||
|         return this.persistenceService; | ||||
|     } | ||||
|  | ||||
|     ObjectServiceProvider.prototype.delete = function (object) { | ||||
|         // TODO! | ||||
|     }; | ||||
| @@ -156,8 +118,7 @@ define([ | ||||
|                 eventEmitter, | ||||
|                 objectService, | ||||
|                 instantiate, | ||||
|                 topic, | ||||
|                 openmct.$injector | ||||
|                 topic | ||||
|             ) | ||||
|         ); | ||||
|  | ||||
|   | ||||
| @@ -101,25 +101,14 @@ define([ | ||||
|      */ | ||||
|  | ||||
|     /** | ||||
|      * Create the given domain object in the corresponding persistence store | ||||
|      * Save this domain object in its current state. | ||||
|      * | ||||
|      * @method create | ||||
|      * @method save | ||||
|      * @memberof module:openmct.ObjectProvider# | ||||
|      * @param {module:openmct.DomainObject} domainObject the domain object to | ||||
|      *        create | ||||
|      *        save | ||||
|      * @returns {Promise} a promise which will resolve when the domain object | ||||
|      *          has been created, or be rejected if it cannot be saved | ||||
|      */ | ||||
|  | ||||
|     /** | ||||
|      * Update this domain object in its persistence store | ||||
|      * | ||||
|      * @method update | ||||
|      * @memberof module:openmct.ObjectProvider# | ||||
|      * @param {module:openmct.DomainObject} domainObject the domain object to | ||||
|      *        update | ||||
|      * @returns {Promise} a promise which will resolve when the domain object | ||||
|      *          has been updated, or be rejected if it cannot be saved | ||||
|      *          has been saved, or be rejected if it cannot be saved | ||||
|      */ | ||||
|  | ||||
|     /** | ||||
| @@ -172,41 +161,8 @@ define([ | ||||
|         throw new Error('Delete not implemented'); | ||||
|     }; | ||||
|  | ||||
|     ObjectAPI.prototype.isPersistable = function (domainObject) { | ||||
|         let provider = this.getProvider(domainObject.identifier); | ||||
|         return provider !== undefined && | ||||
|             provider.create !== undefined && | ||||
|             provider.update !== undefined; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Save this domain object in its current state. EXPERIMENTAL | ||||
|      * | ||||
|      * @private | ||||
|      * @memberof module:openmct.ObjectAPI# | ||||
|      * @param {module:openmct.DomainObject} domainObject the domain object to | ||||
|      *        save | ||||
|      * @returns {Promise} a promise which will resolve when the domain object | ||||
|      *          has been saved, or be rejected if it cannot be saved | ||||
|      */ | ||||
|     ObjectAPI.prototype.save = function (domainObject) { | ||||
|         let provider = this.getProvider(domainObject.identifier); | ||||
|         let result; | ||||
|  | ||||
|         if (!this.isPersistable(domainObject)) { | ||||
|             result = Promise.reject('Object provider does not support saving'); | ||||
|         } else if (hasAlreadyBeenPersisted(domainObject)) { | ||||
|             result = Promise.resolve(true); | ||||
|         } else { | ||||
|             if (domainObject.persisted === undefined) { | ||||
|                 this.mutate(domainObject, 'persisted', domainObject.modified); | ||||
|                 result = provider.create(domainObject); | ||||
|             } else { | ||||
|                 this.mutate(domainObject, 'persisted', domainObject.modified); | ||||
|                 result = provider.update(domainObject); | ||||
|             } | ||||
|         } | ||||
|         return result; | ||||
|     ObjectAPI.prototype.save = function () { | ||||
|         throw new Error('Save not implemented'); | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
| @@ -320,9 +276,5 @@ define([ | ||||
|      * @memberof module:openmct | ||||
|      */ | ||||
|  | ||||
|     function hasAlreadyBeenPersisted(domainObject) { | ||||
|         return domainObject.persisted !== undefined && | ||||
|             domainObject.persisted === domainObject.modified; | ||||
|     } | ||||
|     return ObjectAPI; | ||||
| }); | ||||
|   | ||||
| @@ -1,60 +0,0 @@ | ||||
| import ObjectAPI from './ObjectAPI.js'; | ||||
|  | ||||
| describe("The Object API", () => { | ||||
|     let objectAPI; | ||||
|     let mockDomainObject; | ||||
|     const TEST_NAMESPACE = "test-namespace"; | ||||
|     const FIFTEEN_MINUTES = 15 * 60 * 1000; | ||||
|  | ||||
|     beforeEach(() => { | ||||
|         objectAPI = new ObjectAPI(); | ||||
|         mockDomainObject = { | ||||
|             identifier: { | ||||
|                 namespace: TEST_NAMESPACE, | ||||
|                 key: "test-key" | ||||
|             }, | ||||
|             name: "test object", | ||||
|             type: "test-type" | ||||
|         }; | ||||
|     }) | ||||
|     describe("The save function", () => { | ||||
|         it("Rejects if no provider available", () => { | ||||
|             let rejected = false; | ||||
|             return objectAPI.save(mockDomainObject) | ||||
|                 .catch(() => rejected = true) | ||||
|                 .then(() => expect(rejected).toBe(true)); | ||||
|         }); | ||||
|         describe("when a provider is available", () => { | ||||
|             let mockProvider; | ||||
|             beforeEach(() => { | ||||
|                 mockProvider = jasmine.createSpyObj("mock provider", [ | ||||
|                     "create", | ||||
|                     "update" | ||||
|                 ]); | ||||
|                 objectAPI.addProvider(TEST_NAMESPACE, mockProvider); | ||||
|             }) | ||||
|             it("Calls 'create' on provider if object is new", () => { | ||||
|                 objectAPI.save(mockDomainObject); | ||||
|                 expect(mockProvider.create).toHaveBeenCalled(); | ||||
|                 expect(mockProvider.update).not.toHaveBeenCalled(); | ||||
|             }); | ||||
|             it("Calls 'update' on provider if object is not new", () => { | ||||
|                 mockDomainObject.persisted = Date.now() - FIFTEEN_MINUTES; | ||||
|                 mockDomainObject.modified = Date.now(); | ||||
|  | ||||
|                 objectAPI.save(mockDomainObject); | ||||
|                 expect(mockProvider.create).not.toHaveBeenCalled(); | ||||
|                 expect(mockProvider.update).toHaveBeenCalled(); | ||||
|             }); | ||||
|  | ||||
|             it("Does not persist if the object is unchanged", () => { | ||||
|                 mockDomainObject.persisted = | ||||
|                     mockDomainObject.modified = Date.now(); | ||||
|  | ||||
|                 objectAPI.save(mockDomainObject); | ||||
|                 expect(mockProvider.create).not.toHaveBeenCalled(); | ||||
|                 expect(mockProvider.update).not.toHaveBeenCalled(); | ||||
|             }); | ||||
|         }); | ||||
|     }) | ||||
| }); | ||||
| @@ -7,7 +7,7 @@ | ||||
|     <div class="c-overlay__outer"> | ||||
|         <button | ||||
|             v-if="dismissable" | ||||
|             class="c-click-icon c-overlay__close-button icon-x" | ||||
|             class="c-click-icon c-overlay__close-button icon-x-in-circle" | ||||
|             @click="destroy" | ||||
|         ></button> | ||||
|         <div | ||||
|   | ||||
| @@ -29,12 +29,13 @@ | ||||
|     } | ||||
|  | ||||
|     &__close-button { | ||||
|         $p: $interiorMargin + 2px; | ||||
|         $p: $interiorMargin; | ||||
|         border-radius: 100% !important; | ||||
|         color: $overlayColorFg; | ||||
|         font-size: 1.5em; | ||||
|         display: inline-block; | ||||
|         font-size: 1.25em; | ||||
|         position: absolute; | ||||
|         top: $p; right: $p; | ||||
|         z-index: 99; | ||||
|     } | ||||
|  | ||||
|     &__contents { | ||||
| @@ -42,7 +43,7 @@ | ||||
|         display: flex; | ||||
|         flex-direction: column; | ||||
|         outline: none; | ||||
|         overflow: auto; | ||||
|         overflow: hidden; | ||||
|     } | ||||
|  | ||||
|     &__top-bar { | ||||
| @@ -86,10 +87,6 @@ | ||||
|     .c-click-icon { | ||||
|         filter: $overlayBrightnessAdjust; | ||||
|     } | ||||
|  | ||||
|     .c-object-label__name { | ||||
|         filter: $objectLabelNameFilter; | ||||
|     } | ||||
| } | ||||
|  | ||||
| body.desktop { | ||||
| @@ -103,6 +100,7 @@ body.desktop { | ||||
|     } | ||||
|  | ||||
|     // Overlay types, styling for desktop. Appended to .l-overlay-wrapper element. | ||||
|     .l-overlay-large, | ||||
|     .l-overlay-small, | ||||
|     .l-overlay-fit { | ||||
|         .c-overlay__outer { | ||||
| @@ -120,28 +118,8 @@ body.desktop { | ||||
|  | ||||
|     .l-overlay-large { | ||||
|         // Default | ||||
|         $pad: $interiorMarginLg; | ||||
|         $tbPad: floor($pad * 0.8); | ||||
|         $lrPad: $pad; | ||||
|         .c-overlay { | ||||
|             &__blocker { | ||||
|                 display: none; | ||||
|             } | ||||
|  | ||||
|             &__outer { | ||||
|                 @include overlaySizing($overlayOuterMarginFullscreen); | ||||
|                 padding: $tbPad $lrPad; | ||||
|             } | ||||
|  | ||||
|             &__close-button { | ||||
|                 //top: $interiorMargin; | ||||
|                 //right: $interiorMargin; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         .l-browse-bar { | ||||
|             margin-right: 50px; // Don't cover close button | ||||
|             margin-bottom: $interiorMargin; | ||||
|         .c-overlay__outer { | ||||
|             @include overlaySizing($overlayOuterMarginLg); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -161,4 +139,4 @@ body.desktop { | ||||
|             min-width: 20%; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -334,8 +334,8 @@ define([ | ||||
|             }); | ||||
|             if (subscriber.callbacks.length === 0) { | ||||
|                 subscriber.unsubscribe(); | ||||
|                 delete this.subscribeCache[keyString]; | ||||
|             } | ||||
|             delete this.subscribeCache[keyString]; | ||||
|         }.bind(this); | ||||
|     }; | ||||
|  | ||||
|   | ||||
| @@ -156,29 +156,6 @@ define([ | ||||
|                 expect(callbacktwo).not.toHaveBeenCalledWith('anotherValue'); | ||||
|             }); | ||||
|  | ||||
|             it('only deletes subscription cache when there are no more subscribers', function () { | ||||
|                 var unsubFunc = jasmine.createSpy('unsubscribe'); | ||||
|                 telemetryProvider.subscribe.and.returnValue(unsubFunc); | ||||
|                 telemetryProvider.supportsSubscribe.and.returnValue(true); | ||||
|                 telemetryAPI.addProvider(telemetryProvider); | ||||
|  | ||||
|                 var callback = jasmine.createSpy('callback'); | ||||
|                 var callbacktwo = jasmine.createSpy('callback two'); | ||||
|                 var callbackThree = jasmine.createSpy('callback three'); | ||||
|                 var unsubscribe = telemetryAPI.subscribe(domainObject, callback); | ||||
|                 var unsubscribeTwo = telemetryAPI.subscribe(domainObject, callbacktwo); | ||||
|  | ||||
|                 expect(telemetryProvider.subscribe.calls.count()).toBe(1); | ||||
|                 unsubscribe(); | ||||
|                 var unsubscribeThree = telemetryAPI.subscribe(domainObject, callbackThree); | ||||
|                 // Regression test for where subscription cache was deleted on each unsubscribe, resulting in | ||||
|                 // superfluous additional subscriptions. If the subscription cache is being deleted on each unsubscribe, | ||||
|                 // then a subsequent subscribe will result in a new subscription at the provider. | ||||
|                 expect(telemetryProvider.subscribe.calls.count()).toBe(1); | ||||
|                 unsubscribeTwo(); | ||||
|                 unsubscribeThree(); | ||||
|             }); | ||||
|  | ||||
|             it('does subscribe/unsubscribe', function () { | ||||
|                 var unsubFunc = jasmine.createSpy('unsubscribe'); | ||||
|                 telemetryProvider.subscribe.and.returnValue(unsubFunc); | ||||
|   | ||||
| @@ -64,7 +64,7 @@ export default { | ||||
|     }, | ||||
|     computed: { | ||||
|         formattedTimestamp() { | ||||
|             return this.timestamp !== undefined ? this.getFormattedTimestamp(this.timestamp) : '---'; | ||||
|             return this.timestamp !== undefined ? this.formats[this.timestampKey].format(this.timestamp) : '---'; | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
| @@ -110,11 +110,11 @@ export default { | ||||
|     }, | ||||
|     methods: { | ||||
|         updateValues(datum) { | ||||
|             let newTimestamp = this.getParsedTimestamp(datum), | ||||
|             let newTimestamp = this.formats[this.timestampKey].parse(datum), | ||||
|                 limit; | ||||
|  | ||||
|             if(this.shouldUpdate(newTimestamp)) { | ||||
|                 this.timestamp = newTimestamp; | ||||
|                 this.timestamp = this.formats[this.timestampKey].parse(datum); | ||||
|                 this.value = this.formats[this.valueKey].format(datum); | ||||
|                 limit = this.limitEvaluator.evaluate(datum, this.valueMetadata); | ||||
|                 if (limit) { | ||||
| @@ -125,12 +125,9 @@ export default { | ||||
|             } | ||||
|         }, | ||||
|         shouldUpdate(newTimestamp) { | ||||
|             let newTimestampInBounds = this.inBounds(newTimestamp), | ||||
|                 noExistingTimestamp = this.timestamp === undefined, | ||||
|                 newTimestampIsLatest = newTimestamp > this.timestamp; | ||||
|  | ||||
|             return newTimestampInBounds && | ||||
|                 (noExistingTimestamp || newTimestampIsLatest); | ||||
|             return (this.timestamp === undefined) || | ||||
|                 (this.inBounds(newTimestamp) && | ||||
|                 newTimestamp > this.timestamp); | ||||
|         }, | ||||
|         requestHistory() { | ||||
|             this.openmct | ||||
| @@ -149,7 +146,6 @@ export default { | ||||
|         updateBounds(bounds, isTick) { | ||||
|             this.bounds = bounds; | ||||
|             if(!isTick) { | ||||
|                 this.resetValues(); | ||||
|                 this.requestHistory(); | ||||
|             } | ||||
|         }, | ||||
| @@ -157,34 +153,13 @@ export default { | ||||
|             return timestamp >= this.bounds.start && timestamp <= this.bounds.end; | ||||
|         }, | ||||
|         updateTimeSystem(timeSystem) { | ||||
|             this.resetValues(); | ||||
|             this.value = '---'; | ||||
|             this.timestamp = '---'; | ||||
|             this.valueClass = ''; | ||||
|             this.timestampKey = timeSystem.key; | ||||
|         }, | ||||
|         showContextMenu(event) { | ||||
|             this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS); | ||||
|         }, | ||||
|         resetValues() { | ||||
|             this.value = '---'; | ||||
|             this.timestamp = undefined; | ||||
|             this.valueClass = ''; | ||||
|         }, | ||||
|         getParsedTimestamp(timestamp) { | ||||
|             if(this.timeSystemFormat()) { | ||||
|                 return this.formats[this.timestampKey].parse(timestamp); | ||||
|             } | ||||
|         }, | ||||
|         getFormattedTimestamp(timestamp) { | ||||
|             if(this.timeSystemFormat()) { | ||||
|                 return this.formats[this.timestampKey].format(timestamp); | ||||
|             } | ||||
|         }, | ||||
|         timeSystemFormat() { | ||||
|             if(this.formats[this.timestampKey]) { | ||||
|                 return true; | ||||
|             } else { | ||||
|                 console.warn(`No formatter for ${this.timestampKey} time system for ${this.domainObject.name}.`); | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -29,28 +29,24 @@ define([ | ||||
|     ClearDataAction, | ||||
|     Vue | ||||
| ) { | ||||
|     return function plugin(appliesToObjects, options = {indicator: true}) { | ||||
|         let installIndicator = options.indicator; | ||||
|  | ||||
|     return function plugin(appliesToObjects) { | ||||
|         appliesToObjects = appliesToObjects || []; | ||||
|  | ||||
|         return function install(openmct) { | ||||
|             if (installIndicator) { | ||||
|                 let component = new Vue ({ | ||||
|                         provide: { | ||||
|                             openmct | ||||
|                         }, | ||||
|                         components: { | ||||
|                             GlobalClearIndicator: GlobaClearIndicator.default | ||||
|                         }, | ||||
|                         template: '<GlobalClearIndicator></GlobalClearIndicator>' | ||||
|                     }), | ||||
|                     indicator = { | ||||
|                         element: component.$mount().$el | ||||
|                     }; | ||||
|             let component = new Vue ({ | ||||
|                     provide: { | ||||
|                         openmct | ||||
|                     }, | ||||
|                     components: { | ||||
|                         GlobalClearIndicator: GlobaClearIndicator.default | ||||
|                     }, | ||||
|                     template: '<GlobalClearIndicator></GlobalClearIndicator>' | ||||
|                 }), | ||||
|                 indicator = { | ||||
|                     element: component.$mount().$el | ||||
|                 }; | ||||
|  | ||||
|                 openmct.indicators.add(indicator); | ||||
|             } | ||||
|             openmct.indicators.add(indicator); | ||||
|  | ||||
|             openmct.contextMenu.registerAction(new ClearDataAction.default(openmct, appliesToObjects)); | ||||
|         }; | ||||
|   | ||||
| @@ -150,7 +150,6 @@ export default class Condition extends EventEmitter { | ||||
|             criterion = new TelemetryCriterion(criterionConfigurationWithId, this.openmct); | ||||
|         } | ||||
|         criterion.on('criterionUpdated', (obj) => this.handleCriterionUpdated(obj)); | ||||
|         criterion.on('telemetryIsStale', (obj) => this.handleStaleCriterion(obj)); | ||||
|         if (!this.criteria) { | ||||
|             this.criteria = []; | ||||
|         } | ||||
| @@ -179,12 +178,10 @@ export default class Condition extends EventEmitter { | ||||
|             const newCriterionConfiguration = this.generateCriterion(criterionConfiguration); | ||||
|             let newCriterion = new TelemetryCriterion(newCriterionConfiguration, this.openmct); | ||||
|             newCriterion.on('criterionUpdated', (obj) => this.handleCriterionUpdated(obj)); | ||||
|             newCriterion.on('telemetryIsStale', (obj) => this.handleStaleCriterion(obj)); | ||||
|  | ||||
|             let criterion = found.item; | ||||
|             criterion.unsubscribe(); | ||||
|             criterion.off('criterionUpdated', (obj) => this.handleCriterionUpdated(obj)); | ||||
|             criterion.off('telemetryIsStale', (obj) => this.handleStaleCriterion(obj)); | ||||
|             this.criteria.splice(found.index, 1, newCriterion); | ||||
|             this.updateDescription(); | ||||
|         } | ||||
| @@ -197,9 +194,6 @@ export default class Condition extends EventEmitter { | ||||
|             criterion.off('criterionUpdated', (obj) => { | ||||
|                 this.handleCriterionUpdated(obj); | ||||
|             }); | ||||
|             criterion.off('telemetryIsStale', (obj) => { | ||||
|                 this.handleStaleCriterion(obj); | ||||
|             }); | ||||
|             criterion.destroy(); | ||||
|             this.criteria.splice(found.index, 1); | ||||
|             this.updateDescription(); | ||||
| @@ -217,18 +211,6 @@ export default class Condition extends EventEmitter { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     handleStaleCriterion(updatedCriterion) { | ||||
|         this.result = evaluateResults(this.criteria.map(criterion => criterion.result), this.trigger); | ||||
|         let latestTimestamp = {}; | ||||
|         latestTimestamp = getLatestTimestamp( | ||||
|             latestTimestamp, | ||||
|             updatedCriterion.data, | ||||
|             this.timeSystems, | ||||
|             this.openmct.time.timeSystem() | ||||
|         ); | ||||
|         this.conditionManager.updateCurrentCondition(latestTimestamp); | ||||
|     } | ||||
|  | ||||
|     updateDescription() { | ||||
|         const triggerDescription = this.getTriggerDescription(); | ||||
|         let description = ''; | ||||
|   | ||||
| @@ -103,8 +103,6 @@ export default class ConditionManager extends EventEmitter { | ||||
|                         criterion.operation = ''; | ||||
|                         conditionChanged = true; | ||||
|                     } | ||||
|                 } else { | ||||
|                     conditionChanged = true; | ||||
|                 } | ||||
|             }); | ||||
|             if (conditionChanged) { | ||||
| @@ -317,10 +315,6 @@ export default class ConditionManager extends EventEmitter { | ||||
|             condition.getResult(normalizedDatum); | ||||
|         }); | ||||
|  | ||||
|         this.updateCurrentCondition(timestamp); | ||||
|     } | ||||
|  | ||||
|     updateCurrentCondition(timestamp) { | ||||
|         const currentCondition = this.getCurrentCondition(); | ||||
|  | ||||
|         this.emit('conditionSetResultUpdated', | ||||
|   | ||||
| @@ -46,7 +46,6 @@ export default class StyleRuleManager extends EventEmitter { | ||||
|         if (this.isEditing) { | ||||
|             if (this.stopProvidingTelemetry) { | ||||
|                 this.stopProvidingTelemetry(); | ||||
|                 delete this.stopProvidingTelemetry; | ||||
|             } | ||||
|             if (this.conditionSetIdentifier) { | ||||
|                 this.applySelectedConditionStyle(); | ||||
| @@ -67,7 +66,6 @@ export default class StyleRuleManager extends EventEmitter { | ||||
|     subscribeToConditionSet() { | ||||
|         if (this.stopProvidingTelemetry) { | ||||
|             this.stopProvidingTelemetry(); | ||||
|             delete this.stopProvidingTelemetry; | ||||
|         } | ||||
|         this.openmct.objects.get(this.conditionSetIdentifier).then((conditionSetDomainObject) => { | ||||
|             this.openmct.telemetry.request(conditionSetDomainObject) | ||||
| @@ -156,8 +154,8 @@ export default class StyleRuleManager extends EventEmitter { | ||||
|         this.applyStaticStyle(); | ||||
|         if (this.stopProvidingTelemetry) { | ||||
|             this.stopProvidingTelemetry(); | ||||
|             delete this.stopProvidingTelemetry; | ||||
|         } | ||||
|         delete this.stopProvidingTelemetry; | ||||
|         this.conditionSetIdentifier = undefined; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -55,7 +55,6 @@ | ||||
|                 > | ||||
|                     {{ option.name }} | ||||
|                 </option> | ||||
|                 <option value="dataReceived">any data received</option> | ||||
|             </select> | ||||
|         </span> | ||||
|         <span v-if="criterion.telemetry && criterion.metadata" | ||||
| @@ -84,7 +83,6 @@ | ||||
|                     > | ||||
|                     <span v-if="inputIndex < inputCount-1">and</span> | ||||
|                 </span> | ||||
|                 <span v-if="criterion.metadata === 'dataReceived'">seconds</span> | ||||
|             </template> | ||||
|             <span v-else> | ||||
|                 <span v-if="inputCount && criterion.operation" | ||||
| @@ -150,11 +148,7 @@ export default { | ||||
|             return (this.index !== 0 ? operator : '') + ' when'; | ||||
|         }, | ||||
|         filteredOps: function () { | ||||
|             if (this.criterion.metadata === 'dataReceived') { | ||||
|                 return this.operations.filter(op => op.name === 'isStale'); | ||||
|             } else { | ||||
|                 return this.operations.filter(op => op.appliesTo.indexOf(this.operationFormat) !== -1); | ||||
|             } | ||||
|             return this.operations.filter(op => op.appliesTo.indexOf(this.operationFormat) !== -1); | ||||
|         }, | ||||
|         setInputType: function () { | ||||
|             let type = ''; | ||||
| @@ -220,8 +214,6 @@ export default { | ||||
|                 } else { | ||||
|                     this.operationFormat = 'number'; | ||||
|                 } | ||||
|             } else if (this.criterion.metadata === 'dataReceived') { | ||||
|                 this.operationFormat = 'number'; | ||||
|             } | ||||
|             this.updateInputVisibilityAndValues(); | ||||
|         }, | ||||
|   | ||||
| @@ -197,7 +197,6 @@ export default { | ||||
|             } | ||||
|             if (this.stopProvidingTelemetry) { | ||||
|                 this.stopProvidingTelemetry(); | ||||
|                 delete this.stopProvidingTelemetry; | ||||
|             } | ||||
|         }, | ||||
|         initialize(conditionSetDomainObject) { | ||||
| @@ -211,7 +210,6 @@ export default { | ||||
|             if (this.isEditing) { | ||||
|                 if (this.stopProvidingTelemetry) { | ||||
|                     this.stopProvidingTelemetry(); | ||||
|                     delete this.stopProvidingTelemetry; | ||||
|                 } | ||||
|             } else { | ||||
|                 this.subscribeToConditionSet(); | ||||
| @@ -309,7 +307,6 @@ export default { | ||||
|             this.persist(domainObjectStyles); | ||||
|             if (this.stopProvidingTelemetry) { | ||||
|                 this.stopProvidingTelemetry(); | ||||
|                 delete this.stopProvidingTelemetry; | ||||
|             } | ||||
|         }, | ||||
|         updateDomainObjectItemStyles(newItems) { | ||||
| @@ -378,7 +375,6 @@ export default { | ||||
|         subscribeToConditionSet() { | ||||
|             if (this.stopProvidingTelemetry) { | ||||
|                 this.stopProvidingTelemetry(); | ||||
|                 delete this.stopProvidingTelemetry; | ||||
|             } | ||||
|             if (this.conditionSetDomainObject) { | ||||
|                 this.openmct.telemetry.request(this.conditionSetDomainObject) | ||||
|   | ||||
| @@ -190,7 +190,6 @@ export default { | ||||
|             if (this.isEditing) { | ||||
|                 if (this.stopProvidingTelemetry) { | ||||
|                     this.stopProvidingTelemetry(); | ||||
|                     delete this.stopProvidingTelemetry; | ||||
|                 } | ||||
|             } else { | ||||
|                 this.subscribeToConditionSet(); | ||||
| @@ -326,7 +325,6 @@ export default { | ||||
|  | ||||
|             if (this.stopProvidingTelemetry) { | ||||
|                 this.stopProvidingTelemetry(); | ||||
|                 delete this.stopProvidingTelemetry; | ||||
|             } | ||||
|  | ||||
|             if (this.unObserveObjects) { | ||||
| @@ -339,7 +337,6 @@ export default { | ||||
|         subscribeToConditionSet() { | ||||
|             if (this.stopProvidingTelemetry) { | ||||
|                 this.stopProvidingTelemetry(); | ||||
|                 delete this.stopProvidingTelemetry; | ||||
|             } | ||||
|             if (this.conditionSetDomainObject) { | ||||
|                 this.openmct.telemetry.request(this.conditionSetDomainObject) | ||||
| @@ -497,7 +494,6 @@ export default { | ||||
|  | ||||
|             if (this.stopProvidingTelemetry) { | ||||
|                 this.stopProvidingTelemetry(); | ||||
|                 delete this.stopProvidingTelemetry; | ||||
|             } | ||||
|         }, | ||||
|         removeConditionalStyles(domainObjectStyles, itemId) { | ||||
|   | ||||
| @@ -22,7 +22,7 @@ | ||||
|  | ||||
| import TelemetryCriterion from './TelemetryCriterion'; | ||||
| import { evaluateResults } from "../utils/evaluator"; | ||||
| import {getLatestTimestamp, subscribeForStaleness} from '../utils/time'; | ||||
| import { getLatestTimestamp } from '../utils/time'; | ||||
| import { getOperatorText } from "@/plugins/condition/utils/operations"; | ||||
|  | ||||
| export default class AllTelemetryCriterion extends TelemetryCriterion { | ||||
| @@ -41,32 +41,6 @@ export default class AllTelemetryCriterion extends TelemetryCriterion { | ||||
|     initialize() { | ||||
|         this.telemetryObjects = { ...this.telemetryDomainObjectDefinition.telemetryObjects }; | ||||
|         this.telemetryDataCache = {}; | ||||
|         if (this.isValid() && this.isStalenessCheck() && this.isValidInput()) { | ||||
|             this.subscribeForStaleData(this.telemetryObjects || {}); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     subscribeForStaleData(telemetryObjects) { | ||||
|  | ||||
|         if (!this.stalenessSubscription) { | ||||
|             this.stalenessSubscription = {}; | ||||
|         } | ||||
|         Object.values(telemetryObjects).forEach((telemetryObject) => { | ||||
|             const id = this.openmct.objects.makeKeyString(telemetryObject.identifier); | ||||
|             if (!this.stalenessSubscription[id]) { | ||||
|                 this.stalenessSubscription[id] = subscribeForStaleness((data) => { | ||||
|                     this.handleStaleTelemetry(id, data); | ||||
|                 }, this.input[0]*1000); | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     handleStaleTelemetry(id, data) { | ||||
|         if (this.telemetryDataCache) { | ||||
|             this.telemetryDataCache[id] = true; | ||||
|             this.result = evaluateResults(Object.values(this.telemetryDataCache), this.telemetry); | ||||
|         } | ||||
|         this.emitEvent('telemetryIsStale', data); | ||||
|     } | ||||
|  | ||||
|     isValid() { | ||||
| @@ -76,9 +50,6 @@ export default class AllTelemetryCriterion extends TelemetryCriterion { | ||||
|     updateTelemetryObjects(telemetryObjects) { | ||||
|         this.telemetryObjects = { ...telemetryObjects }; | ||||
|         this.removeTelemetryDataCache(); | ||||
|         if (this.isValid() && this.isStalenessCheck() && this.isValidInput()) { | ||||
|             this.subscribeForStaleData(this.telemetryObjects || {}); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     removeTelemetryDataCache() { | ||||
| @@ -92,7 +63,6 @@ export default class AllTelemetryCriterion extends TelemetryCriterion { | ||||
|         }); | ||||
|         telemetryCacheIds.forEach(id => { | ||||
|             delete (this.telemetryDataCache[id]); | ||||
|             delete (this.stalenessSubscription[id]); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
| @@ -126,14 +96,7 @@ export default class AllTelemetryCriterion extends TelemetryCriterion { | ||||
|         const validatedData = this.isValid() ? data : {}; | ||||
|  | ||||
|         if (validatedData) { | ||||
|             if (this.isStalenessCheck()) { | ||||
|                 if (this.stalenessSubscription && this.stalenessSubscription[validatedData.id]) { | ||||
|                     this.stalenessSubscription[validatedData.id].update(validatedData); | ||||
|                 } | ||||
|                 this.telemetryDataCache[validatedData.id] = false; | ||||
|             } else { | ||||
|                 this.telemetryDataCache[validatedData.id] = this.computeResult(validatedData); | ||||
|             } | ||||
|             this.telemetryDataCache[validatedData.id] = this.computeResult(validatedData); | ||||
|         } | ||||
|  | ||||
|         Object.values(telemetryObjects).forEach(telemetryObject => { | ||||
| @@ -199,7 +162,7 @@ export default class AllTelemetryCriterion extends TelemetryCriterion { | ||||
|  | ||||
|     getDescription() { | ||||
|         const telemetryDescription = this.telemetry === 'all' ? 'all telemetry' : 'any telemetry'; | ||||
|         let metadataValue = (this.metadata === 'dataReceived' ? '' : this.metadata); | ||||
|         let metadataValue = this.metadata; | ||||
|         let inputValue = this.input; | ||||
|         if (this.metadata) { | ||||
|             const telemetryObjects = Object.values(this.telemetryObjects); | ||||
| @@ -219,9 +182,5 @@ export default class AllTelemetryCriterion extends TelemetryCriterion { | ||||
|     destroy() { | ||||
|         delete this.telemetryObjects; | ||||
|         delete this.telemetryDataCache; | ||||
|         if (this.stalenessSubscription) { | ||||
|             Object.values(this.stalenessSubscription).forEach((subscription) => subscription.clear); | ||||
|             delete this.stalenessSubscription; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -22,7 +22,6 @@ | ||||
|  | ||||
| import EventEmitter from 'EventEmitter'; | ||||
| import { OPERATIONS, getOperatorText } from '../utils/operations'; | ||||
| import { subscribeForStaleness } from "../utils/time"; | ||||
|  | ||||
| export default class TelemetryCriterion extends EventEmitter { | ||||
|  | ||||
| @@ -44,7 +43,6 @@ export default class TelemetryCriterion extends EventEmitter { | ||||
|         this.input = telemetryDomainObjectDefinition.input; | ||||
|         this.metadata = telemetryDomainObjectDefinition.metadata; | ||||
|         this.result = undefined; | ||||
|         this.stalenessSubscription = undefined; | ||||
|  | ||||
|         this.initialize(); | ||||
|         this.emitEvent('criterionUpdated', this); | ||||
| @@ -53,40 +51,14 @@ export default class TelemetryCriterion extends EventEmitter { | ||||
|     initialize() { | ||||
|         this.telemetryObjectIdAsString = this.openmct.objects.makeKeyString(this.telemetryDomainObjectDefinition.telemetry); | ||||
|         this.updateTelemetryObjects(this.telemetryDomainObjectDefinition.telemetryObjects); | ||||
|         if (this.isValid() && this.isStalenessCheck() && this.isValidInput()) { | ||||
|             this.subscribeForStaleData() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     subscribeForStaleData() { | ||||
|         if (this.stalenessSubscription) { | ||||
|             this.stalenessSubscription.clear(); | ||||
|         } | ||||
|         this.stalenessSubscription = subscribeForStaleness(this.handleStaleTelemetry.bind(this), this.input[0]*1000); | ||||
|     } | ||||
|  | ||||
|     handleStaleTelemetry(data) { | ||||
|         this.result = true; | ||||
|         this.emitEvent('telemetryIsStale', data); | ||||
|     } | ||||
|  | ||||
|     isValid() { | ||||
|         return this.telemetryObject && this.metadata && this.operation; | ||||
|     } | ||||
|  | ||||
|     isStalenessCheck() { | ||||
|         return this.metadata && this.metadata === 'dataReceived'; | ||||
|     } | ||||
|  | ||||
|     isValidInput() { | ||||
|         return this.input instanceof Array && this.input.length; | ||||
|     } | ||||
|  | ||||
|     updateTelemetryObjects(telemetryObjects) { | ||||
|         this.telemetryObject = telemetryObjects[this.telemetryObjectIdAsString]; | ||||
|         if (this.isValid() && this.isStalenessCheck() && this.isValidInput()) { | ||||
|             this.subscribeForStaleData() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     createNormalizedDatum(telemetryDatum, endpoint) { | ||||
| @@ -119,14 +91,7 @@ export default class TelemetryCriterion extends EventEmitter { | ||||
|  | ||||
|     getResult(data) { | ||||
|         const validatedData = this.isValid() ? data : {}; | ||||
|         if (this.isStalenessCheck()) { | ||||
|             if (this.stalenessSubscription) { | ||||
|                 this.stalenessSubscription.update(validatedData); | ||||
|             } | ||||
|             this.result = false; | ||||
|         } else { | ||||
|             this.result = this.computeResult(validatedData); | ||||
|         } | ||||
|         this.result = this.computeResult(validatedData); | ||||
|     } | ||||
|  | ||||
|     requestLAD() { | ||||
| @@ -142,14 +107,12 @@ export default class TelemetryCriterion extends EventEmitter { | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         let telemetryObject = this.telemetryObject; | ||||
|  | ||||
|         return this.openmct.telemetry.request( | ||||
|             this.telemetryObject, | ||||
|             options | ||||
|         ).then(results => { | ||||
|             const latestDatum = results.length ? results[results.length - 1] : {}; | ||||
|             const normalizedDatum = this.createNormalizedDatum(latestDatum, telemetryObject); | ||||
|             const normalizedDatum = this.createNormalizedDatum(latestDatum, this.telemetryObject); | ||||
|  | ||||
|             return { | ||||
|                 id: this.id, | ||||
| @@ -173,7 +136,7 @@ export default class TelemetryCriterion extends EventEmitter { | ||||
|             let comparator = this.findOperation(this.operation); | ||||
|             let params = []; | ||||
|             params.push(data[this.metadata]); | ||||
|             if (this.isValidInput()) { | ||||
|             if (this.input instanceof Array && this.input.length) { | ||||
|                 this.input.forEach(input => params.push(input)); | ||||
|             } | ||||
|             if (typeof comparator === 'function') { | ||||
| @@ -228,7 +191,7 @@ export default class TelemetryCriterion extends EventEmitter { | ||||
|             description = `Unknown ${this.metadata} ${getOperatorText(this.operation, this.input)}`; | ||||
|         } else { | ||||
|             const metadataObject = this.getMetaDataObject(this.telemetryObject, this.metadata); | ||||
|             const metadataValue = this.getMetadataValueFromMetaData(metadataObject) || (this.metadata === 'dataReceived' ? '' : this.metadata); | ||||
|             const metadataValue = this.getMetadataValueFromMetaData(metadataObject) || this.metadata; | ||||
|             const inputValue = this.getInputValueFromMetaData(metadataObject, this.input) || this.input; | ||||
|             description = `${this.telemetryObject.name} ${metadataValue} ${getOperatorText(this.operation, inputValue)}`; | ||||
|         } | ||||
| @@ -239,8 +202,5 @@ export default class TelemetryCriterion extends EventEmitter { | ||||
|     destroy() { | ||||
|         delete this.telemetryObject; | ||||
|         delete this.telemetryObjectIdAsString; | ||||
|         if (this.stalenessSubscription) { | ||||
|             delete this.stalenessSubscription; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -21,14 +21,12 @@ | ||||
|  *****************************************************************************/ | ||||
|  | ||||
| import TelemetryCriterion from "./TelemetryCriterion"; | ||||
| import { getMockTelemetry } from "utils/testing"; | ||||
|  | ||||
| let openmct = {}, | ||||
|     mockListener, | ||||
|     testCriterionDefinition, | ||||
|     testTelemetryObject, | ||||
|     telemetryCriterion, | ||||
|     mockTelemetry = getMockTelemetry(); | ||||
|     telemetryCriterion; | ||||
|  | ||||
| describe("The telemetry criterion", function () { | ||||
|  | ||||
| @@ -62,7 +60,7 @@ describe("The telemetry criterion", function () { | ||||
|         }; | ||||
|         openmct.objects = jasmine.createSpyObj('objects', ['get', 'makeKeyString']); | ||||
|         openmct.objects.makeKeyString.and.returnValue(testTelemetryObject.identifier.key); | ||||
|         openmct.telemetry = jasmine.createSpyObj('telemetry', ['isTelemetryObject', "subscribe", "getMetadata", "getValueFormatter", "request"]); | ||||
|         openmct.telemetry = jasmine.createSpyObj('telemetry', ['isTelemetryObject', "subscribe", "getMetadata", "getValueFormatter"]); | ||||
|         openmct.telemetry.isTelemetryObject.and.returnValue(true); | ||||
|         openmct.telemetry.subscribe.and.returnValue(function () {}); | ||||
|         openmct.telemetry.getValueFormatter.and.returnValue({ | ||||
| @@ -111,30 +109,4 @@ describe("The telemetry criterion", function () { | ||||
|         }); | ||||
|         expect(telemetryCriterion.result).toBeTrue(); | ||||
|     }); | ||||
|  | ||||
|     describe('the LAD request', () => { | ||||
|         beforeEach(async () => { | ||||
|             let telemetryRequestResolve; | ||||
|             let telemetryRequestPromise = new Promise((resolve) => { | ||||
|                 telemetryRequestResolve = resolve; | ||||
|             }); | ||||
|             openmct.telemetry.request.and.callFake(() => { | ||||
|                 setTimeout(() => { | ||||
|                     telemetryRequestResolve(mockTelemetry); | ||||
|                 }, 100); | ||||
|                 return telemetryRequestPromise; | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         it("returns results for slow LAD requests", async function () { | ||||
|             const criteriaRequest = telemetryCriterion.requestLAD(); | ||||
|             telemetryCriterion.destroy(); | ||||
|             expect(telemetryCriterion.telemetryObject).toBeUndefined(); | ||||
|             setTimeout(() => { | ||||
|                 criteriaRequest.then((result) => { | ||||
|                     expect(result).toBeDefined(); | ||||
|                 }); | ||||
|             }, 300); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
|   | ||||
| @@ -25,50 +25,19 @@ import ConditionPlugin from "./plugin"; | ||||
| import StylesView from "./components/inspector/StylesView.vue"; | ||||
| import Vue from 'vue'; | ||||
| import {getApplicableStylesForItem} from "./utils/styleUtils"; | ||||
| import ConditionManager from "@/plugins/condition/ConditionManager"; | ||||
|  | ||||
| describe('the plugin', function () { | ||||
|     let conditionSetDefinition; | ||||
|     let mockConditionSetDomainObject; | ||||
|     let mockListener; | ||||
|     let element; | ||||
|     let child; | ||||
|     let openmct; | ||||
|     let testTelemetryObject; | ||||
|  | ||||
|     beforeAll(() => { | ||||
|         resetApplicationState(openmct); | ||||
|     }); | ||||
|  | ||||
|     beforeEach((done) => { | ||||
|         testTelemetryObject = { | ||||
|             identifier:{ namespace: "", key: "test-object"}, | ||||
|             type: "test-object", | ||||
|             name: "Test Object", | ||||
|             telemetry: { | ||||
|                 valueMetadatas: [{ | ||||
|                     key: "some-key", | ||||
|                     name: "Some attribute", | ||||
|                     hints: { | ||||
|                         range: 2 | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
|                     key: "utc", | ||||
|                     name: "Time", | ||||
|                     format: "utc", | ||||
|                     hints: { | ||||
|                         domain: 1 | ||||
|                     } | ||||
|                 }, { | ||||
|                     key: "testSource", | ||||
|                     source: "value", | ||||
|                     name: "Test", | ||||
|                     format: "string" | ||||
|                 }] | ||||
|             } | ||||
|         }; | ||||
|  | ||||
|         openmct = createOpenMct(); | ||||
|         openmct.install(new ConditionPlugin()); | ||||
|  | ||||
| @@ -86,8 +55,6 @@ describe('the plugin', function () { | ||||
|             type: 'conditionSet' | ||||
|         }; | ||||
|  | ||||
|         mockListener = jasmine.createSpy('mockListener'); | ||||
|  | ||||
|         conditionSetDefinition.initialize(mockConditionSetDomainObject); | ||||
|  | ||||
|         openmct.on('start', done); | ||||
| @@ -389,113 +356,4 @@ describe('the plugin', function () { | ||||
|         }); | ||||
|  | ||||
|     }); | ||||
|  | ||||
|     describe('the condition check for staleness', () => { | ||||
|         let conditionSetDomainObject; | ||||
|  | ||||
|         beforeEach(()=>{ | ||||
|             conditionSetDomainObject = { | ||||
|                 "configuration":{ | ||||
|                     "conditionTestData":[ | ||||
|                         { | ||||
|                             "telemetry":"", | ||||
|                             "metadata":"", | ||||
|                             "input":"" | ||||
|                         } | ||||
|                     ], | ||||
|                     "conditionCollection":[ | ||||
|                         { | ||||
|                             "id":"39584410-cbf9-499e-96dc-76f27e69885d", | ||||
|                             "configuration":{ | ||||
|                                 "name":"Unnamed Condition", | ||||
|                                 "output":"Any stale telemetry", | ||||
|                                 "trigger":"all", | ||||
|                                 "criteria":[ | ||||
|                                     { | ||||
|                                         "id":"35400132-63b0-425c-ac30-8197df7d5862", | ||||
|                                         "telemetry":"any", | ||||
|                                         "operation":"isStale", | ||||
|                                         "input":[ | ||||
|                                             "1" | ||||
|                                         ], | ||||
|                                         "metadata":"dataReceived" | ||||
|                                     } | ||||
|                                 ] | ||||
|                             }, | ||||
|                             "summary":"Match if all criteria are met: Any telemetry is stale after 5 seconds" | ||||
|                         }, | ||||
|                         { | ||||
|                             "isDefault":true, | ||||
|                             "id":"2532d90a-e0d6-4935-b546-3123522da2de", | ||||
|                             "configuration":{ | ||||
|                                 "name":"Default", | ||||
|                                 "output":"Default", | ||||
|                                 "trigger":"all", | ||||
|                                 "criteria":[ | ||||
|                                 ] | ||||
|                             }, | ||||
|                             "summary":"" | ||||
|                         } | ||||
|                     ] | ||||
|                 }, | ||||
|                 "composition":[ | ||||
|                     { | ||||
|                         "namespace":"", | ||||
|                         "key":"test-object" | ||||
|                     } | ||||
|                 ], | ||||
|                 "telemetry":{ | ||||
|                 }, | ||||
|                 "name":"Condition Set", | ||||
|                 "type":"conditionSet", | ||||
|                 "identifier":{ | ||||
|                     "namespace":"", | ||||
|                     "key":"cf4456a9-296a-4e6b-b182-62ed29cd15b9" | ||||
|                 } | ||||
|  | ||||
|             }; | ||||
|         }); | ||||
|  | ||||
|         it('should evaluate as stale when telemetry is not received in the allotted time', (done) => { | ||||
|  | ||||
|             let conditionMgr = new ConditionManager(conditionSetDomainObject, openmct); | ||||
|             conditionMgr.on('conditionSetResultUpdated', mockListener); | ||||
|             conditionMgr.telemetryObjects = { | ||||
|                 "test-object": testTelemetryObject | ||||
|             }; | ||||
|             conditionMgr.updateConditionTelemetryObjects(); | ||||
|             setTimeout(() => { | ||||
|                 expect(mockListener).toHaveBeenCalledWith({ | ||||
|                     output: 'Any stale telemetry', | ||||
|                     id: { namespace: '', key: 'cf4456a9-296a-4e6b-b182-62ed29cd15b9' }, | ||||
|                     conditionId: '39584410-cbf9-499e-96dc-76f27e69885d', | ||||
|                     utc: undefined | ||||
|                 }); | ||||
|                 done(); | ||||
|             }, 1500); | ||||
|         }); | ||||
|  | ||||
|         it('should not evaluate as stale when telemetry is received in the allotted time', (done) => { | ||||
|             const date = Date.now(); | ||||
|             conditionSetDomainObject.configuration.conditionCollection[0].configuration.criteria[0].input = ["2"]; | ||||
|             let conditionMgr = new ConditionManager(conditionSetDomainObject, openmct); | ||||
|             conditionMgr.on('conditionSetResultUpdated', mockListener); | ||||
|             conditionMgr.telemetryObjects = { | ||||
|                 "test-object": testTelemetryObject | ||||
|             }; | ||||
|             conditionMgr.updateConditionTelemetryObjects(); | ||||
|             conditionMgr.telemetryReceived(testTelemetryObject, { | ||||
|                 utc: date | ||||
|             }); | ||||
|             setTimeout(() => { | ||||
|                 expect(mockListener).toHaveBeenCalledWith({ | ||||
|                     output: 'Default', | ||||
|                     id: { namespace: '', key: 'cf4456a9-296a-4e6b-b182-62ed29cd15b9' }, | ||||
|                     conditionId: '2532d90a-e0d6-4935-b546-3123522da2de', | ||||
|                     utc: undefined | ||||
|                 }); | ||||
|                 done(); | ||||
|             }, 1500); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
|   | ||||
| @@ -283,18 +283,6 @@ export const OPERATIONS = [ | ||||
|         getDescription: function (values) { | ||||
|             return ' is not one of ' + values[0]; | ||||
|         } | ||||
|     }, | ||||
|     { | ||||
|         name: 'isStale', | ||||
|         operation: function () { | ||||
|             return false; | ||||
|         }, | ||||
|         text: 'is older than', | ||||
|         appliesTo: ["number"], | ||||
|         inputCount: 1, | ||||
|         getDescription: function (values) { | ||||
|             return ` is older than ${values[0] || ''} seconds`; | ||||
|         } | ||||
|     } | ||||
| ]; | ||||
|  | ||||
|   | ||||
| @@ -50,26 +50,3 @@ function updateLatestTimeStamp(timestamp, timeSystems) { | ||||
|  | ||||
|     return latest; | ||||
| } | ||||
|  | ||||
| export const subscribeForStaleness = (callback, timeout) => { | ||||
|     let stalenessTimer = setTimeout(() => { | ||||
|         clearTimeout(stalenessTimer); | ||||
|         callback(); | ||||
|     }, timeout); | ||||
|     return { | ||||
|         update: (data) => { | ||||
|             if (stalenessTimer) { | ||||
|                 clearTimeout(stalenessTimer); | ||||
|             } | ||||
|             stalenessTimer = setTimeout(() => { | ||||
|                 clearTimeout(stalenessTimer); | ||||
|                 callback(data); | ||||
|             }, timeout); | ||||
|         }, | ||||
|         clear: () => { | ||||
|             if (stalenessTimer) { | ||||
|                 clearTimeout(stalenessTimer); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| }; | ||||
|   | ||||
| @@ -1,64 +0,0 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2020, 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 { subscribeForStaleness } from "./time"; | ||||
|  | ||||
| describe('time related utils', () => { | ||||
|     let subscription; | ||||
|     let mockListener; | ||||
|  | ||||
|     beforeEach(() => { | ||||
|         mockListener = jasmine.createSpy('listener'); | ||||
|         subscription = subscribeForStaleness(mockListener, 100); | ||||
|     }); | ||||
|  | ||||
|     describe('subscribe for staleness', () => { | ||||
|         it('should call listeners when stale', (done) => { | ||||
|             setTimeout(() => { | ||||
|                 expect(mockListener).toHaveBeenCalled(); | ||||
|                 done(); | ||||
|             }, 200); | ||||
|         }); | ||||
|  | ||||
|         it('should update the subscription', (done) => { | ||||
|             function updated() { | ||||
|                 setTimeout(() => { | ||||
|                     expect(mockListener).not.toHaveBeenCalled(); | ||||
|                     done(); | ||||
|                 }, 50); | ||||
|             } | ||||
|             setTimeout(() => { | ||||
|                 subscription.update(); | ||||
|                 updated(); | ||||
|             }, 50); | ||||
|         }); | ||||
|  | ||||
|         it('should clear the subscription', (done) => { | ||||
|             subscription.clear(); | ||||
|  | ||||
|             setTimeout(() => { | ||||
|                 expect(mockListener).not.toHaveBeenCalled(); | ||||
|                 done(); | ||||
|             }, 200); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
| }); | ||||
| @@ -457,43 +457,15 @@ export default { | ||||
|             this.objectViewMap = {}; | ||||
|             this.layoutItems.forEach(this.trackItem); | ||||
|         }, | ||||
|         isItemAlreadyTracked(child) { | ||||
|             let found = false, | ||||
|                 keyString = this.openmct.objects.makeKeyString(child.identifier); | ||||
|  | ||||
|             this.layoutItems.forEach(item => { | ||||
|                 if (item.identifier) { | ||||
|                     let itemKeyString = this.openmct.objects.makeKeyString(item.identifier); | ||||
|  | ||||
|                     if (itemKeyString === keyString) { | ||||
|                         found = true; | ||||
|                         return; | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|             if (found) { | ||||
|                 return true; | ||||
|             } else if (this.isTelemetry(child)) { | ||||
|                 return this.telemetryViewMap[keyString] && this.objectViewMap[keyString]; | ||||
|             } else { | ||||
|                 return this.objectViewMap[keyString]; | ||||
|             } | ||||
|         }, | ||||
|         addChild(child) { | ||||
|             if (this.isItemAlreadyTracked(child)) { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             let type; | ||||
|  | ||||
|             let keyString = this.openmct.objects.makeKeyString(child.identifier); | ||||
|             if (this.isTelemetry(child)) { | ||||
|                 type = 'telemetry-view'; | ||||
|             } else { | ||||
|                 type = 'subobject-view'; | ||||
|                 if (!this.telemetryViewMap[keyString] && !this.objectViewMap[keyString]) { | ||||
|                     this.addItem('telemetry-view', child); | ||||
|                 } | ||||
|             } else if (!this.objectViewMap[keyString]) { | ||||
|                 this.addItem('subobject-view', child); | ||||
|             } | ||||
|  | ||||
|             this.addItem(type, child); | ||||
|         }, | ||||
|         removeChild(identifier) { | ||||
|             let keyString = this.openmct.objects.makeKeyString(identifier); | ||||
| @@ -587,17 +559,14 @@ export default { | ||||
|             } | ||||
|         }, | ||||
|         updateTelemetryFormat(item, format) { | ||||
|             let index = this.layoutItems.findIndex((layoutItem) => { | ||||
|                 return layoutItem.id === item.id; | ||||
|             }); | ||||
|  | ||||
|             let index = this.layoutItems.findIndex(item); | ||||
|             item.format = format; | ||||
|             this.mutate(`configuration.items[${index}]`, item); | ||||
|         }, | ||||
|         createNewDomainObject(domainObject, composition, viewType, nameExtension, model) { | ||||
|             let identifier = { | ||||
|                     key: uuid(), | ||||
|                     namespace: this.internalDomainObject.identifier.namespace | ||||
|                     namespace: domainObject.identifier.namespace | ||||
|                 }, | ||||
|                 type = this.openmct.types.get(viewType), | ||||
|                 parentKeyString = this.openmct.objects.makeKeyString(this.internalDomainObject.identifier), | ||||
|   | ||||
| @@ -25,8 +25,7 @@ | ||||
|     class="l-layout__frame c-frame" | ||||
|     :class="{ | ||||
|         'no-frame': !item.hasFrame, | ||||
|         'u-inspectable': inspectable, | ||||
|         'is-in-small-container': size.width < 600 || size.height < 600 | ||||
|         'u-inspectable': inspectable | ||||
|     }" | ||||
|     :style="style" | ||||
| > | ||||
| @@ -62,13 +61,6 @@ export default { | ||||
|         } | ||||
|     }, | ||||
|     computed: { | ||||
|         size() { | ||||
|             let {width, height} = this.item; | ||||
|             return { | ||||
|                 width: (this.gridSize[0] * width), | ||||
|                 height: (this.gridSize[1] * height) | ||||
|             }; | ||||
|         }, | ||||
|         style() { | ||||
|             let {x, y, width, height} = this.item; | ||||
|             return { | ||||
|   | ||||
| @@ -22,7 +22,7 @@ | ||||
|  | ||||
| <template> | ||||
| <div | ||||
|     class="l-layout__frame c-frame no-frame c-line-view" | ||||
|     class="l-layout__frame c-frame no-frame" | ||||
|     :class="[styleClass]" | ||||
|     :style="style" | ||||
| > | ||||
| @@ -31,15 +31,9 @@ | ||||
|         height="100%" | ||||
|     > | ||||
|         <line | ||||
|             class="c-line-view__hover-indicator" | ||||
|             v-bind="linePosition" | ||||
|             vector-effect="non-scaling-stroke" | ||||
|         /> | ||||
|         <line | ||||
|             class="c-line-view__line" | ||||
|             v-bind="linePosition" | ||||
|             :stroke="stroke" | ||||
|             vector-effect="non-scaling-stroke" | ||||
|             stroke-width="2" | ||||
|         /> | ||||
|     </svg> | ||||
|  | ||||
| @@ -55,8 +49,7 @@ | ||||
|             class="c-frame-edit__handle" | ||||
|             :class="startHandleClass" | ||||
|             @mousedown="startDrag($event, 'start')" | ||||
|         > | ||||
|         </div> | ||||
|         ></div> | ||||
|         <div | ||||
|             class="c-frame-edit__handle" | ||||
|             :class="endHandleClass" | ||||
| @@ -75,18 +68,14 @@ const START_HANDLE_QUADRANTS = { | ||||
|     1: 'c-frame-edit__handle--sw', | ||||
|     2: 'c-frame-edit__handle--se', | ||||
|     3: 'c-frame-edit__handle--ne', | ||||
|     4: 'c-frame-edit__handle--nw', | ||||
|     5: 'c-frame-edit__handle--nw', | ||||
|     6: 'c-frame-edit__handle--ne' | ||||
|     4: 'c-frame-edit__handle--nw' | ||||
| }; | ||||
|  | ||||
| const END_HANDLE_QUADRANTS = { | ||||
|     1: 'c-frame-edit__handle--ne', | ||||
|     2: 'c-frame-edit__handle--nw', | ||||
|     3: 'c-frame-edit__handle--sw', | ||||
|     4: 'c-frame-edit__handle--se', | ||||
|     5: 'c-frame-edit__handle--sw', | ||||
|     6: 'c-frame-edit__handle--nw' | ||||
|     4: 'c-frame-edit__handle--se' | ||||
| }; | ||||
|  | ||||
| export default { | ||||
| @@ -169,12 +158,6 @@ export default { | ||||
|         }, | ||||
|         vectorQuadrant() { | ||||
|             let {x, y, x2, y2} = this.position; | ||||
|             if (x2 === x) { | ||||
|                 return 5; // Vertical line | ||||
|             } | ||||
|             if (y2 === y) { | ||||
|                 return 6; // Horizontal line | ||||
|             } | ||||
|             if (x2 > x) { | ||||
|                 if (y2 < y) { | ||||
|                     return 1; | ||||
| @@ -187,27 +170,21 @@ export default { | ||||
|             return 3; | ||||
|         }, | ||||
|         linePosition() { | ||||
|             let pos = {}; | ||||
|             switch(this.vectorQuadrant) { | ||||
|             case 1: | ||||
|             case 3: | ||||
|                 // slopes up | ||||
|                 pos = {x1: '0%', y1: '100%', x2: '100%', y2: '0%'}; | ||||
|                 break; | ||||
|             case 5: | ||||
|                 // vertical | ||||
|                 pos = {x1: '0%', y1: '0%', x2: '0%', y2: '100%'}; | ||||
|                 break; | ||||
|             case 6: | ||||
|                 // horizontal | ||||
|                 pos = {x1: '0%', y1: '0%', x2: '100%', y2: '0%'}; | ||||
|                 break; | ||||
|             default: | ||||
|                 // slopes down | ||||
|                 pos = {x1: '0%', y1: '0%', x2: '100%', y2: '100%'}; | ||||
|                 break; | ||||
|             } | ||||
|             return pos; | ||||
|             return this.vectorQuadrant % 2 !== 0 | ||||
|                 // odd vectorQuadrant slopes up | ||||
|                 ? { | ||||
|                     x1: '0%', | ||||
|                     y1: '100%', | ||||
|                     x2: '100%', | ||||
|                     y2: '0%' | ||||
|                 } | ||||
|                 // even vectorQuadrant slopes down | ||||
|                 : { | ||||
|                     x1: '0%', | ||||
|                     y1: '0%', | ||||
|                     x2: '100%', | ||||
|                     y2: '100%' | ||||
|                 }; | ||||
|         } | ||||
|     }, | ||||
|     watch: { | ||||
| @@ -232,7 +209,8 @@ export default { | ||||
|             layoutItem: this.item, | ||||
|             index: this.index | ||||
|         }; | ||||
|         this.removeSelectable = this.openmct.selection.selectable(this.$el, this.context, this.initSelect); | ||||
|         this.removeSelectable = this.openmct.selection.selectable( | ||||
|             this.$el, this.context, this.initSelect); | ||||
|     }, | ||||
|     destroyed() { | ||||
|         if (this.removeSelectable) { | ||||
| @@ -246,17 +224,12 @@ export default { | ||||
|             document.body.addEventListener('mousemove', this.continueDrag); | ||||
|             document.body.addEventListener('mouseup', this.endDrag); | ||||
|             this.startPosition = [event.pageX, event.pageY]; | ||||
|             let {x, y, x2, y2} = this.item; | ||||
|             this.dragPosition = {x, y, x2, y2}; | ||||
|             if (x === x2 || y === y2) { | ||||
|                 if (y > y2 || x < x2) { | ||||
|                     if (this.dragging === 'start') { | ||||
|                         this.dragging = 'end'; | ||||
|                     } else if (this.dragging === 'end') { | ||||
|                         this.dragging = 'start'; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             this.dragPosition = { | ||||
|                 x: this.item.x, | ||||
|                 y: this.item.y, | ||||
|                 x2: this.item.x2, | ||||
|                 y2: this.item.y2 | ||||
|             }; | ||||
|             event.preventDefault(); | ||||
|         }, | ||||
|         continueDrag(event) { | ||||
| @@ -290,7 +263,7 @@ export default { | ||||
|         }, | ||||
|         calculateDragPosition(pxDeltaX, pxDeltaY) { | ||||
|             let gridDeltaX = Math.round(pxDeltaX / this.gridSize[0]); | ||||
|             let gridDeltaY = Math.round(pxDeltaY / this.gridSize[1]); | ||||
|             let gridDeltaY = Math.round(pxDeltaY / this.gridSize[0]); // TODO: should this be gridSize[1]? | ||||
|             let {x, y, x2, y2} = this.item; | ||||
|             let dragPosition = {x, y, x2, y2}; | ||||
|  | ||||
|   | ||||
| @@ -31,16 +31,10 @@ | ||||
|     <div | ||||
|         v-if="domainObject" | ||||
|         class="c-telemetry-view" | ||||
|         :class="{ | ||||
|             styleClass, | ||||
|             'is-missing': domainObject.status === 'missing' | ||||
|         }" | ||||
|         :class="styleClass" | ||||
|         :style="styleObject" | ||||
|         @contextmenu.prevent="showContextMenu" | ||||
|     > | ||||
|         <div class="is-missing__indicator" | ||||
|              title="This item is missing" | ||||
|         ></div> | ||||
|         <div | ||||
|             v-if="showLabel" | ||||
|             class="c-telemetry-view__label" | ||||
|   | ||||
| @@ -1,60 +0,0 @@ | ||||
| .c-box-view { | ||||
|     border-width: $drawingObjBorderW !important; | ||||
|     display: flex; | ||||
|     align-items: stretch; | ||||
|  | ||||
|     .c-frame & { | ||||
|         @include abs(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| .c-line-view { | ||||
|     &.c-frame { | ||||
|         box-shadow: none !important; | ||||
|     } | ||||
|  | ||||
|     .c-frame-edit { | ||||
|         border: none; | ||||
|     } | ||||
|  | ||||
|     .c-handle-info { | ||||
|         background: rgba(#999, 0.2); | ||||
|         padding: 2px; | ||||
|         position: absolute; | ||||
|         top: 5px; left: 5px; | ||||
|         white-space: nowrap; | ||||
|     } | ||||
|  | ||||
|     svg { | ||||
|         // Prevent clipping when line is horizontal and vertical | ||||
|         min-height: 1px; | ||||
|         min-width: 1px; | ||||
|         // Must use !important to counteract setting in normalize.min.css | ||||
|         overflow: visible; | ||||
|     } | ||||
|  | ||||
|     &__line { | ||||
|         stroke-linecap: round; | ||||
|         stroke-width: $drawingObjBorderW; | ||||
|     } | ||||
|  | ||||
|     &__hover-indicator { | ||||
|         display: none; | ||||
|         opacity: 0.5; | ||||
|         stroke: $editFrameColorHov; | ||||
|         stroke-width: $drawingObjBorderW + 4; | ||||
|     } | ||||
|  | ||||
|     .is-editing & { | ||||
|         // Needed to allow line to be moved | ||||
|         $w: 4px; | ||||
|         min-width: $w; | ||||
|         min-height: $w; | ||||
|  | ||||
|         &:hover { | ||||
|             [class*='__hover-indicator'] { | ||||
|                 display: inline; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										8
									
								
								src/plugins/displayLayout/components/box-view.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/plugins/displayLayout/components/box-view.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| .c-box-view { | ||||
|     display: flex; | ||||
|     align-items: stretch; | ||||
|  | ||||
|     .c-frame & { | ||||
|         @include abs(); | ||||
|     } | ||||
| } | ||||
| @@ -7,10 +7,6 @@ | ||||
|     > *:first-child { | ||||
|         flex: 1 1 auto; | ||||
|     } | ||||
|  | ||||
|     &.is-in-small-container { | ||||
|         //background: rgba(blue, 0.1); | ||||
|     } | ||||
| } | ||||
|  | ||||
| .c-frame-edit__move { | ||||
| @@ -65,7 +61,7 @@ | ||||
|     .l-layout { | ||||
|         /******************* 0 - 1 ITEM SELECTED */ | ||||
|         &:not(.is-multi-selected) { | ||||
|             > .l-layout__frame { | ||||
|             > .l-layout__frame[s-selected] { | ||||
|                 > .c-so-view.has-complex-content { | ||||
|                     > .c-so-view__local-controls { | ||||
|                         transition: transform $transOutTime ease-in-out; | ||||
| @@ -93,7 +89,7 @@ | ||||
|                             $lrOffset: 25%; | ||||
|                             @include grippy($editFrameMovebarColorFg); | ||||
|                             content: ''; | ||||
|                             display: none; | ||||
|                             display: block; | ||||
|                             position: absolute; | ||||
|                             top: $tbOffset; | ||||
|                             right: $lrOffset; | ||||
| @@ -123,13 +119,6 @@ | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             > .l-layout__frame[s-selected] { | ||||
|                 > .c-so-view.has-complex-content { | ||||
|                     + .c-frame-edit__move:before { | ||||
|                         display: block; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /******************* > 1 ITEMS SELECTED */ | ||||
|   | ||||
| @@ -26,15 +26,4 @@ | ||||
|         @include abs(); | ||||
|         border: 1px solid transparent; | ||||
|     } | ||||
|  | ||||
|     @include isMissing($absPos: true); | ||||
|  | ||||
|     .is-missing__indicator { | ||||
|         top: 0; | ||||
|         left: 0; | ||||
|     } | ||||
|  | ||||
|     &.is-missing { | ||||
|         border: $borderMissing; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,18 +1,13 @@ | ||||
| <template> | ||||
| <a | ||||
|     class="l-grid-view__item c-grid-item" | ||||
|     :class="{ | ||||
|         'is-alias': item.isAlias === true, | ||||
|         'is-missing': item.model.status === 'missing', | ||||
|         'c-grid-item--unknown': item.type.cssClass === undefined || item.type.cssClass.indexOf('unknown') !== -1 | ||||
|     }" | ||||
|     :class="{ 'is-alias': item.isAlias === true }" | ||||
|     :href="objectLink" | ||||
| > | ||||
|     <div | ||||
|         class="c-grid-item__type-icon" | ||||
|         :class="(item.type.cssClass != undefined) ? 'bg-' + item.type.cssClass : 'bg-icon-object-unknown'" | ||||
|     > | ||||
|     </div> | ||||
|     ></div> | ||||
|     <div class="c-grid-item__details"> | ||||
|         <!-- Name and metadata --> | ||||
|         <div | ||||
| @@ -27,9 +22,6 @@ | ||||
|         </div> | ||||
|     </div> | ||||
|     <div class="c-grid-item__controls"> | ||||
|         <div class="is-missing__indicator" | ||||
|              title="This item is missing" | ||||
|         ></div> | ||||
|         <div | ||||
|             class="icon-people" | ||||
|             title="Shared" | ||||
|   | ||||
| @@ -7,19 +7,13 @@ | ||||
|     <td class="c-list-item__name"> | ||||
|         <a | ||||
|             ref="objectLink" | ||||
|             class="c-object-label" | ||||
|             :class="{ 'is-missing': item.model.status === 'missing' }" | ||||
|             :href="objectLink" | ||||
|         > | ||||
|             <div | ||||
|                 class="c-object-label__type-icon c-list-item__type-icon" | ||||
|                 class="c-list-item__type-icon" | ||||
|                 :class="item.type.cssClass" | ||||
|             > | ||||
|                 <span class="is-missing__indicator" | ||||
|                       title="This item is missing" | ||||
|                 ></span> | ||||
|             </div> | ||||
|             <div class="c-object-label__name c-list-item__name">{{ item.model.name }}</div> | ||||
|             ></div> | ||||
|             <div class="c-list-item__name-value">{{ item.model.name }}</div> | ||||
|         </a> | ||||
|     </td> | ||||
|     <td class="c-list-item__type"> | ||||
|   | ||||
| @@ -38,15 +38,7 @@ | ||||
|         // Object is an alias to an original. | ||||
|         [class*='__type-icon'] { | ||||
|             @include isAlias(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     &.is-missing { | ||||
|         @include isMissing(); | ||||
|  | ||||
|         [class*='__type-icon'], | ||||
|         [class*='__details'] { | ||||
|             opacity: $opacityMissing; | ||||
|             color: $colorIconAliasForKeyFilter; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -93,14 +85,15 @@ | ||||
|     body.desktop & { | ||||
|         $transOutMs: 300ms; | ||||
|         flex-flow: column nowrap; | ||||
|         transition: $transOutMs ease-in-out; | ||||
|         transition: background $transOutMs ease-in-out; | ||||
|  | ||||
|         &:hover { | ||||
|             filter: $filterItemHoverFg; | ||||
|             background: $colorItemBgHov; | ||||
|             transition: $transIn; | ||||
|  | ||||
|             .c-grid-item__type-icon { | ||||
|                 transform: scale(1.1); | ||||
|                 filter: $colorKeyFilterHov; | ||||
|                 transform: scale(1); | ||||
|                 transition: $transInBounce; | ||||
|             } | ||||
|         } | ||||
| @@ -110,7 +103,7 @@ | ||||
|         } | ||||
|  | ||||
|         &__controls { | ||||
|             align-items: baseline; | ||||
|             align-items: start; | ||||
|             flex: 0 0 auto; | ||||
|             order: 1; | ||||
|             .c-info-button, | ||||
| @@ -122,6 +115,7 @@ | ||||
|             font-size: floor($gridItemDesk / 3); | ||||
|             margin: $interiorMargin 22.5% $interiorMargin * 3 22.5%; | ||||
|             order: 2; | ||||
|             transform: scale(0.9); | ||||
|             transform-origin: center; | ||||
|             transition: all $transOutMs ease-in-out; | ||||
|         } | ||||
|   | ||||
| @@ -1,17 +1,37 @@ | ||||
| /******************************* LIST ITEM */ | ||||
| .c-list-item { | ||||
|     &__type-icon { | ||||
|         color: $colorItemTreeIcon; | ||||
|     &__name a { | ||||
|         display: flex; | ||||
|  | ||||
|         > * + * { margin-left: $interiorMarginSm; } | ||||
|     } | ||||
|  | ||||
|     &__name { | ||||
|     &__type-icon { | ||||
|         // Have to do it this way instead of using icon-* class, due to need to apply alias to the icon | ||||
|         color: $colorKey; | ||||
|         display: inline-block; | ||||
|         width: 1em; | ||||
|         margin-right:$interiorMarginSm; | ||||
|     } | ||||
|  | ||||
|     &__name-value { | ||||
|         @include ellipsize(); | ||||
|     } | ||||
|  | ||||
|     &.is-alias { | ||||
|         // Object is an alias to an original. | ||||
|         [class*='__type-icon'] { | ||||
|             @include isAlias(); | ||||
|             &:after { | ||||
|                 color: $colorIconAlias; | ||||
|                 content: $glyph-icon-link; | ||||
|                 font-family: symbolsfont; | ||||
|                 display: block; | ||||
|                 position: absolute; | ||||
|                 text-shadow: rgba(black, 0.5) 0 1px 2px; | ||||
|                 top: auto; left: -1px; bottom: 1px; right: auto; | ||||
|                 transform-origin: bottom left; | ||||
|                 transform: scale(0.65); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -13,8 +13,7 @@ | ||||
|             cursor: pointer; | ||||
|  | ||||
|             &:hover { | ||||
|                 background: $colorItemTreeHoverBg; | ||||
|                 filter: $filterHov; | ||||
|                 background: $colorListItemBgHov; | ||||
|                 transition: $transIn; | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -31,11 +31,11 @@ | ||||
|         <div class="c-imagery__control-bar"> | ||||
|             <div class="c-imagery__timestamp">{{ getTime() }}</div> | ||||
|             <div class="h-local-controls flex-elem"> | ||||
|                 <button | ||||
|                 <a | ||||
|                     class="c-button icon-pause pause-play" | ||||
|                     :class="{'is-paused': paused()}" | ||||
|                     @click="paused(!paused())" | ||||
|                 ></button> | ||||
|                 ></a> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
|   | ||||
| @@ -42,7 +42,6 @@ | ||||
|         height: 135px; | ||||
|         overflow-x: auto; | ||||
|         overflow-y: hidden; | ||||
|         padding-bottom: $interiorMarginSm; | ||||
|  | ||||
|         &.is-paused { | ||||
|             background: rgba($colorPausedBg, 0.4); | ||||
| @@ -100,7 +99,7 @@ | ||||
| .c-imagery { | ||||
|     .h-local-controls--overlay-content { | ||||
|         position: absolute; | ||||
|         left: $interiorMargin; top: $interiorMargin; | ||||
|         right: $interiorMargin; top: $interiorMargin; | ||||
|         z-index: 2; | ||||
|         background: $colorLocalControlOvrBg; | ||||
|         border-radius: $basicCr; | ||||
|   | ||||
| @@ -41,7 +41,7 @@ define([], function () { | ||||
|         this.timeFormat = 'local-format'; | ||||
|         this.durationFormat = 'duration'; | ||||
|  | ||||
|         this.isUTCBased = true; | ||||
|         this.isUTCBased = false; | ||||
|     } | ||||
|  | ||||
|     return LocalTimeSystem; | ||||
|   | ||||
| @@ -24,14 +24,14 @@ import uuid from 'uuid'; | ||||
|  | ||||
| export default class NewFolderAction { | ||||
|     constructor(openmct) { | ||||
|         this.name = 'Add New Folder'; | ||||
|         this.name = 'New Folder'; | ||||
|         this.key = 'newFolder'; | ||||
|         this.description = 'Create a new folder'; | ||||
|         this.cssClass = 'icon-folder-new'; | ||||
|         this.cssClass = 'icon-folder'; | ||||
|  | ||||
|         this._openmct = openmct; | ||||
|         this._dialogForm = { | ||||
|             name: "Add New Folder", | ||||
|             name: "New Folder Name", | ||||
|             sections: [ | ||||
|                 { | ||||
|                     rows: [ | ||||
| @@ -39,9 +39,7 @@ export default class NewFolderAction { | ||||
|                             key: "name", | ||||
|                             control: "textfield", | ||||
|                             name: "Folder Name", | ||||
|                             pattern: "\\S+", | ||||
|                             required: true, | ||||
|                             cssClass: "l-input-lg" | ||||
|                             required: false | ||||
|                         } | ||||
|                     ] | ||||
|                 } | ||||
| @@ -55,7 +53,7 @@ export default class NewFolderAction { | ||||
|             dialogService = this._openmct.$injector.get('dialogService'), | ||||
|             folderType = this._openmct.types.get('folder'); | ||||
|  | ||||
|         dialogService.getUserInput(this._dialogForm, {name: 'Unnamed Folder'}).then((userInput) => { | ||||
|         dialogService.getUserInput(this._dialogForm, {}).then((userInput) => { | ||||
|             let name = userInput.name, | ||||
|                 identifier = { | ||||
|                     key: uuid(), | ||||
|   | ||||
| @@ -2,16 +2,13 @@ | ||||
| <div class="c-snapshots-h"> | ||||
|     <div class="l-browse-bar"> | ||||
|         <div class="l-browse-bar__start"> | ||||
|             <div class="l-browse-bar__object-name--w"> | ||||
|                 <div class="l-browse-bar__object-name c-object-label"> | ||||
|                     <div class="c-object-label__type-icon icon-notebook"></div> | ||||
|                     <div class="c-object-label__name"> | ||||
|                         Notebook Snapshots | ||||
|                         <span v-if="snapshots.length" | ||||
|                               class="l-browse-bar__object-details" | ||||
|                         > {{ snapshots.length }} of {{ getNotebookSnapshotMaxCount() }} | ||||
|                         </span> | ||||
|                     </div> | ||||
|             <div class="l-browse-bar__object-name--w icon-notebook"> | ||||
|                 <div class="l-browse-bar__object-name"> | ||||
|                     Notebook Snapshots | ||||
|                     <span v-if="snapshots.length" | ||||
|                           class="l-browse-bar__object-details" | ||||
|                     > {{ snapshots.length }} of {{ getNotebookSnapshotMaxCount() }} | ||||
|                     </span> | ||||
|                 </div> | ||||
|                 <PopupMenu v-if="snapshots.length > 0" | ||||
|                            :popup-menu-items="popupMenuItems" | ||||
|   | ||||
| @@ -21,34 +21,24 @@ | ||||
| --> | ||||
| <div class="gl-plot plot-legend-{{legend.get('position')}} {{legend.get('expanded')? 'plot-legend-expanded' : 'plot-legend-collapsed'}}"> | ||||
|     <div class="c-plot-legend gl-plot-legend" | ||||
|          ng-class="{ | ||||
|             'hover-on-plot': !!highlights.length, | ||||
|             'is-legend-hidden': legend.get('hideLegendWhenSmall') | ||||
|         }" | ||||
|     > | ||||
|          ng-class="{ 'hover-on-plot': !!highlights.length }" | ||||
|          ng-show="legend.get('position') !== 'hidden'"> | ||||
|         <div class="c-plot-legend__view-control gl-plot-legend__view-control c-disclosure-triangle is-enabled" | ||||
|             ng-class="{ 'c-disclosure-triangle--expanded': legend.get('expanded') }" | ||||
|             ng-click="legend.set('expanded', !legend.get('expanded'));"> | ||||
|         </div> | ||||
|  | ||||
|         <div class="c-plot-legend__wrapper" | ||||
|             ng-class="{ 'is-cursor-locked':  !!lockHighlightPoint }"> | ||||
|         <div class="c-plot-legend__wrapper"> | ||||
|  | ||||
|             <!-- COLLAPSED PLOT LEGEND --> | ||||
|             <div class="plot-wrapper-collapsed-legend" | ||||
|                  ng-class="{'is-cursor-locked': !!lockHighlightPoint }"> | ||||
|                 <div class="c-state-indicator__alert-cursor-lock icon-cursor-lock" title="Cursor is point locked. Click anywhere in the plot to unlock."></div> | ||||
|                  ng-class="{'icon-cursor-lock': !!lockHighlightPoint}"> | ||||
|                 <div class="plot-legend-item" | ||||
|                      ng-class="{ | ||||
|                         'is-missing': series.domainObject.status === 'missing' | ||||
|                     }" | ||||
|                      ng-repeat="series in series track by $index" | ||||
|                 > | ||||
|                       ng-repeat="series in series track by $index"> | ||||
|                     <div class="plot-series-swatch-and-name"> | ||||
|                         <span class="plot-series-color-swatch" | ||||
|                               ng-style="{ 'background-color': series.get('color').asHexString() }"> | ||||
|                         </span> | ||||
|                         <span class="is-missing__indicator" title="This item is missing"></span> | ||||
|                         <span class="plot-series-name">{{ series.get('name') }}</span> | ||||
|                     </div> | ||||
|                     <div class="plot-series-value hover-value-enabled value-to-display-{{ legend.get('valueToShowWhenCollapsed') }} {{ series.closest.mctLimitState.cssClass }}" | ||||
| @@ -65,10 +55,7 @@ | ||||
|             </div> | ||||
|  | ||||
|             <!-- EXPANDED PLOT LEGEND --> | ||||
|             <div class="plot-wrapper-expanded-legend" | ||||
|                  ng-class="{'is-cursor-locked': !!lockHighlightPoint }" | ||||
|             > | ||||
|                 <div class="c-state-indicator__alert-cursor-lock--verbose icon-cursor-lock" title="Click anywhere in the plot to unlock."> Cursor locked to point</div> | ||||
|             <div class="plot-wrapper-expanded-legend"> | ||||
|                 <table> | ||||
|                     <thead> | ||||
|                         <tr> | ||||
| @@ -89,17 +76,12 @@ | ||||
|                             </th> | ||||
|                         </tr> | ||||
|                     </thead> | ||||
|                     <tr ng-repeat="series in series" | ||||
|                         class="plot-legend-item" | ||||
|                         ng-class="{ | ||||
|                             'is-missing': series.domainObject.status === 'missing' | ||||
|                         }" | ||||
|                     > | ||||
|                         <td class="plot-series-swatch-and-name"> | ||||
|                     <tr ng-repeat="series in series" class="plot-legend-item"> | ||||
|                         <td class="plot-series-swatch-and-name" | ||||
|                             ng-class="{'icon-cursor-lock': !!lockHighlightPoint}"> | ||||
|                             <span class="plot-series-color-swatch" | ||||
|                                   ng-style="{ 'background-color': series.get('color').asHexString() }"> | ||||
|                             </span> | ||||
|                             <span class="is-missing__indicator" title="This item is missing"></span> | ||||
|                             <span class="plot-series-name">{{ series.get('name') }}</span> | ||||
|                         </td> | ||||
|  | ||||
| @@ -135,7 +117,7 @@ | ||||
|     <div class="plot-wrapper-axis-and-display-area flex-elem grows"> | ||||
|         <div class="gl-plot-axis-area gl-plot-y has-local-controls" | ||||
|              ng-style="{ | ||||
|                  width: (tickWidth + 20) + 'px' | ||||
|                  width: (tickWidth + 30) + 'px' | ||||
|              }"> | ||||
|  | ||||
|             <div class="gl-plot-label gl-plot-y-label" | ||||
| @@ -152,6 +134,7 @@ | ||||
|                     {{option.name}} | ||||
|                 </option> | ||||
|             </select> | ||||
|              | ||||
|  | ||||
|             <mct-ticks axis="yAxis"> | ||||
|                 <div ng-repeat="tick in ticks track by tick.value" | ||||
| @@ -165,15 +148,17 @@ | ||||
|         </div> | ||||
|         <div class="gl-plot-wrapper-display-area-and-x-axis" | ||||
|              ng-style="{ | ||||
|                  left: (tickWidth + 20) + 'px' | ||||
|              }"> | ||||
|                      left: (tickWidth + 30) + 'px' | ||||
|                  }"> | ||||
|             <div 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> | ||||
|                 <span class="l-state-indicators__alert-cursor-lock icon-cursor-lock" | ||||
|                       title="Telemetry point selection is locked. Click anywhere in the plot to unlock." | ||||
|                       ng-if="lockHighlightPoint"></span> | ||||
|             </div> | ||||
|  | ||||
|             <div class="gl-plot-display-area has-local-controls has-cursor-guides"> | ||||
|                 <div 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> | ||||
|  | ||||
|                 <mct-ticks axis="xAxis"> | ||||
|                     <div class="gl-plot-hash hash-v" | ||||
|                          ng-repeat="tick in ticks track by tick.value" | ||||
|   | ||||
| @@ -44,7 +44,7 @@ | ||||
|                 </li> | ||||
|                 <li class="grid-row"> | ||||
|                     <div class="grid-cell label" | ||||
|                          title="The rendering method to join lines for this series.">Line Method</div> | ||||
|                          title="The line rendering style for this series.">Line Style</div> | ||||
|                     <div class="grid-cell value">{{ { | ||||
|                         'none': 'None', | ||||
|                         'linear': 'Linear interpolation', | ||||
| @@ -56,7 +56,7 @@ | ||||
|                     <div class="grid-cell label" | ||||
|                          title="Whether markers are displayed, and their size.">Markers</div> | ||||
|                     <div class="grid-cell value"> | ||||
|                         {{ series.markerOptionsDisplayText() }} | ||||
|                         {{series.get('markers') ? "Enabled: " + series.get('markerSize') + "px" : "Disabled"}} | ||||
|                     </div> | ||||
|                 </li> | ||||
|                 <li class="grid-row"> | ||||
| @@ -114,11 +114,6 @@ | ||||
|                      title="The position of the legend relative to the plot display area.">Position</div> | ||||
|                 <div class="grid-cell value capitalize">{{ config.legend.get('position') }}</div> | ||||
|             </li> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="Hide the legend when the plot is small">Hide when plot small</div> | ||||
|                 <div class="grid-cell value">{{ config.legend.get('hideLegendWhenSmall') ? "Yes" : "No" }}</div> | ||||
|             </li> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="Show the legend expanded by default">Expand by Default</div> | ||||
|   | ||||
| @@ -52,7 +52,7 @@ | ||||
|                 </li> | ||||
|                 <li class="grid-row"> | ||||
|                     <div class="grid-cell label" | ||||
|                          title="The rendering method to join lines for this series.">Line Method</div> | ||||
|                          title="The line rendering style for this series.">Line Style</div> | ||||
|                     <div class="grid-cell value"> | ||||
|                         <select ng-model="form.interpolate"> | ||||
|                             <option value="none">None</option> | ||||
| @@ -64,27 +64,12 @@ | ||||
|                 <li class="grid-row"> | ||||
|                     <div class="grid-cell label" | ||||
|                          title="Whether markers are displayed.">Markers</div> | ||||
|                     <div class="grid-cell value"> | ||||
|                         <input type="checkbox" ng-model="form.markers"/> | ||||
|                         <select | ||||
|                             ng-show="form.markers" | ||||
|                             ng-model="form.markerShape"> | ||||
|                             <option | ||||
|                                 ng-repeat="option in markerShapeOptions" | ||||
|                                 value="{{ option.value }}" | ||||
|                                 ng-selected="option.value == form.markerShape" | ||||
|                             > | ||||
|                                 {{ option.name }} | ||||
|                             </option> | ||||
|                         </select> | ||||
|                     </div> | ||||
|                     <div class="grid-cell value"><input type="checkbox" ng-model="form.markers"/></div> | ||||
|                 </li> | ||||
|                 <li class="grid-row"> | ||||
|                     <div class="grid-cell label" | ||||
|                          title="Display markers visually denoting points in alarm.">Alarm Markers</div> | ||||
|                     <div class="grid-cell value"> | ||||
|                         <input type="checkbox" ng-model="form.alarmMarkers"/> | ||||
|                     </div> | ||||
|                     <div class="grid-cell value"><input type="checkbox" ng-model="form.alarmMarkers"/></div> | ||||
|                 </li> | ||||
|                 <li class="grid-row" ng-show="form.markers || form.alarmMarkers"> | ||||
|                     <div class="grid-cell label" | ||||
| @@ -174,6 +159,7 @@ | ||||
|                      title="The position of the legend relative to the plot display area.">Position</div> | ||||
|                 <div class="grid-cell value"> | ||||
|                     <select ng-model="form.position"> | ||||
|                         <option value="hidden">Hidden</option> | ||||
|                         <option value="top">Top</option> | ||||
|                         <option value="right">Right</option> | ||||
|                         <option value="bottom">Bottom</option> | ||||
| @@ -181,11 +167,6 @@ | ||||
|                     </select> | ||||
|                 </div> | ||||
|             </li> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="Hide the legend when the plot is small">Hide when plot small</div> | ||||
|                 <div class="grid-cell value"><input type="checkbox" ng-model="form.hideLegendWhenSmall"/></div> | ||||
|             </li> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="Show the legend expanded by default">Expand by default</div> | ||||
|   | ||||
| @@ -371,8 +371,7 @@ function ( | ||||
|             chartElement.getBuffer(), | ||||
|             chartElement.color().asRGBAArray(), | ||||
|             chartElement.count, | ||||
|             chartElement.series.get('markerSize'), | ||||
|             chartElement.series.get('markerShape') | ||||
|             chartElement.series.get('markerSize') | ||||
|         ); | ||||
|     }; | ||||
|  | ||||
| @@ -396,10 +395,9 @@ function ( | ||||
|                 this.offset.yVal(highlight.point, highlight.series) | ||||
|             ]), | ||||
|             color = highlight.series.get('color').asRGBAArray(), | ||||
|             pointCount = 1, | ||||
|             shape = highlight.series.get('markerShape'); | ||||
|             pointCount = 1; | ||||
|  | ||||
|         this.drawAPI.drawPoints(points, color, pointCount, HIGHLIGHT_SIZE, shape); | ||||
|         this.drawAPI.drawPoints(points, color, pointCount, HIGHLIGHT_SIZE); | ||||
|     }; | ||||
|  | ||||
|     MCTChartController.prototype.drawRectangles = function () { | ||||
|   | ||||
| @@ -48,7 +48,6 @@ define([ | ||||
|             return { | ||||
|                 position: 'top', | ||||
|                 expandByDefault: false, | ||||
|                 hideLegendWhenSmall: false, | ||||
|                 valueToShowWhenCollapsed: 'nearestValue', | ||||
|                 showTimestampWhenExpanded: true, | ||||
|                 showValueWhenExpanded: true, | ||||
|   | ||||
| @@ -25,14 +25,12 @@ define([ | ||||
|     'lodash', | ||||
|     '../configuration/Model', | ||||
|     '../lib/extend', | ||||
|     'EventEmitter', | ||||
|     '../draw/MarkerShapes' | ||||
|     'EventEmitter' | ||||
| ], function ( | ||||
|     _, | ||||
|     Model, | ||||
|     extend, | ||||
|     EventEmitter, | ||||
|     MARKER_SHAPES | ||||
|     EventEmitter | ||||
| ) { | ||||
|  | ||||
|     /** | ||||
| @@ -58,7 +56,6 @@ define([ | ||||
|      *                `linear` (points are connected via straight lines), or | ||||
|      *                `stepAfter` (points are connected by steps). | ||||
|      * `markers`: boolean, whether or not this series should render with markers. | ||||
|      * `markerShape`: string, shape of markers. | ||||
|      * `markerSize`: number, size in pixels of markers for this series. | ||||
|      * `alarmMarkers`: whether or not to display alarm markers for this series. | ||||
|      * `stats`: An object that tracks the min and max y values observed in this | ||||
| @@ -104,7 +101,6 @@ define([ | ||||
|                 xKey: options.collection.plot.xAxis.get('key'), | ||||
|                 yKey: range.key, | ||||
|                 markers: true, | ||||
|                 markerShape: 'point', | ||||
|                 markerSize: 2.0, | ||||
|                 alarmMarkers: true | ||||
|             }; | ||||
| @@ -414,18 +410,6 @@ define([ | ||||
|             } else { | ||||
|                 this.filters = deepCopiedFilters; | ||||
|             } | ||||
|         }, | ||||
|         markerOptionsDisplayText: function () { | ||||
|             const showMarkers = this.get('markers'); | ||||
|             if (!showMarkers) { | ||||
|                 return "Disabled"; | ||||
|             } | ||||
|  | ||||
|             const markerShapeKey = this.get('markerShape'); | ||||
|             const markerShape = MARKER_SHAPES[markerShapeKey].label; | ||||
|             const markerSize = this.get('markerSize'); | ||||
|  | ||||
|             return `${markerShape}: ${markerSize}px`; | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|   | ||||
| @@ -23,12 +23,10 @@ | ||||
|  | ||||
| define([ | ||||
|     'EventEmitter', | ||||
|     '../lib/eventHelpers', | ||||
|     './MarkerShapes' | ||||
|     '../lib/eventHelpers' | ||||
| ], function ( | ||||
|     EventEmitter, | ||||
|     eventHelpers, | ||||
|     MARKER_SHAPES | ||||
|     eventHelpers | ||||
| ) { | ||||
|  | ||||
|     /** | ||||
| @@ -123,17 +121,18 @@ define([ | ||||
|         buf, | ||||
|         color, | ||||
|         points, | ||||
|         pointSize, | ||||
|         shape | ||||
|         pointSize | ||||
|     ) { | ||||
|         const drawC2DShape = MARKER_SHAPES[shape].drawC2D.bind(this); | ||||
|         var i = 0, | ||||
|             offset = pointSize / 2; | ||||
|  | ||||
|         this.setColor(color); | ||||
|  | ||||
|         for (let i = 0; i < points; i++) { | ||||
|             drawC2DShape( | ||||
|                 this.x(buf[i * 2]), | ||||
|                 this.y(buf[i * 2 + 1]), | ||||
|         for (; i < points; i++) { | ||||
|             this.c2d.fillRect( | ||||
|                 this.x(buf[i * 2]) - offset, | ||||
|                 this.y(buf[i * 2 + 1]) - offset, | ||||
|                 pointSize, | ||||
|                 pointSize | ||||
|             ); | ||||
|         } | ||||
|   | ||||
| @@ -23,64 +23,30 @@ | ||||
|  | ||||
| define([ | ||||
|     'EventEmitter', | ||||
|     '../lib/eventHelpers', | ||||
|     './MarkerShapes' | ||||
|     '../lib/eventHelpers' | ||||
| ], function ( | ||||
|     EventEmitter, | ||||
|     eventHelpers, | ||||
|     MARKER_SHAPES | ||||
|     eventHelpers | ||||
| ) { | ||||
|  | ||||
|     // WebGL shader sources (for drawing plain colors) | ||||
|     const FRAGMENT_SHADER = ` | ||||
|         precision mediump float; | ||||
|         uniform vec4 uColor; | ||||
|         uniform int uMarkerShape; | ||||
|          | ||||
|         void main(void) { | ||||
|             gl_FragColor = uColor; | ||||
|  | ||||
|             if (uMarkerShape > 1) { | ||||
|                 vec2 clipSpacePointCoord = 2.0 * gl_PointCoord - 1.0; | ||||
|  | ||||
|                 if (uMarkerShape == 2) { // circle | ||||
|                     float distance = length(clipSpacePointCoord); | ||||
|  | ||||
|                     if (distance > 1.0) { | ||||
|                         discard; | ||||
|                     } | ||||
|                 } else if (uMarkerShape == 3) { // diamond | ||||
|                     float distance = abs(clipSpacePointCoord.x) + abs(clipSpacePointCoord.y); | ||||
|  | ||||
|                     if (distance > 1.0) { | ||||
|                         discard; | ||||
|                     } | ||||
|                 } else if (uMarkerShape == 4) { // triangle | ||||
|                     float x = clipSpacePointCoord.x; | ||||
|                     float y = clipSpacePointCoord.y; | ||||
|                     float distance = 2.0 * x - 1.0; | ||||
|                     float distance2 = -2.0 * x - 1.0; | ||||
|  | ||||
|                     if (distance > y || distance2 > y) { | ||||
|                         discard; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|         } | ||||
|     `; | ||||
|  | ||||
|     const VERTEX_SHADER = ` | ||||
|         attribute vec2 aVertexPosition; | ||||
|         uniform vec2 uDimensions; | ||||
|         uniform vec2 uOrigin; | ||||
|         uniform float uPointSize; | ||||
|          | ||||
|         void main(void) { | ||||
|             gl_Position = vec4(2.0 * ((aVertexPosition - uOrigin) / uDimensions) - vec2(1,1), 0, 1); | ||||
|             gl_PointSize = uPointSize; | ||||
|         } | ||||
|     `; | ||||
|     var FRAGMENT_SHADER = [ | ||||
|             "precision mediump float;", | ||||
|             "uniform vec4 uColor;", | ||||
|             "void main(void) {", | ||||
|             "gl_FragColor = uColor;", | ||||
|             "}" | ||||
|         ].join('\n'), | ||||
|         VERTEX_SHADER = [ | ||||
|             "attribute vec2 aVertexPosition;", | ||||
|             "uniform vec2 uDimensions;", | ||||
|             "uniform vec2 uOrigin;", | ||||
|             "uniform float uPointSize;", | ||||
|             "void main(void) {", | ||||
|             "gl_Position = vec4(2.0 * ((aVertexPosition - uOrigin) / uDimensions) - vec2(1,1), 0, 1);", | ||||
|             "gl_PointSize = uPointSize;", | ||||
|             "}" | ||||
|         ].join('\n'); | ||||
|  | ||||
|     /** | ||||
|      * Create a draw api utilizing WebGL. | ||||
| @@ -124,7 +90,6 @@ define([ | ||||
|         this.vertexShader = this.gl.createShader(this.gl.VERTEX_SHADER); | ||||
|         this.gl.shaderSource(this.vertexShader, VERTEX_SHADER); | ||||
|         this.gl.compileShader(this.vertexShader); | ||||
|  | ||||
|         this.fragmentShader = this.gl.createShader(this.gl.FRAGMENT_SHADER); | ||||
|         this.gl.shaderSource(this.fragmentShader, FRAGMENT_SHADER); | ||||
|         this.gl.compileShader(this.fragmentShader); | ||||
| @@ -140,7 +105,6 @@ define([ | ||||
|         // shader programs (to pass values into shaders at draw-time) | ||||
|         this.aVertexPosition = this.gl.getAttribLocation(this.program, "aVertexPosition"); | ||||
|         this.uColor = this.gl.getUniformLocation(this.program, "uColor"); | ||||
|         this.uMarkerShape = this.gl.getUniformLocation(this.program, "uMarkerShape"); | ||||
|         this.uDimensions = this.gl.getUniformLocation(this.program, "uDimensions"); | ||||
|         this.uOrigin = this.gl.getUniformLocation(this.program, "uOrigin"); | ||||
|         this.uPointSize = this.gl.getUniformLocation(this.program, "uPointSize"); | ||||
| @@ -150,6 +114,9 @@ define([ | ||||
|         // Create a buffer to holds points which will be drawn | ||||
|         this.buffer = this.gl.createBuffer(); | ||||
|  | ||||
|         // Use a line width of 2.0 for legibility | ||||
|         this.gl.lineWidth(2.0); | ||||
|  | ||||
|         // Enable blending, for smoothness | ||||
|         this.gl.enable(this.gl.BLEND); | ||||
|         this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA); | ||||
| @@ -171,18 +138,14 @@ define([ | ||||
|             ((v - this.origin[1]) / this.dimensions[1]) * this.height; | ||||
|     }; | ||||
|  | ||||
|     DrawWebGL.prototype.doDraw = function (drawType, buf, color, points, shape) { | ||||
|     DrawWebGL.prototype.doDraw = function (drawType, buf, color, points) { | ||||
|         if (this.isContextLost) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         const shapeCode = MARKER_SHAPES[shape] ? MARKER_SHAPES[shape].drawWebGL : 0; | ||||
|  | ||||
|         this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.buffer); | ||||
|         this.gl.bufferData(this.gl.ARRAY_BUFFER, buf, this.gl.DYNAMIC_DRAW); | ||||
|         this.gl.vertexAttribPointer(this.aVertexPosition, 2, this.gl.FLOAT, false, 0, 0); | ||||
|         this.gl.uniform4fv(this.uColor, color); | ||||
|         this.gl.uniform1i(this.uMarkerShape, shapeCode) | ||||
|         this.gl.drawArrays(drawType, 0, points); | ||||
|     }; | ||||
|  | ||||
| @@ -247,12 +210,12 @@ define([ | ||||
|      * Draw the buffer as points. | ||||
|      * | ||||
|      */ | ||||
|     DrawWebGL.prototype.drawPoints = function (buf, color, points, pointSize, shape) { | ||||
|     DrawWebGL.prototype.drawPoints = function (buf, color, points, pointSize) { | ||||
|         if (this.isContextLost) { | ||||
|             return; | ||||
|         } | ||||
|         this.gl.uniform1f(this.uPointSize, pointSize); | ||||
|         this.doDraw(this.gl.POINTS, buf, color, points, shape); | ||||
|         this.doDraw(this.gl.POINTS, buf, color, points); | ||||
|     }; | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -1,90 +0,0 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2020, 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 () { | ||||
|     /** | ||||
|      * @label string (required) display name of shape | ||||
|      * @drawWebGL integer (unique, required) index provided to WebGL Fragment Shader | ||||
|      * @drawC2D function (required) canvas2d draw function | ||||
|      */ | ||||
|     const MARKER_SHAPES = { | ||||
|         point: { | ||||
|             label: 'Point', | ||||
|             drawWebGL: 1, | ||||
|             drawC2D: function (x, y, size) { | ||||
|                 const offset = size / 2; | ||||
|  | ||||
|                 this.c2d.fillRect(x - offset, y - offset, size, size); | ||||
|             } | ||||
|         }, | ||||
|         circle: { | ||||
|             label: 'Circle', | ||||
|             drawWebGL: 2, | ||||
|             drawC2D: function (x, y, size) { | ||||
|                 const radius = size / 2; | ||||
|  | ||||
|                 this.c2d.beginPath(); | ||||
|                 this.c2d.arc(x, y, radius, 0, 2 * Math.PI, false); | ||||
|                 this.c2d.closePath(); | ||||
|                 this.c2d.fill(); | ||||
|             } | ||||
|         }, | ||||
|         diamond: { | ||||
|             label: 'Diamond', | ||||
|             drawWebGL: 3, | ||||
|             drawC2D: function (x, y, size) { | ||||
|                 const offset = size / 2; | ||||
|                 const top = [x, y + offset]; | ||||
|                 const right = [x + offset, y]; | ||||
|                 const bottom = [x, y - offset]; | ||||
|                 const left = [x - offset, y]; | ||||
|  | ||||
|                 this.c2d.beginPath(); | ||||
|                 this.c2d.moveTo(...top); | ||||
|                 this.c2d.lineTo(...right); | ||||
|                 this.c2d.lineTo(...bottom); | ||||
|                 this.c2d.lineTo(...left); | ||||
|                 this.c2d.closePath(); | ||||
|                 this.c2d.fill(); | ||||
|             } | ||||
|         }, | ||||
|         triangle: { | ||||
|             label: 'Triangle', | ||||
|             drawWebGL: 4, | ||||
|             drawC2D: function (x, y, size) { | ||||
|                 const offset = size / 2; | ||||
|                 const v1 = [x, y - offset]; | ||||
|                 const v2 = [x - offset, y + offset]; | ||||
|                 const v3 = [x + offset, y + offset]; | ||||
|  | ||||
|                 this.c2d.beginPath(); | ||||
|                 this.c2d.moveTo(...v1); | ||||
|                 this.c2d.lineTo(...v2); | ||||
|                 this.c2d.lineTo(...v3); | ||||
|                 this.c2d.closePath(); | ||||
|                 this.c2d.fill(); | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     return MARKER_SHAPES; | ||||
| }); | ||||
| @@ -32,11 +32,6 @@ define([ | ||||
|                 modelProp: 'position', | ||||
|                 objectPath: 'configuration.legend.position' | ||||
|             }, | ||||
|             { | ||||
|                 modelProp: 'hideLegendWhenSmall', | ||||
|                 coerce: Boolean, | ||||
|                 objectPath: 'configuration.legend.hideLegendWhenSmall' | ||||
|             }, | ||||
|             { | ||||
|                 modelProp: 'expandByDefault', | ||||
|                 coerce: Boolean, | ||||
|   | ||||
| @@ -22,11 +22,9 @@ | ||||
|  | ||||
| define([ | ||||
|     './PlotModelFormController', | ||||
|     '../draw/MarkerShapes', | ||||
|     'lodash' | ||||
| ], function ( | ||||
|     PlotModelFormController, | ||||
|     MARKER_SHAPES, | ||||
|     _ | ||||
| ) { | ||||
|  | ||||
| @@ -95,13 +93,6 @@ define([ | ||||
|                         value: o.key | ||||
|                     }; | ||||
|                 }); | ||||
|             this.$scope.markerShapeOptions = Object.entries(MARKER_SHAPES) | ||||
|                 .map(([key, obj]) => { | ||||
|                     return { | ||||
|                         name: obj.label, | ||||
|                         value: key | ||||
|                     }; | ||||
|                 }); | ||||
|         }, | ||||
|  | ||||
|         fields: [ | ||||
| @@ -117,10 +108,6 @@ define([ | ||||
|                 modelProp: 'markers', | ||||
|                 objectPath: dynamicPathForKey('markers') | ||||
|             }, | ||||
|             { | ||||
|                 modelProp: 'markerShape', | ||||
|                 objectPath: dynamicPathForKey('markerShape') | ||||
|             }, | ||||
|             { | ||||
|                 modelProp: 'markerSize', | ||||
|                 coerce: Number, | ||||
|   | ||||
| @@ -71,6 +71,8 @@ define([ | ||||
|         this.listenTo(this.$canvas, 'mouseleave', this.untrackMousePosition, this); | ||||
|         this.listenTo(this.$canvas, 'mousedown', this.onMouseDown, this); | ||||
|         this.listenTo(this.$canvas, 'wheel', this.wheelZoom, this); | ||||
|  | ||||
|         this.watchForMarquee(); | ||||
|     }; | ||||
|  | ||||
|     MCTPlotController.prototype.initialize = function () { | ||||
| @@ -81,6 +83,11 @@ define([ | ||||
|         this.listenTo(this.$canvas, 'mousedown', this.onMouseDown, this); | ||||
|         this.listenTo(this.$canvas, 'wheel', this.wheelZoom, this); | ||||
|  | ||||
|         this.watchForMarquee(); | ||||
|  | ||||
|         this.listenTo(this.$window, 'keydown', this.toggleInteractionMode, this); | ||||
|         this.listenTo(this.$window, 'keyup', this.resetInteractionMode, this); | ||||
|  | ||||
|         this.$scope.rectangles = []; | ||||
|         this.$scope.tickWidth = 0; | ||||
|  | ||||
| @@ -236,16 +243,12 @@ define([ | ||||
|     }; | ||||
|  | ||||
|     MCTPlotController.prototype.onMouseDown = function ($event) { | ||||
|         // do not monitor drag events on browser context click | ||||
|         if (event.ctrlKey) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         this.listenTo(this.$window, 'mouseup', this.onMouseUp, this); | ||||
|         this.listenTo(this.$window, 'mousemove', this.trackMousePosition, this); | ||||
|         if (event.altKey) { | ||||
|         if (this.allowPan) { | ||||
|             return this.startPan($event); | ||||
|         } else { | ||||
|         } | ||||
|         if (this.allowMarquee) { | ||||
|             return this.startMarquee($event); | ||||
|         } | ||||
|     }; | ||||
| @@ -258,11 +261,11 @@ define([ | ||||
|             this.$scope.lockHighlightPoint = !this.$scope.lockHighlightPoint; | ||||
|         } | ||||
|  | ||||
|         if (this.pan) { | ||||
|         if (this.allowPan) { | ||||
|             return this.endPan($event); | ||||
|         } | ||||
|  | ||||
|         if (this.marquee) { | ||||
|         if (this.allowMarquee) { | ||||
|             return this.endMarquee($event); | ||||
|         } | ||||
|     }; | ||||
| @@ -286,9 +289,6 @@ define([ | ||||
|     }; | ||||
|  | ||||
|     MCTPlotController.prototype.startMarquee = function ($event) { | ||||
|         this.$canvas.removeClass('plot-drag'); | ||||
|         this.$canvas.addClass('plot-marquee'); | ||||
|  | ||||
|         this.trackMousePosition($event); | ||||
|         if (this.positionOverPlot) { | ||||
|             this.freeze(); | ||||
| @@ -444,9 +444,6 @@ define([ | ||||
|     }; | ||||
|  | ||||
|     MCTPlotController.prototype.startPan = function ($event) { | ||||
|         this.$canvas.addClass('plot-drag'); | ||||
|         this.$canvas.removeClass('plot-marquee'); | ||||
|  | ||||
|         this.trackMousePosition($event); | ||||
|         this.freeze(); | ||||
|         this.pan = { | ||||
| @@ -489,6 +486,32 @@ define([ | ||||
|         this.$scope.$emit('user:viewport:change:end'); | ||||
|     }; | ||||
|  | ||||
|     MCTPlotController.prototype.watchForMarquee = function () { | ||||
|         this.$canvas.removeClass('plot-drag'); | ||||
|         this.$canvas.addClass('plot-marquee'); | ||||
|         this.allowPan = false; | ||||
|         this.allowMarquee = true; | ||||
|     }; | ||||
|  | ||||
|     MCTPlotController.prototype.watchForPan = function () { | ||||
|         this.$canvas.addClass('plot-drag'); | ||||
|         this.$canvas.removeClass('plot-marquee'); | ||||
|         this.allowPan = true; | ||||
|         this.allowMarquee = false; | ||||
|     }; | ||||
|  | ||||
|     MCTPlotController.prototype.toggleInteractionMode = function (event) { | ||||
|         if (event.keyCode === 18) { // control key. | ||||
|             this.watchForPan(); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     MCTPlotController.prototype.resetInteractionMode = function (event) { | ||||
|         if (event.keyCode === 18) { | ||||
|             this.watchForMarquee(); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     MCTPlotController.prototype.freeze = function () { | ||||
|         this.config.yAxis.set('frozen', true); | ||||
|         this.config.xAxis.set('frozen', true); | ||||
|   | ||||
							
								
								
									
										7
									
								
								src/plugins/tabs/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/plugins/tabs/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| # Espresso Theme | ||||
| A light colored theme for the Open MCT user interface. | ||||
|  | ||||
| ## Installation | ||||
| ```js | ||||
| openmct.install(openmct.plugins.Snow()); | ||||
| ``` | ||||
| @@ -17,19 +17,6 @@ | ||||
|             margin-right: $interiorMarginSm; | ||||
|             opacity: 0.7; | ||||
|         } | ||||
|  | ||||
|         &__label { | ||||
|             flex: 1 1 auto; | ||||
|         } | ||||
|  | ||||
|         &__close-btn { | ||||
|             flex: 0 0 auto; | ||||
|             pointer-events: all; | ||||
|         } | ||||
|  | ||||
|         > * + * { | ||||
|             margin-left: $interiorMargin; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     &__object-holder { | ||||
|   | ||||
| @@ -3,7 +3,7 @@ | ||||
|     <div | ||||
|         class="c-tabs-view__tabs-holder c-tabs" | ||||
|         :class="{ | ||||
|             'is-dragging': isDragging && allowEditing, | ||||
|             'is-dragging': isDragging, | ||||
|             'is-mouse-over': allowDrop | ||||
|         }" | ||||
|     > | ||||
| @@ -19,21 +19,18 @@ | ||||
|         > | ||||
|             Drag objects here to add them to this view. | ||||
|         </div> | ||||
|         <div | ||||
|         <button | ||||
|             v-for="(tab,index) in tabsList" | ||||
|             :key="index" | ||||
|             class="c-tab c-tabs-view__tab" | ||||
|             :class="{ | ||||
|                 'is-current': isCurrent(tab) | ||||
|             }" | ||||
|             class="c-tabs-view__tab c-tab" | ||||
|             :class="[ | ||||
|                 {'is-current': isCurrent(tab)}, | ||||
|                 tab.type.definition.cssClass | ||||
|             ]" | ||||
|             @click="showTab(tab, index)" | ||||
|         > | ||||
|             <span class="c-button__label c-tabs-view__tab__label">{{ tab.domainObject.name }}</span> | ||||
|             <button v-if="isEditing" | ||||
|                     class="icon-x c-click-icon c-tabs-view__tab__close-btn" | ||||
|                     @click="showRemoveDialog(index)" | ||||
|             ></button> | ||||
|         </div> | ||||
|             <span class="c-button__label">{{ tab.domainObject.name }}</span> | ||||
|         </button> | ||||
|     </div> | ||||
|     <div | ||||
|         v-for="(tab, index) in tabsList" | ||||
| @@ -41,6 +38,15 @@ | ||||
|         class="c-tabs-view__object-holder" | ||||
|         :class="{'c-tabs-view__object-holder--hidden': !isCurrent(tab)}" | ||||
|     > | ||||
|         <div | ||||
|             v-if="currentTab" | ||||
|             class="c-tabs-view__object-name c-object-label l-browse-bar__object-name--w" | ||||
|             :class="currentTab.type.definition.cssClass" | ||||
|         > | ||||
|             <div class="l-browse-bar__object-name c-object-label__name"> | ||||
|                 {{ currentTab.domainObject.name }} | ||||
|             </div> | ||||
|         </div> | ||||
|         <object-view | ||||
|             v-if="internalDomainObject.keep_alive ? currentTab : isCurrent(tab)" | ||||
|             class="c-tabs-view__object" | ||||
| @@ -52,13 +58,6 @@ | ||||
|  | ||||
| <script> | ||||
| import ObjectView from '../../../ui/components/ObjectView.vue'; | ||||
| import RemoveAction from '../../remove/RemoveAction.js'; | ||||
| import { | ||||
|     getSearchParam, | ||||
|     setSearchParam, | ||||
|     deleteSearchParam | ||||
| } from 'utils/openmctLocation'; | ||||
|  | ||||
|  | ||||
| var unknownObjectType = { | ||||
|     definition: { | ||||
| @@ -72,114 +71,53 @@ export default { | ||||
|     components: { | ||||
|         ObjectView | ||||
|     }, | ||||
|     props: { | ||||
|         isEditing: { | ||||
|             type: Boolean, | ||||
|             required: true | ||||
|         } | ||||
|     }, | ||||
|     data: function () { | ||||
|         let keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier); | ||||
|  | ||||
|         return { | ||||
|             internalDomainObject: this.domainObject, | ||||
|             currentTab: {}, | ||||
|             currentTabIndex: undefined, | ||||
|             tabsList: [], | ||||
|             setCurrentTab: true, | ||||
|             isDragging: false, | ||||
|             allowDrop: false, | ||||
|             searchTabKey: `tabs.pos.${keyString}` | ||||
|             allowDrop: false | ||||
|         }; | ||||
|     }, | ||||
|     computed: { | ||||
|         allowEditing() { | ||||
|             return !this.internalDomainObject.locked && this.isEditing; | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         if (this.composition) { | ||||
|             this.composition.on('add', this.addItem); | ||||
|             this.composition.on('remove', this.removeItem); | ||||
|             this.composition.on('reorder', this.onReorder); | ||||
|             this.composition.load().then(() => { | ||||
|                 let currentTabIndexFromURL = getSearchParam(this.searchTabKey); | ||||
|                 let currentTabIndexFromDomainObject = this.internalDomainObject.currentTabIndex; | ||||
|                 let currentTabIndex = this.domainObject.currentTabIndex; | ||||
|  | ||||
|                 if (currentTabIndexFromURL !== null) { | ||||
|                     this.setCurrentTabByIndex(currentTabIndexFromURL); | ||||
|                 } else if (currentTabIndexFromDomainObject !== undefined) { | ||||
|                     this.setCurrentTabByIndex(currentTabIndexFromDomainObject); | ||||
|                     this.storeCurrentTabIndexInURL(currentTabIndexFromDomainObject); | ||||
|                 if (currentTabIndex !== undefined && this.tabsList.length > currentTabIndex) { | ||||
|                     this.currentTab = this.tabsList[currentTabIndex]; | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         this.unsubscribe = this.openmct.objects.observe(this.internalDomainObject, '*', this.updateInternalDomainObject); | ||||
|  | ||||
|         this.RemoveAction = new RemoveAction(this.openmct); | ||||
|         document.addEventListener('dragstart', this.dragstart); | ||||
|         document.addEventListener('dragend', this.dragend); | ||||
|     }, | ||||
|     beforeDestroy() { | ||||
|         this.persistCurrentTabIndex(this.currentTabIndex); | ||||
|     }, | ||||
|     destroyed() { | ||||
|         this.composition.off('add', this.addItem); | ||||
|         this.composition.off('remove', this.removeItem); | ||||
|         this.composition.off('reorder', this.onReorder); | ||||
|  | ||||
|         this.unsubscribe(); | ||||
|         this.clearCurrentTabIndexFromURL(); | ||||
|  | ||||
|         document.removeEventListener('dragstart', this.dragstart); | ||||
|         document.removeEventListener('dragend', this.dragend); | ||||
|     }, | ||||
|     methods:{ | ||||
|         setCurrentTabByIndex(index) { | ||||
|             if (this.tabsList[index]) { | ||||
|                 this.currentTab = this.tabsList[index]; | ||||
|             } | ||||
|         }, | ||||
|         showTab(tab, index) { | ||||
|             if (index !== undefined) { | ||||
|                 this.storeCurrentTabIndexInURL(index); | ||||
|                 this.storeCurrentTabIndex(index); | ||||
|             } | ||||
|  | ||||
|             this.currentTab = tab; | ||||
|         }, | ||||
|         showRemoveDialog(index) { | ||||
|             if(!this.tabsList[index]) { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             let activeTab = this.tabsList[index]; | ||||
|             let childDomainObject = activeTab.domainObject | ||||
|  | ||||
|             let prompt = this.openmct.overlays.dialog({ | ||||
|                 iconClass: 'alert', | ||||
|                 message: `This action will remove this tab from the Tabs Layout. Do you want to continue?`, | ||||
|                 buttons: [ | ||||
|                     { | ||||
|                         label: 'Ok', | ||||
|                         emphasis: 'true', | ||||
|                         callback: () => { | ||||
|                             this.removeFromComposition(childDomainObject); | ||||
|                             prompt.dismiss(); | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
|                         label: 'Cancel', | ||||
|                         callback: () => { | ||||
|                             prompt.dismiss(); | ||||
|                         } | ||||
|                     } | ||||
|                 ] | ||||
|             }); | ||||
|         }, | ||||
|         removeFromComposition(childDomainObject) { | ||||
|             this.composition.remove(childDomainObject); | ||||
|         }, | ||||
|         addItem(domainObject) { | ||||
|             let type = this.openmct.types.get(domainObject.type) || unknownObjectType, | ||||
|                 tabItem = { | ||||
| @@ -195,10 +133,6 @@ export default { | ||||
|                 this.setCurrentTab = false; | ||||
|             } | ||||
|         }, | ||||
|         reset() { | ||||
|             this.currentTab = {}; | ||||
|             this.setCurrentTab = true; | ||||
|         }, | ||||
|         removeItem(identifier) { | ||||
|             let pos = this.tabsList.findIndex(tab => | ||||
|                     tab.domainObject.identifier.namespace === identifier.namespace && tab.domainObject.identifier.key === identifier.key | ||||
| @@ -210,10 +144,6 @@ export default { | ||||
|             if (this.isCurrent(tabToBeRemoved)) { | ||||
|                 this.showTab(this.tabsList[this.tabsList.length - 1], this.tabsList.length - 1); | ||||
|             } | ||||
|  | ||||
|             if (!this.tabsList.length) { | ||||
|                 this.reset(); | ||||
|             } | ||||
|         }, | ||||
|         onReorder(reorderPlan) { | ||||
|             let oldTabs = this.tabsList.slice(); | ||||
| @@ -224,7 +154,7 @@ export default { | ||||
|         }, | ||||
|         onDrop(e) { | ||||
|             this.setCurrentTab = true; | ||||
|             this.storeCurrentTabIndexInURL(this.tabsList.length); | ||||
|             this.storeCurrentTabIndex(this.tabsList.length); | ||||
|         }, | ||||
|         dragstart(e) { | ||||
|             if (e.dataTransfer.types.includes('openmct/domain-object-path')) { | ||||
| @@ -247,19 +177,8 @@ export default { | ||||
|         updateInternalDomainObject(domainObject) { | ||||
|             this.internalDomainObject = domainObject; | ||||
|         }, | ||||
|         persistCurrentTabIndex(index) { | ||||
|         storeCurrentTabIndex(index) { | ||||
|             this.openmct.objects.mutate(this.internalDomainObject, 'currentTabIndex', index); | ||||
|         }, | ||||
|         storeCurrentTabIndexInURL(index) { | ||||
|             let currentTabIndexInURL = getSearchParam(this.searchTabKey); | ||||
|  | ||||
|             if (index !== currentTabIndexInURL) { | ||||
|                 setSearchParam(this.searchTabKey, index); | ||||
|                 this.currentTabIndex = index; | ||||
|             } | ||||
|         }, | ||||
|         clearCurrentTabIndexFromURL() { | ||||
|             deleteSearchParam(this.searchTabKey); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -42,28 +42,20 @@ define([ | ||||
|                 let component; | ||||
|  | ||||
|                 return { | ||||
|                     show: function (element, editMode) { | ||||
|                     show: function (element) { | ||||
|                         component =  new Vue({ | ||||
|                             el: element, | ||||
|                             components: { | ||||
|                                 TabsComponent: TabsComponent.default | ||||
|                             }, | ||||
|                             data() { | ||||
|                                 return { | ||||
|                                     isEditing: editMode | ||||
|                                 }; | ||||
|                             }, | ||||
|                             provide: { | ||||
|                                 openmct, | ||||
|                                 domainObject, | ||||
|                                 composition: openmct.composition.get(domainObject) | ||||
|                             }, | ||||
|                             template: '<tabs-component :isEditing="isEditing"></tabs-component>' | ||||
|                             template: '<tabs-component></tabs-component>' | ||||
|                         }); | ||||
|                     }, | ||||
|                     onEditModeChange(editMode) { | ||||
|                         component.isEditing = editMode; | ||||
|                     }, | ||||
|                     destroy: function (element) { | ||||
|                         component.$destroy(); | ||||
|                         component = undefined; | ||||
|   | ||||
| @@ -54,16 +54,6 @@ | ||||
|                 width: 100%; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         &__filter { | ||||
|             .c-table__search { | ||||
|                 padding-top: 0; | ||||
|                 padding-bottom: 0; | ||||
|             } | ||||
|             .is-in-small-container & { | ||||
|                 display: none; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     &__headers__label { | ||||
| @@ -96,10 +86,6 @@ | ||||
|         height: 0; // Fixes Chrome 73 overflow bug | ||||
|         overflow-x: auto; | ||||
|         overflow-y: scroll; | ||||
|  | ||||
|         .is-editing & { | ||||
|             pointer-events: none; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /******************************* TABLES */ | ||||
| @@ -152,7 +138,7 @@ | ||||
|     } | ||||
| } | ||||
|  | ||||
| /******************************* SPECIFIC CASE WRAPPERS */ | ||||
| /******************************* EDITING */ | ||||
| .is-editing { | ||||
|     .c-telemetry-table__headers__labels { | ||||
|         th[draggable], | ||||
| @@ -172,10 +158,8 @@ | ||||
|     } | ||||
| } | ||||
|  | ||||
| .is-paused { | ||||
|     .c-table__body-w { | ||||
|         border: 1px solid rgba($colorPausedBg, 0.8); | ||||
|     } | ||||
| .paused { | ||||
|     border: 1px solid #ff9900; | ||||
| } | ||||
|  | ||||
| /******************************* LEGACY */ | ||||
|   | ||||
| @@ -20,16 +20,13 @@ | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
| <template> | ||||
| <div class="c-table-wrapper" | ||||
|      :class="{ 'is-paused': paused }" | ||||
| > | ||||
| <div class="c-table-wrapper"> | ||||
|     <!-- main contolbar  start--> | ||||
|     <div v-if="!marking.useAlternateControlBar" | ||||
|          class="c-table-control-bar c-control-bar" | ||||
|     > | ||||
|         <button | ||||
|             v-if="allowExport" | ||||
|             v-show="!markedRows.length" | ||||
|             class="c-button icon-download labeled" | ||||
|             title="Export this view's data" | ||||
|             @click="exportAllDataAsCSV()" | ||||
| @@ -128,7 +125,7 @@ | ||||
|         class="c-table c-telemetry-table c-table--filterable c-table--sortable has-control-bar" | ||||
|         :class="{ | ||||
|             'loading': loading, | ||||
|             'is-paused' : paused | ||||
|             'paused' : paused | ||||
|         }" | ||||
|     > | ||||
|         <div :style="{ 'max-width': widthWithScroll, 'min-width': '150px'}"> | ||||
|   | ||||
| @@ -22,12 +22,7 @@ | ||||
| <template> | ||||
| <div | ||||
|     class="c-conductor" | ||||
|     :class="[ | ||||
|         { 'is-zooming': isZooming }, | ||||
|         { 'is-panning': isPanning }, | ||||
|         { 'alt-pressed': altPressed }, | ||||
|         isFixed ? 'is-fixed-mode' : 'is-realtime-mode' | ||||
|     ]" | ||||
|     :class="[isFixed ? 'is-fixed-mode' : 'is-realtime-mode']" | ||||
| > | ||||
|     <form | ||||
|         ref="conductorForm" | ||||
| @@ -57,7 +52,7 @@ | ||||
|                     type="text" | ||||
|                     autocorrect="off" | ||||
|                     spellcheck="false" | ||||
|                     @change="validateAllBounds('startDate'); submitForm()" | ||||
|                     @change="validateAllBounds(); submitForm()" | ||||
|                 > | ||||
|                 <date-picker | ||||
|                     v-if="isFixed && isUTCBased" | ||||
| @@ -97,7 +92,7 @@ | ||||
|                     autocorrect="off" | ||||
|                     spellcheck="false" | ||||
|                     :disabled="!isFixed" | ||||
|                     @change="validateAllBounds('endDate'); submitForm()" | ||||
|                     @change="validateAllBounds(); submitForm()" | ||||
|                 > | ||||
|                 <date-picker | ||||
|                     v-if="isFixed && isUTCBased" | ||||
| @@ -127,25 +122,14 @@ | ||||
|  | ||||
|             <conductor-axis | ||||
|                 class="c-conductor__ticks" | ||||
|                 :view-bounds="viewBounds" | ||||
|                 :is-fixed="isFixed" | ||||
|                 :alt-pressed="altPressed" | ||||
|                 @endPan="endPan" | ||||
|                 @endZoom="endZoom" | ||||
|                 @panAxis="pan" | ||||
|                 @zoomAxis="zoom" | ||||
|                 :bounds="rawBounds" | ||||
|                 @panAxis="setViewFromBounds" | ||||
|             /> | ||||
|  | ||||
|         </div> | ||||
|         <div class="c-conductor__controls"> | ||||
|             <!-- Mode, time system menu buttons and duration slider --> | ||||
|             <ConductorMode class="c-conductor__mode-select" /> | ||||
|             <ConductorTimeSystem class="c-conductor__time-system-select" /> | ||||
|             <ConductorHistory | ||||
|                 v-if="isFixed" | ||||
|                 class="c-conductor__history-select" | ||||
|                 :bounds="openmct.time.bounds()" | ||||
|                 :time-system="timeSystem" | ||||
|             /> | ||||
|         </div> | ||||
|         <input | ||||
|             type="submit" | ||||
| @@ -161,7 +145,6 @@ import ConductorTimeSystem from './ConductorTimeSystem.vue'; | ||||
| import DatePicker from './DatePicker.vue'; | ||||
| import ConductorAxis from './ConductorAxis.vue'; | ||||
| import ConductorModeIcon from './ConductorModeIcon.vue'; | ||||
| import ConductorHistory from './ConductorHistory.vue' | ||||
|  | ||||
| const DEFAULT_DURATION_FORMATTER = 'duration'; | ||||
|  | ||||
| @@ -172,8 +155,7 @@ export default { | ||||
|         ConductorTimeSystem, | ||||
|         DatePicker, | ||||
|         ConductorAxis, | ||||
|         ConductorModeIcon, | ||||
|         ConductorHistory | ||||
|         ConductorModeIcon | ||||
|     }, | ||||
|     data() { | ||||
|         let bounds = this.openmct.time.bounds(); | ||||
| @@ -183,7 +165,6 @@ export default { | ||||
|         let durationFormatter = this.getFormatter(timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER); | ||||
|  | ||||
|         return { | ||||
|             timeSystem: timeSystem, | ||||
|             timeFormatter: timeFormatter, | ||||
|             durationFormatter: durationFormatter, | ||||
|             offsets: { | ||||
| @@ -194,68 +175,29 @@ export default { | ||||
|                 start: timeFormatter.format(bounds.start), | ||||
|                 end: timeFormatter.format(bounds.end) | ||||
|             }, | ||||
|             viewBounds: { | ||||
|             rawBounds: { | ||||
|                 start: bounds.start, | ||||
|                 end: bounds.end | ||||
|             }, | ||||
|             isFixed: this.openmct.time.clock() === undefined, | ||||
|             isUTCBased: timeSystem.isUTCBased, | ||||
|             showDatePicker: false, | ||||
|             altPressed: false, | ||||
|             isPanning: false, | ||||
|             isZooming: false | ||||
|             showDatePicker: false | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         document.addEventListener('keydown', this.handleKeyDown); | ||||
|         document.addEventListener('keyup', this.handleKeyUp); | ||||
|         this.setTimeSystem(JSON.parse(JSON.stringify(this.openmct.time.timeSystem()))); | ||||
|  | ||||
|         this.openmct.time.on('bounds', this.setViewFromBounds); | ||||
|         this.openmct.time.on('timeSystem', this.setTimeSystem); | ||||
|         this.openmct.time.on('clock', this.setViewFromClock); | ||||
|         this.openmct.time.on('clockOffsets', this.setViewFromOffsets) | ||||
|     }, | ||||
|     beforeDestroy() { | ||||
|         document.removeEventListener('keydown', this.handleKeyDown); | ||||
|         document.removeEventListener('keyup', this.handleKeyUp); | ||||
|     }, | ||||
|     methods: { | ||||
|         handleKeyDown(event) { | ||||
|             if (event.key === 'Alt') { | ||||
|                 this.altPressed = true; | ||||
|             } | ||||
|         }, | ||||
|         handleKeyUp(event) { | ||||
|             if (event.key === 'Alt') { | ||||
|                 this.altPressed = false; | ||||
|             } | ||||
|         }, | ||||
|         pan(bounds) { | ||||
|             this.isPanning = true; | ||||
|             this.setViewFromBounds(bounds); | ||||
|         }, | ||||
|         endPan(bounds) { | ||||
|             this.isPanning = false; | ||||
|             if (bounds) { | ||||
|                 this.openmct.time.bounds(bounds); | ||||
|             } | ||||
|         }, | ||||
|         zoom(bounds) { | ||||
|             this.isZooming = true; | ||||
|             this.formattedBounds.start = this.timeFormatter.format(bounds.start); | ||||
|             this.formattedBounds.end = this.timeFormatter.format(bounds.end); | ||||
|         }, | ||||
|         endZoom(bounds) { | ||||
|             const _bounds = bounds ? bounds : this.openmct.time.bounds(); | ||||
|             this.isZooming = false; | ||||
|  | ||||
|             this.openmct.time.bounds(_bounds); | ||||
|         }, | ||||
|         setTimeSystem(timeSystem) { | ||||
|             this.timeSystem = timeSystem | ||||
|             this.timeFormatter = this.getFormatter(timeSystem.timeFormat); | ||||
|             this.durationFormatter = this.getFormatter( | ||||
|                 timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER); | ||||
|  | ||||
|             this.isUTCBased = timeSystem.isUTCBased; | ||||
|         }, | ||||
|         setOffsetsFromView($event) { | ||||
| @@ -295,8 +237,8 @@ export default { | ||||
|         setViewFromBounds(bounds) { | ||||
|             this.formattedBounds.start = this.timeFormatter.format(bounds.start); | ||||
|             this.formattedBounds.end = this.timeFormatter.format(bounds.end); | ||||
|             this.viewBounds.start = bounds.start; | ||||
|             this.viewBounds.end = bounds.end; | ||||
|             this.rawBounds.start = bounds.start; | ||||
|             this.rawBounds.end = bounds.end; | ||||
|         }, | ||||
|         setViewFromOffsets(offsets) { | ||||
|             this.offsets.start = this.durationFormatter.format(Math.abs(offsets.start)); | ||||
| @@ -309,15 +251,6 @@ export default { | ||||
|                 this.setOffsetsFromView(); | ||||
|             } | ||||
|         }, | ||||
|         getBoundsLimit() { | ||||
|             const configuration = this.configuration.menuOptions | ||||
|                 .filter(option => option.timeSystem ===  this.timeSystem.key) | ||||
|                 .find(option => option.limit); | ||||
|  | ||||
|             const limit = configuration ? configuration.limit : undefined; | ||||
|  | ||||
|             return limit; | ||||
|         }, | ||||
|         clearAllValidation() { | ||||
|             if (this.isFixed) { | ||||
|                 [this.$refs.startDate, this.$refs.endDate].forEach(this.clearValidationForInput); | ||||
| @@ -329,52 +262,36 @@ export default { | ||||
|             input.setCustomValidity(''); | ||||
|             input.title = ''; | ||||
|         }, | ||||
|         validateAllBounds(ref) { | ||||
|             if (!this.areBoundsFormatsValid()) { | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             let validationResult = true; | ||||
|             const currentInput = this.$refs[ref]; | ||||
|  | ||||
|         validateAllBounds() { | ||||
|             return [this.$refs.startDate, this.$refs.endDate].every((input) => { | ||||
|                 let boundsValues = { | ||||
|                     start: this.timeFormatter.parse(this.formattedBounds.start), | ||||
|                     end: this.timeFormatter.parse(this.formattedBounds.end) | ||||
|                 }; | ||||
|                 const limit = this.getBoundsLimit(); | ||||
|                 let validationResult = true; | ||||
|                 let formattedDate; | ||||
|  | ||||
|                 if ( | ||||
|                     this.timeSystem.isUTCBased | ||||
|                     && limit | ||||
|                     && boundsValues.end - boundsValues.start > limit | ||||
|                 ) { | ||||
|                     if (input === currentInput) { | ||||
|                         validationResult = "Start and end difference exceeds allowable limit"; | ||||
|                     } | ||||
|                 if (input === this.$refs.startDate) { | ||||
|                     formattedDate = this.formattedBounds.start; | ||||
|                 } else { | ||||
|                     if (input === currentInput) { | ||||
|                         validationResult = this.openmct.time.validateBounds(boundsValues); | ||||
|                     } | ||||
|                     formattedDate = this.formattedBounds.end; | ||||
|                 } | ||||
|  | ||||
|                 return this.handleValidationResults(input, validationResult); | ||||
|             }); | ||||
|         }, | ||||
|         areBoundsFormatsValid() { | ||||
|             let validationResult = true; | ||||
|  | ||||
|             return [this.$refs.startDate, this.$refs.endDate].every((input) => { | ||||
|                 const formattedDate = input === this.$refs.startDate | ||||
|                     ? this.formattedBounds.start | ||||
|                     : this.formattedBounds.end | ||||
|                 ; | ||||
|  | ||||
|                 if (!this.timeFormatter.validate(formattedDate)) { | ||||
|                     validationResult = 'Invalid date'; | ||||
|                 } else { | ||||
|                     let boundsValues = { | ||||
|                         start: this.timeFormatter.parse(this.formattedBounds.start), | ||||
|                         end: this.timeFormatter.parse(this.formattedBounds.end) | ||||
|                     }; | ||||
|                     validationResult = this.openmct.time.validateBounds(boundsValues); | ||||
|                 } | ||||
|  | ||||
|                 return this.handleValidationResults(input, validationResult); | ||||
|                 if (validationResult !== true) { | ||||
|                     input.setCustomValidity(validationResult); | ||||
|                     input.title = validationResult; | ||||
|                     return false; | ||||
|                 } else { | ||||
|                     input.setCustomValidity(''); | ||||
|                     input.title = ''; | ||||
|                     return true; | ||||
|                 } | ||||
|             }); | ||||
|         }, | ||||
|         validateAllOffsets(event) { | ||||
| @@ -398,20 +315,17 @@ export default { | ||||
|                     validationResult = this.openmct.time.validateOffsets(offsetValues); | ||||
|                 } | ||||
|  | ||||
|                 return this.handleValidationResults(input, validationResult); | ||||
|                 if (validationResult !== true) { | ||||
|                     input.setCustomValidity(validationResult); | ||||
|                     input.title = validationResult; | ||||
|                     return false; | ||||
|                 } else { | ||||
|                     input.setCustomValidity(''); | ||||
|                     input.title = ''; | ||||
|                     return true; | ||||
|                 } | ||||
|             }); | ||||
|         }, | ||||
|         handleValidationResults(input, validationResult) { | ||||
|             if (validationResult !== true) { | ||||
|                 input.setCustomValidity(validationResult); | ||||
|                 input.title = validationResult; | ||||
|                 return false; | ||||
|             } else { | ||||
|                 input.setCustomValidity(''); | ||||
|                 input.title = ''; | ||||
|                 return true; | ||||
|             } | ||||
|         }, | ||||
|         submitForm() { | ||||
|             // Allow Vue model to catch up to user input. | ||||
|             // Submitting form will cause validation messages to display (but only if triggered by button click) | ||||
| @@ -424,12 +338,12 @@ export default { | ||||
|         }, | ||||
|         startDateSelected(date) { | ||||
|             this.formattedBounds.start = this.timeFormatter.format(date); | ||||
|             this.validateAllBounds('startDate'); | ||||
|             this.validateAllBounds(); | ||||
|             this.submitForm(); | ||||
|         }, | ||||
|         endDateSelected(date) { | ||||
|             this.formattedBounds.end = this.timeFormatter.format(date); | ||||
|             this.validateAllBounds('endDate'); | ||||
|             this.validateAllBounds(); | ||||
|             this.submitForm(); | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -24,12 +24,7 @@ | ||||
|     ref="axisHolder" | ||||
|     class="c-conductor-axis" | ||||
|     @mousedown="dragStart($event)" | ||||
| > | ||||
|     <div | ||||
|         class="c-conductor-axis__zoom-indicator" | ||||
|         :style="zoomStyle" | ||||
|     ></div> | ||||
| </div> | ||||
| ></div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| @@ -48,81 +43,52 @@ const PIXELS_PER_TICK_WIDE = 200; | ||||
| export default { | ||||
|     inject: ['openmct'], | ||||
|     props: { | ||||
|         viewBounds: { | ||||
|         bounds: { | ||||
|             type: Object, | ||||
|             required: true | ||||
|         }, | ||||
|         isFixed: { | ||||
|             type: Boolean, | ||||
|             required: true | ||||
|         }, | ||||
|         altPressed: { | ||||
|             type: Boolean, | ||||
|             required: true | ||||
|         } | ||||
|     }, | ||||
|     data() { | ||||
|         return { | ||||
|             inPanMode: false, | ||||
|             dragStartX: undefined, | ||||
|             dragX: undefined, | ||||
|             zoomStyle: {} | ||||
|         } | ||||
|     }, | ||||
|     computed: { | ||||
|         inZoomMode() { | ||||
|             return !this.inPanMode; | ||||
|         } | ||||
|     }, | ||||
|     watch: { | ||||
|         viewBounds: { | ||||
|             handler() { | ||||
|         bounds: { | ||||
|             handler(bounds) { | ||||
|                 this.setScale(); | ||||
|             }, | ||||
|             deep: true | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         let vis = d3Selection.select(this.$refs.axisHolder).append("svg:svg"); | ||||
|         let axisHolder = this.$refs.axisHolder; | ||||
|         let height = axisHolder.offsetHeight; | ||||
|         let vis = d3Selection.select(axisHolder) | ||||
|             .append("svg:svg") | ||||
|             .attr("width", "100%") | ||||
|             .attr("height", height); | ||||
|  | ||||
|         this.width = this.$refs.axisHolder.clientWidth; | ||||
|         this.xAxis = d3Axis.axisTop(); | ||||
|         this.dragging = false; | ||||
|  | ||||
|         // draw x axis with labels. CSS is used to position them. | ||||
|         this.axisElement = vis.append("g") | ||||
|             .attr("class", "axis"); | ||||
|         this.axisElement = vis.append("g"); | ||||
|  | ||||
|         this.setViewFromTimeSystem(this.openmct.time.timeSystem()); | ||||
|         this.setAxisDimensions(); | ||||
|         this.setScale(); | ||||
|  | ||||
|         //Respond to changes in conductor | ||||
|         this.openmct.time.on("timeSystem", this.setViewFromTimeSystem); | ||||
|         setInterval(this.resize, RESIZE_POLL_INTERVAL); | ||||
|     }, | ||||
|     destroyed() { | ||||
|     }, | ||||
|     methods: { | ||||
|         setAxisDimensions() { | ||||
|             const axisHolder = this.$refs.axisHolder; | ||||
|             const rect = axisHolder.getBoundingClientRect(); | ||||
|  | ||||
|             this.left = Math.round(rect.left); | ||||
|             this.width = axisHolder.clientWidth; | ||||
|         }, | ||||
|         setScale() { | ||||
|             if (!this.width) { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             let timeSystem = this.openmct.time.timeSystem(); | ||||
|             let bounds = this.bounds; | ||||
|  | ||||
|             if (timeSystem.isUTCBased) { | ||||
|                 this.xScale.domain( | ||||
|                     [new Date(this.viewBounds.start), new Date(this.viewBounds.end)] | ||||
|                 ); | ||||
|                 this.xScale.domain([new Date(bounds.start), new Date(bounds.end)]); | ||||
|             } else { | ||||
|                 this.xScale.domain( | ||||
|                     [this.viewBounds.start, this.viewBounds.end] | ||||
|                 ); | ||||
|                 this.xScale.domain([bounds.start, bounds.end]); | ||||
|             } | ||||
|  | ||||
|             this.xAxis.scale(this.xScale); | ||||
| @@ -136,7 +102,7 @@ export default { | ||||
|                 this.xAxis.ticks(this.width / PIXELS_PER_TICK); | ||||
|             } | ||||
|  | ||||
|             this.msPerPixel = (this.viewBounds.end - this.viewBounds.start) / this.width; | ||||
|             this.msPerPixel = (bounds.end - bounds.start) / this.width; | ||||
|         }, | ||||
|         setViewFromTimeSystem(timeSystem) { | ||||
|             //The D3 scale used depends on the type of time system as d3 | ||||
| @@ -154,8 +120,9 @@ export default { | ||||
|         }, | ||||
|         getActiveFormatter() { | ||||
|             let timeSystem = this.openmct.time.timeSystem(); | ||||
|             let isFixed = this.openmct.time.clock() === undefined; | ||||
|  | ||||
|             if (this.isFixed) { | ||||
|             if (isFixed) { | ||||
|                 return this.getFormatter(timeSystem.timeFormat); | ||||
|             } else { | ||||
|                 return this.getFormatter(timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER); | ||||
| @@ -167,131 +134,45 @@ export default { | ||||
|             }).formatter; | ||||
|         }, | ||||
|         dragStart($event) { | ||||
|             if (this.isFixed) { | ||||
|             let isFixed = this.openmct.time.clock() === undefined; | ||||
|             if (isFixed) { | ||||
|                 this.dragStartX = $event.clientX; | ||||
|  | ||||
|                 if (this.altPressed) { | ||||
|                     this.inPanMode = true; | ||||
|                 } | ||||
|  | ||||
|                 document.addEventListener('mousemove', this.drag); | ||||
|                 document.addEventListener('mouseup', this.dragEnd, { | ||||
|                     once: true | ||||
|                 }); | ||||
|  | ||||
|                 if (this.inZoomMode) { | ||||
|                     this.startZoom(); | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         drag($event) { | ||||
|             if (!this.dragging) { | ||||
|                 this.dragging = true; | ||||
|  | ||||
|                 requestAnimationFrame(() => { | ||||
|                     this.dragX = $event.clientX; | ||||
|                     this.inPanMode ? this.pan() : this.zoom(); | ||||
|                 requestAnimationFrame(()=>{ | ||||
|                     let deltaX = $event.clientX - this.dragStartX; | ||||
|                     let percX = deltaX / this.width; | ||||
|                     let bounds = this.openmct.time.bounds(); | ||||
|                     let deltaTime = bounds.end - bounds.start; | ||||
|                     let newStart = bounds.start - percX * deltaTime; | ||||
|                     this.$emit('panAxis',{ | ||||
|                         start: newStart, | ||||
|                         end: newStart + deltaTime | ||||
|                     }); | ||||
|                     this.dragging = false; | ||||
|                 }); | ||||
|                 }) | ||||
|             } else { | ||||
|                 console.log('Rejected drag due to RAF cap'); | ||||
|             } | ||||
|         }, | ||||
|         dragEnd() { | ||||
|             this.inPanMode ? this.endPan() : this.endZoom(); | ||||
|  | ||||
|             document.removeEventListener('mousemove', this.drag); | ||||
|             this.dragStartX = undefined; | ||||
|             this.dragX = undefined; | ||||
|         }, | ||||
|         pan() { | ||||
|             const panBounds = this.getPanBounds(); | ||||
|             this.$emit('panAxis', panBounds); | ||||
|         }, | ||||
|         endPan() { | ||||
|             const panBounds = this.dragStartX && this.dragX && this.dragStartX !== this.dragX | ||||
|                 ? this.getPanBounds() | ||||
|                 : undefined; | ||||
|             this.$emit('endPan', panBounds); | ||||
|             this.inPanMode = false; | ||||
|         }, | ||||
|         getPanBounds() { | ||||
|             const bounds = this.openmct.time.bounds(); | ||||
|             const deltaTime = bounds.end - bounds.start; | ||||
|             const deltaX = this.dragX - this.dragStartX; | ||||
|             const percX = deltaX / this.width; | ||||
|             const panStart = bounds.start - percX * deltaTime; | ||||
|  | ||||
|             return { | ||||
|                 start: panStart, | ||||
|                 end: panStart + deltaTime | ||||
|             }; | ||||
|         }, | ||||
|         startZoom() { | ||||
|             const x = this.scaleToBounds(this.dragStartX); | ||||
|  | ||||
|             this.zoomStyle = { | ||||
|                 left: `${this.dragStartX - this.left}px` | ||||
|             }; | ||||
|  | ||||
|             this.$emit('zoomAxis', { | ||||
|                 start: x, | ||||
|                 end: x | ||||
|             this.openmct.time.bounds({ | ||||
|                 start: this.bounds.start, | ||||
|                 end: this.bounds.end | ||||
|             }); | ||||
|         }, | ||||
|         zoom() { | ||||
|             const zoomRange = this.getZoomRange(); | ||||
|  | ||||
|             this.zoomStyle = { | ||||
|                 left: `${zoomRange.start - this.left}px`, | ||||
|                 width: `${zoomRange.end - zoomRange.start}px` | ||||
|             }; | ||||
|  | ||||
|             this.$emit('zoomAxis', { | ||||
|                 start: this.scaleToBounds(zoomRange.start), | ||||
|                 end: this.scaleToBounds(zoomRange.end) | ||||
|             }); | ||||
|         }, | ||||
|         endZoom() { | ||||
|             const zoomRange = this.dragStartX && this.dragX && this.dragStartX !== this.dragX | ||||
|                 ? this.getZoomRange() | ||||
|                 : undefined; | ||||
|  | ||||
|             const zoomBounds = zoomRange | ||||
|                 ? { | ||||
|                     start: this.scaleToBounds(zoomRange.start), | ||||
|                     end: this.scaleToBounds(zoomRange.end) | ||||
|                 } | ||||
|                 : this.openmct.time.bounds(); | ||||
|  | ||||
|             this.zoomStyle = {}; | ||||
|             this.$emit('endZoom', zoomBounds); | ||||
|         }, | ||||
|         getZoomRange() { | ||||
|             const leftBound = this.left; | ||||
|             const rightBound = this.left + this.width; | ||||
|  | ||||
|             const zoomStart = this.dragX < leftBound | ||||
|                 ? leftBound | ||||
|                 : Math.min(this.dragX, this.dragStartX); | ||||
|  | ||||
|             const zoomEnd = this.dragX > rightBound | ||||
|                 ? rightBound | ||||
|                 : Math.max(this.dragX, this.dragStartX); | ||||
|  | ||||
|             return { | ||||
|                 start: zoomStart, | ||||
|                 end: zoomEnd | ||||
|             }; | ||||
|         }, | ||||
|         scaleToBounds(value) { | ||||
|             const bounds = this.openmct.time.bounds(); | ||||
|             const timeDelta = bounds.end - bounds.start; | ||||
|             const valueDelta = value - this.left; | ||||
|             const offset = valueDelta / this.width * timeDelta; | ||||
|             return bounds.start + offset; | ||||
|         }, | ||||
|         resize() { | ||||
|             if (this.$refs.axisHolder.clientWidth !== this.width) { | ||||
|                 this.setAxisDimensions(); | ||||
|                 this.width = this.$refs.axisHolder.clientWidth; | ||||
|                 this.setScale(); | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -1,200 +0,0 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT Web, Copyright (c) 2014-2018, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
|  * Open MCT Web is licensed under the Apache License, Version 2.0 (the | ||||
|  * "License"); you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * http://www.apache.org/licenses/LICENSE-2.0. | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
|  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
|  * License for the specific language governing permissions and limitations | ||||
|  * under the License. | ||||
|  * | ||||
|  * Open MCT Web includes source code licensed under additional open source | ||||
|  * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
|  * this source code distribution or the Licensing information page available | ||||
|  * at runtime from the About dialog for additional information. | ||||
|  *****************************************************************************/ | ||||
| <template> | ||||
| <div class="c-ctrl-wrapper c-ctrl-wrapper--menus-up"> | ||||
|     <button class="c-button--menu c-history-button icon-history" | ||||
|             @click.prevent="toggle" | ||||
|     > | ||||
|         <span class="c-button__label">History</span> | ||||
|     </button> | ||||
|     <div v-if="open" | ||||
|          class="c-menu c-conductor__history-menu" | ||||
|     > | ||||
|         <ul v-if="hasHistoryPresets"> | ||||
|             <li | ||||
|                 v-for="preset in presets" | ||||
|                 :key="preset.label" | ||||
|                 class="icon-clock" | ||||
|                 @click="selectPresetBounds(preset.bounds)" | ||||
|             > | ||||
|                 {{ preset.label }} | ||||
|             </li> | ||||
|         </ul> | ||||
|  | ||||
|         <div | ||||
|             v-if="hasHistoryPresets" | ||||
|             class="c-menu__section-separator" | ||||
|         ></div> | ||||
|  | ||||
|         <div class="c-menu__section-hint"> | ||||
|             Past timeframes, ordered by latest first | ||||
|         </div> | ||||
|  | ||||
|         <ul> | ||||
|             <li | ||||
|                 v-for="(timespan, index) in historyForCurrentTimeSystem" | ||||
|                 :key="index" | ||||
|                 class="icon-history" | ||||
|                 @click="selectTimespan(timespan)" | ||||
|             > | ||||
|                 {{ formatTime(timespan.start) }} - {{ formatTime(timespan.end) }} | ||||
|             </li> | ||||
|         </ul> | ||||
|     </div> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import toggleMixin from '../../ui/mixins/toggle-mixin'; | ||||
|  | ||||
| const LOCAL_STORAGE_HISTORY_KEY = 'tcHistory'; | ||||
| const DEFAULT_RECORDS = 10; | ||||
|  | ||||
| export default { | ||||
|     inject: ['openmct', 'configuration'], | ||||
|     mixins: [toggleMixin], | ||||
|     props: { | ||||
|         bounds: { | ||||
|             type: Object, | ||||
|             required: true | ||||
|         }, | ||||
|         timeSystem: { | ||||
|             type: Object, | ||||
|             required: true | ||||
|         } | ||||
|     }, | ||||
|     data() { | ||||
|         return { | ||||
|             history: {}, // contains arrays of timespans {start, end}, array key is time system key | ||||
|             presets: [] | ||||
|         } | ||||
|     }, | ||||
|     computed: { | ||||
|         hasHistoryPresets() { | ||||
|             return this.timeSystem.isUTCBased && this.presets.length; | ||||
|         }, | ||||
|         historyForCurrentTimeSystem() { | ||||
|             const history = this.history[this.timeSystem.key]; | ||||
|  | ||||
|             return history; | ||||
|         } | ||||
|     }, | ||||
|     watch: { | ||||
|         bounds: { | ||||
|             handler() { | ||||
|                 this.addTimespan(); | ||||
|             }, | ||||
|             deep: true | ||||
|         }, | ||||
|         timeSystem: { | ||||
|             handler() { | ||||
|                 this.loadConfiguration(); | ||||
|                 this.addTimespan(); | ||||
|             }, | ||||
|             deep: true | ||||
|         }, | ||||
|         history: { | ||||
|             handler() { | ||||
|                 this.persistHistoryToLocalStorage(); | ||||
|             }, | ||||
|             deep: true | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.getHistoryFromLocalStorage(); | ||||
|     }, | ||||
|     methods: { | ||||
|         getHistoryFromLocalStorage() { | ||||
|             if (localStorage.getItem(LOCAL_STORAGE_HISTORY_KEY)) { | ||||
|                 this.history = JSON.parse(localStorage.getItem(LOCAL_STORAGE_HISTORY_KEY)) | ||||
|             } else { | ||||
|                 this.history = {}; | ||||
|                 this.persistHistoryToLocalStorage(); | ||||
|             } | ||||
|         }, | ||||
|         persistHistoryToLocalStorage() { | ||||
|             localStorage.setItem(LOCAL_STORAGE_HISTORY_KEY, JSON.stringify(this.history)); | ||||
|         }, | ||||
|         addTimespan() { | ||||
|             const key = this.timeSystem.key; | ||||
|             let [...currentHistory] = this.history[key] || []; | ||||
|             const timespan = { | ||||
|                 start: this.bounds.start, | ||||
|                 end: this.bounds.end | ||||
|             }; | ||||
|  | ||||
|             const isNotEqual = function (entry) { | ||||
|                 const start = entry.start !== this.start; | ||||
|                 const end = entry.end !== this.end; | ||||
|  | ||||
|                 return start || end; | ||||
|             }; | ||||
|             currentHistory = currentHistory.filter(isNotEqual, timespan); | ||||
|  | ||||
|             while (currentHistory.length >= this.records) { | ||||
|                 currentHistory.pop(); | ||||
|             } | ||||
|  | ||||
|             currentHistory.unshift(timespan); | ||||
|             this.history[key] = currentHistory; | ||||
|         }, | ||||
|         selectTimespan(timespan) { | ||||
|             this.openmct.time.bounds(timespan); | ||||
|         }, | ||||
|         selectPresetBounds(bounds) { | ||||
|             const start = typeof bounds.start === 'function' ? bounds.start() : bounds.start; | ||||
|             const end = typeof bounds.end === 'function' ? bounds.end() : bounds.end; | ||||
|  | ||||
|             this.selectTimespan({ | ||||
|                 start: start, | ||||
|                 end: end | ||||
|             }); | ||||
|         }, | ||||
|         loadConfiguration() { | ||||
|             const configurations = this.configuration.menuOptions | ||||
|                 .filter(option => option.timeSystem ===  this.timeSystem.key); | ||||
|  | ||||
|             this.presets = this.loadPresets(configurations); | ||||
|             this.records = this.loadRecords(configurations); | ||||
|         }, | ||||
|         loadPresets(configurations) { | ||||
|             const configuration = configurations.find(option => option.presets); | ||||
|             const presets = configuration ? configuration.presets : []; | ||||
|  | ||||
|             return presets; | ||||
|         }, | ||||
|         loadRecords(configurations) { | ||||
|             const configuration = configurations.find(option => option.records); | ||||
|             const records = configuration ? configuration.records : DEFAULT_RECORDS; | ||||
|  | ||||
|             return records; | ||||
|         }, | ||||
|         formatTime(time) { | ||||
|             const formatter = this.openmct.telemetry.getValueFormatter({ | ||||
|                 format: this.timeSystem.timeFormat | ||||
|             }).formatter; | ||||
|  | ||||
|             return formatter.format(time); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| </script> | ||||
| @@ -110,7 +110,7 @@ export default { | ||||
|             if (clock === undefined) { | ||||
|                 return { | ||||
|                     key: 'fixed', | ||||
|                     name: 'Fixed Timespan', | ||||
|                     name: 'Fixed Timespan Mode', | ||||
|                     description: 'Query and explore data that falls between two fixed datetimes.', | ||||
|                     cssClass: 'icon-tabular' | ||||
|                 } | ||||
|   | ||||
| @@ -13,7 +13,7 @@ | ||||
|         text-rendering: geometricPrecision; | ||||
|         width: 100%; | ||||
|         height: 100%; | ||||
|         > g.axis { | ||||
|         > g { | ||||
|             // Overall Tick holder | ||||
|             transform: translateY($tickYPos); | ||||
|             path { | ||||
| @@ -44,6 +44,7 @@ | ||||
|     } | ||||
|  | ||||
|     body.desktop .is-fixed-mode & { | ||||
|         @include cursorGrab(); | ||||
|         background-size: 3px 30%; | ||||
|         background-color: $colorBodyBgSubtle; | ||||
|         box-shadow: inset rgba(black, 0.4) 0 1px 1px; | ||||
| @@ -54,6 +55,17 @@ | ||||
|             stroke: $colorBodyBgSubtle; | ||||
|             transition: $transOut; | ||||
|         } | ||||
|  | ||||
|         &:hover, | ||||
|         &:active { | ||||
|             $c: $colorKeySubtle; | ||||
|             background-color: $c; | ||||
|             transition: $transIn; | ||||
|             svg text { | ||||
|                 stroke: $c; | ||||
|                 transition: $transIn; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     .is-realtime-mode & { | ||||
|   | ||||
| @@ -57,65 +57,6 @@ | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     &.is-fixed-mode { | ||||
|         .c-conductor-axis { | ||||
|             &__zoom-indicator { | ||||
|                 border: 1px solid transparent; | ||||
|                 display: none; // Hidden by default | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         &:not(.is-panning), | ||||
|         &:not(.is-zooming) { | ||||
|             .c-conductor-axis { | ||||
|                 &:hover, | ||||
|                 &:active { | ||||
|                     cursor: col-resize; | ||||
|                     filter: $timeConductorAxisHoverFilter; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         &.is-panning, | ||||
|         &.is-zooming { | ||||
|             .c-conductor-input input { | ||||
|                 // Styles for inputs while zooming or panning | ||||
|                 background: rgba($timeConductorActiveBg, 0.4); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         &.alt-pressed { | ||||
|             .c-conductor-axis:hover { | ||||
|                 // When alt is being pressed and user is hovering over the axis, set the cursor | ||||
|                 @include cursorGrab(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         &.is-panning { | ||||
|             .c-conductor-axis { | ||||
|                 @include cursorGrab(); | ||||
|                 background-color: $timeConductorActivePanBg; | ||||
|                 transition: $transIn; | ||||
|  | ||||
|                 svg text { | ||||
|                     stroke: $timeConductorActivePanBg; | ||||
|                     transition: $transIn; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         &.is-zooming { | ||||
|             .c-conductor-axis__zoom-indicator { | ||||
|                 display: block; | ||||
|                 position: absolute; | ||||
|                 background: rgba($timeConductorActiveBg, 0.4); | ||||
|                 border-left-color: $timeConductorActiveBg; | ||||
|                 border-right-color: $timeConductorActiveBg; | ||||
|                 top: 0; bottom: 0; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     &.is-realtime-mode { | ||||
|         .c-conductor__time-bounds { | ||||
|             grid-template-columns: 20px auto 1fr auto auto; | ||||
|   | ||||
| @@ -84,10 +84,6 @@ $filterHov: brightness(1.3); // Tree, location items | ||||
| $colorSelectedBg: pushBack($colorKey, 10%); | ||||
| $colorSelectedFg: pullForward($colorBodyFg, 20%); | ||||
|  | ||||
| // Object labels | ||||
| $objectLabelTypeIconOpacity: 0.7; | ||||
| $objectLabelNameFilter: brightness(1.3); | ||||
|  | ||||
| // Layout | ||||
| $shellMainPad: 4px 0; | ||||
| $shellPanePad: $interiorMargin, 7px; | ||||
| @@ -98,7 +94,7 @@ $sideBarHeaderBg: rgba($colorBodyFg, 0.2); | ||||
| $sideBarHeaderFg: rgba($colorBodyFg, 0.7); | ||||
|  | ||||
| // Status colors, mainly used for messaging and item ancillary symbols | ||||
| $colorStatusFg: #888; | ||||
| $colorStatusFg: #999; | ||||
| $colorStatusDefault: #ccc; | ||||
| $colorStatusInfo: #60ba7b; | ||||
| $colorStatusInfoFilter: invert(58%) sepia(44%) saturate(405%) hue-rotate(85deg) brightness(102%) contrast(92%); | ||||
| @@ -146,19 +142,12 @@ $colorTimeHov: pullForward($colorTime, 10%); | ||||
| $colorTimeSubtle: pushBack($colorTime, 20%); | ||||
| $colorTOI: $colorBodyFg; // was $timeControllerToiLineColor | ||||
| $colorTOIHov: $colorTime; // was $timeControllerToiLineColorHov | ||||
| $timeConductorAxisHoverFilter: brightness(1.2); | ||||
| $timeConductorActiveBg: $colorKey; | ||||
| $timeConductorActivePanBg: #226074; | ||||
|  | ||||
| /************************************************** BROWSING */ | ||||
| $browseFrameColor: pullForward($colorBodyBg, 10%); | ||||
| $browseFrameBorder: 1px solid $browseFrameColor; // Frames in Disp and Flex Layouts when frame is showing | ||||
| $browseSelectableShdwHov: rgba($colorBodyFg, 0.3) 0 0 3px; | ||||
| $browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.4); | ||||
| $filterItemHoverFg: brightness(1.2) contrast(1.1); | ||||
| $filterItemMissing: brightness(0.6) grayscale(1); | ||||
| $opacityMissing: 0.5; | ||||
| $borderMissing: 1px dashed $colorAlert !important; | ||||
|  | ||||
| /************************************************** EDITING */ | ||||
| $editUIColor: $uiColor; // Base color | ||||
| @@ -209,9 +198,9 @@ $colorBtnMajorBg: $colorKey; | ||||
| $colorBtnMajorBgHov: $colorKeyHov; | ||||
| $colorBtnMajorFg: $colorKeyFg; | ||||
| $colorBtnMajorFgHov: pushBack($colorBtnMajorFg, 10%); | ||||
| $colorBtnCautionBg: $colorStatusAlert; | ||||
| $colorBtnCautionBg: #f16f6f; | ||||
| $colorBtnCautionBgHov: #f1504e; | ||||
| $colorBtnCautionFg: $colorBtnBg; | ||||
| $colorBtnCautionFg: $colorBtnFg; | ||||
| $colorBtnActiveBg: $colorOk; | ||||
| $colorBtnActiveFg: $colorOkFg; | ||||
| $colorBtnSelectedBg: $colorSelectedBg; | ||||
| @@ -339,7 +328,7 @@ $shdwItemText: none; | ||||
| $colorTabBorder: pullForward($colorBodyBg, 10%); | ||||
| $colorTabBodyBg: $colorBodyBg; | ||||
| $colorTabBodyFg: pullForward($colorBodyFg, 20%); | ||||
| $colorTabHeaderBg: rgba($colorBodyFg, 0.15); | ||||
| $colorTabHeaderBg: rgba($colorBodyFg, 0.2); | ||||
| $colorTabHeaderFg: $colorBodyFg; | ||||
| $colorTabHeaderBorder: $colorBodyBg; | ||||
| $colorTabGroupHeaderBg: pullForward($colorBodyBg, 5%); | ||||
| @@ -357,7 +346,7 @@ $stylePlotHash: dashed; | ||||
| $colorPlotAreaBorder: $colorInteriorBorder; | ||||
| $colorPlotLabelFg: pushBack($colorPlotFg, 20%); | ||||
| $legendHoverValueBg: rgba($colorBodyFg, 0.2); | ||||
| $legendTableHeadBg: $colorTabHeaderBg; | ||||
| $legendTableHeadBg: rgba($colorBodyFg, 0.15); | ||||
|  | ||||
| // Tree | ||||
| $colorTreeBg: transparent; | ||||
|   | ||||
| @@ -88,10 +88,6 @@ $filterHov: brightness(1.3); // Tree, location items | ||||
| $colorSelectedBg: pushBack($colorKey, 10%); | ||||
| $colorSelectedFg: pullForward($colorBodyFg, 20%); | ||||
|  | ||||
| // Object labels | ||||
| $objectLabelTypeIconOpacity: 0.7; | ||||
| $objectLabelNameFilter: brightness(1.3); | ||||
|  | ||||
| // Layout | ||||
| $shellMainPad: 4px 0; | ||||
| $shellPanePad: $interiorMargin, 7px; | ||||
| @@ -150,19 +146,12 @@ $colorTimeHov: pullForward($colorTime, 10%); | ||||
| $colorTimeSubtle: pushBack($colorTime, 20%); | ||||
| $colorTOI: $colorBodyFg; // was $timeControllerToiLineColor | ||||
| $colorTOIHov: $colorTime; // was $timeControllerToiLineColorHov | ||||
| $timeConductorAxisHoverFilter: brightness(1.2); | ||||
| $timeConductorActiveBg: $colorKey; | ||||
| $timeConductorActivePanBg: #226074; | ||||
|  | ||||
| /************************************************** BROWSING */ | ||||
| $browseFrameColor: pullForward($colorBodyBg, 10%); | ||||
| $browseFrameBorder: 1px solid $browseFrameColor; // Frames in Disp and Flex Layouts when frame is showing | ||||
| $browseSelectableShdwHov: rgba($colorBodyFg, 0.3) 0 0 3px; | ||||
| $browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.4); | ||||
| $filterItemHoverFg: brightness(1.2) contrast(1.1); | ||||
| $filterItemMissing: contrast(0.2); | ||||
| $opacityMissing: 0.5; | ||||
| $borderMissing: 1px dashed $colorAlert !important; | ||||
|  | ||||
| /************************************************** EDITING */ | ||||
| $editUIColor: $uiColor; // Base color | ||||
| @@ -213,9 +202,9 @@ $colorBtnMajorBg: $colorKey; | ||||
| $colorBtnMajorBgHov: $colorKeyHov; | ||||
| $colorBtnMajorFg: $colorKeyFg; | ||||
| $colorBtnMajorFgHov: pushBack($colorBtnMajorFg, 10%); | ||||
| $colorBtnCautionBg: $colorStatusAlert; | ||||
| $colorBtnCautionBg: #f16f6f; | ||||
| $colorBtnCautionBgHov: #f1504e; | ||||
| $colorBtnCautionFg: $colorBtnBg; | ||||
| $colorBtnCautionFg: $colorBtnFg; | ||||
| $colorBtnActiveBg: $colorOk; | ||||
| $colorBtnActiveFg: $colorOkFg; | ||||
| $colorBtnSelectedBg: $colorSelectedBg; | ||||
| @@ -343,7 +332,7 @@ $shdwItemText: none; | ||||
| $colorTabBorder: pullForward($colorBodyBg, 10%); | ||||
| $colorTabBodyBg: $colorBodyBg; | ||||
| $colorTabBodyFg: pullForward($colorBodyFg, 20%); | ||||
| $colorTabHeaderBg: rgba($colorBodyFg, 0.15); | ||||
| $colorTabHeaderBg: rgba($colorBodyFg, 0.2); | ||||
| $colorTabHeaderFg: $colorBodyFg; | ||||
| $colorTabHeaderBorder: $colorBodyBg; | ||||
| $colorTabGroupHeaderBg: pullForward($colorBodyBg, 5%); | ||||
|   | ||||
| @@ -80,14 +80,10 @@ $uiColor: #289fec; // Resize bars, splitter bars, etc. | ||||
| $colorInteriorBorder: rgba($colorBodyFg, 0.2); | ||||
| $colorA: #999; | ||||
| $colorAHov: $colorKey; | ||||
| $filterHov: brightness(0.8) contrast(2); // Tree, location items | ||||
| $filterHov: brightness(1.3); // Tree, location items | ||||
| $colorSelectedBg: pushBack($colorKey, 40%); | ||||
| $colorSelectedFg: pullForward($colorBodyFg, 10%); | ||||
|  | ||||
| // Object labels | ||||
| $objectLabelTypeIconOpacity: 0.5; | ||||
| $objectLabelNameFilter: brightness(0.5); | ||||
|  | ||||
| // Layout | ||||
| $shellMainPad: 4px 0; | ||||
| $shellPanePad: $interiorMargin, 7px; | ||||
| @@ -136,7 +132,7 @@ $colorPausedFg: #fff; | ||||
| // Base variations | ||||
| $colorBodyBgSubtle: pullForward($colorBodyBg, 5%); | ||||
| $colorBodyBgSubtleHov: pushBack($colorKey, 50%); | ||||
| $colorKeySubtle: pushBack($colorKey, 20%); | ||||
| $colorKeySubtle: pushBack($colorKey, 10%); | ||||
|  | ||||
| // Time Colors | ||||
| $colorTime: #618cff; | ||||
| @@ -146,19 +142,12 @@ $colorTimeHov: pushBack($colorTime, 5%); | ||||
| $colorTimeSubtle: pushBack($colorTime, 20%); | ||||
| $colorTOI: $colorBodyFg; // was $timeControllerToiLineColor | ||||
| $colorTOIHov: $colorTime; // was $timeControllerToiLineColorHov | ||||
| $timeConductorAxisHoverFilter: brightness(0.8); | ||||
| $timeConductorActiveBg: $colorKey; | ||||
| $timeConductorActivePanBg: #A0CDE1; | ||||
|  | ||||
| /************************************************** BROWSING */ | ||||
| $browseFrameColor: pullForward($colorBodyBg, 10%); | ||||
| $browseFrameBorder: 1px solid $browseFrameColor; // Frames in Disp and Flex Layouts when frame is showing | ||||
| $browseSelectableShdwHov: rgba($colorBodyFg, 0.3) 0 0 3px; | ||||
| $browseSelectedBorder: 1px solid rgba($colorBodyFg, 0.4); | ||||
| $filterItemHoverFg: brightness(0.9); | ||||
| $filterItemMissing: contrast(0.2); | ||||
| $opacityMissing: 0.4; | ||||
| $borderMissing: 1px dashed $colorAlert !important; | ||||
|  | ||||
| /************************************************** EDITING */ | ||||
| $editUIColor: $uiColor; // Base color | ||||
| @@ -228,7 +217,7 @@ $colorDisclosureCtrlHov: rgba($colorBodyFg, 0.7); | ||||
| $btnStdH: 24px; | ||||
| $colorCursorGuide: rgba(black, 0.6); | ||||
| $shdwCursorGuide: rgba(white, 0.4) 0 0 2px; | ||||
| $colorLocalControlOvrBg: rgba($colorBodyBg, 0.8); | ||||
| $colorLocalControlOvrBg: rgba($colorBodyFg, 0.8); | ||||
| $colorSelectBg: $colorBtnBg; // This must be a solid color, not a gradient, due to usage of SVG bg in selects | ||||
| $colorSelectFg: $colorBtnFg; | ||||
| $colorSelectArw: lighten($colorBtnBg, 20%); | ||||
|   | ||||
| @@ -40,10 +40,11 @@ $inputTextP: $inputTextPTopBtm $inputTextPLeftRight; | ||||
| $menuLineH: 1.5rem; | ||||
| $treeItemIndent: 16px; | ||||
| $treeTypeIconW: 18px; | ||||
| $overlayOuterMarginLg: 5%; | ||||
| $overlayOuterMarginFullscreen: 0%; | ||||
| $overlayOuterMarginDialog: 20%; | ||||
| $overlayInnerMargin: 25px; | ||||
| $mainViewPad: 0px; | ||||
| $mainViewPad: 2px; | ||||
| /*************** Items */ | ||||
| $itemPadLR: 5px; | ||||
| $gridItemDesk: 175px; | ||||
| @@ -56,11 +57,11 @@ $tabularTdPadTB: 2px; | ||||
| $plotYBarW: 60px; | ||||
| $plotYLabelMinH: 20px; | ||||
| $plotYLabelW: 10px; | ||||
| $plotXBarH: 32px; | ||||
| $plotXBarH: 35px; | ||||
| $plotLegendH: 20px; | ||||
| $plotLegendWidthCollapsed: 20%; | ||||
| $plotLegendWidthExpanded: 50%; | ||||
| $plotSwatchD: 12px; | ||||
| $plotSwatchD: 10px; | ||||
| $plotDisplayArea: (0, 0, $plotXBarH, $plotYBarW); // 1: Top, 2: right, 3: bottom, 4: left | ||||
| $plotMinH: 95px; | ||||
| $controlBarH: 25px; | ||||
| @@ -89,8 +90,6 @@ $messageIconD: 80px; | ||||
| $messageListIconD: 32px; | ||||
| /*************** Tables */ | ||||
| $tableResizeColHitareaD: 6px; | ||||
| /*************** Misc */ | ||||
| $drawingObjBorderW: 3px; | ||||
|  | ||||
| /************************** MOBILE */ | ||||
| $mobileMenuIconD: 24px; // Used | ||||
| @@ -203,8 +202,6 @@ $glyph-icon-history: '\ea31'; | ||||
| $glyph-icon-arrow-nav-to-parent: '\ea32'; | ||||
| $glyph-icon-crosshair-in-circle: '\ea33'; | ||||
| $glyph-icon-target: '\ea34'; | ||||
| $glyph-icon-items-collapse: '\ea35'; | ||||
| $glyph-icon-items-expand: '\ea36'; | ||||
| $glyph-icon-activity: '\eb00'; | ||||
| $glyph-icon-activity-mode: '\eb01'; | ||||
| $glyph-icon-autoflow-tabular: '\eb02'; | ||||
|   | ||||
| @@ -57,6 +57,11 @@ button { | ||||
|         line-height: 90%; | ||||
|         padding: 3px 10px; | ||||
|  | ||||
|         @include hover() { | ||||
|             background: $colorBtnBgHov; | ||||
|             color: $colorBtnFgHov; | ||||
|         } | ||||
|  | ||||
|         @include desktop() { | ||||
|             font-size: 6px; | ||||
|         } | ||||
| @@ -406,17 +411,7 @@ select { | ||||
|  | ||||
| .c-tab { | ||||
|     // Used in Tab View, generic tabs | ||||
|     $notchSize: 7px; | ||||
|     $clipPath: | ||||
|         polygon( | ||||
|             0% 0%, | ||||
|             calc(100% - #{$notchSize}) 0%, | ||||
|             100% #{$notchSize}, | ||||
|             100% calc(100% - #{$notchSize}), | ||||
|             100% 100%, | ||||
|             0% 100% | ||||
|         ); | ||||
|     background: rgba($colorBtnBg, 0.7); | ||||
|     background: $colorBtnBg; | ||||
|     color: $colorBtnFg; | ||||
|     cursor: pointer; | ||||
|     display: flex; | ||||
| @@ -425,15 +420,21 @@ select { | ||||
|     margin: 1px 1px 0 0; | ||||
|     padding: $interiorMargin $interiorMarginLg; | ||||
|     white-space: nowrap; | ||||
|     clip-path: $clipPath; | ||||
|     -webkit-clip-path: $clipPath; // Safari | ||||
|  | ||||
|     > * + * { | ||||
|         margin-left: $interiorMargin; | ||||
|     } | ||||
|     --notchSize: 7px; | ||||
|  | ||||
|     clip-path: | ||||
|         polygon( | ||||
|             0% 0%, | ||||
|             calc(100% - var(--notchSize)) 0%, | ||||
|             100% var(--notchSize), | ||||
|             100% calc(100% - var(--notchSize)), | ||||
|             100% 100%, | ||||
|             0% 100% | ||||
|         ); | ||||
|  | ||||
|     @include hover() { | ||||
|         filter: $filterHov; | ||||
|         background: $colorBtnBgHov; | ||||
|     } | ||||
|  | ||||
|     &.is-current { | ||||
| @@ -461,17 +462,9 @@ select { | ||||
|     text-shadow: $shdwMenuText; | ||||
|     padding: $interiorMarginSm; | ||||
|     box-shadow: $shdwMenu; | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
|     display: block; | ||||
|     position: absolute; | ||||
|     z-index: 100; | ||||
|  | ||||
|     > * { | ||||
|         flex: 0 0 auto; | ||||
|         //+ * { | ||||
|         //    margin-top: $interiorMarginSm; | ||||
|         //} | ||||
|     } | ||||
| } | ||||
|  | ||||
| @mixin menuInner() { | ||||
| @@ -509,23 +502,6 @@ select { | ||||
| .c-menu { | ||||
|     @include menuOuter(); | ||||
|     @include menuInner(); | ||||
|  | ||||
|     &__section-hint { | ||||
|         $m: $interiorMargin; | ||||
|         margin: $m 0; | ||||
|         padding: $m nth($menuItemPad, 2) 0 nth($menuItemPad, 2); | ||||
|  | ||||
|         opacity: 0.6; | ||||
|         font-size: 0.9em; | ||||
|         font-style: italic; | ||||
|     } | ||||
|  | ||||
|     &__section-separator { | ||||
|         $m: $interiorMargin; | ||||
|         border-top: 1px solid $colorInteriorBorder; | ||||
|         margin: $m 0; | ||||
|         padding: $m nth($menuItemPad, 2) 0 nth($menuItemPad, 2); | ||||
|     } | ||||
| } | ||||
|  | ||||
| .c-super-menu { | ||||
|   | ||||
| @@ -206,6 +206,10 @@ body.desktop .has-local-controls { | ||||
|     &:hover { | ||||
|         box-shadow: $browseSelectableShdwHov; | ||||
|     } | ||||
|  | ||||
|     &[s-selected] { | ||||
|         border: $browseSelectedBorder; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /**************************** EDITING */ | ||||
|   | ||||
| @@ -138,8 +138,6 @@ | ||||
| .icon-arrow-nav-to-parent {  @include glyphBefore($glyph-icon-arrow-nav-to-parent); } | ||||
| .icon-crosshair-in-circle {  @include glyphBefore($glyph-icon-crosshair-in-circle); } | ||||
| .icon-target {  @include glyphBefore($glyph-icon-target); } | ||||
| .icon-items-collapse {  @include glyphBefore($glyph-icon-items-collapse); } | ||||
| .icon-items-expand {  @include glyphBefore($glyph-icon-items-expand); } | ||||
| .icon-activity {  @include glyphBefore($glyph-icon-activity); } | ||||
| .icon-activity-mode {  @include glyphBefore($glyph-icon-activity-mode); } | ||||
| .icon-autoflow-tabular {  @include glyphBefore($glyph-icon-autoflow-tabular); } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /***************************************************************************** | ||||
|  * Open MCT, Copyright (c) 2014-2020, United States Government | ||||
|  * Open MCT, Copyright (c) 2014-2018, United States Government | ||||
|  * as represented by the Administrator of the National Aeronautics and Space | ||||
|  * Administration. All rights reserved. | ||||
|  * | ||||
| @@ -29,26 +29,21 @@ mct-plot { | ||||
|     .gl-plot.child-frame { | ||||
|         &:hover { | ||||
|             background: rgba($editUIColorBg, 0.1); | ||||
|             box-shadow: inset rgba($editUIColorBg, 0.3) 0 0 0 1px; | ||||
|             box-shadow: inset rgba($editUIColorBg, 0.8) 0 0 0 1px; | ||||
|         } | ||||
|  | ||||
|         &[s-selected] { | ||||
|             background: rgba($editUIColorBg, 0.2); | ||||
|             box-shadow: inset rgba($editUIColorBg, 0.8) 0 0 0 1px; | ||||
|             border: 1px solid $editUIColorFg !important; | ||||
|             color: $editUIColorFg !important; | ||||
|             box-shadow: $editFrameSelectedShdw; | ||||
|             z-index: 2; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     .plot-wrapper-axis-and-display-area { | ||||
|         pointer-events: none; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .c-plot, | ||||
| .gl-plot { | ||||
|     overflow: hidden; | ||||
|  | ||||
|         .s-status-taking-snapshot & { | ||||
|     .s-status-taking-snapshot & { | ||||
|         .c-control-bar { | ||||
|             display: none; | ||||
|         } | ||||
| @@ -56,35 +51,29 @@ mct-plot { | ||||
|             display: none; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /*********************** MISSING ITEM INDICATORS */ | ||||
|     .is-missing__indicator { | ||||
|         display: none; | ||||
|     } | ||||
|     .is-missing { | ||||
|         @include isMissing(); | ||||
|         .is-missing__indicator { | ||||
|             font-size: 0.8em; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| .c-plot { | ||||
|     //$p: $mainViewPad; | ||||
|     @include abs($mainViewPad); | ||||
|     //position: absolute; | ||||
|     //top: $p; right: $p; bottom: $p; left: $p; | ||||
|  | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
|  | ||||
|     .c-control-bar { | ||||
|     > * + * { | ||||
|         margin-top: $interiorMargin; | ||||
|     } | ||||
|  | ||||
|     .l-control-bar { | ||||
|         flex: 0 0 auto; | ||||
|         margin-bottom: $interiorMargin; | ||||
|     } | ||||
|  | ||||
|     .l-view-section { | ||||
|         display: flex; | ||||
|         flex: 1 1 auto; | ||||
|         flex-direction: column; | ||||
|         overflow: hidden; | ||||
|     } | ||||
|  | ||||
|     &--stacked { | ||||
| @@ -111,23 +100,39 @@ mct-plot { | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     .is-in-small-container & { | ||||
|         .c-control-bar { | ||||
|             display: none; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| .gl-plot { | ||||
|     display: flex; | ||||
|     flex: 1 1 auto; | ||||
|     position: relative; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     min-height: $plotMinH; | ||||
|  | ||||
|     /*********************** AXIS AND DISPLAY AREA */ | ||||
|     .plot-wrapper-axis-and-display-area { | ||||
|         position: relative; | ||||
|         flex: 1 1 auto; | ||||
|         min-height: $plotMinH; | ||||
|  | ||||
|         .l-state-indicators { | ||||
|             color: $colorPausedBg; | ||||
|             position: absolute; | ||||
|             display: block; | ||||
|             font-size: 1.5em; | ||||
|             pointer-events: none; | ||||
|             top: $interiorMarginSm; | ||||
|             left: $interiorMarginSm; | ||||
|             z-index: 2; | ||||
|  | ||||
|             > * + * { | ||||
|                 margin-left: $interiorMarginSm; | ||||
|             } | ||||
|  | ||||
|             .t-alert-unsynced { | ||||
|                 display: none; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     .gl-plot-wrapper-display-area-and-x-axis { | ||||
| @@ -208,7 +213,9 @@ mct-plot { | ||||
|         &.gl-plot-y-label { | ||||
|             display: block; | ||||
|             left: 0; top: 0; right: auto; bottom: 0; | ||||
|             padding-left: 5px; | ||||
|             text-orientation: mixed; | ||||
|             //overflow: hidden; | ||||
|             writing-mode: vertical-lr; | ||||
|             &:before { | ||||
|                 // Icon denoting configurability | ||||
| @@ -273,7 +280,7 @@ mct-plot { | ||||
|         align-items: center; | ||||
|         position: absolute; | ||||
|         top: $m; | ||||
|         left: $m; | ||||
|         right: $m; | ||||
|         z-index: 9; | ||||
|  | ||||
|         &__reset { | ||||
| @@ -286,28 +293,6 @@ mct-plot { | ||||
|             top: $m; | ||||
|             right: $m; | ||||
|         } | ||||
|  | ||||
|         .c-button { | ||||
|             box-shadow: $colorLocalControlOvrBg 0 0 0 2px; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     .l-state-indicators { | ||||
|         color: $colorPausedBg; | ||||
|         position: absolute; | ||||
|         cursor: help; | ||||
|         font-size: 1.2em; | ||||
|         bottom: $interiorMarginSm; | ||||
|         left: $interiorMarginSm; | ||||
|         z-index: 2; | ||||
|  | ||||
|         > * + * { | ||||
|             margin-left: $interiorMarginSm; | ||||
|         } | ||||
|  | ||||
|         .t-alert-unsynced { | ||||
|             display: none; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -356,11 +341,11 @@ mct-plot { | ||||
|  | ||||
| .gl-plot-tick { | ||||
|     &.gl-plot-x-tick-label { | ||||
|         top: $interiorMarginSm; | ||||
|         top: $interiorMargin; | ||||
|     } | ||||
|     &.gl-plot-y-tick-label { | ||||
|         right: $interiorMarginSm; | ||||
|         left: auto; | ||||
|         right: $interiorMargin; | ||||
|         left: $interiorMargin; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -383,6 +368,12 @@ mct-plot { | ||||
|     z-index: -10; | ||||
|  | ||||
|     .l-view-section { | ||||
|         //$m: $interiorMargin; | ||||
|         //top: $m !important; | ||||
|         //right: $m; | ||||
|         //bottom: $m; | ||||
|         //left: $m; | ||||
|  | ||||
|         .s-status-timeconductor-unsynced .holder-plot { | ||||
|             .t-object-alert.t-alert-unsynced { | ||||
|                 display: none; | ||||
| @@ -438,18 +429,13 @@ mct-plot { | ||||
| /****************** _LEGEND.SCSS */ | ||||
| .gl-plot-legend, | ||||
| .c-plot-legend { | ||||
|     overflow: hidden; | ||||
|  | ||||
|     &__wrapper { | ||||
|         // Holds view-control and both collapsed and expanded legends | ||||
|         flex: 1 1 auto; | ||||
|         height: 100%; | ||||
|         overflow: auto; | ||||
|         padding: 2px; | ||||
|     } | ||||
|  | ||||
|     &__view-control { | ||||
|         padding-top: 4px; | ||||
|         padding-top: 2px; | ||||
|         margin-right: $interiorMarginSm; | ||||
|     } | ||||
|  | ||||
| @@ -457,22 +443,8 @@ mct-plot { | ||||
|         @include propertiesHeader(); | ||||
|         margin-bottom: $interiorMarginSm; | ||||
|     } | ||||
|  | ||||
|     .is-in-small-container & { | ||||
|         &.is-legend-hidden { | ||||
|             display: none; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| .c-plot--stacked { | ||||
|     .is-legend-hidden { | ||||
|         // Always show the legend in a stacked plot | ||||
|         display: flex !important; | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| .gl-plot-legend { | ||||
|     display: flex; | ||||
|     align-items: flex-start; | ||||
| @@ -508,21 +480,15 @@ mct-plot { | ||||
| /***************** GENERAL STYLES, ALL STATES */ | ||||
| .plot-legend-item { | ||||
|     // General styles for legend items, both expanded and collapsed legend states | ||||
|     > * + * { | ||||
|         margin-left: $interiorMarginSm; | ||||
|     } | ||||
|  | ||||
|     .plot-series-color-swatch { | ||||
|         border-radius: 30%; //$smallCr; | ||||
|         border-radius: $smallCr; | ||||
|         border: 1px solid $colorBodyBg; | ||||
|         display: inline-block; | ||||
|         flex: 0 0 auto; | ||||
|         height: $plotSwatchD; | ||||
|         width: $plotSwatchD; | ||||
|     } | ||||
|     .plot-series-name { | ||||
|         display: inline; | ||||
|         @include ellipsize(); | ||||
|     } | ||||
|  | ||||
|     .plot-series-value { | ||||
| @@ -530,27 +496,11 @@ mct-plot { | ||||
|     } | ||||
| } | ||||
|  | ||||
| .plot-series-swatch-and-name { | ||||
|     display: flex; | ||||
|     flex: 0 1 auto; | ||||
|     align-items: center; | ||||
|  | ||||
|     > * + * { | ||||
|         margin-left: $interiorMarginSm; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .plot-wrapper-expanded-legend { | ||||
|     flex: 1 1 auto; | ||||
| } | ||||
|  | ||||
| .plot-legend-top .gl-plot-legend { margin-bottom: $interiorMargin; } | ||||
| .plot-legend-bottom .gl-plot-legend { margin-top: $interiorMargin; } | ||||
| .plot-legend-left .gl-plot-legend { margin-right: $interiorMargin; } | ||||
| .plot-legend-right .gl-plot-legend { margin-left: $interiorMargin; } | ||||
|  | ||||
| .gl-plot, | ||||
| .c-plot { | ||||
| .gl-plot { | ||||
|     &.plot-legend-collapsed .plot-wrapper-expanded-legend { display: none; } | ||||
|     &.plot-legend-expanded .plot-wrapper-collapsed-legend { display: none; } | ||||
|  | ||||
| @@ -568,14 +518,21 @@ mct-plot { | ||||
|  | ||||
|         .plot-legend-item { | ||||
|             display: flex; | ||||
|             align-items: center; | ||||
|             justify-content: stretch; | ||||
|  | ||||
|             &:not(:first-child) { | ||||
|                 margin-left: $interiorMarginLg; | ||||
|             } | ||||
|             .plot-series-swatch-and-name, | ||||
|             .plot-series-value { | ||||
|                 @include ellipsize(); | ||||
|                 flex: 1 1 auto; | ||||
|             } | ||||
|  | ||||
|             .plot-series-swatch-and-name { | ||||
|                 margin-right: $interiorMarginSm; | ||||
|             } | ||||
|  | ||||
|             .plot-series-value { | ||||
|                 text-align: left; | ||||
|             } | ||||
| @@ -585,7 +542,7 @@ mct-plot { | ||||
|     /***************** GENERAL STYLES, EXPANDED */ | ||||
|     &.plot-legend-expanded { | ||||
|         .gl-plot-legend { | ||||
|              max-height: 70%; | ||||
|             // max-height: 70%; | ||||
|         } | ||||
|  | ||||
|         .plot-wrapper-expanded-legend { | ||||
| @@ -596,10 +553,8 @@ mct-plot { | ||||
|  | ||||
|     /***************** TOP OR BOTTOM */ | ||||
|     &.plot-legend-top, | ||||
|     &.plot-legend-bottom, | ||||
|     &.plot-legend-hidden { | ||||
|     &.plot-legend-bottom { | ||||
|         // General styles when legend is on the top or bottom | ||||
|         // -hidden included for legacy plots | ||||
|         flex-direction: column; | ||||
|  | ||||
|         &.plot-legend-collapsed { | ||||
| @@ -608,11 +563,6 @@ mct-plot { | ||||
|                 display: flex; | ||||
|                 flex: 1 1 auto; | ||||
|                 overflow: hidden; | ||||
|  | ||||
|                 > .plot-legend-item + .plot-legend-item { | ||||
|                     // Space between plot items | ||||
|                     margin-left: $interiorMarginLg; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -621,7 +571,6 @@ mct-plot { | ||||
|     &.plot-legend-left, | ||||
|     &.plot-legend-right { | ||||
|         // General styles when legend is on left or right | ||||
|  | ||||
|         .gl-plot-legend { | ||||
|             max-height: inherit; | ||||
|         } | ||||
| @@ -645,18 +594,12 @@ mct-plot { | ||||
|                 min-width: 0; | ||||
|                 flex: 1 1 auto; | ||||
|                 overflow-y: auto; | ||||
|  | ||||
|                 > * + * { | ||||
|                     // Space between plot items | ||||
|                     margin-top: $interiorMarginSm; | ||||
|                 } | ||||
|             } | ||||
|             .plot-legend-item { | ||||
|                 margin-bottom: $interiorMarginSm; | ||||
|                 margin-bottom: 1px; | ||||
|                 margin-left: 0; | ||||
|                 flex-wrap: nowrap; | ||||
|                 flex-wrap: wrap; | ||||
|                 .plot-series-swatch-and-name { | ||||
|                     @include ellipsize(); | ||||
|                     flex: 0 1 auto; | ||||
|                     min-width: 20%; | ||||
|                 } | ||||
| @@ -680,31 +623,6 @@ mct-plot { | ||||
|     } | ||||
| } | ||||
|  | ||||
| /***************** STACKED PLOT LEGEND OVERRIDES */ | ||||
| .c-plot--stacked { | ||||
|     // Always show the legend on top, ignore any position setting | ||||
|     .c-plot, | ||||
|     .gl-plot { | ||||
|         flex-direction: column !important; | ||||
|  | ||||
|         .c-plot-legend, | ||||
|         .gl-plot-legend { | ||||
|             margin: 0; | ||||
|             margin-bottom: $interiorMargin; | ||||
|             order: 1 !important; | ||||
|             width: 100% !important; | ||||
|  | ||||
|             .plot-wrapper-collapsed-legend { | ||||
|                 flex-direction: row !important; | ||||
|             } | ||||
|         } | ||||
|         .plot-wrapper-axis-and-display-area { | ||||
|             order: 2 !important; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| /***************** CURSOR GUIDES */ | ||||
| [class*='c-cursor-guide'] { | ||||
|     box-shadow: $shdwCursorGuide; | ||||
| @@ -735,24 +653,3 @@ mct-plot { | ||||
|         display: inline-block !important; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /*********************** CURSOR LOCK INDICATOR */ | ||||
| [class*='c-state-indicator__alert-cursor-lock'] { | ||||
|     display: none; | ||||
| } | ||||
|  | ||||
| [class*='is-cursor-locked'] { | ||||
|     background: rgba($colorInfo, 0.1); | ||||
|  | ||||
|     [class*='c-state-indicator__alert-cursor-lock'] { | ||||
|         @include userSelectNone(); | ||||
|         color: $colorInfo; | ||||
|         display: block; | ||||
|         margin-right: $interiorMarginSm; | ||||
|  | ||||
|         &[class*='--verbose'] { | ||||
|             padding: $interiorMarginSm; | ||||
|  | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -893,7 +893,7 @@ body.desktop { | ||||
| .grid-row { | ||||
|     .grid-cell { | ||||
|         padding: 3px $interiorMarginLg 3px 0; | ||||
|         &[title]:not([title=""]) { | ||||
|         &[title] { | ||||
|             // When a cell has a title, assume it's helpful text | ||||
|             cursor: help; | ||||
|         } | ||||
|   | ||||
| @@ -117,33 +117,6 @@ | ||||
|     } | ||||
| } | ||||
|  | ||||
| @mixin isMissing($absPos: false) { | ||||
|     // Common styles to be applied to tree items, object labels, grid and list item views | ||||
|     //opacity: 0.7; | ||||
|     //pointer-events: none; // Don't think we can do this, as disables title hover on icon element | ||||
|  | ||||
|     .is-missing__indicator { | ||||
|         display: none ; | ||||
|         text-shadow: $colorBodyBg 0 0 2px; | ||||
|         color: $colorAlert; | ||||
|         font-family: symbolsfont; | ||||
|  | ||||
|         &:before { | ||||
|             content: $glyph-icon-alert-triangle; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @if $absPos { | ||||
|         .is-missing__indicator { | ||||
|             position: absolute; | ||||
|             z-index: 3; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     &.is-missing .is-missing__indicator, | ||||
|     .is-missing .is-missing__indicator { display: block !important; } | ||||
| } | ||||
|  | ||||
| @mixin bgDiagonalStripes($c: yellow, $a: 0.1, $d: 40px) { | ||||
|     background-image: linear-gradient(-45deg, | ||||
|         rgba($c, $a) 25%, transparent 25%, | ||||
| @@ -443,18 +416,28 @@ | ||||
|     } | ||||
|  | ||||
|     @include hover() { | ||||
|         filter: $filterHov; | ||||
|         background: $colorBtnBgHov; | ||||
|         color: $colorBtnFgHov; | ||||
|     } | ||||
|  | ||||
|     &[class*="--major"], | ||||
|     &[class*='is-active']{ | ||||
|         background: $colorBtnMajorBg; | ||||
|         color: $colorBtnMajorFg; | ||||
|  | ||||
|         @include hover() { | ||||
|             background: $colorBtnMajorBgHov; | ||||
|             color: $colorBtnMajorFgHov; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     &[class*='--caution'] { | ||||
|         background: $colorBtnCautionBg !important; | ||||
|         color: $colorBtnCautionFg !important; | ||||
|         background: $colorBtnCautionBg; | ||||
|         color: $colorBtnCautionFg; | ||||
|  | ||||
|         &:hover { | ||||
|             background: $colorBtnCautionBgHov; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -49,6 +49,8 @@ table { | ||||
|     td { | ||||
|         vertical-align: top; | ||||
|     } | ||||
|  | ||||
|     a { color: $colorBtnMajorBg; } | ||||
| } | ||||
|  | ||||
| .is-editing { | ||||
| @@ -90,28 +92,14 @@ div.c-table { | ||||
|         flex: 1 1 auto; | ||||
|     } | ||||
|  | ||||
|     .is-in-small-container & { | ||||
|         &:not(.is-paused) { | ||||
|             .c-table-control-bar { | ||||
|                 display: none; | ||||
|             } | ||||
|         } | ||||
|         .c-table-control-bar { | ||||
|             .c-click-icon, | ||||
|             .c-button { | ||||
|                 &__label { | ||||
|                     display: none; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     > * + * { | ||||
|         margin-top: $interiorMarginSm; | ||||
|     } | ||||
| } | ||||
|  | ||||
| .c-table-control-bar { | ||||
|     display: flex; | ||||
|     flex: 0 0 auto; | ||||
|     //margin-bottom: $interiorMarginSm; // This approach to allow margin to go away when control bar is hidden | ||||
|     padding: $interiorMarginSm 0; | ||||
|  | ||||
|     > * + * { | ||||
|         margin-left: $interiorMarginSm; | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -106,8 +106,6 @@ | ||||
| <glyph unicode="" glyph-name="icon-arrow-up-to-parent" horiz-adv-x="1056" d="M643.427 6.739c-81.955 0.697-148.179 67.065-148.642 149.010v395.872l296.871-247.393v197.914l-395.828 329.857-395.828-328.62v-197.502l296.871 246.156v-396.241c0-190.905 155.239-346.556 346.144-346.968l412.321-0.825 0.412 197.914z" /> | ||||
| <glyph unicode="" glyph-name="icon-crosshair-in-circle" 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-54.634-54.8-125.77-93.12-205.322-106.874l-2.278-0.326v250.8h-128v-250.8c-161.302 28.062-286.738 153.497-314.468 312.5l-0.332 2.3h250.8v128h-250.8c28.062 161.302 153.497 286.738 312.5 314.468l2.3 0.332v-250.8h128v250.8c161.302-28.062 286.738-153.497 314.468-312.5l0.332-2.3h-250.8v-128h250.8c-14.080-81.83-52.4-152.966-107.191-207.591l-0.009-0.009z" /> | ||||
| <glyph unicode="" glyph-name="icon-target" d="M512 448c70.692 0 128-57.308 128-128s-57.308-128-128-128c-70.692 0-128 57.308-128 128v0c0.114 70.647 57.353 127.886 127.989 128h0.011zM512 576c-141.385 0-256-114.615-256-256s114.615-256 256-256c141.385 0 256 114.615 256 256v0c-0.114 141.339-114.661 255.886-255.989 256h-0.011zM512 704c211.87-0.128 383.575-171.912 383.575-383.8 0-211.967-171.833-383.8-383.8-383.8s-383.8 171.833-383.8 383.8c0 105.99 42.963 201.945 112.425 271.4v0c69.21 69.437 164.944 112.401 270.713 112.401 0.312 0 0.624 0 0.936-0.001h-0.048zM512 832c-282.8 0-512-229.2-512-512s229.2-512 512-512 512 229.2 512 512-229.2 512-512 512z" /> | ||||
| <glyph unicode="" glyph-name="icon-items-collapse" d="M45.2 173.2h229.6l-274.8-274.6 90.6-90.6 274.6 274.8v-229.6h128v448h-448v-128zM1024 741.4l-90.6 90.6-274.6-274.8v229.6h-128v-448h448v128h-229.6l274.8 274.6z" /> | ||||
| <glyph unicode="" glyph-name="icon-items-expand" d="M448-64h-229.4l274.6 274.8-90.4 90.4-274.8-274.6v229.4h-128v-448h448v128zM530.8 429.2l90.4-90.4 274.8 274.6v-229.4h128v448h-448v-128h229.4l-274.6-274.8z" /> | ||||
| <glyph unicode="" glyph-name="icon-activity" d="M576 768h-256l320-320h-290.256c-44.264 76.516-126.99 128-221.744 128h-128v-512h128c94.754 0 177.48 51.484 221.744 128h290.256l-320-320h256l448 448-448 448z" /> | ||||
| <glyph unicode="" glyph-name="icon-activity-mode" d="M512 832c-214.8 0-398.8-132.4-474.8-320h90.8c56.8 0 108-24.8 143-64h241l-192 192h256l320-320-320-320h-256l192 192h-241c-35-39.2-86.2-64-143-64h-90.8c76-187.6 259.8-320 474.8-320 282.8 0 512 229.2 512 512s-229.2 512-512 512z" /> | ||||
| <glyph unicode="" glyph-name="icon-autoflow-tabular" d="M192 832c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h64v1024h-64zM384 832h256v-1024h-256v1024zM832 832h-64v-704h256v512c0 105.6-86.4 192-192 192z" /> | ||||
|   | ||||
| Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB | 
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -3,7 +3,7 @@ | ||||
| @import "../plugins/condition/components/conditionals.scss"; | ||||
| @import "../plugins/conditionWidget/components/condition-widget.scss"; | ||||
| @import "../plugins/condition/components/inspector/conditional-styles.scss"; | ||||
| @import "../plugins/displayLayout/components/box-and-line-views"; | ||||
| @import "../plugins/displayLayout/components/box-view.scss"; | ||||
| @import "../plugins/displayLayout/components/display-layout.scss"; | ||||
| @import "../plugins/displayLayout/components/edit-marquee.scss"; | ||||
| @import "../plugins/displayLayout/components/image-view.scss"; | ||||
| @@ -13,6 +13,7 @@ | ||||
| @import "../plugins/filters/components/filters-view.scss"; | ||||
| @import "../plugins/filters/components/global-filters.scss"; | ||||
| @import "../plugins/flexibleLayout/components/flexible-layout.scss"; | ||||
| @import "../plugins/folderView/components/grid-item.scss"; | ||||
| @import "../plugins/folderView/components/grid-view.scss"; | ||||
| @import "../plugins/folderView/components/list-item.scss"; | ||||
| @import "../plugins/folderView/components/list-view.scss"; | ||||
|   | ||||
| @@ -24,24 +24,13 @@ | ||||
|     class="c-so-view has-local-controls" | ||||
|     :class="{ | ||||
|         'c-so-view--no-frame': !hasFrame, | ||||
|         'has-complex-content': complexContent, | ||||
|         'is-missing': domainObject.status === 'missing' | ||||
|         'has-complex-content': complexContent | ||||
|     }" | ||||
| > | ||||
|     <div class="c-so-view__header"> | ||||
|         <div class="c-object-label" | ||||
|              :class="{ | ||||
|                  classList, | ||||
|                  'is-missing': domainObject.status === 'missing' | ||||
|              }" | ||||
|              :class="[cssClass, classList]" | ||||
|         > | ||||
|             <div class="c-object-label__type-icon" | ||||
|                  :class="cssClass" | ||||
|             > | ||||
|                 <span class="is-missing__indicator" | ||||
|                       title="This item is missing" | ||||
|                 ></span> | ||||
|             </div> | ||||
|             <div class="c-object-label__name"> | ||||
|                 {{ domainObject && domainObject.name }} | ||||
|             </div> | ||||
| @@ -57,9 +46,6 @@ | ||||
|             @click="expand" | ||||
|         ></button> | ||||
|     </div> | ||||
|     <div class="is-missing__indicator" | ||||
|          title="This item is missing" | ||||
|     ></div> | ||||
|     <object-view | ||||
|         ref="objectView" | ||||
|         class="c-so-view__object-view" | ||||
| @@ -142,11 +128,8 @@ export default { | ||||
|         getOverlayElement(childElement) { | ||||
|             const fragment = new DocumentFragment(); | ||||
|             const header = this.getPreviewHeader(); | ||||
|             const wrapper = document.createElement('div'); | ||||
|             wrapper.classList.add('l-preview-window__object-view'); | ||||
|             wrapper.append(childElement); | ||||
|             fragment.append(header); | ||||
|             fragment.append(wrapper); | ||||
|             fragment.append(childElement); | ||||
|  | ||||
|             return fragment; | ||||
|         }, | ||||
|   | ||||
| @@ -1,10 +1,7 @@ | ||||
| <template> | ||||
| <a | ||||
|     class="c-tree__item__label c-object-label" | ||||
|     :class="{ | ||||
|         classList, | ||||
|         'is-missing': observedObject.status === 'missing' | ||||
|     }" | ||||
|     :class="classList" | ||||
|     draggable="true" | ||||
|     :href="objectLink" | ||||
|     @dragstart="dragStart" | ||||
| @@ -13,14 +10,8 @@ | ||||
|     <div | ||||
|         class="c-tree__item__type-icon c-object-label__type-icon" | ||||
|         :class="typeClass" | ||||
|     > | ||||
|         <span class="is-missing__indicator" | ||||
|               title="This item is missing" | ||||
|         ></span> | ||||
|     </div> | ||||
|     <div class="c-tree__item__name c-object-label__name"> | ||||
|         {{ observedObject.name }} | ||||
|     </div> | ||||
|     ></div> | ||||
|     <div class="c-tree__item__name c-object-label__name">{{ observedObject.name }}</div> | ||||
| </a> | ||||
| </template> | ||||
|  | ||||
|   | ||||
| @@ -53,9 +53,7 @@ export default { | ||||
|     mounted() { | ||||
|         this.currentObject = this.object; | ||||
|         this.updateView(); | ||||
|         this.$el.addEventListener('dragover', this.onDragOver, { | ||||
|             capture: true | ||||
|         }); | ||||
|         this.$el.addEventListener('dragover', this.onDragOver); | ||||
|         this.$el.addEventListener('drop', this.editIfEditable, { | ||||
|             capture: true | ||||
|         }); | ||||
| @@ -271,7 +269,6 @@ export default { | ||||
|             if (provider && | ||||
|                 provider.canEdit && | ||||
|                 provider.canEdit(this.currentObject) && | ||||
|                 this.isEditingAllowed() && | ||||
|                 !this.openmct.editor.isEditing()) { | ||||
|                 this.openmct.editor.edit(); | ||||
|             } | ||||
| @@ -304,7 +301,7 @@ export default { | ||||
|                 objectPath= this.currentObjectPath || this.objectPath, | ||||
|                 parentObject = objectPath[1]; | ||||
|  | ||||
|             return [browseObject, parentObject, this.currentObject].every(object => object && !object.locked); | ||||
|             return [browseObject, parentObject, this.currentObject].every(object => !object.locked); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user