Merge branch 'topic-conditionals' into dave/condition-telemetry-request

This commit is contained in:
David Tsay 2020-03-16 15:31:19 -07:00
commit 90dd53e954
14 changed files with 236 additions and 323 deletions

View File

@ -28,10 +28,7 @@ import {computeCondition} from "./utils/evaluator";
/* /*
* conditionConfiguration = { * conditionConfiguration = {
* identifier: { * id: uuid,
* key: '',
* namespace: ''
* },
* trigger: 'any'/'all', * trigger: 'any'/'all',
* criteria: [ * criteria: [
* { * {
@ -48,14 +45,14 @@ export default class ConditionClass extends EventEmitter {
/** /**
* Manages criteria and emits the result of - true or false - based on criteria evaluated. * Manages criteria and emits the result of - true or false - based on criteria evaluated.
* @constructor * @constructor
* @param conditionConfiguration: {identifier: {domainObject.identifier},trigger: enum, criteria: Array of {id: uuid, operation: enum, input: Array, metaDataKey: string, key: {domainObject.identifier} } * @param conditionConfiguration: {id: uuid,trigger: enum, criteria: Array of {id: uuid, operation: enum, input: Array, metaDataKey: string, key: {domainObject.identifier} }
* @param openmct * @param openmct
*/ */
constructor(conditionConfiguration, openmct) { constructor(conditionConfiguration, openmct) {
super(); super();
this.openmct = openmct; this.openmct = openmct;
this.id = this.openmct.objects.makeKeyString(conditionConfiguration.identifier); this.id = conditionConfiguration.id;
this.criteria = []; this.criteria = [];
this.criteriaResults = {}; this.criteriaResults = {};
this.result = undefined; this.result = undefined;
@ -64,16 +61,11 @@ export default class ConditionClass extends EventEmitter {
this.createCriteria(conditionConfiguration.configuration.criteria); this.createCriteria(conditionConfiguration.configuration.criteria);
} }
this.trigger = conditionConfiguration.configuration.trigger; this.trigger = conditionConfiguration.configuration.trigger;
this.openmct.objects.get(this.id).then(obj => this.observeForChanges(obj));
} }
observeForChanges(conditionDO) { update(conditionConfiguration) {
this.stopObservingForChanges = this.openmct.objects.observe(conditionDO, '*', this.update.bind(this)); this.updateTrigger(conditionConfiguration.configuration.trigger);
} this.updateCriteria(conditionConfiguration.configuration.criteria);
update(newDomainObject) {
this.updateTrigger(newDomainObject.configuration.trigger);
this.updateCriteria(newDomainObject.configuration.criteria);
} }
updateTrigger(trigger) { updateTrigger(trigger) {

View File

@ -25,18 +25,19 @@ import uuid from "uuid";
import EventEmitter from 'EventEmitter'; import EventEmitter from 'EventEmitter';
export default class ConditionManager extends EventEmitter { export default class ConditionManager extends EventEmitter {
constructor(domainObject, openmct) { constructor(conditionSetDomainObject, openmct) {
super(); super();
this.openmct = openmct; this.openmct = openmct;
this.domainObject = domainObject; this.conditionSetDomainObject = conditionSetDomainObject;
this.timeAPI = this.openmct.time; this.timeAPI = this.openmct.time;
this.latestTimestamp = {}; this.latestTimestamp = {};
this.conditionResults = {}; this.composition = this.openmct.composition.get(conditionSetDomainObject);
this.conditionCollection = [];
this.instantiate = this.openmct.$injector.get('instantiate');
this.composition = this.openmct.composition.get(domainObject);
this.loaded = this.composition.load(); this.loaded = this.composition.load();
this.initialize(); this.initialize();
this.stopObservingForChanges = this.openmct.objects.observe(this.conditionSetDomainObject, '*', (newDomainObject) => {
this.update(newDomainObject);
});
} }
load() { load() {
@ -44,85 +45,60 @@ export default class ConditionManager extends EventEmitter {
} }
initialize() { initialize() {
this.observeForChanges(this.domainObject); this.conditionResults = {};
if (this.domainObject.configuration.conditionCollection.length) { this.conditionClassCollection = [];
this.domainObject.configuration.conditionCollection.forEach((conditionConfigurationId, index) => { if (this.conditionSetDomainObject.configuration.conditionCollection.length) {
this.openmct.objects.get(conditionConfigurationId).then((conditionConfiguration) => { this.conditionSetDomainObject.configuration.conditionCollection.forEach((conditionConfiguration, index) => {
this.initCondition(conditionConfiguration, index); this.initCondition(conditionConfiguration, index);
});
}); });
} else {
this.addCondition(true);
} }
} }
observeForChanges(domainObject) { update(newDomainObject) {
//TODO: Observe only the conditionCollection property instead of the whole domainObject this.destroy();
this.stopObservingForChanges = this.openmct.objects.observe(domainObject, '*', this.handleConditionCollectionUpdated.bind(this)); this.conditionSetDomainObject = newDomainObject;
this.stopObservingForChanges = this.openmct.objects.observe(this.conditionSetDomainObject, '*', (newDO) => {
this.update(newDO);
});
this.initialize();
} }
handleConditionCollectionUpdated(newDomainObject) { updateCondition(conditionConfiguration, index) {
let oldConditionIdentifiers = this.domainObject.configuration.conditionCollection.map((conditionConfigurationId) => { let condition = this.conditionClassCollection[index];
return this.openmct.objects.makeKeyString(conditionConfigurationId); condition.update(conditionConfiguration);
}); this.conditionSetDomainObject.configuration.conditionCollection[index] = conditionConfiguration;
let newConditionIdentifiers = newDomainObject.configuration.conditionCollection.map((conditionConfigurationId) => { this.persistConditions();
return this.openmct.objects.makeKeyString(conditionConfigurationId);
});
this.domainObject = newDomainObject;
//check for removed conditions
oldConditionIdentifiers.forEach((identifier, index) => {
if (newConditionIdentifiers.indexOf(identifier) < 0) {
this.removeCondition(identifier);
}
});
let newConditionCount = this.domainObject.configuration.conditionCollection.length - this.conditionCollection.length;
for (let i = 0; i < newConditionCount; i++) {
let conditionConfigurationId = this.domainObject.configuration.conditionCollection[i];
this.openmct.objects.get(conditionConfigurationId).then((conditionConfiguration) => {
this.initCondition(conditionConfiguration, i);
});
}
} }
initCondition(conditionConfiguration, index) { initCondition(conditionConfiguration, index) {
let condition = new Condition(conditionConfiguration, this.openmct); let condition = new Condition(conditionConfiguration, this.openmct);
condition.on('conditionResultUpdated', this.handleConditionResult.bind(this)); condition.on('conditionResultUpdated', this.handleConditionResult.bind(this));
if (index !== undefined) { if (index !== undefined) {
this.conditionCollection.splice(index + 1, 0, condition); this.conditionClassCollection.splice(index + 1, 0, condition);
} else { } else {
this.conditionCollection.unshift(condition); this.conditionClassCollection.unshift(condition);
} }
} }
createConditionDomainObject(isDefault, conditionConfiguration) { createCondition(conditionConfiguration) {
let conditionObj; let conditionObj;
if (conditionConfiguration) { if (conditionConfiguration) {
conditionObj = { conditionObj = {
...conditionConfiguration, ...conditionConfiguration,
name: `Copy of ${conditionConfiguration.name}`, id: uuid(),
identifier: { configuration: {
...this.domainObject.identifier, ...conditionConfiguration.configuration,
key: uuid() name: `Copy of ${conditionConfiguration.configuration.name}`
} }
}; };
} else { } else {
conditionObj = { conditionObj = {
isDefault: isDefault, id: uuid(),
type: 'condition',
identifier: {
...this.domainObject.identifier,
key: uuid()
},
configuration: { configuration: {
name: isDefault ? 'Default' : 'Unnamed Condition', name: 'Unnamed Condition',
output: 'false', output: 'false',
trigger: 'all', trigger: 'all',
criteria: isDefault ? [] : [{ criteria: [{
telemetry: '', telemetry: '',
operation: '', operation: '',
input: [], input: [],
@ -132,58 +108,48 @@ export default class ConditionManager extends EventEmitter {
summary: '' summary: ''
}; };
} }
let conditionDomainObjectKeyString = this.openmct.objects.makeKeyString(conditionObj.identifier);
let newDomainObject = this.instantiate(conditionObj, conditionDomainObjectKeyString);
return newDomainObject.useCapability('adapter'); return conditionObj;
} }
addCondition(isDefault, index) { addCondition() {
this.createAndSaveConditionDomainObject(!!isDefault, index); this.createAndSaveCondition();
} }
cloneCondition(conditionConfigurationId, index) { cloneCondition(conditionConfiguration, index) {
this.openmct.objects.get(conditionConfigurationId).then((conditionConfiguration) => { this.createAndSaveCondition(index, conditionConfiguration);
this.createAndSaveConditionDomainObject(false, index, conditionConfiguration);
});
} }
createAndSaveConditionDomainObject(isDefault, index, conditionConfiguration) { createAndSaveCondition(index, conditionConfiguration) {
let newConditionDomainObject = this.createConditionDomainObject(isDefault, conditionConfiguration); let newCondition = this.createCondition(conditionConfiguration);
//persist the condition domain object so that we can do an openmct.objects.get on it and only persist the identifier in the conditionCollection of conditionSet
this.openmct.objects.mutate(newConditionDomainObject, 'created', new Date());
if (index !== undefined) { if (index !== undefined) {
this.domainObject.configuration.conditionCollection.splice(index + 1, 0, newConditionDomainObject.identifier); this.conditionSetDomainObject.configuration.conditionCollection.splice(index + 1, 0, newCondition);
} else { } else {
this.domainObject.configuration.conditionCollection.unshift(newConditionDomainObject.identifier); this.conditionSetDomainObject.configuration.conditionCollection.unshift(newCondition);
} }
this.persist(); this.initCondition(newCondition, index);
this.persistConditions();
} }
removeCondition(identifier) { removeCondition(index) {
let found = this.findConditionById(identifier); let condition = this.conditionClassCollection[index];
if (found) { condition.destroyCriteria();
let index = found.index; condition.off('conditionResultUpdated', this.handleConditionResult.bind(this));
let condition = this.conditionCollection[index]; this.conditionClassCollection.splice(index, 1);
let conditionIdAsString = condition.id; this.conditionSetDomainObject.configuration.conditionCollection.splice(index, 1);
condition.destroyCriteria(); if (this.conditionResults[condition.id] !== undefined) {
condition.off('conditionResultUpdated', this.handleConditionResult.bind(this)); delete this.conditionResults[condition.id];
this.conditionCollection.splice(index, 1);
this.domainObject.configuration.conditionCollection.splice(index, 1);
if (this.conditionResults[conditionIdAsString] !== undefined) {
delete this.conditionResults[conditionIdAsString];
}
this.persist();
this.handleConditionResult();
} }
this.persistConditions();
this.handleConditionResult();
} }
findConditionById(identifier) { findConditionById(id) {
let found; let found;
for (let i=0, ii=this.conditionCollection.length; i < ii; i++) { for (let i=0, ii=this.conditionClassCollection.length; i < ii; i++) {
if (this.conditionCollection[i].id === this.openmct.objects.makeKeyString(identifier)) { if (this.conditionClassCollection[i].id === id) {
found = { found = {
item: this.conditionCollection[i], item: this.conditionClassCollection[i],
index: i index: i
}; };
break; break;
@ -193,31 +159,30 @@ export default class ConditionManager extends EventEmitter {
return found; return found;
} }
//this.$set(this.conditionCollection, reorderEvent.newIndex, oldConditions[reorderEvent.oldIndex]); //this.$set(this.conditionClassCollection, reorderEvent.newIndex, oldConditions[reorderEvent.oldIndex]);
reorderConditions(reorderPlan) { reorderConditions(reorderPlan) {
let oldConditions = Array.from(this.domainObject.configuration.conditionCollection); let oldConditions = Array.from(this.conditionSetDomainObject.configuration.conditionCollection);
let newCollection = []; let newCollection = [];
reorderPlan.forEach((reorderEvent) => { reorderPlan.forEach((reorderEvent) => {
let item = oldConditions[reorderEvent.oldIndex]; let item = oldConditions[reorderEvent.oldIndex];
newCollection.push(item); newCollection.push(item);
this.domainObject.configuration.conditionCollection = newCollection; this.conditionSetDomainObject.configuration.conditionCollection = newCollection;
}); });
this.persist(); this.persistConditions();
} }
getCurrentConditionId() { getCurrentCondition() {
const conditionCollection = this.domainObject.configuration.conditionCollection; const conditionCollection = this.conditionSetDomainObject.configuration.conditionCollection;
let currentConditionIdentifier = conditionCollection[conditionCollection.length-1]; let currentCondition = conditionCollection[conditionCollection.length-1];
for (let i = 0; i < conditionCollection.length - 1; i++) { for (let i = 0; i < conditionCollection.length - 1; i++) {
const conditionIdAsString = this.openmct.objects.makeKeyString(conditionCollection[i]); if (this.conditionResults[conditionCollection[i].id]) {
if (this.conditionResults[conditionIdAsString]) {
//first condition to be true wins //first condition to be true wins
currentConditionIdentifier = conditionCollection[i]; currentCondition = conditionCollection[i];
break; break;
} }
} }
return currentConditionIdentifier; return currentCondition;
} }
updateConditionResults(resultObj) { updateConditionResults(resultObj) {
@ -225,31 +190,30 @@ export default class ConditionManager extends EventEmitter {
return; return;
} }
let idAsString = this.openmct.objects.makeKeyString(resultObj.id); const id = resultObj.id;
if (this.findConditionById(idAsString)) { if (this.findConditionById(id)) {
this.conditionResults[idAsString] = resultObj.data.result; this.conditionResults[id] = resultObj.data.result;
} }
this.updateTimestamp(resultObj.data); this.updateTimestamp(resultObj.data);
} }
handleConditionResult(resultObj) { handleConditionResult(resultObj) {
// update conditions results and then calculate the current condition
this.updateConditionResults(resultObj); this.updateConditionResults(resultObj);
const currentCondition = this.getCurrentCondition();
const currentConditionIdentifier = this.getCurrentConditionId(); this.emit('conditionSetResultUpdated',
this.openmct.objects.get(currentConditionIdentifier).then((obj) => { Object.assign(
this.emit('conditionSetResultUpdated', {
Object.assign( output: currentCondition.configuration.output,
{ id: this.conditionSetDomainObject.identifier,
output: obj.configuration.output, conditionId: currentCondition.id
id: this.domainObject.identifier, },
conditionId: currentConditionIdentifier this.latestTimestamp
},
this.latestTimestamp
)
) )
}); )
} }
updateTimestamp(timestamp) { updateTimestamp(timestamp) {
@ -263,51 +227,47 @@ export default class ConditionManager extends EventEmitter {
} }
requestLADConditionSetOutput() { requestLADConditionSetOutput() {
if (!this.domainObject.configuration.conditionCollection.length) { if (!this.conditionClassCollection.length || this.conditionClassCollection.length === 1) {
return Promise.resolve([]); return Promise.resolve([]);
} }
return this.load().then(() => { return this.load().then(() => {
if (this.conditionCollection && this.conditionCollection.length === 1) { const ladConditionResults = this.conditionClassCollection
return Promise([]); .filter(condition => !condition.isDefault)
} .map(condition => condition.requestLADConditionResult());
// // do not request LAD for default collection, which is always last
// for (let i = 0; i < this.conditionClassCollection.length - 1; i++) {
// ladConditionResults.push(this.conditionClassCollection[i].requestLADConditionResult());
// }
let ladConditionResults = [];
// do not request LAD for default collection, which is always last
for (let i = 0; i < this.conditionCollection.length - 1; i++) {
ladConditionResults.push(this.conditionCollection[i].requestLADConditionResult());
}
return Promise.all(ladConditionResults) return Promise.all(ladConditionResults)
.then((results) => { .then((results) => {
results.forEach(resultObj => { this.updateConditionResults(resultObj); }); results.forEach(resultObj => { this.updateConditionResults(resultObj); });
const currentConditionIdentifier = this.getCurrentConditionId(); const currentCondition = this.getCurrentCondition();
return this.openmct.objects.get(currentConditionIdentifier)
.then(obj => { // uncomment to see output of lad request (before subscriptions kick in)
// uncomment to see output of lad request (before subscriptions kick in) // console.log(obj.configuration.output);
// console.log(obj.configuration.output); return Object.assign(
return Object.assign( {
{ output: currentCondition.configuration.output,
output: obj.configuration.output, id: this.conditionSetDomainObject.identifier,
id: this.domainObject.identifier, conditionId: currentCondition.id
conditionId: currentConditionIdentifier },
}, this.latestTimestamp
this.latestTimestamp );
);
});
}); });
}); });
} }
persist() { persistConditions() {
this.openmct.objects.mutate(this.domainObject, 'configuration.conditionCollection', this.domainObject.configuration.conditionCollection); this.openmct.objects.mutate(this.conditionSetDomainObject, 'configuration.conditionCollection', this.conditionSetDomainObject.configuration.conditionCollection);
} }
destroy() { destroy() {
if (typeof this.stopObservingForChanges === 'function') { if(this.stopObservingForChanges) {
this.stopObservingForChanges(); this.stopObservingForChanges();
} }
this.conditionCollection.forEach((condition) => { this.conditionClassCollection.forEach((condition) => {
condition.off('conditionResultUpdated', this.handleConditionResult); condition.off('conditionResultUpdated', this.handleConditionResult);
condition.destroy(); condition.destroy();
}) })

View File

@ -27,6 +27,13 @@ describe('ConditionManager', () => {
let conditionMgr; let conditionMgr;
let mockListener; let mockListener;
let openmct = {}; let openmct = {};
let mockCondition = {
isDefault: true,
id: '1234-5678',
configuration: {
criteria: []
}
};
let conditionSetDomainObject = { let conditionSetDomainObject = {
identifier: { identifier: {
namespace: "", namespace: "",
@ -35,15 +42,9 @@ describe('ConditionManager', () => {
type: "conditionSet", type: "conditionSet",
location: "mine", location: "mine",
configuration: { configuration: {
conditionCollection: [] conditionCollection: [
} mockCondition
}; ]
let mockConditionDomainObject = {
isDefault: true,
type: 'condition',
identifier: {
namespace: '',
key: '1234-5678'
} }
}; };
let mockComposition; let mockComposition;
@ -57,7 +58,7 @@ describe('ConditionManager', () => {
let mockDomainObject = { let mockDomainObject = {
useCapability: function () { useCapability: function () {
return mockConditionDomainObject; return mockCondition;
} }
}; };
mockInstantiate.and.callFake(function () { mockInstantiate.and.callFake(function () {
@ -100,7 +101,7 @@ describe('ConditionManager', () => {
openmct.objects.get.and.returnValues(new Promise(function (resolve, reject) { openmct.objects.get.and.returnValues(new Promise(function (resolve, reject) {
resolve(conditionSetDomainObject); resolve(conditionSetDomainObject);
}), new Promise(function (resolve, reject) { }), new Promise(function (resolve, reject) {
resolve(mockConditionDomainObject); resolve(mockCondition);
})); }));
openmct.objects.makeKeyString.and.returnValue(conditionSetDomainObject.identifier.key); openmct.objects.makeKeyString.and.returnValue(conditionSetDomainObject.identifier.key);
openmct.objects.observe.and.returnValue(function () {}); openmct.objects.observe.and.returnValue(function () {});
@ -113,15 +114,9 @@ describe('ConditionManager', () => {
}); });
it('creates a conditionCollection with a default condition', function () { it('creates a conditionCollection with a default condition', function () {
return loader.promise.then(function () { expect(conditionMgr.conditionSetDomainObject.configuration.conditionCollection.length).toEqual(1);
return new Promise(function (resolve) { let defaultConditionId = conditionMgr.conditionClassCollection[0].id;
setTimeout(resolve); expect(defaultConditionId).toEqual(mockCondition.id);
});
}).then(function () {
expect(conditionMgr.domainObject.configuration.conditionCollection.length).toEqual(1);
let defaultConditionIdentifier = conditionMgr.domainObject.configuration.conditionCollection[0];
expect(defaultConditionIdentifier).toEqual(mockConditionDomainObject.identifier);
});
}); });
}); });

View File

@ -1,3 +1,25 @@
/*****************************************************************************
* 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.
*****************************************************************************/
import ConditionManager from './ConditionManager' import ConditionManager from './ConditionManager'
export default class ConditionSetTelemetryProvider { export default class ConditionSetTelemetryProvider {

View File

@ -64,6 +64,7 @@ describe("The condition", function () {
openmct.telemetry.getMetadata.and.returnValue(testTelemetryObject.telemetry.values); openmct.telemetry.getMetadata.and.returnValue(testTelemetryObject.telemetry.values);
testConditionDefinition = { testConditionDefinition = {
id: '123-456',
configuration: { configuration: {
trigger: TRIGGER.ANY, trigger: TRIGGER.ANY,
criteria: [ criteria: [

View File

@ -64,15 +64,13 @@ export default class StyleRuleManager extends EventEmitter {
updateConditionStylesMap(conditionStyles) { updateConditionStylesMap(conditionStyles) {
let conditionStyleMap = {}; let conditionStyleMap = {};
conditionStyles.forEach((conditionStyle) => { conditionStyles.forEach((conditionStyle) => {
const identifier = this.openmct.objects.makeKeyString(conditionStyle.conditionIdentifier); conditionStyleMap[conditionStyle.conditionId] = conditionStyle.style;
conditionStyleMap[identifier] = conditionStyle.style;
}); });
this.conditionalStyleMap = conditionStyleMap; this.conditionalStyleMap = conditionStyleMap;
} }
handleConditionSetResultUpdated(resultData) { handleConditionSetResultUpdated(resultData) {
let identifier = this.openmct.objects.makeKeyString(resultData.conditionId); let foundStyle = this.conditionalStyleMap[resultData.conditionId];
let foundStyle = this.conditionalStyleMap[identifier];
if (foundStyle) { if (foundStyle) {
if (foundStyle !== this.currentStyle) { if (foundStyle !== this.currentStyle) {
this.currentStyle = foundStyle; this.currentStyle = foundStyle;

View File

@ -23,14 +23,13 @@
<template> <template>
<div v-if="isEditing" <div v-if="isEditing"
class="c-condition c-condition--edit js-condition-drag-wrapper" class="c-condition c-condition--edit js-condition-drag-wrapper"
:class="{ 'c-condition--current-match': currentConditionIdentifier && (currentConditionIdentifier.key === conditionIdentifier.key) }"
> >
<!-- Edit view --> <!-- Edit view -->
<div class="c-condition__header"> <div class="c-condition__header">
<span class="c-condition__drag-grippy c-grippy c-grippy--vertical-drag" <span class="c-condition__drag-grippy c-grippy c-grippy--vertical-drag"
title="Drag to reorder conditions" title="Drag to reorder conditions"
:class="[{ 'is-enabled': !domainObject.isDefault }, { 'hide-nice': domainObject.isDefault }]" :class="[{ 'is-enabled': !condition.isDefault }, { 'hide-nice': condition.isDefault }]"
:draggable="!domainObject.isDefault" :draggable="!condition.isDefault"
@dragstart="dragStart" @dragstart="dragStart"
@dragstop="dragStop" @dragstop="dragStop"
@dragover.stop @dragover.stop
@ -41,20 +40,20 @@
@click="expanded = !expanded" @click="expanded = !expanded"
></span> ></span>
<span class="c-condition__name">{{ domainObject.configuration.name }}</span> <span class="c-condition__name">{{ condition.configuration.name }}</span>
<!-- TODO: description should be derived from criteria --> <!-- TODO: description should be derived from criteria -->
<span class="c-condition__summary"> <span class="c-condition__summary">
Description/summary goes here {{ domainObject.configuration.description }} Description/summary goes here {{ condition.configuration.description }}
</span> </span>
<div class="c-condition__buttons"> <div class="c-condition__buttons">
<button v-if="!domainObject.isDefault" <button v-if="!condition.isDefault"
class="c-click-icon c-condition__duplicate-button icon-duplicate" class="c-click-icon c-condition__duplicate-button icon-duplicate"
title="Duplicate this condition" title="Duplicate this condition"
@click="cloneCondition" @click="cloneCondition"
></button> ></button>
<button v-if="!domainObject.isDefault" <button v-if="!condition.isDefault"
class="c-click-icon c-condition__delete-button icon-trash" class="c-click-icon c-condition__delete-button icon-trash"
title="Delete this condition" title="Delete this condition"
@click="removeCondition" @click="removeCondition"
@ -67,7 +66,7 @@
<span class="c-cdef__separator c-row-separator"></span> <span class="c-cdef__separator c-row-separator"></span>
<span class="c-cdef__label">Condition Name</span> <span class="c-cdef__label">Condition Name</span>
<span class="c-cdef__controls"> <span class="c-cdef__controls">
<input v-model="domainObject.configuration.name" <input v-model="condition.configuration.name"
class="t-condition-input__name" class="t-condition-input__name"
type="text" type="text"
@blur="persist" @blur="persist"
@ -88,20 +87,20 @@
</option> </option>
</select> </select>
<input v-if="selectedOutputSelection === outputOptions[2]" <input v-if="selectedOutputSelection === outputOptions[2]"
v-model="domainObject.configuration.output" v-model="condition.configuration.output"
class="t-condition-name-input" class="t-condition-name-input"
type="text" type="text"
@blur="persist" @blur="persist"
> >
</span> </span>
<div v-if="!domainObject.isDefault" <div v-if="!condition.isDefault"
class="c-cdef__match-and-criteria" class="c-cdef__match-and-criteria"
> >
<span class="c-cdef__separator c-row-separator"></span> <span class="c-cdef__separator c-row-separator"></span>
<span class="c-cdef__label">Match</span> <span class="c-cdef__label">Match</span>
<span class="c-cdef__controls"> <span class="c-cdef__controls">
<select v-model="domainObject.configuration.trigger" <select v-model="condition.configuration.trigger"
@change="persist" @change="persist"
> >
<option value="all">when all criteria are met</option> <option value="all">when all criteria are met</option>
@ -110,15 +109,15 @@
</span> </span>
<template v-if="telemetry.length"> <template v-if="telemetry.length">
<div v-for="(criterion, index) in domainObject.configuration.criteria" <div v-for="(criterion, index) in condition.configuration.criteria"
:key="index" :key="index"
class="c-cdef__criteria" class="c-cdef__criteria"
> >
<Criterion :telemetry="telemetry" <Criterion :telemetry="telemetry"
:criterion="criterion" :criterion="criterion"
:index="index" :index="index"
:trigger="domainObject.configuration.trigger" :trigger="condition.configuration.trigger"
:is-default="domainObject.configuration.criteria.length === 1" :is-default="condition.configuration.criteria.length === 1"
@persist="persist" @persist="persist"
/> />
<div class="c-cdef__criteria__buttons"> <div class="c-cdef__criteria__buttons">
@ -126,7 +125,7 @@
title="Duplicate this criteria" title="Duplicate this criteria"
@click="cloneCriterion(index)" @click="cloneCriterion(index)"
></button> ></button>
<button v-if="!(domainObject.configuration.criteria.length === 1)" <button v-if="!(condition.configuration.criteria.length === 1)"
class="c-click-icon c-cdef__criteria-duplicate-button icon-trash" class="c-click-icon c-cdef__criteria-duplicate-button icon-trash"
title="Delete this criteria" title="Delete this criteria"
@click="removeCriterion(index)" @click="removeCriterion(index)"
@ -150,19 +149,18 @@
</div> </div>
<div v-else <div v-else
class="c-condition c-condition--browse" class="c-condition c-condition--browse"
:class="{ 'c-condition--current': currentConditionIdentifier && (currentConditionIdentifier.key === conditionIdentifier.key) }"
> >
<!-- Browse view --> <!-- Browse view -->
<div class="c-condition__header"> <div class="c-condition__header">
<span class="c-condition__name"> <span class="c-condition__name">
{{ domainObject.configuration.name }} {{ condition.configuration.name }}
</span> </span>
<span class="c-condition__output"> <span class="c-condition__output">
Output: {{ domainObject.configuration.output }} Output: {{ condition.configuration.output }}
</span> </span>
</div> </div>
<div class="c-condition__summary"> <div class="c-condition__summary">
Description/summary goes here {{ domainObject.configuration.description }} Description/summary goes here {{ condition.configuration.description }}
</div> </div>
</div> </div>
</template> </template>
@ -176,11 +174,7 @@ export default {
Criterion Criterion
}, },
props: { props: {
conditionIdentifier: { condition: {
type: Object,
required: true
},
currentConditionIdentifier: {
type: Object, type: Object,
required: true required: true
}, },
@ -200,9 +194,6 @@ export default {
}, },
data() { data() {
return { return {
domainObject: {
configuration: {}
},
currentCriteria: this.currentCriteria, currentCriteria: this.currentCriteria,
expanded: true, expanded: true,
trigger: 'all', trigger: 'all',
@ -215,17 +206,11 @@ export default {
this.destroy(); this.destroy();
}, },
mounted() { mounted() {
this.openmct.objects.get(this.conditionIdentifier).then((domainObject => { this.setOutputSelection();
this.domainObject = domainObject;
this.initialize();
}));
}, },
methods: { methods: {
initialize() {
this.setOutputSelection();
},
setOutputSelection() { setOutputSelection() {
let conditionOutput = this.domainObject.configuration.output; let conditionOutput = this.condition.configuration.output;
if (conditionOutput) { if (conditionOutput) {
if (conditionOutput !== 'false' && conditionOutput !== 'true') { if (conditionOutput !== 'false' && conditionOutput !== 'true') {
this.selectedOutputSelection = 'string'; this.selectedOutputSelection = 'string';
@ -236,9 +221,9 @@ export default {
}, },
setOutputValue() { setOutputValue() {
if (this.selectedOutputSelection === 'string') { if (this.selectedOutputSelection === 'string') {
this.domainObject.configuration.output = ''; this.condition.configuration.output = '';
} else { } else {
this.domainObject.configuration.output = this.selectedOutputSelection; this.condition.configuration.output = this.selectedOutputSelection;
} }
this.persist(); this.persist();
}, },
@ -249,7 +234,7 @@ export default {
input: '', input: '',
metadata: '' metadata: ''
}; };
this.domainObject.configuration.criteria.push(criteriaObject); this.condition.configuration.criteria.push(criteriaObject);
}, },
dragStart(e) { dragStart(e) {
e.dataTransfer.setData('dragging', e.target); // required for FF to initiate drag e.dataTransfer.setData('dragging', e.target); // required for FF to initiate drag
@ -263,32 +248,35 @@ export default {
destroy() { destroy() {
}, },
removeCondition(ev) { removeCondition(ev) {
this.$emit('removeCondition', this.conditionIdentifier); this.$emit('removeCondition', this.conditionIndex);
}, },
cloneCondition(ev) { cloneCondition(ev) {
this.$emit('cloneCondition', { this.$emit('cloneCondition', {
identifier: this.conditionIdentifier, condition: this.condition,
index: Number(ev.target.closest('.widget-condition').getAttribute('data-condition-index')) index: this.conditionIndex
}); });
}, },
removeCriterion(index) { removeCriterion(index) {
this.domainObject.configuration.criteria.splice(index, 1); this.condition.configuration.criteria.splice(index, 1);
this.persist() this.persist()
}, },
cloneCriterion(index) { cloneCriterion(index) {
const clonedCriterion = {...this.domainObject.configuration.criteria[index]}; const clonedCriterion = {...this.condition.configuration.criteria[index]};
this.domainObject.configuration.criteria.splice(index + 1, 0, clonedCriterion); this.condition.configuration.criteria.splice(index + 1, 0, clonedCriterion);
this.persist() this.persist()
}, },
hasTelemetry(identifier) { hasTelemetry(identifier) {
// TODO: check parent domainObject.composition.hasTelemetry // TODO: check parent condition.composition.hasTelemetry
return this.currentCriteria && identifier; return this.currentCriteria && identifier;
}, },
persist() { persist() {
this.openmct.objects.mutate(this.domainObject, 'configuration', this.domainObject.configuration); this.$emit('updateCondition', {
condition: this.condition,
index: this.conditionIndex
});
}, },
initCap: function (string) { initCap: function (str) {
return string.charAt(0).toUpperCase() + string.slice(1) return str.charAt(0).toUpperCase() + str.slice(1)
} }
} }
} }

View File

@ -54,8 +54,8 @@
</button> </button>
<div class="c-cs__conditions-h"> <div class="c-cs__conditions-h">
<div v-for="(conditionIdentifier, index) in conditionCollection" <div v-for="(condition, index) in conditionCollection"
:key="conditionIdentifier.key" :key="condition.id"
class="c-condition-h" class="c-condition-h"
> >
<div v-if="isEditing" <div v-if="isEditing"
@ -65,11 +65,11 @@
@dragleave="dragLeave" @dragleave="dragLeave"
@dragover.prevent @dragover.prevent
></div> ></div>
<Condition :condition-identifier="conditionIdentifier" <Condition :condition="condition"
:current-condition-identifier="currentConditionIdentifier"
:condition-index="index" :condition-index="index"
:telemetry="telemetryObjs" :telemetry="telemetryObjs"
:is-editing="isEditing" :is-editing="isEditing"
@updateCondition="updateCondition"
@removeCondition="removeCondition" @removeCondition="removeCondition"
@cloneCondition="cloneCondition" @cloneCondition="cloneCondition"
@setMoveIndex="setMoveIndex" @setMoveIndex="setMoveIndex"
@ -95,11 +95,9 @@ export default {
data() { data() {
return { return {
expanded: true, expanded: true,
parentKeyString: this.openmct.objects.makeKeyString(this.domainObject.identifier),
conditionCollection: [], conditionCollection: [],
conditionResults: {}, conditionResults: {},
conditions: [], conditions: [],
currentConditionIdentifier: this.currentConditionIdentifier || {},
telemetryObjs: [], telemetryObjs: [],
moveIndex: Number, moveIndex: Number,
isDragging: false isDragging: false
@ -111,7 +109,7 @@ export default {
if(this.conditionManager) { if(this.conditionManager) {
this.conditionManager.destroy(); this.conditionManager.destroy();
} }
if (typeof this.stopObservingForChanges === 'function') { if (this.stopObservingForChanges) {
this.stopObservingForChanges(); this.stopObservingForChanges();
} }
}, },
@ -121,13 +119,13 @@ export default {
this.composition.on('remove', this.removeTelemetryObject); this.composition.on('remove', this.removeTelemetryObject);
this.composition.load(); this.composition.load();
this.conditionCollection = this.domainObject.configuration.conditionCollection; this.conditionCollection = this.domainObject.configuration.conditionCollection;
this.conditionManager = new ConditionManager(this.domainObject, this.openmct);
this.observeForChanges(); this.observeForChanges();
this.conditionManager = new ConditionManager(this.domainObject, this.openmct);
}, },
methods: { methods: {
observeForChanges() { observeForChanges() {
this.stopObservingForChanges = this.openmct.objects.observe(this.domainObject, '*', (newDomainObject) => { this.stopObservingForChanges = this.openmct.objects.observe(this.domainObject, 'configuration.conditionCollection', (newConditionCollection) => {
this.conditionCollection = newDomainObject.configuration.conditionCollection; this.conditionCollection = newConditionCollection;
}); });
}, },
setMoveIndex(index) { setMoveIndex(index) {
@ -189,20 +187,20 @@ export default {
this.telemetryObjs.splice(index, 1); this.telemetryObjs.splice(index, 1);
} }
}, },
addCondition(event, isDefault, index) { addCondition() {
this.conditionManager.addCondition(!!isDefault, index); this.conditionManager.addCondition();
}, },
updateCurrentCondition(identifier) { updateCondition(data) {
this.currentConditionIdentifier = identifier; this.conditionManager.updateCondition(data.condition, data.index);
}, },
removeCondition(identifier) { removeCondition(index) {
this.conditionManager.removeCondition(identifier); this.conditionManager.removeCondition(index);
}, },
reorder(reorderPlan) { reorder(reorderPlan) {
this.conditionManager.reorderConditions(reorderPlan); this.conditionManager.reorderConditions(reorderPlan);
}, },
cloneCondition(condition) { cloneCondition(data) {
this.conditionManager.cloneCondition(condition.identifier, condition.index); this.conditionManager.cloneCondition(data.condition, data.index);
} }
} }
} }

View File

@ -52,7 +52,7 @@
<input v-model="criterion.input[inputIndex]" <input v-model="criterion.input[inputIndex]"
class="c-cdef__control__input" class="c-cdef__control__input"
type="text" type="text"
@blur="persist" @change="persist"
> >
<span v-if="inputIndex < inputCount-1">and</span> <span v-if="inputIndex < inputCount-1">and</span>
</span> </span>

View File

@ -79,7 +79,7 @@ export default {
}, },
data() { data() {
return { return {
expanded: true, expanded: false,
isApplied: true isApplied: true
}; };
}, },

View File

@ -1,9 +1,9 @@
<template> <template>
<div> <div>
<div v-if="condition" <div v-if="conditionName"
class="holder c-c-button-wrapper align-left" class="holder c-c-button-wrapper align-left"
> >
<div>{{ condition.configuration.name }}</div> <div>{{ conditionName }}</div>
</div> </div>
</div> </div>
</template> </template>
@ -17,22 +17,12 @@ export default {
'openmct' 'openmct'
], ],
props: { props: {
conditionIdentifier: { conditionName: {
type: Object, type: String,
required: true required: true
} }
}, },
data() {
return {
condition: null
}
},
destroyed() { destroyed() {
},
mounted() {
this.openmct.objects.get(this.conditionIdentifier).then((conditionDomainObject) => {
this.condition = conditionDomainObject;
});
} }
} }
</script> </script>

View File

@ -21,9 +21,9 @@
</div> </div>
<ul> <ul>
<li v-for="conditionStyle in conditionalStyles" <li v-for="conditionStyle in conditionalStyles"
:key="conditionStyle.conditionIdentifier.key" :key="conditionStyle.conditionId"
> >
<conditional-style :condition-identifier="conditionStyle.conditionIdentifier" <conditional-style :condition-name="conditionStyle.conditionName"
:condition-style="conditionStyle.style" :condition-style="conditionStyle.style"
/> />
</li> </li>
@ -77,9 +77,10 @@ export default {
initializeConditionalStyles() { initializeConditionalStyles() {
const backgroundColors = [{backgroundColor: 'red'},{backgroundColor: 'orange'}, {backgroundColor: 'blue'}]; const backgroundColors = [{backgroundColor: 'red'},{backgroundColor: 'orange'}, {backgroundColor: 'blue'}];
this.openmct.objects.get(this.conditionSetIdentifier).then((conditionSetDomainObject) => { this.openmct.objects.get(this.conditionSetIdentifier).then((conditionSetDomainObject) => {
conditionSetDomainObject.configuration.conditionCollection.forEach((identifier, index) => { conditionSetDomainObject.configuration.conditionCollection.forEach((conditionConfiguration, index) => {
this.conditionalStyles.push({ this.conditionalStyles.push({
conditionIdentifier: identifier, conditionId: conditionConfiguration.id,
conditionName: conditionConfiguration.name,
style: backgroundColors[index] style: backgroundColors[index]
}); });
}); });
@ -92,7 +93,7 @@ export default {
}, },
findStyleByConditionId(id) { findStyleByConditionId(id) {
for(let i=0, ii=this.conditionalStyles.length; i < ii; i++) { for(let i=0, ii=this.conditionalStyles.length; i < ii; i++) {
if (this.openmct.objects.makeKeyString(this.conditionalStyles[i].conditionIdentifier) === this.openmct.objects.makeKeyString(id)) { if (this.conditionalStyles[i].conditionId === id) {
return { return {
index: i, index: i,
item: this.conditionalStyles[i] item: this.conditionalStyles[i]
@ -100,8 +101,8 @@ export default {
} }
} }
}, },
updateConditionalStyle(conditionIdentifier, style) { updateConditionalStyle(conditionId, style) {
let found = this.findStyleByConditionId(conditionIdentifier); let found = this.findStyleByConditionId(conditionId);
if (found) { if (found) {
this.conditionalStyles[found.index].style = style; this.conditionalStyles[found.index].style = style;
} }

View File

@ -23,19 +23,11 @@ import ConditionSetViewProvider from './ConditionSetViewProvider.js';
import ConditionSetCompositionPolicy from "./ConditionSetCompositionPolicy"; import ConditionSetCompositionPolicy from "./ConditionSetCompositionPolicy";
import ConditionSetMetadataProvider from './ConditionSetMetadataProvider'; import ConditionSetMetadataProvider from './ConditionSetMetadataProvider';
import ConditionSetTelemetryProvider from './ConditionSetTelemetryProvider'; import ConditionSetTelemetryProvider from './ConditionSetTelemetryProvider';
import uuid from "uuid";
export default function ConditionPlugin() { export default function ConditionPlugin() {
return function install(openmct) { return function install(openmct) {
openmct.types.addType('condition', {
name: 'Condition',
key: 'condition',
description: 'A list of criteria which will be evaluated based on a trigger',
creatable: false,
initialize: function (domainObject) {
domainObject.composition = [];
}
});
openmct.types.addType('conditionSet', { openmct.types.addType('conditionSet', {
name: 'Condition Set', name: 'Condition Set',
@ -45,7 +37,17 @@ export default function ConditionPlugin() {
cssClass: 'icon-conditional', // TODO: replace with class for new icon cssClass: 'icon-conditional', // TODO: replace with class for new icon
initialize: function (domainObject) { initialize: function (domainObject) {
domainObject.configuration = { domainObject.configuration = {
conditionCollection: [] conditionCollection: [{
isDefault: true,
id: uuid(),
configuration: {
name: 'Default',
output: 'false',
trigger: 'all',
criteria: []
},
summary: 'Default condition'
}]
}; };
domainObject.composition = []; domainObject.composition = [];
domainObject.telemetry = {}; domainObject.telemetry = {};

View File

@ -26,26 +26,14 @@ import ConditionPlugin from "./plugin";
let openmct = createOpenMct(); let openmct = createOpenMct();
openmct.install(new ConditionPlugin()); openmct.install(new ConditionPlugin());
let conditionDefinition;
let conditionSetDefinition; let conditionSetDefinition;
let mockDomainObject; let mockConditionSetDomainObject;
let mockDomainObject2;
let element; let element;
let child; let child;
describe('the plugin', function () { describe('the plugin', function () {
beforeAll((done) => { beforeAll((done) => {
conditionDefinition = openmct.types.get('condition').definition;
mockDomainObject = {
identifier: {
key: 'testConditionKey',
namespace: ''
},
type: 'condition'
};
conditionDefinition.initialize(mockDomainObject);
conditionSetDefinition = openmct.types.get('conditionSet').definition; conditionSetDefinition = openmct.types.get('conditionSet').definition;
const appHolder = document.createElement('div'); const appHolder = document.createElement('div');
@ -56,7 +44,7 @@ describe('the plugin', function () {
child = document.createElement('div'); child = document.createElement('div');
element.appendChild(child); element.appendChild(child);
mockDomainObject2 = { mockConditionSetDomainObject = {
identifier: { identifier: {
key: 'testConditionSetKey', key: 'testConditionSetKey',
namespace: '' namespace: ''
@ -64,22 +52,12 @@ describe('the plugin', function () {
type: 'conditionSet' type: 'conditionSet'
}; };
conditionSetDefinition.initialize(mockDomainObject2); conditionSetDefinition.initialize(mockConditionSetDomainObject);
openmct.on('start', done); openmct.on('start', done);
openmct.start(appHolder); openmct.start(appHolder);
}); });
let mockConditionObject = {
name: 'Condition',
key: 'condition',
creatable: false
};
it('defines a condition object type with the correct key', () => {
expect(conditionDefinition.key).toEqual(mockConditionObject.key);
});
let mockConditionSetObject = { let mockConditionSetObject = {
name: 'Condition Set', name: 'Condition Set',
key: 'conditionSet', key: 'conditionSet',
@ -90,18 +68,6 @@ describe('the plugin', function () {
expect(conditionSetDefinition.key).toEqual(mockConditionSetObject.key); expect(conditionSetDefinition.key).toEqual(mockConditionSetObject.key);
}); });
describe('the condition object', () => {
it('is not creatable', () => {
expect(conditionDefinition.creatable).toEqual(mockConditionObject.creatable);
});
it('initializes with an empty composition list', () => {
expect(mockDomainObject.composition instanceof Array).toBeTrue();
expect(mockDomainObject.composition.length).toEqual(0);
});
});
describe('the conditionSet object', () => { describe('the conditionSet object', () => {
it('is creatable', () => { it('is creatable', () => {
@ -109,8 +75,8 @@ describe('the plugin', function () {
}); });
it('initializes with an empty composition list', () => { it('initializes with an empty composition list', () => {
expect(mockDomainObject2.composition instanceof Array).toBeTrue(); expect(mockConditionSetDomainObject.composition instanceof Array).toBeTrue();
expect(mockDomainObject2.composition.length).toEqual(0); expect(mockConditionSetDomainObject.composition.length).toEqual(0);
}); });
it('provides a view', () => { it('provides a view', () => {