From 40bff181764c74d8c8f364b834723e21ccbbd48d Mon Sep 17 00:00:00 2001 From: Jesse Mazzella Date: Tue, 20 Feb 2024 14:07:57 -0800 Subject: [PATCH 1/7] fix(#7456): check if object is an identifier --- src/ui/mixins/staleness-mixin.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ui/mixins/staleness-mixin.js b/src/ui/mixins/staleness-mixin.js index 232604d35b6..6e8ea291fc5 100644 --- a/src/ui/mixins/staleness-mixin.js +++ b/src/ui/mixins/staleness-mixin.js @@ -22,6 +22,7 @@ import { isProxy, toRaw } from 'vue'; +import { isIdentifier } from '@/api/objects/object-utils'; import StalenessUtils from '@/utils/staleness'; export default { @@ -40,7 +41,9 @@ export default { }, methods: { 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) { this.setupClockChanged = true; @@ -97,6 +100,7 @@ export default { if (isProxy(domainObject)) { domainObject = toRaw(domainObject); } + const id = this.getSubscriptionId(domainObject); if (!this.stalenessSubscription[id]) { return; From 9103a59228312137b390e2084cab82c7b7718dc3 Mon Sep 17 00:00:00 2001 From: Jesse Mazzella Date: Tue, 20 Feb 2024 14:08:48 -0800 Subject: [PATCH 2/7] refactor: use v-show, remove unnecessary deep copy, set yAxes array to empty in a way that preserves reactivity --- .../inspectorViews/elements/PlotElementsPool.vue | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/plugins/inspectorViews/elements/PlotElementsPool.vue b/src/plugins/inspectorViews/elements/PlotElementsPool.vue index f38eb709d98..79f6a0da211 100644 --- a/src/plugins/inspectorViews/elements/PlotElementsPool.vue +++ b/src/plugins/inspectorViews/elements/PlotElementsPool.vue @@ -30,7 +30,7 @@ />
    @@ -63,7 +63,7 @@ >
-
No contained elements
+
No contained elements
@@ -169,7 +169,8 @@ export default { setYAxisIds() { const configId = this.openmct.objects.makeKeyString(this.parentObject.identifier); 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({ id: this.config.yAxis.id, elements: this.parentObject.configuration.series.filter( @@ -207,7 +208,7 @@ export default { } // 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) { // Mutate the YAxisId on the domainObject itself this.updateCacheAndMutate(element, yAxisId); @@ -276,7 +277,7 @@ export default { yAxisId }); this.composition.add(domainObject); - this.elementsCache[keyString] = JSON.parse(JSON.stringify(domainObject)); + this.elementsCache[keyString] = domainObject; } this.elementsCache[keyString].yAxisId = yAxisId; From 99b394d538d0330155f34eed096f9b6532d4b2c2 Mon Sep 17 00:00:00 2001 From: Jesse Mazzella Date: Tue, 20 Feb 2024 14:09:07 -0800 Subject: [PATCH 3/7] refactor: use ESM exports --- src/api/objects/object-utils.js | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/src/api/objects/object-utils.js b/src/api/objects/object-utils.js index c6435d7996c..86ba2e88454 100644 --- a/src/api/objects/object-utils.js +++ b/src/api/objects/object-utils.js @@ -24,7 +24,7 @@ * Utility for checking if a thing is an Open MCT Identifier. * @private */ -function isIdentifier(thing) { +export function isIdentifier(thing) { return ( typeof thing === 'object' && 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. * @private */ -function isKeyString(thing) { +export function isKeyString(thing) { return typeof thing === 'string'; } @@ -49,7 +49,7 @@ function isKeyString(thing) { * @param keyString * @returns identifier */ -function parseKeyString(keyString) { +export function parseKeyString(keyString) { if (isIdentifier(keyString)) { return keyString; } @@ -86,7 +86,7 @@ function parseKeyString(keyString) { * @param identifier * @returns keyString */ -function makeKeyString(identifier) { +export function makeKeyString(identifier) { if (!identifier) { throw new Error('Cannot make key string from null identifier'); } @@ -112,7 +112,7 @@ function makeKeyString(identifier) { * @param domainObject * @returns oldFormatModel */ -function toOldFormat(model) { +export function toOldFormat(model) { model = JSON.parse(JSON.stringify(model)); delete model.identifier; if (model.composition) { @@ -131,7 +131,7 @@ function toOldFormat(model) { * @param keyString * @returns domainObject */ -function toNewFormat(model, keyString) { +export function toNewFormat(model, keyString) { model = JSON.parse(JSON.stringify(model)); model.identifier = parseKeyString(keyString); if (model.composition) { @@ -148,7 +148,7 @@ function toNewFormat(model, keyString) { * @param otherIdentifier * @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; } @@ -160,23 +160,12 @@ function identifierEquals(a, b) { * @param otherDomainOBject * @returns Boolean true if objects are equal. */ -function objectEquals(a, b) { +export function objectEquals(a, b) { return identifierEquals(a.identifier, b.identifier); } -function refresh(oldObject, newObject) { +export function refresh(oldObject, newObject) { let deleted = _.difference(Object.keys(oldObject), Object.keys(newObject)); deleted.forEach((propertyName) => delete oldObject[propertyName]); Object.assign(oldObject, newObject); } - -export default { - isIdentifier: isIdentifier, - toOldFormat: toOldFormat, - toNewFormat: toNewFormat, - makeKeyString: makeKeyString, - parseKeyString: parseKeyString, - equals: objectEquals, - identifierEquals: identifierEquals, - refresh: refresh -}; From bf8cc75165f44cd1502dfac78ec29459d1f8f605 Mon Sep 17 00:00:00 2001 From: Jesse Mazzella Date: Tue, 20 Feb 2024 14:09:41 -0800 Subject: [PATCH 4/7] refactor: use ESM imports --- src/api/composition/CompositionProvider.js | 12 ++-- .../composition/DefaultCompositionProvider.js | 8 +-- src/api/objects/MutableDomainObject.js | 6 +- src/api/objects/ObjectAPI.js | 67 +++++++++++-------- src/api/objects/RootRegistry.js | 6 +- src/api/objects/TransactionSpec.js | 6 +- src/api/objects/test/object-utilsSpec.js | 32 ++++----- src/api/telemetry/TelemetryAPI.js | 8 +-- .../ImportFromJSONAction.js | 4 +- .../notebook/utils/notebook-storage.js | 5 +- .../staticRootPlugin/StaticModelProvider.js | 18 ++--- .../summaryWidget/src/ConditionManager.js | 10 +-- .../summaryWidget/src/input/ObjectSelect.js | 6 +- .../src/telemetry/EvaluatorPool.js | 4 +- .../src/telemetry/SummaryWidgetEvaluator.js | 6 +- .../src/MeanTelemetryProvider.js | 8 +-- src/ui/components/ObjectView.vue | 4 +- 17 files changed, 110 insertions(+), 100 deletions(-) diff --git a/src/api/composition/CompositionProvider.js b/src/api/composition/CompositionProvider.js index 0b669f86e03..ec68648a687 100644 --- a/src/api/composition/CompositionProvider.js +++ b/src/api/composition/CompositionProvider.js @@ -21,7 +21,7 @@ *****************************************************************************/ import _ from 'lodash'; -import objectUtils from '../objects/object-utils.js'; +import { makeKeyString, parseKeyString } from '../objects/object-utils.js'; /** * @typedef {import('../objects/ObjectAPI').DomainObject} DomainObject @@ -223,18 +223,18 @@ export default class CompositionProvider { * @param {DomainObject} oldDomainObject */ #onMutation(newDomainObject, oldDomainObject) { - const id = objectUtils.makeKeyString(oldDomainObject.identifier); + const id = makeKeyString(oldDomainObject.identifier); const listeners = this.#listeningTo[id]; if (!listeners) { return; } - const oldComposition = oldDomainObject.composition.map(objectUtils.makeKeyString); - const newComposition = newDomainObject.composition.map(objectUtils.makeKeyString); + const oldComposition = oldDomainObject.composition.map(makeKeyString); + const newComposition = newDomainObject.composition.map(makeKeyString); - const added = _.difference(newComposition, oldComposition).map(objectUtils.parseKeyString); - const removed = _.difference(oldComposition, newComposition).map(objectUtils.parseKeyString); + const added = _.difference(newComposition, oldComposition).map(parseKeyString); + const removed = _.difference(oldComposition, newComposition).map(parseKeyString); function notify(value) { return function (listener) { diff --git a/src/api/composition/DefaultCompositionProvider.js b/src/api/composition/DefaultCompositionProvider.js index c5c595dd63a..05a6603505a 100644 --- a/src/api/composition/DefaultCompositionProvider.js +++ b/src/api/composition/DefaultCompositionProvider.js @@ -21,7 +21,7 @@ *****************************************************************************/ import { toRaw } from 'vue'; -import objectUtils from '../objects/object-utils.js'; +import { makeKeyString } from '../objects/object-utils.js'; import CompositionProvider from './CompositionProvider.js'; /** @@ -91,7 +91,7 @@ export default class DefaultCompositionProvider extends CompositionProvider { this.establishTopicListener(); /** @type {string} */ - const keyString = objectUtils.makeKeyString(domainObject.identifier); + const keyString = makeKeyString(domainObject.identifier); let objectListeners = this.listeningTo[keyString]; if (!objectListeners) { @@ -120,7 +120,7 @@ export default class DefaultCompositionProvider extends CompositionProvider { */ off(domainObject, event, callback, context) { /** @type {string} */ - const keyString = objectUtils.makeKeyString(domainObject.identifier); + const keyString = makeKeyString(domainObject.identifier); const objectListeners = this.listeningTo[keyString]; const index = objectListeners[event].findIndex((l) => { @@ -228,7 +228,7 @@ export default class DefaultCompositionProvider extends CompositionProvider { this.publicAPI.objects.mutate(domainObject, 'composition', newComposition); /** @type {string} */ - let id = objectUtils.makeKeyString(domainObject.identifier); + let id = makeKeyString(domainObject.identifier); const listeners = this.listeningTo[id]; if (!listeners) { diff --git a/src/api/objects/MutableDomainObject.js b/src/api/objects/MutableDomainObject.js index f83a26401a9..80c46598ffc 100644 --- a/src/api/objects/MutableDomainObject.js +++ b/src/api/objects/MutableDomainObject.js @@ -22,7 +22,7 @@ import EventEmitter from 'EventEmitter'; import _ from 'lodash'; -import utils from './object-utils.js'; +import { makeKeyString, refresh } from './object-utils.js'; const ANY_OBJECT_EVENT = 'mutation'; @@ -152,7 +152,7 @@ class MutableDomainObject { mutable.$observe('$_synchronize_model', (updatedObject) => { let clone = JSON.parse(JSON.stringify(updatedObject)); - utils.refresh(mutable, clone); + refresh(mutable, clone); }); return mutable; @@ -168,7 +168,7 @@ class MutableDomainObject { } function qualifiedEventName(object, eventName) { - let keystring = utils.makeKeyString(object.identifier); + let keystring = makeKeyString(object.identifier); return [keystring, eventName].join(':'); } diff --git a/src/api/objects/ObjectAPI.js b/src/api/objects/ObjectAPI.js index d28d1936054..3615f3c94cf 100644 --- a/src/api/objects/ObjectAPI.js +++ b/src/api/objects/ObjectAPI.js @@ -21,7 +21,7 @@ *****************************************************************************/ import EventEmitter from 'EventEmitter'; -import utils from 'objectUtils'; +import { identifierEquals, makeKeyString, parseKeyString, refresh } from 'objectUtils'; import ConflictError from './ConflictError.js'; import InMemorySearchProvider from './InMemorySearchProvider.js'; @@ -82,8 +82,19 @@ import Transaction from './Transaction.js'; * @memberof module:openmct */ export default class ObjectAPI { + #makeKeyString; + #parseKeyString; + #identifierEquals; + #refresh; + #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.SEARCH_TYPES = Object.freeze({ OBJECTS: 'OBJECTS', @@ -206,14 +217,14 @@ export default class ObjectAPI { * has been saved, or be rejected if it cannot be saved */ get(identifier, abortSignal, forceRemote = false) { - let keystring = this.makeKeyString(identifier); + let keystring = this.#makeKeyString(identifier); if (!forceRemote) { if (this.cache[keystring] !== undefined) { return this.cache[keystring]; } - identifier = utils.parseKeyString(identifier); + identifier = parseKeyString(identifier); if (this.isTransactionActive()) { let dirtyObject = this.transaction.getDirtyObject(identifier); @@ -227,7 +238,7 @@ export default class ObjectAPI { const provider = this.getProvider(identifier); 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) { @@ -325,7 +336,7 @@ export default class ObjectAPI { */ getMutable(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) => { @@ -352,7 +363,7 @@ export default class ObjectAPI { } isPersistable(idOrKeyString) { - let identifier = utils.parseKeyString(idOrKeyString); + let identifier = parseKeyString(idOrKeyString); let provider = this.getProvider(identifier); if (provider?.isReadOnly) { return !provider.isReadOnly(); @@ -362,7 +373,7 @@ export default class ObjectAPI { } isMissing(domainObject) { - let identifier = utils.makeKeyString(domainObject.identifier); + let identifier = makeKeyString(domainObject.identifier); let missingName = 'Missing: ' + identifier; return domainObject.name === missingName; @@ -442,21 +453,21 @@ export default class ObjectAPI { if (error instanceof this.errors.Conflict) { // Synchronized objects will resolve their own conflicts if (this.SYNCHRONIZED_OBJECT_TYPES.includes(domainObject.type)) { - this.openmct.notifications.info( - `Conflict detected while saving "${this.makeKeyString( + this.#openmct.notifications.info( + `Conflict detected while saving "${this.#makeKeyString( domainObject.name )}", attempting to resolve` ); } else { - this.openmct.notifications.error( - `Conflict detected while saving ${this.makeKeyString(domainObject.identifier)}` + this.#openmct.notifications.error( + `Conflict detected while saving ${this.#makeKeyString(domainObject.identifier)}` ); if (this.isTransactionActive()) { this.endTransaction(); } - await this.refresh(domainObject); + await this.#refresh(domainObject); } } @@ -465,7 +476,7 @@ export default class ObjectAPI { } async #getCurrentUsername() { - const user = await this.openmct.user.getCurrentUser(); + const user = await this.#openmct.user.getCurrentUser(); let username; if (user !== undefined) { @@ -554,7 +565,7 @@ export default class ObjectAPI { */ getRelativePath(objectPath) { return objectPath - .map((p) => this.makeKeyString(p.identifier)) + .map((p) => this.#makeKeyString(p.identifier)) .reverse() .join('/'); } @@ -574,13 +585,13 @@ export default class ObjectAPI { } let sourceTelemetry = null; - if (telemetryIdentifier && utils.identifierEquals(identifier, telemetryIdentifier)) { + if (telemetryIdentifier && this.#identifierEquals(identifier, telemetryIdentifier)) { sourceTelemetry = identifier; } else if (objectDetails.composition) { sourceTelemetry = objectDetails.composition[0]; if (telemetryIdentifier) { 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); // Check if provider supports realtime updates - let identifier = utils.parseKeyString(mutableObject.identifier); + let identifier = parseKeyString(mutableObject.identifier); let provider = this.getProvider(identifier); if ( @@ -706,7 +717,7 @@ export default class ObjectAPI { if (domainObject.isMutable) { domainObject.$refresh(refreshedObject); } else { - utils.refresh(domainObject, refreshedObject); + refresh(domainObject, refreshedObject); } return domainObject; @@ -745,7 +756,7 @@ export default class ObjectAPI { * @returns {string} A string representation of the given identifier, including namespace and key */ 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 */ parseKeyString(keyString) { - return utils.parseKeyString(keyString); + return parseKeyString(keyString); } /** @@ -761,9 +772,9 @@ export default class ObjectAPI { * @param {module:openmct.ObjectAPI~Identifier[]} 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 ( identifier === firstIdentifier || (identifier.namespace === firstIdentifier.namespace && @@ -791,7 +802,7 @@ export default class ObjectAPI { } return path.some((pathElement) => { - const identifierToCheck = utils.parseKeyString(keyStringToCheck); + const identifierToCheck = this.#parseKeyString(keyStringToCheck); return this.areIdsEqual(identifierToCheck, pathElement.identifier); }); @@ -814,7 +825,7 @@ export default class ObjectAPI { if (location && !this.#pathContainsDomainObject(location, path)) { // if we have a location, and we don't already have this in our constructed path, // then keep walking up the path - return this.getOriginalPath(utils.parseKeyString(location), path, abortSignal); + return this.getOriginalPath(this.#parseKeyString(location), path, abortSignal); } else { return path; } @@ -853,8 +864,8 @@ export default class ObjectAPI { await Promise.all( keyStrings.map((keyString) => this.supportsMutation(keyString) - ? this.getMutable(utils.parseKeyString(keyString)) - : this.get(utils.parseKeyString(keyString)) + ? this.getMutable(this.#parseKeyString(keyString)) + : this.get(this.#parseKeyString(keyString)) ) ) ).reverse(); @@ -866,7 +877,7 @@ export default class ObjectAPI { return ( objectPath !== undefined && objectPath.length > 1 && - domainObject.location !== this.makeKeyString(objectPath[1].identifier) + domainObject.location !== this.#makeKeyString(objectPath[1].identifier) ); } diff --git a/src/api/objects/RootRegistry.js b/src/api/objects/RootRegistry.js index 51c3f211bc0..1f1b652bc49 100644 --- a/src/api/objects/RootRegistry.js +++ b/src/api/objects/RootRegistry.js @@ -20,7 +20,7 @@ * 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 { constructor(openmct) { @@ -47,12 +47,12 @@ export default class RootRegistry { } _isValid(rootItem) { - if (utils.isIdentifier(rootItem) || typeof rootItem === 'function') { + if (isIdentifier(rootItem) || typeof rootItem === 'function') { return true; } if (Array.isArray(rootItem)) { - return rootItem.every(utils.isIdentifier); + return rootItem.every(isIdentifier); } return false; diff --git a/src/api/objects/TransactionSpec.js b/src/api/objects/TransactionSpec.js index 67ba64fc7e4..254641b9b34 100644 --- a/src/api/objects/TransactionSpec.js +++ b/src/api/objects/TransactionSpec.js @@ -1,4 +1,4 @@ -import utils from 'objectUtils'; +import { makeKeyString, parseKeyString } from 'objectUtils'; import Transaction from './Transaction.js'; @@ -9,7 +9,7 @@ let transaction; describe('Transaction Class', () => { beforeEach(() => { objectAPI = { - makeKeyString: (identifier) => utils.makeKeyString(identifier), + makeKeyString: (identifier) => makeKeyString(identifier), save: () => Promise.resolve(true), mutate: (object, prop, value) => { object[prop] = value; @@ -18,7 +18,7 @@ describe('Transaction Class', () => { }, refresh: (object) => Promise.resolve(object), areIdsEqual: (...identifiers) => { - return identifiers.map(utils.parseKeyString).every((identifier) => { + return identifiers.map(parseKeyString).every((identifier) => { return ( identifier === identifiers[0] || (identifier.namespace === identifiers[0].namespace && diff --git a/src/api/objects/test/object-utilsSpec.js b/src/api/objects/test/object-utilsSpec.js index 8c13e995bd8..d17c03f5d89 100644 --- a/src/api/objects/test/object-utilsSpec.js +++ b/src/api/objects/test/object-utilsSpec.js @@ -1,4 +1,4 @@ -import objectUtils from 'objectUtils'; +import { makeKeyString, parseKeyString, toNewFormat, toOldFormat } from 'objectUtils'; describe('objectUtils', function () { describe('keyString util', function () { @@ -31,27 +31,27 @@ describe('objectUtils', function () { Object.keys(EXPECTATIONS).forEach(function (keyString) { it('parses "' + keyString + '".', function () { - expect(objectUtils.parseKeyString(keyString)).toEqual(EXPECTATIONS[keyString]); + expect(parseKeyString(keyString)).toEqual(EXPECTATIONS[keyString]); }); it('parses and re-encodes "' + keyString + '"', function () { - const identifier = objectUtils.parseKeyString(keyString); - expect(objectUtils.makeKeyString(identifier)).toEqual(keyString); + const identifier = parseKeyString(keyString); + expect(makeKeyString(identifier)).toEqual(keyString); }); it('is idempotent for "' + keyString + '".', function () { - const identifier = objectUtils.parseKeyString(keyString); - let again = objectUtils.parseKeyString(identifier); + const identifier = parseKeyString(keyString); + let again = parseKeyString(identifier); expect(identifier).toEqual(again); - again = objectUtils.parseKeyString(again); - again = objectUtils.parseKeyString(again); + again = parseKeyString(again); + again = parseKeyString(again); expect(identifier).toEqual(again); - let againKeyString = objectUtils.makeKeyString(again); + let againKeyString = makeKeyString(again); expect(againKeyString).toEqual(keyString); - againKeyString = objectUtils.makeKeyString(againKeyString); - againKeyString = objectUtils.makeKeyString(againKeyString); - againKeyString = objectUtils.makeKeyString(againKeyString); + againKeyString = makeKeyString(againKeyString); + againKeyString = makeKeyString(againKeyString); + againKeyString = makeKeyString(againKeyString); expect(againKeyString).toEqual(keyString); }); }); @@ -60,7 +60,7 @@ describe('objectUtils', function () { describe('old object conversions', function () { it('translate ids', function () { expect( - objectUtils.toNewFormat( + toNewFormat( { prop: 'someValue' }, @@ -77,7 +77,7 @@ describe('objectUtils', function () { it('translates composition', function () { expect( - objectUtils.toNewFormat( + toNewFormat( { prop: 'someValue', composition: ['anotherObjectId', 'scratch:anotherObjectId'] @@ -107,7 +107,7 @@ describe('objectUtils', function () { describe('new object conversions', function () { it('removes ids', function () { expect( - objectUtils.toOldFormat({ + toOldFormat({ prop: 'someValue', identifier: { namespace: '', @@ -121,7 +121,7 @@ describe('objectUtils', function () { it('translates composition', function () { expect( - objectUtils.toOldFormat({ + toOldFormat({ prop: 'someValue', composition: [ { diff --git a/src/api/telemetry/TelemetryAPI.js b/src/api/telemetry/TelemetryAPI.js index e6aa50bda68..143f3fc32ed 100644 --- a/src/api/telemetry/TelemetryAPI.js +++ b/src/api/telemetry/TelemetryAPI.js @@ -20,7 +20,7 @@ * 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 BatchingWebSocket from './BatchingWebSocket.js'; @@ -429,7 +429,7 @@ export default class TelemetryAPI { this.#subscribeCache = {}; } - const keyString = objectUtils.makeKeyString(domainObject.identifier); + const keyString = makeKeyString(domainObject.identifier); const supportedStrategy = supportsBatching ? requestedStrategy : SUBSCRIBE_STRATEGY.LATEST; // Override the requested strategy with the strategy supported by the provider const optionsWithSupportedStrategy = { @@ -541,7 +541,7 @@ export default class TelemetryAPI { this.stalenessSubscriberCache = {}; } - const keyString = objectUtils.makeKeyString(domainObject.identifier); + const keyString = makeKeyString(domainObject.identifier); let stalenessSubscriber = this.stalenessSubscriberCache[keyString]; if (!stalenessSubscriber) { @@ -600,7 +600,7 @@ export default class TelemetryAPI { this.limitsSubscribeCache = {}; } - const keyString = objectUtils.makeKeyString(domainObject.identifier); + const keyString = makeKeyString(domainObject.identifier); let subscriber = this.limitsSubscribeCache[keyString]; if (!subscriber) { diff --git a/src/plugins/importFromJSONAction/ImportFromJSONAction.js b/src/plugins/importFromJSONAction/ImportFromJSONAction.js index 465ce1a9d1f..9003fbe5ebc 100644 --- a/src/plugins/importFromJSONAction/ImportFromJSONAction.js +++ b/src/plugins/importFromJSONAction/ImportFromJSONAction.js @@ -20,7 +20,7 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ -import objectUtils from 'objectUtils'; +import { parseKeyString } from 'objectUtils'; import { filter__proto__ } from 'utils/sanitization'; import { v4 as uuid } from 'uuid'; @@ -158,7 +158,7 @@ export default class ImportAsJSONAction { key: uuid() }; - const oldId = objectUtils.parseKeyString(domainObjectId); + const oldId = parseKeyString(domainObjectId); tree = this._rewriteId(oldId, newId, tree); }, this); diff --git a/src/plugins/notebook/utils/notebook-storage.js b/src/plugins/notebook/utils/notebook-storage.js index aaca877611e..866cd0faee4 100644 --- a/src/plugins/notebook/utils/notebook-storage.js +++ b/src/plugins/notebook/utils/notebook-storage.js @@ -1,4 +1,4 @@ -import objectUtils from 'objectUtils'; +import { makeKeyString } from 'objectUtils'; const NOTEBOOK_LOCAL_STORAGE = 'notebook-storage'; let currentNotebookObjectIdentifier = null; @@ -22,8 +22,7 @@ function defaultNotebookObjectChanged(newDomainObject) { function observeDefaultNotebookObject(openmct, notebookStorage, domainObject) { if ( currentNotebookObjectIdentifier && - objectUtils.makeKeyString(currentNotebookObjectIdentifier) === - objectUtils.makeKeyString(notebookStorage.identifier) + makeKeyString(currentNotebookObjectIdentifier) === makeKeyString(notebookStorage.identifier) ) { return; } diff --git a/src/plugins/staticRootPlugin/StaticModelProvider.js b/src/plugins/staticRootPlugin/StaticModelProvider.js index d955159b92e..d8006fc75ef 100644 --- a/src/plugins/staticRootPlugin/StaticModelProvider.js +++ b/src/plugins/staticRootPlugin/StaticModelProvider.js @@ -26,7 +26,7 @@ * rootIdentifier, and rewrites all child object identifiers so that they * exist in the same namespace as the rootIdentifier. */ -import objectUtils from 'objectUtils'; +import { makeKeyString, parseKeyString, toNewFormat } from 'objectUtils'; class StaticModelProvider { constructor(importData, rootIdentifier) { @@ -38,7 +38,7 @@ class StaticModelProvider { * Standard "Get". */ get(identifier) { - const keyString = objectUtils.makeKeyString(identifier); + const keyString = makeKeyString(identifier); if (this.objectMap[keyString]) { return this.objectMap[keyString]; } @@ -49,7 +49,7 @@ class StaticModelProvider { parseObjectLeaf(objectLeaf, idMap, newRootNamespace, oldRootNamespace) { Object.keys(objectLeaf).forEach((nodeKey) => { if (idMap.get(nodeKey)) { - const newIdentifier = objectUtils.makeKeyString({ + const newIdentifier = makeKeyString({ namespace: newRootNamespace, key: idMap.get(nodeKey) }); @@ -104,7 +104,7 @@ class StaticModelProvider { let mappedLeafValue; if (oldRootNamespace) { mappedLeafValue = idMap.get( - objectUtils.makeKeyString({ + makeKeyString({ namespace: oldRootNamespace, key: leafValue }) @@ -125,7 +125,7 @@ class StaticModelProvider { return null; } - const newLocationIdentifier = objectUtils.makeKeyString({ + const newLocationIdentifier = makeKeyString({ namespace: newRootNamespace, key: mappedLeafValue }); @@ -134,7 +134,7 @@ class StaticModelProvider { } else { const mappedLeafValue = idMap.get(leafValue); if (mappedLeafValue) { - const newIdentifier = objectUtils.makeKeyString({ + const newIdentifier = makeKeyString({ namespace: newRootNamespace, key: mappedLeafValue }); @@ -147,7 +147,7 @@ class StaticModelProvider { } rewriteObjectIdentifiers(importData, rootIdentifier) { - const { namespace: oldRootNamespace } = objectUtils.parseKeyString(importData.rootId); + const { namespace: oldRootNamespace } = parseKeyString(importData.rootId); const { namespace: newRootNamespace } = rootIdentifier; const idMap = new Map(); const objectTree = importData.openmct; @@ -172,7 +172,7 @@ class StaticModelProvider { */ convertToNewObjects(oldObjectMap) { return Object.keys(oldObjectMap).reduce(function (newObjectMap, key) { - newObjectMap[key] = objectUtils.toNewFormat(oldObjectMap[key], key); + newObjectMap[key] = toNewFormat(oldObjectMap[key], key); return newObjectMap; }, {}); @@ -180,7 +180,7 @@ class StaticModelProvider { /* Set the root location correctly for a top-level object */ setRootLocation(objectMap, rootIdentifier) { - objectMap[objectUtils.makeKeyString(rootIdentifier)].location = 'ROOT'; + objectMap[makeKeyString(rootIdentifier)].location = 'ROOT'; return objectMap; } diff --git a/src/plugins/summaryWidget/src/ConditionManager.js b/src/plugins/summaryWidget/src/ConditionManager.js index 917f386e8a5..dc453dafddd 100644 --- a/src/plugins/summaryWidget/src/ConditionManager.js +++ b/src/plugins/summaryWidget/src/ConditionManager.js @@ -1,6 +1,6 @@ import EventEmitter from 'EventEmitter'; import _ from 'lodash'; -import objectUtils from 'objectUtils'; +import { makeKeyString } from 'objectUtils'; import ConditionEvaluator from './ConditionEvaluator.js'; @@ -119,7 +119,7 @@ ConditionManager.prototype.addGlobalPropertyType = function (key, type) { * has completed and types have been parsed */ ConditionManager.prototype.parsePropertyTypes = function (object) { - const objectId = objectUtils.makeKeyString(object.identifier); + const objectId = makeKeyString(object.identifier); this.telemetryTypesById[objectId] = {}; Object.values(this.telemetryMetadataById[objectId]).forEach(function (valueMetadata) { @@ -182,7 +182,7 @@ ConditionManager.prototype.createNormalizedDatum = function (objId, telemetryDat ConditionManager.prototype.onCompositionAdd = function (obj) { let compositionKeys; const telemetryAPI = this.openmct.telemetry; - const objId = objectUtils.makeKeyString(obj.identifier); + const objId = makeKeyString(obj.identifier); let telemetryMetadata; const self = this; @@ -191,7 +191,7 @@ ConditionManager.prototype.onCompositionAdd = function (obj) { self.telemetryMetadataById[objId] = {}; // 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)) { self.domainObject.composition.push(obj.identifier); } @@ -245,7 +245,7 @@ ConditionManager.prototype.onCompositionAdd = function (obj) { * @private */ ConditionManager.prototype.onCompositionRemove = function (identifier) { - const objectId = objectUtils.makeKeyString(identifier); + const objectId = makeKeyString(identifier); // FIXME: this should just update by listener. _.remove(this.domainObject.composition, function (id) { return id.key === identifier.key && id.namespace === identifier.namespace; diff --git a/src/plugins/summaryWidget/src/input/ObjectSelect.js b/src/plugins/summaryWidget/src/input/ObjectSelect.js index 5547854c4e7..40f0a506d86 100644 --- a/src/plugins/summaryWidget/src/input/ObjectSelect.js +++ b/src/plugins/summaryWidget/src/input/ObjectSelect.js @@ -1,4 +1,4 @@ -import objectUtils from 'objectUtils'; +import { makeKeyString } from 'objectUtils'; import Select from './Select.js'; @@ -39,7 +39,7 @@ export default function ObjectSelect(config, manager, baseOptions) { * @private */ 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 () { 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) { items.splice(index, 0, option); diff --git a/src/plugins/summaryWidget/src/telemetry/EvaluatorPool.js b/src/plugins/summaryWidget/src/telemetry/EvaluatorPool.js index 75ddff560d6..88d3acded3f 100644 --- a/src/plugins/summaryWidget/src/telemetry/EvaluatorPool.js +++ b/src/plugins/summaryWidget/src/telemetry/EvaluatorPool.js @@ -20,7 +20,7 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ -import objectUtils from 'objectUtils'; +import { makeKeyString } from 'objectUtils'; import SummaryWidgetEvaluator from './SummaryWidgetEvaluator.js'; @@ -31,7 +31,7 @@ export default function EvaluatorPool(openmct) { } EvaluatorPool.prototype.get = function (domainObject) { - const objectId = objectUtils.makeKeyString(domainObject.identifier); + const objectId = makeKeyString(domainObject.identifier); let poolEntry = this.byObjectId[objectId]; if (!poolEntry) { poolEntry = { diff --git a/src/plugins/summaryWidget/src/telemetry/SummaryWidgetEvaluator.js b/src/plugins/summaryWidget/src/telemetry/SummaryWidgetEvaluator.js index b05f51cd210..0e61202f674 100644 --- a/src/plugins/summaryWidget/src/telemetry/SummaryWidgetEvaluator.js +++ b/src/plugins/summaryWidget/src/telemetry/SummaryWidgetEvaluator.js @@ -21,7 +21,7 @@ *****************************************************************************/ import _ from 'lodash'; -import objectUtils from 'objectUtils'; +import { makeKeyString } from 'objectUtils'; import eventHelpers from '../eventHelpers.js'; import SummaryWidgetRule from './SummaryWidgetRule.js'; @@ -113,7 +113,7 @@ SummaryWidgetEvaluator.prototype.updateRules = function (domainObject) { }; SummaryWidgetEvaluator.prototype.addChild = function (childObject) { - const childId = objectUtils.makeKeyString(childObject.identifier); + const childId = makeKeyString(childObject.identifier); const metadata = this.openmct.telemetry.getMetadata(childObject); const formats = this.openmct.telemetry.getFormatMap(metadata); @@ -126,7 +126,7 @@ SummaryWidgetEvaluator.prototype.addChild = function (childObject) { }; SummaryWidgetEvaluator.prototype.removeChild = function (childObject) { - const childId = objectUtils.makeKeyString(childObject.identifier); + const childId = makeKeyString(childObject.identifier); delete this.baseState[childId]; }; diff --git a/src/plugins/telemetryMean/src/MeanTelemetryProvider.js b/src/plugins/telemetryMean/src/MeanTelemetryProvider.js index 35557fbeb2b..03ed1c2fe4f 100644 --- a/src/plugins/telemetryMean/src/MeanTelemetryProvider.js +++ b/src/plugins/telemetryMean/src/MeanTelemetryProvider.js @@ -20,7 +20,7 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ -import objectUtils from 'objectUtils'; +import { parseKeyString } from 'objectUtils'; import TelemetryAverager from './TelemetryAverager.js'; @@ -43,7 +43,7 @@ MeanTelemetryProvider.prototype.supportsRequest = MeanTelemetryProvider.prototype.subscribe = function (domainObject, callback) { let wrappedUnsubscribe; let unsubscribeCalled = false; - const objectId = objectUtils.parseKeyString(domainObject.telemetryPoint); + const objectId = parseKeyString(domainObject.telemetryPoint); const samples = domainObject.samples; this.objectAPI @@ -79,7 +79,7 @@ MeanTelemetryProvider.prototype.subscribeToAverage = function (domainObject, sam }; MeanTelemetryProvider.prototype.request = function (domainObject, request) { - const objectId = objectUtils.parseKeyString(domainObject.telemetryPoint); + const objectId = parseKeyString(domainObject.telemetryPoint); const samples = domainObject.samples; return this.objectAPI.get(objectId).then( @@ -119,7 +119,7 @@ MeanTelemetryProvider.prototype.requestAverageTelemetry = function ( * @private */ MeanTelemetryProvider.prototype.getLinkedObject = function (domainObject) { - const objectId = objectUtils.parseKeyString(domainObject.telemetryPoint); + const objectId = parseKeyString(domainObject.telemetryPoint); return this.objectAPI.get(objectId); }; diff --git a/src/ui/components/ObjectView.vue b/src/ui/components/ObjectView.vue index 5cee686ed78..6c5c1c9aa3b 100644 --- a/src/ui/components/ObjectView.vue +++ b/src/ui/components/ObjectView.vue @@ -33,7 +33,7 @@ import StyleRuleManager from '@/plugins/condition/StyleRuleManager'; import { STYLE_CONSTANTS } from '@/plugins/condition/utils/constants'; 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'; export default { @@ -224,7 +224,7 @@ export default { this.updateView(true); }, reload(domainObjectToReload) { - if (objectUtils.equals(domainObjectToReload, this.domainObject)) { + if (objectEquals(domainObjectToReload, this.domainObject)) { this.updateView(true); this.initObjectStyles(); this.triggerStalenessSubscribe(this.domainObject); From 3a38f93bf01c7c67b81313c26ca5c9be63af824b Mon Sep 17 00:00:00 2001 From: Jesse Mazzella Date: Wed, 21 Feb 2024 11:21:09 -0800 Subject: [PATCH 5/7] test(e2e): add test for element item removal from overlay plot --- .../plugins/plot/overlayPlot.e2e.spec.js | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/e2e/tests/functional/plugins/plot/overlayPlot.e2e.spec.js b/e2e/tests/functional/plugins/plot/overlayPlot.e2e.spec.js index 54c76aae972..394c606075d 100644 --- a/e2e/tests/functional/plugins/plot/overlayPlot.e2e.spec.js +++ b/e2e/tests/functional/plugins/plot/overlayPlot.e2e.spec.js @@ -315,6 +315,31 @@ test.describe('Overlay Plot', () => { expect(plotPixelSize).toBeGreaterThan(0); } ); + + test('Can remove an item via the elements pool action menu', async ({ page }) => { + const overlayPlot = await createDomainObjectWithDefaults(page, { + type: 'Overlay Plot' + }); + + 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.getByTitle('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(); + }); }); /** From 0c379c1cf5d38b4961b8fa34ad4784f06f998a01 Mon Sep 17 00:00:00 2001 From: Jesse Mazzella Date: Wed, 21 Feb 2024 11:21:32 -0800 Subject: [PATCH 6/7] a11y: add accessible name for object labels --- .../inspectorViews/elements/ElementItem.vue | 17 +++++--- src/ui/components/ObjectLabel.vue | 14 ++++++ src/ui/composables/edit.js | 43 +++++++++++++++++++ 3 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 src/ui/composables/edit.js diff --git a/src/plugins/inspectorViews/elements/ElementItem.vue b/src/plugins/inspectorViews/elements/ElementItem.vue index f286686990f..6c7e7fe44a6 100644 --- a/src/plugins/inspectorViews/elements/ElementItem.vue +++ b/src/plugins/inspectorViews/elements/ElementItem.vue @@ -23,6 +23,8 @@