[Staleness] Fix staleness on clock change (#7088)

* Update staleness mixin
* Fix listeners and add guard
* Add check to make sure staleness only shows for correct clock
* Add guard for time api
* Cleanup the setting of isStale in ObjectView
* Cleanup use of combinedKey on LadTableSet
This commit is contained in:
Khalid Adil
2023-10-04 15:39:20 -05:00
committed by GitHub
parent 5eed5de3bb
commit 734a8dd592
18 changed files with 355 additions and 407 deletions

View File

@ -50,15 +50,14 @@
<script> <script>
import Vue, { toRaw } from 'vue'; import Vue, { toRaw } from 'vue';
import StalenessUtils from '@/utils/staleness';
import LadRow from './LadRow.vue'; import LadRow from './LadRow.vue';
import stalenessMixin from '@/ui/mixins/staleness-mixin';
export default { export default {
components: { components: {
LadRow LadRow
}, },
mixins: [stalenessMixin],
inject: ['openmct', 'currentView', 'ladTableConfiguration'], inject: ['openmct', 'currentView', 'ladTableConfiguration'],
props: { props: {
domainObject: { domainObject: {
@ -74,7 +73,6 @@ export default {
return { return {
items: [], items: [],
viewContext: {}, viewContext: {},
staleObjects: [],
configuration: this.ladTableConfiguration.getConfiguration() configuration: this.ladTableConfiguration.getConfiguration()
}; };
}, },
@ -96,11 +94,7 @@ export default {
return !this.configuration?.hiddenColumns?.type; return !this.configuration?.hiddenColumns?.type;
}, },
staleClass() { staleClass() {
if (this.staleObjects.length !== 0) { return this.isStale ? 'is-stale' : '';
return 'is-stale';
}
return '';
}, },
applyLayoutClass() { applyLayoutClass() {
if (this.configuration.isFixedLayout) { if (this.configuration.isFixedLayout) {
@ -133,12 +127,16 @@ export default {
this.composition.on('remove', this.removeItem); this.composition.on('remove', this.removeItem);
this.composition.on('reorder', this.reorder); this.composition.on('reorder', this.reorder);
this.composition.load(); this.composition.load();
this.stalenessSubscription = {};
await Vue.nextTick(); await Vue.nextTick();
this.viewActionsCollection = this.openmct.actions.getActionsCollection( this.viewActionsCollection = this.openmct.actions.getActionsCollection(
this.objectPath, this.objectPath,
this.currentView this.currentView
); );
this.setupClockChangedEvent((domainObject) => {
this.triggerUnsubscribeFromStaleness(domainObject);
this.subscribeToStaleness(domainObject);
});
this.initializeViewActions(); this.initializeViewActions();
}, },
unmounted() { unmounted() {
@ -147,11 +145,6 @@ export default {
this.composition.off('add', this.addItem); this.composition.off('add', this.addItem);
this.composition.off('remove', this.removeItem); this.composition.off('remove', this.removeItem);
this.composition.off('reorder', this.reorder); this.composition.off('reorder', this.reorder);
Object.values(this.stalenessSubscription).forEach((stalenessSubscription) => {
stalenessSubscription.unsubscribe();
stalenessSubscription.stalenessUtils.destroy();
});
}, },
methods: { methods: {
addItem(domainObject) { addItem(domainObject) {
@ -160,35 +153,16 @@ export default {
item.key = this.openmct.objects.makeKeyString(domainObject.identifier); item.key = this.openmct.objects.makeKeyString(domainObject.identifier);
this.items.push(item); this.items.push(item);
this.subscribeToStaleness(domainObject);
this.stalenessSubscription[item.key] = {};
this.stalenessSubscription[item.key].stalenessUtils = new StalenessUtils(
this.openmct,
domainObject
);
this.openmct.telemetry.isStale(domainObject).then((stalenessResponse) => {
if (stalenessResponse !== undefined) {
this.handleStaleness(item.key, stalenessResponse);
}
});
const stalenessSubscription = this.openmct.telemetry.subscribeToStaleness(
domainObject,
(stalenessResponse) => {
this.handleStaleness(item.key, stalenessResponse);
}
);
this.stalenessSubscription[item.key].unsubscribe = stalenessSubscription;
}, },
removeItem(identifier) { removeItem(identifier) {
const SKIP_CHECK = true;
const keystring = this.openmct.objects.makeKeyString(identifier); const keystring = this.openmct.objects.makeKeyString(identifier);
const index = this.items.findIndex((item) => keystring === item.key);
const index = this.items.findIndex((item) => keystring === item.key);
this.items.splice(index, 1); this.items.splice(index, 1);
this.stalenessSubscription[keystring].unsubscribe(); const domainObject = this.openmct.objects.get(keystring);
this.handleStaleness(keystring, { isStale: false }, SKIP_CHECK); this.triggerUnsubscribeFromStaleness(domainObject);
}, },
reorder(reorderPlan) { reorder(reorderPlan) {
const oldItems = this.items.slice(); const oldItems = this.items.slice();
@ -204,23 +178,6 @@ export default {
handleConfigurationChange(configuration) { handleConfigurationChange(configuration) {
this.configuration = configuration; this.configuration = configuration;
}, },
handleStaleness(id, stalenessResponse, skipCheck = false) {
if (
skipCheck ||
this.stalenessSubscription[id].stalenessUtils.shouldUpdateStaleness(stalenessResponse)
) {
const index = this.staleObjects.indexOf(id);
if (stalenessResponse.isStale) {
if (index === -1) {
this.staleObjects.push(id);
}
} else {
if (index !== -1) {
this.staleObjects.splice(index, 1);
}
}
}
},
updateViewContext(rowContext) { updateViewContext(rowContext) {
this.viewContext.row = rowContext; this.viewContext.row = rowContext;
}, },

View File

@ -45,9 +45,9 @@
:domain-object="ladRow.domainObject" :domain-object="ladRow.domainObject"
:path-to-table="ladTable.objectPath" :path-to-table="ladTable.objectPath"
:has-units="hasUnits" :has-units="hasUnits"
:is-stale="staleObjects.includes(combineKeys(ladTable.key, ladRow.key))" :is-stale="staleObjects.includes(ladRow.key)"
:configuration="configuration" :configuration="configuration"
@rowContextClick="updateViewContext" @row-context-click="updateViewContext"
/> />
</template> </template>
</tbody> </tbody>
@ -56,7 +56,9 @@
</template> </template>
<script> <script>
import StalenessUtils from '@/utils/staleness'; import { toRaw } from 'vue';
import stalenessMixin from '@/ui/mixins/staleness-mixin';
import LadRow from './LadRow.vue'; import LadRow from './LadRow.vue';
@ -64,6 +66,7 @@ export default {
components: { components: {
LadRow LadRow
}, },
mixins: [stalenessMixin],
inject: ['openmct', 'objectPath', 'currentView', 'ladTableConfiguration'], inject: ['openmct', 'objectPath', 'currentView', 'ladTableConfiguration'],
props: { props: {
domainObject: { domainObject: {
@ -76,8 +79,8 @@ export default {
ladTableObjects: [], ladTableObjects: [],
ladTelemetryObjects: {}, ladTelemetryObjects: {},
viewContext: {}, viewContext: {},
staleObjects: [], configuration: this.ladTableConfiguration.getConfiguration(),
configuration: this.ladTableConfiguration.getConfiguration() subscribedObjects: {}
}; };
}, },
computed: { computed: {
@ -108,11 +111,7 @@ export default {
return !this.configuration?.hiddenColumns?.type; return !this.configuration?.hiddenColumns?.type;
}, },
staleClass() { staleClass() {
if (this.staleObjects.length !== 0) { return this.isStale ? 'is-stale' : '';
return 'is-stale';
}
return '';
} }
}, },
created() { created() {
@ -125,8 +124,10 @@ export default {
this.composition.on('remove', this.removeLadTable); this.composition.on('remove', this.removeLadTable);
this.composition.on('reorder', this.reorderLadTables); this.composition.on('reorder', this.reorderLadTables);
this.composition.load(); this.composition.load();
this.setupClockChangedEvent((domainObject) => {
this.stalenessSubscription = {}; this.triggerUnsubscribeFromStaleness(domainObject);
this.subscribeToStaleness(domainObject);
});
}, },
unmounted() { unmounted() {
this.ladTableConfiguration.off('change', this.handleConfigurationChange); this.ladTableConfiguration.off('change', this.handleConfigurationChange);
@ -137,11 +138,6 @@ export default {
c.composition.off('add', c.addCallback); c.composition.off('add', c.addCallback);
c.composition.off('remove', c.removeCallback); c.composition.off('remove', c.removeCallback);
}); });
Object.values(this.stalenessSubscription).forEach((stalenessSubscription) => {
stalenessSubscription.unsubscribe();
stalenessSubscription.stalenessUtils.destroy();
});
}, },
methods: { methods: {
addLadTable(domainObject) { addLadTable(domainObject) {
@ -176,9 +172,18 @@ export default {
); );
let ladTable = this.ladTableObjects[index]; let ladTable = this.ladTableObjects[index];
this.ladTelemetryObjects[ladTable.key].forEach((telemetryObject) => { ladTable?.domainObject?.composition.forEach((telemetryObject) => {
let combinedKey = this.combineKeys(ladTable.key, telemetryObject.key); const telemetryKey = this.openmct.objects.makeKeyString(telemetryObject);
this.unwatchStaleness(combinedKey); if (!this.subscribedObjects?.[telemetryKey]) {
return;
}
let subscribedObject = toRaw(this.subscribedObjects[telemetryKey]);
if (subscribedObject?.count > 1) {
subscribedObject.count -= 1;
} else if (subscribedObject?.count === 1) {
this.triggerUnsubscribeFromStaleness(subscribedObject.domainObject);
delete this.subscribedObjects[telemetryKey];
}
}); });
delete this.ladTelemetryObjects[ladTable.key]; delete this.ladTelemetryObjects[ladTable.key];
@ -199,77 +204,35 @@ export default {
let telemetryObject = {}; let telemetryObject = {};
telemetryObject.key = this.openmct.objects.makeKeyString(domainObject.identifier); telemetryObject.key = this.openmct.objects.makeKeyString(domainObject.identifier);
telemetryObject.domainObject = domainObject; telemetryObject.domainObject = domainObject;
const combinedKey = this.combineKeys(ladTable.key, telemetryObject.key);
const telemetryObjects = this.ladTelemetryObjects[ladTable.key]; const telemetryObjects = this.ladTelemetryObjects[ladTable.key];
telemetryObjects.push(telemetryObject); telemetryObjects.push(telemetryObject);
this.ladTelemetryObjects[ladTable.key] = telemetryObjects; this.ladTelemetryObjects[ladTable.key] = telemetryObjects;
this.stalenessSubscription[combinedKey] = {}; if (!this.subscribedObjects[telemetryObject?.key]) {
this.stalenessSubscription[combinedKey].stalenessUtils = new StalenessUtils( this.subscribeToStaleness(domainObject);
this.openmct, this.subscribedObjects[telemetryObject?.key] = { count: 1, domainObject };
domainObject } else if (this.subscribedObjects?.[telemetryObject?.key]?.count) {
); this.subscribedObjects[telemetryObject?.key].count += 1;
this.openmct.telemetry.isStale(domainObject).then((stalenessResponse) => {
if (stalenessResponse !== undefined) {
this.handleStaleness(combinedKey, stalenessResponse);
} }
});
const stalenessSubscription = this.openmct.telemetry.subscribeToStaleness(
domainObject,
(stalenessResponse) => {
this.handleStaleness(combinedKey, stalenessResponse);
}
);
this.stalenessSubscription[combinedKey].unsubscribe = stalenessSubscription;
}; };
}, },
removeTelemetryObject(ladTable) { removeTelemetryObject(ladTable) {
return (identifier) => { return (identifier) => {
const keystring = this.openmct.objects.makeKeyString(identifier); const keystring = this.openmct.objects.makeKeyString(identifier);
const telemetryObjects = this.ladTelemetryObjects[ladTable.key]; const telemetryObjects = this.ladTelemetryObjects[ladTable.key];
const combinedKey = this.combineKeys(ladTable.key, keystring);
let index = telemetryObjects.findIndex( let index = telemetryObjects.findIndex(
(telemetryObject) => keystring === telemetryObject.key (telemetryObject) => keystring === telemetryObject.key
); );
this.unwatchStaleness(combinedKey);
telemetryObjects.splice(index, 1); telemetryObjects.splice(index, 1);
this.ladTelemetryObjects[ladTable.key] = telemetryObjects; this.ladTelemetryObjects[ladTable.key] = telemetryObjects;
}; };
}, },
unwatchStaleness(combinedKey) {
const SKIP_CHECK = true;
this.stalenessSubscription[combinedKey].unsubscribe();
this.stalenessSubscription[combinedKey].stalenessUtils.destroy();
this.handleStaleness(combinedKey, { isStale: false }, SKIP_CHECK);
delete this.stalenessSubscription[combinedKey];
},
handleConfigurationChange(configuration) { handleConfigurationChange(configuration) {
this.configuration = configuration; this.configuration = configuration;
}, },
handleStaleness(combinedKey, stalenessResponse, skipCheck = false) {
if (
skipCheck ||
this.stalenessSubscription[combinedKey].stalenessUtils.shouldUpdateStaleness(
stalenessResponse
)
) {
const index = this.staleObjects.indexOf(combinedKey);
const foundStaleObject = index > -1;
if (stalenessResponse.isStale && !foundStaleObject) {
this.staleObjects.push(combinedKey);
} else if (!stalenessResponse.isStale && foundStaleObject) {
this.staleObjects.splice(index, 1);
}
}
},
updateViewContext(rowContext) { updateViewContext(rowContext) {
this.viewContext.row = rowContext; this.viewContext.row = rowContext;
}, },

View File

@ -97,8 +97,10 @@ describe('The condition', function () {
mockTimeSystems = { mockTimeSystems = {
key: 'utc' key: 'utc'
}; };
openmct.time = jasmine.createSpyObj('time', ['getAllTimeSystems']); openmct.time = jasmine.createSpyObj('time', ['getAllTimeSystems', 'on', 'off']);
openmct.time.getAllTimeSystems.and.returnValue([mockTimeSystems]); openmct.time.getAllTimeSystems.and.returnValue([mockTimeSystems]);
openmct.time.on.and.returnValue(() => {});
openmct.time.off.and.returnValue(() => {});
testConditionDefinition = { testConditionDefinition = {
id: '123-456', id: '123-456',

View File

@ -79,15 +79,15 @@
</template> </template>
<script> <script>
import StalenessUtils from '@/utils/staleness';
import ConditionManager from '../ConditionManager'; import ConditionManager from '../ConditionManager';
import Condition from './Condition.vue'; import Condition from './Condition.vue';
import stalenessMixin from '@/ui/mixins/staleness-mixin';
export default { export default {
components: { components: {
Condition Condition
}, },
mixins: [stalenessMixin],
inject: ['openmct', 'domainObject'], inject: ['openmct', 'domainObject'],
props: { props: {
isEditing: Boolean, isEditing: Boolean,
@ -135,13 +135,6 @@ export default {
if (this.stopObservingForChanges) { if (this.stopObservingForChanges) {
this.stopObservingForChanges(); this.stopObservingForChanges();
} }
if (this.stalenessSubscription) {
Object.values(this.stalenessSubscription).forEach((stalenessSubscription) => {
stalenessSubscription.unsubscribe();
stalenessSubscription.stalenessUtils.destroy();
});
}
}, },
mounted() { mounted() {
this.composition = this.openmct.composition.get(this.domainObject); this.composition = this.openmct.composition.get(this.domainObject);
@ -153,7 +146,20 @@ export default {
this.conditionManager = new ConditionManager(this.domainObject, this.openmct); this.conditionManager = new ConditionManager(this.domainObject, this.openmct);
this.conditionManager.on('conditionSetResultUpdated', this.handleConditionSetResultUpdated); this.conditionManager.on('conditionSetResultUpdated', this.handleConditionSetResultUpdated);
this.conditionManager.on('noTelemetryObjects', this.emitNoTelemetryObjectEvent); this.conditionManager.on('noTelemetryObjects', this.emitNoTelemetryObjectEvent);
this.stalenessSubscription = {}; this.setupClockChangedEvent((domainObject) => {
this.triggerUnsubscribeFromStaleness(domainObject, () => {
this.emitStaleness({
keyString: domainObject.identifier,
stalenessResponse: { isStale: false }
});
});
this.subscribeToStaleness(domainObject, (stalenessResponse) => {
this.emitStaleness({
keyString: domainObject.identifier,
stalenessResponse: stalenessResponse
});
});
});
}, },
methods: { methods: {
handleConditionSetResultUpdated(data) { handleConditionSetResultUpdated(data) {
@ -221,28 +227,12 @@ export default {
this.telemetryObjs.push(domainObject); this.telemetryObjs.push(domainObject);
this.$emit('telemetryUpdated', this.telemetryObjs); this.$emit('telemetryUpdated', this.telemetryObjs);
if (!this.stalenessSubscription[keyString]) { this.subscribeToStaleness(domainObject, (stalenessResponse) => {
this.stalenessSubscription[keyString] = {}; this.emitStaleness({
} keyString,
stalenessResponse: stalenessResponse
this.stalenessSubscription[keyString].stalenessUtils = new StalenessUtils( });
this.openmct,
domainObject
);
this.openmct.telemetry.isStale(domainObject).then((stalenessResponse) => {
if (stalenessResponse !== undefined) {
this.handleStaleness(keyString, stalenessResponse);
}
}); });
const stalenessSubscription = this.openmct.telemetry.subscribeToStaleness(
domainObject,
(stalenessResponse) => {
this.handleStaleness(keyString, stalenessResponse);
}
);
this.stalenessSubscription[keyString].unsubscribe = stalenessSubscription;
}, },
removeTelemetryObject(identifier) { removeTelemetryObject(identifier) {
const keyString = this.openmct.objects.makeKeyString(identifier); const keyString = this.openmct.objects.makeKeyString(identifier);
@ -252,31 +242,17 @@ export default {
return objId === keyString; return objId === keyString;
}); });
const domainObject = this.telemetryObjs[index];
this.triggerUnsubscribeFromStaleness(domainObject, () => {
this.emitStaleness({
keyString,
stalenessResponse: { isStale: false }
});
});
if (index > -1) { if (index > -1) {
this.telemetryObjs.splice(index, 1); this.telemetryObjs.splice(index, 1);
} }
if (this.stalenessSubscription[keyString]) {
this.stalenessSubscription[keyString].unsubscribe();
this.stalenessSubscription[keyString].stalenessUtils.destroy();
this.emitStaleness({
keyString,
isStale: false
});
delete this.stalenessSubscription[keyString];
}
},
handleStaleness(keyString, stalenessResponse) {
if (
this.stalenessSubscription[keyString].stalenessUtils.shouldUpdateStaleness(
stalenessResponse
)
) {
this.emitStaleness({
keyString,
isStale: stalenessResponse.isStale
});
}
}, },
emitStaleness(stalenessObject) { emitStaleness(stalenessObject) {
this.$emit('telemetryStaleness', stalenessObject); this.$emit('telemetryStaleness', stalenessObject);

View File

@ -57,12 +57,14 @@
<script> <script>
import ConditionCollection from './ConditionCollection.vue'; import ConditionCollection from './ConditionCollection.vue';
import TestData from './TestData.vue'; import TestData from './TestData.vue';
import stalenessMixin from '@/ui/mixins/staleness-mixin';
export default { export default {
components: { components: {
TestData, TestData,
ConditionCollection ConditionCollection
}, },
mixins: [stalenessMixin],
inject: ['openmct', 'domainObject'], inject: ['openmct', 'domainObject'],
props: { props: {
isEditing: Boolean isEditing: Boolean
@ -71,15 +73,9 @@ export default {
return { return {
currentConditionOutput: '', currentConditionOutput: '',
telemetryObjs: [], telemetryObjs: [],
testData: {}, testData: {}
staleObjects: []
}; };
}, },
computed: {
isStale() {
return this.staleObjects.length !== 0;
}
},
mounted() { mounted() {
this.conditionSetIdentifier = this.openmct.objects.makeKeyString(this.domainObject.identifier); this.conditionSetIdentifier = this.openmct.objects.makeKeyString(this.domainObject.identifier);
this.testData = { this.testData = {
@ -100,17 +96,8 @@ export default {
updateTestData(testData) { updateTestData(testData) {
this.testData = testData; this.testData = testData;
}, },
handleStaleness({ keyString, isStale }) { handleStaleness({ keyString, stalenessResponse }) {
const index = this.staleObjects.indexOf(keyString); this.addOrRemoveStaleObject(keyString, stalenessResponse);
if (isStale) {
if (index === -1) {
this.staleObjects.push(keyString);
}
} else {
if (index !== -1) {
this.staleObjects.splice(index, 1);
}
}
} }
} }
}; };

View File

@ -52,6 +52,8 @@ export default class TelemetryCriterion extends EventEmitter {
this.initialize(); this.initialize();
this.emitEvent('criterionUpdated', this); this.emitEvent('criterionUpdated', this);
this.openmct.time.on('clockChanged', this.subscribeToStaleness);
} }
initialize() { initialize() {
@ -95,6 +97,10 @@ export default class TelemetryCriterion extends EventEmitter {
this.unsubscribeFromStaleness(); this.unsubscribeFromStaleness();
} }
if (!this.telemetryObject) {
return;
}
if (!this.stalenessUtils) { if (!this.stalenessUtils) {
this.stalenessUtils = new StalenessUtils(this.openmct, this.telemetryObject); this.stalenessUtils = new StalenessUtils(this.openmct, this.telemetryObject);
} }
@ -333,6 +339,8 @@ export default class TelemetryCriterion extends EventEmitter {
delete this.ageCheck; delete this.ageCheck;
} }
this.openmct.time.off('clockChanged', this.subscribeToStaleness);
if (this.stalenessUtils) { if (this.stalenessUtils) {
this.stalenessUtils.destroy(); this.stalenessUtils.destroy();
} }

View File

@ -88,7 +88,9 @@ describe('The telemetry criterion', function () {
'timeSystem', 'timeSystem',
'bounds', 'bounds',
'getAllTimeSystems', 'getAllTimeSystems',
'getContextForView' 'getContextForView',
'on',
'off'
]); ]);
openmct.time.timeSystem.and.returnValue({ key: 'system' }); openmct.time.timeSystem.and.returnValue({ key: 'system' });
openmct.time.bounds.and.returnValue({ openmct.time.bounds.and.returnValue({
@ -97,6 +99,8 @@ describe('The telemetry criterion', function () {
}); });
openmct.time.getAllTimeSystems.and.returnValue([{ key: 'system' }]); openmct.time.getAllTimeSystems.and.returnValue([{ key: 'system' }]);
openmct.time.getContextForView.and.returnValue({}); openmct.time.getContextForView.and.returnValue({});
openmct.time.on.and.returnValue(() => {});
openmct.time.off.and.returnValue(() => {});
testCriterionDefinition = { testCriterionDefinition = {
id: 'test-criterion-id', id: 'test-criterion-id',

View File

@ -240,6 +240,11 @@ export default {
this.status = this.openmct.status.get(this.item.identifier); this.status = this.openmct.status.get(this.item.identifier);
this.removeStatusListener = this.openmct.status.observe(this.item.identifier, this.setStatus); this.removeStatusListener = this.openmct.status.observe(this.item.identifier, this.setStatus);
this.setupClockChangedEvent((domainObject) => {
this.triggerUnsubscribeFromStaleness(domainObject);
this.subscribeToStaleness(domainObject);
});
}, },
beforeUnmount() { beforeUnmount() {
this.removeStatusListener(); this.removeStatusListener();

View File

@ -541,6 +541,11 @@ export default {
this.openmct.time.on('bounds', this.refreshData); this.openmct.time.on('bounds', this.refreshData);
this.openmct.time.on('timeSystem', this.setTimeSystem); this.openmct.time.on('timeSystem', this.setTimeSystem);
this.setupClockChangedEvent((domainObject) => {
this.triggerUnsubscribeFromStaleness(domainObject);
this.subscribeToStaleness(domainObject);
});
}, },
unmounted() { unmounted() {
this.composition.off('add', this.addedToComposition); this.composition.off('add', this.addedToComposition);
@ -620,7 +625,7 @@ export default {
this.unsubscribe = null; this.unsubscribe = null;
} }
this.triggerUnsubscribeFromStaleness(); this.triggerUnsubscribeFromStaleness(this.domainObject);
this.curVal = DEFAULT_CURRENT_VALUE; this.curVal = DEFAULT_CURRENT_VALUE;
this.formats = null; this.formats = null;

View File

@ -62,13 +62,12 @@
</template> </template>
<script> <script>
import StalenessUtils from '@/utils/staleness';
import ImageExporter from '../../exporters/ImageExporter'; import ImageExporter from '../../exporters/ImageExporter';
import ProgressBar from '../../ui/components/ProgressBar.vue'; import ProgressBar from '../../ui/components/ProgressBar.vue';
import PlotLegend from './legend/PlotLegend.vue'; import PlotLegend from './legend/PlotLegend.vue';
import eventHelpers from './lib/eventHelpers'; import eventHelpers from './lib/eventHelpers';
import MctPlot from './MctPlot.vue'; import MctPlot from './MctPlot.vue';
import stalenessMixin from '@/ui/mixins/staleness-mixin';
export default { export default {
components: { components: {
@ -76,6 +75,7 @@ export default {
ProgressBar, ProgressBar,
PlotLegend PlotLegend
}, },
mixins: [stalenessMixin],
inject: ['openmct', 'domainObject', 'path'], inject: ['openmct', 'domainObject', 'path'],
props: { props: {
options: { options: {
@ -131,7 +131,6 @@ export default {
return { return {
loading: false, loading: false,
status: '', status: '',
staleObjects: [],
limitLineLabels: undefined, limitLineLabels: undefined,
lockHighlightPoint: false, lockHighlightPoint: false,
highlights: [], highlights: [],
@ -148,11 +147,7 @@ export default {
return this.gridLines ?? !this.options.compact; return this.gridLines ?? !this.options.compact;
}, },
staleClass() { staleClass() {
if (this.staleObjects.length !== 0) { return this.isStale ? 'is-stale' : '';
return 'is-stale';
}
return '';
}, },
plotLegendPositionClass() { plotLegendPositionClass() {
return this.position ? `plot-legend-${this.position}` : ''; return this.position ? `plot-legend-${this.position}` : '';
@ -176,8 +171,11 @@ export default {
created() { created() {
eventHelpers.extend(this); eventHelpers.extend(this);
this.imageExporter = new ImageExporter(this.openmct); this.imageExporter = new ImageExporter(this.openmct);
this.stalenessSubscription = {};
this.loadComposition(); this.loadComposition();
this.setupClockChangedEvent((domainObject) => {
this.triggerUnsubscribeFromStaleness(domainObject);
this.subscribeToStaleness(domainObject);
});
}, },
unmounted() { unmounted() {
this.destroy(); this.destroy();
@ -187,76 +185,19 @@ export default {
this.compositionCollection = this.openmct.composition.get(this.domainObject); this.compositionCollection = this.openmct.composition.get(this.domainObject);
if (this.compositionCollection) { if (this.compositionCollection) {
this.compositionCollection.on('add', this.addItem); this.compositionCollection.on('add', this.subscribeToStaleness);
this.compositionCollection.on('remove', this.removeItem); this.compositionCollection.on('remove', this.triggerUnsubscribeFromStaleness);
this.compositionCollection.load(); this.compositionCollection.load();
} }
}, },
addItem(object) {
const keystring = this.openmct.objects.makeKeyString(object.identifier);
if (!this.stalenessSubscription[keystring]) {
this.stalenessSubscription[keystring] = {};
this.stalenessSubscription[keystring].stalenessUtils = new StalenessUtils(
this.openmct,
object
);
}
this.openmct.telemetry.isStale(object).then((stalenessResponse) => {
if (stalenessResponse !== undefined) {
this.handleStaleness(keystring, stalenessResponse);
}
});
const unsubscribeFromStaleness = this.openmct.telemetry.subscribeToStaleness(
object,
(stalenessResponse) => {
this.handleStaleness(keystring, stalenessResponse);
}
);
this.stalenessSubscription[keystring].unsubscribe = unsubscribeFromStaleness;
},
removeItem(object) {
const SKIP_CHECK = true;
const keystring = this.openmct.objects.makeKeyString(object);
this.stalenessSubscription[keystring].unsubscribe();
this.stalenessSubscription[keystring].stalenessUtils.destroy();
this.handleStaleness(keystring, { isStale: false }, SKIP_CHECK);
delete this.stalenessSubscription[keystring];
},
handleStaleness(id, stalenessResponse, skipCheck = false) {
if (
skipCheck ||
this.stalenessSubscription[id].stalenessUtils.shouldUpdateStaleness(stalenessResponse, id)
) {
const index = this.staleObjects.indexOf(id);
if (stalenessResponse.isStale) {
if (index === -1) {
this.staleObjects.push(id);
}
} else {
if (index !== -1) {
this.staleObjects.splice(index, 1);
}
}
}
},
loadingUpdated(loading) { loadingUpdated(loading) {
this.loading = loading; this.loading = loading;
this.$emit('loadingUpdated', ...arguments); this.$emit('loadingUpdated', ...arguments);
}, },
destroy() { destroy() {
if (this.stalenessSubscription) {
Object.values(this.stalenessSubscription).forEach((stalenessSubscription) => {
stalenessSubscription.unsubscribe();
stalenessSubscription.stalenessUtils.destroy();
});
}
if (this.compositionCollection) { if (this.compositionCollection) {
this.compositionCollection.off('add', this.addItem); this.compositionCollection.off('add', this.subscribeToStaleness);
this.compositionCollection.off('remove', this.removeItem); this.compositionCollection.off('remove', this.triggerUnsubscribeFromStaleness);
} }
this.imageExporter = null; this.imageExporter = null;

View File

@ -127,6 +127,10 @@ export default {
this.config.series.forEach(this.onSeriesAdd, this); this.config.series.forEach(this.onSeriesAdd, this);
this.legend = this.config.legend; this.legend = this.config.legend;
this.loaded = true; this.loaded = true;
this.setupClockChangedEvent((domainObject) => {
this.triggerUnsubscribeFromStaleness(domainObject);
this.subscribeToStaleness(domainObject);
});
}, },
beforeUnmount() { beforeUnmount() {
this.stopListening(); this.stopListening();

View File

@ -150,6 +150,10 @@ export default {
this.config.series.forEach(this.onSeriesAdd, this); this.config.series.forEach(this.onSeriesAdd, this);
this.legend = this.config.legend; this.legend = this.config.legend;
this.loaded = true; this.loaded = true;
this.setupClockChangedEvent((domainObject) => {
this.triggerUnsubscribeFromStaleness(domainObject);
this.subscribeToStaleness(domainObject);
});
}, },
beforeUnmount() { beforeUnmount() {
this.stopListening(); this.stopListening();

View File

@ -28,7 +28,6 @@ import mount from 'utils/mount';
import configStore from '@/plugins/plot/configuration/ConfigStore'; import configStore from '@/plugins/plot/configuration/ConfigStore';
import PlotConfigurationModel from '@/plugins/plot/configuration/PlotConfigurationModel'; import PlotConfigurationModel from '@/plugins/plot/configuration/PlotConfigurationModel';
import stalenessMixin from '@/ui/mixins/staleness-mixin'; import stalenessMixin from '@/ui/mixins/staleness-mixin';
import StalenessUtils from '@/utils/staleness';
import Plot from '../Plot.vue'; import Plot from '../Plot.vue';
import conditionalStylesMixin from './mixins/objectStyles-mixin'; import conditionalStylesMixin from './mixins/objectStyles-mixin';
@ -90,11 +89,6 @@ export default {
} }
} }
}, },
data() {
return {
staleObjects: []
};
},
watch: { watch: {
gridLines(newGridLines) { gridLines(newGridLines) {
this.updateComponentProp('gridLines', newGridLines); this.updateComponentProp('gridLines', newGridLines);
@ -116,20 +110,26 @@ export default {
}, },
staleObjects: { staleObjects: {
handler() { handler() {
this.isStale = this.staleObjects.length > 0;
this.updateComponentProp('isStale', this.isStale); this.updateComponentProp('isStale', this.isStale);
}, },
deep: true deep: true
} }
}, },
mounted() { mounted() {
this.stalenessSubscription = {};
this.updateView(); this.updateView();
this.isEditing = this.openmct.editor.isEditing(); this.isEditing = this.openmct.editor.isEditing();
this.openmct.editor.on('isEditing', this.setEditState); this.openmct.editor.on('isEditing', this.setEditState);
this.setupClockChangedEvent((domainObject) => {
this.triggerUnsubscribeFromStaleness(domainObject);
this.subscribeToStaleness(domainObject);
});
}, },
beforeUnmount() { beforeUnmount() {
this.openmct.editor.off('isEditing', this.setEditState); this.openmct.editor.off('isEditing', this.setEditState);
if (this.composition) {
this.composition.off('add', this.subscribeToStaleness);
this.composition.off('remove', this.triggerUnsubscribeFromStaleness);
}
if (this.removeSelectable) { if (this.removeSelectable) {
this.removeSelectable(); this.removeSelectable();
@ -141,8 +141,6 @@ export default {
if (this._destroy) { if (this._destroy) {
this._destroy(); this._destroy();
} }
this.destroyStalenessListeners();
}, },
methods: { methods: {
setEditState(isEditing) { setEditState(isEditing) {
@ -163,10 +161,6 @@ export default {
} }
}, },
updateView() { updateView() {
this.isStale = false;
this.destroyStalenessListeners();
if (this._destroy) { if (this._destroy) {
this._destroy(); this._destroy();
this.component = null; this.component = null;
@ -190,15 +184,15 @@ export default {
const isMissing = openmct.objects.isMissing(object); const isMissing = openmct.objects.isMissing(object);
if (this.openmct.telemetry.isTelemetryObject(object)) { if (this.openmct.telemetry.isTelemetryObject(object)) {
this.subscribeToStaleness(object, (isStale) => { this.subscribeToStaleness(object, (stalenessResponse) => {
this.updateComponentProp('isStale', isStale); this.updateComponentProp('isStale', stalenessResponse.isStale);
}); });
} else { } else {
// possibly overlay or other composition based plot // possibly overlay or other composition based plot
this.composition = this.openmct.composition.get(object); this.composition = this.openmct.composition.get(object);
this.composition.on('add', this.watchStaleness); this.composition.on('add', this.subscribeToStaleness);
this.composition.on('remove', this.unwatchStaleness); this.composition.on('remove', this.triggerUnsubscribeFromStaleness);
this.composition.load(); this.composition.load();
} }
@ -260,54 +254,6 @@ export default {
this.setSelection(); this.setSelection();
} }
}, },
watchStaleness(domainObject) {
const keyString = this.openmct.objects.makeKeyString(domainObject.identifier);
this.stalenessSubscription[keyString] = {};
this.stalenessSubscription[keyString].stalenessUtils = new StalenessUtils(
this.openmct,
domainObject
);
this.openmct.telemetry.isStale(domainObject).then((stalenessResponse) => {
if (stalenessResponse !== undefined) {
this.handleStaleness(keyString, stalenessResponse);
}
});
const stalenessSubscription = this.openmct.telemetry.subscribeToStaleness(
domainObject,
(stalenessResponse) => {
this.handleStaleness(keyString, stalenessResponse);
}
);
this.stalenessSubscription[keyString].unsubscribe = stalenessSubscription;
},
unwatchStaleness(domainObject) {
const SKIP_CHECK = true;
const keyString = this.openmct.objects.makeKeyString(domainObject.identifier);
this.stalenessSubscription[keyString].unsubscribe();
this.stalenessSubscription[keyString].stalenessUtils.destroy();
this.handleStaleness(keyString, { isStale: false }, SKIP_CHECK);
delete this.stalenessSubscription[keyString];
},
handleStaleness(keyString, stalenessResponse, skipCheck = false) {
if (
skipCheck ||
this.stalenessSubscription[keyString].stalenessUtils.shouldUpdateStaleness(
stalenessResponse
)
) {
const index = this.staleObjects.indexOf(keyString);
const foundStaleObject = index > -1;
if (stalenessResponse.isStale && !foundStaleObject) {
this.staleObjects.push(keyString);
} else if (!stalenessResponse.isStale && foundStaleObject) {
this.staleObjects.splice(index, 1);
}
}
},
onLockHighlightPointUpdated() { onLockHighlightPointUpdated() {
this.$emit('lockHighlightPoint', ...arguments); this.$emit('lockHighlightPoint', ...arguments);
}, },
@ -405,20 +351,6 @@ export default {
return this.childObject; return this.childObject;
} }
},
destroyStalenessListeners() {
this.triggerUnsubscribeFromStaleness();
if (this.composition) {
this.composition.off('add', this.watchStaleness);
this.composition.off('remove', this.unwatchStaleness);
this.composition = null;
}
Object.values(this.stalenessSubscription).forEach((stalenessSubscription) => {
stalenessSubscription.unsubscribe();
stalenessSubscription.stalenessUtils.destroy();
});
} }
} }
}; };

View File

@ -55,6 +55,7 @@ define([
this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier); this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
this.telemetryObjects = {}; this.telemetryObjects = {};
this.subscribedStaleObjects = new Map();
this.telemetryCollections = {}; this.telemetryCollections = {};
this.delayedActions = []; this.delayedActions = [];
this.outstandingRequests = 0; this.outstandingRequests = 0;
@ -74,6 +75,8 @@ define([
this.filterObserver = undefined; this.filterObserver = undefined;
this.createTableRowCollections(); this.createTableRowCollections();
this.resubscribeToStaleness = this.resubscribeAllObjectsToStaleness.bind(this);
this.openmct.time.on('clockChanged', this.resubscribeToStaleness);
} }
/** /**
@ -163,24 +166,7 @@ define([
this.telemetryCollections[keyString].on('clear', this.clearData); this.telemetryCollections[keyString].on('clear', this.clearData);
this.telemetryCollections[keyString].load(); this.telemetryCollections[keyString].load();
this.stalenessSubscription[keyString] = {}; this.subscribeToStaleness(telemetryObject);
this.stalenessSubscription[keyString].stalenessUtils = new StalenessUtils.default(
this.openmct,
telemetryObject
);
this.openmct.telemetry.isStale(telemetryObject).then((stalenessResponse) => {
if (stalenessResponse !== undefined) {
this.handleStaleness(keyString, stalenessResponse);
}
});
const stalenessSubscription = this.openmct.telemetry.subscribeToStaleness(
telemetryObject,
(stalenessResponse) => {
this.handleStaleness(keyString, stalenessResponse);
}
);
this.stalenessSubscription[keyString].unsubscribe = stalenessSubscription;
this.telemetryObjects[keyString] = { this.telemetryObjects[keyString] = {
telemetryObject, telemetryObject,
@ -193,6 +179,42 @@ define([
this.emit('object-added', telemetryObject); this.emit('object-added', telemetryObject);
} }
resubscribeAllObjectsToStaleness() {
if (!this.subscribedStaleObjects || this.subscribedStaleObjects.size < 1) {
return;
}
for (const [, telemetryObject] of this.subscribedStaleObjects) {
this.subscribeToStaleness(telemetryObject);
}
}
subscribeToStaleness(domainObject) {
const keyString = this.openmct.objects.makeKeyString(domainObject.identifier);
if (this.stalenessSubscription?.[keyString]) {
this.unsubscribeFromStaleness(domainObject.identifier);
}
this.stalenessSubscription[keyString] = {};
this.stalenessSubscription[keyString].stalenessUtils = new StalenessUtils.default(
this.openmct,
domainObject
);
this.openmct.telemetry.isStale(domainObject).then((stalenessResponse) => {
if (stalenessResponse !== undefined) {
this.handleStaleness(keyString, stalenessResponse);
}
});
const stalenessSubscription = this.openmct.telemetry.subscribeToStaleness(
domainObject,
(stalenessResponse) => {
this.handleStaleness(keyString, stalenessResponse);
}
);
this.subscribedStaleObjects.set(keyString, domainObject);
this.stalenessSubscription[keyString].unsubscribe = stalenessSubscription;
}
handleStaleness(keyString, stalenessResponse, skipCheck = false) { handleStaleness(keyString, stalenessResponse, skipCheck = false) {
if ( if (
skipCheck || skipCheck ||
@ -203,7 +225,7 @@ define([
) { ) {
this.emit('telemetry-staleness', { this.emit('telemetry-staleness', {
keyString, keyString,
isStale: stalenessResponse.isStale stalenessResponse: stalenessResponse
}); });
} }
} }
@ -310,7 +332,6 @@ define([
removeTelemetryObject(objectIdentifier) { removeTelemetryObject(objectIdentifier) {
const keyString = this.openmct.objects.makeKeyString(objectIdentifier); const keyString = this.openmct.objects.makeKeyString(objectIdentifier);
const SKIP_CHECK = true;
this.configuration.removeColumnsForObject(objectIdentifier, true); this.configuration.removeColumnsForObject(objectIdentifier, true);
this.tableRows.removeRowsByObject(keyString); this.tableRows.removeRowsByObject(keyString);
@ -320,6 +341,13 @@ define([
this.emit('object-removed', objectIdentifier); this.emit('object-removed', objectIdentifier);
this.unsubscribeFromStaleness(objectIdentifier);
}
unsubscribeFromStaleness(objectIdentifier) {
const keyString = this.openmct.objects.makeKeyString(objectIdentifier);
const SKIP_CHECK = true;
this.stalenessSubscription[keyString].unsubscribe(); this.stalenessSubscription[keyString].unsubscribe();
this.stalenessSubscription[keyString].stalenessUtils.destroy(); this.stalenessSubscription[keyString].stalenessUtils.destroy();
this.handleStaleness(keyString, { isStale: false }, SKIP_CHECK); this.handleStaleness(keyString, { isStale: false }, SKIP_CHECK);
@ -423,6 +451,7 @@ define([
this.tableRows.destroy(); this.tableRows.destroy();
this.tableRows.off('resetRowsFromAllData', this.resetRowsFromAllData); this.tableRows.off('resetRowsFromAllData', this.resetRowsFromAllData);
this.openmct.time.off('clockChanged', this.resubscribeToStaleness);
let keystrings = Object.keys(this.telemetryCollections); let keystrings = Object.keys(this.telemetryCollections);
keystrings.forEach(this.removeTelemetryCollection); keystrings.forEach(this.removeTelemetryCollection);

View File

@ -275,6 +275,7 @@
<script> <script>
import _ from 'lodash'; import _ from 'lodash';
import { toRaw } from 'vue'; import { toRaw } from 'vue';
import stalenessMixin from '@/ui/mixins/staleness-mixin';
import CSVExporter from '../../../exporters/CSVExporter.js'; import CSVExporter from '../../../exporters/CSVExporter.js';
import ProgressBar from '../../../ui/components/ProgressBar.vue'; import ProgressBar from '../../../ui/components/ProgressBar.vue';
@ -300,6 +301,7 @@ export default {
SizingRow, SizingRow,
ProgressBar ProgressBar
}, },
mixins: [stalenessMixin],
inject: ['openmct', 'objectPath', 'table', 'currentView'], inject: ['openmct', 'objectPath', 'table', 'currentView'],
props: { props: {
isEditing: { isEditing: {
@ -370,8 +372,7 @@ export default {
enableRegexSearch: {}, enableRegexSearch: {},
hideHeaders: configuration.hideHeaders, hideHeaders: configuration.hideHeaders,
totalNumberOfRows: 0, totalNumberOfRows: 0,
rowContext: {}, rowContext: {}
staleObjects: []
}; };
}, },
computed: { computed: {
@ -414,7 +415,7 @@ export default {
classes.push('is-paused'); classes.push('is-paused');
} }
if (this.staleObjects.length !== 0) { if (this.isStale) {
classes.push('is-stale'); classes.push('is-stale');
} }
@ -745,17 +746,8 @@ export default {
outstandingRequests(loading) { outstandingRequests(loading) {
this.loading = loading; this.loading = loading;
}, },
handleStaleness({ keyString, isStale }) { handleStaleness({ keyString, stalenessResponse }) {
const index = this.staleObjects.indexOf(keyString); this.addOrRemoveStaleObject(keyString, stalenessResponse);
if (isStale) {
if (index === -1) {
this.staleObjects.push(keyString);
}
} else {
if (index !== -1) {
this.staleObjects.splice(index, 1);
}
}
}, },
calculateTableSize() { calculateTableSize() {
this.$nextTick().then(this.calculateColumnWidths); this.$nextTick().then(this.calculateColumnWidths);

View File

@ -172,8 +172,7 @@ export default {
this.composition._destroy(); this.composition._destroy();
} }
this.isStale = false; this.triggerUnsubscribeFromStaleness(this.domainObject);
this.triggerUnsubscribeFromStaleness();
this.openmct.objectViews.off('clearData', this.clearData); this.openmct.objectViews.off('clearData', this.clearData);
this.openmct.objectViews.off('contextAction', this.performContextAction); this.openmct.objectViews.off('contextAction', this.performContextAction);

View File

@ -20,52 +20,190 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
import { isProxy, toRaw } from 'vue';
import StalenessUtils from '@/utils/staleness'; import StalenessUtils from '@/utils/staleness';
export default { export default {
data() { data() {
return { return {
isStale: false staleObjects: [],
stalenessSubscription: {},
compositionObjectMap: new Map(),
setupClockChanged: false
}; };
}, },
beforeUnmount() { computed: {
this.triggerUnsubscribeFromStaleness(); isStale() {
return this.staleObjects.length !== 0;
}
}, },
methods: { methods: {
subscribeToStaleness(domainObject, callback) { getSubscriptionId(domainObject) {
if (!this.stalenessUtils) { return this.openmct?.objects.makeKeyString(domainObject.identifier);
this.stalenessUtils = new StalenessUtils(this.openmct, domainObject); },
setupClockChangedEvent(callback) {
this.setupClockChanged = true;
this.compositionIteratorCallback = this.compositionIterator(callback);
this.openmct.time.on('clockChanged', this.compositionIteratorCallback);
},
addToCompositionMap(id, domainObject) {
if (!this.compositionObjectMap.get(id)) {
this.compositionObjectMap.set(id, domainObject);
}
},
compositionIterator(callback) {
return () => {
this.staleObjects = [];
for (const [, object] of this.compositionObjectMap) {
let domainObject = object;
if (isProxy(domainObject)) {
domainObject = toRaw(object);
}
if (callback && typeof callback === 'function') {
callback(domainObject);
}
}
};
},
subscribeToStaleness(domainObjectList, callback) {
if (domainObjectList === null || domainObjectList === undefined) {
return;
}
if (!Array.isArray(domainObjectList)) {
domainObjectList = [domainObjectList];
} }
this.requestStaleness(domainObject); domainObjectList.forEach((domainObject) => {
this.unsubscribeFromStaleness = this.openmct.telemetry.subscribeToStaleness( if (isProxy(domainObject)) {
domainObject = toRaw(domainObject);
}
const id = this.getSubscriptionId(domainObject);
this.addToCompositionMap(id, domainObject);
this.setupStalenessUtils(domainObject);
this.requestStaleness(domainObject, callback);
this.setupStalenessSubscription(domainObject, callback);
});
},
triggerUnsubscribeFromStaleness(domainObjectList, callback) {
if (domainObjectList === null || domainObjectList === undefined) {
return;
}
if (!Array.isArray(domainObjectList)) {
domainObjectList = [domainObjectList];
}
domainObjectList.forEach((domainObject) => {
if (isProxy(domainObject)) {
domainObject = toRaw(domainObject);
}
const id = this.getSubscriptionId(domainObject);
if (!this.stalenessSubscription[id]) {
return;
}
if (this.staleObjects.length !== 0) {
const SKIP_CHECK = true;
this.handleStalenessResponse(id, { isStale: false }, SKIP_CHECK);
}
this.teardownStalenessSubscription(domainObject);
this.teardownStalenessUtils(domainObject);
delete this.stalenessSubscription[id];
});
if (callback && typeof callback === 'function') {
callback();
}
},
setupStalenessUtils(domainObject) {
const id = this.getSubscriptionId(domainObject);
if (this.stalenessSubscription[id]) {
return;
}
this.stalenessSubscription[id] = {};
this.stalenessSubscription[id].stalenessUtils = new StalenessUtils(
this.openmct,
domainObject
);
},
teardownStalenessUtils(domainObject) {
const id = this.getSubscriptionId(domainObject);
const { stalenessUtils } = this.stalenessSubscription[id];
if (stalenessUtils) {
stalenessUtils.destroy();
delete this.stalenessSubscription[id].stalenessUtils;
}
},
setupStalenessSubscription(domainObject, callback) {
const id = this.getSubscriptionId(domainObject);
this.stalenessSubscription[id].unsubscribe = this.openmct.telemetry.subscribeToStaleness(
domainObject, domainObject,
(stalenessResponse) => { (stalenessResponse) => {
this.handleStalenessResponse(stalenessResponse, callback); const SKIP_CHECK = false;
this.handleStalenessResponse(id, stalenessResponse, SKIP_CHECK, callback);
} }
); );
}, },
async requestStaleness(domainObject) { teardownStalenessSubscription(domainObject) {
const id = this.getSubscriptionId(domainObject);
const { unsubscribe } = this.stalenessSubscription[id];
if (unsubscribe) {
unsubscribe();
delete this.stalenessSubscription[id].unsubscribe;
}
},
resubscribeToStaleness(domainObject, callback, unsubscribeCallback) {
const id = this.getSubscriptionId(domainObject);
this.stalenessSubscription[id].resubscribe = () => {
this.staleObjects = [];
this.triggerUnsubscribeFromStaleness(domainObject, unsubscribeCallback);
this.setupStalenessSubscription(domainObject, callback);
};
},
async requestStaleness(domainObject, callback) {
const id = this.getSubscriptionId(domainObject);
const stalenessResponse = await this.openmct.telemetry.isStale(domainObject); const stalenessResponse = await this.openmct.telemetry.isStale(domainObject);
if (stalenessResponse !== undefined) { if (stalenessResponse !== undefined) {
this.handleStalenessResponse(stalenessResponse); const SKIP_CHECK = false;
this.handleStalenessResponse(id, stalenessResponse, SKIP_CHECK, callback);
} }
}, },
handleStalenessResponse(stalenessResponse, callback) { handleStalenessResponse(id, stalenessResponse, skipCheck, callback) {
if (this.stalenessUtils.shouldUpdateStaleness(stalenessResponse)) { if (!id) {
if (typeof callback === 'function') { id = Object.keys(this.stalenessSubscription)[0];
callback(stalenessResponse.isStale); }
const shouldUpdateStaleness =
this.stalenessSubscription[id].stalenessUtils.shouldUpdateStaleness(stalenessResponse);
if (skipCheck || shouldUpdateStaleness) {
if (callback && typeof callback === 'function') {
callback(stalenessResponse);
} else { } else {
this.isStale = stalenessResponse.isStale; this.addOrRemoveStaleObject(id, stalenessResponse);
} }
} }
}, },
triggerUnsubscribeFromStaleness() { addOrRemoveStaleObject(id, stalenessResponse) {
if (this.unsubscribeFromStaleness) { const index = this.staleObjects.indexOf(id);
this.unsubscribeFromStaleness(); if (stalenessResponse.isStale) {
delete this.unsubscribeFromStaleness; if (index === -1) {
this.stalenessUtils.destroy(); this.staleObjects.push(id);
} }
} else {
if (index !== -1) {
this.staleObjects.splice(index, 1);
}
}
}
},
unmounted() {
let compositionObjects = [];
for (const [, object] of this.compositionObjectMap) {
compositionObjects.push(object);
}
this.triggerUnsubscribeFromStaleness(compositionObjects);
if (this.setupClockChanged) {
this.openmct.time.off('clockChanged', this.compositionIteratorCallback);
this.setupClockChanged = false;
} }
} }
}; };

View File

@ -33,8 +33,10 @@ export default class StalenessUtils {
shouldUpdateStaleness(stalenessResponse, id) { shouldUpdateStaleness(stalenessResponse, id) {
const stalenessResponseTime = this.parseTime(stalenessResponse); const stalenessResponseTime = this.parseTime(stalenessResponse);
const { start } = this.openmct.time.bounds();
const isStalenessInCurrentClock = stalenessResponseTime > start;
if (stalenessResponseTime > this.lastStalenessResponseTime) { if (stalenessResponseTime > this.lastStalenessResponseTime && isStalenessInCurrentClock) {
this.lastStalenessResponseTime = stalenessResponseTime; this.lastStalenessResponseTime = stalenessResponseTime;
return true; return true;