mirror of
https://github.com/nasa/openmct.git
synced 2024-12-30 09:58:52 +00:00
Merge branch 'condition-class' of https://github.com/nasa/openmct into conditionSet-view
This commit is contained in:
commit
aaf1eb8059
@ -64,6 +64,7 @@
|
||||
"request": "^2.69.0",
|
||||
"split": "^1.0.0",
|
||||
"style-loader": "^1.0.1",
|
||||
"uuid": "^3.3.3",
|
||||
"v8-compile-cache": "^1.1.0",
|
||||
"vue": "2.5.6",
|
||||
"vue-loader": "^15.2.6",
|
||||
|
191
src/plugins/condition/Condition.js
Normal file
191
src/plugins/condition/Condition.js
Normal file
@ -0,0 +1,191 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2019, 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 * as EventEmitter from 'eventemitter3';
|
||||
import uuid from 'uuid';
|
||||
import TelemetryCriterion from "@/plugins/condition/criterion/TelemetryCriterion";
|
||||
import { TRIGGER } from "@/plugins/condition/utils/constants";
|
||||
|
||||
/*
|
||||
* conditionDefinition = {
|
||||
* trigger: 'any'/'all',
|
||||
* criteria: [
|
||||
* {
|
||||
* operation: '',
|
||||
* input: '',
|
||||
* metaDataKey: '',
|
||||
* key: 'someTelemetryObjectKey'
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
export default class Condition extends EventEmitter {
|
||||
|
||||
constructor(conditionDefinition, openmct) {
|
||||
super();
|
||||
|
||||
this.openmct = openmct;
|
||||
this.id = uuid();
|
||||
if (conditionDefinition.criteria) {
|
||||
this.createCriteria(conditionDefinition.criteria);
|
||||
} else {
|
||||
this.criteria = [];
|
||||
}
|
||||
this.trigger = conditionDefinition.trigger;
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
updateTrigger(conditionDefinition) {
|
||||
if (this.trigger !== conditionDefinition.trigger) {
|
||||
this.trigger = conditionDefinition.trigger;
|
||||
this.handleConditionUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
generateCriterion(criterionDefinition) {
|
||||
return {
|
||||
id: uuid(),
|
||||
operation: criterionDefinition.operation || '',
|
||||
input: criterionDefinition.input === undefined ? [] : criterionDefinition.input,
|
||||
metaDataKey: criterionDefinition.metaDataKey || '',
|
||||
key: criterionDefinition.key || ''
|
||||
};
|
||||
}
|
||||
|
||||
createCriteria(criterionDefinitions) {
|
||||
criterionDefinitions.forEach((criterionDefinition) => {
|
||||
this.addCriterion(criterionDefinition);
|
||||
});
|
||||
}
|
||||
|
||||
updateCriteria(criterionDefinitions) {
|
||||
this.destroyCriteria();
|
||||
this.createCriteria(criterionDefinitions);
|
||||
}
|
||||
|
||||
/**
|
||||
* adds criterion to the condition.
|
||||
*/
|
||||
addCriterion(criterionDefinition) {
|
||||
let criterionDefinitionWithId = this.generateCriterion(criterionDefinition || null);
|
||||
let criterion = new TelemetryCriterion(criterionDefinitionWithId, this.openmct);
|
||||
criterion.on('criterionUpdated', this.handleCriterionUpdated);
|
||||
if (!this.criteria) {
|
||||
this.criteria = [];
|
||||
}
|
||||
this.criteria.push(criterion);
|
||||
this.handleConditionUpdated();
|
||||
return criterionDefinitionWithId.id;
|
||||
}
|
||||
|
||||
findCriterion(id) {
|
||||
let criterion;
|
||||
|
||||
for (let i=0, ii=this.criteria.length; i < ii; i ++) {
|
||||
if (this.criteria[i].id === id) {
|
||||
criterion = {
|
||||
item: this.criteria[i],
|
||||
index: i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return criterion;
|
||||
}
|
||||
|
||||
updateCriterion(id, criterionDefinition) {
|
||||
let found = this.findCriterion(id);
|
||||
if (found) {
|
||||
const newCriterionDefinition = this.generateCriterion(criterionDefinition);
|
||||
let newCriterion = new TelemetryCriterion(newCriterionDefinition, this.openmct);
|
||||
let criterion = found.item;
|
||||
criterion.unsubscribe();
|
||||
criterion.off('criterionUpdated', (result) => {
|
||||
this.handleCriterionUpdated(id, result);
|
||||
});
|
||||
this.criteria.splice(found.index, 1, newCriterion);
|
||||
this.handleConditionUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
removeCriterion(id) {
|
||||
if (this.destroyCriterion(id)) {
|
||||
this.handleConditionUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
destroyCriterion(id) {
|
||||
let found = this.findCriterion(id);
|
||||
if (found) {
|
||||
let criterion = found.item;
|
||||
criterion.unsubscribe();
|
||||
criterion.off('criterionUpdated', (result) => {
|
||||
this.handleCriterionUpdated(id, result);
|
||||
});
|
||||
this.criteria.splice(found.index, 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
handleCriterionUpdated(id, result) {
|
||||
// reevaluate the condition's output
|
||||
// TODO: should we save the result of a criterion here or in the criterion object itself?
|
||||
this.evaluate();
|
||||
this.handleConditionUpdated();
|
||||
}
|
||||
|
||||
handleConditionUpdated() {
|
||||
// trigger an updated event so that consumers can react accordingly
|
||||
this.emitResult();
|
||||
}
|
||||
|
||||
getCriteria() {
|
||||
return this.criteria;
|
||||
}
|
||||
|
||||
destroyCriteria() {
|
||||
let success = true;
|
||||
//looping through the array backwards since destroyCriterion modifies the criteria array
|
||||
for (let i=this.criteria.length-1; i >= 0; i--) {
|
||||
success = success && this.destroyCriterion(this.criteria[i].id);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
//TODO: implement as part of the evaluator class task.
|
||||
evaluate() {
|
||||
if (this.trigger === TRIGGER.ANY) {
|
||||
this.result = false;
|
||||
} else if (this.trigger === TRIGGER.ALL) {
|
||||
this.result = false;
|
||||
}
|
||||
}
|
||||
|
||||
emitResult(data, error) {
|
||||
this.emit('conditionUpdated', {
|
||||
identifier: this.id,
|
||||
data: data,
|
||||
error: error
|
||||
});
|
||||
}
|
||||
}
|
118
src/plugins/condition/ConditionSpec.js
Normal file
118
src/plugins/condition/ConditionSpec.js
Normal file
@ -0,0 +1,118 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2019, 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 Condition from "./Condition";
|
||||
import {TRIGGER} from "./utils/constants";
|
||||
import TelemetryCriterion from "./criterion/TelemetryCriterion";
|
||||
|
||||
let openmct = {},
|
||||
mockListener,
|
||||
testConditionDefinition,
|
||||
testTelemetryObject,
|
||||
conditionObj;
|
||||
|
||||
describe("The condition", function () {
|
||||
|
||||
beforeEach (() => {
|
||||
mockListener = jasmine.createSpy('listener');
|
||||
testTelemetryObject = {
|
||||
identifier:{ namespace: "", key: "test-object"},
|
||||
type: "test-object",
|
||||
name: "Test Object",
|
||||
telemetry: {
|
||||
values: [{
|
||||
key: "some-key",
|
||||
name: "Some attribute",
|
||||
hints: {
|
||||
domain: 1
|
||||
}
|
||||
}, {
|
||||
key: "some-other-key",
|
||||
name: "Another attribute",
|
||||
hints: {
|
||||
range: 1
|
||||
}
|
||||
}]
|
||||
}
|
||||
};
|
||||
openmct.objects = jasmine.createSpyObj('objects', ['get', 'makeKeyString']);
|
||||
openmct.objects.get.and.returnValue(testTelemetryObject);
|
||||
openmct.objects.makeKeyString.and.returnValue(testTelemetryObject.identifier.key);
|
||||
openmct.telemetry = jasmine.createSpyObj('telemetry', ['isTelemetryObject', 'subscribe']);
|
||||
openmct.telemetry.isTelemetryObject.and.returnValue(true);
|
||||
openmct.telemetry.subscribe.and.returnValue(function () {});
|
||||
|
||||
testConditionDefinition = {
|
||||
trigger: TRIGGER.ANY,
|
||||
criteria: [
|
||||
{
|
||||
operation: 'equalTo',
|
||||
input: false,
|
||||
metaDataKey: 'value',
|
||||
key: testTelemetryObject.identifier
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
conditionObj = new Condition(
|
||||
testConditionDefinition,
|
||||
openmct
|
||||
);
|
||||
|
||||
conditionObj.on('conditionUpdated', mockListener);
|
||||
|
||||
});
|
||||
|
||||
it("generates criteria with an id", function () {
|
||||
const testCriterion = testConditionDefinition.criteria[0];
|
||||
let criterion = conditionObj.generateCriterion(testCriterion);
|
||||
expect(criterion.id).toBeDefined();
|
||||
expect(criterion.operation).toEqual(testCriterion.operation);
|
||||
expect(criterion.input).toEqual(testCriterion.input);
|
||||
expect(criterion.metaDataKey).toEqual(testCriterion.metaDataKey);
|
||||
expect(criterion.key).toEqual(testCriterion.key);
|
||||
});
|
||||
|
||||
it("initializes with an id", function () {
|
||||
expect(conditionObj.id).toBeDefined();
|
||||
});
|
||||
|
||||
it("initializes with criteria from the condition definition", function () {
|
||||
expect(conditionObj.criteria.length).toEqual(1);
|
||||
let criterion = conditionObj.criteria[0];
|
||||
expect(criterion instanceof TelemetryCriterion).toBeTrue();
|
||||
expect(criterion.operator).toEqual(testConditionDefinition.operator);
|
||||
expect(criterion.input).toEqual(testConditionDefinition.input);
|
||||
expect(criterion.metaDataKey).toEqual(testConditionDefinition.metaDataKey);
|
||||
expect(criterion.key).toEqual(testConditionDefinition.key);
|
||||
});
|
||||
|
||||
it("initializes with the trigger from the condition definition", function () {
|
||||
expect(conditionObj.trigger).toEqual(testConditionDefinition.trigger);
|
||||
});
|
||||
|
||||
it("destroys all criteria for a condition", function () {
|
||||
const result = conditionObj.destroyCriteria();
|
||||
expect(result).toBeTrue();
|
||||
expect(conditionObj.criteria.length).toEqual(0);
|
||||
});
|
||||
});
|
0
src/plugins/condition/StyleRuleManager.js
Normal file
0
src/plugins/condition/StyleRuleManager.js
Normal file
85
src/plugins/condition/criterion/TelemetryCriterion.js
Normal file
85
src/plugins/condition/criterion/TelemetryCriterion.js
Normal file
@ -0,0 +1,85 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2019, 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 * as EventEmitter from 'eventemitter3';
|
||||
|
||||
export default class TelemetryCriterion extends EventEmitter {
|
||||
|
||||
constructor(telemetryDomainObjectKey, openmct) {
|
||||
super();
|
||||
|
||||
this.openmct = openmct;
|
||||
this.telemetryObject = this.openmct.objects.get(this.openmct.objects.makeKeyString(telemetryDomainObjectKey));
|
||||
this.telemetryAPI = this.openmct.telemetry;
|
||||
this.subscription = null;
|
||||
this.telemetryMetadata = null;
|
||||
this.telemetryObjectIdAsString = null;
|
||||
if (this.telemetryAPI.isTelemetryObject(this.telemetryObject)) {
|
||||
this.telemetryObjectIdAsString = this.openmct.objects.makeKeyString(this.telemetryObject.identifier);
|
||||
}
|
||||
}
|
||||
|
||||
handleSubscription(datum) {
|
||||
//data is telemetry values, error
|
||||
//how do I get data here?
|
||||
this.emitResult(this.normalizeData(datum));
|
||||
}
|
||||
|
||||
//TODO: Revisit this logic
|
||||
normalizeData(datum) {
|
||||
return {
|
||||
[datum.key]: datum[datum.source]
|
||||
}
|
||||
}
|
||||
|
||||
emitResult(data, error) {
|
||||
this.emit('criterionUpdated', {
|
||||
identifier: this.telemetryObjectIdAsString,
|
||||
data: data,
|
||||
error: error
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribes to the telemetry object and returns an unsubscribe function
|
||||
*/
|
||||
subscribe() {
|
||||
this.subscription = this.telemetryAPI.subscribe(this.telemetryObject, (datum) => {
|
||||
this.handleSubscription(datum);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls an unsubscribe function returned by subscribe() and deletes any initialized data
|
||||
*/
|
||||
unsubscribe() {
|
||||
//unsubscribe from telemetry source
|
||||
if (typeof this.subscription === 'function') {
|
||||
this.subscription();
|
||||
}
|
||||
delete this.subscription;
|
||||
this.emit('criterion::Remove', this.telemetryObjectIdAsString);
|
||||
delete this.telemetryObjectIdAsString;
|
||||
delete this.telemetryObject;
|
||||
delete this.telemetryMetadata;
|
||||
}
|
||||
}
|
112
src/plugins/condition/criterion/TelemetryCriterionSpec.js
Normal file
112
src/plugins/condition/criterion/TelemetryCriterionSpec.js
Normal file
@ -0,0 +1,112 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2019, 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 TelemetryCriterion from "./TelemetryCriterion";
|
||||
|
||||
let openmct = {},
|
||||
mockListener,
|
||||
testTelemetryObject,
|
||||
telemetryCriterion;
|
||||
|
||||
describe("The telemetry criterion", function () {
|
||||
|
||||
beforeEach (() => {
|
||||
testTelemetryObject = {
|
||||
identifier:{ namespace: "", key: "test-object"},
|
||||
type: "test-object",
|
||||
name: "Test Object",
|
||||
telemetry: {
|
||||
values: [{
|
||||
key: "some-key",
|
||||
name: "Some attribute",
|
||||
hints: {
|
||||
domain: 1
|
||||
}
|
||||
}, {
|
||||
key: "some-other-key",
|
||||
name: "Another attribute",
|
||||
hints: {
|
||||
range: 1
|
||||
}
|
||||
}]
|
||||
}
|
||||
};
|
||||
openmct.objects = jasmine.createSpyObj('objects', ['get', 'makeKeyString']);
|
||||
openmct.objects.get.and.returnValue(testTelemetryObject);
|
||||
openmct.objects.makeKeyString.and.returnValue(testTelemetryObject.identifier.key);
|
||||
openmct.telemetry = jasmine.createSpyObj('telemetry', ['isTelemetryObject', "subscribe"]);
|
||||
openmct.telemetry.isTelemetryObject.and.returnValue(true);
|
||||
openmct.telemetry.subscribe.and.returnValue(function () {});
|
||||
|
||||
mockListener = jasmine.createSpy('listener');
|
||||
|
||||
telemetryCriterion = new TelemetryCriterion(
|
||||
testTelemetryObject.identifier,
|
||||
openmct
|
||||
);
|
||||
|
||||
telemetryCriterion.on('criterionUpdated', mockListener);
|
||||
|
||||
});
|
||||
|
||||
it("initializes with a telemetry objectId as string", function () {
|
||||
expect(telemetryCriterion.telemetryObjectIdAsString).toEqual(testTelemetryObject.identifier.key);
|
||||
});
|
||||
|
||||
it("subscribes to telemetry providers", function () {
|
||||
telemetryCriterion.subscribe();
|
||||
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 () {
|
||||
spyOn(telemetryCriterion, 'emitResult').and.callThrough();
|
||||
telemetryCriterion.handleSubscription({
|
||||
key: 'some-key',
|
||||
source: 'testSource',
|
||||
testSource: 'Hello'
|
||||
});
|
||||
expect(telemetryCriterion.emitResult).toHaveBeenCalled();
|
||||
expect(mockListener).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("un-subscribes from telemetry providers", function () {
|
||||
telemetryCriterion.subscribe();
|
||||
expect(telemetryCriterion.subscription).toBeDefined();
|
||||
telemetryCriterion.unsubscribe();
|
||||
expect(telemetryCriterion.subscription).toBeUndefined();
|
||||
expect(telemetryCriterion.telemetryObjectIdAsString).toBeUndefined();
|
||||
expect(telemetryCriterion.telemetryObject).toBeUndefined();
|
||||
expect(telemetryCriterion.telemetryMetadata).toBeUndefined();
|
||||
});
|
||||
|
||||
});
|
4
src/plugins/condition/utils/constants.js
Normal file
4
src/plugins/condition/utils/constants.js
Normal file
@ -0,0 +1,4 @@
|
||||
export const TRIGGER = {
|
||||
ANY: 'any',
|
||||
ALL: 'all'
|
||||
};
|
7
src/plugins/condition/utils/evaluator.js
Normal file
7
src/plugins/condition/utils/evaluator.js
Normal file
@ -0,0 +1,7 @@
|
||||
export const computeConditionForAny = (args) => {
|
||||
return false;
|
||||
};
|
||||
|
||||
export const computeConditionForAll = (args) => {
|
||||
return false;
|
||||
};
|
Loading…
Reference in New Issue
Block a user