mirror of
https://github.com/nasa/openmct.git
synced 2025-06-24 18:25:19 +00:00
Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
8a8cbc778c | |||
44e603cc00 |
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openmct",
|
||||
"version": "2.2.3-SNAPSHOT",
|
||||
"version": "2.2.3",
|
||||
"description": "The Open MCT core platform",
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "7.19.1",
|
||||
|
@ -20,8 +20,6 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
import JSONExporter from '/src/exporters/JSONExporter.js';
|
||||
|
||||
import _ from 'lodash';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
export default class ExportAsJSONAction {
|
||||
@ -35,10 +33,9 @@ export default class ExportAsJSONAction {
|
||||
this.group = "export";
|
||||
this.priority = 1;
|
||||
|
||||
this.externalIdentifiers = [];
|
||||
this.tree = {};
|
||||
this.calls = 0;
|
||||
this.idMap = {};
|
||||
this.tree = null;
|
||||
this.calls = null;
|
||||
this.idMap = null;
|
||||
|
||||
this.JSONExportService = new JSONExporter();
|
||||
}
|
||||
@ -60,21 +57,164 @@ export default class ExportAsJSONAction {
|
||||
*/
|
||||
invoke(objectpath) {
|
||||
this.tree = {};
|
||||
this.calls = 0;
|
||||
this.idMap = {};
|
||||
|
||||
const root = objectpath[0];
|
||||
this.root = JSON.parse(JSON.stringify(root));
|
||||
const rootId = this._getId(this.root);
|
||||
this.root = this._copy(root);
|
||||
|
||||
const rootId = this._getKeystring(this.root);
|
||||
this.tree[rootId] = this.root;
|
||||
|
||||
this._write(this.root);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {object} parent
|
||||
*/
|
||||
async _write(parent) {
|
||||
this.calls++;
|
||||
|
||||
//conditional object styles are not saved on the composition, so we need to check for them
|
||||
const conditionSetIdentifier = this._getConditionSetIdentifier(parent);
|
||||
const hasItemConditionSetIdentifiers = this._hasItemConditionSetIdentifiers(parent);
|
||||
const composition = this.openmct.composition.get(parent);
|
||||
|
||||
if (composition) {
|
||||
const children = await composition.load();
|
||||
|
||||
children.forEach((child) => {
|
||||
this._exportObject(child, parent);
|
||||
});
|
||||
}
|
||||
|
||||
if (!conditionSetIdentifier && !hasItemConditionSetIdentifiers) {
|
||||
this._decrementCallsAndSave();
|
||||
} else {
|
||||
const conditionSetObjects = [];
|
||||
|
||||
// conditionSetIdentifiers directly in objectStyles object
|
||||
if (conditionSetIdentifier) {
|
||||
conditionSetObjects.push(await this.openmct.objects.get(conditionSetIdentifier));
|
||||
}
|
||||
|
||||
// conditionSetIdentifiers stored on item ids in the objectStyles object
|
||||
if (hasItemConditionSetIdentifiers) {
|
||||
const itemConditionSetIdentifiers = this._getItemConditionSetIdentifiers(parent);
|
||||
|
||||
for (const itemConditionSetIdentifier of itemConditionSetIdentifiers) {
|
||||
conditionSetObjects.push(await this.openmct.objects.get(itemConditionSetIdentifier));
|
||||
}
|
||||
}
|
||||
|
||||
for (const conditionSetObject of conditionSetObjects) {
|
||||
this._exportObject(conditionSetObject, parent);
|
||||
}
|
||||
|
||||
this._decrementCallsAndSave();
|
||||
}
|
||||
}
|
||||
|
||||
_exportObject(child, parent) {
|
||||
const originalKeyString = this._getKeystring(child);
|
||||
const createable = this._isCreatableAndPersistable(child);
|
||||
const isNotInfinite = !Object.prototype.hasOwnProperty.call(this.tree, originalKeyString);
|
||||
|
||||
if (createable && isNotInfinite) {
|
||||
// for external or linked objects we generate new keys, if they don't exist already
|
||||
if (this._isLinkedObject(child, parent)) {
|
||||
child = this._rewriteLink(child, parent);
|
||||
} else {
|
||||
this.tree[originalKeyString] = child;
|
||||
}
|
||||
|
||||
this._write(child);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {object} child
|
||||
* @param {object} parent
|
||||
* @returns {object}
|
||||
*/
|
||||
_rewriteLink(child, parent) {
|
||||
const originalKeyString = this._getKeystring(child);
|
||||
const parentKeyString = this._getKeystring(parent);
|
||||
const conditionSetIdentifier = this._getConditionSetIdentifier(parent);
|
||||
const hasItemConditionSetIdentifiers = this._hasItemConditionSetIdentifiers(parent);
|
||||
const existingMappedKeyString = this.idMap[originalKeyString];
|
||||
let copy;
|
||||
|
||||
if (!existingMappedKeyString) {
|
||||
copy = this._copy(child);
|
||||
copy.identifier.key = uuid();
|
||||
|
||||
if (!conditionSetIdentifier && !hasItemConditionSetIdentifiers) {
|
||||
copy.location = parentKeyString;
|
||||
}
|
||||
|
||||
let newKeyString = this._getKeystring(copy);
|
||||
this.idMap[originalKeyString] = newKeyString;
|
||||
this.tree[newKeyString] = copy;
|
||||
} else {
|
||||
copy = this.tree[existingMappedKeyString];
|
||||
}
|
||||
|
||||
if (conditionSetIdentifier || hasItemConditionSetIdentifiers) {
|
||||
|
||||
// update objectStyle object
|
||||
if (conditionSetIdentifier) {
|
||||
const directObjectStylesIdentifier = this.openmct.objects.areIdsEqual(
|
||||
parent.configuration.objectStyles.conditionSetIdentifier,
|
||||
child.identifier
|
||||
);
|
||||
|
||||
if (directObjectStylesIdentifier) {
|
||||
parent.configuration.objectStyles.conditionSetIdentifier = copy.identifier;
|
||||
this.tree[parentKeyString].configuration.objectStyles.conditionSetIdentifier = copy.identifier;
|
||||
}
|
||||
}
|
||||
|
||||
// update per item id on objectStyle object
|
||||
if (hasItemConditionSetIdentifiers) {
|
||||
for (const itemId in parent.configuration.objectStyles) {
|
||||
if (parent.configuration.objectStyles[itemId]) {
|
||||
const itemConditionSetIdentifier = parent.configuration.objectStyles[itemId].conditionSetIdentifier;
|
||||
|
||||
if (
|
||||
itemConditionSetIdentifier
|
||||
&& this.openmct.objects.areIdsEqual(itemConditionSetIdentifier, child.identifier)
|
||||
) {
|
||||
parent.configuration.objectStyles[itemId].conditionSetIdentifier = copy.identifier;
|
||||
this.tree[parentKeyString].configuration.objectStyles[itemId].conditionSetIdentifier = copy.identifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// just update parent
|
||||
const index = parent.composition.findIndex(identifier => {
|
||||
return this.openmct.objects.areIdsEqual(child.identifier, identifier);
|
||||
});
|
||||
|
||||
parent.composition[index] = copy.identifier;
|
||||
this.tree[parentKeyString].composition[index] = copy.identifier;
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {object} domainObject
|
||||
* @returns {string} A string representation of the given identifier, including namespace and key
|
||||
*/
|
||||
_getId(domainObject) {
|
||||
_getKeystring(domainObject) {
|
||||
return this.openmct.objects.makeKeyString(domainObject.identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {object} domainObject
|
||||
@ -86,6 +226,7 @@ export default class ExportAsJSONAction {
|
||||
|
||||
return type && type.definition.creatable && isPersistable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {object} child
|
||||
@ -93,65 +234,47 @@ export default class ExportAsJSONAction {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_isLinkedObject(child, parent) {
|
||||
if (child.location !== this._getId(parent)
|
||||
&& !Object.keys(this.tree).includes(child.location)
|
||||
&& this._getId(child) !== this._getId(this.root)
|
||||
|| this.externalIdentifiers.includes(this._getId(child))) {
|
||||
const rootKeyString = this._getKeystring(this.root);
|
||||
const childKeyString = this._getKeystring(child);
|
||||
const parentKeyString = this._getKeystring(parent);
|
||||
|
||||
return true;
|
||||
return (child.location !== parentKeyString
|
||||
&& !Object.keys(this.tree).includes(child.location)
|
||||
&& childKeyString !== rootKeyString)
|
||||
|| this.idMap[childKeyString] !== undefined;
|
||||
}
|
||||
|
||||
_getConditionSetIdentifier(object) {
|
||||
return object.configuration?.objectStyles?.conditionSetIdentifier;
|
||||
}
|
||||
|
||||
_hasItemConditionSetIdentifiers(parent) {
|
||||
const objectStyles = parent.configuration?.objectStyles;
|
||||
|
||||
for (const itemId in objectStyles) {
|
||||
if (Object.prototype.hasOwnProperty.call(objectStyles[itemId], 'conditionSetIdentifier')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
* @param {object} child
|
||||
* @param {object} parent
|
||||
* @returns {object}
|
||||
*/
|
||||
_rewriteLink(child, parent) {
|
||||
this.externalIdentifiers.push(this._getId(child));
|
||||
const index = parent.composition.findIndex(id => {
|
||||
return _.isEqual(child.identifier, id);
|
||||
});
|
||||
const copyOfChild = JSON.parse(JSON.stringify(child));
|
||||
|
||||
copyOfChild.identifier.key = uuid();
|
||||
const newIdString = this._getId(copyOfChild);
|
||||
const parentId = this._getId(parent);
|
||||
_getItemConditionSetIdentifiers(parent) {
|
||||
const objectStyles = parent.configuration?.objectStyles;
|
||||
let identifiers = new Set();
|
||||
|
||||
this.idMap[this._getId(child)] = newIdString;
|
||||
copyOfChild.location = parentId;
|
||||
parent.composition[index] = copyOfChild.identifier;
|
||||
this.tree[newIdString] = copyOfChild;
|
||||
this.tree[parentId].composition[index] = copyOfChild.identifier;
|
||||
if (objectStyles) {
|
||||
Object.keys(objectStyles).forEach(itemId => {
|
||||
if (objectStyles[itemId].conditionSetIdentifier) {
|
||||
identifiers.add(objectStyles[itemId].conditionSetIdentifier);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return copyOfChild;
|
||||
return Array.from(identifiers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {object} child
|
||||
* @param {object} parent
|
||||
* @returns {object}
|
||||
*/
|
||||
_rewriteLinkForReference(child, parent) {
|
||||
const childId = this._getId(child);
|
||||
this.externalIdentifiers.push(childId);
|
||||
const copyOfChild = JSON.parse(JSON.stringify(child));
|
||||
|
||||
copyOfChild.identifier.key = uuid();
|
||||
const newIdString = this._getId(copyOfChild);
|
||||
const parentId = this._getId(parent);
|
||||
|
||||
this.idMap[childId] = newIdString;
|
||||
copyOfChild.location = null;
|
||||
parent.configuration.objectStyles.conditionSetIdentifier = copyOfChild.identifier;
|
||||
this.tree[newIdString] = copyOfChild;
|
||||
this.tree[parentId].configuration.objectStyles.conditionSetIdentifier = copyOfChild.identifier;
|
||||
|
||||
return copyOfChild;
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@ -204,72 +327,10 @@ export default class ExportAsJSONAction {
|
||||
_wrapTree() {
|
||||
return {
|
||||
"openmct": this.tree,
|
||||
"rootId": this._getId(this.root)
|
||||
"rootId": this._getKeystring(this.root)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {object} parent
|
||||
*/
|
||||
_write(parent) {
|
||||
this.calls++;
|
||||
//conditional object styles are not saved on the composition, so we need to check for them
|
||||
let childObjectReferenceId = parent.configuration?.objectStyles?.conditionSetIdentifier;
|
||||
|
||||
const composition = this.openmct.composition.get(parent);
|
||||
if (composition !== undefined) {
|
||||
composition.load()
|
||||
.then((children) => {
|
||||
children.forEach((child, index) => {
|
||||
// Only export if object is creatable
|
||||
if (this._isCreatableAndPersistable(child)) {
|
||||
// Prevents infinite export of self-contained objs
|
||||
if (!Object.prototype.hasOwnProperty.call(this.tree, this._getId(child))) {
|
||||
// If object is a link to something absent from
|
||||
// tree, generate new id and treat as new object
|
||||
if (this._isLinkedObject(child, parent)) {
|
||||
child = this._rewriteLink(child, parent);
|
||||
} else {
|
||||
this.tree[this._getId(child)] = child;
|
||||
}
|
||||
|
||||
this._write(child);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!childObjectReferenceId) {
|
||||
this._decrementCallsAndSave();
|
||||
}
|
||||
});
|
||||
} else if (!childObjectReferenceId) {
|
||||
this._decrementCallsAndSave();
|
||||
}
|
||||
|
||||
if (childObjectReferenceId) {
|
||||
this.openmct.objects.get(childObjectReferenceId)
|
||||
.then((child) => {
|
||||
// Only export if object is creatable
|
||||
if (this._isCreatableAndPersistable(child)) {
|
||||
// Prevents infinite export of self-contained objs
|
||||
if (!Object.prototype.hasOwnProperty.call(this.tree, this._getId(child))) {
|
||||
// If object is a link to something absent from
|
||||
// tree, generate new id and treat as new object
|
||||
if (this._isLinkedObject(child, parent)) {
|
||||
child = this._rewriteLinkForReference(child, parent);
|
||||
} else {
|
||||
this.tree[this._getId(child)] = child;
|
||||
}
|
||||
|
||||
this._write(child);
|
||||
}
|
||||
}
|
||||
|
||||
this._decrementCallsAndSave();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_decrementCallsAndSave() {
|
||||
this.calls--;
|
||||
if (this.calls === 0) {
|
||||
@ -277,4 +338,8 @@ export default class ExportAsJSONAction {
|
||||
this._saveAs(this._wrapTree());
|
||||
}
|
||||
}
|
||||
|
||||
_copy(object) {
|
||||
return JSON.parse(JSON.stringify(object));
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ export default class ImportAsJSONAction {
|
||||
this.cssClass = "icon-import";
|
||||
this.group = "import";
|
||||
this.priority = 2;
|
||||
this.newObjects = [];
|
||||
|
||||
this.openmct = openmct;
|
||||
}
|
||||
@ -85,22 +86,25 @@ export default class ImportAsJSONAction {
|
||||
let objectIdentifiers = this._getObjectReferenceIds(parent);
|
||||
|
||||
if (objectIdentifiers.length) {
|
||||
let newObj;
|
||||
const parentId = this.openmct.objects.makeKeyString(parent.identifier);
|
||||
seen.push(parentId);
|
||||
|
||||
seen.push(parent.id);
|
||||
|
||||
objectIdentifiers.forEach(async (childId) => {
|
||||
for (const childId of objectIdentifiers) {
|
||||
const keystring = this.openmct.objects.makeKeyString(childId);
|
||||
if (!tree[keystring] || seen.includes(keystring)) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
const newModel = tree[keystring];
|
||||
delete newModel.persisted;
|
||||
|
||||
newObj = await this._instantiate(newModel);
|
||||
this._deepInstantiate(newObj, tree, seen);
|
||||
}, this);
|
||||
this.newObjects.push(newModel);
|
||||
|
||||
// make sure there weren't any errors saving
|
||||
if (newModel) {
|
||||
this._deepInstantiate(newModel, tree, seen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
@ -110,19 +114,32 @@ export default class ImportAsJSONAction {
|
||||
*/
|
||||
_getObjectReferenceIds(parent) {
|
||||
let objectIdentifiers = [];
|
||||
let itemObjectReferences = [];
|
||||
const objectStyles = parent?.configuration?.objectStyles;
|
||||
const parentComposition = this.openmct.composition.get(parent);
|
||||
|
||||
let parentComposition = this.openmct.composition.get(parent);
|
||||
if (parentComposition) {
|
||||
objectIdentifiers = Array.from(parentComposition.domainObject.composition);
|
||||
objectIdentifiers = Array.from(parent.composition);
|
||||
}
|
||||
|
||||
//conditional object styles are not saved on the composition, so we need to check for them
|
||||
let parentObjectReference = parent.configuration?.objectStyles?.conditionSetIdentifier;
|
||||
if (parentObjectReference) {
|
||||
objectIdentifiers.push(parentObjectReference);
|
||||
if (objectStyles) {
|
||||
const parentObjectReference = objectStyles.conditionSetIdentifier;
|
||||
|
||||
if (parentObjectReference) {
|
||||
objectIdentifiers.push(parentObjectReference);
|
||||
}
|
||||
|
||||
function hasConditionSetIdentifier(item) {
|
||||
return Boolean(item.conditionSetIdentifier);
|
||||
}
|
||||
|
||||
itemObjectReferences = Object.values(objectStyles)
|
||||
.filter(hasConditionSetIdentifier)
|
||||
.map(item => item.conditionSetIdentifier);
|
||||
}
|
||||
|
||||
return objectIdentifiers;
|
||||
return Array.from(new Set([...objectIdentifiers, ...itemObjectReferences]));
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
@ -155,13 +172,21 @@ export default class ImportAsJSONAction {
|
||||
const tree = this._generateNewIdentifiers(objTree, namespace);
|
||||
const rootId = tree.rootId;
|
||||
|
||||
const rootModel = tree.openmct[rootId];
|
||||
delete rootModel.persisted;
|
||||
const rootObj = tree.openmct[rootId];
|
||||
delete rootObj.persisted;
|
||||
this.newObjects.push(rootObj);
|
||||
|
||||
const rootObj = await this._instantiate(rootModel);
|
||||
if (this.openmct.composition.checkPolicy(domainObject, rootObj)) {
|
||||
this._deepInstantiate(rootObj, tree.openmct, []);
|
||||
|
||||
try {
|
||||
await Promise.all(this.newObjects.map(this._instantiate, this));
|
||||
} catch (error) {
|
||||
this.openmct.notifications.error('Error saving objects');
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
const compositionCollection = this.openmct.composition.get(domainObject);
|
||||
let domainObjectKeyString = this.openmct.objects.makeKeyString(domainObject.identifier);
|
||||
this.openmct.objects.mutate(rootObj, 'location', domainObjectKeyString);
|
||||
@ -184,16 +209,11 @@ export default class ImportAsJSONAction {
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
* @param {object} rootModel
|
||||
* @param {object} model
|
||||
* @returns {object}
|
||||
*/
|
||||
async _instantiate(rootModel) {
|
||||
const success = await this.openmct.objects.save(rootModel);
|
||||
if (success) {
|
||||
return rootModel;
|
||||
}
|
||||
|
||||
this.openmct.notifications.error('Error saving objects');
|
||||
_instantiate(model) {
|
||||
return this.openmct.objects.save(model);
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
|
Reference in New Issue
Block a user