Merge branch 'condition-ui' of https://github.com/nasa/openmct into condition-clone

This commit is contained in:
Joshi 2020-01-28 13:03:43 -08:00
commit a5a3e41d21
5 changed files with 108 additions and 45 deletions

View File

@ -24,6 +24,7 @@ import * as EventEmitter from 'eventemitter3';
import uuid from 'uuid'; import uuid from 'uuid';
import TelemetryCriterion from "@/plugins/condition/criterion/TelemetryCriterion"; import TelemetryCriterion from "@/plugins/condition/criterion/TelemetryCriterion";
import { TRIGGER } from "@/plugins/condition/utils/constants"; import { TRIGGER } from "@/plugins/condition/utils/constants";
import {computeConditionForAll, computeConditionForAny} from "@/plugins/condition/utils/evaluator";
/* /*
* conditionDefinition = { * conditionDefinition = {
@ -56,6 +57,7 @@ export default class ConditionClass extends EventEmitter {
this.openmct = openmct; this.openmct = openmct;
this.id = this.openmct.objects.makeKeyString(conditionDefinition.identifier); this.id = this.openmct.objects.makeKeyString(conditionDefinition.identifier);
this.criteria = []; this.criteria = [];
this.criteriaResults = {};
if (conditionDefinition.definition.criteria) { if (conditionDefinition.definition.criteria) {
this.createCriteria(conditionDefinition.definition.criteria); this.createCriteria(conditionDefinition.definition.criteria);
} }
@ -71,12 +73,11 @@ export default class ConditionClass extends EventEmitter {
update(newDomainObject) { update(newDomainObject) {
this.updateTrigger(newDomainObject.definition.trigger); this.updateTrigger(newDomainObject.definition.trigger);
this.updateCriteria(newDomainObject.definition.criteria); this.updateCriteria(newDomainObject.definition.criteria);
this.handleConditionUpdated();
} }
updateTrigger(conditionDefinition) { updateTrigger(trigger) {
if (this.trigger !== conditionDefinition.trigger) { if (this.trigger !== trigger) {
this.trigger = conditionDefinition.trigger; this.trigger = trigger;
this.handleConditionUpdated(); this.handleConditionUpdated();
} }
} }
@ -109,6 +110,7 @@ export default class ConditionClass extends EventEmitter {
let criterionDefinitionWithId = this.generateCriterion(criterionDefinition || null); let criterionDefinitionWithId = this.generateCriterion(criterionDefinition || null);
let criterion = new TelemetryCriterion(criterionDefinitionWithId, this.openmct); let criterion = new TelemetryCriterion(criterionDefinitionWithId, this.openmct);
criterion.on('criterionUpdated', (obj) => this.handleCriterionUpdated(obj)); criterion.on('criterionUpdated', (obj) => this.handleCriterionUpdated(obj));
criterion.on('criterionResultUpdated', (obj) => this.handleCriterionResult(obj));
if (!this.criteria) { if (!this.criteria) {
this.criteria = []; this.criteria = [];
} }
@ -138,12 +140,17 @@ export default class ConditionClass extends EventEmitter {
if (found) { if (found) {
const newCriterionDefinition = this.generateCriterion(criterionDefinition); const newCriterionDefinition = this.generateCriterion(criterionDefinition);
let newCriterion = new TelemetryCriterion(newCriterionDefinition, this.openmct); let newCriterion = new TelemetryCriterion(newCriterionDefinition, this.openmct);
newCriterion.on('criterionUpdated', (obj) => this.handleCriterionUpdated(obj));
newCriterion.on('criterionResultUpdated', (obj) => this.handleCriterionResult(obj));
let criterion = found.item; let criterion = found.item;
criterion.unsubscribe(); criterion.unsubscribe();
criterion.off('criterionUpdated', (result) => { criterion.off('criterionUpdated', (obj) => this.handleCriterionUpdated(obj));
this.handleCriterionUpdated(id, result); criterion.off('criterionResultUpdated', (obj) => this.handleCriterionResult(obj));
});
this.criteria.splice(found.index, 1, newCriterion); this.criteria.splice(found.index, 1, newCriterion);
if (this.criteriaResults[criterion.id] !== undefined) {
delete this.criteriaResults[criterion.id];
}
this.handleConditionUpdated(); this.handleConditionUpdated();
} }
} }
@ -163,6 +170,9 @@ export default class ConditionClass extends EventEmitter {
this.handleCriterionUpdated(id, result); this.handleCriterionUpdated(id, result);
}); });
this.criteria.splice(found.index, 1); this.criteria.splice(found.index, 1);
if (this.criteriaResults[criterion.id] !== undefined) {
delete this.criteriaResults[criterion.id];
}
return true; return true;
} }
return false; return false;
@ -173,14 +183,30 @@ export default class ConditionClass extends EventEmitter {
if (found) { if (found) {
this.criteria[found.index] = criterion.data; this.criteria[found.index] = criterion.data;
//Most likely don't need this. //Most likely don't need this.
this.subscribe();
this.emitEvent('conditionUpdated', { this.emitEvent('conditionUpdated', {
trigger: this.trigger, trigger: this.trigger,
criteria: this.criteria criteria: this.criteria
}); });
} }
}
handleCriterionResult(eventData) {
let id = eventData.id;
let result = eventData.data.result;
let found = this.findCriterion(id);
if (found) {
this.criteriaResults[id] = result;
}
this.handleConditionUpdated(); this.handleConditionUpdated();
} }
subscribe() {
this.criteria.forEach((criterion) => {
criterion.subscribe();
})
}
handleConditionUpdated() { handleConditionUpdated() {
// trigger an updated event so that consumers can react accordingly // trigger an updated event so that consumers can react accordingly
this.evaluate(); this.evaluate();
@ -203,9 +229,9 @@ export default class ConditionClass extends EventEmitter {
//TODO: implement as part of the evaluator class task. //TODO: implement as part of the evaluator class task.
evaluate() { evaluate() {
if (this.trigger === TRIGGER.ANY) { if (this.trigger === TRIGGER.ANY) {
this.result = true; this.result = computeConditionForAny(this.criteriaResults);
} else if (this.trigger === TRIGGER.ALL) { } else if (this.trigger === TRIGGER.ALL) {
this.result = false; this.result = computeConditionForAll(this.criteriaResults);
} }
} }

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 = {
definition: {
trigger: TRIGGER.ANY, trigger: TRIGGER.ANY,
criteria: [ criteria: [
{ {
@ -73,6 +74,7 @@ describe("The condition", function () {
key: testTelemetryObject.identifier key: testTelemetryObject.identifier
} }
] ]
}
}; };
conditionObj = new Condition( conditionObj = new Condition(
@ -85,7 +87,7 @@ describe("The condition", function () {
}); });
it("generates criteria with an id", function () { it("generates criteria with an id", function () {
const testCriterion = testConditionDefinition.criteria[0]; const testCriterion = testConditionDefinition.definition.criteria[0];
let criterion = conditionObj.generateCriterion(testCriterion); let criterion = conditionObj.generateCriterion(testCriterion);
expect(criterion.id).toBeDefined(); expect(criterion.id).toBeDefined();
expect(criterion.operation).toEqual(testCriterion.operation); expect(criterion.operation).toEqual(testCriterion.operation);
@ -101,15 +103,15 @@ describe("The condition", function () {
it("initializes with criteria from the condition definition", function () { it("initializes with criteria from the condition definition", function () {
expect(conditionObj.criteria.length).toEqual(1); expect(conditionObj.criteria.length).toEqual(1);
let criterion = conditionObj.criteria[0]; let criterion = conditionObj.criteria[0];
console.log(criterion);
expect(criterion instanceof TelemetryCriterion).toBeTrue(); expect(criterion instanceof TelemetryCriterion).toBeTrue();
expect(criterion.operator).toEqual(testConditionDefinition.operator); expect(criterion.operator).toEqual(testConditionDefinition.definition.criteria[0].operator);
expect(criterion.input).toEqual(testConditionDefinition.input); expect(criterion.input).toEqual(testConditionDefinition.definition.criteria[0].input);
expect(criterion.metaDataKey).toEqual(testConditionDefinition.metaDataKey); expect(criterion.metaDataKey).toEqual(testConditionDefinition.definition.criteria[0].metaDataKey);
expect(criterion.key).toEqual(testConditionDefinition.key);
}); });
it("initializes with the trigger from the condition definition", function () { it("initializes with the trigger from the condition definition", function () {
expect(conditionObj.trigger).toEqual(testConditionDefinition.trigger); expect(conditionObj.trigger).toEqual(testConditionDefinition.definition.trigger);
}); });
it("destroys all criteria for a condition", function () { it("destroys all criteria for a condition", function () {

View File

@ -21,6 +21,7 @@
*****************************************************************************/ *****************************************************************************/
import * as EventEmitter from 'eventemitter3'; import * as EventEmitter from 'eventemitter3';
import {OPERATIONS} from '../utils/operations';
export default class TelemetryCriterion extends EventEmitter { export default class TelemetryCriterion extends EventEmitter {
@ -38,6 +39,9 @@ export default class TelemetryCriterion extends EventEmitter {
this.objectAPI = this.openmct.objects; this.objectAPI = this.openmct.objects;
this.telemetryAPI = this.openmct.telemetry; this.telemetryAPI = this.openmct.telemetry;
this.id = telemetryDomainObjectDefinition.id; this.id = telemetryDomainObjectDefinition.id;
this.operation = telemetryDomainObjectDefinition.operation;
this.input = telemetryDomainObjectDefinition.input;
this.metaDataKey = telemetryDomainObjectDefinition.metaDataKey;
this.subscription = null; this.subscription = null;
this.telemetryMetadata = null; this.telemetryMetadata = null;
this.telemetryObjectIdAsString = null; this.telemetryObjectIdAsString = null;
@ -51,19 +55,36 @@ export default class TelemetryCriterion extends EventEmitter {
this.emitEvent('criterionUpdated', this); this.emitEvent('criterionUpdated', this);
} }
handleSubscription(datum) { handleSubscription(data) {
let data = this.normalizeData(datum); let result = this.computeResult(data);
this.emitEvent('criterionResultUpdated', { this.emitEvent('criterionResultUpdated', {
result: data, result: result,
error: null error: null
}) })
} }
normalizeData(datum) { findOperation(operation) {
return { for (let i=0, ii=OPERATIONS.length; i < ii; i++) {
[datum.key]: datum[datum.source] if (operation === OPERATIONS[i].name) {
return OPERATIONS[i].operation;
} }
} }
return null;
}
computeResult(data) {
let comparator = this.findOperation(this.operation);
let params = [];
let result = false;
params.push(data[this.metaDataKey]);
if (this.input instanceof Array && this.input.length) {
params.push(this.input[0]);
}
if (typeof comparator === 'function') {
result = comparator(params);
}
return result;
}
emitEvent(eventName, data) { emitEvent(eventName, data) {
this.emit(eventName, { this.emit(eventName, {
@ -76,6 +97,7 @@ export default class TelemetryCriterion extends EventEmitter {
* Subscribes to the telemetry object and returns an unsubscribe function * Subscribes to the telemetry object and returns an unsubscribe function
*/ */
subscribe() { subscribe() {
this.unsubscribe();
this.subscription = this.telemetryAPI.subscribe(this.telemetryObject, (datum) => { this.subscription = this.telemetryAPI.subscribe(this.telemetryObject, (datum) => {
this.handleSubscription(datum); this.handleSubscription(datum);
}); });

View File

@ -94,17 +94,6 @@ describe("The telemetry criterion", function () {
expect(telemetryCriterion.subscription).toBeDefined(); expect(telemetryCriterion.subscription).toBeDefined();
}); });
it("normalizes telemetry data", function () {
let result = telemetryCriterion.normalizeData({
key: 'some-key',
source: 'testSource',
testSource: 'Hello'
});
expect(result).toEqual({
'some-key': 'Hello'
})
});
it("emits update event on new data from telemetry providers", function () { it("emits update event on new data from telemetry providers", function () {
spyOn(telemetryCriterion, 'emitEvent').and.callThrough(); spyOn(telemetryCriterion, 'emitEvent').and.callThrough();
telemetryCriterion.handleSubscription({ telemetryCriterion.handleSubscription({

View File

@ -1,7 +1,31 @@
export const computeConditionForAny = (args) => { /**
return false; * Returns true only if at least one of the results is true
**/
export const computeConditionForAny = (resultMap) => {
let result = false;
for (let key in resultMap) {
if (resultMap.hasOwnProperty(key)) {
result = resultMap[key];
if (result) {
break;
}
}
}
return result;
}; };
export const computeConditionForAll = (args) => { /**
return false; * Returns true only if all the results are true
**/
export const computeConditionForAll = (resultMap) => {
let result = false;
for (let key in resultMap) {
if (resultMap.hasOwnProperty(key)) {
result = resultMap[key];
if (!result) {
break;
}
}
}
return result;
}; };