mirror of
https://github.com/nasa/openmct.git
synced 2024-12-20 13:43:09 +00:00
Merge pull request #2800 from nasa/any-all-telemetry
Any all telemetry option for conditions.
This commit is contained in:
commit
e4c9f156a7
@ -25,6 +25,7 @@ import uuid from 'uuid';
|
||||
import TelemetryCriterion from "./criterion/TelemetryCriterion";
|
||||
import { TRIGGER } from "./utils/constants";
|
||||
import {computeCondition, computeConditionByLimit} from "./utils/evaluator";
|
||||
import AllTelemetryCriterion from "./criterion/AllTelemetryCriterion";
|
||||
|
||||
/*
|
||||
* conditionConfiguration = {
|
||||
@ -72,7 +73,11 @@ export default class ConditionClass extends EventEmitter {
|
||||
return;
|
||||
}
|
||||
this.criteria.forEach(criterion => {
|
||||
criterion.emit(`subscription:${datum.id}`, datum);
|
||||
if (criterion.telemetry && (criterion.telemetry === 'all' || criterion.telemetry === 'any')) {
|
||||
criterion.handleSubscription(datum, this.conditionManager.telemetryObjects);
|
||||
} else {
|
||||
criterion.emit(`subscription:${datum.id}`, datum);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -120,8 +125,13 @@ export default class ConditionClass extends EventEmitter {
|
||||
* adds criterion to the condition.
|
||||
*/
|
||||
addCriterion(criterionConfiguration) {
|
||||
let criterion;
|
||||
let criterionConfigurationWithId = this.generateCriterion(criterionConfiguration || null);
|
||||
let criterion = new TelemetryCriterion(criterionConfigurationWithId, this.openmct);
|
||||
if (criterionConfiguration.telemetry && (criterionConfiguration.telemetry === 'any' || criterionConfiguration.telemetry === 'all')) {
|
||||
criterion = new AllTelemetryCriterion(criterionConfigurationWithId, this.openmct);
|
||||
} else {
|
||||
criterion = new TelemetryCriterion(criterionConfigurationWithId, this.openmct);
|
||||
}
|
||||
criterion.on('criterionUpdated', (obj) => this.handleCriterionUpdated(obj));
|
||||
criterion.on('criterionResultUpdated', (obj) => this.handleCriterionResult(obj));
|
||||
if (!this.criteria) {
|
||||
|
@ -9,6 +9,8 @@
|
||||
@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"
|
||||
@ -20,7 +22,8 @@
|
||||
<span v-if="criterion.telemetry"
|
||||
class="c-cdef__control"
|
||||
>
|
||||
<select v-model="criterion.metadata"
|
||||
<select ref="metadataSelect"
|
||||
v-model="criterion.metadata"
|
||||
@change="updateOperations"
|
||||
>
|
||||
<option value="">- Select Field -</option>
|
||||
@ -36,7 +39,7 @@
|
||||
class="c-cdef__control"
|
||||
>
|
||||
<select v-model="criterion.operation"
|
||||
@change="updateOperationInputVisibility"
|
||||
@change="updateInputVisibilityAndValues"
|
||||
>
|
||||
<option value="">- Select Comparison -</option>
|
||||
<option v-for="option in filteredOps"
|
||||
@ -107,8 +110,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
telemetryMetadata: {},
|
||||
telemetryMetadataOptions: {},
|
||||
telemetryMetadataOptions: [],
|
||||
operations: OPERATIONS,
|
||||
inputCount: 0,
|
||||
rowLabel: '',
|
||||
@ -123,13 +125,13 @@ export default {
|
||||
return (this.index !== 0 ? operator : '') + 'when';
|
||||
},
|
||||
filteredOps: function () {
|
||||
return [...this.operations.filter(op => op.appliesTo.indexOf(this.operationFormat) !== -1)];
|
||||
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 === 1) {
|
||||
if (this.filteredOps[i].appliesTo.length) {
|
||||
type = this.inputTypes[this.filteredOps[i].appliesTo[0]];
|
||||
} else {
|
||||
type = 'text'
|
||||
@ -153,79 +155,113 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
checkTelemetry() {
|
||||
if(this.criterion.telemetry &&
|
||||
!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();
|
||||
}
|
||||
},
|
||||
getOperationFormat() {
|
||||
this.enumerations = [];
|
||||
this.telemetryMetadata.valueMetadatas.forEach((value, index) => {
|
||||
if (value.key === this.criterion.metadata) {
|
||||
let valueMetadata = this.telemetryMetadataOptions[index];
|
||||
if (valueMetadata.enumerations !== undefined) {
|
||||
this.operationFormat = 'enum';
|
||||
this.enumerations = valueMetadata.enumerations;
|
||||
} else if (valueMetadata.hints.hasOwnProperty('range')) {
|
||||
this.operationFormat = 'number';
|
||||
} else if (valueMetadata.hints.hasOwnProperty('domain')) {
|
||||
this.operationFormat = 'number';
|
||||
} else if (valueMetadata.key === 'name') {
|
||||
this.operationFormat = 'string';
|
||||
} else {
|
||||
this.operationFormat = 'string';
|
||||
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)
|
||||
}
|
||||
if (this.criterion.telemetry) {
|
||||
this.openmct.objects.get(this.criterion.telemetry).then((telemetryObject) => {
|
||||
this.telemetryMetadata = this.openmct.telemetry.getMetadata(telemetryObject);
|
||||
this.telemetryMetadataOptions = this.telemetryMetadata.values();
|
||||
this.updateOperations(ev);
|
||||
this.updateOperationInputVisibility();
|
||||
});
|
||||
} else {
|
||||
this.criterion.metadata = '';
|
||||
}
|
||||
},
|
||||
updateOperations(ev) {
|
||||
if (ev) {
|
||||
this.clearDependentFields(ev.target);
|
||||
this.persist();
|
||||
}
|
||||
this.getOperationFormat();
|
||||
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();
|
||||
});
|
||||
}
|
||||
},
|
||||
updateOperationInputVisibility(ev) {
|
||||
if (ev) {
|
||||
if (this.enumerations.length) {
|
||||
this.criterion.input = [this.enumerations[0].value.toString()];
|
||||
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 = []}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
this.criterion.operation = '';
|
||||
this.criterion.input = [];
|
||||
this.inputCount = 0;
|
||||
},
|
||||
persist() {
|
||||
this.$emit('persist', this.criterion);
|
||||
|
172
src/plugins/condition/criterion/AllTelemetryCriterion.js
Normal file
172
src/plugins/condition/criterion/AllTelemetryCriterion.js
Normal file
@ -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.
|
||||
*****************************************************************************/
|
||||
|
||||
import EventEmitter from 'EventEmitter';
|
||||
import {OPERATIONS} from '../utils/operations';
|
||||
import {computeCondition} from "@/plugins/condition/utils/evaluator";
|
||||
|
||||
export default class TelemetryCriterion extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Subscribes/Unsubscribes to telemetry and emits the result
|
||||
* of operations performed on the telemetry data returned and a given input value.
|
||||
* @constructor
|
||||
* @param telemetryDomainObjectDefinition {id: uuid, operation: enum, input: Array, metadata: string, key: {domainObject.identifier} }
|
||||
* @param openmct
|
||||
*/
|
||||
constructor(telemetryDomainObjectDefinition, openmct) {
|
||||
super();
|
||||
|
||||
this.openmct = openmct;
|
||||
this.objectAPI = this.openmct.objects;
|
||||
this.telemetryAPI = this.openmct.telemetry;
|
||||
this.timeAPI = this.openmct.time;
|
||||
this.id = telemetryDomainObjectDefinition.id;
|
||||
this.telemetry = telemetryDomainObjectDefinition.telemetry;
|
||||
this.operation = telemetryDomainObjectDefinition.operation;
|
||||
this.telemetryObjects = Object.assign({}, telemetryDomainObjectDefinition.telemetryObjects);
|
||||
this.input = telemetryDomainObjectDefinition.input;
|
||||
this.metadata = telemetryDomainObjectDefinition.metadata;
|
||||
this.telemetryDataCache = {};
|
||||
}
|
||||
|
||||
updateTelemetry(telemetryObjects) {
|
||||
this.telemetryObjects = Object.assign({}, telemetryObjects);
|
||||
}
|
||||
|
||||
formatData(data, telemetryObjects) {
|
||||
if (data) {
|
||||
this.telemetryDataCache[data.id] = this.computeResult(data);
|
||||
}
|
||||
|
||||
let keys = Object.keys(telemetryObjects);
|
||||
keys.forEach((key) => {
|
||||
let telemetryObject = telemetryObjects[key];
|
||||
const id = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
if (this.telemetryDataCache[id] === undefined) {
|
||||
this.telemetryDataCache[id] = false;
|
||||
}
|
||||
});
|
||||
|
||||
const datum = {
|
||||
result: computeCondition(this.telemetryDataCache, this.telemetry === 'all')
|
||||
};
|
||||
|
||||
if (data) {
|
||||
// TODO check back to see if we should format times here
|
||||
this.timeAPI.getAllTimeSystems().forEach(timeSystem => {
|
||||
datum[timeSystem.key] = data[timeSystem.key]
|
||||
});
|
||||
}
|
||||
return datum;
|
||||
}
|
||||
|
||||
handleSubscription(data, telemetryObjects) {
|
||||
if(this.isValid()) {
|
||||
this.emitEvent('criterionResultUpdated', this.formatData(data, telemetryObjects));
|
||||
} else {
|
||||
this.emitEvent('criterionResultUpdated', this.formatData({}, telemetryObjects));
|
||||
}
|
||||
}
|
||||
|
||||
findOperation(operation) {
|
||||
for (let i=0; i < OPERATIONS.length; i++) {
|
||||
if (operation === OPERATIONS[i].name) {
|
||||
return OPERATIONS[i].operation;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
computeResult(data) {
|
||||
let result = false;
|
||||
if (data) {
|
||||
let comparator = this.findOperation(this.operation);
|
||||
let params = [];
|
||||
params.push(data[this.metadata]);
|
||||
if (this.input instanceof Array && this.input.length) {
|
||||
this.input.forEach(input => params.push(input));
|
||||
}
|
||||
if (typeof comparator === 'function') {
|
||||
result = comparator(params);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
emitEvent(eventName, data) {
|
||||
this.emit(eventName, {
|
||||
id: this.id,
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
isValid() {
|
||||
return (this.telemetry === 'any' || this.telemetry === 'all') && this.metadata && this.operation;
|
||||
}
|
||||
|
||||
requestLAD(options) {
|
||||
options = Object.assign({},
|
||||
options,
|
||||
{
|
||||
strategy: 'latest',
|
||||
size: 1
|
||||
}
|
||||
);
|
||||
|
||||
if (!this.isValid()) {
|
||||
return this.formatData({}, options.telemetryObjects);
|
||||
}
|
||||
|
||||
const telemetryRequests = options.telemetryObjects
|
||||
.map(telemetryObject => this.telemetryAPI.request(
|
||||
telemetryObject,
|
||||
options
|
||||
));
|
||||
|
||||
return Promise.all(telemetryRequests)
|
||||
.then(telemetryRequestsResults => {
|
||||
telemetryRequestsResults.forEach((results, index) => {
|
||||
const latestDatum = results.length ? results[results.length - 1] : {};
|
||||
if (index === telemetryRequestsResults.length-1) {
|
||||
//when the last result is computed, we return the result
|
||||
return {
|
||||
id: this.id,
|
||||
data: this.formatData(latestDatum, options.telemetryObjects)
|
||||
};
|
||||
} else {
|
||||
if (latestDatum) {
|
||||
this.telemetryDataCache[latestDatum.id] = this.computeResult(latestDatum);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.emitEvent('criterionRemoved');
|
||||
delete this.telemetryObjects;
|
||||
delete this.telemetryDataCache;
|
||||
delete this.telemetryObjectIdAsString;
|
||||
delete this.telemetryObject;
|
||||
}
|
||||
}
|
@ -71,6 +71,8 @@ export default class TelemetryCriterion extends EventEmitter {
|
||||
handleSubscription(data) {
|
||||
if(this.isValid()) {
|
||||
this.emitEvent('criterionResultUpdated', this.formatData(data));
|
||||
} else {
|
||||
this.emitEvent('criterionResultUpdated', this.formatData({}));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user