mirror of
https://github.com/nasa/openmct.git
synced 2025-04-08 20:04:27 +00:00
Adds NOT and XOR triggers for conditions (#2816)
* Adds XOR and NOT triggers for conditions * Adds unit tests and fixes linting issues
This commit is contained in:
parent
f9e88321a3
commit
a31d10e708
@ -24,12 +24,12 @@ import EventEmitter from 'EventEmitter';
|
||||
import uuid from 'uuid';
|
||||
import TelemetryCriterion from "./criterion/TelemetryCriterion";
|
||||
import { TRIGGER } from "./utils/constants";
|
||||
import {computeCondition} from "./utils/evaluator";
|
||||
import {computeCondition, computeConditionByLimit} from "./utils/evaluator";
|
||||
|
||||
/*
|
||||
* conditionConfiguration = {
|
||||
* id: uuid,
|
||||
* trigger: 'any'/'all',
|
||||
* trigger: 'any'/'all'/'not','xor',
|
||||
* criteria: [
|
||||
* {
|
||||
* telemetry: '',
|
||||
@ -205,7 +205,8 @@ export default class ConditionClass extends EventEmitter {
|
||||
const id = eventData.id;
|
||||
|
||||
if (this.findCriterion(id)) {
|
||||
this.criteriaResults[id] = eventData.data.result;
|
||||
// The !! here is important to convert undefined to false otherwise the criteriaResults won't get deleted when the criteria is destroyed
|
||||
this.criteriaResults[id] = !!eventData.data.result;
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,7 +260,13 @@ export default class ConditionClass extends EventEmitter {
|
||||
}
|
||||
|
||||
evaluate() {
|
||||
this.result = computeCondition(this.criteriaResults, this.trigger === TRIGGER.ALL);
|
||||
if (this.trigger && this.trigger === TRIGGER.XOR) {
|
||||
this.result = computeConditionByLimit(this.criteriaResults, 1);
|
||||
} else if (this.trigger && this.trigger === TRIGGER.NOT) {
|
||||
this.result = computeConditionByLimit(this.criteriaResults, 0);
|
||||
} else {
|
||||
this.result = computeCondition(this.criteriaResults, this.trigger === TRIGGER.ALL);
|
||||
}
|
||||
}
|
||||
|
||||
getLatestTimestamp(current, compare) {
|
||||
|
@ -28,7 +28,6 @@ describe('ConditionSetCompositionPolicy', () => {
|
||||
let testTelemetryObject;
|
||||
let openmct = {};
|
||||
let parentDomainObject;
|
||||
let composition;
|
||||
|
||||
beforeAll(function () {
|
||||
testTelemetryObject = {
|
||||
@ -57,7 +56,6 @@ describe('ConditionSetCompositionPolicy', () => {
|
||||
openmct.telemetry = jasmine.createSpyObj('telemetry', ['isTelemetryObject']);
|
||||
policy = new ConditionSetCompositionPolicy(openmct);
|
||||
parentDomainObject = {};
|
||||
composition = {};
|
||||
});
|
||||
|
||||
it('returns true for object types that are not conditionSets', function () {
|
||||
|
@ -112,7 +112,6 @@ describe("The condition", function () {
|
||||
});
|
||||
|
||||
it("initializes with an id", function () {
|
||||
console.log(conditionObj);
|
||||
expect(conditionObj.id).toBeDefined();
|
||||
});
|
||||
|
||||
|
@ -114,8 +114,10 @@
|
||||
<select v-model="condition.configuration.trigger"
|
||||
@change="persist"
|
||||
>
|
||||
<option value="all">when all criteria are met</option>
|
||||
<option value="any">when any criteria are met</option>
|
||||
<option v-for="option in triggers"
|
||||
:key="option.value"
|
||||
:value="option.value"
|
||||
> {{ option.label }}</option>
|
||||
</select>
|
||||
</span>
|
||||
|
||||
@ -181,6 +183,7 @@
|
||||
<script>
|
||||
import Criterion from './Criterion.vue';
|
||||
import ConditionDescription from "./ConditionDescription.vue";
|
||||
import { TRIGGER, TRIGGER_LABEL } from "@/plugins/condition/utils/constants";
|
||||
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
@ -220,6 +223,17 @@ export default {
|
||||
};
|
||||
},
|
||||
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) {
|
||||
|
@ -77,9 +77,22 @@ export default {
|
||||
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.condition.configuration.trigger === TRIGGER.ANY ? ' or ' : ' and ';
|
||||
this.triggerDescription = this.getTriggerDescription(this.condition.configuration.trigger);
|
||||
this.criterionDescriptions = [];
|
||||
this.condition.configuration.criteria.forEach((criterion, index) => {
|
||||
this.getCriterionDescription(criterion, index);
|
||||
|
@ -1,6 +1,15 @@
|
||||
export const TRIGGER = {
|
||||
ANY: 'any',
|
||||
ALL: 'all'
|
||||
ALL: 'all',
|
||||
NOT: 'not',
|
||||
XOR: 'xor'
|
||||
};
|
||||
|
||||
export const TRIGGER_LABEL = {
|
||||
'any': 'when any criteria are met',
|
||||
'all': 'when all criteria are met',
|
||||
'not': 'when no criteria are met',
|
||||
'xor': 'when only one criteria is met'
|
||||
};
|
||||
|
||||
export const STYLE_CONSTANTS = {
|
||||
|
@ -14,3 +14,19 @@ export const computeCondition = (resultMap, allMustBeTrue) => {
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
//Returns true only if limit number of results are satisfied
|
||||
export const computeConditionByLimit = (resultMap, limit) => {
|
||||
let trueCount = 0;
|
||||
for (let key in resultMap) {
|
||||
if (resultMap.hasOwnProperty(key)) {
|
||||
if (resultMap[key]) {
|
||||
trueCount++;
|
||||
}
|
||||
if (trueCount > limit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return trueCount === limit;
|
||||
};
|
||||
|
66
src/plugins/condition/utils/evaluatorSpec.js
Normal file
66
src/plugins/condition/utils/evaluatorSpec.js
Normal file
@ -0,0 +1,66 @@
|
||||
/*****************************************************************************
|
||||
* 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 { computeConditionByLimit } from "./evaluator";
|
||||
|
||||
describe('evaluate results based on trigger', function () {
|
||||
|
||||
it('should evaluate to true if trigger is NOT', () => {
|
||||
const results = {
|
||||
result: false,
|
||||
result1: false,
|
||||
result2: false
|
||||
};
|
||||
const result = computeConditionByLimit(results, 0);
|
||||
expect(result).toBeTrue();
|
||||
});
|
||||
|
||||
it('should evaluate to false if trigger is NOT', () => {
|
||||
const results = {
|
||||
result: true,
|
||||
result1: false,
|
||||
result2: false
|
||||
};
|
||||
const result = computeConditionByLimit(results, 0);
|
||||
expect(result).toBeFalse();
|
||||
});
|
||||
|
||||
it('should evaluate to true if trigger is XOR', () => {
|
||||
const results = {
|
||||
result: false,
|
||||
result1: true,
|
||||
result2: false
|
||||
};
|
||||
const result = computeConditionByLimit(results, 1);
|
||||
expect(result).toBeTrue();
|
||||
});
|
||||
|
||||
it('should evaluate to false if trigger is XOR', () => {
|
||||
const results = {
|
||||
result: false,
|
||||
result1: true,
|
||||
result2: true
|
||||
};
|
||||
const result = computeConditionByLimit(results, 1);
|
||||
expect(result).toBeFalse();
|
||||
});
|
||||
});
|
@ -26,6 +26,7 @@ export default function ImageryViewProvider(openmct) {
|
||||
return {
|
||||
show: function (element) {
|
||||
component = new Vue({
|
||||
el: element,
|
||||
components: {
|
||||
ImageryViewLayout
|
||||
},
|
||||
@ -33,7 +34,6 @@ export default function ImageryViewProvider(openmct) {
|
||||
openmct,
|
||||
domainObject
|
||||
},
|
||||
el: element,
|
||||
template: '<imagery-view-layout ref="ImageryLayout"></imagery-view-layout>'
|
||||
});
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user