mirror of
https://github.com/nasa/openmct.git
synced 2024-12-24 07:16:39 +00:00
Filters Inspector View (#2296)
* Added telemetry filters to the API * Support multiple inspector views * Renamed InspectorView.vue to InspectorViews.vue * first cut of filter inspector plugin * abstract for better readability * third times the charm * working persist checkbox selections * fix typo * working persisted filters from inspector * add prop validations for FitlerValue and FilterObject * enable filter inspector view for overlay and stacked plots * remove object from persisted filter when object is removed from composition * update filterValue to filterField for clarity * Added filter code to tables * add filter support to Telemetry Tables * fix errors when old domainObject does not have configuration property * working filters on overlay plots * make requested changes * Add filters as 'options' object on subscribe * Significant mods to Filtering - Styling; - Added Browse view in Inspector; - Added .c-checkbox-list class; - "PLOT SERIES" header changed to "PLOT SERIES OPTIONS" for clarity; * make filter update pass updated filters to telemetry adapter * Tolerate undefined configuration * Conditionally destroy filters listener * use @change event instead of @blur'
This commit is contained in:
parent
5151f90bb8
commit
248f160e73
@ -33,12 +33,19 @@ define([
|
||||
formatString: '%0.2f',
|
||||
hints: {
|
||||
range: 1
|
||||
}
|
||||
},
|
||||
filters: [
|
||||
{
|
||||
comparator: 'equals',
|
||||
possibleValues: [1,2,3,4]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: "cos",
|
||||
name: "Cosine",
|
||||
formatString: '%0.2f',
|
||||
filters: ['equals'],
|
||||
hints: {
|
||||
range: 2
|
||||
}
|
||||
|
@ -81,6 +81,7 @@
|
||||
openmct.install(openmct.plugins.Tabs());
|
||||
openmct.install(openmct.plugins.FlexibleLayout());
|
||||
openmct.install(openmct.plugins.LADTable());
|
||||
openmct.install(openmct.plugins.Filters(['table', 'telemetry.plot.overlay']));
|
||||
openmct.install(openmct.plugins.ObjectMigration());
|
||||
openmct.start();
|
||||
</script>
|
||||
|
@ -297,7 +297,7 @@ define([
|
||||
* @returns {Function} a function which may be called to terminate
|
||||
* the subscription
|
||||
*/
|
||||
TelemetryAPI.prototype.subscribe = function (domainObject, callback) {
|
||||
TelemetryAPI.prototype.subscribe = function (domainObject, callback, options) {
|
||||
var provider = this.findSubscriptionProvider(domainObject);
|
||||
|
||||
if (!this.subscribeCache) {
|
||||
@ -316,7 +316,7 @@ define([
|
||||
subscriber.callbacks.forEach(function (cb) {
|
||||
cb(value);
|
||||
});
|
||||
});
|
||||
}, options);
|
||||
} else {
|
||||
subscriber.unsubscribe = function () {};
|
||||
}
|
||||
|
@ -124,6 +124,10 @@ define([
|
||||
return sortedMetadata;
|
||||
};
|
||||
|
||||
TelemetryMetadataManager.prototype.getFilterableValues = function () {
|
||||
return this.valueMetadatas.filter(metadatum => metadatum.filters && metadatum.filters.length > 0);
|
||||
}
|
||||
|
||||
TelemetryMetadataManager.prototype.getDefaultDisplayValue = function () {
|
||||
let valueMetadata = this.valuesForHints(['range'])[0];
|
||||
|
||||
|
113
src/plugins/filters/components/FilterField.vue
Normal file
113
src/plugins/filters/components/FilterField.vue
Normal file
@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<div class="u-contents c-filter-settings">
|
||||
<li class="grid-row c-filter-settings__setting"
|
||||
v-for="(filter, index) in filterField.filters"
|
||||
:key="index">
|
||||
<div class="grid-cell label">
|
||||
{{ filterField.name }} =
|
||||
</div>
|
||||
<div class="grid-cell value">
|
||||
<!-- EDITING -->
|
||||
<!-- String input, editing -->
|
||||
<template v-if="!filter.possibleValues && isEditing">
|
||||
<input class="c-input--flex"
|
||||
type="text"
|
||||
placeholder="Enter Value"
|
||||
:id="`${filter}filterControl`"
|
||||
:value="persistedValue(filter)"
|
||||
@change="updateFilterValue($event, filter)">
|
||||
</template>
|
||||
|
||||
<!-- Checkbox list, editing -->
|
||||
<template v-if="filter.possibleValues && isEditing">
|
||||
<div class="c-checkbox-list__row"
|
||||
v-for="value in filter.possibleValues"
|
||||
:key="value">
|
||||
<input class="c-checkbox-list__input"
|
||||
type="checkbox"
|
||||
:id="`${value}filterControl`"
|
||||
@change="onUserSelect($event, filter.comparator, value)"
|
||||
:checked="isChecked(filter.comparator, value)">
|
||||
<span class="c-checkbox-list__value">
|
||||
{{ value }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- BROWSING -->
|
||||
<!-- String input, NOT editing -->
|
||||
<template v-if="!filter.possibleValues && !isEditing">
|
||||
{{ persistedValue(filter) }}
|
||||
</template>
|
||||
|
||||
<!-- Checkbox list, NOT editing -->
|
||||
<template v-if="filter.possibleValues && !isEditing">
|
||||
<span>{{persistedFilters[filter.comparator].join(', ')}}</span>
|
||||
</template>
|
||||
</div>
|
||||
</li>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import "~styles/sass-base";
|
||||
|
||||
.c-filter-settings {
|
||||
&__setting {
|
||||
.grid-cell.label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: [
|
||||
'openmct'
|
||||
],
|
||||
props: {
|
||||
filterField: Object,
|
||||
persistedFilters: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
expanded: false,
|
||||
isEditing: this.openmct.editor.isEditing()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleIsEditing(isEditing) {
|
||||
this.isEditing = isEditing;
|
||||
},
|
||||
onUserSelect(event, comparator, value){
|
||||
this.$emit('onUserSelect', this.filterField.key, comparator, value, event.target.checked);
|
||||
},
|
||||
isChecked(comparator, value) {
|
||||
if (this.persistedFilters[comparator] && this.persistedFilters[comparator].includes(value)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
persistedValue(comparator) {
|
||||
return this.persistedFilters && this.persistedFilters[comparator];
|
||||
},
|
||||
updateFilterValue(event, comparator) {
|
||||
this.$emit('onTextEnter', this.filterField.key, comparator, event.target.value);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.openmct.editor.on('isEditing', this.toggleIsEditing);
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.openmct.editor.off('isEditing', this.toggleIsEditing);
|
||||
}
|
||||
}
|
||||
</script>
|
93
src/plugins/filters/components/FilterObject.vue
Normal file
93
src/plugins/filters/components/FilterObject.vue
Normal file
@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<li>
|
||||
<div class="c-tree__item menus-to-left"
|
||||
@click="toggleExpanded">
|
||||
<span class="c-disclosure-triangle is-enabled flex-elem"
|
||||
:class="{'c-disclosure-triangle--expanded': expanded}"></span>
|
||||
<div class="c-tree__item__label">
|
||||
<div class="t-object-label l-flex-row flex-elem grows">
|
||||
<div class="t-item-icon flex-elem"
|
||||
:class="objectCssClass">
|
||||
</div>
|
||||
<div class="t-title-label flex-elem grows">{{ filterObject.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="grid-properties" v-if="expanded">
|
||||
<filter-field
|
||||
v-for="field in filterObject.valuesWithFilters"
|
||||
:key="field.key"
|
||||
:filterField="field"
|
||||
:persistedFilters="persistedFilters[field.key]"
|
||||
@onUserSelect="collectUserSelects"
|
||||
@onTextEnter="updateTextFilter">
|
||||
</filter-field>
|
||||
</ul>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import FilterField from './FilterField.vue';
|
||||
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
components: {
|
||||
FilterField
|
||||
},
|
||||
props: {
|
||||
filterObject: Object,
|
||||
persistedFilters: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
expanded: false,
|
||||
objectCssClass: undefined,
|
||||
updatedFilters: this.persistedFilters
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleExpanded() {
|
||||
this.expanded = !this.expanded;
|
||||
},
|
||||
collectUserSelects(key, comparator, valueName, value) {
|
||||
let filterValue = this.updatedFilters[key];
|
||||
|
||||
if (filterValue && filterValue[comparator]) {
|
||||
if (value === false) {
|
||||
filterValue[comparator] = filterValue[comparator].filter(v => v !== valueName);
|
||||
} else {
|
||||
filterValue[comparator].push(valueName);
|
||||
}
|
||||
} else {
|
||||
if (!this.updatedFilters[key]) {
|
||||
this.updatedFilters[key] = {};
|
||||
}
|
||||
this.updatedFilters[key][comparator] = [value ? valueName : undefined];
|
||||
}
|
||||
|
||||
this.$emit('updateFilters', this.keyString, this.updatedFilters);
|
||||
},
|
||||
updateTextFilter(key, comparator, value) {
|
||||
if (!this.updatedFilters[key]) {
|
||||
this.updatedFilters[key] = {};
|
||||
}
|
||||
this.updatedFilters[key][comparator] = value;
|
||||
this.$emit('updateFilters', this.keyString, this.updatedFilters);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
let type = this.openmct.types.get(this.filterObject.domainObject.type) || {};
|
||||
this.keyString = this.openmct.objects.makeKeyString(this.filterObject.domainObject.identifier);
|
||||
this.objectCssClass = type.definition.cssClass;
|
||||
}
|
||||
}
|
||||
</script>
|
85
src/plugins/filters/components/FiltersView.vue
Normal file
85
src/plugins/filters/components/FiltersView.vue
Normal file
@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<ul class="tree c-tree c-properties__section" v-if="Object.keys(children).length">
|
||||
<h2 class="c-properties__header">Filters</h2>
|
||||
<filter-object
|
||||
v-for="(child, key) in children"
|
||||
:key="key"
|
||||
:filterObject="child"
|
||||
:persistedFilters="persistedFilters[key]"
|
||||
@updateFilters="persistFilters">
|
||||
</filter-object>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import FilterObject from './FilterObject.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
FilterObject
|
||||
},
|
||||
inject: [
|
||||
'openmct',
|
||||
'providedObject'
|
||||
],
|
||||
data() {
|
||||
let persistedFilters = {};
|
||||
|
||||
if (this.providedObject.configuration && this.providedObject.configuration.filters) {
|
||||
persistedFilters = this.providedObject.configuration.filters;
|
||||
}
|
||||
|
||||
return {
|
||||
persistedFilters,
|
||||
children: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addChildren(child) {
|
||||
let keyString = this.openmct.objects.makeKeyString(child.identifier),
|
||||
metadata = this.openmct.telemetry.getMetadata(child),
|
||||
valuesWithFilters = metadata.valueMetadatas.filter((value) => value.filters),
|
||||
childObject = {
|
||||
name: child.name,
|
||||
domainObject: child,
|
||||
valuesWithFilters
|
||||
};
|
||||
|
||||
if (childObject.valuesWithFilters.length) {
|
||||
this.$set(this.children, keyString, childObject);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
},
|
||||
removeChildren(identifier) {
|
||||
let keyString = this.openmct.objects.makeKeyString(identifier);
|
||||
this.$delete(this.children, keyString);
|
||||
this.persistFilters(keyString);
|
||||
},
|
||||
persistFilters(keyString, userSelects) {
|
||||
this.persistedFilters[keyString] = userSelects;
|
||||
this.openmct.objects.mutate(this.providedObject, 'configuration.filters', this.persistedFilters);
|
||||
},
|
||||
updatePersistedFilters(filters) {
|
||||
this.persistedFilters = filters;
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
this.composition = this.openmct.composition.get(this.providedObject);
|
||||
this.composition.on('add', this.addChildren);
|
||||
this.composition.on('remove', this.removeChildren);
|
||||
this.composition.load();
|
||||
|
||||
this.unobserve = this.openmct.objects.observe(this.providedObject, 'configuration.filters', this.updatePersistedFilters);
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.composition.off('add', this.addChildren);
|
||||
this.composition.off('remove', this.removeChildren);
|
||||
this.unobserve();
|
||||
}
|
||||
}
|
||||
</script>
|
73
src/plugins/filters/filtersInspectorViewProvider.js
Normal file
73
src/plugins/filters/filtersInspectorViewProvider.js
Normal file
@ -0,0 +1,73 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, 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([
|
||||
'./components/FiltersView.vue',
|
||||
'vue'
|
||||
], function (
|
||||
FiltersView,
|
||||
Vue
|
||||
) {
|
||||
|
||||
function FiltersInspectorViewProvider(openmct, supportedObjectTypesArray) {
|
||||
return {
|
||||
key: 'filters-inspector',
|
||||
name: 'Filters Inspector View',
|
||||
canView: function (selection) {
|
||||
if (selection.length === 0) {
|
||||
return false;
|
||||
}
|
||||
let object = selection[0].context.item;
|
||||
|
||||
return object && supportedObjectTypesArray.some(type => object.type === type);
|
||||
},
|
||||
view: function (selection) {
|
||||
let component;
|
||||
let providedObject = selection[0].context.item;
|
||||
|
||||
return {
|
||||
show: function (element) {
|
||||
component = new Vue({
|
||||
provide: {
|
||||
openmct,
|
||||
providedObject
|
||||
},
|
||||
components: {
|
||||
FiltersView: FiltersView.default
|
||||
},
|
||||
template: '<filters-view></filters-view>',
|
||||
el: element
|
||||
});
|
||||
},
|
||||
destroy: function () {
|
||||
component.$destroy();
|
||||
component = undefined;
|
||||
}
|
||||
}
|
||||
},
|
||||
priority: function () {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FiltersInspectorViewProvider;
|
||||
});
|
33
src/plugins/filters/plugin.js
Normal file
33
src/plugins/filters/plugin.js
Normal file
@ -0,0 +1,33 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, 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([
|
||||
'./filtersInspectorViewProvider'
|
||||
], function (
|
||||
FiltersInspectorViewProvider
|
||||
) {
|
||||
return function plugin(supportedObjectTypesArray) {
|
||||
return function install(openmct) {
|
||||
openmct.inspectorViews.addProvider(new FiltersInspectorViewProvider(openmct, supportedObjectTypesArray));
|
||||
};
|
||||
};
|
||||
});
|
@ -250,7 +250,8 @@ define([
|
||||
{"has": "telemetry"}
|
||||
],
|
||||
"model": {
|
||||
"composition": []
|
||||
"composition": [],
|
||||
"configuration": {}
|
||||
},
|
||||
"properties": [],
|
||||
"priority": 890
|
||||
|
@ -21,7 +21,7 @@
|
||||
-->
|
||||
<div ng-controller="PlotOptionsController">
|
||||
<ul class="tree c-tree">
|
||||
<h2 title="Plot series display properties in this object">Plot Series</h2>
|
||||
<h2 title="Plot series display properties in this object">Plot Series Options</h2>
|
||||
<li ng-repeat="series in config.series.models">
|
||||
<div class="c-tree__item menus-to-left">
|
||||
<span class='c-disclosure-triangle is-enabled flex-elem'
|
||||
|
@ -21,7 +21,7 @@
|
||||
-->
|
||||
<div ng-controller="PlotOptionsController">
|
||||
<ul class="tree c-tree">
|
||||
<h2 title="Display properties for this object">Plot Series</h2>
|
||||
<h2 title="Display properties for this object">Plot Series Options</h2>
|
||||
<li ng-repeat="series in plotSeries"
|
||||
ng-controller="PlotSeriesFormController"
|
||||
form-model="series">
|
||||
|
@ -101,6 +101,19 @@ define([
|
||||
seriesConfig.identifier.namespace === identifier.namespace;
|
||||
})[0];
|
||||
},
|
||||
/**
|
||||
* Retrieve the persisted filters for a given identifier.
|
||||
*/
|
||||
getPersistedFilters: function (identifier) {
|
||||
var domainObject = this.get('domainObject'),
|
||||
keystring = this.openmct.objects.makeKeyString(identifier);
|
||||
|
||||
if (!domainObject.configuration || !domainObject.configuration.filters) {
|
||||
return;
|
||||
}
|
||||
|
||||
return domainObject.configuration.filters[keystring];
|
||||
},
|
||||
/**
|
||||
* Update the domain object with the given value.
|
||||
*/
|
||||
|
@ -84,6 +84,7 @@ define([
|
||||
this.listenTo(this, 'change:xKey', this.onXKeyChange, this);
|
||||
this.listenTo(this, 'change:yKey', this.onYKeyChange, this);
|
||||
this.persistedConfig = options.persistedConfig;
|
||||
this.filters = options.filters;
|
||||
|
||||
Model.apply(this, arguments);
|
||||
this.onXKeyChange(this.get('xKey'));
|
||||
@ -139,13 +140,16 @@ define([
|
||||
* @returns {Promise}
|
||||
*/
|
||||
fetch: function (options) {
|
||||
options = _.extend({}, {size: 1000, strategy: 'minmax'}, options || {});
|
||||
options = _.extend({}, {size: 1000, strategy: 'minmax', filters: this.filters}, options || {});
|
||||
if (!this.unsubscribe) {
|
||||
this.unsubscribe = this.openmct
|
||||
.telemetry
|
||||
.subscribe(
|
||||
this.domainObject,
|
||||
this.add.bind(this)
|
||||
this.add.bind(this),
|
||||
{
|
||||
filters: this.filters
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@ -360,6 +364,19 @@ define([
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
/**
|
||||
* Updates filters, clears the plot series, unsubscribes and resubscribes
|
||||
* @public
|
||||
*/
|
||||
updateFiltersAndRefresh: function (updatedFilters) {
|
||||
this.filters = updatedFilters;
|
||||
this.reset();
|
||||
if (this.unsubscribe) {
|
||||
this.unsubscribe();
|
||||
delete this.unsubscribe;
|
||||
}
|
||||
this.fetch();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -66,6 +66,7 @@ define([
|
||||
},
|
||||
addTelemetryObject: function (domainObject, index) {
|
||||
var seriesConfig = this.plot.getPersistedSeriesConfig(domainObject.identifier);
|
||||
var filters = this.plot.getPersistedFilters(domainObject.identifier);
|
||||
var plotObject = this.plot.get('domainObject');
|
||||
|
||||
if (!seriesConfig) {
|
||||
@ -92,7 +93,8 @@ define([
|
||||
collection: this,
|
||||
openmct: this.openmct,
|
||||
persistedConfig: this.plot
|
||||
.getPersistedSeriesConfig(domainObject.identifier)
|
||||
.getPersistedSeriesConfig(domainObject.identifier),
|
||||
filters: filters
|
||||
}));
|
||||
},
|
||||
removeTelemetryObject: function (identifier) {
|
||||
|
@ -71,6 +71,14 @@ define([
|
||||
this.config.series.forEach(this.addSeries, this);
|
||||
|
||||
this.followTimeConductor();
|
||||
|
||||
this.newStyleDomainObject = $scope.domainObject.useCapability('adapter');
|
||||
|
||||
this.filterObserver = this.openmct.objects.observe(
|
||||
this.newStyleDomainObject,
|
||||
'configuration.filters',
|
||||
this.updateFiltersAndResubscribe.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
eventHelpers.extend(PlotController.prototype);
|
||||
@ -154,6 +162,9 @@ define([
|
||||
clearInterval(this.checkForSize);
|
||||
delete this.checkForSize;
|
||||
}
|
||||
if (this.filterObserver) {
|
||||
this.filterObserver();
|
||||
}
|
||||
};
|
||||
|
||||
PlotController.prototype.loadMoreData = function (range, purge) {
|
||||
@ -244,6 +255,12 @@ define([
|
||||
xRange.max === xDisplayRange.max);
|
||||
};
|
||||
|
||||
PlotController.prototype.updateFiltersAndResubscribe = function (updatedFilters) {
|
||||
this.config.series.forEach(function (series) {
|
||||
series.updateFiltersAndRefresh(updatedFilters[series.keyString]);
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Export view as JPG.
|
||||
*/
|
||||
|
@ -40,6 +40,7 @@ define([
|
||||
'./flexibleLayout/plugin',
|
||||
'./tabs/plugin',
|
||||
'./LADTable/plugin',
|
||||
'./filters/plugin',
|
||||
'./objectMigration/plugin'
|
||||
], function (
|
||||
_,
|
||||
@ -61,6 +62,7 @@ define([
|
||||
FlexibleLayout,
|
||||
Tabs,
|
||||
LADTable,
|
||||
Filters,
|
||||
ObjectMigration
|
||||
) {
|
||||
var bundleMap = {
|
||||
@ -176,6 +178,7 @@ define([
|
||||
plugins.Tabs = Tabs;
|
||||
plugins.FlexibleLayout = FlexibleLayout;
|
||||
plugins.LADTable = LADTable;
|
||||
plugins.Filters = Filters;
|
||||
plugins.ObjectMigration = ObjectMigration.default;
|
||||
|
||||
return plugins;
|
||||
|
@ -46,7 +46,7 @@ define([
|
||||
view: function (selection) {
|
||||
let component;
|
||||
let domainObject = selection[0].context.item;
|
||||
const tableConfiguration = new TelemetryTableConfiguration(domainObject, openmct);
|
||||
let tableConfiguration = new TelemetryTableConfiguration(domainObject, openmct);
|
||||
return {
|
||||
show: function (element) {
|
||||
component = new Vue({
|
||||
@ -64,6 +64,7 @@ define([
|
||||
destroy: function () {
|
||||
component.$destroy();
|
||||
component = undefined;
|
||||
tableConfiguration = undefined;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -53,6 +53,10 @@ define([
|
||||
this.isTelemetryObject = this.isTelemetryObject.bind(this);
|
||||
this.refreshData = this.refreshData.bind(this);
|
||||
this.requestDataFor = this.requestDataFor.bind(this);
|
||||
this.updateFilters = this.updateFilters.bind(this);
|
||||
this.buildOptionsFromConfiguration = this.buildOptionsFromConfiguration.bind(this);
|
||||
|
||||
this.filterObserver = undefined;
|
||||
|
||||
this.createTableRowCollections();
|
||||
openmct.time.on('bounds', this.refreshData);
|
||||
@ -60,6 +64,7 @@ define([
|
||||
|
||||
initialize() {
|
||||
if (this.domainObject.type === 'table') {
|
||||
this.filterObserver = this.openmct.objects.observe(this.domainObject, 'configuration.filters', this.updateFilters);
|
||||
this.loadComposition();
|
||||
} else {
|
||||
this.addTelemetryObject(this.domainObject);
|
||||
@ -81,6 +86,7 @@ define([
|
||||
this.tableComposition = this.openmct.composition.get(this.domainObject);
|
||||
if (this.tableComposition !== undefined) {
|
||||
this.tableComposition.load().then((composition) => {
|
||||
|
||||
composition = composition.filter(this.isTelemetryObject);
|
||||
|
||||
this.configuration.addColumnsForAllObjects(composition);
|
||||
@ -101,6 +107,15 @@ define([
|
||||
this.emit('object-added', telemetryObject);
|
||||
}
|
||||
|
||||
updateFilters() {
|
||||
this.filteredRows.clear();
|
||||
this.boundedRows.clear();
|
||||
Object.keys(this.subscriptions).forEach(this.unsubscribe, this);
|
||||
|
||||
this.telemetryObjects.forEach(this.requestDataFor.bind(this));
|
||||
this.telemetryObjects.forEach(this.subscribeTo.bind(this));
|
||||
}
|
||||
|
||||
removeTelemetryObject(objectIdentifier) {
|
||||
this.configuration.removeColumnsForObject(objectIdentifier, true);
|
||||
let keyString = this.openmct.objects.makeKeyString(objectIdentifier);
|
||||
@ -113,8 +128,8 @@ define([
|
||||
|
||||
requestDataFor(telemetryObject) {
|
||||
this.incrementOutstandingRequests();
|
||||
|
||||
return this.openmct.telemetry.request(telemetryObject)
|
||||
let requestOptions = this.buildOptionsFromConfiguration(telemetryObject);
|
||||
return this.openmct.telemetry.request(telemetryObject, requestOptions)
|
||||
.then(telemetryData => {
|
||||
let keyString = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
let columnMap = this.getColumnMapForObject(keyString);
|
||||
@ -165,19 +180,29 @@ define([
|
||||
}
|
||||
|
||||
subscribeTo(telemetryObject) {
|
||||
let subscribeOptions = this.buildOptionsFromConfiguration(telemetryObject);
|
||||
let keyString = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
let columnMap = this.getColumnMapForObject(keyString);
|
||||
let limitEvaluator = this.openmct.telemetry.limitEvaluator(telemetryObject);
|
||||
|
||||
this.subscriptions[keyString] = this.openmct.telemetry.subscribe(telemetryObject, (datum) => {
|
||||
this.boundedRows.add(new TelemetryTableRow(datum, columnMap, keyString, limitEvaluator));
|
||||
});
|
||||
}, subscribeOptions);
|
||||
}
|
||||
|
||||
isTelemetryObject(domainObject) {
|
||||
return domainObject.hasOwnProperty('telemetry');
|
||||
}
|
||||
|
||||
buildOptionsFromConfiguration(telemetryObject) {
|
||||
let keyString = this.openmct.objects.makeKeyString(telemetryObject.identifier),
|
||||
filters = this.domainObject.configuration &&
|
||||
this.domainObject.configuration.filters &&
|
||||
this.domainObject.configuration.filters[keyString];
|
||||
|
||||
return {filters} || {};
|
||||
}
|
||||
|
||||
unsubscribe(keyString) {
|
||||
this.subscriptions[keyString]();
|
||||
delete this.subscriptions[keyString];
|
||||
@ -188,6 +213,9 @@ define([
|
||||
this.filteredRows.destroy();
|
||||
Object.keys(this.subscriptions).forEach(this.unsubscribe, this);
|
||||
this.openmct.time.off('bounds', this.refreshData);
|
||||
if (this.filterObserver) {
|
||||
this.filterObserver();
|
||||
}
|
||||
|
||||
if (this.tableComposition !== undefined) {
|
||||
this.tableComposition.off('add', this.addTelemetryObject);
|
||||
|
@ -1,19 +1,21 @@
|
||||
<template>
|
||||
<div class="c-properties" v-if="isEditing">
|
||||
<div class="c-properties__header">Table Column Size</div>
|
||||
<ul class="c-properties__section">
|
||||
<li class="c-properties__row">
|
||||
<div class="c-properties__label" title="Show or Hide Column"><label for="AutoSizeControl">Auto-size</label></div>
|
||||
<div class="c-properties__value"><input type="checkbox" id="AutoSizeControl" :checked="configuration.autosize !== false" @change="toggleAutosize()"></div>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="c-properties__header">Table Column Visibility</div>
|
||||
<ul class="c-properties__section">
|
||||
<li class="c-properties__row" v-for="(title, key) in headers">
|
||||
<div class="c-properties__label" title="Show or Hide Column"><label :for="key + 'ColumnControl'">{{title}}</label></div>
|
||||
<div class="c-properties__value"><input type="checkbox" :id="key + 'ColumnControl'" :checked="configuration.hiddenColumns[key] !== true" @change="toggleColumn(key)"></div>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="c-properties">
|
||||
<template v-if="isEditing">
|
||||
<div class="c-properties__header">Table Column Size</div>
|
||||
<ul class="c-properties__section">
|
||||
<li class="c-properties__row">
|
||||
<div class="c-properties__label" title="Show or Hide Column"><label for="AutoSizeControl">Auto-size</label></div>
|
||||
<div class="c-properties__value"><input type="checkbox" id="AutoSizeControl" :checked="configuration.autosize !== false" @change="toggleAutosize()"></div>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="c-properties__header">Table Column Visibility</div>
|
||||
<ul class="c-properties__section">
|
||||
<li class="c-properties__row" v-for="(title, key) in headers">
|
||||
<div class="c-properties__label" title="Show or Hide Column"><label :for="key + 'ColumnControl'">{{title}}</label></div>
|
||||
<div class="c-properties__value"><input type="checkbox" :id="key + 'ColumnControl'" :checked="configuration.hiddenColumns[key] !== true" @change="toggleColumn(key)"></div>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -239,6 +239,18 @@ select {
|
||||
padding: 1px 20px 1px $interiorMargin;
|
||||
}
|
||||
|
||||
// CHECKBOX LISTS
|
||||
// __input followed by __label
|
||||
.c-checkbox-list {
|
||||
// Rows
|
||||
&__row + &__row { margin-top: $interiorMarginSm; }
|
||||
|
||||
// input and label in each __row
|
||||
&__row {
|
||||
> * + * { margin-left: $interiorMargin; }
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************** HYPERLINKS AND HYPERLINK BUTTONS */
|
||||
.c-hyperlink {
|
||||
&--link {
|
||||
|
@ -4,7 +4,7 @@
|
||||
<pane class="c-inspector__properties">
|
||||
<properties></properties>
|
||||
<location></location>
|
||||
<inspector-view></inspector-view>
|
||||
<inspector-views></inspector-views>
|
||||
</pane>
|
||||
<pane class="c-inspector__elements"
|
||||
handle="before"
|
||||
@ -183,6 +183,13 @@
|
||||
}
|
||||
/********************************************* LEGACY SUPPORT */
|
||||
.c-inspector {
|
||||
// FilterField.vue
|
||||
.u-contents + .u-contents {
|
||||
li.grid-row > * {
|
||||
border-top: 1px solid $colorInspectorSectionHeaderBg;
|
||||
}
|
||||
}
|
||||
|
||||
li.grid-row + li.grid-row {
|
||||
> * {
|
||||
border-top: 1px solid $colorInspectorSectionHeaderBg;
|
||||
@ -210,7 +217,7 @@
|
||||
import Elements from './Elements.vue';
|
||||
import Location from './Location.vue';
|
||||
import Properties from './Properties.vue';
|
||||
import InspectorView from './InspectorView.vue';
|
||||
import InspectorViews from './InspectorViews.vue';
|
||||
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
@ -223,7 +230,7 @@
|
||||
Elements,
|
||||
Properties,
|
||||
Location,
|
||||
InspectorView
|
||||
InspectorViews
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -1,37 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
mounted() {
|
||||
this.openmct.selection.on('change', this.updateSelection);
|
||||
this.updateSelection();
|
||||
},
|
||||
destroyed() {
|
||||
this.openmct.selection.off('change', this.updateSelection);
|
||||
},
|
||||
methods: {
|
||||
updateSelection() {
|
||||
let selection = this.openmct.selection.get();
|
||||
if (this.selectedView && this.selectedView.destroy) {
|
||||
this.selectedView.destroy();
|
||||
delete this.viewContainer;
|
||||
this.$el.innerHTML = '';
|
||||
}
|
||||
this.selectedView = this.openmct.inspectorViews.get(selection);
|
||||
if (!this.selectedView) {
|
||||
return;
|
||||
}
|
||||
this.viewContainer = document.createElement('div');
|
||||
this.$el.append(this.viewContainer)
|
||||
this.selectedView.show(this.viewContainer);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
40
src/ui/inspector/InspectorViews.vue
Normal file
40
src/ui/inspector/InspectorViews.vue
Normal file
@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
mounted() {
|
||||
this.openmct.selection.on('change', this.updateSelection);
|
||||
this.updateSelection();
|
||||
},
|
||||
destroyed() {
|
||||
this.openmct.selection.off('change', this.updateSelection);
|
||||
},
|
||||
methods: {
|
||||
updateSelection() {
|
||||
let selection = this.openmct.selection.get();
|
||||
if (this.selectedViews) {
|
||||
this.selectedViews.forEach(selectedView => {
|
||||
selectedView.destroy();
|
||||
});
|
||||
this.$el.innerHTML = '';
|
||||
}
|
||||
this.viewContainers = [];
|
||||
this.selectedViews = this.openmct.inspectorViews.get(selection);
|
||||
this.selectedViews.forEach(selectedView => {
|
||||
let viewContainer = document.createElement('div');
|
||||
this.viewContainers.push(viewContainer);
|
||||
|
||||
this.$el.append(viewContainer)
|
||||
selectedView.show(viewContainer);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -42,13 +42,9 @@ define([], function () {
|
||||
* @private for platform-internal use
|
||||
*/
|
||||
InspectorViewRegistry.prototype.get = function (selection) {
|
||||
var providers = this.getAllProviders().filter(function (provider) {
|
||||
return this.getAllProviders().filter(function (provider) {
|
||||
return provider.canView(selection);
|
||||
});
|
||||
|
||||
if (providers && providers.length > 0) {
|
||||
return providers[0].view(selection);
|
||||
}
|
||||
}).map(provider => provider.view(selection));
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user