Compare commits
16 Commits
tree-searc
...
image-fres
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d20df25893 | ||
|
|
c236444a05 | ||
|
|
39c1eb1d5b | ||
|
|
0500b3967e | ||
|
|
4633436cbd | ||
|
|
3e9b567fce | ||
|
|
6f51de85db | ||
|
|
f202ae19cb | ||
|
|
668bd75025 | ||
|
|
e6e07cf959 | ||
|
|
2f8431905f | ||
|
|
23aba14dfe | ||
|
|
b0fa955914 | ||
|
|
98207a3e0d | ||
|
|
26b81345f2 | ||
|
|
ac2034b243 |
@@ -86,7 +86,7 @@ module.exports = (config) => {
|
||||
reports: ['html', 'lcovonly', 'text-summary'],
|
||||
thresholds: {
|
||||
global: {
|
||||
lines: 65
|
||||
lines: 66
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
function indexItem(id, model) {
|
||||
indexedItems.push({
|
||||
id: id,
|
||||
name: model.name.toLowerCase()
|
||||
name: model.name.toLowerCase(),
|
||||
type: model.type
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -125,13 +125,12 @@ define([
|
||||
* @param topic the topicService.
|
||||
*/
|
||||
GenericSearchProvider.prototype.indexOnMutation = function (topic) {
|
||||
var mutationTopic = topic('mutation'),
|
||||
provider = this;
|
||||
let mutationTopic = topic('mutation');
|
||||
|
||||
mutationTopic.listen(function (mutatedObject) {
|
||||
var editor = mutatedObject.getCapability('editor');
|
||||
mutationTopic.listen(mutatedObject => {
|
||||
let editor = mutatedObject.getCapability('editor');
|
||||
if (!editor || !editor.inEditContext()) {
|
||||
provider.index(
|
||||
this.index(
|
||||
mutatedObject.getId(),
|
||||
mutatedObject.getModel()
|
||||
);
|
||||
@@ -262,6 +261,7 @@ define([
|
||||
return {
|
||||
id: hit.item.id,
|
||||
model: hit.item.model,
|
||||
type: hit.item.type,
|
||||
score: hit.matchCount
|
||||
};
|
||||
});
|
||||
|
||||
@@ -41,7 +41,8 @@
|
||||
indexedItems.push({
|
||||
id: id,
|
||||
vector: vector,
|
||||
model: model
|
||||
model: model,
|
||||
type: model.type
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ class MenuAPI {
|
||||
this._showObjectMenu = this._showObjectMenu.bind(this);
|
||||
}
|
||||
|
||||
showMenu(x, y, actions) {
|
||||
showMenu(x, y, actions, onDestroy) {
|
||||
if (this.menuComponent) {
|
||||
this.menuComponent.dismiss();
|
||||
}
|
||||
@@ -46,7 +46,8 @@ class MenuAPI {
|
||||
let options = {
|
||||
x,
|
||||
y,
|
||||
actions
|
||||
actions,
|
||||
onDestroy
|
||||
};
|
||||
|
||||
this.menuComponent = new Menu(options);
|
||||
|
||||
@@ -31,6 +31,7 @@ describe ('The Menu API', () => {
|
||||
let x;
|
||||
let y;
|
||||
let result;
|
||||
let onDestroy;
|
||||
|
||||
beforeEach(() => {
|
||||
openmct = createOpenMct();
|
||||
@@ -73,7 +74,9 @@ describe ('The Menu API', () => {
|
||||
let vueComponent;
|
||||
|
||||
beforeEach(() => {
|
||||
menuAPI.showMenu(x, y, actionsArray);
|
||||
onDestroy = jasmine.createSpy('onDestroy');
|
||||
|
||||
menuAPI.showMenu(x, y, actionsArray, onDestroy);
|
||||
vueComponent = menuAPI.menuComponent.component;
|
||||
menuComponent = document.querySelector(".c-menu");
|
||||
|
||||
@@ -120,6 +123,12 @@ describe ('The Menu API', () => {
|
||||
|
||||
expect(vueComponent.$destroy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("invokes the onDestroy callback if passed in", () => {
|
||||
document.body.click();
|
||||
|
||||
expect(onDestroy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -75,7 +75,8 @@ export default class Condition extends EventEmitter {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isTelemetryUsed(datum.id)) {
|
||||
// if all the criteria in this condition have no telemetry, we want to force the condition result to evaluate
|
||||
if (this.hasNoTelemetry() || this.isTelemetryUsed(datum.id)) {
|
||||
|
||||
this.criteria.forEach(criterion => {
|
||||
if (this.isAnyOrAllTelemetry(criterion)) {
|
||||
@@ -93,6 +94,12 @@ export default class Condition extends EventEmitter {
|
||||
return (criterion.telemetry && (criterion.telemetry === 'all' || criterion.telemetry === 'any'));
|
||||
}
|
||||
|
||||
hasNoTelemetry() {
|
||||
return this.criteria.every((criterion) => {
|
||||
return !this.isAnyOrAllTelemetry(criterion) && criterion.telemetry === '';
|
||||
});
|
||||
}
|
||||
|
||||
isTelemetryUsed(id) {
|
||||
return this.criteria.some(criterion => {
|
||||
return this.isAnyOrAllTelemetry(criterion) || criterion.telemetryObjectIdAsString === id;
|
||||
@@ -250,10 +257,17 @@ export default class Condition extends EventEmitter {
|
||||
}
|
||||
|
||||
getTriggerDescription() {
|
||||
return {
|
||||
conjunction: TRIGGER_CONJUNCTION[this.trigger],
|
||||
prefix: `${TRIGGER_LABEL[this.trigger]}: `
|
||||
};
|
||||
if (this.trigger) {
|
||||
return {
|
||||
conjunction: TRIGGER_CONJUNCTION[this.trigger],
|
||||
prefix: `${TRIGGER_LABEL[this.trigger]}: `
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
conjunction: '',
|
||||
prefix: ''
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
requestLADConditionResult() {
|
||||
|
||||
@@ -79,6 +79,17 @@ export default class ConditionManager extends EventEmitter {
|
||||
delete this.subscriptions[id];
|
||||
delete this.telemetryObjects[id];
|
||||
this.removeConditionTelemetryObjects();
|
||||
|
||||
//force re-computation of condition set result as we might be in a state where
|
||||
// there is no telemetry datum coming in for a while or at all.
|
||||
let latestTimestamp = getLatestTimestamp(
|
||||
{},
|
||||
{},
|
||||
this.timeSystems,
|
||||
this.openmct.time.timeSystem()
|
||||
);
|
||||
this.updateConditionResults({id: id});
|
||||
this.updateCurrentCondition(latestTimestamp);
|
||||
}
|
||||
|
||||
initialize() {
|
||||
@@ -336,14 +347,17 @@ export default class ConditionManager extends EventEmitter {
|
||||
let timestamp = {};
|
||||
timestamp[timeSystemKey] = normalizedDatum[timeSystemKey];
|
||||
|
||||
this.updateConditionResults(normalizedDatum);
|
||||
this.updateCurrentCondition(timestamp);
|
||||
}
|
||||
|
||||
updateConditionResults(normalizedDatum) {
|
||||
//We want to stop when the first condition evaluates to true.
|
||||
this.conditions.some((condition) => {
|
||||
condition.updateResult(normalizedDatum);
|
||||
|
||||
return condition.result === true;
|
||||
});
|
||||
|
||||
this.updateCurrentCondition(timestamp);
|
||||
}
|
||||
|
||||
updateCurrentCondition(timestamp) {
|
||||
|
||||
@@ -86,6 +86,7 @@ export default class StyleRuleManager extends EventEmitter {
|
||||
updateObjectStyleConfig(styleConfiguration) {
|
||||
if (!styleConfiguration || !styleConfiguration.conditionSetIdentifier) {
|
||||
this.initialize(styleConfiguration || {});
|
||||
this.applyStaticStyle();
|
||||
this.destroy();
|
||||
} else {
|
||||
let isNewConditionSet = !this.conditionSetIdentifier
|
||||
@@ -158,7 +159,6 @@ export default class StyleRuleManager extends EventEmitter {
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.applyStaticStyle();
|
||||
if (this.stopProvidingTelemetry) {
|
||||
this.stopProvidingTelemetry();
|
||||
delete this.stopProvidingTelemetry;
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
v-model="expanded"
|
||||
class="c-tree__item__view-control"
|
||||
:enabled="hasChildren"
|
||||
:propagate="false"
|
||||
/>
|
||||
<div class="c-tree__item__label c-object-label">
|
||||
<div
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<template>
|
||||
<tr
|
||||
class="c-list-item"
|
||||
:class="{ 'is-alias': item.isAlias === true }"
|
||||
:class="{
|
||||
'is-alias': item.isAlias === true
|
||||
}"
|
||||
@click="navigate"
|
||||
>
|
||||
<td class="c-list-item__name">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import ImageryViewLayout from './components/ImageryViewLayout.vue';
|
||||
import Vue from 'vue';
|
||||
|
||||
export default function ImageryViewProvider(openmct) {
|
||||
export default function ImageryViewProvider(openmct, configuration) {
|
||||
const type = 'example.imagery';
|
||||
|
||||
function hasImageTelemetry(domainObject) {
|
||||
@@ -32,7 +32,8 @@ export default function ImageryViewProvider(openmct) {
|
||||
},
|
||||
provide: {
|
||||
openmct,
|
||||
domainObject
|
||||
domainObject,
|
||||
configuration
|
||||
},
|
||||
template: '<imagery-view-layout ref="ImageryLayout"></imagery-view-layout>'
|
||||
});
|
||||
|
||||
@@ -61,11 +61,25 @@
|
||||
<div class="c-imagery__control-bar">
|
||||
<div class="c-imagery__time">
|
||||
<div class="c-imagery__timestamp u-style-receiver js-style-receiver">{{ time }}</div>
|
||||
<!-- Imagery Age Freshness -->
|
||||
<div
|
||||
v-if="canTrackDuration"
|
||||
:class="{'c-imagery--new': isImageNew && !refreshCSS}"
|
||||
class="c-imagery__age icon-timer"
|
||||
>{{ formattedDuration }}</div>
|
||||
<!-- Rover Position Freshness -->
|
||||
<div>isFresh {{ roverPositionIsFresh }}</div>
|
||||
<div
|
||||
v-if="roverPositionIsFresh !== undefined"
|
||||
:class="{'c-imagery--new': roverPositionIsFresh}"
|
||||
class="c-imagery__age icon-timer"
|
||||
>{{ roverPositionIsFresh ? 'ROVER' : '' }}</div>
|
||||
<!-- Rover Camera Position Freshness -->
|
||||
<div
|
||||
v-if="cameraPositionIsFresh !== undefined"
|
||||
:class="{'c-imagery--new': cameraPositionIsFresh && !refreshCSS}"
|
||||
class="c-imagery__age icon-timer"
|
||||
>{{ formattedDuration }}</div>
|
||||
</div>
|
||||
<div class="h-local-controls">
|
||||
<button
|
||||
@@ -116,7 +130,7 @@ const ARROW_RIGHT = 39;
|
||||
const ARROW_LEFT = 37;
|
||||
|
||||
export default {
|
||||
inject: ['openmct', 'domainObject'],
|
||||
inject: ['openmct', 'domainObject', 'configuration'],
|
||||
data() {
|
||||
let timeSystem = this.openmct.time.timeSystem();
|
||||
|
||||
@@ -137,7 +151,14 @@ export default {
|
||||
refreshCSS: false,
|
||||
keyString: undefined,
|
||||
focusedImageIndex: undefined,
|
||||
numericDuration: undefined
|
||||
numericDuration: undefined,
|
||||
metadataEndpoints: {},
|
||||
roverPositionIsFresh: undefined,
|
||||
cameraPositionIsFresh: undefined,
|
||||
roverPositionState: {},
|
||||
cameraPositionState: {},
|
||||
canTrackRoverPositionFreshness: undefined,
|
||||
canTrackCameraPositionFreshness: undefined
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -201,9 +222,11 @@ export default {
|
||||
focusedImageIndex() {
|
||||
this.trackDuration();
|
||||
this.resetAgeCSS();
|
||||
this.determineRoverFreshness();
|
||||
this.determineCameraPositionFreshness();
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
async mounted() {
|
||||
// listen
|
||||
this.openmct.time.on('bounds', this.boundsChange);
|
||||
this.openmct.time.on('timeSystem', this.timeSystemChange);
|
||||
@@ -212,16 +235,34 @@ export default {
|
||||
// set
|
||||
this.keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||
this.metadata = this.openmct.telemetry.getMetadata(this.domainObject);
|
||||
this.imageHints = this.metadata.valuesForHints(['image'])[0];
|
||||
this.durationFormatter = this.getFormatter(this.timeSystem.durationFormat || DEFAULT_DURATION_FORMATTER);
|
||||
this.imageFormatter = this.openmct.telemetry.getValueFormatter(this.metadata.valuesForHints(['image'])[0]);
|
||||
this.imageFormatter = this.openmct.telemetry.getValueFormatter(this.imageHints);
|
||||
|
||||
// DELETE WHEN DONE
|
||||
this.temporaryForImageEnhancements();
|
||||
|
||||
// initialize
|
||||
this.timeKey = this.timeSystem.key;
|
||||
this.timeFormatter = this.getFormatter(this.timeKey);
|
||||
this.roverPositionKeys = ['Rover Heading', 'Rover Roll', 'Rover Pitch', 'Rover Yaw'];
|
||||
this.cameraPositionKeys = ['Camera Tilt', 'Camera Pan'];
|
||||
|
||||
// kickoff
|
||||
this.subscribe();
|
||||
this.requestHistory();
|
||||
await this.initializeRelatedTelemetry();
|
||||
|
||||
// DELETE
|
||||
// examples for requesting historical data for a relatedTelemetry key
|
||||
// and for subscribing to a relatedTelemetry key
|
||||
// example for 'Rover Heading'
|
||||
// ***********************************************************************
|
||||
// let results = await this.relatedTelemetry['Rover Heading'].request();
|
||||
// this.relatedTelemetry['Rover Heading'].subscribe((data) => {
|
||||
// console.log('subscribe test', data);
|
||||
// });
|
||||
// ***********************************************************************
|
||||
},
|
||||
updated() {
|
||||
this.scrollToRight();
|
||||
@@ -236,8 +277,148 @@ export default {
|
||||
this.openmct.time.off('bounds', this.boundsChange);
|
||||
this.openmct.time.off('timeSystem', this.timeSystemChange);
|
||||
this.openmct.time.off('clock', this.clockChange);
|
||||
|
||||
// unsubscribe from related telemetry
|
||||
if (this.hasRelatedTelemetry) {
|
||||
for (let key of this.relatedTelemetry.keys) {
|
||||
if (this.relatedTelemetry[key].unsubscribe) {
|
||||
this.relatedTelemetry[key].unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// for local dev, to be DELETED
|
||||
temporaryForImageEnhancements() {
|
||||
let roverKeys = ['Rover Heading', 'Rover Roll', 'Rover Yaw', 'Rover Pitch'];
|
||||
let cameraKeys = ['Camera Pan', 'Camera Tilt'];
|
||||
|
||||
this.searchService = this.openmct.$injector.get('searchService');
|
||||
this.temporaryDev = true;
|
||||
|
||||
// mock related telemetry metadata
|
||||
this.imageHints.relatedTelemetry = {};
|
||||
|
||||
// populate temp keys in imageHints for local testing
|
||||
[...roverKeys, ...cameraKeys].forEach(key => {
|
||||
|
||||
this.imageHints.relatedTelemetry[key] = {
|
||||
dev: true,
|
||||
realtime: key,
|
||||
historical: key,
|
||||
devInit: async () => {
|
||||
const searchResults = await this.searchService.query(key);
|
||||
const endpoint = searchResults.hits[0].id;
|
||||
const domainObject = await this.openmct.objects.get(endpoint);
|
||||
|
||||
return domainObject;
|
||||
}
|
||||
};
|
||||
});
|
||||
},
|
||||
async initializeRelatedTelemetry() {
|
||||
if (this.imageHints.relatedTelemetry === undefined) {
|
||||
this.hasRelatedTelemetry = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// DELETE
|
||||
if (this.temporaryDev) {
|
||||
let searchIndexBuildDelay = new Promise((resolve, reject) => {
|
||||
setTimeout(resolve, 3000);
|
||||
});
|
||||
|
||||
await searchIndexBuildDelay;
|
||||
}
|
||||
|
||||
let keys = Object.keys(this.imageHints.relatedTelemetry);
|
||||
|
||||
this.hasRelatedTelemetry = true;
|
||||
this.relatedTelemetry = {
|
||||
keys,
|
||||
...this.imageHints.relatedTelemetry
|
||||
};
|
||||
|
||||
// grab historical and subscribe to realtime
|
||||
for (let key of keys) {
|
||||
let historicalId = this.relatedTelemetry[key].historical;
|
||||
let realtimeId = this.relatedTelemetry[key].realtime;
|
||||
let sameId = false;
|
||||
|
||||
if (historicalId && realtimeId && historicalId === realtimeId) {
|
||||
|
||||
// DELETE temp
|
||||
if (this.relatedTelemetry[key].dev) {
|
||||
this.relatedTelemetry[key].historicalDomainObject = await this.relatedTelemetry[key].devInit();
|
||||
delete this.relatedTelemetry[key].dev;
|
||||
delete this.relatedTelemetry[key].devInit;
|
||||
} else {
|
||||
this.relatedTelemetry[key].historicalDomainObject = await this.openmct.objects.get(historicalId);
|
||||
}
|
||||
|
||||
this.relatedTelemetry[key].realtimeDomainObject = this.relatedTelemetry[key].historicalDomainObject;
|
||||
sameId = true;
|
||||
}
|
||||
|
||||
if (historicalId) {
|
||||
// check for on-telemetry data
|
||||
if (historicalId[0] === '.') {
|
||||
this.relatedTelemetry[key].valueOnTelemetry = true;
|
||||
}
|
||||
|
||||
if (!sameId) {
|
||||
this.relatedTelemetry[key].historicalDomainObject = await this.openmct.objects.get(historicalId);
|
||||
}
|
||||
|
||||
this.relatedTelemetry[key].request = async (options) => {
|
||||
let results = await this.openmct.telemetry
|
||||
.request(this.relatedTelemetry[key].historicalDomainObject, options);
|
||||
|
||||
return results;
|
||||
};
|
||||
}
|
||||
|
||||
if (realtimeId) {
|
||||
|
||||
// set up listeners
|
||||
this.relatedTelemetry[key].listeners = [];
|
||||
this.relatedTelemetry[key].subscribe = (callback) => {
|
||||
if (!this.relatedTelemetry[key].listeners.includes(callback)) {
|
||||
this.relatedTelemetry[key].listeners.push(callback);
|
||||
|
||||
return () => {
|
||||
this.relatedTelemetry[key].listeners.remove(callback);
|
||||
};
|
||||
} else {
|
||||
return () => {};
|
||||
}
|
||||
};
|
||||
|
||||
if (!sameId) {
|
||||
this.relatedTelemetry[key].realtimeDomainObject = await this.openmct.objects.get(realtimeId);
|
||||
}
|
||||
|
||||
this.relatedTelemetry[key].unsubscribe = this.openmct.telemetry.subscribe(
|
||||
this.relatedTelemetry[key].realtimeDomainObject,
|
||||
datum => {
|
||||
this.relatedTelemetry[key].latest = datum;
|
||||
this.relatedTelemetry[key].listeners.forEach(callback => {
|
||||
callback(datum);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
async requestRelatedTelemetry(key) {
|
||||
if (this.relatedTelemetry[key] && this.relatedTelemetry[key].historicalDomainObject) {
|
||||
let data = await this.openmct.telemetry.request(this.relatedTelemetry[key].historicalDomainObject);
|
||||
|
||||
return data;
|
||||
}
|
||||
},
|
||||
focusElement() {
|
||||
this.$el.focus();
|
||||
},
|
||||
@@ -405,6 +586,83 @@ export default {
|
||||
|
||||
return valueFormatter;
|
||||
},
|
||||
roverPositionTrackingApplicable() {
|
||||
let canTrack = false; // possibly false first, depending on if we need all or one
|
||||
|
||||
for (const key of this.roverPositionKeys) {
|
||||
// do we need ALL to be available or will one work?
|
||||
if (this.metadata.value(key)) {
|
||||
canTrack = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Force true, will remove
|
||||
if (this.temporaryDev) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return canTrack;
|
||||
},
|
||||
async determineRoverFreshness() {
|
||||
if (this.canTrackRoverPositionFreshness === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
let noChanges = true;
|
||||
|
||||
// set up state tracking
|
||||
for (const key of this.roverPositionKeys) {
|
||||
try {
|
||||
let currentState = await this.getImageMetadataValue(key, this.focusedImage[this.timeKey]);
|
||||
currentState = currentState.toFixed(1);
|
||||
|
||||
if (currentState !== this.roverPositionState[key]) {
|
||||
this.roverPositionState[key] = currentState;
|
||||
this.roverPositionIsFresh = false;
|
||||
noChanges = false;
|
||||
}
|
||||
} catch (err) {
|
||||
this.roverPositionIsFresh = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
if (noChanges) {
|
||||
this.roverPositionIsFresh = true;
|
||||
}
|
||||
|
||||
console.log('roverPosition is fresh', this.roverPositionIsFresh);
|
||||
|
||||
},
|
||||
trackRoverPosition() {
|
||||
this.cancelRoverTrackingInterval = window.setInterval(this.determineRoverFreshness, this.roverTrackingInterval);
|
||||
},
|
||||
cameraPositionTrackingApplicable() {
|
||||
let canTrack = false; // possibly false first, depending on if we need all or one
|
||||
|
||||
for (const key of this.cameraPositionKeys) {
|
||||
// do we need ALL to be available or will one work?
|
||||
if (this.metadata.value(key)) {
|
||||
canTrack = true;
|
||||
}
|
||||
}
|
||||
|
||||
// will remove
|
||||
if (this.temporaryDev) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return canTrack;
|
||||
},
|
||||
determineCameraPositionFreshness() {
|
||||
if (this.canTrackCameraPositionFreshness === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.cameraPositionIsFresh = undefined;
|
||||
},
|
||||
trackCameraPosition() {
|
||||
this.cancelCameraTrackingInterval = window.setInterval(this.determineCameraFreshness, this.cameraTrackingInterval);
|
||||
},
|
||||
trackDuration() {
|
||||
if (this.canTrackDuration) {
|
||||
this.stopDurationTracking();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import ImageryViewProvider from './ImageryViewProvider';
|
||||
|
||||
export default function () {
|
||||
export default function (configuration) {
|
||||
return function install(openmct) {
|
||||
openmct.objectViews.addProvider(new ImageryViewProvider(openmct));
|
||||
openmct.objectViews.addProvider(new ImageryViewProvider(openmct, configuration));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -225,14 +225,12 @@ export default {
|
||||
},
|
||||
createNotebookStorageObject() {
|
||||
const notebookMeta = {
|
||||
name: this.internalDomainObject.name,
|
||||
identifier: this.internalDomainObject.identifier
|
||||
};
|
||||
const page = this.getSelectedPage();
|
||||
const section = this.getSelectedSection();
|
||||
|
||||
return {
|
||||
domainObject: this.internalDomainObject,
|
||||
notebookMeta,
|
||||
section,
|
||||
page
|
||||
@@ -442,10 +440,10 @@ export default {
|
||||
async updateDefaultNotebook(notebookStorage) {
|
||||
const defaultNotebookObject = await this.getDefaultNotebookObject();
|
||||
if (!defaultNotebookObject) {
|
||||
setDefaultNotebook(this.openmct, notebookStorage);
|
||||
setDefaultNotebook(this.openmct, notebookStorage, this.internalDomainObject);
|
||||
} else if (objectUtils.makeKeyString(defaultNotebookObject.identifier) !== objectUtils.makeKeyString(notebookStorage.notebookMeta.identifier)) {
|
||||
this.removeDefaultClass(defaultNotebookObject);
|
||||
setDefaultNotebook(this.openmct, notebookStorage);
|
||||
setDefaultNotebook(this.openmct, notebookStorage, this.internalDomainObject);
|
||||
}
|
||||
|
||||
if (this.defaultSectionId && this.defaultSectionId.length === 0 || this.defaultSectionId !== notebookStorage.section.id) {
|
||||
|
||||
@@ -44,38 +44,46 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
notebookSnapshot: null,
|
||||
notebookSnapshot: undefined,
|
||||
notebookTypes: []
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
validateNotebookStorageObject();
|
||||
this.getDefaultNotebookObject();
|
||||
|
||||
this.notebookSnapshot = new Snapshot(this.openmct);
|
||||
this.setDefaultNotebookStatus();
|
||||
},
|
||||
methods: {
|
||||
showMenu(event) {
|
||||
const notebookTypes = [];
|
||||
async getDefaultNotebookObject() {
|
||||
const defaultNotebook = getDefaultNotebook();
|
||||
const defaultNotebookObject = defaultNotebook && await this.openmct.objects.get(defaultNotebook.notebookMeta.identifier);
|
||||
|
||||
return defaultNotebookObject;
|
||||
},
|
||||
async showMenu(event) {
|
||||
const notebookTypes = [];
|
||||
const elementBoundingClientRect = this.$el.getBoundingClientRect();
|
||||
const x = elementBoundingClientRect.x;
|
||||
const y = elementBoundingClientRect.y + elementBoundingClientRect.height;
|
||||
|
||||
if (defaultNotebook) {
|
||||
const domainObject = defaultNotebook.domainObject;
|
||||
const defaultNotebookObject = await this.getDefaultNotebookObject();
|
||||
if (defaultNotebookObject) {
|
||||
const name = defaultNotebookObject.name;
|
||||
|
||||
if (domainObject.location) {
|
||||
const defaultPath = `${domainObject.name} - ${defaultNotebook.section.name} - ${defaultNotebook.page.name}`;
|
||||
const defaultNotebook = getDefaultNotebook();
|
||||
const sectionName = defaultNotebook.section.name;
|
||||
const pageName = defaultNotebook.page.name;
|
||||
const defaultPath = `${name} - ${sectionName} - ${pageName}`;
|
||||
|
||||
notebookTypes.push({
|
||||
cssClass: 'icon-notebook',
|
||||
name: `Save to Notebook ${defaultPath}`,
|
||||
callBack: () => {
|
||||
return this.snapshot(NOTEBOOK_DEFAULT);
|
||||
}
|
||||
});
|
||||
}
|
||||
notebookTypes.push({
|
||||
cssClass: 'icon-notebook',
|
||||
name: `Save to Notebook ${defaultPath}`,
|
||||
callBack: () => {
|
||||
return this.snapshot(NOTEBOOK_DEFAULT);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
notebookTypes.push({
|
||||
|
||||
@@ -23,13 +23,6 @@ import * as NotebookEntries from './notebook-entries';
|
||||
import { createOpenMct, resetApplicationState } from 'utils/testing';
|
||||
|
||||
const notebookStorage = {
|
||||
domainObject: {
|
||||
name: 'notebook',
|
||||
identifier: {
|
||||
namespace: '',
|
||||
key: 'test-notebook'
|
||||
}
|
||||
},
|
||||
notebookMeta: {
|
||||
name: 'notebook',
|
||||
identifier: {
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import objectUtils from 'objectUtils';
|
||||
|
||||
const NOTEBOOK_LOCAL_STORAGE = 'notebook-storage';
|
||||
let currentNotebookObject = null;
|
||||
let currentNotebookObjectIdentifier = null;
|
||||
let unlisten = null;
|
||||
|
||||
function defaultNotebookObjectChanged(newDomainObject) {
|
||||
if (newDomainObject.location !== null) {
|
||||
currentNotebookObject = newDomainObject;
|
||||
const notebookStorage = getDefaultNotebook();
|
||||
notebookStorage.domainObject = newDomainObject;
|
||||
saveDefaultNotebook(notebookStorage);
|
||||
currentNotebookObjectIdentifier = newDomainObject.identifier;
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -20,10 +19,9 @@ function defaultNotebookObjectChanged(newDomainObject) {
|
||||
clearDefaultNotebook();
|
||||
}
|
||||
|
||||
function observeDefaultNotebookObject(openmct, notebookStorage) {
|
||||
const domainObject = notebookStorage.domainObject;
|
||||
if (currentNotebookObject
|
||||
&& currentNotebookObject.identifier.key === domainObject.identifier.key) {
|
||||
function observeDefaultNotebookObject(openmct, notebookMeta, domainObject) {
|
||||
if (currentNotebookObjectIdentifier
|
||||
&& objectUtils.makeKeyString(currentNotebookObjectIdentifier) === objectUtils.makeKeyString(notebookMeta.identifier)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -32,7 +30,7 @@ function observeDefaultNotebookObject(openmct, notebookStorage) {
|
||||
unlisten = null;
|
||||
}
|
||||
|
||||
unlisten = openmct.objects.observe(notebookStorage.domainObject, '*', defaultNotebookObjectChanged);
|
||||
unlisten = openmct.objects.observe(domainObject, '*', defaultNotebookObjectChanged);
|
||||
}
|
||||
|
||||
function saveDefaultNotebook(notebookStorage) {
|
||||
@@ -40,7 +38,7 @@ function saveDefaultNotebook(notebookStorage) {
|
||||
}
|
||||
|
||||
export function clearDefaultNotebook() {
|
||||
currentNotebookObject = null;
|
||||
currentNotebookObjectIdentifier = null;
|
||||
window.localStorage.setItem(NOTEBOOK_LOCAL_STORAGE, null);
|
||||
}
|
||||
|
||||
@@ -50,8 +48,8 @@ export function getDefaultNotebook() {
|
||||
return JSON.parse(notebookStorage);
|
||||
}
|
||||
|
||||
export function setDefaultNotebook(openmct, notebookStorage) {
|
||||
observeDefaultNotebookObject(openmct, notebookStorage);
|
||||
export function setDefaultNotebook(openmct, notebookStorage, domainObject) {
|
||||
observeDefaultNotebookObject(openmct, notebookStorage.notebookMeta, domainObject);
|
||||
saveDefaultNotebook(notebookStorage);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,14 +23,15 @@
|
||||
import * as NotebookStorage from './notebook-storage';
|
||||
import { createOpenMct, resetApplicationState } from 'utils/testing';
|
||||
|
||||
const domainObject = {
|
||||
name: 'notebook',
|
||||
identifier: {
|
||||
namespace: '',
|
||||
key: 'test-notebook'
|
||||
}
|
||||
};
|
||||
|
||||
const notebookStorage = {
|
||||
domainObject: {
|
||||
name: 'notebook',
|
||||
identifier: {
|
||||
namespace: '',
|
||||
key: 'test-notebook'
|
||||
}
|
||||
},
|
||||
notebookMeta: {
|
||||
name: 'notebook',
|
||||
identifier: {
|
||||
@@ -82,7 +83,7 @@ describe('Notebook Storage:', () => {
|
||||
});
|
||||
|
||||
it('has correct notebookstorage on setDefaultNotebook', () => {
|
||||
NotebookStorage.setDefaultNotebook(openmct, notebookStorage);
|
||||
NotebookStorage.setDefaultNotebook(openmct, notebookStorage, domainObject);
|
||||
const defaultNotebook = NotebookStorage.getDefaultNotebook();
|
||||
|
||||
expect(JSON.stringify(defaultNotebook)).toBe(JSON.stringify(notebookStorage));
|
||||
@@ -98,7 +99,7 @@ describe('Notebook Storage:', () => {
|
||||
sectionTitle: 'Section'
|
||||
};
|
||||
|
||||
NotebookStorage.setDefaultNotebook(openmct, notebookStorage);
|
||||
NotebookStorage.setDefaultNotebook(openmct, notebookStorage, domainObject);
|
||||
NotebookStorage.setDefaultNotebookSection(section);
|
||||
|
||||
const defaultNotebook = NotebookStorage.getDefaultNotebook();
|
||||
@@ -115,7 +116,7 @@ describe('Notebook Storage:', () => {
|
||||
pageTitle: 'Page'
|
||||
};
|
||||
|
||||
NotebookStorage.setDefaultNotebook(openmct, notebookStorage);
|
||||
NotebookStorage.setDefaultNotebook(openmct, notebookStorage, domainObject);
|
||||
NotebookStorage.setDefaultNotebookPage(page);
|
||||
|
||||
const defaultNotebook = NotebookStorage.getDefaultNotebook();
|
||||
|
||||
9
src/plugins/performanceIndicator/README.md
Normal file
9
src/plugins/performanceIndicator/README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# URL Indicator
|
||||
Adds an indicator which shows the number of frames that the browser is able to render per second. This is a useful proxy for the maximum number of updates that any telemetry display can perform per second. This may be useful during performance testing, but probably should not be enabled by default.
|
||||
|
||||
This indicator adds adds about 3% points to CPU usage in the Chrome task manager.
|
||||
|
||||
## Installation
|
||||
```js
|
||||
openmct.install(openmct.plugins.PerformanceIndicator());
|
||||
```
|
||||
62
src/plugins/performanceIndicator/plugin.js
Normal file
62
src/plugins/performanceIndicator/plugin.js
Normal file
@@ -0,0 +1,62 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
export default function PerformanceIndicator() {
|
||||
return function install(openmct) {
|
||||
let frames = 0;
|
||||
let lastCalculated = performance.now();
|
||||
const indicator = openmct.indicators.simpleIndicator();
|
||||
|
||||
indicator.text('~ fps');
|
||||
indicator.statusClass('s-status-info');
|
||||
openmct.indicators.add(indicator);
|
||||
|
||||
let rafHandle = requestAnimationFrame(incremementFrames);
|
||||
|
||||
openmct.on('destroy', () => {
|
||||
cancelAnimationFrame(rafHandle);
|
||||
});
|
||||
|
||||
function incremementFrames() {
|
||||
let now = performance.now();
|
||||
if ((now - lastCalculated) < 1000) {
|
||||
frames++;
|
||||
} else {
|
||||
updateFPS(frames);
|
||||
lastCalculated = now;
|
||||
frames = 1;
|
||||
}
|
||||
|
||||
rafHandle = requestAnimationFrame(incremementFrames);
|
||||
}
|
||||
|
||||
function updateFPS(fps) {
|
||||
indicator.text(`${fps} fps`);
|
||||
if (fps >= 40) {
|
||||
indicator.statusClass('s-status-on');
|
||||
} else if (fps < 40 && fps >= 20) {
|
||||
indicator.statusClass('s-status-warning');
|
||||
} else {
|
||||
indicator.statusClass('s-status-error');
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
87
src/plugins/performanceIndicator/pluginSpec.js
Normal file
87
src/plugins/performanceIndicator/pluginSpec.js
Normal file
@@ -0,0 +1,87 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2020, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
import PerformancePlugin from './plugin.js';
|
||||
import {
|
||||
createOpenMct,
|
||||
resetApplicationState
|
||||
} from 'utils/testing';
|
||||
|
||||
describe('the plugin', () => {
|
||||
let openmct;
|
||||
let element;
|
||||
let child;
|
||||
|
||||
let performanceIndicator;
|
||||
let countFramesPromise;
|
||||
|
||||
beforeEach((done) => {
|
||||
openmct = createOpenMct(false);
|
||||
|
||||
element = document.createElement('div');
|
||||
child = document.createElement('div');
|
||||
element.appendChild(child);
|
||||
|
||||
openmct.install(new PerformancePlugin());
|
||||
|
||||
countFramesPromise = countFrames();
|
||||
|
||||
openmct.on('start', done);
|
||||
|
||||
performanceIndicator = openmct.indicators.indicatorObjects.find((indicator) => {
|
||||
return indicator.text && indicator.text() === '~ fps';
|
||||
});
|
||||
|
||||
openmct.startHeadless();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
return resetApplicationState(openmct);
|
||||
});
|
||||
|
||||
it('installs the performance indicator', () => {
|
||||
expect(performanceIndicator).toBeDefined();
|
||||
});
|
||||
|
||||
it('correctly calculates fps', () => {
|
||||
return countFramesPromise.then((frames) => {
|
||||
expect(performanceIndicator.text()).toEqual(`${frames} fps`);
|
||||
});
|
||||
});
|
||||
|
||||
function countFrames() {
|
||||
let startTime = performance.now();
|
||||
let frames = 0;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
requestAnimationFrame(function incrementCount() {
|
||||
let now = performance.now();
|
||||
|
||||
if ((now - startTime) < 1000) {
|
||||
frames++;
|
||||
requestAnimationFrame(incrementCount);
|
||||
} else {
|
||||
resolve(frames);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -60,7 +60,8 @@ define([
|
||||
'./defaultRootName/plugin',
|
||||
'./timeline/plugin',
|
||||
'./viewDatumAction/plugin',
|
||||
'./interceptors/plugin'
|
||||
'./interceptors/plugin',
|
||||
'./performanceIndicator/plugin'
|
||||
], function (
|
||||
_,
|
||||
UTCTimeSystem,
|
||||
@@ -101,7 +102,8 @@ define([
|
||||
DefaultRootName,
|
||||
Timeline,
|
||||
ViewDatumAction,
|
||||
ObjectInterceptors
|
||||
ObjectInterceptors,
|
||||
PerformanceIndicator
|
||||
) {
|
||||
const bundleMap = {
|
||||
LocalStorage: 'platform/persistence/local',
|
||||
@@ -197,6 +199,7 @@ define([
|
||||
plugins.Timeline = Timeline.default;
|
||||
plugins.ViewDatumAction = ViewDatumAction.default;
|
||||
plugins.ObjectInterceptors = ObjectInterceptors.default;
|
||||
plugins.PerformanceIndicator = PerformanceIndicator.default;
|
||||
|
||||
return plugins;
|
||||
});
|
||||
|
||||
@@ -100,11 +100,13 @@ define([], function () {
|
||||
* @param {*} metadataValues
|
||||
*/
|
||||
function createNormalizedDatum(datum, columns) {
|
||||
return Object.values(columns).reduce((normalizedDatum, column) => {
|
||||
normalizedDatum[column.getKey()] = column.getRawValue(datum);
|
||||
const normalizedDatum = JSON.parse(JSON.stringify(datum));
|
||||
|
||||
return normalizedDatum;
|
||||
}, {});
|
||||
Object.values(columns).forEach(column => {
|
||||
normalizedDatum[column.getKey()] = column.getRawValue(datum);
|
||||
});
|
||||
|
||||
return normalizedDatum;
|
||||
}
|
||||
|
||||
return TelemetryTableRow;
|
||||
|
||||
@@ -22,10 +22,6 @@ export default {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propagate: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
controlClass: {
|
||||
type: String,
|
||||
default: 'c-disclosure-triangle'
|
||||
@@ -33,10 +29,8 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
handleClick(event) {
|
||||
event.stopPropagation();
|
||||
this.$emit('input', !this.value);
|
||||
if (!this.propagate) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -95,6 +95,10 @@
|
||||
color: $colorItemTreeSelectedFg;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-context-clicked {
|
||||
box-shadow: inset $colorItemTreeSelectedBg 0 0 0 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
v-for="(ancestor, index) in focusedAncestors"
|
||||
:key="ancestor.id"
|
||||
:node="ancestor"
|
||||
:show-up="index < focusedAncestors.length - 1"
|
||||
:show-up="index < focusedAncestors.length - 1 && initialLoad"
|
||||
:show-down="false"
|
||||
:left-offset="index * 10 + 'px'"
|
||||
@resetTree="beginNavigationRequest('handleReset', ancestor)"
|
||||
@@ -156,6 +156,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
root: undefined,
|
||||
initialLoad: false,
|
||||
isLoading: false,
|
||||
mainTreeHeight: undefined,
|
||||
searchLoading: false,
|
||||
@@ -499,6 +500,11 @@ export default {
|
||||
this.ancestors = ancestors;
|
||||
this.childItems = children;
|
||||
|
||||
// track when FIRST full load of tree happens
|
||||
if (!this.initialLoad) {
|
||||
this.initialLoad = true;
|
||||
}
|
||||
|
||||
// any new items added or removed handled here
|
||||
this.composition.on('add', this.addChild);
|
||||
this.composition.on('remove', this.removeChild);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<template>
|
||||
<div
|
||||
ref="me"
|
||||
:style="{
|
||||
'top': virtualScroll ? itemTop : 'auto',
|
||||
'position': virtualScroll ? 'absolute' : 'relative'
|
||||
@@ -11,10 +10,14 @@
|
||||
class="c-tree__item"
|
||||
:class="{
|
||||
'is-alias': isAlias,
|
||||
'is-navigated-object': navigated
|
||||
'is-navigated-object': navigated,
|
||||
'is-context-clicked': contextClickActive
|
||||
}"
|
||||
@click.capture="handleClick"
|
||||
@contextmenu.capture="handleContextMenu"
|
||||
>
|
||||
<view-control
|
||||
ref="navUp"
|
||||
v-model="expanded"
|
||||
class="c-tree__item__view-control"
|
||||
:control-class="'c-nav__up'"
|
||||
@@ -22,12 +25,15 @@
|
||||
@input="resetTreeHere"
|
||||
/>
|
||||
<object-label
|
||||
ref="objectLabel"
|
||||
:domain-object="node.object"
|
||||
:object-path="node.objectPath"
|
||||
:navigate-to-path="navigationPath"
|
||||
:style="{ paddingLeft: leftOffset }"
|
||||
@context-click-active="setContextClickActive"
|
||||
/>
|
||||
<view-control
|
||||
ref="navDown"
|
||||
v-model="expanded"
|
||||
class="c-tree__item__view-control"
|
||||
:control-class="'c-nav__down'"
|
||||
@@ -91,7 +97,8 @@ export default {
|
||||
return {
|
||||
hasComposition: false,
|
||||
navigated: this.isNavigated(),
|
||||
expanded: false
|
||||
expanded: false,
|
||||
contextClickActive: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -134,6 +141,20 @@ export default {
|
||||
this.openmct.router.off('change:path', this.highlightIfNavigated);
|
||||
},
|
||||
methods: {
|
||||
handleClick(event) {
|
||||
// skip for navigation, let viewControl handle click
|
||||
if ([this.$refs.navUp.$el, this.$refs.navDown.$el].includes(event.target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.stopPropagation();
|
||||
|
||||
this.$refs.objectLabel.$el.click();
|
||||
},
|
||||
handleContextMenu(event) {
|
||||
event.stopPropagation();
|
||||
this.$refs.objectLabel.showContextMenu(event);
|
||||
},
|
||||
isNavigated() {
|
||||
return this.navigationPath === this.openmct.router.currentLocation.path;
|
||||
},
|
||||
@@ -142,6 +163,9 @@ export default {
|
||||
},
|
||||
resetTreeHere() {
|
||||
this.$emit('resetTree', this.node);
|
||||
},
|
||||
setContextClickActive(active) {
|
||||
this.contextClickActive = active;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -8,6 +8,11 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
contextClickActive: false
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
//TODO: touch support
|
||||
this.$el.addEventListener('contextmenu', this.showContextMenu);
|
||||
@@ -35,7 +40,13 @@ export default {
|
||||
let actions = actionsCollection.getVisibleActions();
|
||||
let sortedActions = this.openmct.actions._groupAndSortActions(actions);
|
||||
|
||||
this.openmct.menus.showMenu(event.clientX, event.clientY, sortedActions);
|
||||
this.openmct.menus.showMenu(event.clientX, event.clientY, sortedActions, this.onContextMenuDestroyed);
|
||||
this.contextClickActive = true;
|
||||
this.$emit('context-click-active', true);
|
||||
},
|
||||
onContextMenuDestroyed() {
|
||||
this.contextClickActive = false;
|
||||
this.$emit('context-click-active', false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
class="l-browse-bar__object-name--w c-object-label"
|
||||
>
|
||||
<div class="c-object-label__type-icon"
|
||||
:class="type.cssClass"
|
||||
:class="type.definition.cssClass"
|
||||
></div>
|
||||
<span class="l-browse-bar__object-name c-object-label__name">
|
||||
{{ domainObject.name }}
|
||||
|
||||
Reference in New Issue
Block a user