mirror of
https://github.com/nasa/openmct.git
synced 2025-02-01 00:45:41 +00:00
Merge remote-tracking branch 'khalidadil/extend-conditional' into combined-rodap-stuff
This commit is contained in:
commit
f78f76818b
@ -51,7 +51,8 @@ const config = {
|
||||
compsMathWorker: './src/plugins/comps/CompsMathWorker.js',
|
||||
espressoTheme: './src/plugins/themes/espresso-theme.scss',
|
||||
snowTheme: './src/plugins/themes/snow-theme.scss',
|
||||
darkmatterTheme: './src/plugins/themes/darkmatter-theme.scss'
|
||||
darkmatterTheme: './src/plugins/themes/darkmatter-theme.scss',
|
||||
historicalTelemetryWorker: './src/plugins/condition/historicalTelemetryWorker.js',
|
||||
},
|
||||
output: {
|
||||
globalObject: 'this',
|
||||
|
@ -66,6 +66,10 @@ module.exports = async (config) => {
|
||||
{
|
||||
pattern: 'dist/generatorWorker.js*',
|
||||
included: false
|
||||
},
|
||||
{
|
||||
pattern: 'dist/historicalTelemetryWorker.js*',
|
||||
included: false
|
||||
}
|
||||
],
|
||||
port: 9876,
|
||||
|
53
src/plugins/condition/ConditionInspectorViewProvider.js
Normal file
53
src/plugins/condition/ConditionInspectorViewProvider.js
Normal file
@ -0,0 +1,53 @@
|
||||
// src/plugins/condition/ConditionInspectorView.js
|
||||
|
||||
import mount from 'utils/mount';
|
||||
|
||||
import ConditionConfigView from './components/ConditionInspectorConfigView.vue';
|
||||
|
||||
export default function ConditionInspectorView(openmct) {
|
||||
return {
|
||||
key: 'condition-config',
|
||||
name: 'Config',
|
||||
canView: function (selection) {
|
||||
return selection.length > 0 && selection[0][0].context.item.type === 'conditionSet';
|
||||
},
|
||||
view: function (selection) {
|
||||
let _destroy = null;
|
||||
const domainObject = selection[0][0].context.item;
|
||||
|
||||
return {
|
||||
show: function (element) {
|
||||
const { destroy } = mount(
|
||||
{
|
||||
el: element,
|
||||
components: {
|
||||
ConditionConfigView: ConditionConfigView
|
||||
},
|
||||
provide: {
|
||||
openmct,
|
||||
domainObject
|
||||
},
|
||||
template: '<condition-config-view></condition-config-view>'
|
||||
},
|
||||
{
|
||||
app: openmct.app,
|
||||
element
|
||||
}
|
||||
);
|
||||
_destroy = destroy;
|
||||
},
|
||||
showTab: function (isEditing) {
|
||||
return isEditing;
|
||||
},
|
||||
priority: function () {
|
||||
return 1;
|
||||
},
|
||||
destroy: function () {
|
||||
if (_destroy) {
|
||||
_destroy();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
@ -24,6 +24,7 @@ import { EventEmitter } from 'eventemitter3';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import Condition from './Condition.js';
|
||||
import HistoricalTelemetryProvider from './historicalTelemetryProvider.js';
|
||||
import { getLatestTimestamp } from './utils/time.js';
|
||||
|
||||
export default class ConditionManager extends EventEmitter {
|
||||
@ -39,64 +40,57 @@ export default class ConditionManager extends EventEmitter {
|
||||
this.shouldEvaluateNewTelemetry = this.shouldEvaluateNewTelemetry.bind(this);
|
||||
|
||||
this.compositionLoad = this.composition.load();
|
||||
this.subscriptions = {};
|
||||
this.telemetryCollections = {};
|
||||
this.telemetryObjects = {};
|
||||
this.testData = {
|
||||
conditionTestInputs: this.conditionSetDomainObject.configuration.conditionTestData,
|
||||
applied: false
|
||||
};
|
||||
this.initialize();
|
||||
this.telemetryBuffer = [];
|
||||
this.isProcessing = false;
|
||||
}
|
||||
|
||||
async requestLatestValue(endpoint) {
|
||||
const options = {
|
||||
subscribeToTelemetry(telemetryObject) {
|
||||
const keyString = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
|
||||
if (this.telemetryCollections[keyString]) {
|
||||
return;
|
||||
}
|
||||
|
||||
const requestOptions = {
|
||||
size: 1,
|
||||
strategy: 'latest'
|
||||
};
|
||||
const latestData = await this.openmct.telemetry.request(endpoint, options);
|
||||
|
||||
if (!latestData) {
|
||||
throw new Error('Telemetry request failed by returning a falsy response');
|
||||
}
|
||||
if (latestData.length === 0) {
|
||||
return;
|
||||
}
|
||||
this.telemetryReceived(endpoint, latestData[0]);
|
||||
}
|
||||
|
||||
subscribeToTelemetry(endpoint) {
|
||||
const telemetryKeyString = this.openmct.objects.makeKeyString(endpoint.identifier);
|
||||
if (this.subscriptions[telemetryKeyString]) {
|
||||
return;
|
||||
}
|
||||
|
||||
const metadata = this.openmct.telemetry.getMetadata(endpoint);
|
||||
|
||||
this.telemetryObjects[telemetryKeyString] = Object.assign({}, endpoint, {
|
||||
telemetryMetaData: metadata ? metadata.valueMetadatas : []
|
||||
});
|
||||
|
||||
// get latest telemetry value (in case subscription is cached and no new data is coming in)
|
||||
this.requestLatestValue(endpoint);
|
||||
|
||||
this.subscriptions[telemetryKeyString] = this.openmct.telemetry.subscribe(
|
||||
endpoint,
|
||||
this.telemetryReceived.bind(this, endpoint)
|
||||
this.telemetryCollections[keyString] = this.openmct.telemetry.requestCollection(
|
||||
telemetryObject,
|
||||
requestOptions
|
||||
);
|
||||
|
||||
const metadata = this.openmct.telemetry.getMetadata(telemetryObject);
|
||||
const telemetryMetaData = metadata ? metadata.valueMetadatas : [];
|
||||
|
||||
this.telemetryObjects[keyString] = { ...telemetryObject, telemetryMetaData };
|
||||
|
||||
this.telemetryCollections[keyString].on(
|
||||
'add',
|
||||
this.telemetryReceived.bind(this, telemetryObject)
|
||||
);
|
||||
this.telemetryCollections[keyString].load();
|
||||
|
||||
this.updateConditionTelemetryObjects();
|
||||
}
|
||||
|
||||
unsubscribeFromTelemetry(endpointIdentifier) {
|
||||
const id = this.openmct.objects.makeKeyString(endpointIdentifier);
|
||||
if (!this.subscriptions[id]) {
|
||||
console.log('no subscription to remove');
|
||||
|
||||
const keyString = this.openmct.objects.makeKeyString(endpointIdentifier);
|
||||
if (!this.telemetryCollections[keyString]) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.subscriptions[id]();
|
||||
delete this.subscriptions[id];
|
||||
delete this.telemetryObjects[id];
|
||||
this.telemetryCollections[keyString].destroy();
|
||||
this.telemetryCollections[keyString] = null;
|
||||
this.telemetryObjects[keyString] = null;
|
||||
this.removeConditionTelemetryObjects();
|
||||
|
||||
//force re-computation of condition set result as we might be in a state where
|
||||
@ -107,7 +101,7 @@ export default class ConditionManager extends EventEmitter {
|
||||
this.timeSystems,
|
||||
this.openmct.time.getTimeSystem()
|
||||
);
|
||||
this.updateConditionResults({ id: id });
|
||||
this.updateConditionResults({ id: keyString });
|
||||
this.updateCurrentCondition(latestTimestamp);
|
||||
|
||||
if (Object.keys(this.telemetryObjects).length === 0) {
|
||||
@ -329,6 +323,19 @@ export default class ConditionManager extends EventEmitter {
|
||||
return currentCondition;
|
||||
}
|
||||
|
||||
getHistoricalData() {
|
||||
if (!this.conditionSetDomainObject.configuration.shouldFetchHistorical) {
|
||||
return [];
|
||||
}
|
||||
const historicalTelemetry = new HistoricalTelemetryProvider(
|
||||
this.openmct,
|
||||
this.telemetryObjects,
|
||||
this.conditions,
|
||||
this.conditionSetDomainObject
|
||||
);
|
||||
return historicalTelemetry.getHistoricalData();
|
||||
}
|
||||
|
||||
getCurrentConditionLAD(conditionResults) {
|
||||
const conditionCollection = this.conditionSetDomainObject.configuration.conditionCollection;
|
||||
let currentCondition = conditionCollection[conditionCollection.length - 1];
|
||||
@ -384,8 +391,26 @@ export default class ConditionManager extends EventEmitter {
|
||||
}
|
||||
|
||||
const currentCondition = this.getCurrentConditionLAD(conditionResults);
|
||||
let output = currentCondition?.configuration?.output;
|
||||
if (output === 'telemetry value') {
|
||||
const { outputTelemetry, outputMetadata } = currentCondition.configuration;
|
||||
const outputTelemetryObject = await this.openmct.objects.get(outputTelemetry);
|
||||
const telemetryOptions = {
|
||||
size: 1,
|
||||
strategy: 'latest',
|
||||
timeContext: this.openmct.time.getContextForView([])
|
||||
};
|
||||
const latestData = await this.openmct.telemetry.request(
|
||||
outputTelemetryObject,
|
||||
telemetryOptions
|
||||
);
|
||||
if (latestData?.[0]?.[outputMetadata]) {
|
||||
output = latestData?.[0]?.[outputMetadata];
|
||||
}
|
||||
}
|
||||
|
||||
const currentOutput = {
|
||||
output: currentCondition.configuration.output,
|
||||
output: output,
|
||||
id: this.conditionSetDomainObject.identifier,
|
||||
conditionId: currentCondition.id,
|
||||
...latestTimestamp
|
||||
@ -403,6 +428,18 @@ export default class ConditionManager extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
const conditionTelemetries = [];
|
||||
const conditions = this.conditionSetDomainObject.configuration.conditionCollection;
|
||||
conditions.forEach((condition) => {
|
||||
if (condition?.configuration?.outputTelemetry) {
|
||||
conditionTelemetries.push(condition?.configuration?.outputTelemetry);
|
||||
}
|
||||
});
|
||||
|
||||
if (conditionTelemetries.includes(id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -410,11 +447,13 @@ export default class ConditionManager extends EventEmitter {
|
||||
return this.openmct.time.getBounds().end >= currentTimestamp;
|
||||
}
|
||||
|
||||
telemetryReceived(endpoint, datum) {
|
||||
telemetryReceived(endpoint, data) {
|
||||
if (!this.isTelemetryUsed(endpoint)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const datum = data[0];
|
||||
|
||||
const normalizedDatum = this.createNormalizedDatum(datum, endpoint);
|
||||
const timeSystemKey = this.openmct.time.getTimeSystem().key;
|
||||
let timestamp = {};
|
||||
@ -422,7 +461,7 @@ export default class ConditionManager extends EventEmitter {
|
||||
timestamp[timeSystemKey] = currentTimestamp;
|
||||
if (this.shouldEvaluateNewTelemetry(currentTimestamp)) {
|
||||
this.updateConditionResults(normalizedDatum);
|
||||
this.updateCurrentCondition(timestamp);
|
||||
this.updateCurrentCondition(timestamp, endpoint, datum);
|
||||
}
|
||||
}
|
||||
|
||||
@ -435,14 +474,12 @@ export default class ConditionManager extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
updateCurrentCondition(timestamp) {
|
||||
const currentCondition = this.getCurrentCondition();
|
||||
|
||||
emitConditionSetResult(currentCondition, timestamp, outputValue) {
|
||||
this.emit(
|
||||
'conditionSetResultUpdated',
|
||||
Object.assign(
|
||||
{
|
||||
output: currentCondition.configuration.output,
|
||||
output: outputValue,
|
||||
id: this.conditionSetDomainObject.identifier,
|
||||
conditionId: currentCondition.id
|
||||
},
|
||||
@ -451,6 +488,60 @@ export default class ConditionManager extends EventEmitter {
|
||||
);
|
||||
}
|
||||
|
||||
updateCurrentCondition(timestamp, telemetryObject, telemetryData) {
|
||||
this.telemetryBuffer.push({ timestamp, telemetryObject, telemetryData });
|
||||
|
||||
if (!this.isProcessing) {
|
||||
this.processBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
async processBuffer() {
|
||||
this.isProcessing = true;
|
||||
|
||||
while (this.telemetryBuffer.length > 0) {
|
||||
const { timestamp, telemetryObject, telemetryData } = this.telemetryBuffer.shift();
|
||||
await this.processCondition(timestamp, telemetryObject, telemetryData);
|
||||
}
|
||||
|
||||
this.isProcessing = false;
|
||||
}
|
||||
|
||||
async processCondition(timestamp, telemetryObject, telemetryData) {
|
||||
const currentCondition = this.getCurrentCondition();
|
||||
let telemetryValue = currentCondition.configuration.output;
|
||||
if (currentCondition?.configuration?.outputTelemetry) {
|
||||
const selectedOutputIdentifier = currentCondition?.configuration?.outputTelemetry;
|
||||
const outputMetadata = currentCondition?.configuration?.outputMetadata;
|
||||
const telemetryKeystring = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
|
||||
if (selectedOutputIdentifier === telemetryKeystring) {
|
||||
telemetryValue = telemetryData[outputMetadata];
|
||||
} else {
|
||||
const outputTelemetryObject = await this.openmct.objects.get(selectedOutputIdentifier);
|
||||
const telemetryOptions = {
|
||||
size: 1,
|
||||
strategy: 'latest',
|
||||
start: timestamp?.utc - 1000,
|
||||
end: timestamp?.utc + 1000
|
||||
};
|
||||
const outputTelemetryData = await this.openmct.telemetry.request(
|
||||
outputTelemetryObject,
|
||||
telemetryOptions
|
||||
);
|
||||
const outputTelemetryValue =
|
||||
outputTelemetryData?.length > 0 ? outputTelemetryData.slice(-1)[0] : null;
|
||||
if (outputTelemetryData.length && outputTelemetryValue?.[outputMetadata]) {
|
||||
telemetryValue = outputTelemetryValue?.[outputMetadata];
|
||||
} else {
|
||||
telemetryValue = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.emitConditionSetResult(currentCondition, timestamp, telemetryValue);
|
||||
}
|
||||
|
||||
getTestData(metadatum) {
|
||||
let data = undefined;
|
||||
if (this.testData.applied) {
|
||||
@ -507,8 +598,9 @@ export default class ConditionManager extends EventEmitter {
|
||||
destroy() {
|
||||
this.composition.off('add', this.subscribeToTelemetry, this);
|
||||
this.composition.off('remove', this.unsubscribeFromTelemetry, this);
|
||||
Object.values(this.subscriptions).forEach((unsubscribe) => unsubscribe());
|
||||
delete this.subscriptions;
|
||||
Object.values(this.telemetryCollections).forEach((telemetryCollection) =>
|
||||
telemetryCollection.destroy()
|
||||
);
|
||||
|
||||
this.conditions.forEach((condition) => {
|
||||
condition.destroy();
|
||||
|
@ -42,8 +42,9 @@ export default class ConditionSetTelemetryProvider {
|
||||
|
||||
async request(domainObject, options) {
|
||||
let conditionManager = this.getConditionManager(domainObject);
|
||||
const formattedHistoricalData = await conditionManager.getHistoricalData();
|
||||
let latestOutput = await conditionManager.requestLADConditionSetOutput(options);
|
||||
return latestOutput;
|
||||
return [...formattedHistoricalData, ...latestOutput];
|
||||
}
|
||||
|
||||
subscribe(domainObject, callback) {
|
||||
|
@ -235,10 +235,11 @@ export default {
|
||||
|
||||
return arr;
|
||||
},
|
||||
addTelemetryObject(domainObject) {
|
||||
async addTelemetryObject(domainObject) {
|
||||
const keyString = this.openmct.objects.makeKeyString(domainObject.identifier);
|
||||
const telemetryPath = await this.getFullTelemetryPath(domainObject);
|
||||
|
||||
this.telemetryObjs.push(domainObject);
|
||||
this.telemetryObjs.push({ ...domainObject, path: telemetryPath });
|
||||
this.$emit('telemetry-updated', this.telemetryObjs);
|
||||
|
||||
this.subscribeToStaleness(domainObject, (stalenessResponse) => {
|
||||
@ -248,6 +249,19 @@ export default {
|
||||
});
|
||||
});
|
||||
},
|
||||
async getFullTelemetryPath(telemetry) {
|
||||
const keyString = this.openmct.objects.makeKeyString(telemetry.identifier);
|
||||
const originalPathObjects = await this.openmct.objects.getOriginalPath(keyString, []);
|
||||
|
||||
const telemetryPath = originalPathObjects.reverse().map((pathObject) => {
|
||||
if (pathObject.type !== 'root') {
|
||||
return pathObject.name;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
return telemetryPath.join('/');
|
||||
},
|
||||
removeTelemetryObject(identifier) {
|
||||
const keyString = this.openmct.objects.makeKeyString(identifier);
|
||||
const index = this.telemetryObjs.findIndex((obj) => {
|
||||
|
@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div class="c-inspect-properties">
|
||||
<h2>Configuration</h2>
|
||||
<section>
|
||||
<div class="c-form-row">
|
||||
<label for="historical-toggle">Enable Historical: </label>
|
||||
<ToggleSwitch
|
||||
id="historical-toggle"
|
||||
class="c-toggle-switch"
|
||||
:checked="historicalEnabled"
|
||||
name="condition-historical-toggle"
|
||||
@change="onToggleChange"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ToggleSwitch from '../../../ui/components/ToggleSwitch.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ToggleSwitch
|
||||
},
|
||||
inject: ['openmct', 'domainObject'],
|
||||
data() {
|
||||
return {
|
||||
historicalEnabled: false
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.historicalEnabled = this.domainObject.configuration.shouldFetchHistorical;
|
||||
},
|
||||
methods: {
|
||||
onToggleChange() {
|
||||
this.historicalEnabled = !this.historicalEnabled;
|
||||
this.openmct.objects.mutate(
|
||||
this.domainObject,
|
||||
'configuration.shouldFetchHistorical',
|
||||
this.historicalEnabled
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.c-inspect-properties {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.c-form-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
label {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
@ -99,13 +99,13 @@
|
||||
@change="setOutputValue"
|
||||
>
|
||||
<option v-for="option in outputOptions" :key="option" :value="option">
|
||||
{{ initCap(option) }}
|
||||
{{ option }}
|
||||
</option>
|
||||
</select>
|
||||
</span>
|
||||
<span class="c-cdef__control">
|
||||
<input
|
||||
v-if="selectedOutputSelection === outputOptions[2]"
|
||||
v-if="selectedOutputSelection === outputOptions[3]"
|
||||
v-model="condition.configuration.output"
|
||||
aria-label="Condition Output String"
|
||||
class="t-condition-name-input"
|
||||
@ -113,8 +113,41 @@
|
||||
@change="persist"
|
||||
/>
|
||||
</span>
|
||||
<span v-if="selectedOutputSelection === 'telemetry value'" class="c-cdef__control">
|
||||
<select
|
||||
v-model="condition.configuration.outputTelemetry"
|
||||
aria-label="Output Telemetry Selection"
|
||||
@change="persist"
|
||||
>
|
||||
<option value="">- Select Telemetry -</option>
|
||||
<option
|
||||
v-for="telemetryOption in telemetry"
|
||||
:key="openmct.objects.makeKeyString(telemetryOption.identifier)"
|
||||
:value="openmct.objects.makeKeyString(telemetryOption.identifier)"
|
||||
>
|
||||
{{ telemetryOption.path }}
|
||||
</option>
|
||||
</select>
|
||||
</span>
|
||||
<span v-if="condition.configuration.outputTelemetry" class="c-cdef__control">
|
||||
<select
|
||||
v-model="condition.configuration.outputMetadata"
|
||||
aria-label="Output Telemetry Metadata Selection"
|
||||
@change="persist"
|
||||
>
|
||||
<option value="">- Select Field -</option>
|
||||
<option
|
||||
v-for="(option, index) in telemetryMetadataOptions[
|
||||
condition.configuration.outputTelemetry
|
||||
]"
|
||||
:key="index"
|
||||
:value="option.key"
|
||||
>
|
||||
{{ option.name }}
|
||||
</option>
|
||||
</select>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<div v-if="!condition.isDefault" class="c-cdef__match-and-criteria">
|
||||
<span class="c-cdef__separator c-row-separator"></span>
|
||||
<span class="c-cdef__label">Match</span>
|
||||
@ -181,7 +214,12 @@
|
||||
<span class="c-condition__name">
|
||||
{{ condition.configuration.name }}
|
||||
</span>
|
||||
<span class="c-condition__output"> Output: {{ condition.configuration.output }} </span>
|
||||
<span class="c-condition__output">
|
||||
Output:
|
||||
{{
|
||||
condition.configuration.output === undefined ? 'none' : condition.configuration.output
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="c-condition__summary">
|
||||
<ConditionDescription :show-label="false" :condition="condition" />
|
||||
@ -250,10 +288,11 @@ export default {
|
||||
expanded: true,
|
||||
trigger: 'all',
|
||||
selectedOutputSelection: '',
|
||||
outputOptions: ['false', 'true', 'string'],
|
||||
outputOptions: ['none', 'false', 'true', 'string', 'telemetry value'],
|
||||
criterionIndex: 0,
|
||||
draggingOver: false,
|
||||
isDefault: this.condition.isDefault
|
||||
isDefault: this.condition.isDefault,
|
||||
telemetryMetadataOptions: {}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -287,26 +326,51 @@ export default {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
condition: {
|
||||
handler() {
|
||||
if (this.condition.configuration.output !== 'telemetry value') {
|
||||
this.condition.configuration.outputTelemetry = null;
|
||||
this.condition.configuration.outputMetadata = null;
|
||||
}
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
isEditing(newValue, oldValue) {
|
||||
if (newValue === true) {
|
||||
this.initializeMetadata();
|
||||
}
|
||||
}
|
||||
},
|
||||
unmounted() {
|
||||
this.destroy();
|
||||
},
|
||||
mounted() {
|
||||
this.setOutputSelection();
|
||||
this.initializeMetadata();
|
||||
},
|
||||
methods: {
|
||||
setOutputSelection() {
|
||||
let conditionOutput = this.condition.configuration.output;
|
||||
if (conditionOutput) {
|
||||
if (conditionOutput !== 'false' && conditionOutput !== 'true') {
|
||||
if (
|
||||
conditionOutput !== 'false' &&
|
||||
conditionOutput !== 'true' &&
|
||||
conditionOutput !== 'telemetry value'
|
||||
) {
|
||||
this.selectedOutputSelection = 'string';
|
||||
} else {
|
||||
this.selectedOutputSelection = conditionOutput;
|
||||
}
|
||||
} else if (conditionOutput === undefined) {
|
||||
this.selectedOutputSelection = 'none';
|
||||
}
|
||||
},
|
||||
setOutputValue() {
|
||||
if (this.selectedOutputSelection === 'string') {
|
||||
this.condition.configuration.output = '';
|
||||
} else if (this.selectedOutputSelection === 'none') {
|
||||
this.condition.configuration.output = undefined;
|
||||
} else {
|
||||
this.condition.configuration.output = this.selectedOutputSelection;
|
||||
}
|
||||
@ -401,6 +465,24 @@ export default {
|
||||
},
|
||||
initCap(str) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
},
|
||||
initializeMetadata() {
|
||||
this.telemetry.forEach((telemetryObject) => {
|
||||
const id = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
let telemetryMetadata = this.openmct.telemetry.getMetadata(telemetryObject);
|
||||
if (telemetryMetadata) {
|
||||
this.telemetryMetadataOptions[id] = telemetryMetadata.values().slice();
|
||||
} else {
|
||||
this.telemetryMetadataOptions[id] = [];
|
||||
}
|
||||
});
|
||||
},
|
||||
getId(identifier) {
|
||||
if (identifier) {
|
||||
return this.openmct.objects.makeKeyString(identifier);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -40,7 +40,7 @@
|
||||
:key="telemetryOption.identifier.key"
|
||||
:value="telemetryOption.identifier"
|
||||
>
|
||||
{{ telemetryOption.name }}
|
||||
{{ telemetryOption.path }}
|
||||
</option>
|
||||
</select>
|
||||
</span>
|
||||
|
@ -63,7 +63,7 @@
|
||||
:key="index"
|
||||
:value="telemetryOption.identifier"
|
||||
>
|
||||
{{ telemetryOption.name }}
|
||||
{{ telemetryPaths[index] || telemetryOption.name }}
|
||||
</option>
|
||||
</select>
|
||||
</span>
|
||||
@ -147,7 +147,8 @@ export default {
|
||||
expanded: true,
|
||||
isApplied: false,
|
||||
testInputs: [],
|
||||
telemetryMetadataOptions: {}
|
||||
telemetryMetadataOptions: {},
|
||||
telemetryPaths: []
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
@ -200,6 +201,10 @@ export default {
|
||||
this.telemetryMetadataOptions[id] = [];
|
||||
}
|
||||
});
|
||||
this.telemetry.forEach(async (telemetryOption, index) => {
|
||||
const telemetryPath = await this.getFullTelemetryPath(telemetryOption);
|
||||
this.telemetryPaths[index] = telemetryPath;
|
||||
});
|
||||
},
|
||||
addTestInput(testInput) {
|
||||
this.testInputs.push(
|
||||
@ -244,6 +249,22 @@ export default {
|
||||
applied: this.isApplied,
|
||||
conditionTestInputs: this.testInputs
|
||||
});
|
||||
},
|
||||
async getFullTelemetryPath(telemetry) {
|
||||
const keyStringForObject = this.openmct.objects.makeKeyString(telemetry.identifier);
|
||||
const originalPathObjects = await this.openmct.objects.getOriginalPath(
|
||||
keyStringForObject,
|
||||
[]
|
||||
);
|
||||
|
||||
const telemetryPath = originalPathObjects.reverse().map((pathObject) => {
|
||||
if (pathObject.type !== 'root') {
|
||||
return pathObject.name;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
return telemetryPath.join('/');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
287
src/plugins/condition/historicalTelemetryProvider.js
Normal file
287
src/plugins/condition/historicalTelemetryProvider.js
Normal file
@ -0,0 +1,287 @@
|
||||
export default class HistoricalTelemetryProvider {
|
||||
constructor(openmct, telemetryObjects, conditions, conditionSetDomainObject) {
|
||||
this.openmct = openmct;
|
||||
this.telemetryObjects = telemetryObjects;
|
||||
this.bounds = { start: null, end: null };
|
||||
this.telemetryList = [];
|
||||
this.conditions = conditions;
|
||||
this.conditionSetDomainObject = conditionSetDomainObject;
|
||||
this.historicalTelemetryPoolMap = new Map();
|
||||
this.historicalTelemetryDateMap = new Map();
|
||||
this.index = 0;
|
||||
}
|
||||
|
||||
setTimeBounds(bounds) {
|
||||
this.bounds = bounds;
|
||||
}
|
||||
|
||||
refreshAllHistoricalTelemetries() {
|
||||
const refreshPromises = [];
|
||||
for (const [, value] of Object.entries(this.telemetryObjects)) {
|
||||
refreshPromises.push(this.refreshHistoricalTelemetry(value));
|
||||
}
|
||||
return Promise.all(refreshPromises);
|
||||
}
|
||||
|
||||
async refreshHistoricalTelemetry(domainObject, identifier) {
|
||||
console.log('refreshHistoricalTelemetry');
|
||||
if (!domainObject && identifier) {
|
||||
domainObject = await this.openmct.objects.get(identifier);
|
||||
}
|
||||
const id = this.openmct.objects.makeKeyString(domainObject.identifier);
|
||||
const telemetryOptions = { ...this.bounds };
|
||||
const historicalTelemetry = await this.openmct.telemetry.request(
|
||||
domainObject,
|
||||
telemetryOptions
|
||||
);
|
||||
this.historicalTelemetryPoolMap.set(id, { domainObject, historicalTelemetry });
|
||||
return { domainObject, historicalTelemetry };
|
||||
}
|
||||
|
||||
evaluateTrueCondition(historicalDateMap, timestamp, condition, conditionCollectionMap) {
|
||||
const telemetryData = historicalDateMap.get(timestamp);
|
||||
const conditionConfiguration = conditionCollectionMap.get(condition.id)?.configuration;
|
||||
const { outputTelemetry, outputMetadata } = conditionConfiguration;
|
||||
let output = {};
|
||||
if (outputTelemetry) {
|
||||
const outputTelemetryID = this.openmct.objects.makeKeyString(outputTelemetry);
|
||||
const outputTelemetryData = telemetryData.get(outputTelemetryID);
|
||||
output.telemetry = outputTelemetryData;
|
||||
output.value = outputTelemetryData[outputMetadata];
|
||||
output.condition = condition;
|
||||
} else if (conditionConfiguration?.output) {
|
||||
output.telemetry = null;
|
||||
output.value = conditionConfiguration?.output;
|
||||
output.condition = condition;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
async getAllTelemetries(conditionCollection) {
|
||||
const conditionCollectionMap = new Map();
|
||||
const inputTelemetries = [];
|
||||
const outputTelemetries = [];
|
||||
const historicalTelemetryPoolPromises = [];
|
||||
|
||||
conditionCollection.forEach((condition, index) => {
|
||||
console.log('-------------------------');
|
||||
console.log(condition);
|
||||
const { id } = condition;
|
||||
const { criteria, output, outputTelemetry, outputMetadata } = condition.configuration;
|
||||
const inputTelemetry = criteria?.[0]?.telemetry;
|
||||
console.log(id);
|
||||
console.log(criteria);
|
||||
console.log(output);
|
||||
console.log(outputMetadata);
|
||||
console.log('inputTelemetry', inputTelemetry);
|
||||
console.log('outputTelemetry', outputTelemetry);
|
||||
conditionCollectionMap.set(condition?.id, condition);
|
||||
if (inputTelemetry) {
|
||||
const inputTelemetryId = this.openmct.objects.makeKeyString(inputTelemetry);
|
||||
if (![...inputTelemetries, ...outputTelemetries].includes(inputTelemetryId)) {
|
||||
historicalTelemetryPoolPromises.push(
|
||||
this.refreshHistoricalTelemetry(null, inputTelemetry)
|
||||
);
|
||||
}
|
||||
inputTelemetries.push(inputTelemetryId);
|
||||
} else {
|
||||
inputTelemetries.push(null);
|
||||
}
|
||||
if (outputTelemetry) {
|
||||
if (![...inputTelemetries, ...outputTelemetries].includes(outputTelemetry)) {
|
||||
historicalTelemetryPoolPromises.push(
|
||||
this.refreshHistoricalTelemetry(null, outputTelemetry)
|
||||
);
|
||||
}
|
||||
outputTelemetries.push(outputTelemetry);
|
||||
} else {
|
||||
outputTelemetries.push(null);
|
||||
}
|
||||
});
|
||||
|
||||
const historicalTelemetriesPool = await Promise.all(historicalTelemetryPoolPromises);
|
||||
return {
|
||||
historicalTelemetriesPool,
|
||||
inputTelemetries,
|
||||
outputTelemetries,
|
||||
conditionCollectionMap
|
||||
};
|
||||
}
|
||||
|
||||
sortTelemetriesByDate(historicalTelemetriesPool) {
|
||||
const historicalTelemetryDateMap = new Map();
|
||||
historicalTelemetriesPool.forEach((historicalTelemetryList) => {
|
||||
const { historicalTelemetry, domainObject } = historicalTelemetryList;
|
||||
const { identifier } = domainObject;
|
||||
const telemetryIdentifier = this.openmct.objects.makeKeyString(identifier);
|
||||
historicalTelemetry.forEach((historicalTelemetryItem) => {
|
||||
if (!historicalTelemetryDateMap.get(historicalTelemetryItem.utc)) {
|
||||
const telemetryMap = new Map();
|
||||
telemetryMap.set(telemetryIdentifier, historicalTelemetryItem);
|
||||
historicalTelemetryDateMap.set(historicalTelemetryItem.utc, telemetryMap);
|
||||
} else {
|
||||
const telemetryMap = historicalTelemetryDateMap.get(historicalTelemetryItem.utc);
|
||||
telemetryMap.set(telemetryIdentifier, historicalTelemetryItem);
|
||||
historicalTelemetryDateMap.set(historicalTelemetryItem.utc, telemetryMap);
|
||||
}
|
||||
});
|
||||
});
|
||||
return historicalTelemetryDateMap;
|
||||
}
|
||||
|
||||
async sortTelemetriesInWorker(historicalTelemetriesPool) {
|
||||
const sortedTelemetries = await this.startWorker('sortTelemetries', {
|
||||
historicalTelemetriesPool
|
||||
});
|
||||
return sortedTelemetries;
|
||||
}
|
||||
|
||||
async startWorker(type, data) {
|
||||
// eslint-disable-next-line no-undef
|
||||
const workerUrl = `${this.openmct.getAssetPath()}${__OPENMCT_ROOT_RELATIVE__}historicalTelemetryWorker.js`;
|
||||
const worker = new Worker(workerUrl);
|
||||
|
||||
try {
|
||||
const result = await this.getDataFromWorker(worker, type, data);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('Error in condition manager getHistoricalData:', error);
|
||||
throw error;
|
||||
} finally {
|
||||
worker.terminate();
|
||||
}
|
||||
}
|
||||
|
||||
getDataFromWorker(worker, type, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
worker.onmessage = (e) => {
|
||||
if (e.data.type === 'result') {
|
||||
resolve(e.data.data);
|
||||
} else if (e.data.type === 'error') {
|
||||
reject(new Error(e.data.error));
|
||||
}
|
||||
};
|
||||
|
||||
worker.onerror = (error) => {
|
||||
reject(error);
|
||||
};
|
||||
|
||||
worker.postMessage({
|
||||
type,
|
||||
data
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
evaluateConditionsByDate(historicalTelemetryDateMap, conditionCollectionMap) {
|
||||
const outputTelemetryDateMap = new Map();
|
||||
historicalTelemetryDateMap.forEach((historicalTelemetryMap, timestamp) => {
|
||||
let isConditionValid = false;
|
||||
const evaluatedConditions = [];
|
||||
this.conditions.forEach((condition) => {
|
||||
if (isConditionValid) {
|
||||
return;
|
||||
}
|
||||
const { id } = condition;
|
||||
const conditionMetadata = { condition };
|
||||
const conditionCriteria = condition.criteria[0];
|
||||
let result;
|
||||
if (conditionCriteria?.telemetry) {
|
||||
const conditionInputTelemetryId = this.openmct.objects.makeKeyString(
|
||||
conditionCriteria.telemetry
|
||||
);
|
||||
const inputTelemetry = historicalTelemetryMap.get(conditionInputTelemetryId);
|
||||
conditionMetadata.inputTelemetry = inputTelemetry;
|
||||
result = conditionCriteria.computeResult({
|
||||
id,
|
||||
...inputTelemetry
|
||||
});
|
||||
} else if (!conditionCriteria) {
|
||||
const conditionDetails = conditionCollectionMap.get(id);
|
||||
const { isDefault } = conditionDetails;
|
||||
const conditionConfiguration = conditionDetails?.configuration;
|
||||
const { outputTelemetry, outputMetadata, output } = conditionConfiguration;
|
||||
if (isDefault) {
|
||||
const conditionOutput = {
|
||||
telemetry: null,
|
||||
value: output,
|
||||
condition
|
||||
};
|
||||
outputTelemetryDateMap.set(timestamp, conditionOutput);
|
||||
}
|
||||
}
|
||||
conditionMetadata.result = result;
|
||||
evaluatedConditions.push(conditionMetadata);
|
||||
if (result === true) {
|
||||
isConditionValid = true;
|
||||
const conditionOutput = this.evaluateTrueCondition(
|
||||
historicalTelemetryDateMap,
|
||||
timestamp,
|
||||
condition,
|
||||
conditionCollectionMap
|
||||
);
|
||||
outputTelemetryDateMap.set(timestamp, conditionOutput);
|
||||
}
|
||||
});
|
||||
});
|
||||
return outputTelemetryDateMap;
|
||||
}
|
||||
|
||||
async getHistoricalInputsByDate() {
|
||||
const conditionCollection = this.conditionSetDomainObject.configuration.conditionCollection;
|
||||
|
||||
const {
|
||||
historicalTelemetriesPool,
|
||||
inputTelemetries,
|
||||
outputTelemetries,
|
||||
conditionCollectionMap
|
||||
} = await this.getAllTelemetries(conditionCollection);
|
||||
|
||||
const historicalTelemetryDateMap =
|
||||
await this.sortTelemetriesInWorker(historicalTelemetriesPool);
|
||||
const outputTelemetryDateMap = this.evaluateConditionsByDate(
|
||||
historicalTelemetryDateMap,
|
||||
conditionCollectionMap
|
||||
);
|
||||
|
||||
console.log('*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣*️⃣');
|
||||
console.log(historicalTelemetriesPool);
|
||||
console.log(this.historicalTelemetryPoolMap);
|
||||
console.log(inputTelemetries);
|
||||
console.log(outputTelemetries);
|
||||
console.log(historicalTelemetryDateMap);
|
||||
console.log(outputTelemetryDateMap);
|
||||
|
||||
return outputTelemetryDateMap;
|
||||
}
|
||||
|
||||
addItemToHistoricalTelemetryMap(telemetryMap, item, type, index) {
|
||||
if (type === 'input') {
|
||||
telemetryMap.set();
|
||||
}
|
||||
}
|
||||
|
||||
async getHistoricalData() {
|
||||
console.log('getHistoricalData');
|
||||
this.setTimeBounds(this.openmct.time.getBounds());
|
||||
const outputTelemetryMap = await this.getHistoricalInputsByDate();
|
||||
const formattedOutputTelemetry = this.formatOutputData(outputTelemetryMap);
|
||||
console.log(formattedOutputTelemetry);
|
||||
return formattedOutputTelemetry;
|
||||
}
|
||||
|
||||
formatOutputData(outputTelemetryMap) {
|
||||
const outputTelemetryList = [];
|
||||
const domainObject = this.conditionSetDomainObject;
|
||||
outputTelemetryMap.forEach((outputMetadata, timestamp) => {
|
||||
const { condition, telemetry, value } = outputMetadata;
|
||||
outputTelemetryList.push({
|
||||
conditionId: condition.id,
|
||||
id: domainObject.identifier,
|
||||
output: value,
|
||||
utc: timestamp
|
||||
});
|
||||
});
|
||||
return outputTelemetryList;
|
||||
}
|
||||
}
|
33
src/plugins/condition/historicalTelemetryWorker.js
Normal file
33
src/plugins/condition/historicalTelemetryWorker.js
Normal file
@ -0,0 +1,33 @@
|
||||
import { makeKeyString } from '../../api/objects/object-utils.js';
|
||||
|
||||
function sortTelemetriesByDate(historicalTelemetriesPool) {
|
||||
const historicalTelemetryDateMap = new Map();
|
||||
historicalTelemetriesPool.forEach((historicalTelemetryList) => {
|
||||
const { historicalTelemetry, domainObject } = historicalTelemetryList;
|
||||
const { identifier } = domainObject;
|
||||
const telemetryIdentifier = makeKeyString(identifier);
|
||||
historicalTelemetry.forEach((historicalTelemetryItem) => {
|
||||
if (!historicalTelemetryDateMap.get(historicalTelemetryItem.utc)) {
|
||||
const telemetryMap = new Map();
|
||||
telemetryMap.set(telemetryIdentifier, historicalTelemetryItem);
|
||||
historicalTelemetryDateMap.set(historicalTelemetryItem.utc, telemetryMap);
|
||||
} else {
|
||||
const telemetryMap = historicalTelemetryDateMap.get(historicalTelemetryItem.utc);
|
||||
telemetryMap.set(telemetryIdentifier, historicalTelemetryItem);
|
||||
historicalTelemetryDateMap.set(historicalTelemetryItem.utc, telemetryMap);
|
||||
}
|
||||
});
|
||||
});
|
||||
return historicalTelemetryDateMap;
|
||||
}
|
||||
|
||||
self.onmessage = function (e) {
|
||||
const { type, data } = e.data;
|
||||
|
||||
if (type === 'sortTelemetries') {
|
||||
const sortedTelemetries = sortTelemetriesByDate(data.historicalTelemetriesPool);
|
||||
self.postMessage({ type: 'result', data: sortedTelemetries });
|
||||
} else {
|
||||
self.postMessage({ type: 'error', error: 'Unknown message type' });
|
||||
}
|
||||
};
|
@ -21,6 +21,7 @@
|
||||
*****************************************************************************/
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import ConditionInspectorViewProvider from './ConditionInspectorViewProvider.js';
|
||||
import ConditionSetCompositionPolicy from './ConditionSetCompositionPolicy.js';
|
||||
import ConditionSetMetadataProvider from './ConditionSetMetadataProvider.js';
|
||||
import ConditionSetTelemetryProvider from './ConditionSetTelemetryProvider.js';
|
||||
@ -37,6 +38,7 @@ export default function ConditionPlugin() {
|
||||
cssClass: 'icon-conditional',
|
||||
initialize: function (domainObject) {
|
||||
domainObject.configuration = {
|
||||
shouldFetchHistorical: false,
|
||||
conditionTestData: [],
|
||||
conditionCollection: [
|
||||
{
|
||||
@ -61,5 +63,6 @@ export default function ConditionPlugin() {
|
||||
openmct.telemetry.addProvider(new ConditionSetMetadataProvider(openmct));
|
||||
openmct.telemetry.addProvider(new ConditionSetTelemetryProvider(openmct));
|
||||
openmct.objectViews.addProvider(new ConditionSetViewProvider(openmct));
|
||||
openmct.inspectorViews.addProvider(new ConditionInspectorViewProvider(openmct));
|
||||
};
|
||||
}
|
||||
|
@ -720,50 +720,69 @@ describe('the plugin', function () {
|
||||
};
|
||||
});
|
||||
|
||||
it('should evaluate as old when telemetry is not received in the allotted time', (done) => {
|
||||
it('should evaluate as old when telemetry is not received in the allotted time', async () => {
|
||||
let onAddResolve;
|
||||
const onAddCalledPromise = new Promise((resolve) => {
|
||||
onAddResolve = resolve;
|
||||
});
|
||||
const mockTelemetryCollection = {
|
||||
load: jasmine.createSpy('load'),
|
||||
on: jasmine.createSpy('on').and.callFake((event, callback) => {
|
||||
if (event === 'add') {
|
||||
onAddResolve();
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
openmct.telemetry = jasmine.createSpyObj('telemetry', [
|
||||
'subscribe',
|
||||
'getMetadata',
|
||||
'request',
|
||||
'getValueFormatter',
|
||||
'abortAllRequests'
|
||||
'abortAllRequests',
|
||||
'requestCollection'
|
||||
]);
|
||||
openmct.telemetry.request.and.returnValue(Promise.resolve([]));
|
||||
openmct.telemetry.getMetadata.and.returnValue({
|
||||
...testTelemetryObject.telemetry,
|
||||
valueMetadatas: []
|
||||
valueMetadatas: testTelemetryObject.telemetry.values,
|
||||
valuesForHints: jasmine
|
||||
.createSpy('valuesForHints')
|
||||
.and.returnValue(testTelemetryObject.telemetry.values),
|
||||
value: jasmine.createSpy('value').and.callFake((key) => {
|
||||
return testTelemetryObject.telemetry.values.find((value) => value.key === key);
|
||||
})
|
||||
});
|
||||
openmct.telemetry.request.and.returnValue(Promise.resolve([]));
|
||||
openmct.telemetry.requestCollection.and.returnValue(mockTelemetryCollection);
|
||||
openmct.telemetry.getValueFormatter.and.returnValue({
|
||||
parse: function (value) {
|
||||
return value;
|
||||
}
|
||||
});
|
||||
|
||||
let conditionMgr = new ConditionManager(conditionSetDomainObject, openmct);
|
||||
conditionMgr.on('conditionSetResultUpdated', mockListener);
|
||||
conditionMgr.telemetryObjects = {
|
||||
'test-object': testTelemetryObject
|
||||
};
|
||||
conditionMgr.updateConditionTelemetryObjects();
|
||||
setTimeout(() => {
|
||||
expect(mockListener).toHaveBeenCalledWith({
|
||||
output: 'Any old telemetry',
|
||||
id: {
|
||||
namespace: '',
|
||||
key: 'cf4456a9-296a-4e6b-b182-62ed29cd15b9'
|
||||
},
|
||||
conditionId: '39584410-cbf9-499e-96dc-76f27e69885d',
|
||||
utc: undefined
|
||||
});
|
||||
done();
|
||||
}, 400);
|
||||
// Wait for the 'on' callback to be called
|
||||
await onAddCalledPromise;
|
||||
|
||||
// Simulate the passage of time and no data received
|
||||
await new Promise((resolve) => setTimeout(resolve, 400));
|
||||
|
||||
expect(mockListener).toHaveBeenCalledWith({
|
||||
output: 'Any old telemetry',
|
||||
id: {
|
||||
namespace: '',
|
||||
key: 'cf4456a9-296a-4e6b-b182-62ed29cd15b9'
|
||||
},
|
||||
conditionId: '39584410-cbf9-499e-96dc-76f27e69885d',
|
||||
utc: undefined
|
||||
});
|
||||
});
|
||||
|
||||
it('should not evaluate as old when telemetry is received in the allotted time', (done) => {
|
||||
openmct.telemetry.getMetadata = jasmine.createSpy('getMetadata');
|
||||
openmct.telemetry.getMetadata.and.returnValue({
|
||||
...testTelemetryObject.telemetry,
|
||||
valueMetadatas: testTelemetryObject.telemetry.values
|
||||
});
|
||||
it('should not evaluate as old when telemetry is received in the allotted time', async () => {
|
||||
const testDatum = {
|
||||
'some-key2': '',
|
||||
utc: 1,
|
||||
@ -771,8 +790,49 @@ describe('the plugin', function () {
|
||||
'some-key': null,
|
||||
id: 'test-object'
|
||||
};
|
||||
openmct.telemetry.request = jasmine.createSpy('request');
|
||||
|
||||
let onAddResolve;
|
||||
let onAddCallback;
|
||||
const onAddCalledPromise = new Promise((resolve) => {
|
||||
onAddResolve = resolve;
|
||||
});
|
||||
|
||||
const mockTelemetryCollection = {
|
||||
load: jasmine.createSpy('load'),
|
||||
on: jasmine.createSpy('on').and.callFake((event, callback) => {
|
||||
if (event === 'add') {
|
||||
onAddCallback = callback;
|
||||
onAddResolve();
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
openmct.telemetry = jasmine.createSpyObj('telemetry', [
|
||||
'getMetadata',
|
||||
'getValueFormatter',
|
||||
'request',
|
||||
'subscribe',
|
||||
'requestCollection'
|
||||
]);
|
||||
openmct.telemetry.subscribe.and.returnValue(function () {});
|
||||
openmct.telemetry.request.and.returnValue(Promise.resolve([testDatum]));
|
||||
openmct.telemetry.getMetadata.and.returnValue({
|
||||
...testTelemetryObject.telemetry,
|
||||
valueMetadatas: testTelemetryObject.telemetry.values,
|
||||
valuesForHints: jasmine
|
||||
.createSpy('valuesForHints')
|
||||
.and.returnValue(testTelemetryObject.telemetry.values),
|
||||
value: jasmine.createSpy('value').and.callFake((key) => {
|
||||
return testTelemetryObject.telemetry.values.find((value) => value.key === key);
|
||||
})
|
||||
});
|
||||
openmct.telemetry.requestCollection.and.returnValue(mockTelemetryCollection);
|
||||
openmct.telemetry.getValueFormatter.and.returnValue({
|
||||
parse: function (value) {
|
||||
return value;
|
||||
}
|
||||
});
|
||||
|
||||
const date = 1;
|
||||
conditionSetDomainObject.configuration.conditionCollection[0].configuration.criteria[0].input =
|
||||
['0.4'];
|
||||
@ -782,19 +842,25 @@ describe('the plugin', function () {
|
||||
'test-object': testTelemetryObject
|
||||
};
|
||||
conditionMgr.updateConditionTelemetryObjects();
|
||||
conditionMgr.telemetryReceived(testTelemetryObject, testDatum);
|
||||
setTimeout(() => {
|
||||
expect(mockListener).toHaveBeenCalledWith({
|
||||
output: 'Default',
|
||||
id: {
|
||||
namespace: '',
|
||||
key: 'cf4456a9-296a-4e6b-b182-62ed29cd15b9'
|
||||
},
|
||||
conditionId: '2532d90a-e0d6-4935-b546-3123522da2de',
|
||||
utc: date
|
||||
});
|
||||
done();
|
||||
}, 300);
|
||||
|
||||
// Wait for the 'on' callback to be called
|
||||
await onAddCalledPromise;
|
||||
|
||||
// Simulate receiving telemetry data
|
||||
onAddCallback([testDatum]);
|
||||
|
||||
// Wait a bit for the condition manager to process the data
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
|
||||
expect(mockListener).toHaveBeenCalledWith({
|
||||
output: 'Default',
|
||||
id: {
|
||||
namespace: '',
|
||||
key: 'cf4456a9-296a-4e6b-b182-62ed29cd15b9'
|
||||
},
|
||||
conditionId: '2532d90a-e0d6-4935-b546-3123522da2de',
|
||||
utc: date
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -902,17 +968,25 @@ describe('the plugin', function () {
|
||||
openmct.telemetry.getMetadata = jasmine.createSpy('getMetadata');
|
||||
openmct.telemetry.getMetadata.and.returnValue({
|
||||
...testTelemetryObject.telemetry,
|
||||
valueMetadatas: []
|
||||
valueMetadatas: testTelemetryObject.telemetry.values,
|
||||
valuesForHints: jasmine
|
||||
.createSpy('valuesForHints')
|
||||
.and.returnValue(testTelemetryObject.telemetry.values),
|
||||
value: jasmine.createSpy('value').and.callFake((key) => {
|
||||
return testTelemetryObject.telemetry.values.find((value) => value.key === key);
|
||||
})
|
||||
});
|
||||
conditionMgr.on('conditionSetResultUpdated', mockListener);
|
||||
conditionMgr.telemetryObjects = {
|
||||
'test-object': testTelemetryObject
|
||||
};
|
||||
conditionMgr.updateConditionTelemetryObjects();
|
||||
conditionMgr.telemetryReceived(testTelemetryObject, {
|
||||
'some-key': 2,
|
||||
utc: date
|
||||
});
|
||||
conditionMgr.telemetryReceived(testTelemetryObject, [
|
||||
{
|
||||
'some-key': 2,
|
||||
utc: date
|
||||
}
|
||||
]);
|
||||
let result = conditionMgr.conditions.map((condition) => condition.result);
|
||||
expect(result[2]).toBeUndefined();
|
||||
});
|
||||
@ -1002,26 +1076,37 @@ describe('the plugin', function () {
|
||||
}
|
||||
};
|
||||
openmct.$injector = jasmine.createSpyObj('$injector', ['get']);
|
||||
// const mockTransactionService = jasmine.createSpyObj(
|
||||
// 'transactionService',
|
||||
// ['commit']
|
||||
// );
|
||||
openmct.telemetry = jasmine.createSpyObj('telemetry', [
|
||||
'isTelemetryObject',
|
||||
'request',
|
||||
'subscribe',
|
||||
'getMetadata',
|
||||
'getValueFormatter',
|
||||
'request'
|
||||
'requestCollection'
|
||||
]);
|
||||
openmct.telemetry.isTelemetryObject.and.returnValue(true);
|
||||
openmct.telemetry.subscribe.and.returnValue(function () {});
|
||||
openmct.telemetry.request.and.returnValue(Promise.resolve([]));
|
||||
openmct.telemetry.isTelemetryObject.and.returnValue(true);
|
||||
openmct.telemetry.getMetadata.and.returnValue(testTelemetryObject.telemetry);
|
||||
openmct.telemetry.getMetadata.and.returnValue({
|
||||
...testTelemetryObject.telemetry,
|
||||
valueMetadatas: testTelemetryObject.telemetry.values,
|
||||
valuesForHints: jasmine
|
||||
.createSpy('valuesForHints')
|
||||
.and.returnValue(testTelemetryObject.telemetry.values),
|
||||
value: jasmine.createSpy('value').and.callFake((key) => {
|
||||
return testTelemetryObject.telemetry.values.find((value) => value.key === key);
|
||||
})
|
||||
});
|
||||
openmct.telemetry.getValueFormatter.and.returnValue({
|
||||
parse: function (value) {
|
||||
return value;
|
||||
}
|
||||
});
|
||||
openmct.telemetry.getMetadata.and.returnValue(testTelemetryObject.telemetry);
|
||||
openmct.telemetry.request.and.returnValue(Promise.resolve([]));
|
||||
openmct.telemetry.requestCollection.and.returnValue({
|
||||
load: jasmine.createSpy('load'),
|
||||
on: jasmine.createSpy('on')
|
||||
});
|
||||
|
||||
const styleRuleManger = new StyleRuleManager(stylesObject, openmct, null, true);
|
||||
spyOn(styleRuleManger, 'subscribeToConditionSet');
|
||||
|
@ -243,6 +243,7 @@ export default {
|
||||
domainObject: {
|
||||
...this.childObject,
|
||||
configuration: {
|
||||
...this.childObject.configuration,
|
||||
series: [
|
||||
{
|
||||
identifier: this.childObject.identifier,
|
||||
|
@ -128,36 +128,26 @@ export default {
|
||||
}
|
||||
},
|
||||
updateStyle(styleObj) {
|
||||
let elemToStyle = this.getStyleReceiver();
|
||||
const elemToStyle = this.getStyleReceiver();
|
||||
|
||||
if (!styleObj || elemToStyle === undefined) {
|
||||
if (!styleObj || !elemToStyle) {
|
||||
return;
|
||||
}
|
||||
|
||||
let keys = Object.keys(styleObj);
|
||||
// handle visibility separately
|
||||
if (styleObj.isStyleInvisible !== undefined) {
|
||||
elemToStyle.classList.toggle(STYLE_CONSTANTS.isStyleInvisible, styleObj.isStyleInvisible);
|
||||
styleObj.isStyleInvisible = null;
|
||||
}
|
||||
|
||||
keys.forEach((key) => {
|
||||
if (elemToStyle) {
|
||||
if (typeof styleObj[key] === 'string' && styleObj[key].indexOf('__no_value') > -1) {
|
||||
if (elemToStyle.style[key]) {
|
||||
elemToStyle.style[key] = '';
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
Object.entries(styleObj).forEach(([key, value]) => {
|
||||
if (typeof value !== 'string' || !value.includes('__no_value')) {
|
||||
elemToStyle.style[key] = value;
|
||||
} else {
|
||||
if (
|
||||
!styleObj.isStyleInvisible &&
|
||||
elemToStyle.classList.contains(STYLE_CONSTANTS.isStyleInvisible)
|
||||
) {
|
||||
elemToStyle.classList.remove(STYLE_CONSTANTS.isStyleInvisible);
|
||||
} else if (
|
||||
styleObj.isStyleInvisible &&
|
||||
!elemToStyle.classList.contains(styleObj.isStyleInvisible)
|
||||
) {
|
||||
elemToStyle.classList.add(styleObj.isStyleInvisible);
|
||||
}
|
||||
|
||||
elemToStyle.style[key] = styleObj[key];
|
||||
elemToStyle.style[key] = ''; // remove the property
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ export function ticks(start, stop, count) {
|
||||
}
|
||||
|
||||
export function commonPrefix(a, b) {
|
||||
const maxLen = Math.min(a.length, b.length);
|
||||
const maxLen = Math.min(a.length, b?.length);
|
||||
let breakpoint = 0;
|
||||
for (let i = 0; i < maxLen; i++) {
|
||||
if (a[i] !== b[i]) {
|
||||
@ -110,7 +110,7 @@ export function commonPrefix(a, b) {
|
||||
}
|
||||
|
||||
export function commonSuffix(a, b) {
|
||||
const maxLen = Math.min(a.length, b.length);
|
||||
const maxLen = Math.min(a.length, b?.length);
|
||||
let breakpoint = 0;
|
||||
for (let i = 0; i <= maxLen; i++) {
|
||||
if (a[a.length - i] !== b[b.length - i]) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user