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:
Deep Tailor 2019-03-12 12:20:03 -07:00 committed by Andrew Henry
parent 5151f90bb8
commit 248f160e73
25 changed files with 585 additions and 74 deletions

View File

@ -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
}

View File

@ -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>

View File

@ -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 () {};
}

View File

@ -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];

View 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>

View 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>

View 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>

View 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;
});

View 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));
};
};
});

View File

@ -250,7 +250,8 @@ define([
{"has": "telemetry"}
],
"model": {
"composition": []
"composition": [],
"configuration": {}
},
"properties": [],
"priority": 890

View File

@ -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'

View File

@ -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">

View File

@ -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.
*/

View File

@ -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();
}
});

View File

@ -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) {

View File

@ -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.
*/

View File

@ -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;

View File

@ -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;
}
}
},

View File

@ -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);

View File

@ -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>

View File

@ -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 {

View File

@ -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 {

View File

@ -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>

View 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>

View File

@ -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));
};
/**