Compare commits
	
		
			56 Commits
		
	
	
		
			collimate-
			...
			plots-insp
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 59c3c836c3 | ||
|   | 3a2f78cbc6 | ||
|   | 10b281de94 | ||
|   | 53bf50d3e6 | ||
|   | e6188e3d80 | ||
|   | ab4089f4d0 | ||
|   | dcb69503a5 | ||
|   | 5a5974ae73 | ||
|   | 57b2e2bee2 | ||
|   | 697f9f16ae | ||
|   | 8d6e6569cc | ||
|   | 00a0bdef37 | ||
|   | 23dd1b236b | ||
|   | 4e113772d7 | ||
|   | 8c756bf81e | ||
|   | cfef77edfc | ||
|   | 188cfb3087 | ||
|   | d01768f14f | ||
|   | ab95ace86d | ||
|   | e53aee0076 | ||
|   | 6ff5bb7012 | ||
|   | 83ab35b376 | ||
|   | aacbce8e3a | ||
|   | fb04e4998f | ||
|   | 1f1e754943 | ||
|   | 9a885d7dcc | ||
|   | 8b26e9db82 | ||
|   | 8c3cf43895 | ||
|   | 8f0a993b3d | ||
|   | 9889a636c0 | ||
|   | bdf15ad3b0 | ||
|   | 1e337844b6 | ||
|   | 5178cdd979 | ||
|   | 8d5796f8be | ||
|   | ece57c0e0c | ||
|   | b977505c0e | ||
|   | 7aa39c9617 | ||
|   | bd387fe1cf | ||
|   | d8777e5f5b | ||
|   | 0b625dc47e | ||
|   | 535e8aef13 | ||
|   | a4bbd0d3d7 | ||
|   | 7282516d30 | ||
|   | 7b244a6bc7 | ||
|   | 343ee67444 | ||
|   | b93efa63b2 | ||
|   | 8f764be600 | ||
|   | b1b98d5d43 | ||
|   | 5958f146a4 | ||
|   | 649d7ef92a | ||
|   | 2da5bea996 | ||
|   | 1ab08fc523 | ||
|   | c2cd2356e9 | ||
|   | 6fd91ac4bf | ||
|   | d9caf081d8 | ||
|   | 72a95da7b1 | 
| @@ -24,6 +24,13 @@ define([ | ||||
|                     return false; | ||||
|                 } | ||||
|  | ||||
|                 //TODO: Remove this when plots Angular implementation is deprecated | ||||
|                 let parent = selection[0].length > 1 && selection[0][1].context.item; | ||||
|                 if (parent && parent.type === 'time-strip') { | ||||
|                     return (selectionContext.item.type === typeDefinition.key) | ||||
|                             && (typeDefinition.key !== 'telemetry.plot.overlay'); | ||||
|                 } | ||||
|  | ||||
|                 return selectionContext.item.type === typeDefinition.key; | ||||
|             }, | ||||
|             view: function (selection) { | ||||
|   | ||||
							
								
								
									
										64
									
								
								src/plugins/plot/vue/inspector/PlotOptions.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								src/plugins/plot/vue/inspector/PlotOptions.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| <!-- | ||||
|  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. | ||||
| --> | ||||
| <template> | ||||
| <div> | ||||
|     <div v-if="canEdit"> | ||||
|         <plot-options-edit /> | ||||
|     </div> | ||||
|     <div v-else> | ||||
|         <plot-options-browse /> | ||||
|     </div> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import PlotOptionsBrowse from "@/plugins/plot/vue/inspector/PlotOptionsBrowse.vue"; | ||||
| import PlotOptionsEdit from "@/plugins/plot/vue/inspector/PlotOptionsEdit.vue"; | ||||
| export default { | ||||
|     components: { | ||||
|         PlotOptionsBrowse, | ||||
|         PlotOptionsEdit | ||||
|     }, | ||||
|     inject: ['openmct', 'domainObject'], | ||||
|     data() { | ||||
|         return { | ||||
|             isEditing: this.openmct.editor.isEditing() | ||||
|         }; | ||||
|     }, | ||||
|     computed: { | ||||
|         canEdit() { | ||||
|             return this.isEditing && !this.domainObject.locked; | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.openmct.editor.on('isEditing', this.setEditState); | ||||
|     }, | ||||
|     beforeDestroy() { | ||||
|         this.openmct.editor.off('isEditing', this.setEditState); | ||||
|     }, | ||||
|     methods: { | ||||
|         setEditState(isEditing) { | ||||
|             this.isEditing = isEditing; | ||||
|         } | ||||
|     } | ||||
| }; | ||||
| </script> | ||||
							
								
								
									
										198
									
								
								src/plugins/plot/vue/inspector/PlotOptionsBrowse.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								src/plugins/plot/vue/inspector/PlotOptionsBrowse.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,198 @@ | ||||
| <!-- | ||||
|  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. | ||||
| --> | ||||
| <template> | ||||
| <div v-if="config && loaded" | ||||
|      class="js-plot-options-browse" | ||||
| > | ||||
|     <ul class="c-tree"> | ||||
|         <h2 title="Plot series display properties in this object">Plot Series</h2> | ||||
|         <plot-options-item v-for="series in plotSeries" | ||||
|                            :key="series.key" | ||||
|                            :series="series" | ||||
|         /> | ||||
|     </ul> | ||||
|     <div class="grid-properties"> | ||||
|         <ul class="l-inspector-part"> | ||||
|             <h2 title="Y axis settings for this object">Y Axis</h2> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="Manually override how the Y axis is labeled." | ||||
|                 >Label</div> | ||||
|                 <div class="grid-cell value">{{ label ? label : "Not defined" }}</div> | ||||
|             </li> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="Automatically scale the Y axis to keep all values in view." | ||||
|                 >Autoscale</div> | ||||
|                 <div class="grid-cell value"> | ||||
|                     {{ autoscale ? "Enabled: " : "Disabled" }} | ||||
|                     {{ autoscale ? autoscalePadding : "" }} | ||||
|                 </div> | ||||
|             </li> | ||||
|             <li v-if="!autoscale && rangeMin" | ||||
|                 class="grid-row" | ||||
|             > | ||||
|                 <div class="grid-cell label" | ||||
|                      title="Minimum Y axis value." | ||||
|                 >Minimum value</div> | ||||
|                 <div class="grid-cell value">{{ rangeMin }}</div> | ||||
|             </li> | ||||
|             <li v-if="!autoscale && rangeMax" | ||||
|                 class="grid-row" | ||||
|             > | ||||
|                 <div class="grid-cell label" | ||||
|                      title="Maximum Y axis value." | ||||
|                 >Maximum value</div> | ||||
|                 <div class="grid-cell value">{{ rangeMax }}</div> | ||||
|             </li> | ||||
|         </ul> | ||||
|         <ul class="l-inspector-part"> | ||||
|             <h2 title="Legend settings for this object">Legend</h2> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="The position of the legend relative to the plot display area." | ||||
|                 >Position</div> | ||||
|                 <div class="grid-cell value capitalize">{{ 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">{{ 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> | ||||
|                 <div class="grid-cell value">{{ expandByDefault ? "Yes" : "No" }}</div> | ||||
|             </li> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="What to display in the legend when it's collapsed." | ||||
|                 >Show when collapsed:</div> | ||||
|                 <div class="grid-cell value">{{ | ||||
|                     valueToShowWhenCollapsed.replace('nearest', '') | ||||
|                 }} | ||||
|                 </div> | ||||
|             </li> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="What to display in the legend when it's expanded." | ||||
|                 >Show when expanded:</div> | ||||
|                 <div class="grid-cell value comma-list"> | ||||
|                     <span v-if="showTimestampWhenExpanded">Timestamp</span> | ||||
|                     <span v-if="showValueWhenExpanded">Value</span> | ||||
|                     <span v-if="showMinimumWhenExpanded">Min</span> | ||||
|                     <span v-if="showMaximumWhenExpanded">Max</span> | ||||
|                     <span v-if="showUnitsWhenExpanded">Units</span> | ||||
|                 </div> | ||||
|             </li> | ||||
|         </ul> | ||||
|     </div> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import PlotOptionsItem from "./PlotOptionsItem.vue"; | ||||
| import configStore from "../single/configuration/configStore"; | ||||
| import eventHelpers from "../single/lib/eventHelpers"; | ||||
|  | ||||
| export default { | ||||
|     components: { | ||||
|         PlotOptionsItem | ||||
|     }, | ||||
|     inject: ['openmct', 'domainObject'], | ||||
|     data() { | ||||
|         return { | ||||
|             config: undefined, | ||||
|             label: '', | ||||
|             autoscale: '', | ||||
|             autoscalePadding: '', | ||||
|             rangeMin: '', | ||||
|             rangeMax: '', | ||||
|             position: '', | ||||
|             hideLegendWhenSmall: '', | ||||
|             expandByDefault: '', | ||||
|             valueToShowWhenCollapsed: '', | ||||
|             showTimestampWhenExpanded: '', | ||||
|             showValueWhenExpanded: '', | ||||
|             showMinimumWhenExpanded: '', | ||||
|             showMaximumWhenExpanded: '', | ||||
|             showUnitsWhenExpanded: '', | ||||
|             loaded: false, | ||||
|             plotSeries: [] | ||||
|         }; | ||||
|     }, | ||||
|     mounted() { | ||||
|         eventHelpers.extend(this); | ||||
|         this.config = this.getConfig(); | ||||
|         this.initConfiguration(); | ||||
|         this.registerListeners(); | ||||
|         this.loaded = true; | ||||
|     }, | ||||
|     beforeDestroy() { | ||||
|         this.stopListening(); | ||||
|     }, | ||||
|     methods: { | ||||
|         initConfiguration() { | ||||
|             this.label = this.config.yAxis.get('label'); | ||||
|             this.autoscale = this.config.yAxis.get('autoscale'); | ||||
|             this.autoscalePadding = this.config.yAxis.get('autoscalePadding'); | ||||
|             const range = this.config.yAxis.get('range'); | ||||
|             if (range) { | ||||
|                 this.rangeMin = range.min; | ||||
|                 this.rangeMax = range.max; | ||||
|             } | ||||
|  | ||||
|             this.position = this.config.legend.get('position'); | ||||
|             this.hideLegendWhenSmall = this.config.legend.get('hideLegendWhenSmall'); | ||||
|             this.expandByDefault = this.config.legend.get('expandByDefault'); | ||||
|             this.valueToShowWhenCollapsed = this.config.legend.get('valueToShowWhenCollapsed'); | ||||
|             this.showTimestampWhenExpanded = this.config.legend.get('showTimestampWhenExpanded'); | ||||
|             this.showValueWhenExpanded = this.config.legend.get('showValueWhenExpanded'); | ||||
|             this.showMinimumWhenExpanded = this.config.legend.get('showMinimumWhenExpanded'); | ||||
|             this.showMaximumWhenExpanded = this.config.legend.get('showMaximumWhenExpanded'); | ||||
|             this.showUnitsWhenExpanded = this.config.legend.get('showUnitsWhenExpanded'); | ||||
|         }, | ||||
|         getConfig() { | ||||
|             this.configId = this.openmct.objects.makeKeyString(this.domainObject.identifier); | ||||
|  | ||||
|             return configStore.get(this.configId); | ||||
|         }, | ||||
|         registerListeners() { | ||||
|             this.config.series.forEach(this.addSeries, this); | ||||
|  | ||||
|             this.listenTo(this.config.series, 'add', this.addSeries, this); | ||||
|             this.listenTo(this.config.series, 'remove', this.resetAllSeries, this); | ||||
|         }, | ||||
|  | ||||
|         addSeries(series, index) { | ||||
|             this.plotSeries[index] = series; | ||||
|         }, | ||||
|  | ||||
|         resetAllSeries() { | ||||
|             this.plotSeries = []; | ||||
|             this.config.series.forEach(this.addSeries, this); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
| </script> | ||||
							
								
								
									
										100
									
								
								src/plugins/plot/vue/inspector/PlotOptionsEdit.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/plugins/plot/vue/inspector/PlotOptionsEdit.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | ||||
| <!-- | ||||
|  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. | ||||
| --> | ||||
| <template> | ||||
| <div v-if="config && loaded" | ||||
|      class="js-plot-options-edit" | ||||
| > | ||||
|     <ul class="c-tree"> | ||||
|         <h2 title="Display properties for this object">Plot Series</h2> | ||||
|         <li v-for="series in plotSeries" | ||||
|             :key="series.key" | ||||
|         > | ||||
|             <series-form :series="series" /> | ||||
|         </li> | ||||
|     </ul> | ||||
|     <y-axis-form v-show="!!plotSeries.length" | ||||
|                  class="grid-properties" | ||||
|                  :y-axis="config.yAxis" | ||||
|     /> | ||||
|     <ul class="l-inspector-part"> | ||||
|         <h2 title="Legend options">Legend</h2> | ||||
|         <legend-form v-show="!!plotSeries.length" | ||||
|                      class="grid-properties" | ||||
|                      :legend="config.legend" | ||||
|         /> | ||||
|     </ul> | ||||
| </div> | ||||
| </template> | ||||
| <script> | ||||
| import SeriesForm from "@/plugins/plot/vue/inspector/forms/SeriesForm.vue"; | ||||
| import YAxisForm from "@/plugins/plot/vue/inspector/forms/YAxisForm.vue"; | ||||
| import LegendForm from "@/plugins/plot/vue/inspector/forms/LegendForm.vue"; | ||||
| import eventHelpers from "@/plugins/plot/vue/single/lib/eventHelpers"; | ||||
| import configStore from "@/plugins/plot/vue/single/configuration/configStore"; | ||||
|  | ||||
| export default { | ||||
|     components: { | ||||
|         LegendForm, | ||||
|         SeriesForm, | ||||
|         YAxisForm | ||||
|     }, | ||||
|     inject: ['openmct', 'domainObject'], | ||||
|     data() { | ||||
|         return { | ||||
|             config: {}, | ||||
|             plotSeries: [], | ||||
|             loaded: false | ||||
|         }; | ||||
|     }, | ||||
|     mounted() { | ||||
|         eventHelpers.extend(this); | ||||
|         this.config = this.getConfig(); | ||||
|         this.registerListeners(); | ||||
|         this.loaded = true; | ||||
|     }, | ||||
|     beforeDestroy() { | ||||
|         this.stopListening(); | ||||
|     }, | ||||
|     methods: { | ||||
|         getConfig() { | ||||
|             this.configId = this.openmct.objects.makeKeyString(this.domainObject.identifier); | ||||
|  | ||||
|             return configStore.get(this.configId); | ||||
|         }, | ||||
|         registerListeners() { | ||||
|             this.config.series.forEach(this.addSeries, this); | ||||
|  | ||||
|             this.listenTo(this.config.series, 'add', this.addSeries, this); | ||||
|             this.listenTo(this.config.series, 'remove', this.resetAllSeries, this); | ||||
|         }, | ||||
|  | ||||
|         addSeries(series, index) { | ||||
|             this.plotSeries[index] = series; | ||||
|         }, | ||||
|  | ||||
|         resetAllSeries() { | ||||
|             this.plotSeries = []; | ||||
|             this.config.series.forEach(this.addSeries, this); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
| </script> | ||||
							
								
								
									
										155
									
								
								src/plugins/plot/vue/inspector/PlotOptionsItem.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								src/plugins/plot/vue/inspector/PlotOptionsItem.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,155 @@ | ||||
| <template> | ||||
| <ul> | ||||
|     <li class="c-tree__item menus-to-left"> | ||||
|         <span class="c-disclosure-triangle is-enabled flex-elem" | ||||
|               :class="expandedCssClass" | ||||
|               @click="toggleExpanded" | ||||
|         > | ||||
|         </span> | ||||
|         <div class="c-object-label" | ||||
|              :class="statusClass" | ||||
|         > | ||||
|             <div class="c-object-label__type-icon" | ||||
|                  :class="getSeriesClass" | ||||
|             > | ||||
|                 <span class="is-status__indicator" | ||||
|                       title="This item is missing or suspect" | ||||
|                 ></span> | ||||
|             </div> | ||||
|             <div class="c-object-label__name">{{ series.domainObject.name }}</div> | ||||
|         </div> | ||||
|     </li> | ||||
|     <li v-show="expanded" | ||||
|         class="c-tree__item menus-to-left" | ||||
|     > | ||||
|         <ul class="grid-properties js-plot-options-browse-properties"> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="The field to be plotted as a value for this series." | ||||
|                 >Value</div> | ||||
|                 <div class="grid-cell value"> | ||||
|                     {{ yKey }} | ||||
|                 </div> | ||||
|             </li> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="The rendering method to join lines for this series." | ||||
|                 >Line Method</div> | ||||
|                 <div class="grid-cell value">{{ { | ||||
|                     'none': 'None', | ||||
|                     'linear': 'Linear interpolation', | ||||
|                     'stepAfter': 'Step After' | ||||
|                 }[interpolate] }} | ||||
|                 </div> | ||||
|             </li> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="Whether markers are displayed, and their size." | ||||
|                 >Markers</div> | ||||
|                 <div class="grid-cell value"> | ||||
|                     {{ markerOptionsDisplayText }} | ||||
|                 </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"> | ||||
|                     {{ alarmMarkers ? "Enabled" : "Disabled" }} | ||||
|                 </div> | ||||
|             </li> | ||||
|             <li class="grid-row"> | ||||
|                 <div class="grid-cell label" | ||||
|                      title="The plot line and marker color for this series." | ||||
|                 >Color</div> | ||||
|                 <div class="grid-cell value"> | ||||
|                     <span class="c-color-swatch" | ||||
|                           :style="{ | ||||
|                               'background': seriesHexColor | ||||
|                           }" | ||||
|                     > | ||||
|                     </span> | ||||
|                 </div> | ||||
|             </li> | ||||
|         </ul> | ||||
|     </li> | ||||
| </ul> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|     inject: ['openmct'], | ||||
|     props: { | ||||
|         series: { | ||||
|             type: Object, | ||||
|             default() { | ||||
|                 return {}; | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     data() { | ||||
|         return { | ||||
|             expanded: false | ||||
|         }; | ||||
|     }, | ||||
|     computed: { | ||||
|         getSeriesClass() { | ||||
|             let cssClass = ''; | ||||
|             let legacyObject = this.openmct.legacyObject(this.series.domainObject); | ||||
|             let location = legacyObject.getCapability('location'); | ||||
|             if (location && location.isLink()) { | ||||
|                 cssClass = 'l-icon-link'; | ||||
|             } | ||||
|  | ||||
|             let type = legacyObject.getCapability('type'); | ||||
|             if (type) { | ||||
|                 cssClass = `${cssClass} ${type.getCssClass()}`; | ||||
|             } | ||||
|  | ||||
|             return cssClass; | ||||
|         }, | ||||
|         expandedCssClass() { | ||||
|             if (this.expanded === true) { | ||||
|                 return 'c-disclosure-triangle--expanded'; | ||||
|             } | ||||
|  | ||||
|             return ''; | ||||
|         }, | ||||
|         statusClass() { | ||||
|             return (this.status) ? `is-status--${this.status}` : ''; | ||||
|         }, | ||||
|         yKey() { | ||||
|             return this.series.get('yKey'); | ||||
|         }, | ||||
|         interpolate() { | ||||
|             return this.series.get('interpolate'); | ||||
|         }, | ||||
|         markerOptionsDisplayText() { | ||||
|             return this.series.markerOptionsDisplayText(); | ||||
|         }, | ||||
|         alarmMarkers() { | ||||
|             return this.series.get('alarmMarkers'); | ||||
|         }, | ||||
|         seriesHexColor() { | ||||
|             return this.series.get('color').asHexString(); | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.status = this.openmct.status.get(this.series.domainObject.identifier); | ||||
|         this.removeStatusListener = this.openmct.status.observe(this.series.domainObject.identifier, this.setStatus); | ||||
|     }, | ||||
|     beforeDestroy() { | ||||
|         if (this.removeStatusListener) { | ||||
|             this.removeStatusListener(); | ||||
|         } | ||||
|     }, | ||||
|     methods: { | ||||
|         toggleExpanded() { | ||||
|             this.expanded = !this.expanded; | ||||
|         }, | ||||
|         setStatus(status) { | ||||
|             this.status = status; | ||||
|         } | ||||
|     } | ||||
| }; | ||||
| </script> | ||||
							
								
								
									
										51
									
								
								src/plugins/plot/vue/inspector/PlotsInspectorViewProvider.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/plugins/plot/vue/inspector/PlotsInspectorViewProvider.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
|  | ||||
| import PlotOptions from "./PlotOptions.vue"; | ||||
| import Vue from 'vue'; | ||||
|  | ||||
| export default function PlotsInspectorViewProvider(openmct) { | ||||
|     return { | ||||
|         key: 'plots-inspector', | ||||
|         name: 'Plots Inspector View', | ||||
|         canView: function (selection) { | ||||
|             if (selection.length === 0 || selection[0].length === 0) { | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             let parent = selection[0].length > 1 && selection[0][1].context.item; | ||||
|             let object = selection[0][0].context.item; | ||||
|  | ||||
|             return parent | ||||
|                 && parent.type === 'time-strip' | ||||
|                 && object | ||||
|                 && object.type === 'telemetry.plot.overlay'; | ||||
|         }, | ||||
|         view: function (selection) { | ||||
|             let component; | ||||
|  | ||||
|             return { | ||||
|                 show: function (element) { | ||||
|                     component = new Vue({ | ||||
|                         el: element, | ||||
|                         components: { | ||||
|                             PlotOptions: PlotOptions | ||||
|                         }, | ||||
|                         provide: { | ||||
|                             openmct, | ||||
|                             domainObject: openmct.selection.get()[0][0].context.item | ||||
|                         }, | ||||
|                         template: '<plot-options></plot-options>' | ||||
|                     }); | ||||
|                 }, | ||||
|                 destroy: function () { | ||||
|                     if (component) { | ||||
|                         component.$destroy(); | ||||
|                         component = undefined; | ||||
|                     } | ||||
|                 } | ||||
|             }; | ||||
|         }, | ||||
|         priority: function () { | ||||
|             return 1; | ||||
|         } | ||||
|     }; | ||||
| } | ||||
							
								
								
									
										207
									
								
								src/plugins/plot/vue/inspector/forms/LegendForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								src/plugins/plot/vue/inspector/forms/LegendForm.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,207 @@ | ||||
| <template> | ||||
| <div> | ||||
|     <li class="grid-row"> | ||||
|         <div class="grid-cell label" | ||||
|              title="The position of the legend relative to the plot display area." | ||||
|         >Position</div> | ||||
|         <div class="grid-cell value"> | ||||
|             <select v-model="position" | ||||
|                     @change="updateForm('position')" | ||||
|             > | ||||
|                 <option value="top">Top</option> | ||||
|                 <option value="right">Right</option> | ||||
|                 <option value="bottom">Bottom</option> | ||||
|                 <option value="left">Left</option> | ||||
|             </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 v-model="hideLegendWhenSmall" | ||||
|                                             type="checkbox" | ||||
|                                             @change="updateForm('hideLegendWhenSmall')" | ||||
|         ></div> | ||||
|     </li> | ||||
|     <li class="grid-row"> | ||||
|         <div class="grid-cell label" | ||||
|              title="Show the legend expanded by default" | ||||
|         >Expand by default</div> | ||||
|         <div class="grid-cell value"><input v-model="expandByDefault" | ||||
|                                             type="checkbox" | ||||
|                                             @change="updateForm('expandByDefault')" | ||||
|         ></div> | ||||
|     </li> | ||||
|     <li class="grid-row"> | ||||
|         <div class="grid-cell label" | ||||
|              title="What to display in the legend when it's collapsed." | ||||
|         >When collapsed show</div> | ||||
|         <div class="grid-cell value"> | ||||
|             <select v-model="valueToShowWhenCollapsed" | ||||
|                     @change="updateForm('valueToShowWhenCollapsed')" | ||||
|             > | ||||
|                 <option value="none">Nothing</option> | ||||
|                 <option value="nearestTimestamp">Nearest timestamp</option> | ||||
|                 <option value="nearestValue">Nearest value</option> | ||||
|                 <option value="min">Minimum value</option> | ||||
|                 <option value="max">Maximum value</option> | ||||
|                 <option value="units">Units</option> | ||||
|             </select> | ||||
|         </div> | ||||
|     </li> | ||||
|     <li class="grid-row"> | ||||
|         <div class="grid-cell label" | ||||
|              title="What to display in the legend when it's expanded." | ||||
|         >When expanded show</div> | ||||
|         <div class="grid-cell value"> | ||||
|             <ul> | ||||
|                 <li><input v-model="showTimestampWhenExpanded" | ||||
|                            type="checkbox" | ||||
|                            @change="updateForm('showTimestampWhenExpanded')" | ||||
|                 > Nearest timestamp</li> | ||||
|                 <li><input v-model="showValueWhenExpanded" | ||||
|                            type="checkbox" | ||||
|                            @change="updateForm('showValueWhenExpanded')" | ||||
|                 > Nearest value</li> | ||||
|                 <li><input v-model="showMinimumWhenExpanded" | ||||
|                            type="checkbox" | ||||
|                            @change="updateForm('showMinimumWhenExpanded')" | ||||
|                 > Minimum value</li> | ||||
|                 <li><input v-model="showMaximumWhenExpanded" | ||||
|                            type="checkbox" | ||||
|                            @change="updateForm('showMaximumWhenExpanded')" | ||||
|                 > Maximum value</li> | ||||
|                 <li><input v-model="showUnitsWhenExpanded" | ||||
|                            type="checkbox" | ||||
|                            @change="updateForm('showUnitsWhenExpanded')" | ||||
|                 > Units</li> | ||||
|             </ul> | ||||
|  | ||||
|         </div> | ||||
|     </li> | ||||
| </div> | ||||
| </template> | ||||
| <script> | ||||
| import {coerce, objectPath, validate} from "@/plugins/plot/vue/inspector/forms/formUtil"; | ||||
| import _ from "lodash"; | ||||
|  | ||||
| export default { | ||||
|     inject: ['openmct', 'domainObject'], | ||||
|     props: { | ||||
|         legend: { | ||||
|             type: Object, | ||||
|             default() { | ||||
|                 return {}; | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     data() { | ||||
|         return { | ||||
|             position: '', | ||||
|             hideLegendWhenSmall: '', | ||||
|             expandByDefault: '', | ||||
|             valueToShowWhenCollapsed: '', | ||||
|             showTimestampWhenExpanded: '', | ||||
|             showValueWhenExpanded: '', | ||||
|             showMinimumWhenExpanded: '', | ||||
|             showMaximumWhenExpanded: '', | ||||
|             showUnitsWhenExpanded: '', | ||||
|             validation: {} | ||||
|         }; | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.initialize(); | ||||
|         this.initFormValues(); | ||||
|     }, | ||||
|     methods: { | ||||
|         initialize() { | ||||
|             this.fields = [ | ||||
|                 { | ||||
|                     modelProp: 'position', | ||||
|                     objectPath: 'configuration.legend.position' | ||||
|                 }, | ||||
|                 { | ||||
|                     modelProp: 'hideLegendWhenSmall', | ||||
|                     coerce: Boolean, | ||||
|                     objectPath: 'configuration.legend.hideLegendWhenSmall' | ||||
|                 }, | ||||
|                 { | ||||
|                     modelProp: 'expandByDefault', | ||||
|                     coerce: Boolean, | ||||
|                     objectPath: 'configuration.legend.expandByDefault' | ||||
|                 }, | ||||
|                 { | ||||
|                     modelProp: 'valueToShowWhenCollapsed', | ||||
|                     objectPath: 'configuration.legend.valueToShowWhenCollapsed' | ||||
|                 }, | ||||
|                 { | ||||
|                     modelProp: 'showValueWhenExpanded', | ||||
|                     coerce: Boolean, | ||||
|                     objectPath: 'configuration.legend.showValueWhenExpanded' | ||||
|                 }, | ||||
|                 { | ||||
|                     modelProp: 'showTimestampWhenExpanded', | ||||
|                     coerce: Boolean, | ||||
|                     objectPath: 'configuration.legend.showTimestampWhenExpanded' | ||||
|                 }, | ||||
|                 { | ||||
|                     modelProp: 'showMaximumWhenExpanded', | ||||
|                     coerce: Boolean, | ||||
|                     objectPath: 'configuration.legend.showMaximumWhenExpanded' | ||||
|                 }, | ||||
|                 { | ||||
|                     modelProp: 'showMinimumWhenExpanded', | ||||
|                     coerce: Boolean, | ||||
|                     objectPath: 'configuration.legend.showMinimumWhenExpanded' | ||||
|                 }, | ||||
|                 { | ||||
|                     modelProp: 'showUnitsWhenExpanded', | ||||
|                     coerce: Boolean, | ||||
|                     objectPath: 'configuration.legend.showUnitsWhenExpanded' | ||||
|                 } | ||||
|             ]; | ||||
|         }, | ||||
|         initFormValues() { | ||||
|             this.position = this.legend.get('position'); | ||||
|             this.hideLegendWhenSmall = this.legend.get('hideLegendWhenSmall'); | ||||
|             this.expandByDefault = this.legend.get('expandByDefault'); | ||||
|             this.valueToShowWhenCollapsed = this.legend.get('valueToShowWhenCollapsed'); | ||||
|             this.showTimestampWhenExpanded = this.legend.get('showTimestampWhenExpanded'); | ||||
|             this.showValueWhenExpanded = this.legend.get('showValueWhenExpanded'); | ||||
|             this.showMinimumWhenExpanded = this.legend.get('showMinimumWhenExpanded'); | ||||
|             this.showMaximumWhenExpanded = this.legend.get('showMaximumWhenExpanded'); | ||||
|             this.showUnitsWhenExpanded = this.legend.get('showUnitsWhenExpanded'); | ||||
|         }, | ||||
|         updateForm(formKey) { | ||||
|             const newVal = this[formKey]; | ||||
|             const oldVal = this.legend.get(formKey); | ||||
|             const formField = this.fields.find((field) => field.modelProp === formKey); | ||||
|  | ||||
|             const path = objectPath(formField.objectPath); | ||||
|             const validationResult = validate(newVal, this.legend, formField.validate); | ||||
|             if (validationResult === true) { | ||||
|                 delete this.validation[formKey]; | ||||
|             } else { | ||||
|                 this.validation[formKey] = validationResult; | ||||
|  | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             if (!_.isEqual(coerce(newVal, formField.coerce), coerce(oldVal, formField.coerce))) { | ||||
|                 this.legend.set(formKey, coerce(newVal, formField.coerce)); | ||||
|                 if (path) { | ||||
|                     this.openmct.objects.mutate( | ||||
|                         this.domainObject, | ||||
|                         path(this.domainObject, this.legend), | ||||
|                         coerce(newVal, formField.coerce) | ||||
|                     ); | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         setStatus(status) { | ||||
|             this.status = status; | ||||
|         } | ||||
|     } | ||||
| }; | ||||
| </script> | ||||
							
								
								
									
										347
									
								
								src/plugins/plot/vue/inspector/forms/SeriesForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										347
									
								
								src/plugins/plot/vue/inspector/forms/SeriesForm.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,347 @@ | ||||
| <template> | ||||
| <ul> | ||||
|     <li class="c-tree__item menus-to-left"> | ||||
|         <span class="c-disclosure-triangle is-enabled flex-elem" | ||||
|               :class="expandedCssClass" | ||||
|               @click="toggleExpanded" | ||||
|         > | ||||
|         </span> | ||||
|         <div :class="objectLabelCss"> | ||||
|             <div class="c-object-label__type-icon" | ||||
|                  :class="[seriesCss, linkCss]" | ||||
|             > | ||||
|                 <span class="is-status__indicator" | ||||
|                       title="This item is missing or suspect" | ||||
|                 ></span> | ||||
|             </div> | ||||
|             <div class="c-object-label__name">{{ series.domainObject.name }}</div> | ||||
|         </div> | ||||
|     </li> | ||||
|     <ul v-show="expanded" | ||||
|         class="grid-properties js-plot-options-edit-properties" | ||||
|     > | ||||
|         <li class="grid-row"> | ||||
|             <!-- Value to be displayed --> | ||||
|             <div class="grid-cell label" | ||||
|                  title="The field to be plotted as a value for this series." | ||||
|             >Value</div> | ||||
|             <div class="grid-cell value"> | ||||
|                 <select v-model="yKey" | ||||
|                         @change="updateForm('yKey')" | ||||
|                 > | ||||
|                     <option v-for="option in yKeyOptions" | ||||
|                             :key="option.value" | ||||
|                             :value="option.value" | ||||
|                             :selected="option.value == yKey" | ||||
|                     > | ||||
|                         {{ option.name }} | ||||
|                     </option> | ||||
|                 </select> | ||||
|             </div> | ||||
|         </li> | ||||
|         <li class="grid-row"> | ||||
|             <div class="grid-cell label" | ||||
|                  title="The rendering method to join lines for this series." | ||||
|             >Line Method</div> | ||||
|             <div class="grid-cell value"> | ||||
|                 <select v-model="interpolate" | ||||
|                         @change="updateForm('interpolate')" | ||||
|                 > | ||||
|                     <option value="none">None</option> | ||||
|                     <option value="linear">Linear interpolate</option> | ||||
|                     <option value="stepAfter">Step after</option> | ||||
|                 </select> | ||||
|             </div> | ||||
|         </li> | ||||
|         <li class="grid-row"> | ||||
|             <div class="grid-cell label" | ||||
|                  title="Whether markers are displayed." | ||||
|             >Markers</div> | ||||
|             <div class="grid-cell value"> | ||||
|                 <input v-model="markers" | ||||
|                        type="checkbox" | ||||
|                        @change="updateForm('markers')" | ||||
|                 > | ||||
|                 <select | ||||
|                     v-show="markers" | ||||
|                     v-model="markerShape" | ||||
|                     @change="updateForm('markerShape')" | ||||
|                 > | ||||
|                     <option | ||||
|                         v-for="option in markerShapeOptions" | ||||
|                         :key="option.value" | ||||
|                         :value="option.value" | ||||
|                         :selected="option.value == markerShape" | ||||
|                     > | ||||
|                         {{ option.name }} | ||||
|                     </option> | ||||
|                 </select> | ||||
|             </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 v-model="alarmMarkers" | ||||
|                        type="checkbox" | ||||
|                        @change="updateForm('alarmMarkers')" | ||||
|                 > | ||||
|             </div> | ||||
|         </li> | ||||
|         <li v-show="markers || alarmMarkers" | ||||
|             class="grid-row" | ||||
|         > | ||||
|             <div class="grid-cell label" | ||||
|                  title="The size of regular and alarm markers for this series." | ||||
|             >Marker Size:</div> | ||||
|             <div class="grid-cell value"><input v-model="markerSize" | ||||
|                                                 class="c-input--flex" | ||||
|                                                 type="text" | ||||
|                                                 @change="updateForm('markerSize')" | ||||
|             ></div> | ||||
|         </li> | ||||
|         <li v-show="interpolate !== 'none' || markers" | ||||
|             class="grid-row" | ||||
|         > | ||||
|             <div class="grid-cell label" | ||||
|                  title="Manually set the plot line and marker color for this series." | ||||
|             >Color</div> | ||||
|             <div class="grid-cell value"> | ||||
|                 <div class="c-click-swatch c-click-swatch--menu" | ||||
|                      @click="toggleSwatch()" | ||||
|                 > | ||||
|                     <span class="c-color-swatch" | ||||
|                           :style="{ background: seriesColorAsHex }" | ||||
|                     > | ||||
|                     </span> | ||||
|                 </div> | ||||
|                 <div class="c-palette c-palette--color"> | ||||
|                     <div v-show="swatchActive" | ||||
|                          class="c-palette__items" | ||||
|                     > | ||||
|                         <div v-for="(group, index) in colorPalette" | ||||
|                              :key="index" | ||||
|                              class="u-contents" | ||||
|                         > | ||||
|                             <div v-for="(color, colorIndex) in group" | ||||
|                                  :key="colorIndex" | ||||
|                                  class="c-palette__item" | ||||
|                                  :class="{ 'selected': series.get('color').equalTo(color) }" | ||||
|                                  :style="{ background: color.asHexString() }" | ||||
|                                  @click="setColor(color)" | ||||
|                             > | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </li> | ||||
|     </ul> | ||||
| </ul> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { MARKER_SHAPES } from "../../single/draw/MarkerShapes"; | ||||
| import { objectPath, validate, coerce } from "./formUtil"; | ||||
| import _ from 'lodash'; | ||||
|  | ||||
| export default { | ||||
|     inject: ['openmct', 'domainObject'], | ||||
|     props: { | ||||
|         series: { | ||||
|             type: Object, | ||||
|             default() { | ||||
|                 return {}; | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     data() { | ||||
|         return { | ||||
|             expanded: false, | ||||
|             markerShapeOptions: [], | ||||
|             yKey: this.series.get('yKey'), | ||||
|             yKeyOptions: [], | ||||
|             interpolate: this.series.get('interpolate'), | ||||
|             markers: this.series.get('markers'), | ||||
|             markerShape: this.series.get('markerShape'), | ||||
|             alarmMarkers: this.series.get('alarmMarkers'), | ||||
|             markerSize: this.series.get('markerSize'), | ||||
|             validation: {}, | ||||
|             swatchActive: false | ||||
|         }; | ||||
|     }, | ||||
|     computed: { | ||||
|         colorPalette() { | ||||
|             return this.series.collection.palette.groups(); | ||||
|         }, | ||||
|         objectLabelCss() { | ||||
|             return this.status ? `c-object-label is-status--${this.status}'` : 'c-object-label'; | ||||
|         }, | ||||
|         seriesCss() { | ||||
|             let legacyObject = this.openmct.legacyObject(this.series.domainObject); | ||||
|             let type = legacyObject.getCapability('type'); | ||||
|  | ||||
|             return type ? `c-object-label__type-icon ${type.getCssClass()}` : `c-object-label__type-icon`; | ||||
|         }, | ||||
|         linkCss() { | ||||
|             let cssClass = ''; | ||||
|             let legacyObject = this.openmct.legacyObject(this.series.domainObject); | ||||
|             let location = legacyObject.getCapability('location'); | ||||
|             if (location && location.isLink()) { | ||||
|                 cssClass = 'l-icon-link'; | ||||
|             } | ||||
|  | ||||
|             return cssClass; | ||||
|         }, | ||||
|         expandedCssClass() { | ||||
|             return this.expanded ? 'c-disclosure-triangle--expanded' : ''; | ||||
|         }, | ||||
|         seriesColorAsHex() { | ||||
|             return this.series.get('color').asHexString(); | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.initialize(); | ||||
|  | ||||
|         this.status = this.openmct.status.get(this.series.domainObject.identifier); | ||||
|         this.removeStatusListener = this.openmct.status.observe(this.series.domainObject.identifier, this.setStatus); | ||||
|     }, | ||||
|     beforeDestroy() { | ||||
|         if (this.removeStatusListener) { | ||||
|             this.removeStatusListener(); | ||||
|         } | ||||
|     }, | ||||
|     methods: { | ||||
|         initialize: function () { | ||||
|             this.fields = [ | ||||
|                 { | ||||
|                     modelProp: 'yKey', | ||||
|                     objectPath: this.dynamicPathForKey('yKey') | ||||
|                 }, | ||||
|                 { | ||||
|                     modelProp: 'interpolate', | ||||
|                     objectPath: this.dynamicPathForKey('interpolate') | ||||
|                 }, | ||||
|                 { | ||||
|                     modelProp: 'markers', | ||||
|                     objectPath: this.dynamicPathForKey('markers') | ||||
|                 }, | ||||
|                 { | ||||
|                     modelProp: 'markerShape', | ||||
|                     objectPath: this.dynamicPathForKey('markerShape') | ||||
|                 }, | ||||
|                 { | ||||
|                     modelProp: 'markerSize', | ||||
|                     coerce: Number, | ||||
|                     objectPath: this.dynamicPathForKey('markerSize') | ||||
|                 }, | ||||
|                 { | ||||
|                     modelProp: 'alarmMarkers', | ||||
|                     coerce: Boolean, | ||||
|                     objectPath: this.dynamicPathForKey('alarmMarkers') | ||||
|                 } | ||||
|             ]; | ||||
|  | ||||
|             const metadata = this.series.metadata; | ||||
|             this.yKeyOptions = metadata | ||||
|                 .valuesForHints(['range']) | ||||
|                 .map(function (o) { | ||||
|                     return { | ||||
|                         name: o.key, | ||||
|                         value: o.key | ||||
|                     }; | ||||
|                 }); | ||||
|             this.markerShapeOptions = Object.entries(MARKER_SHAPES) | ||||
|                 .map(([key, obj]) => { | ||||
|                     return { | ||||
|                         name: obj.label, | ||||
|                         value: key | ||||
|                     }; | ||||
|                 }); | ||||
|         }, | ||||
|         dynamicPathForKey(key) { | ||||
|             return function (object, model) { | ||||
|                 const modelIdentifier = model.get('identifier'); | ||||
|                 const index = object.configuration.series.findIndex(s => { | ||||
|                     return _.isEqual(s.identifier, modelIdentifier); | ||||
|                 }); | ||||
|  | ||||
|                 return 'configuration.series[' + index + '].' + key; | ||||
|             }; | ||||
|         }, | ||||
|         /** | ||||
|        * Set the color for the current plot series.  If the new color was | ||||
|        * already assigned to a different plot series, then swap the colors. | ||||
|        */ | ||||
|         setColor: function (color) { | ||||
|             const oldColor = this.series.get('color'); | ||||
|             const otherSeriesWithColor = this.series.collection.filter(function (s) { | ||||
|                 return s.get('color') === color; | ||||
|             })[0]; | ||||
|  | ||||
|             this.series.set('color', color); | ||||
|  | ||||
|             const getPath = this.dynamicPathForKey('color'); | ||||
|             const seriesColorPath = getPath(this.domainObject, this.series); | ||||
|  | ||||
|             this.openmct.objects.mutate( | ||||
|                 this.domainObject, | ||||
|                 seriesColorPath, | ||||
|                 color.asHexString() | ||||
|             ); | ||||
|  | ||||
|             if (otherSeriesWithColor) { | ||||
|                 otherSeriesWithColor.set('color', oldColor); | ||||
|  | ||||
|                 const otherSeriesColorPath = getPath( | ||||
|                     this.domainObject, | ||||
|                     otherSeriesWithColor | ||||
|                 ); | ||||
|  | ||||
|                 this.openmct.objects.mutate( | ||||
|                     this.domainObject, | ||||
|                     otherSeriesColorPath, | ||||
|                     oldColor.asHexString() | ||||
|                 ); | ||||
|             } | ||||
|         }, | ||||
|         toggleExpanded() { | ||||
|             this.expanded = !this.expanded; | ||||
|         }, | ||||
|         updateForm(formKey) { | ||||
|             const newVal = this[formKey]; | ||||
|             const oldVal = this.series.get(formKey); | ||||
|             const formField = this.fields.find((field) => field.modelProp === formKey); | ||||
|  | ||||
|             const path = objectPath(formField.objectPath); | ||||
|             const validationResult = validate(newVal, this.series, formField.validate); | ||||
|             if (validationResult === true) { | ||||
|                 delete this.validation[formKey]; | ||||
|             } else { | ||||
|                 this.validation[formKey] = validationResult; | ||||
|  | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             if (!_.isEqual(coerce(newVal, formField.coerce), coerce(oldVal, formField.coerce))) { | ||||
|                 this.series.set(formKey, coerce(newVal, formField.coerce)); | ||||
|                 if (path) { | ||||
|                     this.openmct.objects.mutate( | ||||
|                         this.domainObject, | ||||
|                         path(this.domainObject, this.series), | ||||
|                         coerce(newVal, formField.coerce) | ||||
|                     ); | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         setStatus(status) { | ||||
|             this.status = status; | ||||
|         }, | ||||
|         toggleSwatch() { | ||||
|             this.swatchActive = !this.swatchActive; | ||||
|         } | ||||
|     } | ||||
| }; | ||||
|  | ||||
| </script> | ||||
							
								
								
									
										226
									
								
								src/plugins/plot/vue/inspector/forms/YAxisForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								src/plugins/plot/vue/inspector/forms/YAxisForm.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,226 @@ | ||||
| <template> | ||||
| <div> | ||||
|     <ul class="l-inspector-part"> | ||||
|         <h2>Y Axis</h2> | ||||
|         <li class="grid-row"> | ||||
|             <div class="grid-cell label" | ||||
|                  title="Manually override how the Y axis is labeled." | ||||
|             >Label</div> | ||||
|             <div class="grid-cell value"><input v-model="label" | ||||
|                                                 class="c-input--flex" | ||||
|                                                 type="text" | ||||
|                                                 @change="updateForm('label')" | ||||
|             ></div> | ||||
|         </li> | ||||
|     </ul> | ||||
|     <ul class="l-inspector-part"> | ||||
|         <h2>Y Axis Scaling</h2> | ||||
|         <li class="grid-row"> | ||||
|             <div class="grid-cell label" | ||||
|                  title="Automatically scale the Y axis to keep all values in view." | ||||
|             >Auto scale</div> | ||||
|             <div class="grid-cell value"><input v-model="autoscale" | ||||
|                                                 type="checkbox" | ||||
|                                                 @change="updateForm('autoscale')" | ||||
|             ></div> | ||||
|         </li> | ||||
|         <li v-show="autoscale" | ||||
|             class="grid-row" | ||||
|         > | ||||
|             <div class="grid-cell label" | ||||
|                  title="Percentage of padding above and below plotted min and max values. 0.1, 1.0, etc." | ||||
|             > | ||||
|                 Padding</div> | ||||
|             <div class="grid-cell value"> | ||||
|                 <input v-model="autoscalePadding" | ||||
|                        class="c-input--flex" | ||||
|                        type="text" | ||||
|                        @change="updateForm('autoscalePadding')" | ||||
|                 > | ||||
|             </div> | ||||
|         </li> | ||||
|     </ul> | ||||
|     <ul v-show="!autoscale" | ||||
|         class="l-inspector-part" | ||||
|     > | ||||
|         <div v-show="!autoscale && validation.range" | ||||
|              class="grid-span-all form-error" | ||||
|         > | ||||
|             {{ validation.range }} | ||||
|         </div> | ||||
|         <li class="grid-row force-border"> | ||||
|             <div class="grid-cell label" | ||||
|                  title="Minimum Y axis value." | ||||
|             >Minimum Value</div> | ||||
|             <div class="grid-cell value"> | ||||
|                 <input v-model="rangeMin" | ||||
|                        class="c-input--flex" | ||||
|                        type="number" | ||||
|                        @change="updateForm('range')" | ||||
|                 > | ||||
|             </div> | ||||
|         </li> | ||||
|         <li class="grid-row"> | ||||
|             <div class="grid-cell label" | ||||
|                  title="Maximum Y axis value." | ||||
|             >Maximum Value</div> | ||||
|             <div class="grid-cell value"><input v-model="rangeMax" | ||||
|                                                 class="c-input--flex" | ||||
|                                                 type="number" | ||||
|                                                 @change="updateForm('range')" | ||||
|             ></div> | ||||
|         </li> | ||||
|     </ul> | ||||
| </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { objectPath, validate, coerce } from "./formUtil"; | ||||
| import _ from "lodash"; | ||||
|  | ||||
| export default { | ||||
|     inject: ['openmct', 'domainObject'], | ||||
|     props: { | ||||
|         yAxis: { | ||||
|             type: Object, | ||||
|             default() { | ||||
|                 return {}; | ||||
|             } | ||||
|         } | ||||
|     }, | ||||
|     data() { | ||||
|         return { | ||||
|             label: '', | ||||
|             autoscale: '', | ||||
|             autoscalePadding: '', | ||||
|             rangeMin: '', | ||||
|             rangeMax: '', | ||||
|             validation: {} | ||||
|         }; | ||||
|     }, | ||||
|     mounted() { | ||||
|         this.initialize(); | ||||
|         this.initFormValues(); | ||||
|     }, | ||||
|     methods: { | ||||
|         initialize: function () { | ||||
|             this.fields = [ | ||||
|                 { | ||||
|                     modelProp: 'label', | ||||
|                     objectPath: 'configuration.yAxis.label' | ||||
|                 }, | ||||
|                 { | ||||
|                     modelProp: 'autoscale', | ||||
|                     coerce: Boolean, | ||||
|                     objectPath: 'configuration.yAxis.autoscale' | ||||
|                 }, | ||||
|                 { | ||||
|                     modelProp: 'autoscalePadding', | ||||
|                     coerce: Number, | ||||
|                     objectPath: 'configuration.yAxis.autoscalePadding' | ||||
|                 }, | ||||
|                 { | ||||
|                     modelProp: 'range', | ||||
|                     objectPath: 'configuration.yAxis.range', | ||||
|                     coerce: function coerceRange(range) { | ||||
|                         if (!range) { | ||||
|                             return { | ||||
|                                 min: 0, | ||||
|                                 max: 0 | ||||
|                             }; | ||||
|                         } | ||||
|  | ||||
|                         const newRange = {}; | ||||
|                         if (typeof range.min !== 'undefined' && range.min !== null) { | ||||
|                             newRange.min = Number(range.min); | ||||
|                         } | ||||
|  | ||||
|                         if (typeof range.max !== 'undefined' && range.max !== null) { | ||||
|                             newRange.max = Number(range.max); | ||||
|                         } | ||||
|  | ||||
|                         return newRange; | ||||
|                     }, | ||||
|                     validate: function validateRange(range, model) { | ||||
|                         if (!range) { | ||||
|                             return 'Need range'; | ||||
|                         } | ||||
|  | ||||
|                         if (range.min === '' || range.min === null || typeof range.min === 'undefined') { | ||||
|                             return 'Must specify Minimum'; | ||||
|                         } | ||||
|  | ||||
|                         if (range.max === '' || range.max === null || typeof range.max === 'undefined') { | ||||
|                             return 'Must specify Maximum'; | ||||
|                         } | ||||
|  | ||||
|                         if (Number.isNaN(Number(range.min))) { | ||||
|                             return 'Minimum must be a number.'; | ||||
|                         } | ||||
|  | ||||
|                         if (Number.isNaN(Number(range.max))) { | ||||
|                             return 'Maximum must be a number.'; | ||||
|                         } | ||||
|  | ||||
|                         if (Number(range.min) > Number(range.max)) { | ||||
|                             return 'Minimum must be less than Maximum.'; | ||||
|                         } | ||||
|  | ||||
|                         if (model.get('autoscale')) { | ||||
|                             return false; | ||||
|                         } | ||||
|  | ||||
|                         return true; | ||||
|                     } | ||||
|                 } | ||||
|             ]; | ||||
|         }, | ||||
|         initFormValues() { | ||||
|             this.label = this.yAxis.get('label'); | ||||
|             this.autoscale = this.yAxis.get('autoscale'); | ||||
|             this.autoscalePadding = this.yAxis.get('autoscalePadding'); | ||||
|             const range = this.yAxis.get('range'); | ||||
|             if (range) { | ||||
|                 this.rangeMin = range.min; | ||||
|                 this.rangeMax = range.max; | ||||
|             } | ||||
|         }, | ||||
|         updateForm(formKey) { | ||||
|             let newVal; | ||||
|             if (formKey === 'range') { | ||||
|                 newVal = { | ||||
|                     min: this.rangeMin, | ||||
|                     max: this.rangeMax | ||||
|                 }; | ||||
|             } else { | ||||
|                 newVal = this[formKey]; | ||||
|             } | ||||
|  | ||||
|             const oldVal = this.yAxis.get(formKey); | ||||
|             const formField = this.fields.find((field) => field.modelProp === formKey); | ||||
|  | ||||
|             const path = objectPath(formField.objectPath); | ||||
|             const validationResult = validate(newVal, this.yAxis, formField.validate); | ||||
|             if (validationResult === true) { | ||||
|                 delete this.validation[formKey]; | ||||
|             } else { | ||||
|                 this.validation[formKey] = validationResult; | ||||
|  | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             if (!_.isEqual(coerce(newVal, formField.coerce), coerce(oldVal, formField.coerce))) { | ||||
|                 this.yAxis.set(formKey, coerce(newVal, formField.coerce)); | ||||
|                 if (path) { | ||||
|                     this.openmct.objects.mutate( | ||||
|                         this.domainObject, | ||||
|                         path(this.domainObject, this.yAxis), | ||||
|                         coerce(newVal, formField.coerce) | ||||
|                     ); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| }; | ||||
|  | ||||
| </script> | ||||
							
								
								
									
										29
									
								
								src/plugins/plot/vue/inspector/forms/formUtil.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/plugins/plot/vue/inspector/forms/formUtil.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| export function coerce(value, coerceFunc) { | ||||
|     if (coerceFunc) { | ||||
|         return coerceFunc(value); | ||||
|     } | ||||
|  | ||||
|     return value; | ||||
| } | ||||
|  | ||||
| export function validate(value, model, validateFunc) { | ||||
|     if (validateFunc) { | ||||
|         return validateFunc(value, model); | ||||
|     } | ||||
|  | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| export function objectPath(path) { | ||||
|     if (path) { | ||||
|         if (typeof path !== "function") { | ||||
|             const staticObjectPath = path; | ||||
|  | ||||
|             return function (object, model) { | ||||
|                 return staticObjectPath; | ||||
|             }; | ||||
|         } | ||||
|  | ||||
|         return path; | ||||
|     } | ||||
| } | ||||
| @@ -23,12 +23,14 @@ | ||||
| import PlotViewProvider from './PlotViewProvider'; | ||||
| import OverlayPlotViewProvider from '../overlayPlot/OverlayPlotViewProvider'; | ||||
| import StackedPlotViewProvider from '../stackedPlot/StackedPlotViewProvider'; | ||||
| import PlotsInspectorViewProvider from '../inspector/PlotsInspectorViewProvider'; | ||||
|  | ||||
| export default function () { | ||||
|     return function install(openmct) { | ||||
|         openmct.objectViews.addProvider(new StackedPlotViewProvider(openmct)); | ||||
|         openmct.objectViews.addProvider(new OverlayPlotViewProvider(openmct)); | ||||
|         openmct.objectViews.addProvider(new PlotViewProvider(openmct)); | ||||
|         openmct.inspectorViews.addProvider(new PlotsInspectorViewProvider(openmct)); | ||||
|     }; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -26,6 +26,8 @@ import Vue from "vue"; | ||||
| import StackedPlot from "../stackedPlot/StackedPlot.vue"; | ||||
| import configStore from "@/plugins/plot/vue/single/configuration/configStore"; | ||||
| import EventEmitter from "EventEmitter"; | ||||
| import PlotOptions from "../inspector/PlotOptions.vue"; | ||||
| import PlotConfigurationModel from "@/plugins/plot/vue/single/configuration/PlotConfigurationModel"; | ||||
|  | ||||
| describe("the plugin", function () { | ||||
|     let element; | ||||
| @@ -174,6 +176,35 @@ describe("the plugin", function () { | ||||
|             expect(plotView).toBeDefined(); | ||||
|         }); | ||||
|  | ||||
|         it('provides an inspector view for overlay plots', () => { | ||||
|             let selection = [ | ||||
|                 [ | ||||
|                     { | ||||
|                         context: { | ||||
|                             item: { | ||||
|                                 id: "test-object", | ||||
|                                 type: "telemetry.plot.overlay", | ||||
|                                 telemetry: { | ||||
|                                     values: [{ | ||||
|                                         key: "some-key" | ||||
|                                     }] | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
|                         context: { | ||||
|                             item: { | ||||
|                                 type: 'time-strip' | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 ] | ||||
|             ]; | ||||
|             const plotInspectorView = openmct.inspectorViews.get(selection); | ||||
|             expect(plotInspectorView.length).toEqual(1); | ||||
|         }); | ||||
|  | ||||
|         it("provides a stacked plot view for objects with telemetry", () => { | ||||
|             const testTelemetryObject = { | ||||
|                 id: "test-object", | ||||
| @@ -578,4 +609,218 @@ describe("the plugin", function () { | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('the inspector view', () => { | ||||
|         let component; | ||||
|         let viewComponentObject; | ||||
|         let mockComposition; | ||||
|         let testTelemetryObject; | ||||
|         let selection; | ||||
|         let config; | ||||
|         beforeEach((done) => { | ||||
|             testTelemetryObject = { | ||||
|                 identifier: { | ||||
|                     namespace: "", | ||||
|                     key: "test-object" | ||||
|                 }, | ||||
|                 type: "test-object", | ||||
|                 name: "Test Object", | ||||
|                 telemetry: { | ||||
|                     values: [{ | ||||
|                         key: "utc", | ||||
|                         format: "utc", | ||||
|                         name: "Time", | ||||
|                         hints: { | ||||
|                             domain: 1 | ||||
|                         } | ||||
|                     }, { | ||||
|                         key: "some-key", | ||||
|                         name: "Some attribute", | ||||
|                         hints: { | ||||
|                             range: 1 | ||||
|                         } | ||||
|                     }, { | ||||
|                         key: "some-other-key", | ||||
|                         name: "Another attribute", | ||||
|                         hints: { | ||||
|                             range: 2 | ||||
|                         } | ||||
|                     }] | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             selection = [ | ||||
|                 [ | ||||
|                     { | ||||
|                         context: { | ||||
|                             item: { | ||||
|                                 id: "test-object", | ||||
|                                 identifier: { | ||||
|                                     key: "test-object", | ||||
|                                     namespace: '' | ||||
|                                 }, | ||||
|                                 type: "telemetry.plot.overlay", | ||||
|                                 configuration: { | ||||
|                                     series: [ | ||||
|                                         { | ||||
|                                             identifier: { | ||||
|                                                 key: "test-object", | ||||
|                                                 namespace: '' | ||||
|                                             } | ||||
|                                         } | ||||
|                                     ] | ||||
|                                 }, | ||||
|                                 composition: [] | ||||
|                             } | ||||
|                         } | ||||
|                     }, | ||||
|                     { | ||||
|                         context: { | ||||
|                             item: { | ||||
|                                 type: 'time-strip', | ||||
|                                 identifier: { | ||||
|                                     key: 'some-other-key', | ||||
|                                     namespace: '' | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 ] | ||||
|             ]; | ||||
|  | ||||
|             mockComposition = new EventEmitter(); | ||||
|             mockComposition.load = () => { | ||||
|                 mockComposition.emit('add', testTelemetryObject); | ||||
|  | ||||
|                 return [testTelemetryObject]; | ||||
|             }; | ||||
|  | ||||
|             spyOn(openmct.composition, 'get').and.returnValue(mockComposition); | ||||
|  | ||||
|             const configId = openmct.objects.makeKeyString(selection[0][0].context.item.identifier); | ||||
|             config = new PlotConfigurationModel({ | ||||
|                 id: configId, | ||||
|                 domainObject: selection[0][0].context.item, | ||||
|                 openmct: openmct | ||||
|             }); | ||||
|             configStore.add(configId, config); | ||||
|  | ||||
|             let viewContainer = document.createElement('div'); | ||||
|             child.append(viewContainer); | ||||
|             component = new Vue({ | ||||
|                 el: viewContainer, | ||||
|                 components: { | ||||
|                     PlotOptions | ||||
|                 }, | ||||
|                 provide: { | ||||
|                     openmct: openmct, | ||||
|                     domainObject: selection[0][0].context.item, | ||||
|                     path: [selection[0][0].context.item, selection[0][1].context.item] | ||||
|                 }, | ||||
|                 template: '<plot-options/>' | ||||
|             }); | ||||
|  | ||||
|             Vue.nextTick(() => { | ||||
|                 viewComponentObject = component.$root.$children[0]; | ||||
|                 done(); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         describe('in view only mode', () => { | ||||
|             let browseOptionsEl; | ||||
|             let editOptionsEl; | ||||
|             beforeEach(() => { | ||||
|                 browseOptionsEl = viewComponentObject.$el.querySelector('.js-plot-options-browse'); | ||||
|                 editOptionsEl = viewComponentObject.$el.querySelector('.js-plot-options-edit'); | ||||
|             }); | ||||
|  | ||||
|             it('does not show the edit options', () => { | ||||
|                 expect(editOptionsEl).toBeNull(); | ||||
|             }); | ||||
|  | ||||
|             it('shows the name', () => { | ||||
|                 const seriesEl = browseOptionsEl.querySelector('.c-object-label__name'); | ||||
|                 expect(seriesEl.innerHTML).toEqual(testTelemetryObject.name); | ||||
|             }); | ||||
|  | ||||
|             it('shows in collapsed mode', () => { | ||||
|                 const seriesEl = browseOptionsEl.querySelectorAll('.c-disclosure-triangle--expanded'); | ||||
|                 expect(seriesEl.length).toEqual(0); | ||||
|             }); | ||||
|  | ||||
|             it('shows in expanded mode', () => { | ||||
|                 let expandControl = browseOptionsEl.querySelector(".c-disclosure-triangle"); | ||||
|                 const clickEvent = createMouseEvent("click"); | ||||
|                 expandControl.dispatchEvent(clickEvent); | ||||
|  | ||||
|                 const plotOptionsProperties = browseOptionsEl.querySelectorAll('.js-plot-options-browse-properties .grid-row'); | ||||
|                 expect(plotOptionsProperties.length).toEqual(5); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         describe('in edit mode', () => { | ||||
|             let editOptionsEl; | ||||
|             let browseOptionsEl; | ||||
|  | ||||
|             beforeEach((done) => { | ||||
|                 viewComponentObject.setEditState(true); | ||||
|                 Vue.nextTick(() => { | ||||
|                     editOptionsEl = viewComponentObject.$el.querySelector('.js-plot-options-edit'); | ||||
|                     browseOptionsEl = viewComponentObject.$el.querySelector('.js-plot-options-browse'); | ||||
|                     done(); | ||||
|                 }); | ||||
|             }); | ||||
|  | ||||
|             it('does not show the browse options', () => { | ||||
|                 expect(browseOptionsEl).toBeNull(); | ||||
|             }); | ||||
|  | ||||
|             it('shows the name', () => { | ||||
|                 const seriesEl = editOptionsEl.querySelector('.c-object-label__name'); | ||||
|                 expect(seriesEl.innerHTML).toEqual(testTelemetryObject.name); | ||||
|             }); | ||||
|  | ||||
|             it('shows in collapsed mode', () => { | ||||
|                 const seriesEl = editOptionsEl.querySelectorAll('.c-disclosure-triangle--expanded'); | ||||
|                 expect(seriesEl.length).toEqual(0); | ||||
|             }); | ||||
|  | ||||
|             it('shows in collapsed mode', () => { | ||||
|                 const seriesEl = editOptionsEl.querySelectorAll('.c-disclosure-triangle--expanded'); | ||||
|                 expect(seriesEl.length).toEqual(0); | ||||
|             }); | ||||
|  | ||||
|             it('renders expanded', () => { | ||||
|                 const expandControl = editOptionsEl.querySelector(".c-disclosure-triangle"); | ||||
|                 const clickEvent = createMouseEvent("click"); | ||||
|                 expandControl.dispatchEvent(clickEvent); | ||||
|  | ||||
|                 const plotOptionsProperties = editOptionsEl.querySelectorAll(".js-plot-options-edit-properties .grid-row"); | ||||
|                 expect(plotOptionsProperties.length).toEqual(6); | ||||
|             }); | ||||
|  | ||||
|             it('shows yKeyOptions', () => { | ||||
|                 const expandControl = editOptionsEl.querySelector(".c-disclosure-triangle"); | ||||
|                 const clickEvent = createMouseEvent("click"); | ||||
|                 expandControl.dispatchEvent(clickEvent); | ||||
|  | ||||
|                 const plotOptionsProperties = editOptionsEl.querySelectorAll(".js-plot-options-edit-properties .grid-row"); | ||||
|  | ||||
|                 const yKeySelection = plotOptionsProperties[0].querySelector('select'); | ||||
|                 const options = Array.from(yKeySelection.options).map((option) => { | ||||
|                     return option.value; | ||||
|                 }); | ||||
|                 expect(options).toEqual([testTelemetryObject.telemetry.values[1].key, testTelemetryObject.telemetry.values[2].key]); | ||||
|             }); | ||||
|  | ||||
|             it('shows yAxis options', () => { | ||||
|                 const expandControl = editOptionsEl.querySelector(".c-disclosure-triangle"); | ||||
|                 const clickEvent = createMouseEvent("click"); | ||||
|                 expandControl.dispatchEvent(clickEvent); | ||||
|  | ||||
|                 const yAxisProperties = editOptionsEl.querySelectorAll("div.grid-properties:first-of-type .l-inspector-part"); | ||||
|                 expect(yAxisProperties.length).toEqual(3); | ||||
|             }); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
| }); | ||||
|   | ||||
							
								
								
									
										113
									
								
								src/plugins/timeline/TimelineObjectView.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								src/plugins/timeline/TimelineObjectView.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,113 @@ | ||||
| /***************************************************************************** | ||||
| * Open MCT, Copyright (c) 2014-2021, United States Government | ||||
| * as represented by the Administrator of the National Aeronautics and Space | ||||
| * Administration. All rights reserved. | ||||
| * | ||||
| * Open MCT is licensed under the Apache License, Version 2.0 (the | ||||
| * "License"); you may not use this file except in compliance with the License. | ||||
| * You may obtain a copy of the License at | ||||
| * http://www.apache.org/licenses/LICENSE-2.0. | ||||
| * | ||||
| * Unless required by applicable law or agreed to in writing, software | ||||
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| * License for the specific language governing permissions and limitations | ||||
| * under the License. | ||||
| * | ||||
| * Open MCT includes source code licensed under additional open source | ||||
| * licenses. See the Open Source Licenses file (LICENSES.md) included with | ||||
| * this source code distribution or the Licensing information page available | ||||
| * at runtime from the About dialog for additional information. | ||||
| *****************************************************************************/ | ||||
| <template> | ||||
| <swim-lane :icon-class="item.type.definition.cssClass" | ||||
|            :min-height="item.height" | ||||
|            :show-ucontents="item.domainObject.type === 'plan'" | ||||
|            :span-rows-count="item.rowCount" | ||||
| > | ||||
|     <template slot="label"> | ||||
|         {{ item.domainObject.name }} | ||||
|     </template> | ||||
|     <object-view | ||||
|         ref="objectView" | ||||
|         slot="object" | ||||
|         class="u-contents" | ||||
|         :default-object="item.domainObject" | ||||
|         :object-view-key="item.viewKey" | ||||
|         :object-path="item.objectPath" | ||||
|     /> | ||||
| </swim-lane> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import ObjectView from '@/ui/components/ObjectView.vue'; | ||||
| import SwimLane from "@/ui/components/swim-lane/SwimLane.vue"; | ||||
|  | ||||
| export default { | ||||
|     components: { | ||||
|         ObjectView, | ||||
|         SwimLane | ||||
|     }, | ||||
|     inject: ['openmct'], | ||||
|     props: { | ||||
|         item: { | ||||
|             type: Object, | ||||
|             required: true | ||||
|         } | ||||
|     }, | ||||
|     data() { | ||||
|         return { | ||||
|             domainObject: undefined, | ||||
|             mutablePromise: undefined | ||||
|         }; | ||||
|     }, | ||||
|     watch: { | ||||
|         item(newItem) { | ||||
|             if (!this.context) { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             this.context.item = newItem.domainObject; | ||||
|         } | ||||
|     }, | ||||
|     mounted() { | ||||
|         if (this.openmct.objects.supportsMutation(this.item.domainObject.identifier)) { | ||||
|             this.mutablePromise = this.openmct.objects.getMutable(this.item.domainObject.identifier) | ||||
|                 .then(this.setObject); | ||||
|         } else { | ||||
|             this.openmct.objects.get(this.item.domainObject.identifier) | ||||
|                 .then(this.setObject); | ||||
|         } | ||||
|     }, | ||||
|     beforeDestroy() { | ||||
|         if (this.removeSelectable) { | ||||
|             this.removeSelectable(); | ||||
|         } | ||||
|  | ||||
|         if (this.mutablePromise) { | ||||
|             this.mutablePromise.then(() => { | ||||
|                 this.openmct.objects.destroyMutable(this.domainObject); | ||||
|             }); | ||||
|         } else { | ||||
|             this.openmct.objects.destroyMutable(this.domainObject); | ||||
|         } | ||||
|     }, | ||||
|     methods: { | ||||
|         setObject(domainObject) { | ||||
|             this.domainObject = domainObject; | ||||
|             this.mutablePromise = undefined; | ||||
|             this.$nextTick(() => { | ||||
|                 let reference = this.$refs.objectView; | ||||
|  | ||||
|                 if (reference) { | ||||
|                     let childContext = this.$refs.objectView.getSelectionContext(); | ||||
|                     childContext.item = domainObject; | ||||
|                     this.context = childContext; | ||||
|                     this.removeSelectable = this.openmct.selection.selectable( | ||||
|                         this.$el, this.context); | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
| </script> | ||||
| @@ -52,22 +52,10 @@ | ||||
|                 :key="item.keyString" | ||||
|                 class="u-contents c-timeline__content" | ||||
|             > | ||||
|                 <swim-lane :icon-class="item.type.definition.cssClass" | ||||
|                            :min-height="item.height" | ||||
|                            :show-ucontents="item.domainObject.type === 'plan'" | ||||
|                            :span-rows-count="item.rowCount" | ||||
|                 > | ||||
|                     <template slot="label"> | ||||
|                         {{ item.domainObject.name }} | ||||
|                     </template> | ||||
|                     <object-view | ||||
|                         slot="object" | ||||
|                         class="u-contents" | ||||
|                         :default-object="item.domainObject" | ||||
|                         :object-view-key="item.viewKey" | ||||
|                         :object-path="item.objectPath" | ||||
|                     /> | ||||
|                 </swim-lane> | ||||
|                 <timeline-object-view | ||||
|                     class="u-contents" | ||||
|                     :item="item" | ||||
|                 /> | ||||
|             </div> | ||||
|         </div> | ||||
|     </div> | ||||
| @@ -75,7 +63,7 @@ | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import ObjectView from '@/ui/components/ObjectView.vue'; | ||||
| import TimelineObjectView from './TimelineObjectView.vue'; | ||||
| import TimelineAxis from '../../ui/components/TimeSystemAxis.vue'; | ||||
| import SwimLane from "@/ui/components/swim-lane/SwimLane.vue"; | ||||
| import { getValidatedPlan } from "../plan/util"; | ||||
| @@ -101,7 +89,7 @@ function getViewKey(domainObject, objectPath, openmct) { | ||||
|  | ||||
| export default { | ||||
|     components: { | ||||
|         ObjectView, | ||||
|         TimelineObjectView, | ||||
|         TimelineAxis, | ||||
|         SwimLane | ||||
|     }, | ||||
| @@ -158,6 +146,7 @@ export default { | ||||
|         }, | ||||
|         removeItem(identifier) { | ||||
|             let index = this.items.findIndex(item => this.openmct.objects.areIdsEqual(identifier, item.domainObject.identifier)); | ||||
|             this.removeSelectable(this.items[index]); | ||||
|             this.items.splice(index, 1); | ||||
|         }, | ||||
|         reorder(reorderPlan) { | ||||
|   | ||||
| @@ -21,7 +21,6 @@ | ||||
|     <div class="c-swimlane__lane-object" | ||||
|          :style="{'min-height': minHeight}" | ||||
|          :class="{'u-contents': showUcontents}" | ||||
|          data-selectable | ||||
|     > | ||||
|         <slot name="object"></slot> | ||||
|     </div> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user