fix(#7456): allow children of Overlay Plots to be removed (#7516)

* fix(#7456): check if object is an identifier

* refactor: use v-show, remove unnecessary deep copy, set yAxes array to empty in a way that preserves reactivity

* refactor: use ESM exports

* refactor: use ESM imports

* test(e2e): add test for element item removal from overlay plot

* a11y: add accessible name for object labels

* refactor: move overlayPlot creation to beforeAll, use getByLabel
This commit is contained in:
Jesse Mazzella 2024-02-21 16:07:48 -08:00 committed by GitHub
parent 6393a77c19
commit 29d83e9c6d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 223 additions and 152 deletions

View File

@ -33,15 +33,15 @@ import {
import { expect, test } from '../../../../pluginFixtures.js'; import { expect, test } from '../../../../pluginFixtures.js';
test.describe('Overlay Plot', () => { test.describe('Overlay Plot', () => {
let overlayPlot;
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
await page.goto('./', { waitUntil: 'domcontentloaded' }); await page.goto('./', { waitUntil: 'domcontentloaded' });
overlayPlot = await createDomainObjectWithDefaults(page, {
type: 'Overlay Plot'
});
}); });
test('Plot legend color is in sync with plot series color', async ({ page }) => { test('Plot legend color is in sync with plot series color', async ({ page }) => {
const overlayPlot = await createDomainObjectWithDefaults(page, {
type: 'Overlay Plot'
});
await createDomainObjectWithDefaults(page, { await createDomainObjectWithDefaults(page, {
type: 'Sine Wave Generator', type: 'Sine Wave Generator',
parent: overlayPlot.uuid parent: overlayPlot.uuid
@ -68,9 +68,6 @@ test.describe('Overlay Plot', () => {
type: 'issue', type: 'issue',
description: 'https://github.com/nasa/openmct/issues/7403' description: 'https://github.com/nasa/openmct/issues/7403'
}); });
const overlayPlot = await createDomainObjectWithDefaults(page, {
type: 'Overlay Plot'
});
await createDomainObjectWithDefaults(page, { await createDomainObjectWithDefaults(page, {
type: 'Sine Wave Generator', type: 'Sine Wave Generator',
@ -130,10 +127,6 @@ test.describe('Overlay Plot', () => {
type: 'issue', type: 'issue',
description: 'https://github.com/nasa/openmct/issues/6338' description: 'https://github.com/nasa/openmct/issues/6338'
}); });
// Create an Overlay Plot with a default SWG
const overlayPlot = await createDomainObjectWithDefaults(page, {
type: 'Overlay Plot'
});
const swgA = await createDomainObjectWithDefaults(page, { const swgA = await createDomainObjectWithDefaults(page, {
type: 'Sine Wave Generator', type: 'Sine Wave Generator',
@ -199,10 +192,6 @@ test.describe('Overlay Plot', () => {
test('The elements pool supports dragging series into multiple y-axis buckets', async ({ test('The elements pool supports dragging series into multiple y-axis buckets', async ({
page page
}) => { }) => {
const overlayPlot = await createDomainObjectWithDefaults(page, {
type: 'Overlay Plot'
});
const swgA = await createDomainObjectWithDefaults(page, { const swgA = await createDomainObjectWithDefaults(page, {
type: 'Sine Wave Generator', type: 'Sine Wave Generator',
parent: overlayPlot.uuid parent: overlayPlot.uuid
@ -292,10 +281,6 @@ test.describe('Overlay Plot', () => {
description: 'https://github.com/nasa/openmct/issues/7421' description: 'https://github.com/nasa/openmct/issues/7421'
}); });
const overlayPlot = await createDomainObjectWithDefaults(page, {
type: 'Overlay Plot'
});
const swgA = await createDomainObjectWithDefaults(page, { const swgA = await createDomainObjectWithDefaults(page, {
type: 'Sine Wave Generator', type: 'Sine Wave Generator',
parent: overlayPlot.uuid parent: overlayPlot.uuid
@ -309,12 +294,32 @@ test.describe('Overlay Plot', () => {
await page.getByRole('tab', { name: 'Elements' }).click(); await page.getByRole('tab', { name: 'Elements' }).click();
await page.locator(`#inspector-elements-tree >> text=${swgA.name}`).click(); await page.locator(`#inspector-elements-tree >> text=${swgA.name}`).click();
const plotPixels = await getCanvasPixels(page, '.js-overlay canvas'); const plotPixels = await getCanvasPixels(page, '.js-overlay canvas');
const plotPixelSize = plotPixels.length; const plotPixelSize = plotPixels.length;
expect(plotPixelSize).toBeGreaterThan(0); expect(plotPixelSize).toBeGreaterThan(0);
} }
); );
test('Can remove an item via the elements pool action menu', async ({ page }) => {
const swgA = await createDomainObjectWithDefaults(page, {
type: 'Sine Wave Generator',
parent: overlayPlot.uuid
});
await page.goto(overlayPlot.url);
// Wait for plot series data to load and be drawn
await waitForPlotsToRender(page);
await page.getByLabel('Edit Object').click();
await page.getByRole('tab', { name: 'Elements' }).click();
const swgAElementsPoolItem = page.getByLabel(`Preview ${swgA.name}`);
await expect(swgAElementsPoolItem).toBeVisible();
await swgAElementsPoolItem.click({ button: 'right' });
await page.getByRole('menuitem', { name: 'Remove' }).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
await expect(swgAElementsPoolItem).toBeHidden();
});
}); });
/** /**

View File

@ -21,7 +21,7 @@
*****************************************************************************/ *****************************************************************************/
import _ from 'lodash'; import _ from 'lodash';
import objectUtils from '../objects/object-utils.js'; import { makeKeyString, parseKeyString } from '../objects/object-utils.js';
/** /**
* @typedef {import('../objects/ObjectAPI').DomainObject} DomainObject * @typedef {import('../objects/ObjectAPI').DomainObject} DomainObject
@ -223,18 +223,18 @@ export default class CompositionProvider {
* @param {DomainObject} oldDomainObject * @param {DomainObject} oldDomainObject
*/ */
#onMutation(newDomainObject, oldDomainObject) { #onMutation(newDomainObject, oldDomainObject) {
const id = objectUtils.makeKeyString(oldDomainObject.identifier); const id = makeKeyString(oldDomainObject.identifier);
const listeners = this.#listeningTo[id]; const listeners = this.#listeningTo[id];
if (!listeners) { if (!listeners) {
return; return;
} }
const oldComposition = oldDomainObject.composition.map(objectUtils.makeKeyString); const oldComposition = oldDomainObject.composition.map(makeKeyString);
const newComposition = newDomainObject.composition.map(objectUtils.makeKeyString); const newComposition = newDomainObject.composition.map(makeKeyString);
const added = _.difference(newComposition, oldComposition).map(objectUtils.parseKeyString); const added = _.difference(newComposition, oldComposition).map(parseKeyString);
const removed = _.difference(oldComposition, newComposition).map(objectUtils.parseKeyString); const removed = _.difference(oldComposition, newComposition).map(parseKeyString);
function notify(value) { function notify(value) {
return function (listener) { return function (listener) {

View File

@ -21,7 +21,7 @@
*****************************************************************************/ *****************************************************************************/
import { toRaw } from 'vue'; import { toRaw } from 'vue';
import objectUtils from '../objects/object-utils.js'; import { makeKeyString } from '../objects/object-utils.js';
import CompositionProvider from './CompositionProvider.js'; import CompositionProvider from './CompositionProvider.js';
/** /**
@ -91,7 +91,7 @@ export default class DefaultCompositionProvider extends CompositionProvider {
this.establishTopicListener(); this.establishTopicListener();
/** @type {string} */ /** @type {string} */
const keyString = objectUtils.makeKeyString(domainObject.identifier); const keyString = makeKeyString(domainObject.identifier);
let objectListeners = this.listeningTo[keyString]; let objectListeners = this.listeningTo[keyString];
if (!objectListeners) { if (!objectListeners) {
@ -120,7 +120,7 @@ export default class DefaultCompositionProvider extends CompositionProvider {
*/ */
off(domainObject, event, callback, context) { off(domainObject, event, callback, context) {
/** @type {string} */ /** @type {string} */
const keyString = objectUtils.makeKeyString(domainObject.identifier); const keyString = makeKeyString(domainObject.identifier);
const objectListeners = this.listeningTo[keyString]; const objectListeners = this.listeningTo[keyString];
const index = objectListeners[event].findIndex((l) => { const index = objectListeners[event].findIndex((l) => {
@ -228,7 +228,7 @@ export default class DefaultCompositionProvider extends CompositionProvider {
this.publicAPI.objects.mutate(domainObject, 'composition', newComposition); this.publicAPI.objects.mutate(domainObject, 'composition', newComposition);
/** @type {string} */ /** @type {string} */
let id = objectUtils.makeKeyString(domainObject.identifier); let id = makeKeyString(domainObject.identifier);
const listeners = this.listeningTo[id]; const listeners = this.listeningTo[id];
if (!listeners) { if (!listeners) {

View File

@ -22,7 +22,7 @@
import EventEmitter from 'EventEmitter'; import EventEmitter from 'EventEmitter';
import _ from 'lodash'; import _ from 'lodash';
import utils from './object-utils.js'; import { makeKeyString, refresh } from './object-utils.js';
const ANY_OBJECT_EVENT = 'mutation'; const ANY_OBJECT_EVENT = 'mutation';
@ -152,7 +152,7 @@ class MutableDomainObject {
mutable.$observe('$_synchronize_model', (updatedObject) => { mutable.$observe('$_synchronize_model', (updatedObject) => {
let clone = JSON.parse(JSON.stringify(updatedObject)); let clone = JSON.parse(JSON.stringify(updatedObject));
utils.refresh(mutable, clone); refresh(mutable, clone);
}); });
return mutable; return mutable;
@ -168,7 +168,7 @@ class MutableDomainObject {
} }
function qualifiedEventName(object, eventName) { function qualifiedEventName(object, eventName) {
let keystring = utils.makeKeyString(object.identifier); let keystring = makeKeyString(object.identifier);
return [keystring, eventName].join(':'); return [keystring, eventName].join(':');
} }

View File

@ -21,7 +21,7 @@
*****************************************************************************/ *****************************************************************************/
import EventEmitter from 'EventEmitter'; import EventEmitter from 'EventEmitter';
import utils from 'objectUtils'; import { identifierEquals, makeKeyString, parseKeyString, refresh } from 'objectUtils';
import ConflictError from './ConflictError.js'; import ConflictError from './ConflictError.js';
import InMemorySearchProvider from './InMemorySearchProvider.js'; import InMemorySearchProvider from './InMemorySearchProvider.js';
@ -82,8 +82,19 @@ import Transaction from './Transaction.js';
* @memberof module:openmct * @memberof module:openmct
*/ */
export default class ObjectAPI { export default class ObjectAPI {
#makeKeyString;
#parseKeyString;
#identifierEquals;
#refresh;
#openmct;
constructor(typeRegistry, openmct) { constructor(typeRegistry, openmct) {
this.openmct = openmct; this.#makeKeyString = makeKeyString;
this.#parseKeyString = parseKeyString;
this.#identifierEquals = identifierEquals;
this.#refresh = refresh;
this.#openmct = openmct;
this.typeRegistry = typeRegistry; this.typeRegistry = typeRegistry;
this.SEARCH_TYPES = Object.freeze({ this.SEARCH_TYPES = Object.freeze({
OBJECTS: 'OBJECTS', OBJECTS: 'OBJECTS',
@ -206,14 +217,14 @@ export default class ObjectAPI {
* has been saved, or be rejected if it cannot be saved * has been saved, or be rejected if it cannot be saved
*/ */
get(identifier, abortSignal, forceRemote = false) { get(identifier, abortSignal, forceRemote = false) {
let keystring = this.makeKeyString(identifier); let keystring = this.#makeKeyString(identifier);
if (!forceRemote) { if (!forceRemote) {
if (this.cache[keystring] !== undefined) { if (this.cache[keystring] !== undefined) {
return this.cache[keystring]; return this.cache[keystring];
} }
identifier = utils.parseKeyString(identifier); identifier = parseKeyString(identifier);
if (this.isTransactionActive()) { if (this.isTransactionActive()) {
let dirtyObject = this.transaction.getDirtyObject(identifier); let dirtyObject = this.transaction.getDirtyObject(identifier);
@ -227,7 +238,7 @@ export default class ObjectAPI {
const provider = this.getProvider(identifier); const provider = this.getProvider(identifier);
if (!provider) { if (!provider) {
throw new Error(`No Provider Matched for keyString "${this.makeKeyString(identifier)}"`); throw new Error(`No Provider Matched for keyString "${this.#makeKeyString(identifier)}"`);
} }
if (!provider.get) { if (!provider.get) {
@ -325,7 +336,7 @@ export default class ObjectAPI {
*/ */
getMutable(identifier) { getMutable(identifier) {
if (!this.supportsMutation(identifier)) { if (!this.supportsMutation(identifier)) {
throw new Error(`Object "${this.makeKeyString(identifier)}" does not support mutation.`); throw new Error(`Object "${this.#makeKeyString(identifier)}" does not support mutation.`);
} }
return this.get(identifier).then((object) => { return this.get(identifier).then((object) => {
@ -352,7 +363,7 @@ export default class ObjectAPI {
} }
isPersistable(idOrKeyString) { isPersistable(idOrKeyString) {
let identifier = utils.parseKeyString(idOrKeyString); let identifier = parseKeyString(idOrKeyString);
let provider = this.getProvider(identifier); let provider = this.getProvider(identifier);
if (provider?.isReadOnly) { if (provider?.isReadOnly) {
return !provider.isReadOnly(); return !provider.isReadOnly();
@ -362,7 +373,7 @@ export default class ObjectAPI {
} }
isMissing(domainObject) { isMissing(domainObject) {
let identifier = utils.makeKeyString(domainObject.identifier); let identifier = makeKeyString(domainObject.identifier);
let missingName = 'Missing: ' + identifier; let missingName = 'Missing: ' + identifier;
return domainObject.name === missingName; return domainObject.name === missingName;
@ -442,21 +453,21 @@ export default class ObjectAPI {
if (error instanceof this.errors.Conflict) { if (error instanceof this.errors.Conflict) {
// Synchronized objects will resolve their own conflicts // Synchronized objects will resolve their own conflicts
if (this.SYNCHRONIZED_OBJECT_TYPES.includes(domainObject.type)) { if (this.SYNCHRONIZED_OBJECT_TYPES.includes(domainObject.type)) {
this.openmct.notifications.info( this.#openmct.notifications.info(
`Conflict detected while saving "${this.makeKeyString( `Conflict detected while saving "${this.#makeKeyString(
domainObject.name domainObject.name
)}", attempting to resolve` )}", attempting to resolve`
); );
} else { } else {
this.openmct.notifications.error( this.#openmct.notifications.error(
`Conflict detected while saving ${this.makeKeyString(domainObject.identifier)}` `Conflict detected while saving ${this.#makeKeyString(domainObject.identifier)}`
); );
if (this.isTransactionActive()) { if (this.isTransactionActive()) {
this.endTransaction(); this.endTransaction();
} }
await this.refresh(domainObject); await this.#refresh(domainObject);
} }
} }
@ -465,7 +476,7 @@ export default class ObjectAPI {
} }
async #getCurrentUsername() { async #getCurrentUsername() {
const user = await this.openmct.user.getCurrentUser(); const user = await this.#openmct.user.getCurrentUser();
let username; let username;
if (user !== undefined) { if (user !== undefined) {
@ -554,7 +565,7 @@ export default class ObjectAPI {
*/ */
getRelativePath(objectPath) { getRelativePath(objectPath) {
return objectPath return objectPath
.map((p) => this.makeKeyString(p.identifier)) .map((p) => this.#makeKeyString(p.identifier))
.reverse() .reverse()
.join('/'); .join('/');
} }
@ -574,13 +585,13 @@ export default class ObjectAPI {
} }
let sourceTelemetry = null; let sourceTelemetry = null;
if (telemetryIdentifier && utils.identifierEquals(identifier, telemetryIdentifier)) { if (telemetryIdentifier && this.#identifierEquals(identifier, telemetryIdentifier)) {
sourceTelemetry = identifier; sourceTelemetry = identifier;
} else if (objectDetails.composition) { } else if (objectDetails.composition) {
sourceTelemetry = objectDetails.composition[0]; sourceTelemetry = objectDetails.composition[0];
if (telemetryIdentifier) { if (telemetryIdentifier) {
sourceTelemetry = objectDetails.composition.find((telemetrySource) => sourceTelemetry = objectDetails.composition.find((telemetrySource) =>
utils.identifierEquals(telemetrySource, telemetryIdentifier) this.#identifierEquals(telemetrySource, telemetryIdentifier)
); );
} }
} }
@ -666,7 +677,7 @@ export default class ObjectAPI {
mutableObject = MutableDomainObject.createMutable(domainObject, this.eventEmitter); mutableObject = MutableDomainObject.createMutable(domainObject, this.eventEmitter);
// Check if provider supports realtime updates // Check if provider supports realtime updates
let identifier = utils.parseKeyString(mutableObject.identifier); let identifier = parseKeyString(mutableObject.identifier);
let provider = this.getProvider(identifier); let provider = this.getProvider(identifier);
if ( if (
@ -706,7 +717,7 @@ export default class ObjectAPI {
if (domainObject.isMutable) { if (domainObject.isMutable) {
domainObject.$refresh(refreshedObject); domainObject.$refresh(refreshedObject);
} else { } else {
utils.refresh(domainObject, refreshedObject); refresh(domainObject, refreshedObject);
} }
return domainObject; return domainObject;
@ -745,7 +756,7 @@ export default class ObjectAPI {
* @returns {string} A string representation of the given identifier, including namespace and key * @returns {string} A string representation of the given identifier, including namespace and key
*/ */
makeKeyString(identifier) { makeKeyString(identifier) {
return utils.makeKeyString(identifier); return makeKeyString(identifier);
} }
/** /**
@ -753,7 +764,7 @@ export default class ObjectAPI {
* @returns {module:openmct.ObjectAPI~Identifier} An identifier object * @returns {module:openmct.ObjectAPI~Identifier} An identifier object
*/ */
parseKeyString(keyString) { parseKeyString(keyString) {
return utils.parseKeyString(keyString); return parseKeyString(keyString);
} }
/** /**
@ -761,9 +772,9 @@ export default class ObjectAPI {
* @param {module:openmct.ObjectAPI~Identifier[]} identifiers * @param {module:openmct.ObjectAPI~Identifier[]} identifiers
*/ */
areIdsEqual(...identifiers) { areIdsEqual(...identifiers) {
const firstIdentifier = utils.parseKeyString(identifiers[0]); const firstIdentifier = this.#parseKeyString(identifiers[0]);
return identifiers.map(utils.parseKeyString).every((identifier) => { return identifiers.map(this.#parseKeyString).every((identifier) => {
return ( return (
identifier === firstIdentifier || identifier === firstIdentifier ||
(identifier.namespace === firstIdentifier.namespace && (identifier.namespace === firstIdentifier.namespace &&
@ -791,7 +802,7 @@ export default class ObjectAPI {
} }
return path.some((pathElement) => { return path.some((pathElement) => {
const identifierToCheck = utils.parseKeyString(keyStringToCheck); const identifierToCheck = this.#parseKeyString(keyStringToCheck);
return this.areIdsEqual(identifierToCheck, pathElement.identifier); return this.areIdsEqual(identifierToCheck, pathElement.identifier);
}); });
@ -814,7 +825,7 @@ export default class ObjectAPI {
if (location && !this.#pathContainsDomainObject(location, path)) { if (location && !this.#pathContainsDomainObject(location, path)) {
// if we have a location, and we don't already have this in our constructed path, // if we have a location, and we don't already have this in our constructed path,
// then keep walking up the path // then keep walking up the path
return this.getOriginalPath(utils.parseKeyString(location), path, abortSignal); return this.getOriginalPath(this.#parseKeyString(location), path, abortSignal);
} else { } else {
return path; return path;
} }
@ -853,8 +864,8 @@ export default class ObjectAPI {
await Promise.all( await Promise.all(
keyStrings.map((keyString) => keyStrings.map((keyString) =>
this.supportsMutation(keyString) this.supportsMutation(keyString)
? this.getMutable(utils.parseKeyString(keyString)) ? this.getMutable(this.#parseKeyString(keyString))
: this.get(utils.parseKeyString(keyString)) : this.get(this.#parseKeyString(keyString))
) )
) )
).reverse(); ).reverse();
@ -866,7 +877,7 @@ export default class ObjectAPI {
return ( return (
objectPath !== undefined && objectPath !== undefined &&
objectPath.length > 1 && objectPath.length > 1 &&
domainObject.location !== this.makeKeyString(objectPath[1].identifier) domainObject.location !== this.#makeKeyString(objectPath[1].identifier)
); );
} }

View File

@ -20,7 +20,7 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
import utils from './object-utils.js'; import { isIdentifier } from './object-utils.js';
export default class RootRegistry { export default class RootRegistry {
constructor(openmct) { constructor(openmct) {
@ -47,12 +47,12 @@ export default class RootRegistry {
} }
_isValid(rootItem) { _isValid(rootItem) {
if (utils.isIdentifier(rootItem) || typeof rootItem === 'function') { if (isIdentifier(rootItem) || typeof rootItem === 'function') {
return true; return true;
} }
if (Array.isArray(rootItem)) { if (Array.isArray(rootItem)) {
return rootItem.every(utils.isIdentifier); return rootItem.every(isIdentifier);
} }
return false; return false;

View File

@ -1,4 +1,4 @@
import utils from 'objectUtils'; import { makeKeyString, parseKeyString } from 'objectUtils';
import Transaction from './Transaction.js'; import Transaction from './Transaction.js';
@ -9,7 +9,7 @@ let transaction;
describe('Transaction Class', () => { describe('Transaction Class', () => {
beforeEach(() => { beforeEach(() => {
objectAPI = { objectAPI = {
makeKeyString: (identifier) => utils.makeKeyString(identifier), makeKeyString: (identifier) => makeKeyString(identifier),
save: () => Promise.resolve(true), save: () => Promise.resolve(true),
mutate: (object, prop, value) => { mutate: (object, prop, value) => {
object[prop] = value; object[prop] = value;
@ -18,7 +18,7 @@ describe('Transaction Class', () => {
}, },
refresh: (object) => Promise.resolve(object), refresh: (object) => Promise.resolve(object),
areIdsEqual: (...identifiers) => { areIdsEqual: (...identifiers) => {
return identifiers.map(utils.parseKeyString).every((identifier) => { return identifiers.map(parseKeyString).every((identifier) => {
return ( return (
identifier === identifiers[0] || identifier === identifiers[0] ||
(identifier.namespace === identifiers[0].namespace && (identifier.namespace === identifiers[0].namespace &&

View File

@ -24,7 +24,7 @@
* Utility for checking if a thing is an Open MCT Identifier. * Utility for checking if a thing is an Open MCT Identifier.
* @private * @private
*/ */
function isIdentifier(thing) { export function isIdentifier(thing) {
return ( return (
typeof thing === 'object' && typeof thing === 'object' &&
Object.prototype.hasOwnProperty.call(thing, 'key') && Object.prototype.hasOwnProperty.call(thing, 'key') &&
@ -36,7 +36,7 @@ function isIdentifier(thing) {
* Utility for checking if a thing is a key string. Not perfect. * Utility for checking if a thing is a key string. Not perfect.
* @private * @private
*/ */
function isKeyString(thing) { export function isKeyString(thing) {
return typeof thing === 'string'; return typeof thing === 'string';
} }
@ -49,7 +49,7 @@ function isKeyString(thing) {
* @param keyString * @param keyString
* @returns identifier * @returns identifier
*/ */
function parseKeyString(keyString) { export function parseKeyString(keyString) {
if (isIdentifier(keyString)) { if (isIdentifier(keyString)) {
return keyString; return keyString;
} }
@ -86,7 +86,7 @@ function parseKeyString(keyString) {
* @param identifier * @param identifier
* @returns keyString * @returns keyString
*/ */
function makeKeyString(identifier) { export function makeKeyString(identifier) {
if (!identifier) { if (!identifier) {
throw new Error('Cannot make key string from null identifier'); throw new Error('Cannot make key string from null identifier');
} }
@ -112,7 +112,7 @@ function makeKeyString(identifier) {
* @param domainObject * @param domainObject
* @returns oldFormatModel * @returns oldFormatModel
*/ */
function toOldFormat(model) { export function toOldFormat(model) {
model = JSON.parse(JSON.stringify(model)); model = JSON.parse(JSON.stringify(model));
delete model.identifier; delete model.identifier;
if (model.composition) { if (model.composition) {
@ -131,7 +131,7 @@ function toOldFormat(model) {
* @param keyString * @param keyString
* @returns domainObject * @returns domainObject
*/ */
function toNewFormat(model, keyString) { export function toNewFormat(model, keyString) {
model = JSON.parse(JSON.stringify(model)); model = JSON.parse(JSON.stringify(model));
model.identifier = parseKeyString(keyString); model.identifier = parseKeyString(keyString);
if (model.composition) { if (model.composition) {
@ -148,7 +148,7 @@ function toNewFormat(model, keyString) {
* @param otherIdentifier * @param otherIdentifier
* @returns Boolean true if identifiers are equal. * @returns Boolean true if identifiers are equal.
*/ */
function identifierEquals(a, b) { export function identifierEquals(a, b) {
return a.key === b.key && a.namespace === b.namespace; return a.key === b.key && a.namespace === b.namespace;
} }
@ -160,23 +160,12 @@ function identifierEquals(a, b) {
* @param otherDomainOBject * @param otherDomainOBject
* @returns Boolean true if objects are equal. * @returns Boolean true if objects are equal.
*/ */
function objectEquals(a, b) { export function objectEquals(a, b) {
return identifierEquals(a.identifier, b.identifier); return identifierEquals(a.identifier, b.identifier);
} }
function refresh(oldObject, newObject) { export function refresh(oldObject, newObject) {
let deleted = _.difference(Object.keys(oldObject), Object.keys(newObject)); let deleted = _.difference(Object.keys(oldObject), Object.keys(newObject));
deleted.forEach((propertyName) => delete oldObject[propertyName]); deleted.forEach((propertyName) => delete oldObject[propertyName]);
Object.assign(oldObject, newObject); Object.assign(oldObject, newObject);
} }
export default {
isIdentifier: isIdentifier,
toOldFormat: toOldFormat,
toNewFormat: toNewFormat,
makeKeyString: makeKeyString,
parseKeyString: parseKeyString,
equals: objectEquals,
identifierEquals: identifierEquals,
refresh: refresh
};

View File

@ -1,4 +1,4 @@
import objectUtils from 'objectUtils'; import { makeKeyString, parseKeyString, toNewFormat, toOldFormat } from 'objectUtils';
describe('objectUtils', function () { describe('objectUtils', function () {
describe('keyString util', function () { describe('keyString util', function () {
@ -31,27 +31,27 @@ describe('objectUtils', function () {
Object.keys(EXPECTATIONS).forEach(function (keyString) { Object.keys(EXPECTATIONS).forEach(function (keyString) {
it('parses "' + keyString + '".', function () { it('parses "' + keyString + '".', function () {
expect(objectUtils.parseKeyString(keyString)).toEqual(EXPECTATIONS[keyString]); expect(parseKeyString(keyString)).toEqual(EXPECTATIONS[keyString]);
}); });
it('parses and re-encodes "' + keyString + '"', function () { it('parses and re-encodes "' + keyString + '"', function () {
const identifier = objectUtils.parseKeyString(keyString); const identifier = parseKeyString(keyString);
expect(objectUtils.makeKeyString(identifier)).toEqual(keyString); expect(makeKeyString(identifier)).toEqual(keyString);
}); });
it('is idempotent for "' + keyString + '".', function () { it('is idempotent for "' + keyString + '".', function () {
const identifier = objectUtils.parseKeyString(keyString); const identifier = parseKeyString(keyString);
let again = objectUtils.parseKeyString(identifier); let again = parseKeyString(identifier);
expect(identifier).toEqual(again); expect(identifier).toEqual(again);
again = objectUtils.parseKeyString(again); again = parseKeyString(again);
again = objectUtils.parseKeyString(again); again = parseKeyString(again);
expect(identifier).toEqual(again); expect(identifier).toEqual(again);
let againKeyString = objectUtils.makeKeyString(again); let againKeyString = makeKeyString(again);
expect(againKeyString).toEqual(keyString); expect(againKeyString).toEqual(keyString);
againKeyString = objectUtils.makeKeyString(againKeyString); againKeyString = makeKeyString(againKeyString);
againKeyString = objectUtils.makeKeyString(againKeyString); againKeyString = makeKeyString(againKeyString);
againKeyString = objectUtils.makeKeyString(againKeyString); againKeyString = makeKeyString(againKeyString);
expect(againKeyString).toEqual(keyString); expect(againKeyString).toEqual(keyString);
}); });
}); });
@ -60,7 +60,7 @@ describe('objectUtils', function () {
describe('old object conversions', function () { describe('old object conversions', function () {
it('translate ids', function () { it('translate ids', function () {
expect( expect(
objectUtils.toNewFormat( toNewFormat(
{ {
prop: 'someValue' prop: 'someValue'
}, },
@ -77,7 +77,7 @@ describe('objectUtils', function () {
it('translates composition', function () { it('translates composition', function () {
expect( expect(
objectUtils.toNewFormat( toNewFormat(
{ {
prop: 'someValue', prop: 'someValue',
composition: ['anotherObjectId', 'scratch:anotherObjectId'] composition: ['anotherObjectId', 'scratch:anotherObjectId']
@ -107,7 +107,7 @@ describe('objectUtils', function () {
describe('new object conversions', function () { describe('new object conversions', function () {
it('removes ids', function () { it('removes ids', function () {
expect( expect(
objectUtils.toOldFormat({ toOldFormat({
prop: 'someValue', prop: 'someValue',
identifier: { identifier: {
namespace: '', namespace: '',
@ -121,7 +121,7 @@ describe('objectUtils', function () {
it('translates composition', function () { it('translates composition', function () {
expect( expect(
objectUtils.toOldFormat({ toOldFormat({
prop: 'someValue', prop: 'someValue',
composition: [ composition: [
{ {

View File

@ -20,7 +20,7 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
import objectUtils from 'objectUtils'; import { makeKeyString } from 'objectUtils';
import CustomStringFormatter from '../../plugins/displayLayout/CustomStringFormatter.js'; import CustomStringFormatter from '../../plugins/displayLayout/CustomStringFormatter.js';
import BatchingWebSocket from './BatchingWebSocket.js'; import BatchingWebSocket from './BatchingWebSocket.js';
@ -429,7 +429,7 @@ export default class TelemetryAPI {
this.#subscribeCache = {}; this.#subscribeCache = {};
} }
const keyString = objectUtils.makeKeyString(domainObject.identifier); const keyString = makeKeyString(domainObject.identifier);
const supportedStrategy = supportsBatching ? requestedStrategy : SUBSCRIBE_STRATEGY.LATEST; const supportedStrategy = supportsBatching ? requestedStrategy : SUBSCRIBE_STRATEGY.LATEST;
// Override the requested strategy with the strategy supported by the provider // Override the requested strategy with the strategy supported by the provider
const optionsWithSupportedStrategy = { const optionsWithSupportedStrategy = {
@ -541,7 +541,7 @@ export default class TelemetryAPI {
this.stalenessSubscriberCache = {}; this.stalenessSubscriberCache = {};
} }
const keyString = objectUtils.makeKeyString(domainObject.identifier); const keyString = makeKeyString(domainObject.identifier);
let stalenessSubscriber = this.stalenessSubscriberCache[keyString]; let stalenessSubscriber = this.stalenessSubscriberCache[keyString];
if (!stalenessSubscriber) { if (!stalenessSubscriber) {
@ -600,7 +600,7 @@ export default class TelemetryAPI {
this.limitsSubscribeCache = {}; this.limitsSubscribeCache = {};
} }
const keyString = objectUtils.makeKeyString(domainObject.identifier); const keyString = makeKeyString(domainObject.identifier);
let subscriber = this.limitsSubscribeCache[keyString]; let subscriber = this.limitsSubscribeCache[keyString];
if (!subscriber) { if (!subscriber) {

View File

@ -20,7 +20,7 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
import objectUtils from 'objectUtils'; import { parseKeyString } from 'objectUtils';
import { filter__proto__ } from 'utils/sanitization'; import { filter__proto__ } from 'utils/sanitization';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
@ -158,7 +158,7 @@ export default class ImportAsJSONAction {
key: uuid() key: uuid()
}; };
const oldId = objectUtils.parseKeyString(domainObjectId); const oldId = parseKeyString(domainObjectId);
tree = this._rewriteId(oldId, newId, tree); tree = this._rewriteId(oldId, newId, tree);
}, this); }, this);

View File

@ -23,6 +23,8 @@
<template> <template>
<li <li
draggable="true" draggable="true"
:aria-label="`${elementObject.name} Element Item`"
:aria-grabbed="hover"
@dragstart="emitDragStartEvent" @dragstart="emitDragStartEvent"
@dragenter="onDragenter" @dragenter="onDragenter"
@dragover.prevent @dragover.prevent
@ -76,16 +78,19 @@ export default {
}, },
emits: ['drop-custom', 'dragstart-custom'], emits: ['drop-custom', 'dragstart-custom'],
data() { data() {
const isAlias =
this.elementObject.location !==
this.openmct.objects.makeKeyString(this.domainObject.identifier);
return { return {
contextClickActive: false, contextClickActive: false,
hover: false, hover: false
isAlias
}; };
}, },
computed: {
isAlias() {
return (
this.elementObject.location !==
this.openmct.objects.makeKeyString(this.domainObject.identifier)
);
}
},
methods: { methods: {
emitDropEvent(event) { emitDropEvent(event) {
this.$emit('drop-custom', event); this.$emit('drop-custom', event);

View File

@ -30,7 +30,7 @@
/> />
<div class="c-elements-pool__elements"> <div class="c-elements-pool__elements">
<ul <ul
v-if="hasElements" v-show="hasElements"
id="inspector-elements-tree" id="inspector-elements-tree"
class="c-tree c-elements-pool__tree js-elements-pool__tree" class="c-tree c-elements-pool__tree js-elements-pool__tree"
> >
@ -63,7 +63,7 @@
></li> ></li>
</element-item-group> </element-item-group>
</ul> </ul>
<div v-if="!hasElements">No contained elements</div> <div v-show="!hasElements">No contained elements</div>
</div> </div>
</div> </div>
</template> </template>
@ -169,7 +169,8 @@ export default {
setYAxisIds() { setYAxisIds() {
const configId = this.openmct.objects.makeKeyString(this.parentObject.identifier); const configId = this.openmct.objects.makeKeyString(this.parentObject.identifier);
this.config = configStore.get(configId); this.config = configStore.get(configId);
this.yAxes = []; // Clear the yAxes array and repopulate it with the current YAxis elements
this.yAxes.splice(0);
this.yAxes.push({ this.yAxes.push({
id: this.config.yAxis.id, id: this.config.yAxis.id,
elements: this.parentObject.configuration.series.filter( elements: this.parentObject.configuration.series.filter(
@ -207,7 +208,7 @@ export default {
} }
// Store the element in the cache and set its yAxisId // Store the element in the cache and set its yAxisId
this.elementsCache[keyString] = JSON.parse(JSON.stringify(element)); this.elementsCache[keyString] = element;
if (this.elementsCache[keyString].yAxisId !== yAxisId) { if (this.elementsCache[keyString].yAxisId !== yAxisId) {
// Mutate the YAxisId on the domainObject itself // Mutate the YAxisId on the domainObject itself
this.updateCacheAndMutate(element, yAxisId); this.updateCacheAndMutate(element, yAxisId);
@ -276,7 +277,7 @@ export default {
yAxisId yAxisId
}); });
this.composition.add(domainObject); this.composition.add(domainObject);
this.elementsCache[keyString] = JSON.parse(JSON.stringify(domainObject)); this.elementsCache[keyString] = domainObject;
} }
this.elementsCache[keyString].yAxisId = yAxisId; this.elementsCache[keyString].yAxisId = yAxisId;

View File

@ -1,4 +1,4 @@
import objectUtils from 'objectUtils'; import { makeKeyString } from 'objectUtils';
const NOTEBOOK_LOCAL_STORAGE = 'notebook-storage'; const NOTEBOOK_LOCAL_STORAGE = 'notebook-storage';
let currentNotebookObjectIdentifier = null; let currentNotebookObjectIdentifier = null;
@ -22,8 +22,7 @@ function defaultNotebookObjectChanged(newDomainObject) {
function observeDefaultNotebookObject(openmct, notebookStorage, domainObject) { function observeDefaultNotebookObject(openmct, notebookStorage, domainObject) {
if ( if (
currentNotebookObjectIdentifier && currentNotebookObjectIdentifier &&
objectUtils.makeKeyString(currentNotebookObjectIdentifier) === makeKeyString(currentNotebookObjectIdentifier) === makeKeyString(notebookStorage.identifier)
objectUtils.makeKeyString(notebookStorage.identifier)
) { ) {
return; return;
} }

View File

@ -26,7 +26,7 @@
* rootIdentifier, and rewrites all child object identifiers so that they * rootIdentifier, and rewrites all child object identifiers so that they
* exist in the same namespace as the rootIdentifier. * exist in the same namespace as the rootIdentifier.
*/ */
import objectUtils from 'objectUtils'; import { makeKeyString, parseKeyString, toNewFormat } from 'objectUtils';
class StaticModelProvider { class StaticModelProvider {
constructor(importData, rootIdentifier) { constructor(importData, rootIdentifier) {
@ -38,7 +38,7 @@ class StaticModelProvider {
* Standard "Get". * Standard "Get".
*/ */
get(identifier) { get(identifier) {
const keyString = objectUtils.makeKeyString(identifier); const keyString = makeKeyString(identifier);
if (this.objectMap[keyString]) { if (this.objectMap[keyString]) {
return this.objectMap[keyString]; return this.objectMap[keyString];
} }
@ -49,7 +49,7 @@ class StaticModelProvider {
parseObjectLeaf(objectLeaf, idMap, newRootNamespace, oldRootNamespace) { parseObjectLeaf(objectLeaf, idMap, newRootNamespace, oldRootNamespace) {
Object.keys(objectLeaf).forEach((nodeKey) => { Object.keys(objectLeaf).forEach((nodeKey) => {
if (idMap.get(nodeKey)) { if (idMap.get(nodeKey)) {
const newIdentifier = objectUtils.makeKeyString({ const newIdentifier = makeKeyString({
namespace: newRootNamespace, namespace: newRootNamespace,
key: idMap.get(nodeKey) key: idMap.get(nodeKey)
}); });
@ -104,7 +104,7 @@ class StaticModelProvider {
let mappedLeafValue; let mappedLeafValue;
if (oldRootNamespace) { if (oldRootNamespace) {
mappedLeafValue = idMap.get( mappedLeafValue = idMap.get(
objectUtils.makeKeyString({ makeKeyString({
namespace: oldRootNamespace, namespace: oldRootNamespace,
key: leafValue key: leafValue
}) })
@ -125,7 +125,7 @@ class StaticModelProvider {
return null; return null;
} }
const newLocationIdentifier = objectUtils.makeKeyString({ const newLocationIdentifier = makeKeyString({
namespace: newRootNamespace, namespace: newRootNamespace,
key: mappedLeafValue key: mappedLeafValue
}); });
@ -134,7 +134,7 @@ class StaticModelProvider {
} else { } else {
const mappedLeafValue = idMap.get(leafValue); const mappedLeafValue = idMap.get(leafValue);
if (mappedLeafValue) { if (mappedLeafValue) {
const newIdentifier = objectUtils.makeKeyString({ const newIdentifier = makeKeyString({
namespace: newRootNamespace, namespace: newRootNamespace,
key: mappedLeafValue key: mappedLeafValue
}); });
@ -147,7 +147,7 @@ class StaticModelProvider {
} }
rewriteObjectIdentifiers(importData, rootIdentifier) { rewriteObjectIdentifiers(importData, rootIdentifier) {
const { namespace: oldRootNamespace } = objectUtils.parseKeyString(importData.rootId); const { namespace: oldRootNamespace } = parseKeyString(importData.rootId);
const { namespace: newRootNamespace } = rootIdentifier; const { namespace: newRootNamespace } = rootIdentifier;
const idMap = new Map(); const idMap = new Map();
const objectTree = importData.openmct; const objectTree = importData.openmct;
@ -172,7 +172,7 @@ class StaticModelProvider {
*/ */
convertToNewObjects(oldObjectMap) { convertToNewObjects(oldObjectMap) {
return Object.keys(oldObjectMap).reduce(function (newObjectMap, key) { return Object.keys(oldObjectMap).reduce(function (newObjectMap, key) {
newObjectMap[key] = objectUtils.toNewFormat(oldObjectMap[key], key); newObjectMap[key] = toNewFormat(oldObjectMap[key], key);
return newObjectMap; return newObjectMap;
}, {}); }, {});
@ -180,7 +180,7 @@ class StaticModelProvider {
/* Set the root location correctly for a top-level object */ /* Set the root location correctly for a top-level object */
setRootLocation(objectMap, rootIdentifier) { setRootLocation(objectMap, rootIdentifier) {
objectMap[objectUtils.makeKeyString(rootIdentifier)].location = 'ROOT'; objectMap[makeKeyString(rootIdentifier)].location = 'ROOT';
return objectMap; return objectMap;
} }

View File

@ -1,6 +1,6 @@
import EventEmitter from 'EventEmitter'; import EventEmitter from 'EventEmitter';
import _ from 'lodash'; import _ from 'lodash';
import objectUtils from 'objectUtils'; import { makeKeyString } from 'objectUtils';
import ConditionEvaluator from './ConditionEvaluator.js'; import ConditionEvaluator from './ConditionEvaluator.js';
@ -119,7 +119,7 @@ ConditionManager.prototype.addGlobalPropertyType = function (key, type) {
* has completed and types have been parsed * has completed and types have been parsed
*/ */
ConditionManager.prototype.parsePropertyTypes = function (object) { ConditionManager.prototype.parsePropertyTypes = function (object) {
const objectId = objectUtils.makeKeyString(object.identifier); const objectId = makeKeyString(object.identifier);
this.telemetryTypesById[objectId] = {}; this.telemetryTypesById[objectId] = {};
Object.values(this.telemetryMetadataById[objectId]).forEach(function (valueMetadata) { Object.values(this.telemetryMetadataById[objectId]).forEach(function (valueMetadata) {
@ -182,7 +182,7 @@ ConditionManager.prototype.createNormalizedDatum = function (objId, telemetryDat
ConditionManager.prototype.onCompositionAdd = function (obj) { ConditionManager.prototype.onCompositionAdd = function (obj) {
let compositionKeys; let compositionKeys;
const telemetryAPI = this.openmct.telemetry; const telemetryAPI = this.openmct.telemetry;
const objId = objectUtils.makeKeyString(obj.identifier); const objId = makeKeyString(obj.identifier);
let telemetryMetadata; let telemetryMetadata;
const self = this; const self = this;
@ -191,7 +191,7 @@ ConditionManager.prototype.onCompositionAdd = function (obj) {
self.telemetryMetadataById[objId] = {}; self.telemetryMetadataById[objId] = {};
// FIXME: this should just update based on listener. // FIXME: this should just update based on listener.
compositionKeys = self.domainObject.composition.map(objectUtils.makeKeyString); compositionKeys = self.domainObject.composition.map(makeKeyString);
if (!compositionKeys.includes(objId)) { if (!compositionKeys.includes(objId)) {
self.domainObject.composition.push(obj.identifier); self.domainObject.composition.push(obj.identifier);
} }
@ -245,7 +245,7 @@ ConditionManager.prototype.onCompositionAdd = function (obj) {
* @private * @private
*/ */
ConditionManager.prototype.onCompositionRemove = function (identifier) { ConditionManager.prototype.onCompositionRemove = function (identifier) {
const objectId = objectUtils.makeKeyString(identifier); const objectId = makeKeyString(identifier);
// FIXME: this should just update by listener. // FIXME: this should just update by listener.
_.remove(this.domainObject.composition, function (id) { _.remove(this.domainObject.composition, function (id) {
return id.key === identifier.key && id.namespace === identifier.namespace; return id.key === identifier.key && id.namespace === identifier.namespace;

View File

@ -1,4 +1,4 @@
import objectUtils from 'objectUtils'; import { makeKeyString } from 'objectUtils';
import Select from './Select.js'; import Select from './Select.js';
@ -39,7 +39,7 @@ export default function ObjectSelect(config, manager, baseOptions) {
* @private * @private
*/ */
function onCompositionAdd(obj) { function onCompositionAdd(obj) {
self.select.addOption(objectUtils.makeKeyString(obj.identifier), obj.name); self.select.addOption(makeKeyString(obj.identifier), obj.name);
} }
/** /**
@ -77,7 +77,7 @@ export default function ObjectSelect(config, manager, baseOptions) {
*/ */
ObjectSelect.prototype.generateOptions = function () { ObjectSelect.prototype.generateOptions = function () {
const items = Object.values(this.compositionObjs).map(function (obj) { const items = Object.values(this.compositionObjs).map(function (obj) {
return [objectUtils.makeKeyString(obj.identifier), obj.name]; return [makeKeyString(obj.identifier), obj.name];
}); });
this.baseOptions.forEach(function (option, index) { this.baseOptions.forEach(function (option, index) {
items.splice(index, 0, option); items.splice(index, 0, option);

View File

@ -20,7 +20,7 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
import objectUtils from 'objectUtils'; import { makeKeyString } from 'objectUtils';
import SummaryWidgetEvaluator from './SummaryWidgetEvaluator.js'; import SummaryWidgetEvaluator from './SummaryWidgetEvaluator.js';
@ -31,7 +31,7 @@ export default function EvaluatorPool(openmct) {
} }
EvaluatorPool.prototype.get = function (domainObject) { EvaluatorPool.prototype.get = function (domainObject) {
const objectId = objectUtils.makeKeyString(domainObject.identifier); const objectId = makeKeyString(domainObject.identifier);
let poolEntry = this.byObjectId[objectId]; let poolEntry = this.byObjectId[objectId];
if (!poolEntry) { if (!poolEntry) {
poolEntry = { poolEntry = {

View File

@ -21,7 +21,7 @@
*****************************************************************************/ *****************************************************************************/
import _ from 'lodash'; import _ from 'lodash';
import objectUtils from 'objectUtils'; import { makeKeyString } from 'objectUtils';
import eventHelpers from '../eventHelpers.js'; import eventHelpers from '../eventHelpers.js';
import SummaryWidgetRule from './SummaryWidgetRule.js'; import SummaryWidgetRule from './SummaryWidgetRule.js';
@ -113,7 +113,7 @@ SummaryWidgetEvaluator.prototype.updateRules = function (domainObject) {
}; };
SummaryWidgetEvaluator.prototype.addChild = function (childObject) { SummaryWidgetEvaluator.prototype.addChild = function (childObject) {
const childId = objectUtils.makeKeyString(childObject.identifier); const childId = makeKeyString(childObject.identifier);
const metadata = this.openmct.telemetry.getMetadata(childObject); const metadata = this.openmct.telemetry.getMetadata(childObject);
const formats = this.openmct.telemetry.getFormatMap(metadata); const formats = this.openmct.telemetry.getFormatMap(metadata);
@ -126,7 +126,7 @@ SummaryWidgetEvaluator.prototype.addChild = function (childObject) {
}; };
SummaryWidgetEvaluator.prototype.removeChild = function (childObject) { SummaryWidgetEvaluator.prototype.removeChild = function (childObject) {
const childId = objectUtils.makeKeyString(childObject.identifier); const childId = makeKeyString(childObject.identifier);
delete this.baseState[childId]; delete this.baseState[childId];
}; };

View File

@ -20,7 +20,7 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
import objectUtils from 'objectUtils'; import { parseKeyString } from 'objectUtils';
import TelemetryAverager from './TelemetryAverager.js'; import TelemetryAverager from './TelemetryAverager.js';
@ -43,7 +43,7 @@ MeanTelemetryProvider.prototype.supportsRequest =
MeanTelemetryProvider.prototype.subscribe = function (domainObject, callback) { MeanTelemetryProvider.prototype.subscribe = function (domainObject, callback) {
let wrappedUnsubscribe; let wrappedUnsubscribe;
let unsubscribeCalled = false; let unsubscribeCalled = false;
const objectId = objectUtils.parseKeyString(domainObject.telemetryPoint); const objectId = parseKeyString(domainObject.telemetryPoint);
const samples = domainObject.samples; const samples = domainObject.samples;
this.objectAPI this.objectAPI
@ -79,7 +79,7 @@ MeanTelemetryProvider.prototype.subscribeToAverage = function (domainObject, sam
}; };
MeanTelemetryProvider.prototype.request = function (domainObject, request) { MeanTelemetryProvider.prototype.request = function (domainObject, request) {
const objectId = objectUtils.parseKeyString(domainObject.telemetryPoint); const objectId = parseKeyString(domainObject.telemetryPoint);
const samples = domainObject.samples; const samples = domainObject.samples;
return this.objectAPI.get(objectId).then( return this.objectAPI.get(objectId).then(
@ -119,7 +119,7 @@ MeanTelemetryProvider.prototype.requestAverageTelemetry = function (
* @private * @private
*/ */
MeanTelemetryProvider.prototype.getLinkedObject = function (domainObject) { MeanTelemetryProvider.prototype.getLinkedObject = function (domainObject) {
const objectId = objectUtils.parseKeyString(domainObject.telemetryPoint); const objectId = parseKeyString(domainObject.telemetryPoint);
return this.objectAPI.get(objectId); return this.objectAPI.get(objectId);
}; };

View File

@ -25,6 +25,7 @@
class="c-tree__item__label c-object-label" class="c-tree__item__label c-object-label"
:class="[statusClass]" :class="[statusClass]"
draggable="true" draggable="true"
:aria-label="ariaLabel"
@dragstart="dragStart" @dragstart="dragStart"
@click="navigateOrPreview" @click="navigateOrPreview"
> >
@ -47,7 +48,10 @@
</template> </template>
<script> <script>
import { inject } from 'vue';
import tooltipHelpers from '../../api/tooltips/tooltipMixins.js'; import tooltipHelpers from '../../api/tooltips/tooltipMixins.js';
import { useIsEditing } from '../../ui/composables/edit.js';
import ContextMenuGesture from '../mixins/context-menu-gesture.js'; import ContextMenuGesture from '../mixins/context-menu-gesture.js';
import ObjectLink from '../mixins/object-link.js'; import ObjectLink from '../mixins/object-link.js';
import PreviewAction from '../preview/PreviewAction.js'; import PreviewAction from '../preview/PreviewAction.js';
@ -76,6 +80,13 @@ export default {
} }
} }
}, },
setup() {
const openmct = inject('openmct');
const { isEditing } = useIsEditing(openmct);
return {
isEditing
};
},
data() { data() {
return { return {
status: '' status: ''
@ -92,6 +103,9 @@ export default {
}, },
statusClass() { statusClass() {
return this.status ? `is-status--${this.status}` : ''; return this.status ? `is-status--${this.status}` : '';
},
ariaLabel() {
return `${this.isEditing ? 'Preview' : 'Navigate to'} ${this.domainObject.name} ${this.domainObject.type} Object`;
} }
}, },
mounted() { mounted() {

View File

@ -33,7 +33,7 @@ import StyleRuleManager from '@/plugins/condition/StyleRuleManager';
import { STYLE_CONSTANTS } from '@/plugins/condition/utils/constants'; import { STYLE_CONSTANTS } from '@/plugins/condition/utils/constants';
import stalenessMixin from '@/ui/mixins/staleness-mixin'; import stalenessMixin from '@/ui/mixins/staleness-mixin';
import objectUtils from '../../api/objects/object-utils.js'; import { objectEquals } from '../../api/objects/object-utils.js';
import VisibilityObserver from '../../utils/visibility/VisibilityObserver.js'; import VisibilityObserver from '../../utils/visibility/VisibilityObserver.js';
export default { export default {
@ -224,7 +224,7 @@ export default {
this.updateView(true); this.updateView(true);
}, },
reload(domainObjectToReload) { reload(domainObjectToReload) {
if (objectUtils.equals(domainObjectToReload, this.domainObject)) { if (objectEquals(domainObjectToReload, this.domainObject)) {
this.updateView(true); this.updateView(true);
this.initObjectStyles(); this.initObjectStyles();
this.triggerStalenessSubscribe(this.domainObject); this.triggerStalenessSubscribe(this.domainObject);

View File

@ -0,0 +1,43 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2024, 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 { ref } from 'vue';
import { useEventEmitter } from './event.js';
/**
* Provides a reactive `isEditing` property that reflects the current editing state of the
* application.
* @param {OpenMCT} openmct the Open MCT API
* @returns {{
* isEditing: import('vue').Ref<boolean>
* }}
*/
export function useIsEditing(openmct) {
const isEditing = ref(openmct.editor.isEditing());
useEventEmitter(openmct.editor, 'isEditing', (_isEditing) => {
isEditing.value = _isEditing;
});
return { isEditing };
}

View File

@ -22,6 +22,7 @@
import { isProxy, toRaw } from 'vue'; import { isProxy, toRaw } from 'vue';
import { isIdentifier } from '@/api/objects/object-utils';
import StalenessUtils from '@/utils/staleness'; import StalenessUtils from '@/utils/staleness';
export default { export default {
@ -40,7 +41,9 @@ export default {
}, },
methods: { methods: {
getSubscriptionId(domainObject) { getSubscriptionId(domainObject) {
return this.openmct?.objects.makeKeyString(domainObject.identifier); // Only extract the identifier if it is not already an identifier
const identifier = isIdentifier(domainObject) ? domainObject : domainObject.identifier;
return this.openmct?.objects.makeKeyString(identifier);
}, },
setupClockChangedEvent(callback) { setupClockChangedEvent(callback) {
this.setupClockChanged = true; this.setupClockChanged = true;
@ -97,6 +100,7 @@ export default {
if (isProxy(domainObject)) { if (isProxy(domainObject)) {
domainObject = toRaw(domainObject); domainObject = toRaw(domainObject);
} }
const id = this.getSubscriptionId(domainObject); const id = this.getSubscriptionId(domainObject);
if (!this.stalenessSubscription[id]) { if (!this.stalenessSubscription[id]) {
return; return;