mirror of
https://github.com/nasa/openmct.git
synced 2024-12-23 15:02:23 +00:00
Correctly use creatable attribute and persistability when working with domainObjects (#4898)
* making move action location check persistability * adding persistence check instead of creatability for styles * added check for link action to make sure parent is persistable * debug * adding parent to link action and move action form location controls so they can be used in the form * adding parent persistability check for duplicate * updating multilple actions appliesTo methods to check for persistability * updated the tree to not require an initial selection if being used in a form * remove noneditable folder plugin * added persistence check for the parent, in the create wizard * minor name change * removing noneditabl folder from default plugins as well * checking the correct parent for persistability in create wizard * importing file-saver correctly * updated tests for import as json * changes addressing PR review: using consts, removing comments, removing unneccessary code Co-authored-by: Scott Bell <scott@traclabs.com>
This commit is contained in:
parent
bcd668594d
commit
e691a89682
@ -269,7 +269,6 @@ define([
|
|||||||
this.install(this.plugins.ViewDatumAction());
|
this.install(this.plugins.ViewDatumAction());
|
||||||
this.install(this.plugins.ViewLargeAction());
|
this.install(this.plugins.ViewLargeAction());
|
||||||
this.install(this.plugins.ObjectInterceptors());
|
this.install(this.plugins.ObjectInterceptors());
|
||||||
this.install(this.plugins.NonEditableFolder());
|
|
||||||
this.install(this.plugins.DeviceClassifier());
|
this.install(this.plugins.DeviceClassifier());
|
||||||
this.install(this.plugins.UserIndicator());
|
this.install(this.plugins.UserIndicator());
|
||||||
}
|
}
|
||||||
|
@ -325,16 +325,7 @@ export default {
|
|||||||
return item && (item.type === type);
|
return item && (item.type === type);
|
||||||
},
|
},
|
||||||
canPersistObject(item) {
|
canPersistObject(item) {
|
||||||
// for now the only way to tell if an object can be persisted is if it is creatable.
|
return this.openmct.objects.isPersistable(item.identifier);
|
||||||
let creatable = false;
|
|
||||||
if (item) {
|
|
||||||
const type = this.openmct.types.get(item.type);
|
|
||||||
if (type && type.definition) {
|
|
||||||
creatable = (type.definition.creatable !== undefined && (type.definition.creatable === 'true' || type.definition.creatable === true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return creatable;
|
|
||||||
},
|
},
|
||||||
hasConditionalStyle(domainObject, layoutItem) {
|
hasConditionalStyle(domainObject, layoutItem) {
|
||||||
const id = layoutItem ? layoutItem.id : undefined;
|
const id = layoutItem ? layoutItem.id : undefined;
|
||||||
|
@ -97,13 +97,16 @@ export default class DuplicateAction {
|
|||||||
|
|
||||||
validate(currentParent) {
|
validate(currentParent) {
|
||||||
return (data) => {
|
return (data) => {
|
||||||
const parentCandidatePath = data.value;
|
const parentCandidate = data.value[0];
|
||||||
const parentCandidate = parentCandidatePath[0];
|
|
||||||
|
|
||||||
let currentParentKeystring = this.openmct.objects.makeKeyString(currentParent.identifier);
|
let currentParentKeystring = this.openmct.objects.makeKeyString(currentParent.identifier);
|
||||||
let parentCandidateKeystring = this.openmct.objects.makeKeyString(parentCandidate.identifier);
|
let parentCandidateKeystring = this.openmct.objects.makeKeyString(parentCandidate.identifier);
|
||||||
let objectKeystring = this.openmct.objects.makeKeyString(this.object.identifier);
|
let objectKeystring = this.openmct.objects.makeKeyString(this.object.identifier);
|
||||||
|
|
||||||
|
if (!this.openmct.objects.isPersistable(parentCandidate.identifier)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!parentCandidateKeystring || !currentParentKeystring) {
|
if (!parentCandidateKeystring || !currentParentKeystring) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -122,13 +125,14 @@ export default class DuplicateAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
appliesTo(objectPath) {
|
appliesTo(objectPath) {
|
||||||
let parent = objectPath[1];
|
const parent = objectPath[1];
|
||||||
let parentType = parent && this.openmct.types.get(parent.type);
|
const parentType = parent && this.openmct.types.get(parent.type);
|
||||||
let child = objectPath[0];
|
const child = objectPath[0];
|
||||||
let childType = child && this.openmct.types.get(child.type);
|
const childType = child && this.openmct.types.get(child.type);
|
||||||
let locked = child.locked ? child.locked : parent && parent.locked;
|
const locked = child.locked ? child.locked : parent && parent.locked;
|
||||||
|
const isPersistable = this.openmct.objects.isPersistable(child.identifier);
|
||||||
|
|
||||||
if (locked) {
|
if (locked || !isPersistable) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ export default class ExportAsJSONAction {
|
|||||||
appliesTo(objectPath) {
|
appliesTo(objectPath) {
|
||||||
let domainObject = objectPath[0];
|
let domainObject = objectPath[0];
|
||||||
|
|
||||||
return this._isCreatable(domainObject);
|
return this._isCreatableAndPersistable(domainObject);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -80,10 +80,11 @@ export default class ExportAsJSONAction {
|
|||||||
* @param {object} domainObject
|
* @param {object} domainObject
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
_isCreatable(domainObject) {
|
_isCreatableAndPersistable(domainObject) {
|
||||||
const type = this.openmct.types.get(domainObject.type);
|
const type = this.openmct.types.get(domainObject.type);
|
||||||
|
const isPersistable = this.openmct.objects.isPersistable(domainObject.identifier);
|
||||||
|
|
||||||
return type && type.definition.creatable;
|
return type && type.definition.creatable && isPersistable;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
@ -170,7 +171,7 @@ export default class ExportAsJSONAction {
|
|||||||
.then((children) => {
|
.then((children) => {
|
||||||
children.forEach((child, index) => {
|
children.forEach((child, index) => {
|
||||||
// Only export if object is creatable
|
// Only export if object is creatable
|
||||||
if (this._isCreatable(child)) {
|
if (this._isCreatableAndPersistable(child)) {
|
||||||
// Prevents infinite export of self-contained objs
|
// Prevents infinite export of self-contained objs
|
||||||
if (!Object.prototype.hasOwnProperty.call(this.tree, this._getId(child))) {
|
if (!Object.prototype.hasOwnProperty.call(this.tree, this._getId(child))) {
|
||||||
// If object is a link to something absent from
|
// If object is a link to something absent from
|
||||||
|
@ -27,6 +27,10 @@ describe('Export as JSON plugin', () => {
|
|||||||
|
|
||||||
it('ExportAsJSONAction applies to folder', () => {
|
it('ExportAsJSONAction applies to folder', () => {
|
||||||
domainObject = {
|
domainObject = {
|
||||||
|
identifier: {
|
||||||
|
key: 'export-testing',
|
||||||
|
namespace: ''
|
||||||
|
},
|
||||||
composition: [],
|
composition: [],
|
||||||
location: 'mine',
|
location: 'mine',
|
||||||
modified: 1640115501237,
|
modified: 1640115501237,
|
||||||
@ -40,6 +44,10 @@ describe('Export as JSON plugin', () => {
|
|||||||
|
|
||||||
it('ExportAsJSONAction applies to telemetry.plot.overlay', () => {
|
it('ExportAsJSONAction applies to telemetry.plot.overlay', () => {
|
||||||
domainObject = {
|
domainObject = {
|
||||||
|
identifier: {
|
||||||
|
key: 'export-testing',
|
||||||
|
namespace: ''
|
||||||
|
},
|
||||||
composition: [],
|
composition: [],
|
||||||
location: 'mine',
|
location: 'mine',
|
||||||
modified: 1640115501237,
|
modified: 1640115501237,
|
||||||
@ -53,6 +61,10 @@ describe('Export as JSON plugin', () => {
|
|||||||
|
|
||||||
it('ExportAsJSONAction applies to telemetry.plot.stacked', () => {
|
it('ExportAsJSONAction applies to telemetry.plot.stacked', () => {
|
||||||
domainObject = {
|
domainObject = {
|
||||||
|
identifier: {
|
||||||
|
key: 'export-testing',
|
||||||
|
namespace: ''
|
||||||
|
},
|
||||||
composition: [],
|
composition: [],
|
||||||
location: 'mine',
|
location: 'mine',
|
||||||
modified: 1640115501237,
|
modified: 1640115501237,
|
||||||
@ -64,16 +76,24 @@ describe('Export as JSON plugin', () => {
|
|||||||
expect(exportAsJSONAction.appliesTo([domainObject])).toEqual(true);
|
expect(exportAsJSONAction.appliesTo([domainObject])).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('ExportAsJSONAction applies does not applies to non-creatable objects', () => {
|
it('ExportAsJSONAction does not applie to non-persistable objects', () => {
|
||||||
domainObject = {
|
domainObject = {
|
||||||
|
identifier: {
|
||||||
|
key: 'export-testing',
|
||||||
|
namespace: ''
|
||||||
|
},
|
||||||
composition: [],
|
composition: [],
|
||||||
location: 'mine',
|
location: 'mine',
|
||||||
modified: 1640115501237,
|
modified: 1640115501237,
|
||||||
name: 'Non Editable Folder',
|
name: 'Non Editable Folder',
|
||||||
persisted: 1640115501237,
|
persisted: 1640115501237,
|
||||||
type: 'noneditable.folder'
|
type: 'folder'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
spyOn(openmct.objects, 'getProvider').and.callFake(() => {
|
||||||
|
return { get: () => domainObject };
|
||||||
|
});
|
||||||
|
|
||||||
expect(exportAsJSONAction.appliesTo([domainObject])).toEqual(false);
|
expect(exportAsJSONAction.appliesTo([domainObject])).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -101,7 +101,10 @@ export default class CreateWizard {
|
|||||||
// Ensure there is always a 'save in' section
|
// Ensure there is always a 'save in' section
|
||||||
if (includeLocation) {
|
if (includeLocation) {
|
||||||
function validateLocation(data) {
|
function validateLocation(data) {
|
||||||
return self.openmct.composition.checkPolicy(data.value[0], domainObject);
|
const policyCheck = self.openmct.composition.checkPolicy(data.value[0], domainObject);
|
||||||
|
const parentIsPersistable = self.openmct.objects.isPersistable(data.value[0].identifier);
|
||||||
|
|
||||||
|
return policyCheck && parentIsPersistable;
|
||||||
}
|
}
|
||||||
|
|
||||||
sections.push({
|
sections.push({
|
||||||
|
@ -33,10 +33,7 @@ export default class LinkAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
appliesTo(objectPath) {
|
appliesTo(objectPath) {
|
||||||
let domainObject = objectPath[0];
|
return true; // link away!
|
||||||
let type = domainObject && this.openmct.types.get(domainObject.type);
|
|
||||||
|
|
||||||
return type && type.definition.creatable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
invoke(objectPath) {
|
invoke(objectPath) {
|
||||||
@ -77,6 +74,7 @@ export default class LinkAction {
|
|||||||
{
|
{
|
||||||
name: "location",
|
name: "location",
|
||||||
control: "locator",
|
control: "locator",
|
||||||
|
parent: parentDomainObject,
|
||||||
required: true,
|
required: true,
|
||||||
validate: this.validate(parentDomainObject),
|
validate: this.validate(parentDomainObject),
|
||||||
key: 'location'
|
key: 'location'
|
||||||
@ -97,6 +95,10 @@ export default class LinkAction {
|
|||||||
const parentCandidateKeystring = this.openmct.objects.makeKeyString(parentCandidate.identifier);
|
const parentCandidateKeystring = this.openmct.objects.makeKeyString(parentCandidate.identifier);
|
||||||
const objectKeystring = this.openmct.objects.makeKeyString(this.object.identifier);
|
const objectKeystring = this.openmct.objects.makeKeyString(this.object.identifier);
|
||||||
|
|
||||||
|
if (!this.openmct.objects.isPersistable(parentCandidate.identifier)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!parentCandidateKeystring || !currentParentKeystring) {
|
if (!parentCandidateKeystring || !currentParentKeystring) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -126,6 +126,7 @@ export default class MoveAction {
|
|||||||
{
|
{
|
||||||
name: "Location",
|
name: "Location",
|
||||||
control: "locator",
|
control: "locator",
|
||||||
|
parent: parentDomainObject,
|
||||||
required: true,
|
required: true,
|
||||||
validate: this.validate(parentDomainObject),
|
validate: this.validate(parentDomainObject),
|
||||||
key: 'location'
|
key: 'location'
|
||||||
@ -144,6 +145,10 @@ export default class MoveAction {
|
|||||||
const parentCandidatePath = data.value;
|
const parentCandidatePath = data.value;
|
||||||
const parentCandidate = parentCandidatePath[0];
|
const parentCandidate = parentCandidatePath[0];
|
||||||
|
|
||||||
|
if (!this.openmct.objects.isPersistable(parentCandidate.identifier)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
let currentParentKeystring = this.openmct.objects.makeKeyString(currentParent.identifier);
|
let currentParentKeystring = this.openmct.objects.makeKeyString(currentParent.identifier);
|
||||||
let parentCandidateKeystring = this.openmct.objects.makeKeyString(parentCandidate.identifier);
|
let parentCandidateKeystring = this.openmct.objects.makeKeyString(parentCandidate.identifier);
|
||||||
let objectKeystring = this.openmct.objects.makeKeyString(this.object.identifier);
|
let objectKeystring = this.openmct.objects.makeKeyString(this.object.identifier);
|
||||||
@ -174,8 +179,9 @@ export default class MoveAction {
|
|||||||
let parentType = parent && this.openmct.types.get(parent.type);
|
let parentType = parent && this.openmct.types.get(parent.type);
|
||||||
let child = objectPath[0];
|
let child = objectPath[0];
|
||||||
let childType = child && this.openmct.types.get(child.type);
|
let childType = child && this.openmct.types.get(child.type);
|
||||||
|
let isPersistable = this.openmct.objects.isPersistable(child.identifier);
|
||||||
|
|
||||||
if (child.locked || (parent && parent.locked)) {
|
if (child.locked || (parent && parent.locked) || !isPersistable) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
* Administration. All rights reserved.
|
|
||||||
*
|
|
||||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*
|
|
||||||
* Open MCT includes source code licensed under additional open source
|
|
||||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
||||||
* this source code distribution or the Licensing information page available
|
|
||||||
* at runtime from the About dialog for additional information.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
export default function () {
|
|
||||||
return function (openmct) {
|
|
||||||
openmct.types.addType("noneditable.folder", {
|
|
||||||
name: "Non-Editable Folder",
|
|
||||||
key: "noneditable.folder",
|
|
||||||
description: "Create folders to organize other objects or links to objects without the ability to edit it's properties.",
|
|
||||||
cssClass: "icon-folder",
|
|
||||||
creatable: false
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2022, United States Government
|
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
* Administration. All rights reserved.
|
|
||||||
*
|
|
||||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*
|
|
||||||
* Open MCT includes source code licensed under additional open source
|
|
||||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
||||||
* this source code distribution or the Licensing information page available
|
|
||||||
* at runtime from the About dialog for additional information.
|
|
||||||
*****************************************************************************/
|
|
||||||
import {
|
|
||||||
createOpenMct,
|
|
||||||
resetApplicationState
|
|
||||||
} from 'utils/testing';
|
|
||||||
|
|
||||||
describe("the plugin", () => {
|
|
||||||
const NON_EDITABLE_FOLDER_KEY = 'noneditable.folder';
|
|
||||||
let openmct;
|
|
||||||
|
|
||||||
beforeEach((done) => {
|
|
||||||
openmct = createOpenMct();
|
|
||||||
openmct.install(openmct.plugins.NonEditableFolder());
|
|
||||||
|
|
||||||
openmct.on('start', done);
|
|
||||||
openmct.startHeadless();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
return resetApplicationState(openmct);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('adds the new non-editable folder type', () => {
|
|
||||||
const type = openmct.types.get(NON_EDITABLE_FOLDER_KEY);
|
|
||||||
|
|
||||||
expect(type).toBeDefined();
|
|
||||||
expect(type.definition.creatable).toBeFalse();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
@ -61,7 +61,6 @@ define([
|
|||||||
'./URLTimeSettingsSynchronizer/plugin',
|
'./URLTimeSettingsSynchronizer/plugin',
|
||||||
'./notificationIndicator/plugin',
|
'./notificationIndicator/plugin',
|
||||||
'./newFolderAction/plugin',
|
'./newFolderAction/plugin',
|
||||||
'./nonEditableFolder/plugin',
|
|
||||||
'./persistence/couch/plugin',
|
'./persistence/couch/plugin',
|
||||||
'./defaultRootName/plugin',
|
'./defaultRootName/plugin',
|
||||||
'./plan/plugin',
|
'./plan/plugin',
|
||||||
@ -119,7 +118,6 @@ define([
|
|||||||
URLTimeSettingsSynchronizer,
|
URLTimeSettingsSynchronizer,
|
||||||
NotificationIndicator,
|
NotificationIndicator,
|
||||||
NewFolderAction,
|
NewFolderAction,
|
||||||
NonEditableFolder,
|
|
||||||
CouchDBPlugin,
|
CouchDBPlugin,
|
||||||
DefaultRootName,
|
DefaultRootName,
|
||||||
PlanLayout,
|
PlanLayout,
|
||||||
@ -197,7 +195,6 @@ define([
|
|||||||
plugins.URLTimeSettingsSynchronizer = URLTimeSettingsSynchronizer.default;
|
plugins.URLTimeSettingsSynchronizer = URLTimeSettingsSynchronizer.default;
|
||||||
plugins.NotificationIndicator = NotificationIndicator.default;
|
plugins.NotificationIndicator = NotificationIndicator.default;
|
||||||
plugins.NewFolderAction = NewFolderAction.default;
|
plugins.NewFolderAction = NewFolderAction.default;
|
||||||
plugins.NonEditableFolder = NonEditableFolder.default;
|
|
||||||
plugins.ISOTimeFormat = ISOTimeFormat.default;
|
plugins.ISOTimeFormat = ISOTimeFormat.default;
|
||||||
plugins.DefaultRootName = DefaultRootName.default;
|
plugins.DefaultRootName = DefaultRootName.default;
|
||||||
plugins.PlanLayout = PlanLayout.default;
|
plugins.PlanLayout = PlanLayout.default;
|
||||||
|
@ -106,6 +106,11 @@ export default class RemoveAction {
|
|||||||
let child = objectPath[0];
|
let child = objectPath[0];
|
||||||
let locked = child.locked ? child.locked : parent && parent.locked;
|
let locked = child.locked ? child.locked : parent && parent.locked;
|
||||||
let isEditing = this.openmct.editor.isEditing();
|
let isEditing = this.openmct.editor.isEditing();
|
||||||
|
let isPersistable = this.openmct.objects.isPersistable(child.identifier);
|
||||||
|
|
||||||
|
if (locked || !isPersistable) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (isEditing) {
|
if (isEditing) {
|
||||||
let currentItemInView = this.openmct.router.path[0];
|
let currentItemInView = this.openmct.router.path[0];
|
||||||
@ -116,10 +121,6 @@ export default class RemoveAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locked) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return parentType
|
return parentType
|
||||||
&& parentType.definition.creatable
|
&& parentType.definition.creatable
|
||||||
&& Array.isArray(parent.composition);
|
&& Array.isArray(parent.composition);
|
||||||
|
@ -258,11 +258,13 @@ export default {
|
|||||||
if (!this.isSelectorTree) {
|
if (!this.isSelectorTree) {
|
||||||
await this.syncTreeOpenItems();
|
await this.syncTreeOpenItems();
|
||||||
} else {
|
} else {
|
||||||
|
if (this.initialSelection.identifier) {
|
||||||
const objectPath = await this.openmct.objects.getOriginalPath(this.initialSelection.identifier);
|
const objectPath = await this.openmct.objects.getOriginalPath(this.initialSelection.identifier);
|
||||||
const navigationPath = this.buildNavigationPath(objectPath);
|
const navigationPath = this.buildNavigationPath(objectPath);
|
||||||
|
|
||||||
this.openAndScrollTo(navigationPath);
|
this.openAndScrollTo(navigationPath);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.getSearchResults = _.debounce(this.getSearchResults, 400);
|
this.getSearchResults = _.debounce(this.getSearchResults, 400);
|
||||||
|
Loading…
Reference in New Issue
Block a user