325
src/plugins/condition/components/Condition.vue
Normal file
325
src/plugins/condition/components/Condition.vue
Normal file
@@ -0,0 +1,325 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
<template>
|
||||
<div v-if="isEditing"
|
||||
class="c-condition c-condition--edit js-condition-drag-wrapper"
|
||||
>
|
||||
<!-- Edit view -->
|
||||
<div class="c-condition__header">
|
||||
<span class="c-condition__drag-grippy c-grippy c-grippy--vertical-drag"
|
||||
title="Drag to reorder conditions"
|
||||
:class="[{ 'is-enabled': !condition.isDefault }, { 'hide-nice': condition.isDefault }]"
|
||||
:draggable="!condition.isDefault"
|
||||
@dragstart="dragStart"
|
||||
@dragstop="dragStop"
|
||||
@dragover.stop
|
||||
></span>
|
||||
|
||||
<span class="c-condition__disclosure c-disclosure-triangle c-tree__item__view-control is-enabled"
|
||||
:class="{ 'c-disclosure-triangle--expanded': expanded }"
|
||||
@click="expanded = !expanded"
|
||||
></span>
|
||||
|
||||
<span class="c-condition__name">{{ condition.configuration.name }}</span>
|
||||
<!-- TODO: description should be derived from criteria -->
|
||||
<span class="c-condition__summary">
|
||||
<template v-if="!canEvaluateCriteria">
|
||||
Define criteria
|
||||
</template>
|
||||
<span v-else>
|
||||
<condition-description :show-label="false"
|
||||
:condition="condition"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<div class="c-condition__buttons">
|
||||
<button v-if="!condition.isDefault"
|
||||
class="c-click-icon c-condition__duplicate-button icon-duplicate"
|
||||
title="Duplicate this condition"
|
||||
@click="cloneCondition"
|
||||
></button>
|
||||
|
||||
<button v-if="!condition.isDefault"
|
||||
class="c-click-icon c-condition__delete-button icon-trash"
|
||||
title="Delete this condition"
|
||||
@click="removeCondition"
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="expanded"
|
||||
class="c-condition__definition c-cdef"
|
||||
>
|
||||
<span class="c-cdef__separator c-row-separator"></span>
|
||||
<span class="c-cdef__label">Condition Name</span>
|
||||
<span class="c-cdef__controls">
|
||||
<input v-model="condition.configuration.name"
|
||||
class="t-condition-input__name"
|
||||
type="text"
|
||||
@blur="persist"
|
||||
>
|
||||
</span>
|
||||
|
||||
<span class="c-cdef__label">Output</span>
|
||||
<span class="c-cdef__controls">
|
||||
<span class="c-cdef__control">
|
||||
<select v-model="selectedOutputSelection"
|
||||
@change="setOutputValue"
|
||||
>
|
||||
<option v-for="option in outputOptions"
|
||||
:key="option"
|
||||
:value="option"
|
||||
>
|
||||
{{ initCap(option) }}
|
||||
</option>
|
||||
</select>
|
||||
</span>
|
||||
<span class="c-cdef__control">
|
||||
<input v-if="selectedOutputSelection === outputOptions[2]"
|
||||
v-model="condition.configuration.output"
|
||||
class="t-condition-name-input"
|
||||
type="text"
|
||||
@blur="persist"
|
||||
>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<div v-if="!condition.isDefault"
|
||||
class="c-cdef__match-and-criteria"
|
||||
>
|
||||
<span class="c-cdef__separator c-row-separator"></span>
|
||||
<span class="c-cdef__label">Match</span>
|
||||
<span class="c-cdef__controls">
|
||||
<select v-model="condition.configuration.trigger"
|
||||
@change="persist"
|
||||
>
|
||||
<option v-for="option in triggers"
|
||||
:key="option.value"
|
||||
:value="option.value"
|
||||
> {{ option.label }}</option>
|
||||
</select>
|
||||
</span>
|
||||
|
||||
<template v-if="telemetry.length || condition.configuration.criteria.length">
|
||||
<div v-for="(criterion, index) in condition.configuration.criteria"
|
||||
:key="index"
|
||||
class="c-cdef__criteria"
|
||||
>
|
||||
<Criterion :telemetry="telemetry"
|
||||
:criterion="criterion"
|
||||
:index="index"
|
||||
:trigger="condition.configuration.trigger"
|
||||
:is-default="condition.configuration.criteria.length === 1"
|
||||
@persist="persist"
|
||||
/>
|
||||
<div class="c-cdef__criteria__buttons">
|
||||
<button class="c-click-icon c-cdef__criteria-duplicate-button icon-duplicate"
|
||||
title="Duplicate this criteria"
|
||||
@click="cloneCriterion(index)"
|
||||
></button>
|
||||
<button v-if="!(condition.configuration.criteria.length === 1)"
|
||||
class="c-click-icon c-cdef__criteria-duplicate-button icon-trash"
|
||||
title="Delete this criteria"
|
||||
@click="removeCriterion(index)"
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="c-cdef__separator c-row-separator"></div>
|
||||
<div class="c-cdef__controls"
|
||||
:disabled="!telemetry.length"
|
||||
>
|
||||
<button
|
||||
class="c-cdef__add-criteria-button c-button c-button--labeled icon-plus"
|
||||
@click="addCriteria"
|
||||
>
|
||||
<span class="c-button__label">Add Criteria</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else
|
||||
class="c-condition c-condition--browse"
|
||||
>
|
||||
<!-- Browse view -->
|
||||
<div class="c-condition__header">
|
||||
<span class="c-condition__name">
|
||||
{{ condition.configuration.name }}
|
||||
</span>
|
||||
<span class="c-condition__output">
|
||||
Output: {{ condition.configuration.output }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="c-condition__summary">
|
||||
<condition-description :show-label="false"
|
||||
:condition="condition"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Criterion from './Criterion.vue';
|
||||
import ConditionDescription from "./ConditionDescription.vue";
|
||||
import { TRIGGER, TRIGGER_LABEL } from "@/plugins/condition/utils/constants";
|
||||
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
components: {
|
||||
Criterion,
|
||||
ConditionDescription
|
||||
},
|
||||
props: {
|
||||
condition: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
conditionIndex: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
isEditing: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
telemetry: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentCriteria: this.currentCriteria,
|
||||
expanded: true,
|
||||
trigger: 'all',
|
||||
selectedOutputSelection: '',
|
||||
outputOptions: ['false', 'true', 'string'],
|
||||
criterionIndex: 0,
|
||||
selectedTelemetryName: '',
|
||||
selectedFieldName: ''
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
triggers() {
|
||||
const keys = Object.keys(TRIGGER);
|
||||
const triggerOptions = [];
|
||||
keys.forEach((trigger) => {
|
||||
triggerOptions.push({
|
||||
value: TRIGGER[trigger],
|
||||
label: TRIGGER_LABEL[TRIGGER[trigger]]
|
||||
});
|
||||
});
|
||||
return triggerOptions;
|
||||
},
|
||||
canEvaluateCriteria: function () {
|
||||
let criteria = this.condition.configuration.criteria;
|
||||
if (criteria.length) {
|
||||
let lastCriterion = criteria[criteria.length - 1];
|
||||
if (lastCriterion.telemetry &&
|
||||
lastCriterion.operation &&
|
||||
(lastCriterion.input.length ||
|
||||
lastCriterion.operation === 'isDefined' ||
|
||||
lastCriterion.operation === 'isUndefined')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
this.destroy();
|
||||
},
|
||||
mounted() {
|
||||
this.setOutputSelection();
|
||||
},
|
||||
methods: {
|
||||
setOutputSelection() {
|
||||
let conditionOutput = this.condition.configuration.output;
|
||||
if (conditionOutput) {
|
||||
if (conditionOutput !== 'false' && conditionOutput !== 'true') {
|
||||
this.selectedOutputSelection = 'string';
|
||||
} else {
|
||||
this.selectedOutputSelection = conditionOutput;
|
||||
}
|
||||
}
|
||||
},
|
||||
setOutputValue() {
|
||||
if (this.selectedOutputSelection === 'string') {
|
||||
this.condition.configuration.output = '';
|
||||
} else {
|
||||
this.condition.configuration.output = this.selectedOutputSelection;
|
||||
}
|
||||
this.persist();
|
||||
},
|
||||
addCriteria() {
|
||||
const criteriaObject = {
|
||||
telemetry: '',
|
||||
operation: '',
|
||||
input: '',
|
||||
metadata: ''
|
||||
};
|
||||
this.condition.configuration.criteria.push(criteriaObject);
|
||||
},
|
||||
dragStart(e) {
|
||||
e.dataTransfer.setData('dragging', e.target); // required for FF to initiate drag
|
||||
e.dataTransfer.effectAllowed = "copyMove";
|
||||
e.dataTransfer.setDragImage(e.target.closest('.js-condition-drag-wrapper'), 0, 0);
|
||||
this.$emit('setMoveIndex', this.conditionIndex);
|
||||
},
|
||||
dragStop(e) {
|
||||
e.dataTransfer.clearData();
|
||||
},
|
||||
destroy() {
|
||||
},
|
||||
removeCondition(ev) {
|
||||
this.$emit('removeCondition', this.conditionIndex);
|
||||
},
|
||||
cloneCondition(ev) {
|
||||
this.$emit('cloneCondition', {
|
||||
condition: this.condition,
|
||||
index: this.conditionIndex
|
||||
});
|
||||
},
|
||||
removeCriterion(index) {
|
||||
this.condition.configuration.criteria.splice(index, 1);
|
||||
this.persist();
|
||||
},
|
||||
cloneCriterion(index) {
|
||||
const clonedCriterion = JSON.parse(JSON.stringify(this.condition.configuration.criteria[index]));
|
||||
this.condition.configuration.criteria.splice(index + 1, 0, clonedCriterion);
|
||||
this.persist();
|
||||
},
|
||||
persist() {
|
||||
this.$emit('updateCondition', {
|
||||
condition: this.condition,
|
||||
index: this.conditionIndex
|
||||
});
|
||||
},
|
||||
initCap: function (str) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
245
src/plugins/condition/components/ConditionCollection.vue
Normal file
245
src/plugins/condition/components/ConditionCollection.vue
Normal file
@@ -0,0 +1,245 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
<template>
|
||||
<section id="conditionCollection"
|
||||
class="c-cs__conditions"
|
||||
:class="{ 'is-expanded': expanded }"
|
||||
>
|
||||
<div class="c-cs__header c-section__header">
|
||||
<span
|
||||
class="c-disclosure-triangle c-tree__item__view-control is-enabled"
|
||||
:class="{ 'c-disclosure-triangle--expanded': expanded }"
|
||||
@click="expanded = !expanded"
|
||||
></span>
|
||||
<div class="c-cs__header-label c-section__label">Conditions</div>
|
||||
</div>
|
||||
<div v-if="expanded"
|
||||
class="c-cs__content"
|
||||
>
|
||||
<div v-show="isEditing"
|
||||
class="hint"
|
||||
:class="{ 's-status-icon-warning-lo': !telemetryObjs.length }"
|
||||
>
|
||||
<template v-if="!telemetryObjs.length">Drag telemetry into this Condition Set to configure Conditions and add criteria.</template>
|
||||
<template v-else>The first condition to match is the one that is applied. Drag conditions to reorder.</template>
|
||||
</div>
|
||||
|
||||
<button
|
||||
v-show="isEditing"
|
||||
id="addCondition"
|
||||
class="c-button c-button--major icon-plus labeled"
|
||||
@click="addCondition"
|
||||
>
|
||||
<span class="c-cs-button__label">Add Condition</span>
|
||||
</button>
|
||||
|
||||
<div class="c-cs__conditions-h">
|
||||
<div v-for="(condition, index) in conditionCollection"
|
||||
:key="condition.id"
|
||||
class="c-condition-h"
|
||||
>
|
||||
<div v-if="isEditing"
|
||||
class="c-c__drag-ghost"
|
||||
@drop.prevent="dropCondition"
|
||||
@dragenter="dragEnter"
|
||||
@dragleave="dragLeave"
|
||||
@dragover.prevent
|
||||
></div>
|
||||
<Condition :condition="condition"
|
||||
:condition-index="index"
|
||||
:telemetry="telemetryObjs"
|
||||
:is-editing="isEditing"
|
||||
@updateCondition="updateCondition"
|
||||
@removeCondition="removeCondition"
|
||||
@cloneCondition="cloneCondition"
|
||||
@setMoveIndex="setMoveIndex"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Condition from './Condition.vue';
|
||||
import ConditionManager from '../ConditionManager';
|
||||
|
||||
export default {
|
||||
inject: ['openmct', 'domainObject'],
|
||||
components: {
|
||||
Condition
|
||||
},
|
||||
props: {
|
||||
isEditing: Boolean,
|
||||
testData: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => {
|
||||
return {
|
||||
applied: false,
|
||||
conditionTestInputs: []
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
expanded: true,
|
||||
conditionCollection: [],
|
||||
conditionResults: {},
|
||||
conditions: [],
|
||||
telemetryObjs: [],
|
||||
moveIndex: Number,
|
||||
isDragging: false,
|
||||
defaultOutput: undefined
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
defaultOutput(newOutput, oldOutput) {
|
||||
this.$emit('updateDefaultOutput', newOutput);
|
||||
},
|
||||
testData: {
|
||||
handler() {
|
||||
this.updateTestData();
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
this.composition.off('add', this.addTelemetryObject);
|
||||
this.composition.off('remove', this.removeTelemetryObject);
|
||||
if(this.conditionManager) {
|
||||
this.conditionManager.off('conditionSetResultUpdated', this.handleConditionSetResultUpdated);
|
||||
this.conditionManager.destroy();
|
||||
}
|
||||
if (this.stopObservingForChanges) {
|
||||
this.stopObservingForChanges();
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.composition = this.openmct.composition.get(this.domainObject);
|
||||
this.composition.on('add', this.addTelemetryObject);
|
||||
this.composition.on('remove', this.removeTelemetryObject);
|
||||
this.composition.load();
|
||||
this.conditionCollection = this.domainObject.configuration.conditionCollection;
|
||||
this.observeForChanges();
|
||||
this.conditionManager = new ConditionManager(this.domainObject, this.openmct);
|
||||
this.conditionManager.on('conditionSetResultUpdated', this.handleConditionSetResultUpdated);
|
||||
this.updateDefaultCondition();
|
||||
},
|
||||
methods: {
|
||||
handleConditionSetResultUpdated(data) {
|
||||
this.$emit('conditionSetResultUpdated', data)
|
||||
},
|
||||
observeForChanges() {
|
||||
this.stopObservingForChanges = this.openmct.objects.observe(this.domainObject, 'configuration.conditionCollection', (newConditionCollection) => {
|
||||
this.conditionCollection = newConditionCollection;
|
||||
this.updateDefaultCondition();
|
||||
});
|
||||
},
|
||||
updateDefaultCondition() {
|
||||
const defaultCondition = this.domainObject.configuration.conditionCollection
|
||||
.find(conditionConfiguration => conditionConfiguration.isDefault);
|
||||
this.defaultOutput = defaultCondition.configuration.output;
|
||||
},
|
||||
setMoveIndex(index) {
|
||||
this.moveIndex = index;
|
||||
this.isDragging = true;
|
||||
},
|
||||
dropCondition(e) {
|
||||
let targetIndex = Array.from(document.querySelectorAll('.c-c__drag-ghost')).indexOf(e.target);
|
||||
if (targetIndex > this.moveIndex) { targetIndex-- } // for 'downward' move
|
||||
const oldIndexArr = Object.keys(this.conditionCollection);
|
||||
const move = function (arr, old_index, new_index) {
|
||||
while (old_index < 0) {
|
||||
old_index += arr.length;
|
||||
}
|
||||
while (new_index < 0) {
|
||||
new_index += arr.length;
|
||||
}
|
||||
if (new_index >= arr.length) {
|
||||
var k = new_index - arr.length;
|
||||
while ((k--) + 1) {
|
||||
arr.push(undefined);
|
||||
}
|
||||
}
|
||||
arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
|
||||
return arr;
|
||||
}
|
||||
const newIndexArr = move(oldIndexArr, this.moveIndex, targetIndex);
|
||||
const reorderPlan = [];
|
||||
|
||||
for (let i = 0; i < oldIndexArr.length; i++) {
|
||||
reorderPlan.push({oldIndex: Number(newIndexArr[i]), newIndex: i});
|
||||
}
|
||||
|
||||
this.reorder(reorderPlan);
|
||||
|
||||
e.target.classList.remove("dragging");
|
||||
this.isDragging = false;
|
||||
},
|
||||
dragEnter(e) {
|
||||
if (!this.isDragging) { return }
|
||||
let targetIndex = Array.from(document.querySelectorAll('.c-c__drag-ghost')).indexOf(e.target);
|
||||
if (targetIndex > this.moveIndex) { targetIndex-- } // for 'downward' move
|
||||
if (this.moveIndex === targetIndex) { return }
|
||||
e.target.classList.add("dragging");
|
||||
},
|
||||
dragLeave(e) {
|
||||
e.target.classList.remove("dragging");
|
||||
},
|
||||
addTelemetryObject(domainObject) {
|
||||
this.telemetryObjs.push(domainObject);
|
||||
this.$emit('telemetryUpdated', this.telemetryObjs);
|
||||
},
|
||||
removeTelemetryObject(identifier) {
|
||||
let index = _.findIndex(this.telemetryObjs, (obj) => {
|
||||
let objId = this.openmct.objects.makeKeyString(obj.identifier);
|
||||
let id = this.openmct.objects.makeKeyString(identifier);
|
||||
return objId === id;
|
||||
});
|
||||
if (index > -1) {
|
||||
this.telemetryObjs.splice(index, 1);
|
||||
}
|
||||
},
|
||||
addCondition() {
|
||||
this.conditionManager.addCondition();
|
||||
},
|
||||
updateCondition(data) {
|
||||
this.conditionManager.updateCondition(data.condition, data.index);
|
||||
},
|
||||
removeCondition(index) {
|
||||
this.conditionManager.removeCondition(index);
|
||||
},
|
||||
reorder(reorderPlan) {
|
||||
this.conditionManager.reorderConditions(reorderPlan);
|
||||
},
|
||||
cloneCondition(data) {
|
||||
this.conditionManager.cloneCondition(data.condition, data.index);
|
||||
},
|
||||
updateTestData() {
|
||||
this.conditionManager.updateTestData(this.testData);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
145
src/plugins/condition/components/ConditionDescription.vue
Normal file
145
src/plugins/condition/components/ConditionDescription.vue
Normal file
@@ -0,0 +1,145 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
<template>
|
||||
<div class="c-style__condition-desc">
|
||||
<span v-if="showLabel && condition"
|
||||
class="c-style__condition-desc__name c-condition__name"
|
||||
>
|
||||
{{ condition.configuration.name }}
|
||||
</span>
|
||||
<span v-for="(criterionDescription, index) in criterionDescriptions"
|
||||
:key="criterionDescription"
|
||||
class="c-style__condition-desc__text"
|
||||
>
|
||||
<template v-if="!index">When</template>
|
||||
{{ criterionDescription }}
|
||||
<template v-if="index < (criterionDescriptions.length-1)">{{ triggerDescription }}</template>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { TRIGGER } from "@/plugins/condition/utils/constants";
|
||||
import { OPERATIONS } from "@/plugins/condition/utils/operations";
|
||||
|
||||
export default {
|
||||
name: 'ConditionDescription',
|
||||
inject: [
|
||||
'openmct'
|
||||
],
|
||||
props: {
|
||||
showLabel: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
condition: {
|
||||
type: Object,
|
||||
default() {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
criterionDescriptions: [],
|
||||
triggerDescription: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
condition: {
|
||||
handler(val) {
|
||||
this.getConditionDescription();
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getConditionDescription();
|
||||
},
|
||||
methods: {
|
||||
getTriggerDescription(trigger) {
|
||||
let description = '';
|
||||
switch(trigger) {
|
||||
case TRIGGER.ANY:
|
||||
case TRIGGER.XOR:
|
||||
description = 'or';
|
||||
break;
|
||||
case TRIGGER.ALL:
|
||||
case TRIGGER.NOT: description = 'and';
|
||||
break;
|
||||
}
|
||||
return description;
|
||||
},
|
||||
getConditionDescription() {
|
||||
if (this.condition) {
|
||||
this.triggerDescription = this.getTriggerDescription(this.condition.configuration.trigger);
|
||||
this.criterionDescriptions = [];
|
||||
this.condition.configuration.criteria.forEach((criterion, index) => {
|
||||
this.getCriterionDescription(criterion, index);
|
||||
});
|
||||
if (this.condition.isDefault) {
|
||||
this.criterionDescriptions.splice(0, 0, 'all else fails');
|
||||
}
|
||||
} else {
|
||||
this.criterionDescriptions = [];
|
||||
}
|
||||
},
|
||||
getCriterionDescription(criterion, index) {
|
||||
this.openmct.objects.get(criterion.telemetry).then((telemetryObject) => {
|
||||
if (telemetryObject.type === 'unknown') {
|
||||
let description = `Unknown ${criterion.metadata} ${this.getOperatorText(criterion.operation, criterion.input)}`;
|
||||
this.criterionDescriptions.splice(index, 0, description);
|
||||
} else {
|
||||
let metadataValue = criterion.metadata;
|
||||
let inputValue = criterion.input;
|
||||
if (criterion.metadata) {
|
||||
this.telemetryMetadata = this.openmct.telemetry.getMetadata(telemetryObject);
|
||||
|
||||
const metadataObj = this.telemetryMetadata.valueMetadatas.find((metadata) => metadata.key === criterion.metadata);
|
||||
if (metadataObj) {
|
||||
if (metadataObj.name) {
|
||||
metadataValue = metadataObj.name;
|
||||
}
|
||||
if(metadataObj.enumerations && inputValue.length) {
|
||||
if (metadataObj.enumerations[inputValue[0]] && metadataObj.enumerations[inputValue[0]].string) {
|
||||
inputValue = [metadataObj.enumerations[inputValue[0]].string];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let description = `${telemetryObject.name} ${metadataValue} ${this.getOperatorText(criterion.operation, inputValue)}`;
|
||||
if (this.criterionDescriptions[index]) {
|
||||
this.criterionDescriptions[index] = description;
|
||||
} else {
|
||||
this.criterionDescriptions.splice(index, 0, description);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
getOperatorText(operationName, values) {
|
||||
const found = OPERATIONS.find((operation) => operation.name === operationName);
|
||||
return found ? found.getDescription(values) : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
80
src/plugins/condition/components/ConditionError.vue
Normal file
80
src/plugins/condition/components/ConditionError.vue
Normal file
@@ -0,0 +1,80 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
<template>
|
||||
<div v-if="conditionErrors.length"
|
||||
class="c-condition__errors"
|
||||
>
|
||||
<div v-for="(error, index) in conditionErrors"
|
||||
:key="index"
|
||||
class="u-alert u-alert--block u-alert--with-icon"
|
||||
>{{ error.message.errorText }} {{ error.additionalInfo }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { ERROR } from "@/plugins/condition/utils/constants";
|
||||
|
||||
export default {
|
||||
name: 'ConditionError',
|
||||
inject: [
|
||||
'openmct'
|
||||
],
|
||||
props: {
|
||||
condition: {
|
||||
type: Object,
|
||||
default() {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
conditionErrors: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getConditionErrors();
|
||||
},
|
||||
methods: {
|
||||
getConditionErrors() {
|
||||
if (this.condition) {
|
||||
this.condition.configuration.criteria.forEach((criterion, index) => {
|
||||
this.getCriterionErrors(criterion, index);
|
||||
});
|
||||
}
|
||||
},
|
||||
getCriterionErrors(criterion, index) {
|
||||
this.openmct.objects.get(criterion.telemetry).then((telemetryObject) => {
|
||||
if (telemetryObject.type === 'unknown') {
|
||||
this.conditionErrors.push({
|
||||
message: ERROR.TELEMETRY_NOT_FOUND,
|
||||
additionalInfo: criterion.telemetry ? `Key: ${this.openmct.objects.makeKeyString(criterion.telemetry)}` : ''
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
97
src/plugins/condition/components/ConditionSet.vue
Normal file
97
src/plugins/condition/components/ConditionSet.vue
Normal file
@@ -0,0 +1,97 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
<template>
|
||||
<div class="c-cs">
|
||||
<section class="c-cs__current-output c-section">
|
||||
<div class="c-cs__header c-section__header">
|
||||
<span class="c-cs__header-label c-section__label">Current Output</span>
|
||||
</div>
|
||||
<div class="c-cs__content c-cs__current-output-value">
|
||||
<template v-if="currentConditionOutput">
|
||||
{{ currentConditionOutput }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ defaultConditionOutput }}
|
||||
</template>
|
||||
</div>
|
||||
</section>
|
||||
<TestData :is-editing="isEditing"
|
||||
:test-data="testData"
|
||||
:telemetry="telemetryObjs"
|
||||
@updateTestData="updateTestData"
|
||||
/>
|
||||
<ConditionCollection
|
||||
:is-editing="isEditing"
|
||||
:test-data="testData"
|
||||
@conditionSetResultUpdated="updateCurrentOutput"
|
||||
@updateDefaultOutput="updateDefaultOutput"
|
||||
@telemetryUpdated="updateTelemetry"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TestData from './TestData.vue';
|
||||
import ConditionCollection from './ConditionCollection.vue';
|
||||
|
||||
export default {
|
||||
inject: ["openmct", "domainObject"],
|
||||
components: {
|
||||
TestData,
|
||||
ConditionCollection
|
||||
},
|
||||
props: {
|
||||
isEditing: Boolean
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentConditionOutput: '',
|
||||
defaultConditionOutput: '',
|
||||
telemetryObjs: [],
|
||||
testData: {}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.conditionSetIdentifier = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||
this.testData = {
|
||||
applied: false,
|
||||
conditionTestInputs: this.domainObject.configuration.conditionTestData || []
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
updateCurrentOutput(currentConditionResult) {
|
||||
this.currentConditionOutput = currentConditionResult.output;
|
||||
},
|
||||
updateDefaultOutput(output) {
|
||||
this.currentConditionOutput = output;
|
||||
},
|
||||
updateTelemetry(telemetryObjs) {
|
||||
this.telemetryObjs = telemetryObjs;
|
||||
},
|
||||
updateTestData(testData) {
|
||||
this.testData = testData;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
293
src/plugins/condition/components/Criterion.vue
Normal file
293
src/plugins/condition/components/Criterion.vue
Normal file
@@ -0,0 +1,293 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
<template>
|
||||
<div class="u-contents">
|
||||
<div class="c-cdef__separator c-row-separator"></div>
|
||||
<span class="c-cdef__label">{{ setRowLabel }}</span>
|
||||
<span class="c-cdef__controls">
|
||||
<span class="c-cdef__control">
|
||||
<select ref="telemetrySelect"
|
||||
v-model="criterion.telemetry"
|
||||
@change="updateMetadataOptions"
|
||||
>
|
||||
<option value="">- Select Telemetry -</option>
|
||||
<option value="all">all telemetry</option>
|
||||
<option value="any">any telemetry</option>
|
||||
<option v-for="telemetryOption in telemetry"
|
||||
:key="telemetryOption.identifier.key"
|
||||
:value="telemetryOption.identifier"
|
||||
>
|
||||
{{ telemetryOption.name }}
|
||||
</option>
|
||||
</select>
|
||||
</span>
|
||||
<span v-if="criterion.telemetry"
|
||||
class="c-cdef__control"
|
||||
>
|
||||
<select ref="metadataSelect"
|
||||
v-model="criterion.metadata"
|
||||
@change="updateOperations"
|
||||
>
|
||||
<option value="">- Select Field -</option>
|
||||
<option v-for="option in telemetryMetadataOptions"
|
||||
:key="option.key"
|
||||
:value="option.key"
|
||||
>
|
||||
{{ option.name }}
|
||||
</option>
|
||||
</select>
|
||||
</span>
|
||||
<span v-if="criterion.telemetry && criterion.metadata"
|
||||
class="c-cdef__control"
|
||||
>
|
||||
<select v-model="criterion.operation"
|
||||
@change="updateInputVisibilityAndValues"
|
||||
>
|
||||
<option value="">- Select Comparison -</option>
|
||||
<option v-for="option in filteredOps"
|
||||
:key="option.name"
|
||||
:value="option.name"
|
||||
>
|
||||
{{ option.text }}
|
||||
</option>
|
||||
</select>
|
||||
<template v-if="!enumerations.length">
|
||||
<span v-for="(item, inputIndex) in inputCount"
|
||||
:key="inputIndex"
|
||||
class="c-cdef__control__inputs"
|
||||
>
|
||||
<input v-model="criterion.input[inputIndex]"
|
||||
class="c-cdef__control__input"
|
||||
:type="setInputType"
|
||||
@blur="persist"
|
||||
>
|
||||
<span v-if="inputIndex < inputCount-1">and</span>
|
||||
</span>
|
||||
</template>
|
||||
<span v-else>
|
||||
<span v-if="inputCount && criterion.operation"
|
||||
class="c-cdef__control"
|
||||
>
|
||||
<select v-model="criterion.input[0]"
|
||||
@change="persist"
|
||||
>
|
||||
<option v-for="option in enumerations"
|
||||
:key="option.string"
|
||||
:value="option.value.toString()"
|
||||
>
|
||||
{{ option.string }}
|
||||
</option>
|
||||
</select>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { OPERATIONS } from '../utils/operations';
|
||||
import { INPUT_TYPES } from '../utils/operations';
|
||||
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
props: {
|
||||
criterion: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
telemetry: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => []
|
||||
},
|
||||
index: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
trigger: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
telemetryMetadataOptions: [],
|
||||
operations: OPERATIONS,
|
||||
inputCount: 0,
|
||||
rowLabel: '',
|
||||
operationFormat: '',
|
||||
enumerations: [],
|
||||
inputTypes: INPUT_TYPES
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
setRowLabel: function () {
|
||||
let operator = this.trigger === 'all' ? 'and ': 'or ';
|
||||
return (this.index !== 0 ? operator : '') + 'when';
|
||||
},
|
||||
filteredOps: function () {
|
||||
return this.operations.filter(op => op.appliesTo.indexOf(this.operationFormat) !== -1);
|
||||
},
|
||||
setInputType: function () {
|
||||
let type = '';
|
||||
for (let i = 0; i < this.filteredOps.length; i++) {
|
||||
if (this.criterion.operation === this.filteredOps[i].name) {
|
||||
if (this.filteredOps[i].appliesTo.length) {
|
||||
type = this.inputTypes[this.filteredOps[i].appliesTo[0]];
|
||||
} else {
|
||||
type = 'text'
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
telemetry: {
|
||||
handler(newTelemetry, oldTelemetry) {
|
||||
this.checkTelemetry();
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.updateMetadataOptions();
|
||||
},
|
||||
methods: {
|
||||
checkTelemetry() {
|
||||
if(this.criterion.telemetry) {
|
||||
if (this.criterion.telemetry === 'any' || this.criterion.telemetry === 'all') {
|
||||
this.updateMetadataOptions();
|
||||
} else {
|
||||
if (!this.telemetry.find((telemetryObj) => this.openmct.objects.areIdsEqual(this.criterion.telemetry, telemetryObj.identifier))) {
|
||||
//telemetry being used was removed. So reset this criterion.
|
||||
this.criterion.telemetry = '';
|
||||
this.criterion.metadata = '';
|
||||
this.criterion.input = [];
|
||||
this.criterion.operation = '';
|
||||
this.persist();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
updateOperationFormat() {
|
||||
this.enumerations = [];
|
||||
let foundMetadata = this.telemetryMetadataOptions.find((value) => {
|
||||
return value.key === this.criterion.metadata;
|
||||
});
|
||||
if (foundMetadata) {
|
||||
if (foundMetadata.enumerations !== undefined) {
|
||||
this.operationFormat = 'enum';
|
||||
this.enumerations = foundMetadata.enumerations;
|
||||
} else if (foundMetadata.hints.hasOwnProperty('range')) {
|
||||
this.operationFormat = 'number';
|
||||
} else if (foundMetadata.hints.hasOwnProperty('domain')) {
|
||||
this.operationFormat = 'number';
|
||||
} else if (foundMetadata.key === 'name') {
|
||||
this.operationFormat = 'string';
|
||||
} else {
|
||||
this.operationFormat = 'string';
|
||||
}
|
||||
}
|
||||
this.updateInputVisibilityAndValues();
|
||||
},
|
||||
updateMetadataOptions(ev) {
|
||||
if (ev) {
|
||||
this.clearDependentFields(ev.target);
|
||||
this.persist();
|
||||
}
|
||||
if (this.criterion.telemetry) {
|
||||
const telemetry = (this.criterion.telemetry === 'all' || this.criterion.telemetry === 'any') ? this.telemetry : [{
|
||||
identifier: this.criterion.telemetry
|
||||
}];
|
||||
|
||||
let telemetryPromises = telemetry.map((telemetryObject) => this.openmct.objects.get(telemetryObject.identifier));
|
||||
Promise.all(telemetryPromises).then(telemetryObjects => {
|
||||
this.telemetryMetadataOptions = [];
|
||||
telemetryObjects.forEach(telemetryObject => {
|
||||
let telemetryMetadata = this.openmct.telemetry.getMetadata(telemetryObject);
|
||||
this.addMetaDataOptions(telemetryMetadata.values());
|
||||
});
|
||||
this.updateOperations();
|
||||
});
|
||||
}
|
||||
},
|
||||
addMetaDataOptions(options) {
|
||||
if (!this.telemetryMetadataOptions) {
|
||||
this.telemetryMetadataOptions = options;
|
||||
}
|
||||
options.forEach((option) => {
|
||||
const found = this.telemetryMetadataOptions.find((metadataOption) => {
|
||||
return (metadataOption.key && (metadataOption.key === option.key)) && (metadataOption.name && (metadataOption.name === option.name))
|
||||
});
|
||||
if (!found) {
|
||||
this.telemetryMetadataOptions.push(option);
|
||||
}
|
||||
});
|
||||
},
|
||||
updateOperations(ev) {
|
||||
this.updateOperationFormat();
|
||||
if (ev) {
|
||||
this.clearDependentFields(ev.target);
|
||||
this.persist();
|
||||
}
|
||||
},
|
||||
updateInputVisibilityAndValues(ev) {
|
||||
if (ev) {
|
||||
this.clearDependentFields();
|
||||
this.persist();
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.filteredOps.length; i++) {
|
||||
if (this.criterion.operation === this.filteredOps[i].name) {
|
||||
this.inputCount = this.filteredOps[i].inputCount;
|
||||
}
|
||||
}
|
||||
if (!this.inputCount) {
|
||||
this.criterion.input = [];
|
||||
}
|
||||
},
|
||||
clearDependentFields(el) {
|
||||
if (el === this.$refs.telemetrySelect) {
|
||||
this.criterion.metadata = '';
|
||||
} else if (el === this.$refs.metadataSelect) {
|
||||
if (!this.filteredOps.find(operation => operation.name === this.criterion.operation)) {
|
||||
this.criterion.operation = '';
|
||||
this.criterion.input = this.enumerations.length ? [this.enumerations[0].value.toString()] : [];
|
||||
this.inputCount = 0;
|
||||
}
|
||||
} else {
|
||||
if (this.enumerations.length && !this.criterion.input.length) {
|
||||
this.criterion.input = [this.enumerations[0].value.toString()];
|
||||
}
|
||||
this.inputCount = 0;
|
||||
}
|
||||
},
|
||||
persist() {
|
||||
this.$emit('persist', this.criterion);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
237
src/plugins/condition/components/TestData.vue
Normal file
237
src/plugins/condition/components/TestData.vue
Normal file
@@ -0,0 +1,237 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
<template>
|
||||
<section v-show="isEditing"
|
||||
id="test-data"
|
||||
class="c-cs__test-data"
|
||||
:class="{ 'is-expanded': expanded }"
|
||||
>
|
||||
<div class="c-cs__header c-section__header">
|
||||
<span
|
||||
class="c-disclosure-triangle c-tree__item__view-control is-enabled"
|
||||
:class="{ 'c-disclosure-triangle--expanded': expanded }"
|
||||
@click="expanded = !expanded"
|
||||
></span>
|
||||
<div class="c-cs__header-label c-section__label">Test Data</div>
|
||||
</div>
|
||||
<div v-if="expanded"
|
||||
class="c-cs__content"
|
||||
>
|
||||
<div class="c-cdef__controls"
|
||||
:disabled="!telemetry.length"
|
||||
>
|
||||
<label class="c-toggle-switch">
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="isApplied"
|
||||
@change="applyTestData"
|
||||
>
|
||||
<span class="c-toggle-switch__slider"></span>
|
||||
<span class="c-toggle-switch__label">Apply Test Data</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="c-cs-tests">
|
||||
<span v-for="(testInput, tIndex) in testInputs"
|
||||
:key="tIndex"
|
||||
class="c-test-datum c-cs-test"
|
||||
>
|
||||
<span class="c-cs-test__label">Set</span>
|
||||
<span class="c-cs-test__controls">
|
||||
<span class="c-cdef__control">
|
||||
<select v-model="testInput.telemetry"
|
||||
@change="updateMetadata(testInput)"
|
||||
>
|
||||
<option value="">- Select Telemetry -</option>
|
||||
<option v-for="(telemetryOption, index) in telemetry"
|
||||
:key="index"
|
||||
:value="telemetryOption.identifier"
|
||||
>
|
||||
{{ telemetryOption.name }}
|
||||
</option>
|
||||
</select>
|
||||
</span>
|
||||
<span v-if="testInput.telemetry"
|
||||
class="c-cdef__control"
|
||||
>
|
||||
<select v-model="testInput.metadata"
|
||||
@change="updateTestData"
|
||||
>
|
||||
<option value="">- Select Field -</option>
|
||||
<option v-for="(option, index) in telemetryMetadataOptions[getId(testInput.telemetry)]"
|
||||
:key="index"
|
||||
:value="option.key"
|
||||
>
|
||||
{{ option.name }}
|
||||
</option>
|
||||
</select>
|
||||
</span>
|
||||
<span v-if="testInput.metadata"
|
||||
class="c-cdef__control__inputs"
|
||||
>
|
||||
<input v-model="testInput.value"
|
||||
placeholder="Enter test input"
|
||||
type="text"
|
||||
class="c-cdef__control__input"
|
||||
@change="updateTestData"
|
||||
>
|
||||
</span>
|
||||
</span>
|
||||
<div class="c-test-datum__buttons">
|
||||
<button class="c-click-icon c-test-data__duplicate-button icon-duplicate"
|
||||
title="Duplicate this test datum"
|
||||
@click="addTestInput(testInput)"
|
||||
></button>
|
||||
<button class="c-click-icon c-test-data__delete-button icon-trash"
|
||||
title="Delete this test datum"
|
||||
@click="removeTestInput(tIndex)"
|
||||
></button>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
v-show="isEditing"
|
||||
id="addTestDatum"
|
||||
class="c-button c-button--major icon-plus labeled"
|
||||
@click="addTestInput"
|
||||
>
|
||||
<span class="c-cs-button__label">Add Test Datum</span>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
props: {
|
||||
isEditing: Boolean,
|
||||
telemetry: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => []
|
||||
},
|
||||
testData: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => {
|
||||
return {
|
||||
applied: false,
|
||||
conditionTestInputs: []
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
expanded: true,
|
||||
isApplied: false,
|
||||
testInputs: [],
|
||||
telemetryMetadataOptions: {}
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
isEditing(editing) {
|
||||
if (!editing) {
|
||||
this.resetApplied();
|
||||
}
|
||||
},
|
||||
telemetry: {
|
||||
handler() {
|
||||
this.initializeMetadata();
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
testData: {
|
||||
handler() {
|
||||
this.initialize();
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.resetApplied();
|
||||
},
|
||||
mounted() {
|
||||
this.initialize();
|
||||
this.initializeMetadata();
|
||||
},
|
||||
methods: {
|
||||
applyTestData() {
|
||||
this.isApplied = !this.isApplied;
|
||||
this.updateTestData();
|
||||
},
|
||||
initialize() {
|
||||
if (this.testData && this.testData.conditionTestInputs) {
|
||||
this.testInputs = this.testData.conditionTestInputs;
|
||||
}
|
||||
if (!this.testInputs.length) {
|
||||
this.addTestInput();
|
||||
}
|
||||
},
|
||||
initializeMetadata() {
|
||||
this.telemetry.forEach((telemetryObject) => {
|
||||
const id = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
let telemetryMetadata = this.openmct.telemetry.getMetadata(telemetryObject);
|
||||
this.telemetryMetadataOptions[id] = telemetryMetadata.values().slice();
|
||||
});
|
||||
},
|
||||
addTestInput(testInput) {
|
||||
this.testInputs.push(Object.assign({
|
||||
telemetry: '',
|
||||
metadata: '',
|
||||
input: ''
|
||||
}, testInput));
|
||||
},
|
||||
removeTestInput(index) {
|
||||
this.testInputs.splice(index, 1);
|
||||
this.updateTestData();
|
||||
},
|
||||
getId(identifier) {
|
||||
if (identifier) {
|
||||
return this.openmct.objects.makeKeyString(identifier);
|
||||
}
|
||||
return [];
|
||||
},
|
||||
updateMetadata(testInput) {
|
||||
if (testInput.telemetry) {
|
||||
const id = this.openmct.objects.makeKeyString(testInput.telemetry);
|
||||
if(this.telemetryMetadataOptions[id]) {
|
||||
return;
|
||||
}
|
||||
let telemetryMetadata = this.openmct.telemetry.getMetadata(testInput);
|
||||
this.telemetryMetadataOptions[id] = telemetryMetadata.values().slice();
|
||||
}
|
||||
},
|
||||
resetApplied() {
|
||||
this.isApplied = false;
|
||||
this.updateTestData();
|
||||
},
|
||||
updateTestData() {
|
||||
this.$emit('updateTestData', {
|
||||
applied: this.isApplied,
|
||||
conditionTestInputs: this.testInputs
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
116
src/plugins/condition/components/condition-set.scss
Normal file
116
src/plugins/condition/components/condition-set.scss
Normal file
@@ -0,0 +1,116 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
.c-cs {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 0 1 auto;
|
||||
overflow: hidden;
|
||||
|
||||
> * {
|
||||
flex: 0 0 auto;
|
||||
overflow: hidden;
|
||||
+ * {
|
||||
margin-top: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
|
||||
.c-button {
|
||||
align-self: start;
|
||||
}
|
||||
}
|
||||
|
||||
.is-editing & {
|
||||
// Add some space to kick away from blue editing border indication
|
||||
padding: $interiorMargin;
|
||||
}
|
||||
|
||||
section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&__conditions-h {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 1 auto;
|
||||
overflow: auto;
|
||||
padding-right: $interiorMarginSm;
|
||||
|
||||
> * + * {
|
||||
margin-top: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
|
||||
&__conditions {
|
||||
> * + * {
|
||||
margin-top: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
|
||||
.hint {
|
||||
padding: $interiorMarginSm;
|
||||
}
|
||||
|
||||
/************************** SPECIFIC ITEMS */
|
||||
&__current-output-value {
|
||||
font-size: 1.25em;
|
||||
padding: $interiorMargin;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************** TEST DATA */
|
||||
.c-cs-tests {
|
||||
flex: 0 1 auto;
|
||||
overflow: auto;
|
||||
padding-right: $interiorMarginSm;
|
||||
|
||||
> * + * {
|
||||
margin-top: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
|
||||
.c-cs-test {
|
||||
> * {
|
||||
flex: 0 0 auto;
|
||||
+ * {
|
||||
margin-left: $interiorMargin;
|
||||
}
|
||||
}
|
||||
|
||||
&__controls {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
|
||||
> * + * {
|
||||
margin-left: $interiorMargin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
133
src/plugins/condition/components/condition.scss
Normal file
133
src/plugins/condition/components/condition.scss
Normal file
@@ -0,0 +1,133 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
.c-condition,
|
||||
.c-test-datum {
|
||||
@include discreteItem();
|
||||
display: flex;
|
||||
padding: $interiorMargin;
|
||||
|
||||
&--edit {
|
||||
line-height: 160%; // For layout when inputs wrap, like in criteria
|
||||
}
|
||||
}
|
||||
|
||||
.c-condition {
|
||||
flex-direction: column;
|
||||
min-width: 400px;
|
||||
|
||||
> * + * {
|
||||
margin-top: $interiorMarginSm;
|
||||
}
|
||||
&--browse {
|
||||
.c-condition__summary {
|
||||
border-top: 1px solid $colorInteriorBorder;
|
||||
padding-top: $interiorMargin;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************** HEADER */
|
||||
&__header {
|
||||
$h: 22px;
|
||||
display: flex;
|
||||
align-items: start;
|
||||
align-content: stretch;
|
||||
overflow: hidden;
|
||||
min-height: $h;
|
||||
line-height: $h;
|
||||
|
||||
> * {
|
||||
flex: 0 0 auto;
|
||||
+ * {
|
||||
margin-left: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__drag-grippy {
|
||||
transform: translateY(50%);
|
||||
}
|
||||
|
||||
&__name {
|
||||
font-weight: bold;
|
||||
align-self: baseline; // Fixes bold line-height offset problem
|
||||
}
|
||||
|
||||
&__output,
|
||||
&__summary {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************** CONDITION DEFINITION, EDITING */
|
||||
.c-cdef {
|
||||
display: grid;
|
||||
grid-row-gap: $interiorMarginSm;
|
||||
grid-column-gap: $interiorMargin;
|
||||
grid-auto-columns: min-content 1fr max-content;
|
||||
align-items: start;
|
||||
min-width: 150px;
|
||||
margin-left: 29px;
|
||||
overflow: hidden;
|
||||
|
||||
&__criteria,
|
||||
&__match-and-criteria {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
&__label {
|
||||
grid-column: 1;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&__separator {
|
||||
grid-column: 1 / span 3;
|
||||
}
|
||||
|
||||
&__controls {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
grid-column: 2;
|
||||
|
||||
> * > * {
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
grid-column: 3;
|
||||
}
|
||||
}
|
||||
|
||||
.c-c__drag-ghost {
|
||||
width: 100%;
|
||||
min-height: $interiorMarginSm;
|
||||
|
||||
&.dragging {
|
||||
min-height: 5em;
|
||||
background-color: lightblue;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
<template>
|
||||
<li class="c-tree__item-h">
|
||||
<div
|
||||
class="c-tree__item"
|
||||
:class="{ 'is-alias': isAlias, 'is-navigated-object': navigated }"
|
||||
@click="handleItemSelected(node.object, node)"
|
||||
>
|
||||
<view-control
|
||||
v-model="expanded"
|
||||
class="c-tree__item__view-control"
|
||||
:enabled="hasChildren"
|
||||
:propagate="false"
|
||||
/>
|
||||
<div class="c-tree__item__label c-object-label">
|
||||
<div
|
||||
class="c-tree__item__type-icon c-object-label__type-icon"
|
||||
:class="typeClass"
|
||||
></div>
|
||||
<div class="c-tree__item__name c-object-label__name">{{ node.object.name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul
|
||||
v-if="expanded"
|
||||
class="c-tree"
|
||||
>
|
||||
<li
|
||||
v-if="isLoading && !loaded"
|
||||
class="c-tree__item-h"
|
||||
>
|
||||
<div class="c-tree__item loading">
|
||||
<span class="c-tree__item__label">Loading...</span>
|
||||
</div>
|
||||
</li>
|
||||
<condition-set-dialog-tree-item
|
||||
v-for="child in children"
|
||||
:key="child.id"
|
||||
:node="child"
|
||||
:selected-item="selectedItem"
|
||||
:handle-item-selected="handleItemSelected"
|
||||
/>
|
||||
</ul>
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import viewControl from '@/ui/components/viewControl.vue';
|
||||
|
||||
export default {
|
||||
name: 'ConditionSetDialogTreeItem',
|
||||
inject: ['openmct'],
|
||||
components: {
|
||||
viewControl
|
||||
},
|
||||
props: {
|
||||
node: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
selectedItem: {
|
||||
type: Object,
|
||||
default() {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
handleItemSelected: {
|
||||
type: Function,
|
||||
default() {
|
||||
return (item) => {};
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hasChildren: false,
|
||||
isLoading: false,
|
||||
loaded: false,
|
||||
children: [],
|
||||
expanded: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
navigated() {
|
||||
const itemId = this.selectedItem && this.selectedItem.itemId;
|
||||
const isSelectedObject = itemId && this.openmct.objects.areIdsEqual(this.node.object.identifier, itemId);
|
||||
if (isSelectedObject && this.node.objectPath && this.node.objectPath.length > 1) {
|
||||
const isParent = this.openmct.objects.areIdsEqual(this.node.objectPath[1].identifier, this.selectedItem.parentId);
|
||||
return isSelectedObject && isParent;
|
||||
}
|
||||
return isSelectedObject;
|
||||
},
|
||||
isAlias() {
|
||||
let parent = this.node.objectPath[1];
|
||||
if (!parent) {
|
||||
return false;
|
||||
}
|
||||
let parentKeyString = this.openmct.objects.makeKeyString(parent.identifier);
|
||||
return parentKeyString !== this.node.object.location;
|
||||
},
|
||||
typeClass() {
|
||||
let type = this.openmct.types.get(this.node.object.type);
|
||||
if (!type) {
|
||||
return 'icon-object-unknown';
|
||||
}
|
||||
return type.definition.cssClass;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
expanded() {
|
||||
if (!this.hasChildren) {
|
||||
return;
|
||||
}
|
||||
if (!this.loaded && !this.isLoading) {
|
||||
this.composition = this.openmct.composition.get(this.domainObject);
|
||||
this.composition.on('add', this.addChild);
|
||||
this.composition.on('remove', this.removeChild);
|
||||
this.composition.load().then(this.finishLoading);
|
||||
this.isLoading = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.domainObject = this.node.object;
|
||||
let removeListener = this.openmct.objects.observe(this.domainObject, '*', (newObject) => {
|
||||
this.domainObject = newObject;
|
||||
});
|
||||
|
||||
this.$once('hook:destroyed', removeListener);
|
||||
if (this.openmct.composition.get(this.node.object)) {
|
||||
this.hasChildren = true;
|
||||
}
|
||||
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.expanded = false;
|
||||
},
|
||||
destroyed() {
|
||||
if (this.composition) {
|
||||
this.composition.off('add', this.addChild);
|
||||
this.composition.off('remove', this.removeChild);
|
||||
delete this.composition;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addChild(child) {
|
||||
this.children.push({
|
||||
id: this.openmct.objects.makeKeyString(child.identifier),
|
||||
object: child,
|
||||
objectPath: [child].concat(this.node.objectPath),
|
||||
navigateToParent: this.navigateToPath
|
||||
});
|
||||
},
|
||||
removeChild(identifier) {
|
||||
let removeId = this.openmct.objects.makeKeyString(identifier);
|
||||
this.children = this.children
|
||||
.filter(c => c.id !== removeId);
|
||||
},
|
||||
finishLoading() {
|
||||
this.isLoading = false;
|
||||
this.loaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,172 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
<template>
|
||||
<div class="u-contents">
|
||||
<div class="c-overlay__top-bar">
|
||||
<div class="c-overlay__dialog-title">Select Condition Set</div>
|
||||
</div>
|
||||
<div class="c-overlay__contents-main c-selector c-tree-and-search">
|
||||
<div class="c-tree-and-search__search">
|
||||
<search ref="shell-search"
|
||||
class="c-search"
|
||||
:value="searchValue"
|
||||
@input="searchTree"
|
||||
@clear="searchTree"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- loading -->
|
||||
<div v-if="isLoading"
|
||||
class="c-tree-and-search__loading loading"
|
||||
></div>
|
||||
<!-- end loading -->
|
||||
|
||||
<div v-if="(allTreeItems.length === 0) || (searchValue && filteredTreeItems.length === 0)"
|
||||
class="c-tree-and-search__no-results"
|
||||
>
|
||||
No results found
|
||||
</div>
|
||||
|
||||
<!-- main tree -->
|
||||
<ul v-if="!isLoading"
|
||||
v-show="!searchValue"
|
||||
class="c-tree-and-search__tree c-tree"
|
||||
>
|
||||
<condition-set-dialog-tree-item
|
||||
v-for="treeItem in allTreeItems"
|
||||
:key="treeItem.id"
|
||||
:node="treeItem"
|
||||
:selected-item="selectedItem"
|
||||
:handle-item-selected="handleItemSelection"
|
||||
/>
|
||||
</ul>
|
||||
<!-- end main tree -->
|
||||
|
||||
<!-- search tree -->
|
||||
<ul v-if="searchValue"
|
||||
class="c-tree-and-search__tree c-tree"
|
||||
>
|
||||
<condition-set-dialog-tree-item
|
||||
v-for="treeItem in filteredTreeItems"
|
||||
:key="treeItem.id"
|
||||
:node="treeItem"
|
||||
:selected-item="selectedItem"
|
||||
:handle-item-selected="handleItemSelection"
|
||||
/>
|
||||
</ul>
|
||||
<!-- end search tree -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import search from '@/ui/components/search.vue';
|
||||
import ConditionSetDialogTreeItem from './ConditionSetDialogTreeItem.vue';
|
||||
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
name: 'ConditionSetSelectorDialog',
|
||||
components: {
|
||||
search,
|
||||
ConditionSetDialogTreeItem
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
expanded: false,
|
||||
searchValue: '',
|
||||
allTreeItems: [],
|
||||
filteredTreeItems: [],
|
||||
isLoading: false,
|
||||
selectedItem: undefined
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.searchService = this.openmct.$injector.get('searchService');
|
||||
this.getAllChildren();
|
||||
},
|
||||
methods: {
|
||||
getAllChildren() {
|
||||
this.isLoading = true;
|
||||
this.openmct.objects.get('ROOT')
|
||||
.then(root => {
|
||||
return this.openmct.composition.get(root).load()
|
||||
})
|
||||
.then(children => {
|
||||
this.isLoading = false;
|
||||
this.allTreeItems = children.map(c => {
|
||||
return {
|
||||
id: this.openmct.objects.makeKeyString(c.identifier),
|
||||
object: c,
|
||||
objectPath: [c],
|
||||
navigateToParent: '/browse'
|
||||
};
|
||||
});
|
||||
});
|
||||
},
|
||||
getFilteredChildren() {
|
||||
this.searchService.query(this.searchValue).then(children => {
|
||||
this.filteredTreeItems = children.hits.map(child => {
|
||||
|
||||
let context = child.object.getCapability('context'),
|
||||
object = child.object.useCapability('adapter'),
|
||||
objectPath = [],
|
||||
navigateToParent;
|
||||
|
||||
if (context) {
|
||||
objectPath = context.getPath().slice(1)
|
||||
.map(oldObject => oldObject.useCapability('adapter'))
|
||||
.reverse();
|
||||
navigateToParent = '/browse/' + objectPath.slice(1)
|
||||
.map((parent) => this.openmct.objects.makeKeyString(parent.identifier))
|
||||
.join('/');
|
||||
}
|
||||
|
||||
return {
|
||||
id: this.openmct.objects.makeKeyString(object.identifier),
|
||||
object,
|
||||
objectPath,
|
||||
navigateToParent
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
searchTree(value) {
|
||||
this.searchValue = value;
|
||||
|
||||
if (this.searchValue !== '') {
|
||||
this.getFilteredChildren();
|
||||
}
|
||||
},
|
||||
handleItemSelection(item, node) {
|
||||
if (item && item.type === 'conditionSet') {
|
||||
const parentId = (node.objectPath && node.objectPath.length > 1) ? node.objectPath[1].identifier : undefined;
|
||||
this.selectedItem = {
|
||||
itemId: item.identifier,
|
||||
parentId
|
||||
};
|
||||
this.$emit('conditionSetSelected', item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,335 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
<template>
|
||||
<div 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"
|
||||
>
|
||||
<style-editor 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"
|
||||
:href="navigateToPath"
|
||||
@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"
|
||||
>
|
||||
<condition-error :show-label="true"
|
||||
:condition="getCondition(conditionStyle.conditionId)"
|
||||
/>
|
||||
<condition-description :show-label="true"
|
||||
:condition="getCondition(conditionStyle.conditionId)"
|
||||
/>
|
||||
<style-editor 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 ConditionSetSelectorDialog from "./ConditionSetSelectorDialog.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";
|
||||
|
||||
export default {
|
||||
name: 'ConditionalStylesView',
|
||||
components: {
|
||||
ConditionDescription,
|
||||
ConditionError,
|
||||
StyleEditor
|
||||
},
|
||||
inject: [
|
||||
'openmct',
|
||||
'domainObject'
|
||||
],
|
||||
props: {
|
||||
itemId: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
initialStyles: {
|
||||
type: Object,
|
||||
default() {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
canHide: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
conditionalStyles: [],
|
||||
staticStyle: undefined,
|
||||
conditionSetDomainObject: undefined,
|
||||
isEditing: this.openmct.editor.isEditing(),
|
||||
conditions: undefined,
|
||||
conditionsLoaded: false,
|
||||
navigateToPath: ''
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
this.openmct.editor.off('isEditing', this.setEditState);
|
||||
},
|
||||
mounted() {
|
||||
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: {
|
||||
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;
|
||||
},
|
||||
addConditionSet() {
|
||||
let conditionSetDomainObject;
|
||||
const handleItemSelection = (item) => {
|
||||
if (item) {
|
||||
conditionSetDomainObject = item;
|
||||
}
|
||||
};
|
||||
const dismissDialog = (overlay, initialize) => {
|
||||
overlay.dismiss();
|
||||
if (initialize && conditionSetDomainObject) {
|
||||
this.conditionSetDomainObject = conditionSetDomainObject;
|
||||
this.conditionalStyles = [];
|
||||
this.initializeConditionalStyles();
|
||||
}
|
||||
};
|
||||
let vm = new Vue({
|
||||
provide: {
|
||||
openmct: this.openmct
|
||||
},
|
||||
components: {ConditionSetSelectorDialog},
|
||||
data() {
|
||||
return {
|
||||
handleItemSelection
|
||||
}
|
||||
},
|
||||
template: '<condition-set-selector-dialog @conditionSetSelected="handleItemSelection"></condition-set-selector-dialog>'
|
||||
}).$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.objectPath
|
||||
.map(o => o && this.openmct.objects.makeKeyString(o.identifier))
|
||||
.reverse()
|
||||
.join('/');
|
||||
}
|
||||
);
|
||||
},
|
||||
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);
|
||||
}
|
||||
},
|
||||
removeConditionSet() {
|
||||
this.conditionSetDomainObject = undefined;
|
||||
this.conditionalStyles = [];
|
||||
let domainObjectStyles = (this.domainObject.configuration && this.domainObject.configuration.objectStyles) || {};
|
||||
if (this.itemId) {
|
||||
domainObjectStyles[this.itemId].conditionSetIdentifier = 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;
|
||||
delete domainObjectStyles.conditionSetIdentifier;
|
||||
domainObjectStyles.styles = undefined;
|
||||
delete domainObjectStyles.styles;
|
||||
}
|
||||
if (_.isEmpty(domainObjectStyles)) {
|
||||
domainObjectStyles = undefined;
|
||||
}
|
||||
|
||||
this.persist(domainObjectStyles);
|
||||
},
|
||||
initializeConditionalStyles() {
|
||||
if (!this.conditions) {
|
||||
this.conditions = {};
|
||||
}
|
||||
let conditionalStyles = [];
|
||||
this.conditionSetDomainObject.configuration.conditionCollection.forEach((conditionConfiguration, index) => {
|
||||
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());
|
||||
},
|
||||
initializeStaticStyle(objectStyles) {
|
||||
let staticStyle = objectStyles && objectStyles.staticStyle;
|
||||
this.staticStyle = 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.persist(this.getDomainObjectConditionalStyle());
|
||||
}
|
||||
},
|
||||
getDomainObjectConditionalStyle() {
|
||||
let objectStyle = {
|
||||
styles: this.conditionalStyles,
|
||||
staticStyle: this.staticStyle
|
||||
};
|
||||
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] : {};
|
||||
},
|
||||
persist(style) {
|
||||
this.openmct.objects.mutate(this.domainObject, 'configuration.objectStyles', style);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
179
src/plugins/condition/components/inspector/StyleEditor.vue
Normal file
179
src/plugins/condition/components/inspector/StyleEditor.vue
Normal file
@@ -0,0 +1,179 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
<template>
|
||||
<div class="c-style">
|
||||
<span class="c-style-thumb"
|
||||
:class="{ 'is-style-invisible': styleItem.style.isStyleInvisible }"
|
||||
:style="[styleItem.style.imageUrl ? { backgroundImage:'url(' + styleItem.style.imageUrl + ')'} : styleItem.style ]"
|
||||
>
|
||||
<span class="c-style-thumb__text"
|
||||
:class="{ 'hide-nice': !styleItem.style.color }"
|
||||
>
|
||||
ABC
|
||||
</span>
|
||||
</span>
|
||||
<span class="c-toolbar">
|
||||
<toolbar-color-picker v-if="styleItem.style.border"
|
||||
class="c-style__toolbar-button--border-color u-menu-to--center"
|
||||
:options="borderColorOption"
|
||||
@change="updateStyleValue"
|
||||
/>
|
||||
<toolbar-color-picker v-if="styleItem.style.backgroundColor"
|
||||
class="c-style__toolbar-button--background-color u-menu-to--center"
|
||||
:options="backgroundColorOption"
|
||||
@change="updateStyleValue"
|
||||
/>
|
||||
<toolbar-color-picker v-if="styleItem.style.color"
|
||||
class="c-style__toolbar-button--color u-menu-to--center"
|
||||
:options="colorOption"
|
||||
@change="updateStyleValue"
|
||||
/>
|
||||
<toolbar-button v-if="styleItem.style.imageUrl !== undefined"
|
||||
class="c-style__toolbar-button--image-url"
|
||||
:options="imageUrlOption"
|
||||
@change="updateStyleValue"
|
||||
/>
|
||||
<toolbar-toggle-button v-if="styleItem.style.isStyleInvisible !== undefined"
|
||||
class="c-style__toolbar-button--toggle-visible"
|
||||
:options="isStyleInvisibleOption"
|
||||
@change="updateStyleValue"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import ToolbarColorPicker from "@/ui/toolbar/components/toolbar-color-picker.vue";
|
||||
import ToolbarButton from "@/ui/toolbar/components/toolbar-button.vue";
|
||||
import ToolbarToggleButton from "@/ui/toolbar/components/toolbar-toggle-button.vue";
|
||||
import {STYLE_CONSTANTS} from "@/plugins/condition/utils/constants";
|
||||
|
||||
export default {
|
||||
name: 'StyleEditor',
|
||||
components: {
|
||||
ToolbarButton,
|
||||
ToolbarColorPicker,
|
||||
ToolbarToggleButton
|
||||
},
|
||||
inject: [
|
||||
'openmct'
|
||||
],
|
||||
props: {
|
||||
isEditing: {
|
||||
type: Boolean
|
||||
},
|
||||
styleItem: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
borderColorOption() {
|
||||
return {
|
||||
icon: 'icon-line-horz',
|
||||
title: STYLE_CONSTANTS.borderColorTitle,
|
||||
value: this.styleItem.style.border.replace('1px solid ', ''),
|
||||
property: 'border',
|
||||
isEditing: this.isEditing
|
||||
}
|
||||
},
|
||||
backgroundColorOption() {
|
||||
return {
|
||||
icon: 'icon-paint-bucket',
|
||||
title: STYLE_CONSTANTS.backgroundColorTitle,
|
||||
value: this.styleItem.style.backgroundColor,
|
||||
property: 'backgroundColor',
|
||||
isEditing: this.isEditing
|
||||
}
|
||||
},
|
||||
colorOption() {
|
||||
return {
|
||||
icon: 'icon-font',
|
||||
title: STYLE_CONSTANTS.textColorTitle,
|
||||
value: this.styleItem.style.color,
|
||||
property: 'color',
|
||||
isEditing: this.isEditing
|
||||
}
|
||||
},
|
||||
imageUrlOption() {
|
||||
return {
|
||||
icon: 'icon-image',
|
||||
title: STYLE_CONSTANTS.imagePropertiesTitle,
|
||||
dialog: {
|
||||
name: "Image Properties",
|
||||
sections: [
|
||||
{
|
||||
rows: [
|
||||
{
|
||||
key: "url",
|
||||
control: "textfield",
|
||||
name: "Image URL",
|
||||
"cssClass": "l-input-lg"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
property: 'imageUrl',
|
||||
formKeys: ['url'],
|
||||
value: {url: this.styleItem.style.imageUrl},
|
||||
isEditing: this.isEditing
|
||||
}
|
||||
},
|
||||
isStyleInvisibleOption() {
|
||||
return {
|
||||
value: this.styleItem.style.isStyleInvisible,
|
||||
property: 'isStyleInvisible',
|
||||
isEditing: this.isEditing,
|
||||
options: [
|
||||
{
|
||||
value: '',
|
||||
icon: 'icon-eye-disabled',
|
||||
title: STYLE_CONSTANTS.visibilityHidden
|
||||
},
|
||||
{
|
||||
value: STYLE_CONSTANTS.isStyleInvisible,
|
||||
icon: 'icon-eye-open',
|
||||
title: STYLE_CONSTANTS.visibilityVisible
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateStyleValue(value, item) {
|
||||
if (item.property === 'border') {
|
||||
value = '1px solid ' + value;
|
||||
}
|
||||
if (value && (value.url !== undefined)) {
|
||||
this.styleItem.style[item.property] = value.url;
|
||||
} else {
|
||||
this.styleItem.style[item.property] = value;
|
||||
}
|
||||
this.$emit('persist', this.styleItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,124 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
/********************************************* INSPECTOR STYLES TAB */
|
||||
.c-inspect-styles {
|
||||
> * + * {
|
||||
margin-top: $interiorMargin;
|
||||
}
|
||||
|
||||
&__content,
|
||||
&__conditions,
|
||||
&__condition {
|
||||
> * + * {
|
||||
margin-top: $interiorMargin;
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&__condition-set {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
.c-object-label {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.c-button {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
&__style,
|
||||
&__condition {
|
||||
padding: $interiorMargin;
|
||||
}
|
||||
|
||||
&__condition {
|
||||
@include discreteItem();
|
||||
}
|
||||
|
||||
.c-style {
|
||||
padding: 2px; // Allow a bit of room for thumb box-shadow
|
||||
|
||||
&__condition-desc {
|
||||
@include ellipsize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-inspect-styles__style {
|
||||
.is-editing & {
|
||||
border-bottom: 1px solid $colorInteriorBorder;
|
||||
}
|
||||
}
|
||||
|
||||
.l-shell:not(.is-editing) .c-inspect-styles {
|
||||
.c-toolbar {
|
||||
// Disabled-look toolbar when not editing
|
||||
pointer-events: none;
|
||||
cursor: inherit;
|
||||
|
||||
// Hide control buttons, like image URL
|
||||
[class*='--image-url'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// Make buttons look disabled by knocking back icon, not swatch element
|
||||
.c-icon-button {
|
||||
&:before {
|
||||
opacity: $controlDisabledOpacity;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.c-toggle-styling-button {
|
||||
display: none;
|
||||
|
||||
.is-editing & {
|
||||
display: block;
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
.is-style-invisible {
|
||||
display: none !important;
|
||||
|
||||
.is-editing & {
|
||||
display: block !important;
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
&.c-style-thumb {
|
||||
display: block !important;
|
||||
background-color: transparent !important;
|
||||
border-color: transparent !important;
|
||||
@include bgCheckerboard($size: 10px, $imp: true);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user