mirror of
https://github.com/nasa/openmct.git
synced 2025-06-01 23:20:50 +00:00
Condition set output label (#4233)
* Show condition set label for condition widgets * CSS changes * Ensure condition set output as labels also works when condition widget is part of a display layout * Adds tests for conditionWidget * Tests for condition label output. Fix breaking tests. * Don't remove event listeners when conditionset changes Co-authored-by: Charles Hacskaylo <charlesh88@gmail.com> Co-authored-by: Andrew Henry <akhenry@gmail.com> Co-authored-by: David Tsay <3614296+davetsay@users.noreply.github.com>
This commit is contained in:
parent
88a94c80be
commit
3620760991
@ -109,7 +109,7 @@ export default class StyleRuleManager extends EventEmitter {
|
|||||||
if (!styleConfiguration || !styleConfiguration.conditionSetIdentifier) {
|
if (!styleConfiguration || !styleConfiguration.conditionSetIdentifier) {
|
||||||
this.initialize(styleConfiguration || {});
|
this.initialize(styleConfiguration || {});
|
||||||
this.applyStaticStyle();
|
this.applyStaticStyle();
|
||||||
this.destroy();
|
this.destroy(true);
|
||||||
} else {
|
} else {
|
||||||
let isNewConditionSet = !this.conditionSetIdentifier
|
let isNewConditionSet = !this.conditionSetIdentifier
|
||||||
|| !this.openmct.objects.areIdsEqual(this.conditionSetIdentifier, styleConfiguration.conditionSetIdentifier);
|
|| !this.openmct.objects.areIdsEqual(this.conditionSetIdentifier, styleConfiguration.conditionSetIdentifier);
|
||||||
@ -180,15 +180,17 @@ export default class StyleRuleManager extends EventEmitter {
|
|||||||
this.updateDomainObjectStyle();
|
this.updateDomainObjectStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy(skipEventListeners) {
|
||||||
if (this.stopProvidingTelemetry) {
|
if (this.stopProvidingTelemetry) {
|
||||||
|
|
||||||
this.stopProvidingTelemetry();
|
this.stopProvidingTelemetry();
|
||||||
delete this.stopProvidingTelemetry;
|
delete this.stopProvidingTelemetry;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.openmct.time.off("bounds", this.refreshData);
|
if (!skipEventListeners) {
|
||||||
this.openmct.editor.off('isEditing', this.toggleSubscription);
|
this.openmct.time.off("bounds", this.refreshData);
|
||||||
|
this.openmct.editor.off('isEditing', this.toggleSubscription);
|
||||||
|
}
|
||||||
|
|
||||||
this.conditionSetIdentifier = undefined;
|
this.conditionSetIdentifier = undefined;
|
||||||
}
|
}
|
||||||
|
@ -1,475 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2021, United States Government
|
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
* Administration. All rights reserved.
|
|
||||||
*
|
|
||||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*
|
|
||||||
* Open MCT includes source code licensed under additional open source
|
|
||||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
||||||
* this source code distribution or the Licensing information page available
|
|
||||||
* at runtime from the About dialog for additional information.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="c-inspector__styles c-inspect-styles">
|
|
||||||
<template v-if="!conditionSetDomainObject">
|
|
||||||
<div class="c-inspect-styles__header">
|
|
||||||
Object Style
|
|
||||||
</div>
|
|
||||||
<div class="c-inspect-styles__content">
|
|
||||||
<div v-if="staticStyle"
|
|
||||||
class="c-inspect-styles__style"
|
|
||||||
>
|
|
||||||
<StyleEditor class="c-inspect-styles__editor"
|
|
||||||
:style-item="staticStyle"
|
|
||||||
:is-editing="isEditing"
|
|
||||||
@persist="updateStaticStyle"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
id="addConditionSet"
|
|
||||||
class="c-button c-button--major c-toggle-styling-button labeled"
|
|
||||||
@click="addConditionSet"
|
|
||||||
>
|
|
||||||
<span class="c-cs-button__label">Use Conditional Styling...</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<div class="c-inspect-styles__header">
|
|
||||||
Conditional Object Styles
|
|
||||||
</div>
|
|
||||||
<div class="c-inspect-styles__content c-inspect-styles__condition-set">
|
|
||||||
<a v-if="conditionSetDomainObject"
|
|
||||||
class="c-object-label icon-conditional"
|
|
||||||
@click="navigateOrPreview"
|
|
||||||
>
|
|
||||||
<span class="c-object-label__name">{{ conditionSetDomainObject.name }}</span>
|
|
||||||
</a>
|
|
||||||
<template v-if="isEditing">
|
|
||||||
<button
|
|
||||||
id="changeConditionSet"
|
|
||||||
class="c-button labeled"
|
|
||||||
@click="addConditionSet"
|
|
||||||
>
|
|
||||||
<span class="c-button__label">Change...</span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button class="c-click-icon icon-x"
|
|
||||||
title="Remove conditional styles"
|
|
||||||
@click="removeConditionSet"
|
|
||||||
></button>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="conditionsLoaded"
|
|
||||||
class="c-inspect-styles__conditions"
|
|
||||||
>
|
|
||||||
<div v-for="(conditionStyle, index) in conditionalStyles"
|
|
||||||
:key="index"
|
|
||||||
class="c-inspect-styles__condition"
|
|
||||||
:class="{'is-current': conditionStyle.conditionId === selectedConditionId}"
|
|
||||||
@click="applySelectedConditionStyle(conditionStyle.conditionId)"
|
|
||||||
>
|
|
||||||
<condition-error :show-label="true"
|
|
||||||
:condition="getCondition(conditionStyle.conditionId)"
|
|
||||||
/>
|
|
||||||
<condition-description :show-label="true"
|
|
||||||
:condition="getCondition(conditionStyle.conditionId)"
|
|
||||||
/>
|
|
||||||
<StyleEditor class="c-inspect-styles__editor"
|
|
||||||
:style-item="conditionStyle"
|
|
||||||
:is-editing="isEditing"
|
|
||||||
@persist="updateConditionalStyle"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
|
|
||||||
import StyleEditor from "./StyleEditor.vue";
|
|
||||||
import SelectorDialogTree from '@/ui/components/SelectorDialogTree.vue';
|
|
||||||
import ConditionDescription from "@/plugins/condition/components/ConditionDescription.vue";
|
|
||||||
import ConditionError from "@/plugins/condition/components/ConditionError.vue";
|
|
||||||
import Vue from 'vue';
|
|
||||||
import PreviewAction from "@/ui/preview/PreviewAction.js";
|
|
||||||
import { getApplicableStylesForItem } from "@/plugins/condition/utils/styleUtils";
|
|
||||||
import isEmpty from 'lodash/isEmpty';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'ConditionalStylesView',
|
|
||||||
components: {
|
|
||||||
ConditionDescription,
|
|
||||||
ConditionError,
|
|
||||||
StyleEditor
|
|
||||||
},
|
|
||||||
inject: [
|
|
||||||
'openmct',
|
|
||||||
'selection'
|
|
||||||
],
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
conditionalStyles: [],
|
|
||||||
staticStyle: undefined,
|
|
||||||
conditionSetDomainObject: undefined,
|
|
||||||
isEditing: this.openmct.editor.isEditing(),
|
|
||||||
conditions: undefined,
|
|
||||||
conditionsLoaded: false,
|
|
||||||
navigateToPath: '',
|
|
||||||
selectedConditionId: ''
|
|
||||||
};
|
|
||||||
},
|
|
||||||
destroyed() {
|
|
||||||
this.removeListeners();
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.itemId = '';
|
|
||||||
this.getDomainObjectFromSelection();
|
|
||||||
this.previewAction = new PreviewAction(this.openmct);
|
|
||||||
if (this.domainObject.configuration && this.domainObject.configuration.objectStyles) {
|
|
||||||
let objectStyles = this.itemId ? this.domainObject.configuration.objectStyles[this.itemId] : this.domainObject.configuration.objectStyles;
|
|
||||||
this.initializeStaticStyle(objectStyles);
|
|
||||||
if (objectStyles && objectStyles.conditionSetIdentifier) {
|
|
||||||
this.openmct.objects.get(objectStyles.conditionSetIdentifier).then(this.initialize);
|
|
||||||
this.conditionalStyles = objectStyles.styles;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.initializeStaticStyle();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.openmct.editor.on('isEditing', this.setEditState);
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
isItemType(type, item) {
|
|
||||||
return item && (item.type === type);
|
|
||||||
},
|
|
||||||
getDomainObjectFromSelection() {
|
|
||||||
let layoutItem;
|
|
||||||
let domainObject;
|
|
||||||
|
|
||||||
if (this.selection[0].length > 1) {
|
|
||||||
//If there are more than 1 items in the this.selection[0] list, the first one could either be a sub domain object OR a layout drawing control.
|
|
||||||
//The second item in the this.selection[0] list is the container object (usually a layout)
|
|
||||||
layoutItem = this.selection[0][0].context.layoutItem;
|
|
||||||
const item = this.selection[0][0].context.item;
|
|
||||||
this.canHide = true;
|
|
||||||
if (item
|
|
||||||
&& (!layoutItem || (this.isItemType('subobject-view', layoutItem)))) {
|
|
||||||
domainObject = item;
|
|
||||||
} else {
|
|
||||||
domainObject = this.selection[0][1].context.item;
|
|
||||||
if (layoutItem) {
|
|
||||||
this.itemId = layoutItem.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
domainObject = this.selection[0][0].context.item;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.domainObject = domainObject;
|
|
||||||
this.initialStyles = getApplicableStylesForItem(domainObject, layoutItem);
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.removeListeners();
|
|
||||||
if (this.domainObject) {
|
|
||||||
this.stopObserving = this.openmct.objects.observe(this.domainObject, '*', newDomainObject => this.domainObject = newDomainObject);
|
|
||||||
this.stopObservingItems = this.openmct.objects.observe(this.domainObject, 'configuration.items', this.updateDomainObjectItemStyles);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
removeListeners() {
|
|
||||||
if (this.stopObserving) {
|
|
||||||
this.stopObserving();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.stopObservingItems) {
|
|
||||||
this.stopObservingItems();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.stopProvidingTelemetry) {
|
|
||||||
this.stopProvidingTelemetry();
|
|
||||||
delete this.stopProvidingTelemetry;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
initialize(conditionSetDomainObject) {
|
|
||||||
//If there are new conditions in the conditionSet we need to set those styles to default
|
|
||||||
this.conditionSetDomainObject = conditionSetDomainObject;
|
|
||||||
this.enableConditionSetNav();
|
|
||||||
this.initializeConditionalStyles();
|
|
||||||
},
|
|
||||||
setEditState(isEditing) {
|
|
||||||
this.isEditing = isEditing;
|
|
||||||
if (this.isEditing) {
|
|
||||||
if (this.stopProvidingTelemetry) {
|
|
||||||
this.stopProvidingTelemetry();
|
|
||||||
delete this.stopProvidingTelemetry;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.subscribeToConditionSet();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
addConditionSet() {
|
|
||||||
let conditionSetDomainObject;
|
|
||||||
let self = this;
|
|
||||||
|
|
||||||
function handleItemSelection({ item }) {
|
|
||||||
if (item) {
|
|
||||||
conditionSetDomainObject = item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function dismissDialog(overlay, initialize) {
|
|
||||||
overlay.dismiss();
|
|
||||||
if (initialize && conditionSetDomainObject) {
|
|
||||||
self.conditionSetDomainObject = conditionSetDomainObject;
|
|
||||||
self.conditionalStyles = [];
|
|
||||||
self.initializeConditionalStyles();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let vm = new Vue({
|
|
||||||
components: { SelectorDialogTree },
|
|
||||||
provide: {
|
|
||||||
openmct: this.openmct
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
handleItemSelection,
|
|
||||||
title: 'Select Condition Set'
|
|
||||||
};
|
|
||||||
},
|
|
||||||
template: '<selector-dialog-tree :title="title" @treeItemSelected="handleItemSelection"></selector-dialog-tree>'
|
|
||||||
}).$mount();
|
|
||||||
|
|
||||||
let overlay = this.openmct.overlays.overlay({
|
|
||||||
element: vm.$el,
|
|
||||||
size: 'small',
|
|
||||||
buttons: [
|
|
||||||
{
|
|
||||||
label: 'OK',
|
|
||||||
emphasis: 'true',
|
|
||||||
callback: () => dismissDialog(overlay, true)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Cancel',
|
|
||||||
callback: () => dismissDialog(overlay, false)
|
|
||||||
}
|
|
||||||
],
|
|
||||||
onDestroy: () => vm.$destroy()
|
|
||||||
});
|
|
||||||
},
|
|
||||||
enableConditionSetNav() {
|
|
||||||
this.openmct.objects.getOriginalPath(this.conditionSetDomainObject.identifier).then(
|
|
||||||
(objectPath) => {
|
|
||||||
this.objectPath = objectPath;
|
|
||||||
this.navigateToPath = '#/browse/' + this.openmct.objects.getRelativePath(this.objectPath);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
navigateOrPreview(event) {
|
|
||||||
// If editing, display condition set in Preview overlay; otherwise nav to it while browsing
|
|
||||||
if (this.openmct.editor.isEditing()) {
|
|
||||||
event.preventDefault();
|
|
||||||
this.previewAction.invoke(this.objectPath);
|
|
||||||
} else {
|
|
||||||
this.openmct.router.navigate(this.navigateToPath);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
removeConditionSet() {
|
|
||||||
this.conditionSetDomainObject = undefined;
|
|
||||||
this.conditionalStyles = [];
|
|
||||||
let domainObjectStyles = (this.domainObject.configuration && this.domainObject.configuration.objectStyles) || {};
|
|
||||||
if (this.itemId) {
|
|
||||||
domainObjectStyles[this.itemId].conditionSetIdentifier = undefined;
|
|
||||||
domainObjectStyles[this.itemId].selectedConditionId = undefined;
|
|
||||||
domainObjectStyles[this.itemId].defaultConditionId = undefined;
|
|
||||||
delete domainObjectStyles[this.itemId].conditionSetIdentifier;
|
|
||||||
domainObjectStyles[this.itemId].styles = undefined;
|
|
||||||
delete domainObjectStyles[this.itemId].styles;
|
|
||||||
if (isEmpty(domainObjectStyles[this.itemId])) {
|
|
||||||
delete domainObjectStyles[this.itemId];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
domainObjectStyles.conditionSetIdentifier = undefined;
|
|
||||||
domainObjectStyles.selectedConditionId = undefined;
|
|
||||||
domainObjectStyles.defaultConditionId = undefined;
|
|
||||||
delete domainObjectStyles.conditionSetIdentifier;
|
|
||||||
domainObjectStyles.styles = undefined;
|
|
||||||
delete domainObjectStyles.styles;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isEmpty(domainObjectStyles)) {
|
|
||||||
domainObjectStyles = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.persist(domainObjectStyles);
|
|
||||||
if (this.stopProvidingTelemetry) {
|
|
||||||
this.stopProvidingTelemetry();
|
|
||||||
delete this.stopProvidingTelemetry;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
updateDomainObjectItemStyles(newItems) {
|
|
||||||
//check that all items that have been styles still exist. Otherwise delete those styles
|
|
||||||
let domainObjectStyles = (this.domainObject.configuration && this.domainObject.configuration.objectStyles) || {};
|
|
||||||
let itemsToRemove = [];
|
|
||||||
let keys = Object.keys(domainObjectStyles);
|
|
||||||
//TODO: Need an easier way to find which properties are itemIds
|
|
||||||
keys.forEach((key) => {
|
|
||||||
const keyIsItemId = (key !== 'styles')
|
|
||||||
&& (key !== 'staticStyle')
|
|
||||||
&& (key !== 'defaultConditionId')
|
|
||||||
&& (key !== 'selectedConditionId')
|
|
||||||
&& (key !== 'conditionSetIdentifier');
|
|
||||||
if (keyIsItemId) {
|
|
||||||
if (!(newItems.find(item => item.id === key))) {
|
|
||||||
itemsToRemove.push(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (itemsToRemove.length) {
|
|
||||||
this.removeItemStyles(itemsToRemove, domainObjectStyles);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
removeItemStyles(itemIds, domainObjectStyles) {
|
|
||||||
itemIds.forEach(itemId => {
|
|
||||||
if (domainObjectStyles[itemId]) {
|
|
||||||
domainObjectStyles[itemId] = undefined;
|
|
||||||
delete domainObjectStyles[this.itemId];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (isEmpty(domainObjectStyles)) {
|
|
||||||
domainObjectStyles = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.persist(domainObjectStyles);
|
|
||||||
},
|
|
||||||
initializeConditionalStyles() {
|
|
||||||
if (!this.conditions) {
|
|
||||||
this.conditions = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
let conditionalStyles = [];
|
|
||||||
this.conditionSetDomainObject.configuration.conditionCollection.forEach((conditionConfiguration, index) => {
|
|
||||||
if (conditionConfiguration.isDefault) {
|
|
||||||
this.selectedConditionId = conditionConfiguration.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.conditions[conditionConfiguration.id] = conditionConfiguration;
|
|
||||||
let foundStyle = this.findStyleByConditionId(conditionConfiguration.id);
|
|
||||||
if (foundStyle) {
|
|
||||||
foundStyle.style = Object.assign((this.canHide ? { isStyleInvisible: '' } : {}), this.initialStyles, foundStyle.style);
|
|
||||||
conditionalStyles.push(foundStyle);
|
|
||||||
} else {
|
|
||||||
conditionalStyles.splice(index, 0, {
|
|
||||||
conditionId: conditionConfiguration.id,
|
|
||||||
style: Object.assign((this.canHide ? { isStyleInvisible: '' } : {}), this.initialStyles)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
//we're doing this so that we remove styles for any conditions that have been removed from the condition set
|
|
||||||
this.conditionalStyles = conditionalStyles;
|
|
||||||
this.conditionsLoaded = true;
|
|
||||||
this.persist(this.getDomainObjectConditionalStyle(this.selectedConditionId));
|
|
||||||
if (!this.isEditing) {
|
|
||||||
this.subscribeToConditionSet();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
subscribeToConditionSet() {
|
|
||||||
if (this.stopProvidingTelemetry) {
|
|
||||||
this.stopProvidingTelemetry();
|
|
||||||
delete this.stopProvidingTelemetry;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.conditionSetDomainObject) {
|
|
||||||
this.openmct.telemetry.request(this.conditionSetDomainObject)
|
|
||||||
.then(output => {
|
|
||||||
if (output && output.length) {
|
|
||||||
this.handleConditionSetResultUpdated(output[0]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.stopProvidingTelemetry = this.openmct.telemetry.subscribe(this.conditionSetDomainObject, this.handleConditionSetResultUpdated.bind(this));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleConditionSetResultUpdated(resultData) {
|
|
||||||
this.selectedConditionId = resultData ? resultData.conditionId : '';
|
|
||||||
},
|
|
||||||
initializeStaticStyle(objectStyles) {
|
|
||||||
let staticStyle = objectStyles && objectStyles.staticStyle;
|
|
||||||
if (staticStyle) {
|
|
||||||
this.staticStyle = {
|
|
||||||
style: Object.assign({}, this.initialStyles, staticStyle.style)
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
this.staticStyle = {
|
|
||||||
style: Object.assign({}, this.initialStyles)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
findStyleByConditionId(id) {
|
|
||||||
return this.conditionalStyles.find(conditionalStyle => conditionalStyle.conditionId === id);
|
|
||||||
},
|
|
||||||
updateStaticStyle(staticStyle) {
|
|
||||||
this.staticStyle = staticStyle;
|
|
||||||
this.persist(this.getDomainObjectConditionalStyle());
|
|
||||||
},
|
|
||||||
updateConditionalStyle(conditionStyle) {
|
|
||||||
let found = this.findStyleByConditionId(conditionStyle.conditionId);
|
|
||||||
if (found) {
|
|
||||||
found.style = conditionStyle.style;
|
|
||||||
this.selectedConditionId = found.conditionId;
|
|
||||||
this.persist(this.getDomainObjectConditionalStyle());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getDomainObjectConditionalStyle(defaultConditionId) {
|
|
||||||
let objectStyle = {
|
|
||||||
styles: this.conditionalStyles,
|
|
||||||
staticStyle: this.staticStyle,
|
|
||||||
selectedConditionId: this.selectedConditionId
|
|
||||||
};
|
|
||||||
if (defaultConditionId) {
|
|
||||||
objectStyle.defaultConditionId = defaultConditionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.conditionSetDomainObject) {
|
|
||||||
objectStyle.conditionSetIdentifier = this.conditionSetDomainObject.identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
let domainObjectStyles = (this.domainObject.configuration && this.domainObject.configuration.objectStyles) || {};
|
|
||||||
|
|
||||||
if (this.itemId) {
|
|
||||||
domainObjectStyles[this.itemId] = objectStyle;
|
|
||||||
} else {
|
|
||||||
//we're deconstructing here to ensure that if an item within a domainObject already had a style we don't lose it
|
|
||||||
domainObjectStyles = {
|
|
||||||
...domainObjectStyles,
|
|
||||||
...objectStyle
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return domainObjectStyles;
|
|
||||||
},
|
|
||||||
getCondition(id) {
|
|
||||||
return this.conditions ? this.conditions[id] : {};
|
|
||||||
},
|
|
||||||
applySelectedConditionStyle(conditionId) {
|
|
||||||
this.selectedConditionId = conditionId;
|
|
||||||
this.persist(this.getDomainObjectConditionalStyle());
|
|
||||||
},
|
|
||||||
persist(style) {
|
|
||||||
this.openmct.objects.mutate(this.domainObject, 'configuration.objectStyles', style);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
@ -1,280 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2021, United States Government
|
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
* Administration. All rights reserved.
|
|
||||||
*
|
|
||||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*
|
|
||||||
* Open MCT includes source code licensed under additional open source
|
|
||||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
||||||
* this source code distribution or the Licensing information page available
|
|
||||||
* at runtime from the About dialog for additional information.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="c-inspector__styles c-inspect-styles">
|
|
||||||
<div class="c-inspect-styles__header">
|
|
||||||
Object Style
|
|
||||||
</div>
|
|
||||||
<div class="c-inspect-styles__content">
|
|
||||||
<div v-if="isStaticAndConditionalStyles"
|
|
||||||
class="c-inspect-styles__mixed-static-and-conditional u-alert u-alert--block u-alert--with-icon"
|
|
||||||
>
|
|
||||||
Your selection includes one or more items that use Conditional Styling. Applying a static style below will replace any Conditional Styling with the new choice.
|
|
||||||
</div>
|
|
||||||
<div v-if="staticStyle"
|
|
||||||
class="c-inspect-styles__style"
|
|
||||||
>
|
|
||||||
<style-editor class="c-inspect-styles__editor"
|
|
||||||
:style-item="staticStyle"
|
|
||||||
:is-editing="isEditing"
|
|
||||||
:mixed-styles="mixedStyles"
|
|
||||||
@persist="updateStaticStyle"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
|
|
||||||
import StyleEditor from "./StyleEditor.vue";
|
|
||||||
import PreviewAction from "@/ui/preview/PreviewAction.js";
|
|
||||||
import { getApplicableStylesForItem, getConsolidatedStyleValues, getConditionalStyleForItem } from "@/plugins/condition/utils/styleUtils";
|
|
||||||
import isEmpty from 'lodash/isEmpty';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'MultiSelectStylesView',
|
|
||||||
components: {
|
|
||||||
StyleEditor
|
|
||||||
},
|
|
||||||
inject: [
|
|
||||||
'openmct',
|
|
||||||
'selection'
|
|
||||||
],
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
staticStyle: undefined,
|
|
||||||
isEditing: this.openmct.editor.isEditing(),
|
|
||||||
mixedStyles: [],
|
|
||||||
isStaticAndConditionalStyles: false
|
|
||||||
};
|
|
||||||
},
|
|
||||||
destroyed() {
|
|
||||||
this.removeListeners();
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.items = [];
|
|
||||||
this.previewAction = new PreviewAction(this.openmct);
|
|
||||||
this.getObjectsAndItemsFromSelection();
|
|
||||||
this.initializeStaticStyle();
|
|
||||||
this.openmct.editor.on('isEditing', this.setEditState);
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
isItemType(type, item) {
|
|
||||||
return item && (item.type === type);
|
|
||||||
},
|
|
||||||
hasConditionalStyles(domainObject, id) {
|
|
||||||
return getConditionalStyleForItem(domainObject, id) !== undefined;
|
|
||||||
},
|
|
||||||
getObjectsAndItemsFromSelection() {
|
|
||||||
let domainObject;
|
|
||||||
let subObjects = [];
|
|
||||||
|
|
||||||
//multiple selection
|
|
||||||
let itemInitialStyles = [];
|
|
||||||
let itemStyle;
|
|
||||||
this.selection.forEach((selectionItem) => {
|
|
||||||
const item = selectionItem[0].context.item;
|
|
||||||
const layoutItem = selectionItem[0].context.layoutItem;
|
|
||||||
if (item && this.isItemType('subobject-view', layoutItem)) {
|
|
||||||
subObjects.push(item);
|
|
||||||
itemStyle = getApplicableStylesForItem(item);
|
|
||||||
if (!this.isStaticAndConditionalStyles) {
|
|
||||||
this.isStaticAndConditionalStyles = this.hasConditionalStyles(item);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
domainObject = selectionItem[1].context.item;
|
|
||||||
itemStyle = getApplicableStylesForItem(domainObject, layoutItem || item);
|
|
||||||
this.items.push({
|
|
||||||
id: layoutItem.id,
|
|
||||||
applicableStyles: itemStyle
|
|
||||||
});
|
|
||||||
if (!this.isStaticAndConditionalStyles) {
|
|
||||||
this.isStaticAndConditionalStyles = this.hasConditionalStyles(domainObject, layoutItem.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
itemInitialStyles.push(itemStyle);
|
|
||||||
});
|
|
||||||
const {styles, mixedStyles} = getConsolidatedStyleValues(itemInitialStyles);
|
|
||||||
this.initialStyles = styles;
|
|
||||||
this.mixedStyles = mixedStyles;
|
|
||||||
|
|
||||||
this.domainObject = domainObject;
|
|
||||||
this.removeListeners();
|
|
||||||
if (this.domainObject) {
|
|
||||||
this.stopObserving = this.openmct.objects.observe(this.domainObject, '*', newDomainObject => this.domainObject = newDomainObject);
|
|
||||||
this.stopObservingItems = this.openmct.objects.observe(this.domainObject, 'configuration.items', this.updateDomainObjectItemStyles);
|
|
||||||
}
|
|
||||||
|
|
||||||
subObjects.forEach(this.registerListener);
|
|
||||||
},
|
|
||||||
updateDomainObjectItemStyles(newItems) {
|
|
||||||
//check that all items that have been styles still exist. Otherwise delete those styles
|
|
||||||
let keys = Object.keys(this.domainObject.configuration.objectStyles || {});
|
|
||||||
keys.forEach((key) => {
|
|
||||||
if ((key !== 'styles')
|
|
||||||
&& (key !== 'staticStyle')
|
|
||||||
&& (key !== 'conditionSetIdentifier')) {
|
|
||||||
if (!(newItems.find(item => item.id === key))) {
|
|
||||||
this.removeItemStyles(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
registerListener(domainObject) {
|
|
||||||
let id = this.openmct.objects.makeKeyString(domainObject.identifier);
|
|
||||||
|
|
||||||
if (!this.domainObjectsById) {
|
|
||||||
this.domainObjectsById = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.domainObjectsById[id]) {
|
|
||||||
this.domainObjectsById[id] = domainObject;
|
|
||||||
this.observeObject(domainObject, id);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
observeObject(domainObject, id) {
|
|
||||||
let unobserveObject = this.openmct.objects.observe(domainObject, '*', function (newObject) {
|
|
||||||
this.domainObjectsById[id] = JSON.parse(JSON.stringify(newObject));
|
|
||||||
}.bind(this));
|
|
||||||
this.unObserveObjects.push(unobserveObject);
|
|
||||||
},
|
|
||||||
removeListeners() {
|
|
||||||
if (this.stopObserving) {
|
|
||||||
this.stopObserving();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.stopObservingItems) {
|
|
||||||
this.stopObservingItems();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.unObserveObjects) {
|
|
||||||
this.unObserveObjects.forEach((unObserveObject) => {
|
|
||||||
unObserveObject();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.unObserveObjects = [];
|
|
||||||
},
|
|
||||||
removeItemStyles(itemId) {
|
|
||||||
let domainObjectStyles = (this.domainObject.configuration && this.domainObject.configuration.objectStyles) || {};
|
|
||||||
if (itemId && domainObjectStyles[itemId]) {
|
|
||||||
domainObjectStyles[itemId] = undefined;
|
|
||||||
delete domainObjectStyles[this.itemId];
|
|
||||||
|
|
||||||
if (isEmpty(domainObjectStyles)) {
|
|
||||||
domainObjectStyles = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.persist(this.domainObject, domainObjectStyles);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
removeConditionalStyles(domainObjectStyles, itemId) {
|
|
||||||
if (itemId) {
|
|
||||||
domainObjectStyles[itemId].conditionSetIdentifier = undefined;
|
|
||||||
delete domainObjectStyles[itemId].conditionSetIdentifier;
|
|
||||||
domainObjectStyles[itemId].styles = undefined;
|
|
||||||
delete domainObjectStyles[itemId].styles;
|
|
||||||
} else {
|
|
||||||
domainObjectStyles.conditionSetIdentifier = undefined;
|
|
||||||
delete domainObjectStyles.conditionSetIdentifier;
|
|
||||||
domainObjectStyles.styles = undefined;
|
|
||||||
delete domainObjectStyles.styles;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setEditState(isEditing) {
|
|
||||||
this.isEditing = isEditing;
|
|
||||||
},
|
|
||||||
initializeStaticStyle() {
|
|
||||||
this.staticStyle = {
|
|
||||||
style: Object.assign({}, this.initialStyles)
|
|
||||||
};
|
|
||||||
},
|
|
||||||
updateStaticStyle(staticStyle, property) {
|
|
||||||
//update the static style for each of the layoutItems as well as each sub object item
|
|
||||||
this.staticStyle = staticStyle;
|
|
||||||
this.persist(this.domainObject, this.getDomainObjectStyle(this.domainObject, property, this.items));
|
|
||||||
if (this.domainObjectsById) {
|
|
||||||
const keys = Object.keys(this.domainObjectsById);
|
|
||||||
keys.forEach(key => {
|
|
||||||
let domainObject = this.domainObjectsById[key];
|
|
||||||
this.persist(domainObject, this.getDomainObjectStyle(domainObject, property));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isStaticAndConditionalStyles = false;
|
|
||||||
let foundIndex = this.mixedStyles.indexOf(property);
|
|
||||||
if (foundIndex > -1) {
|
|
||||||
this.mixedStyles.splice(foundIndex, 1);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getDomainObjectStyle(domainObject, property, items) {
|
|
||||||
let domainObjectStyles = (domainObject.configuration && domainObject.configuration.objectStyles) || {};
|
|
||||||
|
|
||||||
if (items) {
|
|
||||||
items.forEach(item => {
|
|
||||||
let itemStaticStyle = {};
|
|
||||||
if (domainObjectStyles[item.id] && domainObjectStyles[item.id].staticStyle) {
|
|
||||||
itemStaticStyle = domainObjectStyles[item.id].staticStyle.style;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.keys(item.applicableStyles).forEach(key => {
|
|
||||||
if (property === key) {
|
|
||||||
itemStaticStyle[key] = this.staticStyle.style[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (this.isStaticAndConditionalStyles) {
|
|
||||||
this.removeConditionalStyles(domainObjectStyles, item.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isEmpty(itemStaticStyle)) {
|
|
||||||
itemStaticStyle = undefined;
|
|
||||||
domainObjectStyles[item.id] = undefined;
|
|
||||||
} else {
|
|
||||||
domainObjectStyles[item.id] = Object.assign({}, { staticStyle: { style: itemStaticStyle } });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (!domainObjectStyles.staticStyle) {
|
|
||||||
domainObjectStyles.staticStyle = {
|
|
||||||
style: {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isStaticAndConditionalStyles) {
|
|
||||||
this.removeConditionalStyles(domainObjectStyles);
|
|
||||||
}
|
|
||||||
|
|
||||||
domainObjectStyles.staticStyle.style[property] = this.staticStyle.style[property];
|
|
||||||
}
|
|
||||||
|
|
||||||
return domainObjectStyles;
|
|
||||||
},
|
|
||||||
|
|
||||||
persist(domainObject, style) {
|
|
||||||
this.openmct.objects.mutate(domainObject, 'configuration.objectStyles', style);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
@ -63,7 +63,7 @@
|
|||||||
<div class="c-inspect-styles__header">
|
<div class="c-inspect-styles__header">
|
||||||
Conditional Object Styles
|
Conditional Object Styles
|
||||||
</div>
|
</div>
|
||||||
<div class="c-inspect-styles__content c-inspect-styles__condition-set">
|
<div class="c-inspect-styles__content c-inspect-styles__condition-set c-inspect-styles__elem">
|
||||||
<a v-if="conditionSetDomainObject"
|
<a v-if="conditionSetDomainObject"
|
||||||
class="c-object-label"
|
class="c-object-label"
|
||||||
@click="navigateOrPreview"
|
@click="navigateOrPreview"
|
||||||
@ -87,6 +87,27 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="isConditionWidget && allowEditing"
|
||||||
|
class="c-inspect-styles__elem c-inspect-styles__output-label-toggle"
|
||||||
|
>
|
||||||
|
<label class="c-toggle-switch">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
:checked="useConditionSetOutputAsLabel"
|
||||||
|
@change="updateConditionSetOutputLabel"
|
||||||
|
>
|
||||||
|
<span class="c-toggle-switch__slider"></span>
|
||||||
|
<span class="c-toggle-switch__label">Use Condition Set output as label</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div v-if="isConditionWidget && !allowEditing"
|
||||||
|
class="c-inspect-styles__elem"
|
||||||
|
>
|
||||||
|
<span class="c-toggle-switch__label">Condition Set output as label:
|
||||||
|
<span v-if="useConditionSetOutputAsLabel"> Yes</span><span v-else> No</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<FontStyleEditor
|
<FontStyleEditor
|
||||||
v-if="canStyleFont"
|
v-if="canStyleFont"
|
||||||
:font-style="consolidatedFontStyle"
|
:font-style="consolidatedFontStyle"
|
||||||
@ -172,7 +193,8 @@ export default {
|
|||||||
selectedConditionId: '',
|
selectedConditionId: '',
|
||||||
items: [],
|
items: [],
|
||||||
domainObject: undefined,
|
domainObject: undefined,
|
||||||
consolidatedFontStyle: {}
|
consolidatedFontStyle: {},
|
||||||
|
useConditionSetOutputAsLabel: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -187,6 +209,11 @@ export default {
|
|||||||
allowEditing() {
|
allowEditing() {
|
||||||
return this.isEditing && !this.locked;
|
return this.isEditing && !this.locked;
|
||||||
},
|
},
|
||||||
|
isConditionWidget() {
|
||||||
|
const hasConditionWidgetObjects = this.domainObjectsById && Object.values(this.domainObjectsById).some((object) => object.type === 'conditionWidget');
|
||||||
|
|
||||||
|
return (hasConditionWidgetObjects || (this.domainObject && this.domainObject.type === 'conditionWidget'));
|
||||||
|
},
|
||||||
styleableFontItems() {
|
styleableFontItems() {
|
||||||
return this.selection.filter(selectionPath => {
|
return this.selection.filter(selectionPath => {
|
||||||
const item = selectionPath[0].context.item;
|
const item = selectionPath[0].context.item;
|
||||||
@ -205,28 +232,6 @@ export default {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
computedconsolidatedFontStyle() {
|
|
||||||
let consolidatedFontStyle;
|
|
||||||
const styles = [];
|
|
||||||
|
|
||||||
this.styleableFontItems.forEach(styleable => {
|
|
||||||
const fontStyle = this.getFontStyle(styleable[0]);
|
|
||||||
|
|
||||||
styles.push(fontStyle);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (styles.length) {
|
|
||||||
const hasConsolidatedFontSize = styles.length && styles.every((fontStyle, i, arr) => fontStyle.fontSize === arr[0].fontSize);
|
|
||||||
const hasConsolidatedFont = styles.length && styles.every((fontStyle, i, arr) => fontStyle.font === arr[0].font);
|
|
||||||
|
|
||||||
consolidatedFontStyle = {
|
|
||||||
fontSize: hasConsolidatedFontSize ? styles[0].fontSize : NON_SPECIFIC,
|
|
||||||
font: hasConsolidatedFont ? styles[0].font : NON_SPECIFIC
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return consolidatedFontStyle;
|
|
||||||
},
|
|
||||||
nonSpecificFontProperties() {
|
nonSpecificFontProperties() {
|
||||||
if (!this.consolidatedFontStyle) {
|
if (!this.consolidatedFontStyle) {
|
||||||
return [];
|
return [];
|
||||||
@ -247,6 +252,8 @@ export default {
|
|||||||
this.previewAction = new PreviewAction(this.openmct);
|
this.previewAction = new PreviewAction(this.openmct);
|
||||||
this.isMultipleSelection = this.selection.length > 1;
|
this.isMultipleSelection = this.selection.length > 1;
|
||||||
this.getObjectsAndItemsFromSelection();
|
this.getObjectsAndItemsFromSelection();
|
||||||
|
this.useConditionSetOutputAsLabel = this.getConfigurationForLabel();
|
||||||
|
|
||||||
if (!this.isMultipleSelection) {
|
if (!this.isMultipleSelection) {
|
||||||
let objectStyles = this.getObjectStyles();
|
let objectStyles = this.getObjectStyles();
|
||||||
this.initializeStaticStyle(objectStyles);
|
this.initializeStaticStyle(objectStyles);
|
||||||
@ -264,6 +271,12 @@ export default {
|
|||||||
this.stylesManager.on('styleSelected', this.applyStyleToSelection);
|
this.stylesManager.on('styleSelected', this.applyStyleToSelection);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
getConfigurationForLabel() {
|
||||||
|
const childObjectUsesLabels = Object.values(this.domainObjectsById || {}).some((object) => object.configuration && object.configuration.useConditionSetOutputAsLabel);
|
||||||
|
const domainObjectUsesLabels = this.domainObject && this.domainObject.configuration && this.domainObject.configuration.useConditionSetOutputAsLabel;
|
||||||
|
|
||||||
|
return childObjectUsesLabels || domainObjectUsesLabels;
|
||||||
|
},
|
||||||
getObjectStyles() {
|
getObjectStyles() {
|
||||||
let objectStyles;
|
let objectStyles;
|
||||||
if (this.domainObjectsById) {
|
if (this.domainObjectsById) {
|
||||||
@ -487,13 +500,14 @@ export default {
|
|||||||
|
|
||||||
this.conditions[conditionConfiguration.id] = conditionConfiguration;
|
this.conditions[conditionConfiguration.id] = conditionConfiguration;
|
||||||
let foundStyle = this.findStyleByConditionId(conditionConfiguration.id);
|
let foundStyle = this.findStyleByConditionId(conditionConfiguration.id);
|
||||||
|
let output = { output: conditionConfiguration.configuration.output };
|
||||||
if (foundStyle) {
|
if (foundStyle) {
|
||||||
foundStyle.style = Object.assign((this.canHide ? { isStyleInvisible: '' } : {}), this.initialStyles, foundStyle.style);
|
foundStyle.style = Object.assign((this.canHide ? { isStyleInvisible: '' } : {}), this.initialStyles, foundStyle.style, output);
|
||||||
conditionalStyles.push(foundStyle);
|
conditionalStyles.push(foundStyle);
|
||||||
} else {
|
} else {
|
||||||
conditionalStyles.splice(index, 0, {
|
conditionalStyles.splice(index, 0, {
|
||||||
conditionId: conditionConfiguration.id,
|
conditionId: conditionConfiguration.id,
|
||||||
style: Object.assign((this.canHide ? { isStyleInvisible: '' } : {}), this.initialStyles)
|
style: Object.assign((this.canHide ? { isStyleInvisible: '' } : {}), this.initialStyles, output)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -715,6 +729,12 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
objectStyle.styles.forEach((conditionalStyle, index) => {
|
objectStyle.styles.forEach((conditionalStyle, index) => {
|
||||||
let style = {};
|
let style = {};
|
||||||
|
if (domainObject.configuration.useConditionSetOutputAsLabel) {
|
||||||
|
style.output = conditionalStyle.style.output;
|
||||||
|
} else {
|
||||||
|
style.output = '';
|
||||||
|
}
|
||||||
|
|
||||||
Object.keys(item.applicableStyles).concat(['isStyleInvisible']).forEach(key => {
|
Object.keys(item.applicableStyles).concat(['isStyleInvisible']).forEach(key => {
|
||||||
style[key] = conditionalStyle.style[key];
|
style[key] = conditionalStyle.style[key];
|
||||||
});
|
});
|
||||||
@ -731,10 +751,21 @@ export default {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
domainObjectStyles = {
|
if (domainObject.configuration.useConditionSetOutputAsLabel !== true) {
|
||||||
...domainObjectStyles,
|
let objectConditionStyle = JSON.parse(JSON.stringify(objectStyle));
|
||||||
...objectStyle
|
objectConditionStyle.styles.forEach((conditionalStyle) => {
|
||||||
};
|
conditionalStyle.style.output = '';
|
||||||
|
});
|
||||||
|
domainObjectStyles = {
|
||||||
|
...domainObjectStyles,
|
||||||
|
...objectConditionStyle
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
domainObjectStyles = {
|
||||||
|
...domainObjectStyles,
|
||||||
|
...objectStyle
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return domainObjectStyles;
|
return domainObjectStyles;
|
||||||
@ -743,6 +774,17 @@ export default {
|
|||||||
this.selectedConditionId = conditionId;
|
this.selectedConditionId = conditionId;
|
||||||
this.getAndPersistStyles();
|
this.getAndPersistStyles();
|
||||||
},
|
},
|
||||||
|
persistLabelConfiguration() {
|
||||||
|
if (this.domainObjectsById) {
|
||||||
|
Object.values(this.domainObjectsById).forEach((object) => {
|
||||||
|
this.openmct.objects.mutate(object, 'configuration.useConditionSetOutputAsLabel', this.useConditionSetOutputAsLabel);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.openmct.objects.mutate(this.domainObject, 'configuration.useConditionSetOutputAsLabel', this.useConditionSetOutputAsLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getAndPersistStyles();
|
||||||
|
},
|
||||||
persist(domainObject, style) {
|
persist(domainObject, style) {
|
||||||
this.openmct.objects.mutate(domainObject, 'configuration.objectStyles', style);
|
this.openmct.objects.mutate(domainObject, 'configuration.objectStyles', style);
|
||||||
},
|
},
|
||||||
@ -863,6 +905,10 @@ export default {
|
|||||||
const layoutItemType = selectionPath[0].context.layoutItem && selectionPath[0].context.layoutItem.type;
|
const layoutItemType = selectionPath[0].context.layoutItem && selectionPath[0].context.layoutItem.type;
|
||||||
|
|
||||||
return layoutItemType && layoutItemType !== 'subobject-view';
|
return layoutItemType && layoutItemType !== 'subobject-view';
|
||||||
|
},
|
||||||
|
updateConditionSetOutputLabel(event) {
|
||||||
|
this.useConditionSetOutputAsLabel = event.target.checked === true;
|
||||||
|
this.persistLabelConfiguration();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -39,12 +39,15 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__elem {
|
||||||
|
border-bottom: 1px solid $colorInteriorBorder;
|
||||||
|
padding-bottom: $interiorMargin;
|
||||||
|
}
|
||||||
|
|
||||||
&__condition-set {
|
&__condition-set {
|
||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
border-bottom: 1px solid $colorInteriorBorder;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
padding-bottom: $interiorMargin;
|
|
||||||
|
|
||||||
.c-object-label {
|
.c-object-label {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
@ -133,6 +133,168 @@ describe('the plugin', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('the condition set usage for condition widgets', () => {
|
||||||
|
let conditionWidgetItem;
|
||||||
|
let selection;
|
||||||
|
let component;
|
||||||
|
let styleViewComponentObject;
|
||||||
|
const conditionSetDomainObject = {
|
||||||
|
"configuration": {
|
||||||
|
"conditionTestData": [
|
||||||
|
{
|
||||||
|
"telemetry": "",
|
||||||
|
"metadata": "",
|
||||||
|
"input": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"conditionCollection": [
|
||||||
|
{
|
||||||
|
"id": "39584410-cbf9-499e-96dc-76f27e69885d",
|
||||||
|
"configuration": {
|
||||||
|
"name": "Unnamed Condition",
|
||||||
|
"output": "Sine > 0",
|
||||||
|
"trigger": "all",
|
||||||
|
"criteria": [
|
||||||
|
{
|
||||||
|
"id": "85fbb2f7-7595-42bd-9767-a932266c5225",
|
||||||
|
"telemetry": {
|
||||||
|
"namespace": "",
|
||||||
|
"key": "be0ba97f-b510-4f40-a18d-4ff121d5ea1a"
|
||||||
|
},
|
||||||
|
"operation": "greaterThan",
|
||||||
|
"input": [
|
||||||
|
"0"
|
||||||
|
],
|
||||||
|
"metadata": "sin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "35400132-63b0-425c-ac30-8197df7d5862",
|
||||||
|
"telemetry": "any",
|
||||||
|
"operation": "enumValueIs",
|
||||||
|
"input": [
|
||||||
|
"0"
|
||||||
|
],
|
||||||
|
"metadata": "state"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"summary": "Match if all criteria are met: Sine Wave Generator Sine > 0 and any telemetry State is OFF "
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"isDefault": true,
|
||||||
|
"id": "2532d90a-e0d6-4935-b546-3123522da2de",
|
||||||
|
"configuration": {
|
||||||
|
"name": "Default",
|
||||||
|
"output": "Default",
|
||||||
|
"trigger": "all",
|
||||||
|
"criteria": [
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"summary": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"composition": [
|
||||||
|
{
|
||||||
|
"namespace": "",
|
||||||
|
"key": "be0ba97f-b510-4f40-a18d-4ff121d5ea1a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"namespace": "",
|
||||||
|
"key": "077ffa67-e78f-4e99-80e0-522ac33a3888"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"telemetry": {
|
||||||
|
},
|
||||||
|
"name": "Condition Set",
|
||||||
|
"type": "conditionSet",
|
||||||
|
"identifier": {
|
||||||
|
"namespace": "",
|
||||||
|
"key": "863012c1-f6ca-4ab0-aed7-fd43d5e4cd12"
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
conditionWidgetItem = {
|
||||||
|
"label": "Condition Widget",
|
||||||
|
"conditionalLabel": "",
|
||||||
|
"configuration": {
|
||||||
|
},
|
||||||
|
"name": "Condition Widget",
|
||||||
|
"type": "conditionWidget",
|
||||||
|
"identifier": {
|
||||||
|
"namespace": "",
|
||||||
|
"key": "c5e636c1-6771-4c9c-b933-8665cab189b3"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
selection = [
|
||||||
|
[{
|
||||||
|
context: {
|
||||||
|
"item": conditionWidgetItem,
|
||||||
|
"supportsMultiSelect": false
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
];
|
||||||
|
let viewContainer = document.createElement('div');
|
||||||
|
child.append(viewContainer);
|
||||||
|
component = new Vue({
|
||||||
|
el: viewContainer,
|
||||||
|
components: {
|
||||||
|
StylesView
|
||||||
|
},
|
||||||
|
provide: {
|
||||||
|
openmct: openmct,
|
||||||
|
selection: selection,
|
||||||
|
stylesManager
|
||||||
|
},
|
||||||
|
template: '<styles-view/>'
|
||||||
|
});
|
||||||
|
|
||||||
|
return Vue.nextTick().then(() => {
|
||||||
|
styleViewComponentObject = component.$root.$children[0];
|
||||||
|
styleViewComponentObject.setEditState(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
component.$destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not include the output label when the flag is disabled', () => {
|
||||||
|
styleViewComponentObject.conditionSetDomainObject = conditionSetDomainObject;
|
||||||
|
styleViewComponentObject.conditionalStyles = [];
|
||||||
|
styleViewComponentObject.initializeConditionalStyles();
|
||||||
|
expect(styleViewComponentObject.conditionalStyles.length).toBe(2);
|
||||||
|
|
||||||
|
return Vue.nextTick().then(() => {
|
||||||
|
const hasNoOutput = styleViewComponentObject.domainObject.configuration.objectStyles.styles.every((style) => {
|
||||||
|
return style.style.output === '' || style.style.output === undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(hasNoOutput).toBeTrue();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('includes the output label when the flag is enabled', () => {
|
||||||
|
styleViewComponentObject.conditionSetDomainObject = conditionSetDomainObject;
|
||||||
|
styleViewComponentObject.conditionalStyles = [];
|
||||||
|
styleViewComponentObject.initializeConditionalStyles();
|
||||||
|
expect(styleViewComponentObject.conditionalStyles.length).toBe(2);
|
||||||
|
|
||||||
|
styleViewComponentObject.useConditionSetOutputAsLabel = true;
|
||||||
|
styleViewComponentObject.persistLabelConfiguration();
|
||||||
|
|
||||||
|
return Vue.nextTick().then(() => {
|
||||||
|
const outputs = styleViewComponentObject.domainObject.configuration.objectStyles.styles.map((style) => {
|
||||||
|
return style.style.output;
|
||||||
|
});
|
||||||
|
expect(outputs.join(',')).toEqual('Sine > 0,Default');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
describe('the condition set usage for multiple display layout items', () => {
|
describe('the condition set usage for multiple display layout items', () => {
|
||||||
let displayLayoutItem;
|
let displayLayoutItem;
|
||||||
let lineLayoutItem;
|
let lineLayoutItem;
|
||||||
@ -449,6 +611,10 @@ describe('the plugin', function () {
|
|||||||
const applicableStyles = getApplicableStylesForItem(styleViewComponentObject.domainObject, item);
|
const applicableStyles = getApplicableStylesForItem(styleViewComponentObject.domainObject, item);
|
||||||
const applicableStylesKeys = Object.keys(applicableStyles).concat(['isStyleInvisible']);
|
const applicableStylesKeys = Object.keys(applicableStyles).concat(['isStyleInvisible']);
|
||||||
Object.keys(foundStyle.style).forEach((key) => {
|
Object.keys(foundStyle.style).forEach((key) => {
|
||||||
|
if (key === 'output') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
expect(applicableStylesKeys.indexOf(key)).toBeGreaterThan(-1);
|
expect(applicableStylesKeys.indexOf(key)).toBeGreaterThan(-1);
|
||||||
expect(foundStyle.style[key]).toEqual(conditionalStyle.style[key]);
|
expect(foundStyle.style[key]).toEqual(conditionalStyle.style[key]);
|
||||||
});
|
});
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
:href="url"
|
:href="url"
|
||||||
>
|
>
|
||||||
<div class="c-condition-widget__label">
|
<div class="c-condition-widget__label">
|
||||||
{{ internalDomainObject.label }}
|
{{ internalDomainObject.conditionalLabel || internalDomainObject.label }}
|
||||||
</div>
|
</div>
|
||||||
</component>
|
</component>
|
||||||
</template>
|
</template>
|
||||||
|
@ -27,12 +27,15 @@ export default function plugin() {
|
|||||||
openmct.objectViews.addProvider(new ConditionWidgetViewProvider(openmct));
|
openmct.objectViews.addProvider(new ConditionWidgetViewProvider(openmct));
|
||||||
|
|
||||||
openmct.types.addType('conditionWidget', {
|
openmct.types.addType('conditionWidget', {
|
||||||
|
key: 'conditionWidget',
|
||||||
name: "Condition Widget",
|
name: "Condition Widget",
|
||||||
description: "A button that can be used on its own, or dynamically styled with a Condition Set.",
|
description: "A button that can be used on its own, or dynamically styled with a Condition Set.",
|
||||||
creatable: true,
|
creatable: true,
|
||||||
cssClass: 'icon-condition-widget',
|
cssClass: 'icon-condition-widget',
|
||||||
initialize(domainObject) {
|
initialize(domainObject) {
|
||||||
|
domainObject.configuration = {};
|
||||||
domainObject.label = 'Condition Widget';
|
domainObject.label = 'Condition Widget';
|
||||||
|
domainObject.conditionalLabel = '';
|
||||||
},
|
},
|
||||||
form: [
|
form: [
|
||||||
{
|
{
|
||||||
|
103
src/plugins/conditionWidget/pluginSpec.js
Normal file
103
src/plugins/conditionWidget/pluginSpec.js
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import { createOpenMct, resetApplicationState } from "utils/testing";
|
||||||
|
import ConditionWidgetPlugin from "./plugin";
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
describe('the plugin', function () {
|
||||||
|
let objectDef;
|
||||||
|
let element;
|
||||||
|
let child;
|
||||||
|
let openmct;
|
||||||
|
let mockObjectPath;
|
||||||
|
|
||||||
|
beforeEach((done) => {
|
||||||
|
mockObjectPath = [
|
||||||
|
{
|
||||||
|
name: 'mock folder',
|
||||||
|
type: 'fake-folder',
|
||||||
|
identifier: {
|
||||||
|
key: 'mock-folder',
|
||||||
|
namespace: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'mock parent folder',
|
||||||
|
type: 'conditionWidget',
|
||||||
|
identifier: {
|
||||||
|
key: 'mock-parent-folder',
|
||||||
|
namespace: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const timeSystem = {
|
||||||
|
timeSystemKey: 'utc',
|
||||||
|
bounds: {
|
||||||
|
start: 1597160002854,
|
||||||
|
end: 1597181232854
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
openmct = createOpenMct(timeSystem);
|
||||||
|
openmct.install(new ConditionWidgetPlugin());
|
||||||
|
|
||||||
|
objectDef = openmct.types.get('conditionWidget').definition;
|
||||||
|
|
||||||
|
element = document.createElement('div');
|
||||||
|
element.style.width = '640px';
|
||||||
|
element.style.height = '480px';
|
||||||
|
child = document.createElement('div');
|
||||||
|
child.style.width = '640px';
|
||||||
|
child.style.height = '480px';
|
||||||
|
element.appendChild(child);
|
||||||
|
|
||||||
|
openmct.on('start', done);
|
||||||
|
openmct.startHeadless();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
return resetApplicationState(openmct);
|
||||||
|
});
|
||||||
|
|
||||||
|
let mockObject = {
|
||||||
|
name: 'Condition Widget',
|
||||||
|
key: 'conditionWidget',
|
||||||
|
creatable: true
|
||||||
|
};
|
||||||
|
|
||||||
|
it('defines a conditionWidget object type with the correct key', () => {
|
||||||
|
expect(objectDef.key).toEqual(mockObject.key);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('the conditionWidget object', () => {
|
||||||
|
it('is creatable', () => {
|
||||||
|
expect(objectDef.creatable).toEqual(mockObject.creatable);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('the view', () => {
|
||||||
|
let conditionWidgetView;
|
||||||
|
let testViewObject;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
testViewObject = {
|
||||||
|
id: "test-object",
|
||||||
|
identifier: {
|
||||||
|
key: "test-object",
|
||||||
|
namespace: ''
|
||||||
|
},
|
||||||
|
type: "conditionWidget"
|
||||||
|
};
|
||||||
|
|
||||||
|
const applicableViews = openmct.objectViews.get(testViewObject, mockObjectPath);
|
||||||
|
conditionWidgetView = applicableViews.find((viewProvider) => viewProvider.key === 'conditionWidget');
|
||||||
|
let view = conditionWidgetView.view(testViewObject, element);
|
||||||
|
view.show(child, true);
|
||||||
|
|
||||||
|
return Vue.nextTick();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('provides a view', () => {
|
||||||
|
expect(conditionWidgetView).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -38,10 +38,14 @@ export default {
|
|||||||
this.objectStyle = this.getObjectStyleForItem(this.parentDomainObject.configuration.objectStyles);
|
this.objectStyle = this.getObjectStyleForItem(this.parentDomainObject.configuration.objectStyles);
|
||||||
this.initObjectStyles();
|
this.initObjectStyles();
|
||||||
},
|
},
|
||||||
destroyed() {
|
beforeDestroy() {
|
||||||
if (this.stopListeningObjectStyles) {
|
if (this.stopListeningObjectStyles) {
|
||||||
this.stopListeningObjectStyles();
|
this.stopListeningObjectStyles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.styleRuleManager) {
|
||||||
|
this.styleRuleManager.destroy();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getObjectStyleForItem(objectStyle) {
|
getObjectStyleForItem(objectStyle) {
|
||||||
|
@ -191,6 +191,12 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this.domainObject && this.domainObject.type === 'conditionWidget' && keys.includes('output')) {
|
||||||
|
this.openmct.objects.mutate(this.domainObject, 'conditionalLabel', styleObj.output);
|
||||||
|
} else {
|
||||||
|
this.openmct.objects.mutate(this.domainObject, 'conditionalLabel', '');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
updateView(immediatelySelect) {
|
updateView(immediatelySelect) {
|
||||||
this.clear();
|
this.clear();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user