From 92ecf3af1d40e89b0a7d70b54c1475976ce61e15 Mon Sep 17 00:00:00 2001 From: David Tsay Date: Tue, 25 Feb 2020 16:37:43 -0800 Subject: [PATCH 01/17] provide telemetry * listen to realtime data --- .../ConditionSetTelemetryProvider.js | 24 +++++++++++++++++++ .../condition/components/ConditionSet.vue | 9 +++++++ src/plugins/condition/plugin.js | 3 ++- 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 src/plugins/condition/ConditionSetTelemetryProvider.js diff --git a/src/plugins/condition/ConditionSetTelemetryProvider.js b/src/plugins/condition/ConditionSetTelemetryProvider.js new file mode 100644 index 0000000000..f462d9ccbf --- /dev/null +++ b/src/plugins/condition/ConditionSetTelemetryProvider.js @@ -0,0 +1,24 @@ +import ConditionManager from './ConditionManager' + +export default class ConditionSetTelemetryProvider { + constructor(openmct) { + this.openmct = openmct; + } + + supportsRequest(domainObject, options) { + return false; + } + + supportsSubscribe(domainObject) { + return domainObject.type === 'conditionSet'; + } + + subscribe(domainObject, callback) { + let conditionManager = new ConditionManager(domainObject, this.openmct); + conditionManager.on('conditionSetResultUpdated', (output) => output); + + return function unsubscribe() { + conditionManager.off('conditionSetResultUpdated'); + } + } +} diff --git a/src/plugins/condition/components/ConditionSet.vue b/src/plugins/condition/components/ConditionSet.vue index cc5af46072..ae7823b416 100644 --- a/src/plugins/condition/components/ConditionSet.vue +++ b/src/plugins/condition/components/ConditionSet.vue @@ -54,12 +54,21 @@ export default { }, mounted() { this.conditionSetIdentifier = this.openmct.objects.makeKeyString(this.domainObject.identifier); + this.provideTelemetry(); + }, + beforeDestroy() { + if (this.stopProvidingTelemetry) { + this.stopProvidingTelemetry(); + } }, methods: { updateCurrentOutput(currentConditionResult) { if (this.openmct.objects.makeKeyString(currentConditionResult.id) === this.conditionSetIdentifier) { this.currentConditionOutput = currentConditionResult.output; } + }, + provideTelemetry() { + this.stopProvidingTelemetry = this.openmct.telemetry.subscribe(this.domainObject); } } }; diff --git a/src/plugins/condition/plugin.js b/src/plugins/condition/plugin.js index 4994904f43..60172d5132 100644 --- a/src/plugins/condition/plugin.js +++ b/src/plugins/condition/plugin.js @@ -21,6 +21,7 @@ *****************************************************************************/ import ConditionSetViewProvider from './ConditionSetViewProvider.js'; import ConditionSetCompositionPolicy from "./ConditionSetCompositionPolicy"; +import ConditionSetTelemetryProvider from './ConditionSetTelemetryProvider'; export default function ConditionPlugin() { @@ -50,7 +51,7 @@ export default function ConditionPlugin() { }); openmct.composition.addPolicy(new ConditionSetCompositionPolicy(openmct).allow); - + openmct.telemetry.addProvider(new ConditionSetTelemetryProvider(openmct)); openmct.objectViews.addProvider(new ConditionSetViewProvider(openmct)); } From 486dae54bd7e2c4f3413320a3f3a4effd951a6fa Mon Sep 17 00:00:00 2001 From: David Tsay Date: Tue, 25 Feb 2020 17:27:08 -0800 Subject: [PATCH 02/17] add metadata provider --- .../condition/ConditionSetMetadataProvider.js | 37 +++++++++++++++++++ src/plugins/condition/plugin.js | 2 + 2 files changed, 39 insertions(+) create mode 100644 src/plugins/condition/ConditionSetMetadataProvider.js diff --git a/src/plugins/condition/ConditionSetMetadataProvider.js b/src/plugins/condition/ConditionSetMetadataProvider.js new file mode 100644 index 0000000000..6f58db3655 --- /dev/null +++ b/src/plugins/condition/ConditionSetMetadataProvider.js @@ -0,0 +1,37 @@ +export default class ConditionSetMetadataProvider { + constructor(openmct) { + this.openmct = openmct; + } + + supportsMetadata(domainObject) { + return domainObject.type === 'conditionSet'; + } + + getDomains(domainObject) { + return this.openmct.time.getAllTimeSystems().map(function (ts, i) { + return { + key: ts.key, + name: ts.name, + format: ts.timeFormat, + hints: { + domain: i + } + }; + }); + } + + getMetadata(domainObject) { + return { + values: this.getDomains().concat([ + { + name: 'Output', + key: 'output', + type: 'string', + hints: { + range: 1 + } + } + ]) + }; + } +} diff --git a/src/plugins/condition/plugin.js b/src/plugins/condition/plugin.js index 60172d5132..691e088d0c 100644 --- a/src/plugins/condition/plugin.js +++ b/src/plugins/condition/plugin.js @@ -21,6 +21,7 @@ *****************************************************************************/ import ConditionSetViewProvider from './ConditionSetViewProvider.js'; import ConditionSetCompositionPolicy from "./ConditionSetCompositionPolicy"; +import ConditionSetMetadataProvider from './ConditionSetMetadataProvider'; import ConditionSetTelemetryProvider from './ConditionSetTelemetryProvider'; export default function ConditionPlugin() { @@ -51,6 +52,7 @@ export default function ConditionPlugin() { }); openmct.composition.addPolicy(new ConditionSetCompositionPolicy(openmct).allow); + openmct.telemetry.addProvider(new ConditionSetMetadataProvider(openmct)); openmct.telemetry.addProvider(new ConditionSetTelemetryProvider(openmct)); openmct.objectViews.addProvider(new ConditionSetViewProvider(openmct)); From 0915aaea3b4f53188e213b2ad72f81541c8636e2 Mon Sep 17 00:00:00 2001 From: David Tsay Date: Wed, 26 Feb 2020 11:31:26 -0800 Subject: [PATCH 03/17] allow conditions to be dropped into telemetry views --- src/plugins/condition/ConditionSetTelemetryProvider.js | 3 +++ src/plugins/condition/ConditionSetViewProvider.js | 10 ++++++++++ src/plugins/condition/plugin.js | 1 + 3 files changed, 14 insertions(+) diff --git a/src/plugins/condition/ConditionSetTelemetryProvider.js b/src/plugins/condition/ConditionSetTelemetryProvider.js index f462d9ccbf..513b16a2eb 100644 --- a/src/plugins/condition/ConditionSetTelemetryProvider.js +++ b/src/plugins/condition/ConditionSetTelemetryProvider.js @@ -4,6 +4,9 @@ export default class ConditionSetTelemetryProvider { constructor(openmct) { this.openmct = openmct; } + isTelemetryObject(domainObject) { + return domainObject.type === 'conditionSet'; + } supportsRequest(domainObject, options) { return false; diff --git a/src/plugins/condition/ConditionSetViewProvider.js b/src/plugins/condition/ConditionSetViewProvider.js index 91bd2f5409..43eb436f7e 100644 --- a/src/plugins/condition/ConditionSetViewProvider.js +++ b/src/plugins/condition/ConditionSetViewProvider.js @@ -23,6 +23,8 @@ import ConditionSet from './components/ConditionSet.vue'; import Vue from 'vue'; +const DEFAULT_VIEW_PRIORITY = 100; + export default class ConditionSetViewProvider { constructor(openmct) { this.openmct = openmct; @@ -71,4 +73,12 @@ export default class ConditionSetViewProvider { } }; } + + priority(domainObject) { + if (domainObject.type === 'conditionSet') { + return Number.MAX_VALUE; + } else { + return DEFAULT_VIEW_PRIORITY; + } + } } diff --git a/src/plugins/condition/plugin.js b/src/plugins/condition/plugin.js index 691e088d0c..dc485f4573 100644 --- a/src/plugins/condition/plugin.js +++ b/src/plugins/condition/plugin.js @@ -48,6 +48,7 @@ export default function ConditionPlugin() { conditionCollection: [] }; domainObject.composition = []; + domainObject.telemetry = {}; } }); From 44566330108831d802b46208014eedc80084c38f Mon Sep 17 00:00:00 2001 From: David Tsay Date: Wed, 26 Feb 2020 12:27:28 -0800 Subject: [PATCH 04/17] output telemetry to views --- src/plugins/condition/ConditionSetMetadataProvider.js | 2 +- src/plugins/condition/ConditionSetTelemetryProvider.js | 3 ++- src/plugins/condition/components/ConditionSet.vue | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/plugins/condition/ConditionSetMetadataProvider.js b/src/plugins/condition/ConditionSetMetadataProvider.js index 6f58db3655..0d81a692b1 100644 --- a/src/plugins/condition/ConditionSetMetadataProvider.js +++ b/src/plugins/condition/ConditionSetMetadataProvider.js @@ -26,7 +26,7 @@ export default class ConditionSetMetadataProvider { { name: 'Output', key: 'output', - type: 'string', + format: 'string', hints: { range: 1 } diff --git a/src/plugins/condition/ConditionSetTelemetryProvider.js b/src/plugins/condition/ConditionSetTelemetryProvider.js index 513b16a2eb..d75db13e11 100644 --- a/src/plugins/condition/ConditionSetTelemetryProvider.js +++ b/src/plugins/condition/ConditionSetTelemetryProvider.js @@ -4,6 +4,7 @@ export default class ConditionSetTelemetryProvider { constructor(openmct) { this.openmct = openmct; } + isTelemetryObject(domainObject) { return domainObject.type === 'conditionSet'; } @@ -18,7 +19,7 @@ export default class ConditionSetTelemetryProvider { subscribe(domainObject, callback) { let conditionManager = new ConditionManager(domainObject, this.openmct); - conditionManager.on('conditionSetResultUpdated', (output) => output); + conditionManager.on('conditionSetResultUpdated', callback); return function unsubscribe() { conditionManager.off('conditionSetResultUpdated'); diff --git a/src/plugins/condition/components/ConditionSet.vue b/src/plugins/condition/components/ConditionSet.vue index ae7823b416..2cf3b25989 100644 --- a/src/plugins/condition/components/ConditionSet.vue +++ b/src/plugins/condition/components/ConditionSet.vue @@ -68,7 +68,7 @@ export default { } }, provideTelemetry() { - this.stopProvidingTelemetry = this.openmct.telemetry.subscribe(this.domainObject); + this.stopProvidingTelemetry = this.openmct.telemetry.subscribe(this.domainObject, (output) => output); } } }; From 9d5c7a4015fc3c4bdb9b0455658a4623cc2882f8 Mon Sep 17 00:00:00 2001 From: David Tsay Date: Wed, 26 Feb 2020 15:26:39 -0800 Subject: [PATCH 05/17] destroy conditionManager instance on stop providing telemetry --- src/plugins/condition/ConditionSetTelemetryProvider.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/condition/ConditionSetTelemetryProvider.js b/src/plugins/condition/ConditionSetTelemetryProvider.js index d75db13e11..cf721654ce 100644 --- a/src/plugins/condition/ConditionSetTelemetryProvider.js +++ b/src/plugins/condition/ConditionSetTelemetryProvider.js @@ -23,6 +23,7 @@ export default class ConditionSetTelemetryProvider { return function unsubscribe() { conditionManager.off('conditionSetResultUpdated'); + conditionManager.destroy(); } } } From 89ae6ef8c705adddcad19ed1c15f02a4b2509c62 Mon Sep 17 00:00:00 2001 From: David Tsay Date: Fri, 28 Feb 2020 11:15:19 -0800 Subject: [PATCH 06/17] provide telemetry with timestamps --- src/plugins/condition/Condition.js | 26 +++++++------------ src/plugins/condition/ConditionManager.js | 20 +++++++------- .../condition/components/ConditionSet.vue | 6 ++--- .../condition/criterion/TelemetryCriterion.js | 15 +++++++---- 4 files changed, 32 insertions(+), 35 deletions(-) diff --git a/src/plugins/condition/Condition.js b/src/plugins/condition/Condition.js index a102dff575..09723e47c6 100644 --- a/src/plugins/condition/Condition.js +++ b/src/plugins/condition/Condition.js @@ -58,7 +58,7 @@ export default class ConditionClass extends EventEmitter { this.id = this.openmct.objects.makeKeyString(conditionConfiguration.identifier); this.criteria = []; this.criteriaResults = {}; - this.result = null; + this.result = undefined; if (conditionConfiguration.configuration.criteria) { this.createCriteria(conditionConfiguration.configuration.criteria); } @@ -163,6 +163,7 @@ export default class ConditionClass extends EventEmitter { if (found) { let criterion = found.item; criterion.destroy(); + // TODO this is passing the wrong args criterion.off('criterionUpdated', (result) => { this.handleCriterionUpdated(id, result); }); @@ -180,6 +181,7 @@ export default class ConditionClass extends EventEmitter { if (found) { this.criteria[found.index] = criterion.data; this.subscribe(); + // TODO nothing is listening to this this.emitEvent('conditionUpdated', { trigger: this.trigger, criteria: this.criteria @@ -189,26 +191,22 @@ export default class ConditionClass extends EventEmitter { handleCriterionResult(eventData) { let id = eventData.id; - let result = eventData.data.result; - let found = this.findCriterion(id); - if (found) { - this.criteriaResults[id] = result; + if (this.findCriterion(id)) { + this.criteriaResults[id] = eventData.data.result; } - this.handleConditionUpdated(); + // change criterion result to be condition result as passed down the line + // hacky but trying not to make sweeping changes to current architecture + eventData.data.result = computeCondition(this.criteriaResults, this.trigger === TRIGGER.ALL); + this.emitEvent('conditionResultUpdated', eventData.data); } subscribe() { + // TODO it looks like on any single criterion update subscriptions fire for all criteria this.criteria.forEach((criterion) => { criterion.subscribe(); }) } - handleConditionUpdated() { - // trigger an updated event so that consumers can react accordingly - this.evaluate(); - this.emitEvent('conditionResultUpdated', {result: this.result}); - } - getCriteria() { return this.criteria; } @@ -222,10 +220,6 @@ export default class ConditionClass extends EventEmitter { return success; } - evaluate() { - this.result = computeCondition(this.criteriaResults, this.trigger === TRIGGER.ALL); - } - emitEvent(eventName, data) { this.emit(eventName, { id: this.id, diff --git a/src/plugins/condition/ConditionManager.js b/src/plugins/condition/ConditionManager.js index d86397d464..a6493230d8 100644 --- a/src/plugins/condition/ConditionManager.js +++ b/src/plugins/condition/ConditionManager.js @@ -207,31 +207,31 @@ export default class ConditionManager extends EventEmitter { handleConditionResult(resultObj) { let conditionCollection = this.domainObject.configuration.conditionCollection; + // set current condition to default condition let currentConditionIdentifier = conditionCollection[conditionCollection.length-1]; + let currentConditionResult = {}; if (resultObj) { let idAsString = this.openmct.objects.makeKeyString(resultObj.id); - let found = this.findConditionById(idAsString); - if (found) { - this.conditionResults[idAsString] = resultObj.data.result; + if (this.findConditionById(idAsString)) { + this.conditionResults[idAsString] = resultObj.data; } } - for (let i = 0, ii = conditionCollection.length - 1; i < ii; i++) { + for (let i = 0; i < conditionCollection.length - 1; i++) { let conditionIdAsString = this.openmct.objects.makeKeyString(conditionCollection[i]); - if (this.conditionResults[conditionIdAsString]) { + if (this.conditionResults[conditionIdAsString] && this.conditionResults[conditionIdAsString].result) { //first condition to be true wins currentConditionIdentifier = conditionCollection[i]; + currentConditionResult = this.conditionResults[conditionIdAsString]; break; } } this.openmct.objects.get(currentConditionIdentifier).then((obj) => { - this.emit('conditionSetResultUpdated', { - id: this.domainObject.identifier, - output: obj.configuration.output, - conditionId: currentConditionIdentifier - }) + this.emit('conditionSetResultUpdated', + Object.assign(currentConditionResult, {output: obj.configuration.output}) + ) }); } diff --git a/src/plugins/condition/components/ConditionSet.vue b/src/plugins/condition/components/ConditionSet.vue index 2cf3b25989..23a7ce01c4 100644 --- a/src/plugins/condition/components/ConditionSet.vue +++ b/src/plugins/condition/components/ConditionSet.vue @@ -63,12 +63,10 @@ export default { }, methods: { updateCurrentOutput(currentConditionResult) { - if (this.openmct.objects.makeKeyString(currentConditionResult.id) === this.conditionSetIdentifier) { - this.currentConditionOutput = currentConditionResult.output; - } + this.currentConditionOutput = currentConditionResult.output; }, provideTelemetry() { - this.stopProvidingTelemetry = this.openmct.telemetry.subscribe(this.domainObject, (output) => output); + this.stopProvidingTelemetry = this.openmct.telemetry.subscribe(this.domainObject, output => output); } } }; diff --git a/src/plugins/condition/criterion/TelemetryCriterion.js b/src/plugins/condition/criterion/TelemetryCriterion.js index a5201fc711..d0f76a060e 100644 --- a/src/plugins/condition/criterion/TelemetryCriterion.js +++ b/src/plugins/condition/criterion/TelemetryCriterion.js @@ -38,6 +38,7 @@ export default class TelemetryCriterion extends EventEmitter { this.openmct = openmct; this.objectAPI = this.openmct.objects; this.telemetryAPI = this.openmct.telemetry; + this.timeAPI = this.openmct.time; this.id = telemetryDomainObjectDefinition.id; this.telemetry = telemetryDomainObjectDefinition.telemetry; this.operation = telemetryDomainObjectDefinition.operation; @@ -55,11 +56,15 @@ export default class TelemetryCriterion extends EventEmitter { } handleSubscription(data) { - let result = this.computeResult(data); - this.emitEvent('criterionResultUpdated', { - result: result, - error: null - }) + const datum = {}; + const timeSystemKey = this.timeAPI.timeSystem().key; + + datum.result = this.computeResult(data); + if (data && data[timeSystemKey]) { + datum[timeSystemKey] = data[timeSystemKey] + } + + this.emitEvent('criterionResultUpdated', datum); } findOperation(operation) { From 14e3500a88b9d43e0b7695908fb357741582d437 Mon Sep 17 00:00:00 2001 From: David Tsay Date: Fri, 28 Feb 2020 12:27:51 -0800 Subject: [PATCH 07/17] add timestamps for default condition --- src/plugins/condition/ConditionManager.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/condition/ConditionManager.js b/src/plugins/condition/ConditionManager.js index a6493230d8..231ac6e6d2 100644 --- a/src/plugins/condition/ConditionManager.js +++ b/src/plugins/condition/ConditionManager.js @@ -20,6 +20,7 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ +import _ from 'lodash'; import Condition from "./Condition"; import uuid from "uuid"; import * as EventEmitter from 'eventemitter3'; @@ -29,6 +30,7 @@ export default class ConditionManager extends EventEmitter { super(); this.domainObject = domainObject; this.openmct = openmct; + this.timeAPI = this.openmct.time; this.instantiate = this.openmct.$injector.get('instantiate'); this.initialize(); } @@ -207,9 +209,9 @@ export default class ConditionManager extends EventEmitter { handleConditionResult(resultObj) { let conditionCollection = this.domainObject.configuration.conditionCollection; - // set current condition to default condition let currentConditionIdentifier = conditionCollection[conditionCollection.length-1]; - let currentConditionResult = {}; + // This sets timestamps for the default condition + let currentConditionResult = resultObj ? resultObj.data : {}; if (resultObj) { let idAsString = this.openmct.objects.makeKeyString(resultObj.id); From 3626ff994718b4ee3933fd7665ab004019608cb4 Mon Sep 17 00:00:00 2001 From: David Tsay Date: Fri, 28 Feb 2020 12:47:34 -0800 Subject: [PATCH 08/17] fix linting issues --- src/ui/inspector/Inspector.vue | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ui/inspector/Inspector.vue b/src/ui/inspector/Inspector.vue index ff3a8d36e5..78705bc48d 100644 --- a/src/ui/inspector/Inspector.vue +++ b/src/ui/inspector/Inspector.vue @@ -1,9 +1,9 @@ @@ -66,7 +64,8 @@ export default { this.currentConditionOutput = currentConditionResult.output; }, provideTelemetry() { - this.stopProvidingTelemetry = this.openmct.telemetry.subscribe(this.domainObject, output => output); + this.stopProvidingTelemetry = this.openmct.telemetry + .subscribe(this.domainObject, output => { this.updateCurrentOutput(output); }); } } }; From ecabd00b0c710b725f53ace559fb6a10d201d670 Mon Sep 17 00:00:00 2001 From: David Tsay Date: Mon, 2 Mar 2020 14:48:24 -0800 Subject: [PATCH 17/17] fix failing unit tests --- src/plugins/condition/criterion/TelemetryCriterionSpec.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/plugins/condition/criterion/TelemetryCriterionSpec.js b/src/plugins/condition/criterion/TelemetryCriterionSpec.js index 8c9cb67671..86ccbd6a68 100644 --- a/src/plugins/condition/criterion/TelemetryCriterionSpec.js +++ b/src/plugins/condition/criterion/TelemetryCriterionSpec.js @@ -62,6 +62,12 @@ describe("The telemetry criterion", function () { openmct.telemetry.subscribe.and.returnValue(function () {}); openmct.telemetry.getMetadata.and.returnValue(testTelemetryObject.telemetry.values); + openmct.time = jasmine.createSpyObj('timeAPI', + ['timeSystem', 'bounds'] + ); + openmct.time.timeSystem.and.returnValue({key: 'system'}); + openmct.time.bounds.and.returnValue({start: 0, end: 1}); + testCriterionDefinition = { id: 'test-criterion-id', telemetry: openmct.objects.makeKeyString(testTelemetryObject.identifier)