mirror of
https://github.com/nasa/openmct.git
synced 2025-02-01 08:48:28 +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',
|
compsMathWorker: './src/plugins/comps/CompsMathWorker.js',
|
||||||
espressoTheme: './src/plugins/themes/espresso-theme.scss',
|
espressoTheme: './src/plugins/themes/espresso-theme.scss',
|
||||||
snowTheme: './src/plugins/themes/snow-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: {
|
output: {
|
||||||
globalObject: 'this',
|
globalObject: 'this',
|
||||||
|
@ -66,6 +66,10 @@ module.exports = async (config) => {
|
|||||||
{
|
{
|
||||||
pattern: 'dist/generatorWorker.js*',
|
pattern: 'dist/generatorWorker.js*',
|
||||||
included: false
|
included: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: 'dist/historicalTelemetryWorker.js*',
|
||||||
|
included: false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
port: 9876,
|
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 { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
import Condition from './Condition.js';
|
import Condition from './Condition.js';
|
||||||
|
import HistoricalTelemetryProvider from './historicalTelemetryProvider.js';
|
||||||
import { getLatestTimestamp } from './utils/time.js';
|
import { getLatestTimestamp } from './utils/time.js';
|
||||||
|
|
||||||
export default class ConditionManager extends EventEmitter {
|
export default class ConditionManager extends EventEmitter {
|
||||||
@ -39,64 +40,57 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
this.shouldEvaluateNewTelemetry = this.shouldEvaluateNewTelemetry.bind(this);
|
this.shouldEvaluateNewTelemetry = this.shouldEvaluateNewTelemetry.bind(this);
|
||||||
|
|
||||||
this.compositionLoad = this.composition.load();
|
this.compositionLoad = this.composition.load();
|
||||||
this.subscriptions = {};
|
this.telemetryCollections = {};
|
||||||
this.telemetryObjects = {};
|
this.telemetryObjects = {};
|
||||||
this.testData = {
|
this.testData = {
|
||||||
conditionTestInputs: this.conditionSetDomainObject.configuration.conditionTestData,
|
conditionTestInputs: this.conditionSetDomainObject.configuration.conditionTestData,
|
||||||
applied: false
|
applied: false
|
||||||
};
|
};
|
||||||
this.initialize();
|
this.initialize();
|
||||||
|
this.telemetryBuffer = [];
|
||||||
|
this.isProcessing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async requestLatestValue(endpoint) {
|
subscribeToTelemetry(telemetryObject) {
|
||||||
const options = {
|
const keyString = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||||
|
|
||||||
|
if (this.telemetryCollections[keyString]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestOptions = {
|
||||||
size: 1,
|
size: 1,
|
||||||
strategy: 'latest'
|
strategy: 'latest'
|
||||||
};
|
};
|
||||||
const latestData = await this.openmct.telemetry.request(endpoint, options);
|
|
||||||
|
|
||||||
if (!latestData) {
|
this.telemetryCollections[keyString] = this.openmct.telemetry.requestCollection(
|
||||||
throw new Error('Telemetry request failed by returning a falsy response');
|
telemetryObject,
|
||||||
}
|
requestOptions
|
||||||
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)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
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();
|
this.updateConditionTelemetryObjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsubscribeFromTelemetry(endpointIdentifier) {
|
unsubscribeFromTelemetry(endpointIdentifier) {
|
||||||
const id = this.openmct.objects.makeKeyString(endpointIdentifier);
|
const keyString = this.openmct.objects.makeKeyString(endpointIdentifier);
|
||||||
if (!this.subscriptions[id]) {
|
if (!this.telemetryCollections[keyString]) {
|
||||||
console.log('no subscription to remove');
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.subscriptions[id]();
|
this.telemetryCollections[keyString].destroy();
|
||||||
delete this.subscriptions[id];
|
this.telemetryCollections[keyString] = null;
|
||||||
delete this.telemetryObjects[id];
|
this.telemetryObjects[keyString] = null;
|
||||||
this.removeConditionTelemetryObjects();
|
this.removeConditionTelemetryObjects();
|
||||||
|
|
||||||
//force re-computation of condition set result as we might be in a state where
|
//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.timeSystems,
|
||||||
this.openmct.time.getTimeSystem()
|
this.openmct.time.getTimeSystem()
|
||||||
);
|
);
|
||||||
this.updateConditionResults({ id: id });
|
this.updateConditionResults({ id: keyString });
|
||||||
this.updateCurrentCondition(latestTimestamp);
|
this.updateCurrentCondition(latestTimestamp);
|
||||||
|
|
||||||
if (Object.keys(this.telemetryObjects).length === 0) {
|
if (Object.keys(this.telemetryObjects).length === 0) {
|
||||||
@ -329,6 +323,19 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
return currentCondition;
|
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) {
|
getCurrentConditionLAD(conditionResults) {
|
||||||
const conditionCollection = this.conditionSetDomainObject.configuration.conditionCollection;
|
const conditionCollection = this.conditionSetDomainObject.configuration.conditionCollection;
|
||||||
let currentCondition = conditionCollection[conditionCollection.length - 1];
|
let currentCondition = conditionCollection[conditionCollection.length - 1];
|
||||||
@ -384,8 +391,26 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const currentCondition = this.getCurrentConditionLAD(conditionResults);
|
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 = {
|
const currentOutput = {
|
||||||
output: currentCondition.configuration.output,
|
output: output,
|
||||||
id: this.conditionSetDomainObject.identifier,
|
id: this.conditionSetDomainObject.identifier,
|
||||||
conditionId: currentCondition.id,
|
conditionId: currentCondition.id,
|
||||||
...latestTimestamp
|
...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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,11 +447,13 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
return this.openmct.time.getBounds().end >= currentTimestamp;
|
return this.openmct.time.getBounds().end >= currentTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
telemetryReceived(endpoint, datum) {
|
telemetryReceived(endpoint, data) {
|
||||||
if (!this.isTelemetryUsed(endpoint)) {
|
if (!this.isTelemetryUsed(endpoint)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const datum = data[0];
|
||||||
|
|
||||||
const normalizedDatum = this.createNormalizedDatum(datum, endpoint);
|
const normalizedDatum = this.createNormalizedDatum(datum, endpoint);
|
||||||
const timeSystemKey = this.openmct.time.getTimeSystem().key;
|
const timeSystemKey = this.openmct.time.getTimeSystem().key;
|
||||||
let timestamp = {};
|
let timestamp = {};
|
||||||
@ -422,7 +461,7 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
timestamp[timeSystemKey] = currentTimestamp;
|
timestamp[timeSystemKey] = currentTimestamp;
|
||||||
if (this.shouldEvaluateNewTelemetry(currentTimestamp)) {
|
if (this.shouldEvaluateNewTelemetry(currentTimestamp)) {
|
||||||
this.updateConditionResults(normalizedDatum);
|
this.updateConditionResults(normalizedDatum);
|
||||||
this.updateCurrentCondition(timestamp);
|
this.updateCurrentCondition(timestamp, endpoint, datum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,14 +474,12 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCurrentCondition(timestamp) {
|
emitConditionSetResult(currentCondition, timestamp, outputValue) {
|
||||||
const currentCondition = this.getCurrentCondition();
|
|
||||||
|
|
||||||
this.emit(
|
this.emit(
|
||||||
'conditionSetResultUpdated',
|
'conditionSetResultUpdated',
|
||||||
Object.assign(
|
Object.assign(
|
||||||
{
|
{
|
||||||
output: currentCondition.configuration.output,
|
output: outputValue,
|
||||||
id: this.conditionSetDomainObject.identifier,
|
id: this.conditionSetDomainObject.identifier,
|
||||||
conditionId: currentCondition.id
|
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) {
|
getTestData(metadatum) {
|
||||||
let data = undefined;
|
let data = undefined;
|
||||||
if (this.testData.applied) {
|
if (this.testData.applied) {
|
||||||
@ -507,8 +598,9 @@ export default class ConditionManager extends EventEmitter {
|
|||||||
destroy() {
|
destroy() {
|
||||||
this.composition.off('add', this.subscribeToTelemetry, this);
|
this.composition.off('add', this.subscribeToTelemetry, this);
|
||||||
this.composition.off('remove', this.unsubscribeFromTelemetry, this);
|
this.composition.off('remove', this.unsubscribeFromTelemetry, this);
|
||||||
Object.values(this.subscriptions).forEach((unsubscribe) => unsubscribe());
|
Object.values(this.telemetryCollections).forEach((telemetryCollection) =>
|
||||||
delete this.subscriptions;
|
telemetryCollection.destroy()
|
||||||
|
);
|
||||||
|
|
||||||
this.conditions.forEach((condition) => {
|
this.conditions.forEach((condition) => {
|
||||||
condition.destroy();
|
condition.destroy();
|
||||||
|
@ -42,8 +42,9 @@ export default class ConditionSetTelemetryProvider {
|
|||||||
|
|
||||||
async request(domainObject, options) {
|
async request(domainObject, options) {
|
||||||
let conditionManager = this.getConditionManager(domainObject);
|
let conditionManager = this.getConditionManager(domainObject);
|
||||||
|
const formattedHistoricalData = await conditionManager.getHistoricalData();
|
||||||
let latestOutput = await conditionManager.requestLADConditionSetOutput(options);
|
let latestOutput = await conditionManager.requestLADConditionSetOutput(options);
|
||||||
return latestOutput;
|
return [...formattedHistoricalData, ...latestOutput];
|
||||||
}
|
}
|
||||||
|
|
||||||
subscribe(domainObject, callback) {
|
subscribe(domainObject, callback) {
|
||||||
|
@ -235,10 +235,11 @@ export default {
|
|||||||
|
|
||||||
return arr;
|
return arr;
|
||||||
},
|
},
|
||||||
addTelemetryObject(domainObject) {
|
async addTelemetryObject(domainObject) {
|
||||||
const keyString = this.openmct.objects.makeKeyString(domainObject.identifier);
|
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.$emit('telemetry-updated', this.telemetryObjs);
|
||||||
|
|
||||||
this.subscribeToStaleness(domainObject, (stalenessResponse) => {
|
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) {
|
removeTelemetryObject(identifier) {
|
||||||
const keyString = this.openmct.objects.makeKeyString(identifier);
|
const keyString = this.openmct.objects.makeKeyString(identifier);
|
||||||
const index = this.telemetryObjs.findIndex((obj) => {
|
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"
|
@change="setOutputValue"
|
||||||
>
|
>
|
||||||
<option v-for="option in outputOptions" :key="option" :value="option">
|
<option v-for="option in outputOptions" :key="option" :value="option">
|
||||||
{{ initCap(option) }}
|
{{ option }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</span>
|
</span>
|
||||||
<span class="c-cdef__control">
|
<span class="c-cdef__control">
|
||||||
<input
|
<input
|
||||||
v-if="selectedOutputSelection === outputOptions[2]"
|
v-if="selectedOutputSelection === outputOptions[3]"
|
||||||
v-model="condition.configuration.output"
|
v-model="condition.configuration.output"
|
||||||
aria-label="Condition Output String"
|
aria-label="Condition Output String"
|
||||||
class="t-condition-name-input"
|
class="t-condition-name-input"
|
||||||
@ -113,8 +113,41 @@
|
|||||||
@change="persist"
|
@change="persist"
|
||||||
/>
|
/>
|
||||||
</span>
|
</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>
|
</span>
|
||||||
|
|
||||||
<div v-if="!condition.isDefault" class="c-cdef__match-and-criteria">
|
<div v-if="!condition.isDefault" class="c-cdef__match-and-criteria">
|
||||||
<span class="c-cdef__separator c-row-separator"></span>
|
<span class="c-cdef__separator c-row-separator"></span>
|
||||||
<span class="c-cdef__label">Match</span>
|
<span class="c-cdef__label">Match</span>
|
||||||
@ -181,7 +214,12 @@
|
|||||||
<span class="c-condition__name">
|
<span class="c-condition__name">
|
||||||
{{ condition.configuration.name }}
|
{{ condition.configuration.name }}
|
||||||
</span>
|
</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>
|
||||||
<div class="c-condition__summary">
|
<div class="c-condition__summary">
|
||||||
<ConditionDescription :show-label="false" :condition="condition" />
|
<ConditionDescription :show-label="false" :condition="condition" />
|
||||||
@ -250,10 +288,11 @@ export default {
|
|||||||
expanded: true,
|
expanded: true,
|
||||||
trigger: 'all',
|
trigger: 'all',
|
||||||
selectedOutputSelection: '',
|
selectedOutputSelection: '',
|
||||||
outputOptions: ['false', 'true', 'string'],
|
outputOptions: ['none', 'false', 'true', 'string', 'telemetry value'],
|
||||||
criterionIndex: 0,
|
criterionIndex: 0,
|
||||||
draggingOver: false,
|
draggingOver: false,
|
||||||
isDefault: this.condition.isDefault
|
isDefault: this.condition.isDefault,
|
||||||
|
telemetryMetadataOptions: {}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -287,26 +326,51 @@ export default {
|
|||||||
return false;
|
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() {
|
unmounted() {
|
||||||
this.destroy();
|
this.destroy();
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.setOutputSelection();
|
this.setOutputSelection();
|
||||||
|
this.initializeMetadata();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
setOutputSelection() {
|
setOutputSelection() {
|
||||||
let conditionOutput = this.condition.configuration.output;
|
let conditionOutput = this.condition.configuration.output;
|
||||||
if (conditionOutput) {
|
if (conditionOutput) {
|
||||||
if (conditionOutput !== 'false' && conditionOutput !== 'true') {
|
if (
|
||||||
|
conditionOutput !== 'false' &&
|
||||||
|
conditionOutput !== 'true' &&
|
||||||
|
conditionOutput !== 'telemetry value'
|
||||||
|
) {
|
||||||
this.selectedOutputSelection = 'string';
|
this.selectedOutputSelection = 'string';
|
||||||
} else {
|
} else {
|
||||||
this.selectedOutputSelection = conditionOutput;
|
this.selectedOutputSelection = conditionOutput;
|
||||||
}
|
}
|
||||||
|
} else if (conditionOutput === undefined) {
|
||||||
|
this.selectedOutputSelection = 'none';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setOutputValue() {
|
setOutputValue() {
|
||||||
if (this.selectedOutputSelection === 'string') {
|
if (this.selectedOutputSelection === 'string') {
|
||||||
this.condition.configuration.output = '';
|
this.condition.configuration.output = '';
|
||||||
|
} else if (this.selectedOutputSelection === 'none') {
|
||||||
|
this.condition.configuration.output = undefined;
|
||||||
} else {
|
} else {
|
||||||
this.condition.configuration.output = this.selectedOutputSelection;
|
this.condition.configuration.output = this.selectedOutputSelection;
|
||||||
}
|
}
|
||||||
@ -401,6 +465,24 @@ export default {
|
|||||||
},
|
},
|
||||||
initCap(str) {
|
initCap(str) {
|
||||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
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"
|
:key="telemetryOption.identifier.key"
|
||||||
:value="telemetryOption.identifier"
|
:value="telemetryOption.identifier"
|
||||||
>
|
>
|
||||||
{{ telemetryOption.name }}
|
{{ telemetryOption.path }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</span>
|
</span>
|
||||||
|
@ -63,7 +63,7 @@
|
|||||||
:key="index"
|
:key="index"
|
||||||
:value="telemetryOption.identifier"
|
:value="telemetryOption.identifier"
|
||||||
>
|
>
|
||||||
{{ telemetryOption.name }}
|
{{ telemetryPaths[index] || telemetryOption.name }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</span>
|
</span>
|
||||||
@ -147,7 +147,8 @@ export default {
|
|||||||
expanded: true,
|
expanded: true,
|
||||||
isApplied: false,
|
isApplied: false,
|
||||||
testInputs: [],
|
testInputs: [],
|
||||||
telemetryMetadataOptions: {}
|
telemetryMetadataOptions: {},
|
||||||
|
telemetryPaths: []
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -200,6 +201,10 @@ export default {
|
|||||||
this.telemetryMetadataOptions[id] = [];
|
this.telemetryMetadataOptions[id] = [];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
this.telemetry.forEach(async (telemetryOption, index) => {
|
||||||
|
const telemetryPath = await this.getFullTelemetryPath(telemetryOption);
|
||||||
|
this.telemetryPaths[index] = telemetryPath;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
addTestInput(testInput) {
|
addTestInput(testInput) {
|
||||||
this.testInputs.push(
|
this.testInputs.push(
|
||||||
@ -244,6 +249,22 @@ export default {
|
|||||||
applied: this.isApplied,
|
applied: this.isApplied,
|
||||||
conditionTestInputs: this.testInputs
|
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 { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
|
import ConditionInspectorViewProvider from './ConditionInspectorViewProvider.js';
|
||||||
import ConditionSetCompositionPolicy from './ConditionSetCompositionPolicy.js';
|
import ConditionSetCompositionPolicy from './ConditionSetCompositionPolicy.js';
|
||||||
import ConditionSetMetadataProvider from './ConditionSetMetadataProvider.js';
|
import ConditionSetMetadataProvider from './ConditionSetMetadataProvider.js';
|
||||||
import ConditionSetTelemetryProvider from './ConditionSetTelemetryProvider.js';
|
import ConditionSetTelemetryProvider from './ConditionSetTelemetryProvider.js';
|
||||||
@ -37,6 +38,7 @@ export default function ConditionPlugin() {
|
|||||||
cssClass: 'icon-conditional',
|
cssClass: 'icon-conditional',
|
||||||
initialize: function (domainObject) {
|
initialize: function (domainObject) {
|
||||||
domainObject.configuration = {
|
domainObject.configuration = {
|
||||||
|
shouldFetchHistorical: false,
|
||||||
conditionTestData: [],
|
conditionTestData: [],
|
||||||
conditionCollection: [
|
conditionCollection: [
|
||||||
{
|
{
|
||||||
@ -61,5 +63,6 @@ export default function ConditionPlugin() {
|
|||||||
openmct.telemetry.addProvider(new ConditionSetMetadataProvider(openmct));
|
openmct.telemetry.addProvider(new ConditionSetMetadataProvider(openmct));
|
||||||
openmct.telemetry.addProvider(new ConditionSetTelemetryProvider(openmct));
|
openmct.telemetry.addProvider(new ConditionSetTelemetryProvider(openmct));
|
||||||
openmct.objectViews.addProvider(new ConditionSetViewProvider(openmct));
|
openmct.objectViews.addProvider(new ConditionSetViewProvider(openmct));
|
||||||
|
openmct.inspectorViews.addProvider(new ConditionInspectorViewProvider(openmct));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -720,31 +720,57 @@ 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', [
|
openmct.telemetry = jasmine.createSpyObj('telemetry', [
|
||||||
'subscribe',
|
|
||||||
'getMetadata',
|
'getMetadata',
|
||||||
'request',
|
'request',
|
||||||
'getValueFormatter',
|
'getValueFormatter',
|
||||||
'abortAllRequests'
|
'abortAllRequests',
|
||||||
|
'requestCollection'
|
||||||
]);
|
]);
|
||||||
|
openmct.telemetry.request.and.returnValue(Promise.resolve([]));
|
||||||
openmct.telemetry.getMetadata.and.returnValue({
|
openmct.telemetry.getMetadata.and.returnValue({
|
||||||
...testTelemetryObject.telemetry,
|
...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({
|
openmct.telemetry.getValueFormatter.and.returnValue({
|
||||||
parse: function (value) {
|
parse: function (value) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let conditionMgr = new ConditionManager(conditionSetDomainObject, openmct);
|
let conditionMgr = new ConditionManager(conditionSetDomainObject, openmct);
|
||||||
conditionMgr.on('conditionSetResultUpdated', mockListener);
|
conditionMgr.on('conditionSetResultUpdated', mockListener);
|
||||||
conditionMgr.telemetryObjects = {
|
conditionMgr.telemetryObjects = {
|
||||||
'test-object': testTelemetryObject
|
'test-object': testTelemetryObject
|
||||||
};
|
};
|
||||||
conditionMgr.updateConditionTelemetryObjects();
|
conditionMgr.updateConditionTelemetryObjects();
|
||||||
setTimeout(() => {
|
// 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({
|
expect(mockListener).toHaveBeenCalledWith({
|
||||||
output: 'Any old telemetry',
|
output: 'Any old telemetry',
|
||||||
id: {
|
id: {
|
||||||
@ -754,16 +780,9 @@ describe('the plugin', function () {
|
|||||||
conditionId: '39584410-cbf9-499e-96dc-76f27e69885d',
|
conditionId: '39584410-cbf9-499e-96dc-76f27e69885d',
|
||||||
utc: undefined
|
utc: undefined
|
||||||
});
|
});
|
||||||
done();
|
|
||||||
}, 400);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not evaluate as old when telemetry is received in the allotted time', (done) => {
|
it('should not evaluate as old when telemetry is received in the allotted time', async () => {
|
||||||
openmct.telemetry.getMetadata = jasmine.createSpy('getMetadata');
|
|
||||||
openmct.telemetry.getMetadata.and.returnValue({
|
|
||||||
...testTelemetryObject.telemetry,
|
|
||||||
valueMetadatas: testTelemetryObject.telemetry.values
|
|
||||||
});
|
|
||||||
const testDatum = {
|
const testDatum = {
|
||||||
'some-key2': '',
|
'some-key2': '',
|
||||||
utc: 1,
|
utc: 1,
|
||||||
@ -771,8 +790,49 @@ describe('the plugin', function () {
|
|||||||
'some-key': null,
|
'some-key': null,
|
||||||
id: 'test-object'
|
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.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;
|
const date = 1;
|
||||||
conditionSetDomainObject.configuration.conditionCollection[0].configuration.criteria[0].input =
|
conditionSetDomainObject.configuration.conditionCollection[0].configuration.criteria[0].input =
|
||||||
['0.4'];
|
['0.4'];
|
||||||
@ -782,8 +842,16 @@ describe('the plugin', function () {
|
|||||||
'test-object': testTelemetryObject
|
'test-object': testTelemetryObject
|
||||||
};
|
};
|
||||||
conditionMgr.updateConditionTelemetryObjects();
|
conditionMgr.updateConditionTelemetryObjects();
|
||||||
conditionMgr.telemetryReceived(testTelemetryObject, testDatum);
|
|
||||||
setTimeout(() => {
|
// 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({
|
expect(mockListener).toHaveBeenCalledWith({
|
||||||
output: 'Default',
|
output: 'Default',
|
||||||
id: {
|
id: {
|
||||||
@ -793,8 +861,6 @@ describe('the plugin', function () {
|
|||||||
conditionId: '2532d90a-e0d6-4935-b546-3123522da2de',
|
conditionId: '2532d90a-e0d6-4935-b546-3123522da2de',
|
||||||
utc: date
|
utc: date
|
||||||
});
|
});
|
||||||
done();
|
|
||||||
}, 300);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -902,17 +968,25 @@ describe('the plugin', function () {
|
|||||||
openmct.telemetry.getMetadata = jasmine.createSpy('getMetadata');
|
openmct.telemetry.getMetadata = jasmine.createSpy('getMetadata');
|
||||||
openmct.telemetry.getMetadata.and.returnValue({
|
openmct.telemetry.getMetadata.and.returnValue({
|
||||||
...testTelemetryObject.telemetry,
|
...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.on('conditionSetResultUpdated', mockListener);
|
||||||
conditionMgr.telemetryObjects = {
|
conditionMgr.telemetryObjects = {
|
||||||
'test-object': testTelemetryObject
|
'test-object': testTelemetryObject
|
||||||
};
|
};
|
||||||
conditionMgr.updateConditionTelemetryObjects();
|
conditionMgr.updateConditionTelemetryObjects();
|
||||||
conditionMgr.telemetryReceived(testTelemetryObject, {
|
conditionMgr.telemetryReceived(testTelemetryObject, [
|
||||||
|
{
|
||||||
'some-key': 2,
|
'some-key': 2,
|
||||||
utc: date
|
utc: date
|
||||||
});
|
}
|
||||||
|
]);
|
||||||
let result = conditionMgr.conditions.map((condition) => condition.result);
|
let result = conditionMgr.conditions.map((condition) => condition.result);
|
||||||
expect(result[2]).toBeUndefined();
|
expect(result[2]).toBeUndefined();
|
||||||
});
|
});
|
||||||
@ -1002,26 +1076,37 @@ describe('the plugin', function () {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
openmct.$injector = jasmine.createSpyObj('$injector', ['get']);
|
openmct.$injector = jasmine.createSpyObj('$injector', ['get']);
|
||||||
// const mockTransactionService = jasmine.createSpyObj(
|
|
||||||
// 'transactionService',
|
|
||||||
// ['commit']
|
|
||||||
// );
|
|
||||||
openmct.telemetry = jasmine.createSpyObj('telemetry', [
|
openmct.telemetry = jasmine.createSpyObj('telemetry', [
|
||||||
'isTelemetryObject',
|
'isTelemetryObject',
|
||||||
|
'request',
|
||||||
'subscribe',
|
'subscribe',
|
||||||
'getMetadata',
|
'getMetadata',
|
||||||
'getValueFormatter',
|
'getValueFormatter',
|
||||||
'request'
|
'requestCollection'
|
||||||
]);
|
]);
|
||||||
openmct.telemetry.isTelemetryObject.and.returnValue(true);
|
|
||||||
openmct.telemetry.subscribe.and.returnValue(function () {});
|
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({
|
openmct.telemetry.getValueFormatter.and.returnValue({
|
||||||
parse: function (value) {
|
parse: function (value) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
openmct.telemetry.getMetadata.and.returnValue(testTelemetryObject.telemetry);
|
openmct.telemetry.requestCollection.and.returnValue({
|
||||||
openmct.telemetry.request.and.returnValue(Promise.resolve([]));
|
load: jasmine.createSpy('load'),
|
||||||
|
on: jasmine.createSpy('on')
|
||||||
|
});
|
||||||
|
|
||||||
const styleRuleManger = new StyleRuleManager(stylesObject, openmct, null, true);
|
const styleRuleManger = new StyleRuleManager(stylesObject, openmct, null, true);
|
||||||
spyOn(styleRuleManger, 'subscribeToConditionSet');
|
spyOn(styleRuleManger, 'subscribeToConditionSet');
|
||||||
|
@ -243,6 +243,7 @@ export default {
|
|||||||
domainObject: {
|
domainObject: {
|
||||||
...this.childObject,
|
...this.childObject,
|
||||||
configuration: {
|
configuration: {
|
||||||
|
...this.childObject.configuration,
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
identifier: this.childObject.identifier,
|
identifier: this.childObject.identifier,
|
||||||
|
@ -128,37 +128,27 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateStyle(styleObj) {
|
updateStyle(styleObj) {
|
||||||
let elemToStyle = this.getStyleReceiver();
|
const elemToStyle = this.getStyleReceiver();
|
||||||
|
|
||||||
if (!styleObj || elemToStyle === undefined) {
|
if (!styleObj || !elemToStyle) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let keys = Object.keys(styleObj);
|
// handle visibility separately
|
||||||
|
if (styleObj.isStyleInvisible !== undefined) {
|
||||||
keys.forEach((key) => {
|
elemToStyle.classList.toggle(STYLE_CONSTANTS.isStyleInvisible, styleObj.isStyleInvisible);
|
||||||
if (elemToStyle) {
|
styleObj.isStyleInvisible = null;
|
||||||
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 {
|
} else {
|
||||||
if (
|
elemToStyle.style[key] = ''; // remove the property
|
||||||
!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];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -94,7 +94,7 @@ export function ticks(start, stop, count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function commonPrefix(a, b) {
|
export function commonPrefix(a, b) {
|
||||||
const maxLen = Math.min(a.length, b.length);
|
const maxLen = Math.min(a.length, b?.length);
|
||||||
let breakpoint = 0;
|
let breakpoint = 0;
|
||||||
for (let i = 0; i < maxLen; i++) {
|
for (let i = 0; i < maxLen; i++) {
|
||||||
if (a[i] !== b[i]) {
|
if (a[i] !== b[i]) {
|
||||||
@ -110,7 +110,7 @@ export function commonPrefix(a, b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function commonSuffix(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;
|
let breakpoint = 0;
|
||||||
for (let i = 0; i <= maxLen; i++) {
|
for (let i = 0; i <= maxLen; i++) {
|
||||||
if (a[a.length - i] !== b[b.length - i]) {
|
if (a[a.length - i] !== b[b.length - i]) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user