mirror of
https://github.com/nasa/openmct.git
synced 2025-06-25 18:50:11 +00:00
Compare commits
19 Commits
eslint-pla
...
fix-duplic
Author | SHA1 | Date | |
---|---|---|---|
d3825fc554 | |||
d42b2dd023 | |||
59ae7cddc5 | |||
321c7a3af5 | |||
609cf72bd1 | |||
a447b0ada8 | |||
5788f4cc69 | |||
f94b4e53c7 | |||
faf71f1e67 | |||
23310f85ae | |||
d80819634b | |||
483b62c152 | |||
1254279635 | |||
c768a71656 | |||
678a92bd29 | |||
34b488944a | |||
4d1dd2f51d | |||
080f7b8f4b | |||
483f2feac8 |
@ -23,5 +23,5 @@ module.exports = merge(common, {
|
||||
__OPENMCT_ROOT_RELATIVE__: '""'
|
||||
})
|
||||
],
|
||||
devtool: "source-map"
|
||||
devtool: "eval-source-map"
|
||||
});
|
||||
|
@ -239,9 +239,15 @@ export default class ObjectAPI {
|
||||
|
||||
return domainObject;
|
||||
}).catch((error) => {
|
||||
console.warn(`Failed to retrieve ${keystring}:`, error);
|
||||
let result;
|
||||
|
||||
delete this.cache[keystring];
|
||||
const result = this.applyGetInterceptors(identifier);
|
||||
|
||||
// suppress abort errors
|
||||
if (error.name !== 'AbortError') {
|
||||
console.warn(`Failed to retrieve ${keystring}:`, error);
|
||||
result = this.applyGetInterceptors(identifier);
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
|
@ -55,6 +55,11 @@ define([
|
||||
*/
|
||||
function parseKeyString(keyString) {
|
||||
if (isIdentifier(keyString)) {
|
||||
// TODO REMOVE FOR OMM-RELEASE-5.0
|
||||
if (!keyString.namespace && keyString.key.includes(':')) {
|
||||
console.error(`smushed key: ${keyString.key}`);
|
||||
}
|
||||
|
||||
return keyString;
|
||||
}
|
||||
|
||||
|
@ -88,7 +88,7 @@ export default class TelemetryAPI {
|
||||
* @memberof module:openmct.TelemetryAPI~TelemetryProvider#
|
||||
*/
|
||||
canProvideTelemetry(domainObject) {
|
||||
return Boolean(this.#findSubscriptionProvider(domainObject))
|
||||
return Boolean(this.findSubscriptionProvider(domainObject))
|
||||
|| Boolean(this.findRequestProvider(domainObject));
|
||||
}
|
||||
|
||||
@ -123,9 +123,10 @@ export default class TelemetryAPI {
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Returns a telemetry subscription provider that supports
|
||||
* a given domain object and options.
|
||||
*/
|
||||
#findSubscriptionProvider() {
|
||||
findSubscriptionProvider() {
|
||||
const args = Array.prototype.slice.apply(arguments);
|
||||
function supportsDomainObject(provider) {
|
||||
return provider.supportsSubscribe.apply(provider, args);
|
||||
@ -348,7 +349,7 @@ export default class TelemetryAPI {
|
||||
return () => {};
|
||||
}
|
||||
|
||||
const provider = this.#findSubscriptionProvider(domainObject);
|
||||
const provider = this.findSubscriptionProvider(domainObject);
|
||||
|
||||
if (!this.subscribeCache) {
|
||||
this.subscribeCache = {};
|
||||
|
@ -21,16 +21,18 @@
|
||||
*****************************************************************************/
|
||||
|
||||
<template>
|
||||
<component
|
||||
:is="urlDefined ? 'a' : 'span'"
|
||||
<div
|
||||
ref="conditionWidgetElement"
|
||||
class="c-condition-widget u-style-receiver js-style-receiver"
|
||||
:href="url"
|
||||
:target="url ? '_BLANK' : ''"
|
||||
>
|
||||
<div class="c-condition-widget__label">
|
||||
{{ label }}
|
||||
</div>
|
||||
</component>
|
||||
<component
|
||||
:is="urlDefined ? 'a' : 'div'"
|
||||
class="c-condition-widget__label-wrapper"
|
||||
:href="url"
|
||||
>
|
||||
<div class="c-condition-widget__label">{{ label }}</div>
|
||||
</component>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -40,19 +42,26 @@ export default {
|
||||
inject: ['openmct', 'domainObject'],
|
||||
data: function () {
|
||||
return {
|
||||
conditionalLabel: '',
|
||||
conditionSetIdentifier: null,
|
||||
domainObjectLabel: '',
|
||||
url: null,
|
||||
urlDefined: false,
|
||||
useConditionSetOutputAsLabel: false
|
||||
conditionalLabel: ''
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
urlDefined() {
|
||||
return this.domainObject.url?.length > 0;
|
||||
},
|
||||
url() {
|
||||
return this.urlDefined ? sanitizeUrl(this.domainObject.url) : null;
|
||||
},
|
||||
useConditionSetOutputAsLabel() {
|
||||
return this.conditionSetIdentifier && this.domainObject.configuration.useConditionSetOutputAsLabel;
|
||||
},
|
||||
conditionSetIdentifier() {
|
||||
return this.domainObject.configuration?.objectStyles?.conditionSetIdentifier;
|
||||
},
|
||||
label() {
|
||||
return this.useConditionSetOutputAsLabel
|
||||
? this.conditionalLabel
|
||||
: this.domainObjectLabel
|
||||
: this.domainObject.label
|
||||
;
|
||||
}
|
||||
},
|
||||
@ -69,20 +78,11 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.unlisten = this.openmct.objects.observe(this.domainObject, '*', this.updateDomainObject);
|
||||
|
||||
if (this.domainObject) {
|
||||
this.updateDomainObject(this.domainObject);
|
||||
this.listenToConditionSetChanges();
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.conditionSetIdentifier = null;
|
||||
|
||||
if (this.unlisten) {
|
||||
this.unlisten();
|
||||
}
|
||||
|
||||
this.stopListeningToConditionSetChanges();
|
||||
},
|
||||
methods: {
|
||||
@ -121,31 +121,6 @@ export default {
|
||||
}
|
||||
|
||||
this.conditionalLabel = latestDatum.output || '';
|
||||
},
|
||||
updateDomainObject(domainObject) {
|
||||
if (this.domainObjectLabel !== domainObject.label) {
|
||||
this.domainObjectLabel = domainObject.label;
|
||||
}
|
||||
|
||||
const urlDefined = domainObject.url && domainObject.url.length > 0;
|
||||
if (this.urlDefined !== urlDefined) {
|
||||
this.urlDefined = urlDefined;
|
||||
}
|
||||
|
||||
const url = this.urlDefined ? sanitizeUrl(domainObject.url) : null;
|
||||
if (this.url !== url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
const conditionSetIdentifier = domainObject.configuration?.objectStyles?.conditionSetIdentifier;
|
||||
if (conditionSetIdentifier && this.conditionSetIdentifier !== conditionSetIdentifier) {
|
||||
this.conditionSetIdentifier = conditionSetIdentifier;
|
||||
}
|
||||
|
||||
const useConditionSetOutputAsLabel = this.conditionSetIdentifier && domainObject.configuration.useConditionSetOutputAsLabel;
|
||||
if (this.useConditionSetOutputAsLabel !== useConditionSetOutputAsLabel) {
|
||||
this.useConditionSetOutputAsLabel = useConditionSetOutputAsLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -26,31 +26,35 @@
|
||||
background-color: rgba($colorBodyFg, 0.1); // Give a little presence if the user hasn't defined a fill color
|
||||
border-radius: $basicCr;
|
||||
border: 1px solid transparent;
|
||||
display: inline-block;
|
||||
padding: $interiorMarginLg $interiorMarginLg * 2;
|
||||
display: block;
|
||||
max-width: max-content;
|
||||
|
||||
a {
|
||||
display: block;
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.c-condition-widget__label {
|
||||
padding: $interiorMargin;
|
||||
// Either a <div> or an <a> tag
|
||||
padding: $interiorMargin $interiorMargin * 1.5;
|
||||
text-align: center;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
a.c-condition-widget {
|
||||
// Widget is conditionally made into a <a> when URL property has been defined
|
||||
cursor: pointer !important;
|
||||
pointer-events: inherit;
|
||||
}
|
||||
|
||||
// Make Condition Widget expand when in a hidden frame Layout context
|
||||
// For both static and Flexible Layouts
|
||||
.c-so-view--conditionWidget.c-so-view--no-frame {
|
||||
.c-condition-widget {
|
||||
@include abs();
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
max-width: unset;
|
||||
|
||||
&__label-wrapper {
|
||||
@include abs();
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.c-so-view__frame-controls { display: none; }
|
||||
|
@ -36,6 +36,7 @@ export default function plugin() {
|
||||
domainObject.configuration = {};
|
||||
domainObject.label = 'Condition Widget';
|
||||
domainObject.conditionalLabel = '';
|
||||
domainObject.url = '';
|
||||
},
|
||||
form: [
|
||||
{
|
||||
|
@ -35,34 +35,34 @@ export default class DuplicateAction {
|
||||
}
|
||||
|
||||
invoke(objectPath) {
|
||||
this.object = objectPath[0];
|
||||
this.parent = objectPath[1];
|
||||
const object = objectPath[0];
|
||||
const parent = objectPath[1];
|
||||
|
||||
this.showForm(this.object, this.parent);
|
||||
this.showForm(object, parent);
|
||||
}
|
||||
|
||||
inNavigationPath() {
|
||||
inNavigationPath(object) {
|
||||
return this.openmct.router.path
|
||||
.some(objectInPath => this.openmct.objects.areIdsEqual(objectInPath.identifier, this.object.identifier));
|
||||
.some(objectInPath => this.openmct.objects.areIdsEqual(objectInPath.identifier, object.identifier));
|
||||
}
|
||||
|
||||
async onSave(changes) {
|
||||
async onSave(object, parent, changes) {
|
||||
this.startTransaction();
|
||||
|
||||
let inNavigationPath = this.inNavigationPath();
|
||||
let inNavigationPath = this.inNavigationPath(object);
|
||||
if (inNavigationPath && this.openmct.editor.isEditing()) {
|
||||
this.openmct.editor.save();
|
||||
}
|
||||
|
||||
let duplicationTask = new DuplicateTask(this.openmct);
|
||||
if (changes.name && (changes.name !== this.object.name)) {
|
||||
if (changes.name && (changes.name !== object.name)) {
|
||||
duplicationTask.changeName(changes.name);
|
||||
}
|
||||
|
||||
const parentDomainObjectpath = changes.location || [this.parent];
|
||||
const parent = parentDomainObjectpath[0];
|
||||
const parentDomainObjectpath = changes.location || [parent];
|
||||
const parentObject = parentDomainObjectpath[0];
|
||||
|
||||
await duplicationTask.duplicate(this.object, parent);
|
||||
await duplicationTask.duplicate(object, parentObject);
|
||||
|
||||
return this.saveTransaction();
|
||||
}
|
||||
@ -88,7 +88,7 @@ export default class DuplicateAction {
|
||||
control: "locator",
|
||||
required: true,
|
||||
parent: parentDomainObject,
|
||||
validate: this.validate(parentDomainObject),
|
||||
validate: this.validate(domainObject, parentDomainObject),
|
||||
key: 'location'
|
||||
}
|
||||
]
|
||||
@ -97,16 +97,19 @@ export default class DuplicateAction {
|
||||
};
|
||||
|
||||
this.openmct.forms.showForm(formStructure)
|
||||
.then(this.onSave.bind(this));
|
||||
.then(changes => {
|
||||
let onSave = this.onSave.bind(this);
|
||||
onSave(domainObject, parentDomainObject, changes);
|
||||
});
|
||||
}
|
||||
|
||||
validate(currentParent) {
|
||||
validate(domainObject, currentParent) {
|
||||
return (data) => {
|
||||
const parentCandidate = data.value[0];
|
||||
|
||||
let currentParentKeystring = this.openmct.objects.makeKeyString(currentParent.identifier);
|
||||
let parentCandidateKeystring = this.openmct.objects.makeKeyString(parentCandidate.identifier);
|
||||
let objectKeystring = this.openmct.objects.makeKeyString(this.object.identifier);
|
||||
let objectKeystring = this.openmct.objects.makeKeyString(domainObject.identifier);
|
||||
|
||||
if (!this.openmct.objects.isPersistable(parentCandidate.identifier)) {
|
||||
return false;
|
||||
@ -125,7 +128,7 @@ export default class DuplicateAction {
|
||||
return false;
|
||||
}
|
||||
|
||||
return parentCandidate && this.openmct.composition.checkPolicy(parentCandidate, this.object);
|
||||
return parentCandidate && this.openmct.composition.checkPolicy(parentCandidate, domainObject);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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 = "json";
|
||||
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,74 +234,80 @@ 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
|
||||
*/
|
||||
_rewriteReferences() {
|
||||
const oldKeyStrings = Object.keys(this.idMap);
|
||||
let treeString = JSON.stringify(this.tree);
|
||||
Object.keys(this.idMap).forEach(function (oldId) {
|
||||
const newId = this.idMap[oldId];
|
||||
treeString = treeString.split(oldId).join(newId);
|
||||
}.bind(this));
|
||||
|
||||
oldKeyStrings.forEach((oldKeyString) => {
|
||||
// this will cover keyStrings, identifiers and identifiers created
|
||||
// by hand that may be structured differently from those created with 'makeKeyString'
|
||||
const newKeyString = this.idMap[oldKeyString];
|
||||
const newIdentifier = JSON.stringify(this.openmct.objects.parseKeyString(newKeyString));
|
||||
const oldIdentifier = this.openmct.objects.parseKeyString(oldKeyString);
|
||||
const oldIdentifierNamespaceFirst = JSON.stringify(oldIdentifier);
|
||||
const oldIdentifierKeyFirst = JSON.stringify({
|
||||
key: oldIdentifier.key,
|
||||
namespace: oldIdentifier.namespace
|
||||
});
|
||||
|
||||
// replace keyStrings
|
||||
treeString = treeString.split(oldKeyString).join(newKeyString);
|
||||
|
||||
// check for namespace first identifiers, replace if necessary
|
||||
if (treeString.includes(oldIdentifierNamespaceFirst)) {
|
||||
treeString = treeString.split(oldIdentifierNamespaceFirst).join(newIdentifier);
|
||||
}
|
||||
|
||||
// check for key first identifiers, replace if necessary
|
||||
if (treeString.includes(oldIdentifierKeyFirst)) {
|
||||
treeString = treeString.split(oldIdentifierKeyFirst).join(newIdentifier);
|
||||
}
|
||||
|
||||
});
|
||||
this.tree = JSON.parse(treeString);
|
||||
}
|
||||
/**
|
||||
@ -180,70 +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);
|
||||
}
|
||||
}
|
||||
});
|
||||
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) {
|
||||
@ -251,4 +338,8 @@ export default class ExportAsJSONAction {
|
||||
this._saveAs(this._wrapTree());
|
||||
}
|
||||
}
|
||||
|
||||
_copy(object) {
|
||||
return JSON.parse(JSON.stringify(object));
|
||||
}
|
||||
}
|
||||
|
@ -56,6 +56,10 @@ define([
|
||||
});
|
||||
},
|
||||
showTab: function (isEditing) {
|
||||
if (isEditing) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const hasPersistedFilters = Boolean(domainObject?.configuration?.filters);
|
||||
const hasGlobalFilters = Boolean(domainObject?.configuration?.globalFilters);
|
||||
|
||||
|
@ -64,6 +64,11 @@ export default class CreateAction extends PropertiesAction {
|
||||
|
||||
const parentDomainObject = this.openmct.objects.toMutable(parentDomainObjectPath[0]);
|
||||
|
||||
// TODO REMOVE FOR OMM-RELEASE-5.0
|
||||
if (!parentDomainObject.identifier.namespace && parentDomainObject.key) {
|
||||
console.error(`parent namespace in key: ${parentDomainObject.key}`);
|
||||
}
|
||||
|
||||
this.domainObject.modified = Date.now();
|
||||
this.domainObject.location = this.openmct.objects.makeKeyString(parentDomainObject.identifier);
|
||||
this.domainObject.identifier.namespace = parentDomainObject.identifier.namespace;
|
||||
|
@ -31,6 +31,7 @@ export default class ImportAsJSONAction {
|
||||
this.cssClass = "icon-import";
|
||||
this.group = "json";
|
||||
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
|
||||
|
@ -19,7 +19,7 @@
|
||||
class="c-icon-button c-button--menu icon-font"
|
||||
@click.prevent.stop="showFontMenu"
|
||||
>
|
||||
<span class="c-button__label">{{ fontTypeLable }}</span>
|
||||
<span class="c-button__label">{{ fontTypeLabel }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -43,7 +43,7 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
fontTypeLable() {
|
||||
fontTypeLabel() {
|
||||
const fontType = FONTS.find(f => f.value === this.fontStyle.font);
|
||||
if (!fontType) {
|
||||
return '??';
|
||||
|
@ -88,7 +88,7 @@ define([], function () {
|
||||
}
|
||||
|
||||
getContextMenuActions() {
|
||||
return ['viewDatumAction'];
|
||||
return ['viewDatumAction', 'viewHistoricalData'];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,14 +175,22 @@ export default {
|
||||
getDatum() {
|
||||
return this.row.fullDatum;
|
||||
},
|
||||
showContextMenu: function (event) {
|
||||
showContextMenu: async function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
this.updateViewContext();
|
||||
this.markRow(event);
|
||||
|
||||
const contextualDomainObject = await this.row.getContextualDomainObject?.(this.openmct, this.row.objectKeyString);
|
||||
|
||||
let objectPath = this.objectPath;
|
||||
if (contextualDomainObject) {
|
||||
objectPath = objectPath.slice();
|
||||
objectPath.unshift(contextualDomainObject);
|
||||
}
|
||||
|
||||
const actions = this.row.getContextMenuActions().map(key => this.openmct.actions.getAction(key));
|
||||
const menuItems = this.openmct.menus.actionsToMenuItems(actions, this.objectPath, this.currentView);
|
||||
const menuItems = this.openmct.menus.actionsToMenuItems(actions, objectPath, this.currentView);
|
||||
if (menuItems.length) {
|
||||
this.openmct.menus.showMenu(event.x, event.y, menuItems);
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ export default {
|
||||
return this.domainObject && (this.currentObjectPath || this.objectPath);
|
||||
},
|
||||
objectFontStyle() {
|
||||
return this.domainObject && this.domainObject.configuration && this.domainObject.configuration.fontStyle;
|
||||
return this.domainObject?.configuration?.fontStyle;
|
||||
},
|
||||
fontSize() {
|
||||
return this.objectFontStyle ? this.objectFontStyle.fontSize : this.layoutFontSize;
|
||||
@ -287,6 +287,8 @@ export default {
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.updateStyle(this.styleRuleManager?.currentStyle);
|
||||
this.setFontSize(this.fontSize);
|
||||
this.setFont(this.font);
|
||||
this.getActionCollection();
|
||||
});
|
||||
},
|
||||
@ -329,9 +331,9 @@ export default {
|
||||
},
|
||||
initObjectStyles() {
|
||||
if (!this.styleRuleManager) {
|
||||
this.styleRuleManager = new StyleRuleManager((this.domainObject.configuration && this.domainObject.configuration.objectStyles), this.openmct, this.updateStyle.bind(this), true);
|
||||
this.styleRuleManager = new StyleRuleManager((this.domainObject.configuration?.objectStyles), this.openmct, this.updateStyle.bind(this), true);
|
||||
} else {
|
||||
this.styleRuleManager.updateObjectStyleConfig(this.domainObject.configuration && this.domainObject.configuration.objectStyles);
|
||||
this.styleRuleManager.updateObjectStyleConfig(this.domainObject.configuration?.objectStyles);
|
||||
}
|
||||
|
||||
if (this.stopListeningStyles) {
|
||||
@ -343,9 +345,6 @@ export default {
|
||||
this.styleRuleManager.updateObjectStyleConfig(newObjectStyle);
|
||||
});
|
||||
|
||||
this.setFontSize(this.fontSize);
|
||||
this.setFont(this.font);
|
||||
|
||||
this.stopListeningFontStyles = this.openmct.objects.observe(this.domainObject, 'configuration.fontStyle', (newFontStyle) => {
|
||||
this.setFontSize(newFontStyle.fontSize);
|
||||
this.setFont(newFontStyle.font);
|
||||
|
@ -322,10 +322,14 @@ export default {
|
||||
},
|
||||
async openTreeItem(parentItem) {
|
||||
const parentPath = parentItem.navigationPath;
|
||||
const abortSignal = this.startItemLoad(parentPath);
|
||||
|
||||
this.startItemLoad(parentPath);
|
||||
// pass in abort signal when functional
|
||||
const childrenItems = await this.loadAndBuildTreeItemsFor(parentItem.object.identifier, parentItem.objectPath);
|
||||
const childrenItems = await this.loadAndBuildTreeItemsFor(
|
||||
parentItem.object.identifier,
|
||||
parentItem.objectPath,
|
||||
abortSignal
|
||||
);
|
||||
const parentIndex = this.treeItems.indexOf(parentItem);
|
||||
|
||||
// if it's not loading, it was aborted
|
||||
|
Reference in New Issue
Block a user