[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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 355 additions and 407 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -28,7 +28,6 @@ import mount from 'utils/mount';
import configStore from '@/plugins/plot/configuration/ConfigStore';
import PlotConfigurationModel from '@/plugins/plot/configuration/PlotConfigurationModel';
import stalenessMixin from '@/ui/mixins/staleness-mixin';
import StalenessUtils from '@/utils/staleness';
import Plot from '../Plot.vue';
import conditionalStylesMixin from './mixins/objectStyles-mixin';
@ -90,11 +89,6 @@ export default {
}
}
},
data() {
return {
staleObjects: []
};
},
watch: {
gridLines(newGridLines) {
this.updateComponentProp('gridLines', newGridLines);
@ -116,20 +110,26 @@ export default {
},
staleObjects: {
handler() {
this.isStale = this.staleObjects.length > 0;
this.updateComponentProp('isStale', this.isStale);
},
deep: true
}
},
mounted() {
this.stalenessSubscription = {};
this.updateView();
this.isEditing = this.openmct.editor.isEditing();
this.openmct.editor.on('isEditing', this.setEditState);
this.setupClockChangedEvent((domainObject) => {
this.triggerUnsubscribeFromStaleness(domainObject);
this.subscribeToStaleness(domainObject);
});
},
beforeUnmount() {
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) {
this.removeSelectable();
@ -141,8 +141,6 @@ export default {
if (this._destroy) {
this._destroy();
}
this.destroyStalenessListeners();
},
methods: {
setEditState(isEditing) {
@ -163,10 +161,6 @@ export default {
}
},
updateView() {
this.isStale = false;
this.destroyStalenessListeners();
if (this._destroy) {
this._destroy();
this.component = null;
@ -190,15 +184,15 @@ export default {
const isMissing = openmct.objects.isMissing(object);
if (this.openmct.telemetry.isTelemetryObject(object)) {
this.subscribeToStaleness(object, (isStale) => {
this.updateComponentProp('isStale', isStale);
this.subscribeToStaleness(object, (stalenessResponse) => {
this.updateComponentProp('isStale', stalenessResponse.isStale);
});
} else {
// possibly overlay or other composition based plot
this.composition = this.openmct.composition.get(object);
this.composition.on('add', this.watchStaleness);
this.composition.on('remove', this.unwatchStaleness);
this.composition.on('add', this.subscribeToStaleness);
this.composition.on('remove', this.triggerUnsubscribeFromStaleness);
this.composition.load();
}
@ -260,54 +254,6 @@ export default {
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() {
this.$emit('lockHighlightPoint', ...arguments);
},
@ -405,20 +351,6 @@ export default {
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.telemetryObjects = {};
this.subscribedStaleObjects = new Map();
this.telemetryCollections = {};
this.delayedActions = [];
this.outstandingRequests = 0;
@ -74,6 +75,8 @@ define([
this.filterObserver = undefined;
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].load();
this.stalenessSubscription[keyString] = {};
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.subscribeToStaleness(telemetryObject);
this.telemetryObjects[keyString] = {
telemetryObject,
@ -193,6 +179,42 @@ define([
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) {
if (
skipCheck ||
@ -203,7 +225,7 @@ define([
) {
this.emit('telemetry-staleness', {
keyString,
isStale: stalenessResponse.isStale
stalenessResponse: stalenessResponse
});
}
}
@ -310,7 +332,6 @@ define([
removeTelemetryObject(objectIdentifier) {
const keyString = this.openmct.objects.makeKeyString(objectIdentifier);
const SKIP_CHECK = true;
this.configuration.removeColumnsForObject(objectIdentifier, true);
this.tableRows.removeRowsByObject(keyString);
@ -320,6 +341,13 @@ define([
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].stalenessUtils.destroy();
this.handleStaleness(keyString, { isStale: false }, SKIP_CHECK);
@ -423,6 +451,7 @@ define([
this.tableRows.destroy();
this.tableRows.off('resetRowsFromAllData', this.resetRowsFromAllData);
this.openmct.time.off('clockChanged', this.resubscribeToStaleness);
let keystrings = Object.keys(this.telemetryCollections);
keystrings.forEach(this.removeTelemetryCollection);

View File

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

View File

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

View File

@ -20,52 +20,190 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
import { isProxy, toRaw } from 'vue';
import StalenessUtils from '@/utils/staleness';
export default {
data() {
return {
isStale: false
staleObjects: [],
stalenessSubscription: {},
compositionObjectMap: new Map(),
setupClockChanged: false
};
},
beforeUnmount() {
this.triggerUnsubscribeFromStaleness();
computed: {
isStale() {
return this.staleObjects.length !== 0;
}
},
methods: {
subscribeToStaleness(domainObject, callback) {
if (!this.stalenessUtils) {
this.stalenessUtils = new StalenessUtils(this.openmct, domainObject);
getSubscriptionId(domainObject) {
return this.openmct?.objects.makeKeyString(domainObject.identifier);
},
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);
this.unsubscribeFromStaleness = this.openmct.telemetry.subscribeToStaleness(
domainObjectList.forEach((domainObject) => {
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,
(stalenessResponse) => {
this.handleStalenessResponse(stalenessResponse, callback);
const SKIP_CHECK = false;
this.handleStalenessResponse(id, stalenessResponse, SKIP_CHECK, callback);
}
);
},
async requestStaleness(domainObject) {
const stalenessResponse = await this.openmct.telemetry.isStale(domainObject);
if (stalenessResponse !== undefined) {
this.handleStalenessResponse(stalenessResponse);
teardownStalenessSubscription(domainObject) {
const id = this.getSubscriptionId(domainObject);
const { unsubscribe } = this.stalenessSubscription[id];
if (unsubscribe) {
unsubscribe();
delete this.stalenessSubscription[id].unsubscribe;
}
},
handleStalenessResponse(stalenessResponse, callback) {
if (this.stalenessUtils.shouldUpdateStaleness(stalenessResponse)) {
if (typeof callback === 'function') {
callback(stalenessResponse.isStale);
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);
if (stalenessResponse !== undefined) {
const SKIP_CHECK = false;
this.handleStalenessResponse(id, stalenessResponse, SKIP_CHECK, callback);
}
},
handleStalenessResponse(id, stalenessResponse, skipCheck, callback) {
if (!id) {
id = Object.keys(this.stalenessSubscription)[0];
}
const shouldUpdateStaleness =
this.stalenessSubscription[id].stalenessUtils.shouldUpdateStaleness(stalenessResponse);
if (skipCheck || shouldUpdateStaleness) {
if (callback && typeof callback === 'function') {
callback(stalenessResponse);
} else {
this.isStale = stalenessResponse.isStale;
this.addOrRemoveStaleObject(id, stalenessResponse);
}
}
},
triggerUnsubscribeFromStaleness() {
if (this.unsubscribeFromStaleness) {
this.unsubscribeFromStaleness();
delete this.unsubscribeFromStaleness;
this.stalenessUtils.destroy();
addOrRemoveStaleObject(id, 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);
}
}
}
},
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) {
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;
return true;