mirror of
https://github.com/nasa/openmct.git
synced 2025-06-18 07:08:12 +00:00
Elements pool and drag drop (#2196)
* Implemented drag-and-drop composition * Added composition policy for tables * Reimplemented elements pool in Vue * No need to resolve all objects on the navigated path * Only show elements pool in edit mode * Remove old elements pool * Updated legacy code to use composition policy API * Keep object in sync when mutated
This commit is contained in:
committed by
Pete Richards
parent
a296bc2b81
commit
cbcfd44016
@ -23,7 +23,6 @@
|
|||||||
define([
|
define([
|
||||||
"./src/controllers/EditActionController",
|
"./src/controllers/EditActionController",
|
||||||
"./src/controllers/EditPanesController",
|
"./src/controllers/EditPanesController",
|
||||||
"./src/controllers/ElementsController",
|
|
||||||
"./src/controllers/EditObjectController",
|
"./src/controllers/EditObjectController",
|
||||||
"./src/actions/EditAndComposeAction",
|
"./src/actions/EditAndComposeAction",
|
||||||
"./src/actions/EditAction",
|
"./src/actions/EditAction",
|
||||||
@ -47,7 +46,6 @@ define([
|
|||||||
"./src/creation/LocatorController",
|
"./src/creation/LocatorController",
|
||||||
"./src/creation/CreationPolicy",
|
"./src/creation/CreationPolicy",
|
||||||
"./src/creation/CreateActionProvider",
|
"./src/creation/CreateActionProvider",
|
||||||
"./src/creation/AddActionProvider",
|
|
||||||
"./src/creation/CreationService",
|
"./src/creation/CreationService",
|
||||||
"./res/templates/create/locator.html",
|
"./res/templates/create/locator.html",
|
||||||
"./res/templates/create/create-button.html",
|
"./res/templates/create/create-button.html",
|
||||||
@ -55,13 +53,11 @@ define([
|
|||||||
"./res/templates/library.html",
|
"./res/templates/library.html",
|
||||||
"./res/templates/edit-object.html",
|
"./res/templates/edit-object.html",
|
||||||
"./res/templates/edit-action-buttons.html",
|
"./res/templates/edit-action-buttons.html",
|
||||||
"./res/templates/elements.html",
|
|
||||||
"./res/templates/topbar-edit.html",
|
"./res/templates/topbar-edit.html",
|
||||||
'legacyRegistry'
|
'legacyRegistry'
|
||||||
], function (
|
], function (
|
||||||
EditActionController,
|
EditActionController,
|
||||||
EditPanesController,
|
EditPanesController,
|
||||||
ElementsController,
|
|
||||||
EditObjectController,
|
EditObjectController,
|
||||||
EditAndComposeAction,
|
EditAndComposeAction,
|
||||||
EditAction,
|
EditAction,
|
||||||
@ -85,7 +81,6 @@ define([
|
|||||||
LocatorController,
|
LocatorController,
|
||||||
CreationPolicy,
|
CreationPolicy,
|
||||||
CreateActionProvider,
|
CreateActionProvider,
|
||||||
AddActionProvider,
|
|
||||||
CreationService,
|
CreationService,
|
||||||
locatorTemplate,
|
locatorTemplate,
|
||||||
createButtonTemplate,
|
createButtonTemplate,
|
||||||
@ -93,7 +88,6 @@ define([
|
|||||||
libraryTemplate,
|
libraryTemplate,
|
||||||
editObjectTemplate,
|
editObjectTemplate,
|
||||||
editActionButtonsTemplate,
|
editActionButtonsTemplate,
|
||||||
elementsTemplate,
|
|
||||||
topbarEditTemplate,
|
topbarEditTemplate,
|
||||||
legacyRegistry
|
legacyRegistry
|
||||||
) {
|
) {
|
||||||
@ -115,14 +109,6 @@ define([
|
|||||||
"$scope"
|
"$scope"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"key": "ElementsController",
|
|
||||||
"implementation": ElementsController,
|
|
||||||
"depends": [
|
|
||||||
"$scope",
|
|
||||||
"openmct"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"key": "EditObjectController",
|
"key": "EditObjectController",
|
||||||
"implementation": EditObjectController,
|
"implementation": EditObjectController,
|
||||||
@ -225,10 +211,10 @@ define([
|
|||||||
"description": "Save changes made to these objects.",
|
"description": "Save changes made to these objects.",
|
||||||
"depends": [
|
"depends": [
|
||||||
"$injector",
|
"$injector",
|
||||||
"policyService",
|
|
||||||
"dialogService",
|
"dialogService",
|
||||||
"copyService",
|
"copyService",
|
||||||
"notificationService"
|
"notificationService",
|
||||||
|
"openmct"
|
||||||
],
|
],
|
||||||
"priority": "mandatory"
|
"priority": "mandatory"
|
||||||
},
|
},
|
||||||
@ -296,13 +282,6 @@ define([
|
|||||||
"action"
|
"action"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"key": "edit-elements",
|
|
||||||
"template": elementsTemplate,
|
|
||||||
"gestures": [
|
|
||||||
"drop"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"key": "topbar-edit",
|
"key": "topbar-edit",
|
||||||
"template": topbarEditTemplate
|
"template": topbarEditTemplate
|
||||||
@ -319,12 +298,6 @@ define([
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"templates": [
|
|
||||||
{
|
|
||||||
key: "elementsPool",
|
|
||||||
template: elementsTemplate
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"components": [
|
"components": [
|
||||||
{
|
{
|
||||||
"type": "decorator",
|
"type": "decorator",
|
||||||
@ -356,18 +329,6 @@ define([
|
|||||||
"policyService"
|
"policyService"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"key": "AddActionProvider",
|
|
||||||
"provides": "actionService",
|
|
||||||
"type": "provider",
|
|
||||||
"implementation": AddActionProvider,
|
|
||||||
"depends": [
|
|
||||||
"$q",
|
|
||||||
"typeService",
|
|
||||||
"dialogService",
|
|
||||||
"policyService"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"key": "CreationService",
|
"key": "CreationService",
|
||||||
"provides": "creationService",
|
"provides": "creationService",
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
<!--
|
|
||||||
Open MCT, Copyright (c) 2014-2018, 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.
|
|
||||||
-->
|
|
||||||
<div ng-controller="ElementsController" class="flex-elem l-flex-col holder grows">
|
|
||||||
<mct-include key="'input-filter'"
|
|
||||||
class="flex-elem holder"
|
|
||||||
ng-model="filterBy">
|
|
||||||
</mct-include>
|
|
||||||
<div class="flex-elem grows vscroll scroll-pad">
|
|
||||||
<ul class="tree" id="inspector-elements-tree"
|
|
||||||
ng-if="composition.length > 0">
|
|
||||||
<li ng-repeat="containedObject in composition | filter:searchElements">
|
|
||||||
<span class="tree-item">
|
|
||||||
<span class="grippy-sm"
|
|
||||||
ng-if="composition.length > 1"
|
|
||||||
data-id="{{ containedObject.id }}"
|
|
||||||
mct-drag-down="dragDown($event)"
|
|
||||||
mct-drag="drag($event)"
|
|
||||||
mct-drag-up="dragUp($event)">
|
|
||||||
</span>
|
|
||||||
<mct-representation
|
|
||||||
class="rep-object-label"
|
|
||||||
key="'label'"
|
|
||||||
mct-object="containedObject">
|
|
||||||
</mct-representation>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div ng-if="composition.length === 0">No contained elements</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -40,20 +40,20 @@ function (
|
|||||||
*/
|
*/
|
||||||
function SaveAsAction(
|
function SaveAsAction(
|
||||||
$injector,
|
$injector,
|
||||||
policyService,
|
|
||||||
dialogService,
|
dialogService,
|
||||||
copyService,
|
copyService,
|
||||||
notificationService,
|
notificationService,
|
||||||
|
openmct,
|
||||||
context
|
context
|
||||||
) {
|
) {
|
||||||
this.domainObject = (context || {}).domainObject;
|
this.domainObject = (context || {}).domainObject;
|
||||||
this.injectObjectService = function () {
|
this.injectObjectService = function () {
|
||||||
this.objectService = $injector.get("objectService");
|
this.objectService = $injector.get("objectService");
|
||||||
};
|
};
|
||||||
this.policyService = policyService;
|
|
||||||
this.dialogService = dialogService;
|
this.dialogService = dialogService;
|
||||||
this.copyService = copyService;
|
this.copyService = copyService;
|
||||||
this.notificationService = notificationService;
|
this.notificationService = notificationService;
|
||||||
|
this.openmct = openmct;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,7 +63,7 @@ function (
|
|||||||
return new CreateWizard(
|
return new CreateWizard(
|
||||||
this.domainObject,
|
this.domainObject,
|
||||||
parent,
|
parent,
|
||||||
this.policyService
|
this.openmct
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -51,8 +51,11 @@ define(
|
|||||||
*/
|
*/
|
||||||
EditorCapability.prototype.edit = function () {
|
EditorCapability.prototype.edit = function () {
|
||||||
console.warn('DEPRECATED: cannot edit via edit capability, use openmct.editor instead.');
|
console.warn('DEPRECATED: cannot edit via edit capability, use openmct.editor instead.');
|
||||||
this.openmct.editor.edit();
|
|
||||||
this.domainObject.getCapability('status').set('editing', true);
|
if (!this.openmct.editor.isEditing()) {
|
||||||
|
this.openmct.editor.edit();
|
||||||
|
this.domainObject.getCapability('status').set('editing', true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,197 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2018, 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
define(
|
|
||||||
['zepto'],
|
|
||||||
function ($) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The ElementsController prepares the elements view for display
|
|
||||||
*
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
function ElementsController($scope, openmct) {
|
|
||||||
this.scope = $scope;
|
|
||||||
this.scope.composition = [];
|
|
||||||
this.openmct = openmct;
|
|
||||||
this.dragDown = this.dragDown.bind(this);
|
|
||||||
this.dragUp = this.dragUp.bind(this);
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
function filterBy(text) {
|
|
||||||
if (typeof text === 'undefined') {
|
|
||||||
return $scope.searchText;
|
|
||||||
} else {
|
|
||||||
$scope.searchText = text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function searchElements(value) {
|
|
||||||
if ($scope.searchText) {
|
|
||||||
return value.getModel().name.toLowerCase().search(
|
|
||||||
$scope.searchText.toLowerCase()) !== -1;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setSelection(selection) {
|
|
||||||
if (!selection[0]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.mutationListener) {
|
|
||||||
self.mutationListener();
|
|
||||||
delete self.mutationListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
var domainObject = selection[0].context.oldItem;
|
|
||||||
self.refreshComposition(domainObject);
|
|
||||||
|
|
||||||
if (domainObject) {
|
|
||||||
|
|
||||||
self.mutationListener = domainObject.getCapability('mutation')
|
|
||||||
.listen(self.refreshComposition.bind(self, domainObject));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.filterBy = filterBy;
|
|
||||||
$scope.searchElements = searchElements;
|
|
||||||
|
|
||||||
openmct.selection.on('change', setSelection);
|
|
||||||
setSelection(openmct.selection.get());
|
|
||||||
|
|
||||||
$scope.dragDown = this.dragDown;
|
|
||||||
$scope.drag = this.drag;
|
|
||||||
$scope.dragUp = this.dragUp;
|
|
||||||
|
|
||||||
$scope.$on("$destroy", function () {
|
|
||||||
openmct.selection.off("change", setSelection);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoked on DragStart - Adds reordering class to parent UL element
|
|
||||||
* Sets selected object ID, to be used on Drag End
|
|
||||||
*
|
|
||||||
* @param {object} event | Mouse Event
|
|
||||||
*/
|
|
||||||
ElementsController.prototype.dragDown = function (event) {
|
|
||||||
if (!this.parentUL) {
|
|
||||||
this.parentUL = $(document).find('#inspector-elements-tree');
|
|
||||||
}
|
|
||||||
|
|
||||||
this.selectedTreeItem = $(event.target).parent();
|
|
||||||
this.selectedObjectId = event.target.getAttribute('data-id');
|
|
||||||
|
|
||||||
this.parentUL.addClass('reordering');
|
|
||||||
this.selectedTreeItem.addClass('reorder-actor');
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invoked on dragEnd - Removes selected object from position in composition
|
|
||||||
* and replaces it at the target position. Composition is then updated with current
|
|
||||||
* scope
|
|
||||||
*
|
|
||||||
* @param {object} event - Mouse Event
|
|
||||||
*/
|
|
||||||
ElementsController.prototype.dragUp = function (event) {
|
|
||||||
this.targetObjectId = event.target.getAttribute('data-id');
|
|
||||||
|
|
||||||
if (this.targetObjectId && this.selectedObjectId) {
|
|
||||||
var selectedObjectPosition,
|
|
||||||
targetObjectPosition;
|
|
||||||
|
|
||||||
selectedObjectPosition = findObjectInCompositionFromId(this.selectedObjectId, this.scope.composition);
|
|
||||||
targetObjectPosition = findObjectInCompositionFromId(this.targetObjectId, this.scope.composition);
|
|
||||||
|
|
||||||
if ((selectedObjectPosition !== -1) && (targetObjectPosition !== -1)) {
|
|
||||||
var selectedObject = this.scope.composition.splice(selectedObjectPosition, 1),
|
|
||||||
selection = this.openmct.selection.get(),
|
|
||||||
domainObject = selection ? selection[0].context.oldItem : undefined;
|
|
||||||
|
|
||||||
this.scope.composition.splice(targetObjectPosition, 0, selectedObject[0]);
|
|
||||||
|
|
||||||
if (domainObject) {
|
|
||||||
domainObject.getCapability('mutation').mutate(function (model) {
|
|
||||||
model.composition = this.scope.composition.map(function (dObject) {
|
|
||||||
return dObject.id;
|
|
||||||
});
|
|
||||||
}.bind(this));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.parentUL) {
|
|
||||||
this.parentUL.removeClass('reordering');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.selectedTreeItem) {
|
|
||||||
this.selectedTreeItem.removeClass('reorder-actor');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ElementsController.prototype.drag = function (event) {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the composition for the selected object and populates the scope with it.
|
|
||||||
*
|
|
||||||
* @param domainObject the selected object
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
ElementsController.prototype.refreshComposition = function (domainObject) {
|
|
||||||
var refreshTracker = {};
|
|
||||||
this.currentRefresh = refreshTracker;
|
|
||||||
|
|
||||||
var selectedObjectComposition = domainObject && domainObject.useCapability('composition');
|
|
||||||
if (selectedObjectComposition) {
|
|
||||||
selectedObjectComposition.then(function (composition) {
|
|
||||||
if (this.currentRefresh === refreshTracker) {
|
|
||||||
this.scope.composition = composition;
|
|
||||||
}
|
|
||||||
}.bind(this));
|
|
||||||
} else {
|
|
||||||
this.scope.composition = [];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds position of object with given ID in Composition
|
|
||||||
*
|
|
||||||
* @param {String} id
|
|
||||||
* @param {Array} composition
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
function findObjectInCompositionFromId(id, composition) {
|
|
||||||
var mapped = composition.map(function (element) {
|
|
||||||
return element.id;
|
|
||||||
});
|
|
||||||
|
|
||||||
return mapped.indexOf(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ElementsController;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,133 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2018, 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module defining AddAction. Created by ahenry on 01/21/16.
|
|
||||||
*/
|
|
||||||
define(
|
|
||||||
[
|
|
||||||
'./CreateWizard'
|
|
||||||
],
|
|
||||||
function (CreateWizard) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Add Action is performed to create new instances of
|
|
||||||
* domain objects of a specific type that are subobjects of an
|
|
||||||
* object being edited. This is the action that is performed when a
|
|
||||||
* user uses the Add menu option.
|
|
||||||
*
|
|
||||||
* @memberof platform/commonUI/browse
|
|
||||||
* @implements {Action}
|
|
||||||
* @constructor
|
|
||||||
*
|
|
||||||
* @param {Type} type the type of domain object to create
|
|
||||||
* @param {DomainObject} parent the domain object that should
|
|
||||||
* act as a container for the newly-created object
|
|
||||||
* (note that the user will have an opportunity to
|
|
||||||
* override this)
|
|
||||||
* @param {ActionContext} context the context in which the
|
|
||||||
* action is being performed
|
|
||||||
* @param {DialogService} dialogService
|
|
||||||
*/
|
|
||||||
function AddAction(type, parent, context, $q, dialogService, policyService) {
|
|
||||||
this.metadata = {
|
|
||||||
key: 'add',
|
|
||||||
cssClass: type.getCssClass(),
|
|
||||||
name: type.getName(),
|
|
||||||
type: type.getKey(),
|
|
||||||
description: type.getDescription(),
|
|
||||||
context: context
|
|
||||||
};
|
|
||||||
|
|
||||||
this.type = type;
|
|
||||||
this.parent = parent;
|
|
||||||
this.$q = $q;
|
|
||||||
this.dialogService = dialogService;
|
|
||||||
this.policyService = policyService;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Create a new object of the given type.
|
|
||||||
* This will prompt for user input first.
|
|
||||||
*
|
|
||||||
* @returns {Promise} that will be resolved with the object that the
|
|
||||||
* action was originally invoked on (ie. the 'parent')
|
|
||||||
*/
|
|
||||||
AddAction.prototype.perform = function () {
|
|
||||||
var newModel = this.type.getInitialModel(),
|
|
||||||
newObject,
|
|
||||||
parentObject = this.parent,
|
|
||||||
wizard;
|
|
||||||
|
|
||||||
newModel.type = this.type.getKey();
|
|
||||||
newObject = parentObject.getCapability('instantiation').instantiate(newModel);
|
|
||||||
newObject.useCapability('mutation', function (model) {
|
|
||||||
model.location = parentObject.getId();
|
|
||||||
});
|
|
||||||
|
|
||||||
wizard = new CreateWizard(newObject, this.parent, this.policyService);
|
|
||||||
|
|
||||||
function populateObjectFromInput(formValue) {
|
|
||||||
return wizard.populateObjectFromInput(formValue, newObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
function persistAndReturn(domainObject) {
|
|
||||||
return domainObject.getCapability('persistence')
|
|
||||||
.persist()
|
|
||||||
.then(function () {
|
|
||||||
return domainObject;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function addToParent(populatedObject) {
|
|
||||||
parentObject.getCapability('composition').add(populatedObject);
|
|
||||||
return persistAndReturn(parentObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.dialogService
|
|
||||||
.getUserInput(wizard.getFormStructure(false), wizard.getInitialFormValue())
|
|
||||||
.then(populateObjectFromInput)
|
|
||||||
.then(persistAndReturn)
|
|
||||||
.then(addToParent);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Metadata associated with a Add action.
|
|
||||||
* @typedef {ActionMetadata} AddActionMetadata
|
|
||||||
* @property {string} type the key for the type of domain object
|
|
||||||
* to be created
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get metadata about this action.
|
|
||||||
* @returns {AddActionMetadata} metadata about this action
|
|
||||||
*/
|
|
||||||
AddAction.prototype.getMetadata = function () {
|
|
||||||
return this.metadata;
|
|
||||||
};
|
|
||||||
|
|
||||||
return AddAction;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,82 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2018, 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module defining AddActionProvider.js. Created by ahenry on 01/21/16.
|
|
||||||
*/
|
|
||||||
define(
|
|
||||||
["./AddAction"],
|
|
||||||
function (AddAction) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The AddActionProvider is an ActionProvider which introduces
|
|
||||||
* an Add action for creating sub objects.
|
|
||||||
*
|
|
||||||
* @memberof platform/commonUI/browse
|
|
||||||
* @constructor
|
|
||||||
* @implements {ActionService}
|
|
||||||
*
|
|
||||||
* @param {TypeService} typeService the type service, used to discover
|
|
||||||
* available types
|
|
||||||
* @param {DialogService} dialogService the dialog service, used by
|
|
||||||
* specific Create actions to get user input to populate the
|
|
||||||
* model of the newly-created domain object.
|
|
||||||
* @param {CreationService} creationService the creation service (also
|
|
||||||
* introduced in this bundle), responsible for handling actual
|
|
||||||
* object creation.
|
|
||||||
*/
|
|
||||||
function AddActionProvider($q, typeService, dialogService, policyService) {
|
|
||||||
this.typeService = typeService;
|
|
||||||
this.dialogService = dialogService;
|
|
||||||
this.$q = $q;
|
|
||||||
this.policyService = policyService;
|
|
||||||
}
|
|
||||||
|
|
||||||
AddActionProvider.prototype.getActions = function (actionContext) {
|
|
||||||
var context = actionContext || {},
|
|
||||||
key = context.key,
|
|
||||||
destination = context.domainObject;
|
|
||||||
|
|
||||||
// We only provide Add actions, and we need a
|
|
||||||
// domain object to serve as the container for the
|
|
||||||
// newly-created object (although the user may later
|
|
||||||
// make a different selection)
|
|
||||||
if (key !== 'add' || !destination) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Introduce one create action per type
|
|
||||||
return ['timeline', 'activity'].map(function (type) {
|
|
||||||
return new AddAction(
|
|
||||||
this.typeService.getType(type),
|
|
||||||
destination,
|
|
||||||
context,
|
|
||||||
this.$q,
|
|
||||||
this.dialogService,
|
|
||||||
this.policyService
|
|
||||||
);
|
|
||||||
}, this);
|
|
||||||
};
|
|
||||||
|
|
||||||
return AddActionProvider;
|
|
||||||
}
|
|
||||||
);
|
|
@ -34,13 +34,13 @@ define(
|
|||||||
* @memberof platform/commonUI/browse
|
* @memberof platform/commonUI/browse
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function CreateWizard(domainObject, parent, policyService) {
|
function CreateWizard(domainObject, parent, openmct) {
|
||||||
this.type = domainObject.getCapability('type');
|
this.type = domainObject.getCapability('type');
|
||||||
this.model = domainObject.getModel();
|
this.model = domainObject.getModel();
|
||||||
this.domainObject = domainObject;
|
this.domainObject = domainObject;
|
||||||
this.properties = this.type.getProperties();
|
this.properties = this.type.getProperties();
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.policyService = policyService;
|
this.openmct = openmct;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,15 +56,10 @@ define(
|
|||||||
*/
|
*/
|
||||||
CreateWizard.prototype.getFormStructure = function (includeLocation) {
|
CreateWizard.prototype.getFormStructure = function (includeLocation) {
|
||||||
var sections = [],
|
var sections = [],
|
||||||
domainObject = this.domainObject,
|
domainObject = this.domainObject;
|
||||||
policyService = this.policyService;
|
|
||||||
|
|
||||||
function validateLocation(parent) {
|
function validateLocation(parent) {
|
||||||
return parent && policyService.allow(
|
return parent && this.openmct.composition.checkPolicy(parent.useCapability('adapter'), domainObject.useCapability('adapter'));
|
||||||
"composition",
|
|
||||||
parent,
|
|
||||||
domainObject
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sections.push({
|
sections.push({
|
||||||
@ -93,7 +88,7 @@ define(
|
|||||||
rows: [{
|
rows: [{
|
||||||
name: "Save In",
|
name: "Save In",
|
||||||
control: "locator",
|
control: "locator",
|
||||||
validate: validateLocation,
|
validate: validateLocation.bind(this),
|
||||||
key: "createParent"
|
key: "createParent"
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
|
@ -1,184 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2018, 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
/*global describe,it,expect,beforeEach,jasmine*/
|
|
||||||
|
|
||||||
define(
|
|
||||||
["../../src/controllers/ElementsController"],
|
|
||||||
function (ElementsController) {
|
|
||||||
|
|
||||||
describe("The Elements Pane controller", function () {
|
|
||||||
var mockScope,
|
|
||||||
mockOpenMCT,
|
|
||||||
mockSelection,
|
|
||||||
mockDomainObject,
|
|
||||||
mockMutationCapability,
|
|
||||||
mockCompositionCapability,
|
|
||||||
mockCompositionObjects,
|
|
||||||
mockComposition,
|
|
||||||
mockUnlisten,
|
|
||||||
selectable = [],
|
|
||||||
controller;
|
|
||||||
|
|
||||||
function mockPromise(value) {
|
|
||||||
return {
|
|
||||||
then: function (thenFunc) {
|
|
||||||
return mockPromise(thenFunc(value));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function createDomainObject() {
|
|
||||||
return {
|
|
||||||
useCapability: function () {
|
|
||||||
return mockCompositionCapability;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockComposition = ["a", "b"];
|
|
||||||
mockCompositionObjects = mockComposition.map(createDomainObject);
|
|
||||||
mockCompositionCapability = mockPromise(mockCompositionObjects);
|
|
||||||
|
|
||||||
mockUnlisten = jasmine.createSpy('unlisten');
|
|
||||||
mockMutationCapability = jasmine.createSpyObj("mutationCapability", [
|
|
||||||
"listen"
|
|
||||||
]);
|
|
||||||
mockMutationCapability.listen.and.returnValue(mockUnlisten);
|
|
||||||
mockDomainObject = jasmine.createSpyObj("domainObject", [
|
|
||||||
"getCapability",
|
|
||||||
"useCapability"
|
|
||||||
]);
|
|
||||||
mockDomainObject.useCapability.and.returnValue(mockCompositionCapability);
|
|
||||||
mockDomainObject.getCapability.and.returnValue(mockMutationCapability);
|
|
||||||
|
|
||||||
mockScope = jasmine.createSpyObj("$scope", ['$on']);
|
|
||||||
mockSelection = jasmine.createSpyObj("selection", [
|
|
||||||
'on',
|
|
||||||
'off',
|
|
||||||
'get'
|
|
||||||
]);
|
|
||||||
mockSelection.get.and.returnValue([]);
|
|
||||||
mockOpenMCT = {
|
|
||||||
selection: mockSelection
|
|
||||||
};
|
|
||||||
|
|
||||||
selectable[0] = {
|
|
||||||
context: {
|
|
||||||
oldItem: mockDomainObject
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
spyOn(ElementsController.prototype, 'refreshComposition').and.callThrough();
|
|
||||||
|
|
||||||
controller = new ElementsController(mockScope, mockOpenMCT);
|
|
||||||
});
|
|
||||||
|
|
||||||
function getModel(model) {
|
|
||||||
return function () {
|
|
||||||
return model;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
it("filters objects in elements pool based on input text and" +
|
|
||||||
" object name", function () {
|
|
||||||
var objects = [
|
|
||||||
{
|
|
||||||
getModel: getModel({name: "first element"})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
getModel: getModel({name: "second element"})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
getModel: getModel({name: "third element"})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
getModel: getModel({name: "THIRD Element 1"})
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
mockScope.filterBy("third element");
|
|
||||||
expect(objects.filter(mockScope.searchElements).length).toBe(2);
|
|
||||||
mockScope.filterBy("element");
|
|
||||||
expect(objects.filter(mockScope.searchElements).length).toBe(4);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("refreshes composition on selection", function () {
|
|
||||||
mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable);
|
|
||||||
|
|
||||||
expect(ElementsController.prototype.refreshComposition).toHaveBeenCalledWith(mockDomainObject);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("listens on mutation and refreshes composition", function () {
|
|
||||||
mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable);
|
|
||||||
|
|
||||||
expect(mockDomainObject.getCapability).toHaveBeenCalledWith('mutation');
|
|
||||||
expect(mockMutationCapability.listen).toHaveBeenCalled();
|
|
||||||
expect(ElementsController.prototype.refreshComposition.calls.count()).toBe(1);
|
|
||||||
|
|
||||||
mockMutationCapability.listen.calls.mostRecent().args[0](mockDomainObject);
|
|
||||||
|
|
||||||
expect(ElementsController.prototype.refreshComposition.calls.count()).toBe(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("cleans up mutation listener when selection changes", function () {
|
|
||||||
mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable);
|
|
||||||
|
|
||||||
expect(mockMutationCapability.listen).toHaveBeenCalled();
|
|
||||||
|
|
||||||
mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable);
|
|
||||||
|
|
||||||
expect(mockUnlisten).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not listen on mutation for element proxy selectable", function () {
|
|
||||||
selectable[0] = {
|
|
||||||
context: {
|
|
||||||
elementProxy: {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable);
|
|
||||||
|
|
||||||
expect(mockDomainObject.getCapability).not.toHaveBeenCalledWith('mutation');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("checks concurrent changes to composition", function () {
|
|
||||||
var secondMockComposition = ["a", "b", "c"],
|
|
||||||
secondMockCompositionObjects = secondMockComposition.map(createDomainObject),
|
|
||||||
firstCompositionCallback,
|
|
||||||
secondCompositionCallback;
|
|
||||||
|
|
||||||
spyOn(mockCompositionCapability, "then").and.callThrough();
|
|
||||||
|
|
||||||
controller.refreshComposition(mockDomainObject);
|
|
||||||
controller.refreshComposition(mockDomainObject);
|
|
||||||
|
|
||||||
firstCompositionCallback = mockCompositionCapability.then.calls.all()[0].args[0];
|
|
||||||
secondCompositionCallback = mockCompositionCapability.then.calls.all()[1].args[0];
|
|
||||||
secondCompositionCallback(secondMockCompositionObjects);
|
|
||||||
firstCompositionCallback(mockCompositionObjects);
|
|
||||||
|
|
||||||
expect(mockScope.composition).toBe(secondMockCompositionObjects);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,105 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2018, 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MCTRepresentationSpec. Created by ahenry on 01/21/14.
|
|
||||||
*/
|
|
||||||
define(
|
|
||||||
["../../src/creation/AddActionProvider"],
|
|
||||||
function (AddActionProvider) {
|
|
||||||
|
|
||||||
describe("The add action provider", function () {
|
|
||||||
var mockTypeService,
|
|
||||||
mockDialogService,
|
|
||||||
mockPolicyService,
|
|
||||||
mockTypeMap,
|
|
||||||
mockTypes,
|
|
||||||
mockDomainObject,
|
|
||||||
mockQ,
|
|
||||||
provider;
|
|
||||||
|
|
||||||
function createMockType(name) {
|
|
||||||
var mockType = jasmine.createSpyObj(
|
|
||||||
"type" + name,
|
|
||||||
[
|
|
||||||
"getKey",
|
|
||||||
"getGlyph",
|
|
||||||
"getCssClass",
|
|
||||||
"getName",
|
|
||||||
"getDescription",
|
|
||||||
"getProperties",
|
|
||||||
"getInitialModel",
|
|
||||||
"hasFeature"
|
|
||||||
]
|
|
||||||
);
|
|
||||||
mockType.hasFeature.and.returnValue(true);
|
|
||||||
mockType.getName.and.returnValue(name);
|
|
||||||
mockType.getKey.and.returnValue(name);
|
|
||||||
return mockType;
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockTypeService = jasmine.createSpyObj(
|
|
||||||
"typeService",
|
|
||||||
["getType"]
|
|
||||||
);
|
|
||||||
mockDialogService = {};
|
|
||||||
mockPolicyService = {};
|
|
||||||
mockDomainObject = {};
|
|
||||||
|
|
||||||
mockTypes = [
|
|
||||||
"timeline",
|
|
||||||
"activity",
|
|
||||||
"other"
|
|
||||||
].map(createMockType);
|
|
||||||
mockTypeMap = {};
|
|
||||||
|
|
||||||
mockTypes.forEach(function (type) {
|
|
||||||
mockTypeMap[type.getKey()] = type;
|
|
||||||
});
|
|
||||||
|
|
||||||
mockTypeService.getType.and.callFake(function (key) {
|
|
||||||
return mockTypeMap[key];
|
|
||||||
});
|
|
||||||
|
|
||||||
provider = new AddActionProvider(
|
|
||||||
mockQ,
|
|
||||||
mockTypeService,
|
|
||||||
mockDialogService,
|
|
||||||
mockPolicyService
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("provides actions for timeline and activity", function () {
|
|
||||||
var actions = provider.getActions({
|
|
||||||
key: "add",
|
|
||||||
domainObject: mockDomainObject
|
|
||||||
});
|
|
||||||
expect(actions.length).toBe(2);
|
|
||||||
expect(actions[0].metadata.type).toBe('timeline');
|
|
||||||
expect(actions[1].metadata.type).toBe('activity');
|
|
||||||
|
|
||||||
// Make sure it was creation which was used to check
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -58,7 +58,8 @@ define([
|
|||||||
"category": "action",
|
"category": "action",
|
||||||
"implementation": ComposeActionPolicy,
|
"implementation": ComposeActionPolicy,
|
||||||
"depends": [
|
"depends": [
|
||||||
"$injector"
|
"$injector",
|
||||||
|
"openmct"
|
||||||
],
|
],
|
||||||
"message": "Objects of this type cannot contain objects of that type."
|
"message": "Objects of this type cannot contain objects of that type."
|
||||||
},
|
},
|
||||||
|
@ -36,10 +36,11 @@ define(
|
|||||||
* @memberof platform/containment
|
* @memberof platform/containment
|
||||||
* @implements {Policy.<Action, ActionContext>}
|
* @implements {Policy.<Action, ActionContext>}
|
||||||
*/
|
*/
|
||||||
function ComposeActionPolicy($injector) {
|
function ComposeActionPolicy($injector, openmct) {
|
||||||
this.getPolicyService = function () {
|
this.getPolicyService = function () {
|
||||||
return $injector.get('policyService');
|
return $injector.get('policyService');
|
||||||
};
|
};
|
||||||
|
this.openmct = openmct;
|
||||||
}
|
}
|
||||||
|
|
||||||
ComposeActionPolicy.prototype.allowComposition = function (containerObject, selectedObject) {
|
ComposeActionPolicy.prototype.allowComposition = function (containerObject, selectedObject) {
|
||||||
@ -49,11 +50,8 @@ define(
|
|||||||
|
|
||||||
// ...and delegate to the composition policy
|
// ...and delegate to the composition policy
|
||||||
return containerObject.getId() !== selectedObject.getId() &&
|
return containerObject.getId() !== selectedObject.getId() &&
|
||||||
this.policyService.allow(
|
this.openmct.composition.checkPolicy(containerObject.useCapability('adapter'),
|
||||||
'composition',
|
selectedObject.useCapability('adapter'));
|
||||||
containerObject,
|
|
||||||
selectedObject
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -170,7 +170,7 @@ define([
|
|||||||
"description": "Provides a service for moving objects",
|
"description": "Provides a service for moving objects",
|
||||||
"implementation": MoveService,
|
"implementation": MoveService,
|
||||||
"depends": [
|
"depends": [
|
||||||
"policyService",
|
"openmct",
|
||||||
"linkService",
|
"linkService",
|
||||||
"$q"
|
"$q"
|
||||||
]
|
]
|
||||||
@ -181,7 +181,7 @@ define([
|
|||||||
"description": "Provides a service for linking objects",
|
"description": "Provides a service for linking objects",
|
||||||
"implementation": LinkService,
|
"implementation": LinkService,
|
||||||
"depends": [
|
"depends": [
|
||||||
"policyService"
|
"openmct"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -192,7 +192,7 @@ define([
|
|||||||
"depends": [
|
"depends": [
|
||||||
"$q",
|
"$q",
|
||||||
"policyService",
|
"policyService",
|
||||||
"now"
|
"openmct"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -33,9 +33,10 @@ define(
|
|||||||
* @memberof platform/entanglement
|
* @memberof platform/entanglement
|
||||||
* @implements {platform/entanglement.AbstractComposeService}
|
* @implements {platform/entanglement.AbstractComposeService}
|
||||||
*/
|
*/
|
||||||
function CopyService($q, policyService) {
|
function CopyService($q, policyService, openmct) {
|
||||||
this.$q = $q;
|
this.$q = $q;
|
||||||
this.policyService = policyService;
|
this.policyService = policyService;
|
||||||
|
this.openmct = openmct;
|
||||||
}
|
}
|
||||||
|
|
||||||
CopyService.prototype.validate = function (object, parentCandidate) {
|
CopyService.prototype.validate = function (object, parentCandidate) {
|
||||||
@ -45,11 +46,7 @@ define(
|
|||||||
if (parentCandidate.getId() === object.getId()) {
|
if (parentCandidate.getId() === object.getId()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this.policyService.allow(
|
return this.openmct.composition.checkPolicy(parentCandidate.useCapability('adapter'), object.useCapability('adapter'));
|
||||||
"composition",
|
|
||||||
parentCandidate,
|
|
||||||
object
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,8 +32,8 @@ define(
|
|||||||
* @memberof platform/entanglement
|
* @memberof platform/entanglement
|
||||||
* @implements {platform/entanglement.AbstractComposeService}
|
* @implements {platform/entanglement.AbstractComposeService}
|
||||||
*/
|
*/
|
||||||
function LinkService(policyService) {
|
function LinkService(openmct) {
|
||||||
this.policyService = policyService;
|
this.openmct = openmct;
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkService.prototype.validate = function (object, parentCandidate) {
|
LinkService.prototype.validate = function (object, parentCandidate) {
|
||||||
@ -49,11 +49,7 @@ define(
|
|||||||
if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) {
|
if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this.policyService.allow(
|
return this.openmct.composition.checkPolicy(parentCandidate.useCapability('adapter'), object.useCapability('adapter'));
|
||||||
"composition",
|
|
||||||
parentCandidate,
|
|
||||||
object
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
LinkService.prototype.perform = function (object, parentObject) {
|
LinkService.prototype.perform = function (object, parentObject) {
|
||||||
|
@ -31,8 +31,8 @@ define(
|
|||||||
* @memberof platform/entanglement
|
* @memberof platform/entanglement
|
||||||
* @implements {platform/entanglement.AbstractComposeService}
|
* @implements {platform/entanglement.AbstractComposeService}
|
||||||
*/
|
*/
|
||||||
function MoveService(policyService, linkService) {
|
function MoveService(openmct, linkService) {
|
||||||
this.policyService = policyService;
|
this.openmct = openmct;
|
||||||
this.linkService = linkService;
|
this.linkService = linkService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,10 +53,9 @@ define(
|
|||||||
if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) {
|
if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this.policyService.allow(
|
return this.openmct.composition.checkPolicy(
|
||||||
"composition",
|
parentCandidate.useCapability('adapter'),
|
||||||
parentCandidate,
|
object.useCapability('adapter')
|
||||||
object
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2018, 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
define(
|
|
||||||
[],
|
|
||||||
function () {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines composition policy for Display Layout objects.
|
|
||||||
* They cannot contain folders.
|
|
||||||
* @constructor
|
|
||||||
* @memberof platform/features/layout
|
|
||||||
* @implements {Policy.<View, DomainObject>}
|
|
||||||
*/
|
|
||||||
function LayoutCompositionPolicy() {
|
|
||||||
}
|
|
||||||
|
|
||||||
LayoutCompositionPolicy.prototype.allow = function (parent, child) {
|
|
||||||
var parentType = parent.getCapability('type');
|
|
||||||
if (parentType.instanceOf('layout') &&
|
|
||||||
child.getCapability('type').instanceOf('folder')) {
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
return LayoutCompositionPolicy;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2018, 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
define(
|
|
||||||
["../src/LayoutCompositionPolicy"],
|
|
||||||
function (LayoutCompositionPolicy) {
|
|
||||||
describe("Layout's composition policy", function () {
|
|
||||||
var mockChild,
|
|
||||||
mockCandidateObj,
|
|
||||||
mockCandidate,
|
|
||||||
mockContext,
|
|
||||||
candidateType,
|
|
||||||
contextType,
|
|
||||||
policy;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockChild = jasmine.createSpyObj(
|
|
||||||
'childObject',
|
|
||||||
['getCapability']
|
|
||||||
);
|
|
||||||
mockCandidate =
|
|
||||||
jasmine.createSpyObj('candidateType', ['instanceOf']);
|
|
||||||
mockContext =
|
|
||||||
jasmine.createSpyObj('contextType', ['instanceOf']);
|
|
||||||
|
|
||||||
mockCandidateObj = jasmine.createSpyObj('domainObj', [
|
|
||||||
'getCapability'
|
|
||||||
]);
|
|
||||||
mockCandidateObj.getCapability.and.returnValue(mockCandidate);
|
|
||||||
|
|
||||||
mockChild.getCapability.and.returnValue(mockContext);
|
|
||||||
|
|
||||||
mockCandidate.instanceOf.and.callFake(function (t) {
|
|
||||||
return t === candidateType;
|
|
||||||
});
|
|
||||||
mockContext.instanceOf.and.callFake(function (t) {
|
|
||||||
return t === contextType;
|
|
||||||
});
|
|
||||||
|
|
||||||
policy = new LayoutCompositionPolicy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("disallows folders in layouts", function () {
|
|
||||||
candidateType = 'layout';
|
|
||||||
contextType = 'folder';
|
|
||||||
expect(policy.allow(mockCandidateObj, mockChild)).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not disallow folders elsewhere", function () {
|
|
||||||
candidateType = 'nonlayout';
|
|
||||||
contextType = 'folder';
|
|
||||||
expect(policy.allow(mockCandidateObj, mockChild)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("allows things other than folders in layouts", function () {
|
|
||||||
candidateType = 'layout';
|
|
||||||
contextType = 'nonfolder';
|
|
||||||
expect(policy.allow(mockCandidateObj, mockChild)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -28,7 +28,6 @@ define([
|
|||||||
'./services/Instantiate',
|
'./services/Instantiate',
|
||||||
'./services/MissingModelCompatibilityDecorator',
|
'./services/MissingModelCompatibilityDecorator',
|
||||||
'./capabilities/APICapabilityDecorator',
|
'./capabilities/APICapabilityDecorator',
|
||||||
'./policies/AdapterCompositionPolicy',
|
|
||||||
'./policies/AdaptedViewPolicy',
|
'./policies/AdaptedViewPolicy',
|
||||||
'./runs/AlternateCompositionInitializer',
|
'./runs/AlternateCompositionInitializer',
|
||||||
'./runs/TimeSettingsURLHandler',
|
'./runs/TimeSettingsURLHandler',
|
||||||
@ -36,7 +35,8 @@ define([
|
|||||||
'./runs/LegacyTelemetryProvider',
|
'./runs/LegacyTelemetryProvider',
|
||||||
'./runs/RegisterLegacyTypes',
|
'./runs/RegisterLegacyTypes',
|
||||||
'./services/LegacyObjectAPIInterceptor',
|
'./services/LegacyObjectAPIInterceptor',
|
||||||
'./views/installLegacyViews'
|
'./views/installLegacyViews',
|
||||||
|
'./policies/legacyCompositionPolicyAdapter'
|
||||||
], function (
|
], function (
|
||||||
legacyRegistry,
|
legacyRegistry,
|
||||||
ActionDialogDecorator,
|
ActionDialogDecorator,
|
||||||
@ -45,7 +45,6 @@ define([
|
|||||||
Instantiate,
|
Instantiate,
|
||||||
MissingModelCompatibilityDecorator,
|
MissingModelCompatibilityDecorator,
|
||||||
APICapabilityDecorator,
|
APICapabilityDecorator,
|
||||||
AdapterCompositionPolicy,
|
|
||||||
AdaptedViewPolicy,
|
AdaptedViewPolicy,
|
||||||
AlternateCompositionInitializer,
|
AlternateCompositionInitializer,
|
||||||
TimeSettingsURLHandler,
|
TimeSettingsURLHandler,
|
||||||
@ -53,7 +52,8 @@ define([
|
|||||||
LegacyTelemetryProvider,
|
LegacyTelemetryProvider,
|
||||||
RegisterLegacyTypes,
|
RegisterLegacyTypes,
|
||||||
LegacyObjectAPIInterceptor,
|
LegacyObjectAPIInterceptor,
|
||||||
installLegacyViews
|
installLegacyViews,
|
||||||
|
legacyCompositionPolicyAdapter
|
||||||
) {
|
) {
|
||||||
legacyRegistry.register('src/adapter', {
|
legacyRegistry.register('src/adapter', {
|
||||||
"extensions": {
|
"extensions": {
|
||||||
@ -117,11 +117,6 @@ define([
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
policies: [
|
policies: [
|
||||||
{
|
|
||||||
category: "composition",
|
|
||||||
implementation: AdapterCompositionPolicy,
|
|
||||||
depends: ["openmct"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
category: "view",
|
category: "view",
|
||||||
implementation: AdaptedViewPolicy,
|
implementation: AdaptedViewPolicy,
|
||||||
@ -168,6 +163,12 @@ define([
|
|||||||
"types[]",
|
"types[]",
|
||||||
"openmct"
|
"openmct"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
implementation: legacyCompositionPolicyAdapter.default,
|
||||||
|
depends: [
|
||||||
|
"openmct"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
licenses: [
|
licenses: [
|
||||||
|
@ -20,20 +20,23 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define([], function () {
|
export default function legacyCompositionPolicyAdapter(openmct) {
|
||||||
function AdapterCompositionPolicy(openmct) {
|
const instantiate = this.openmct.$injector.get('instantiate');
|
||||||
this.openmct = openmct;
|
const policyService = this.openmct.$injector.get('policyService');
|
||||||
}
|
|
||||||
|
|
||||||
AdapterCompositionPolicy.prototype.allow = function (
|
openmct.composition.addPolicy((parent, child) => {
|
||||||
parent,
|
|
||||||
child
|
let parentId = this.openmct.objects.makeKeyString(parent.identifier);
|
||||||
) {
|
let childId = this.openmct.objects.makeKeyString(child.identifier);
|
||||||
return this.openmct.composition.checkPolicy(
|
|
||||||
parent,
|
let legacyParent = instantiate(parent, parentId);
|
||||||
child
|
let legacyChild = instantiate(child, childId);
|
||||||
|
let result = policyService.allow(
|
||||||
|
'composition',
|
||||||
|
legacyParent,
|
||||||
|
legacyChild
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
return AdapterCompositionPolicy;
|
return result;
|
||||||
});
|
});
|
||||||
|
}
|
@ -36,6 +36,9 @@ export default class Editor extends EventEmitter {
|
|||||||
* or finish() are called.
|
* or finish() are called.
|
||||||
*/
|
*/
|
||||||
edit() {
|
edit() {
|
||||||
|
if (this.editing === true) {
|
||||||
|
throw "Already editing";
|
||||||
|
}
|
||||||
this.editing = true;
|
this.editing = true;
|
||||||
this.getTransactionService().startTransaction();
|
this.getTransactionService().startTransaction();
|
||||||
this.emit('isEditing', true);
|
this.emit('isEditing', true);
|
||||||
|
@ -44,7 +44,7 @@ define([
|
|||||||
function CompositionAPI(publicAPI) {
|
function CompositionAPI(publicAPI) {
|
||||||
this.registry = [];
|
this.registry = [];
|
||||||
this.policies = [];
|
this.policies = [];
|
||||||
this.addProvider(new DefaultCompositionProvider(publicAPI));
|
this.addProvider(new DefaultCompositionProvider(publicAPI, this));
|
||||||
this.publicAPI = publicAPI;
|
this.publicAPI = publicAPI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,9 +43,34 @@ define([
|
|||||||
* @memberof module:openmct
|
* @memberof module:openmct
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function DefaultCompositionProvider(publicAPI) {
|
function DefaultCompositionProvider(publicAPI, compositionAPI) {
|
||||||
this.publicAPI = publicAPI;
|
this.publicAPI = publicAPI;
|
||||||
this.listeningTo = {};
|
this.listeningTo = {};
|
||||||
|
|
||||||
|
this.cannotContainDuplicates = this.cannotContainDuplicates.bind(this);
|
||||||
|
this.cannotContainItself = this.cannotContainItself.bind(this);
|
||||||
|
|
||||||
|
compositionAPI.addPolicy(this.cannotContainDuplicates);
|
||||||
|
compositionAPI.addPolicy(this.cannotContainItself);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
DefaultCompositionProvider.prototype.cannotContainDuplicates = function (parent, child) {
|
||||||
|
return this.appliesTo(parent) &&
|
||||||
|
parent.composition.findIndex((composeeId) => {
|
||||||
|
return composeeId.namespace === child.identifier.namespace &&
|
||||||
|
composeeId.key === child.identifier.key;
|
||||||
|
}) === -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
DefaultCompositionProvider.prototype.cannotContainItself = function (parent, child) {
|
||||||
|
return !(parent.identifier.namespace === child.identifier.namespace &&
|
||||||
|
parent.identifier.key === child.identifier.key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -203,7 +228,7 @@ define([
|
|||||||
}
|
}
|
||||||
|
|
||||||
var oldComposition = listeners.composition.map(objectUtils.makeKeyString);
|
var oldComposition = listeners.composition.map(objectUtils.makeKeyString);
|
||||||
var newComposition = oldDomainObject.getModel().composition;
|
var newComposition = oldDomainObject.getModel().composition.map(objectUtils.makeKeyString);
|
||||||
|
|
||||||
var added = _.difference(newComposition, oldComposition).map(objectUtils.parseKeyString);
|
var added = _.difference(newComposition, oldComposition).map(objectUtils.parseKeyString);
|
||||||
var removed = _.difference(oldComposition, newComposition).map(objectUtils.parseKeyString);
|
var removed = _.difference(oldComposition, newComposition).map(objectUtils.parseKeyString);
|
||||||
|
@ -276,33 +276,14 @@
|
|||||||
},
|
},
|
||||||
handleDrop($event) {
|
handleDrop($event) {
|
||||||
$event.preventDefault();
|
$event.preventDefault();
|
||||||
$event.stopPropagation();
|
|
||||||
|
|
||||||
let child = JSON.parse($event.dataTransfer.getData('domainObject'));
|
let child = JSON.parse($event.dataTransfer.getData('domainObject'));
|
||||||
let duplicates = [];
|
|
||||||
let composition = this.newDomainObject.composition;
|
|
||||||
composition.forEach((object) => {
|
|
||||||
if (this.openmct.objects.makeKeyString(JSON.parse(JSON.stringify(object))) ===
|
|
||||||
this.openmct.objects.makeKeyString(child.identifier)) {
|
|
||||||
duplicates.push(object);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Disallow adding a duplicate object to the composition
|
|
||||||
if (duplicates.length !== 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let elementRect = this.$el.getBoundingClientRect();
|
let elementRect = this.$el.getBoundingClientRect();
|
||||||
this.droppedObjectPosition = {
|
this.droppedObjectPosition = {
|
||||||
x: $event.pageX - elementRect.left,
|
x: $event.pageX - elementRect.left,
|
||||||
y: $event.pageY - elementRect.top
|
y: $event.pageY - elementRect.top
|
||||||
}
|
}
|
||||||
// TODO: use the composition API to add child once the default composition
|
|
||||||
// provider supports it instead of mutating the composition directly.
|
|
||||||
// this.composition.add(child).
|
|
||||||
composition.push(child.identifier);
|
|
||||||
this.mutate('composition', composition);
|
|
||||||
},
|
},
|
||||||
handleDragOver($event){
|
handleDragOver($event){
|
||||||
$event.preventDefault();
|
$event.preventDefault();
|
||||||
|
@ -63,6 +63,13 @@ export default function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
openmct.types.addType('layout', DisplayLayoutType());
|
openmct.types.addType('layout', DisplayLayoutType());
|
||||||
|
openmct.composition.addPolicy((parent, child) => {
|
||||||
|
if (parent.type === 'layout' && child.type === 'folder') {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
openmct.toolbars.addProvider({
|
openmct.toolbars.addProvider({
|
||||||
name: "Display Layout Toolbar",
|
name: "Display Layout Toolbar",
|
||||||
key: "layout",
|
key: "layout",
|
||||||
|
@ -21,19 +21,16 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define(function () {
|
define(function () {
|
||||||
function TelemetryTableType() {
|
return {
|
||||||
return {
|
name: 'Telemetry Table',
|
||||||
name: 'Telemetry Table',
|
description: 'Display telemetry values for the current time bounds in tabular form. Supports filtering and sorting.',
|
||||||
description: 'Display telemetry values for the current time bounds in tabular form. Supports filtering and sorting.',
|
creatable: true,
|
||||||
creatable: true,
|
cssClass: 'icon-tabular-realtime',
|
||||||
cssClass: 'icon-tabular-realtime',
|
initialize(domainObject) {
|
||||||
initialize(domainObject) {
|
domainObject.composition = [];
|
||||||
domainObject.composition = [];
|
domainObject.configuration = {
|
||||||
domainObject.configuration = {
|
columns: {}
|
||||||
columns: {}
|
};
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
return TelemetryTableType;
|
});
|
||||||
});
|
|
||||||
|
@ -191,7 +191,6 @@ export default {
|
|||||||
search
|
search
|
||||||
},
|
},
|
||||||
inject: ['table', 'openmct', 'csvExporter'],
|
inject: ['table', 'openmct', 'csvExporter'],
|
||||||
props: ['configuration'],
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
headers: {},
|
headers: {},
|
||||||
|
@ -20,20 +20,27 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define([
|
define([
|
||||||
'./TelemetryTableViewProvider',
|
'./TelemetryTableViewProvider',
|
||||||
'./TableConfigurationViewProvider',
|
'./TableConfigurationViewProvider',
|
||||||
'./TelemetryTableType'
|
'./TelemetryTableType'
|
||||||
], function (
|
], function (
|
||||||
TelemetryTableViewProvider,
|
TelemetryTableViewProvider,
|
||||||
TableConfigurationViewProvider,
|
TableConfigurationViewProvider,
|
||||||
TelemetryTableType
|
TelemetryTableType
|
||||||
) {
|
) {
|
||||||
return function plugin() {
|
return function plugin() {
|
||||||
return function install(openmct) {
|
return function install(openmct) {
|
||||||
openmct.objectViews.addProvider(new TelemetryTableViewProvider(openmct));
|
openmct.objectViews.addProvider(new TelemetryTableViewProvider(openmct));
|
||||||
openmct.inspectorViews.addProvider(new TableConfigurationViewProvider(openmct));
|
openmct.inspectorViews.addProvider(new TableConfigurationViewProvider(openmct));
|
||||||
openmct.types.addType('table', TelemetryTableType());
|
openmct.types.addType('table', TelemetryTableType);
|
||||||
|
openmct.composition.addPolicy((parent, child) => {
|
||||||
|
if (parent.type === 'table') {
|
||||||
|
return child.hasOwnProperty('telemetry');
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
42
src/ui/components/controls/ObjectLabel.vue
Normal file
42
src/ui/components/controls/ObjectLabel.vue
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<template>
|
||||||
|
<a class="c-tree__item__label"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart="dragStart"
|
||||||
|
:href="urlLink">
|
||||||
|
<div class="c-tree__item__type-icon"
|
||||||
|
:class="cssClass"></div>
|
||||||
|
<div class="c-tree__item__name">{{ domainObject.name }}</div>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
inject: ['openmct'],
|
||||||
|
props: {
|
||||||
|
'domainObject': Object,
|
||||||
|
'urlLink': String
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
cssClass: 'icon-object-unknown'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
let type = this.openmct.types.get(this.domainObject.type);
|
||||||
|
|
||||||
|
if (type.definition.cssClass) {
|
||||||
|
this.cssClass = type.definition.cssClass;
|
||||||
|
} else {
|
||||||
|
console.log("Failed to get typeDef.cssClass for object", this.domainObject.name, this.domainObject.type);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
dragStart(event) {
|
||||||
|
event.dataTransfer.setData("domainObject", JSON.stringify(this.domainObject));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -1,33 +1,136 @@
|
|||||||
<template>
|
<template>
|
||||||
<div></div>
|
<div class="flex-elem l-flex-col holder grows">
|
||||||
|
<Search @input="applySearch"></Search>
|
||||||
|
<div class="flex-elem grows vscroll scroll-pad">
|
||||||
|
<ul class="tree" id="inspector-elements-tree"
|
||||||
|
v-if="elements.length > 0">
|
||||||
|
<li :key="element.identifier.key" v-for="(element, index) in elements" @drop="moveTo(index)" @dragover="allowDrop">
|
||||||
|
<span class="tree-item">
|
||||||
|
<span class="grippy-sm"
|
||||||
|
v-if="elements.length > 1 && isEditing"
|
||||||
|
draggable="true"
|
||||||
|
@dragstart="moveFrom(index)">
|
||||||
|
</span>
|
||||||
|
<object-label :domainObject="element"></object-label>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li class="js-last-place" @drop="moveToIndex(elements.length)"></li>
|
||||||
|
</ul>
|
||||||
|
<div v-if="elements.length === 0">No contained elements</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<style lang="scss">
|
||||||
|
@import "~styles/sass-base";
|
||||||
|
@import "~styles/glyphs";
|
||||||
|
|
||||||
|
.grippy-sm {
|
||||||
|
// Used in editor Elements pool
|
||||||
|
@extend .icon-grippy-12px;
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
|
||||||
|
.js-last-place{
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
<script>
|
<script>
|
||||||
|
import Search from '../controls/search.vue';
|
||||||
|
import ObjectLabel from '../controls/ObjectLabel.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
|
components: {
|
||||||
|
'Search': Search,
|
||||||
|
'ObjectLabel': ObjectLabel
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
elements: [],
|
||||||
|
isEditing: this.openmct.editor.isEditing()
|
||||||
|
}
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
let openmct = this.openmct;
|
let selection = this.openmct.selection.get();
|
||||||
let $injector = openmct.$injector;
|
if (selection && selection.length > 0){
|
||||||
let angular = openmct.$angular;
|
this.showSelection(selection);
|
||||||
|
}
|
||||||
let templateLinker = $injector.get('templateLinker');
|
this.openmct.selection.on('change', this.showSelection);
|
||||||
|
this.openmct.editor.on('isEditing', (isEditing)=>{
|
||||||
let templateMap = {};
|
this.isEditing = isEditing;
|
||||||
$injector.get('templates[]').forEach((t) => {
|
this.showSelection(this.openmct.selection.get());
|
||||||
templateMap[t.key] = templateMap[t.key] || t;
|
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showSelection(selection) {
|
||||||
|
this.elements = [];
|
||||||
|
this.elementsCache = [];
|
||||||
|
this.parentObject = selection[0].context.item;
|
||||||
|
if (this.mutationUnobserver) {
|
||||||
|
this.mutationUnobserver();
|
||||||
|
}
|
||||||
|
this.mutationUnobserver = this.openmct.objects.observe(this.parentObject, '*', (updatedModel) => {
|
||||||
|
this.parentObject = updatedModel;
|
||||||
|
this.refreshComposition();
|
||||||
|
});
|
||||||
|
this.refreshComposition();
|
||||||
|
},
|
||||||
|
refreshComposition() {
|
||||||
|
let composition = this.openmct.composition.get(this.parentObject);
|
||||||
|
|
||||||
let $rootScope = $injector.get('$rootScope');
|
if (composition){
|
||||||
this.$scope = $rootScope.$new();
|
composition.load().then(this.setElements);
|
||||||
|
}
|
||||||
|
|
||||||
templateLinker.link(
|
},
|
||||||
this.$scope,
|
setElements(elements) {
|
||||||
angular.element(this.$el),
|
this.elementsCache = elements.map((element)=>JSON.parse(JSON.stringify(element)))
|
||||||
templateMap.elementsPool
|
this.applySearch(this.currentSearch);
|
||||||
);
|
},
|
||||||
|
applySearch(input) {
|
||||||
|
this.currentSearch = input;
|
||||||
|
this.elements = this.elementsCache.filter((element) => {
|
||||||
|
return element.name.toLowerCase().search(
|
||||||
|
this.currentSearch) !== -1;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
addObject(child){
|
||||||
|
this.elementsCache.push(child);
|
||||||
|
this.applySearch(this.currentSearch);
|
||||||
|
},
|
||||||
|
removeObject(childId){
|
||||||
|
this.elementsCache = this.elementsCache.filter((element) => !matches(element, childId));
|
||||||
|
this.applySearch(this.currentSearch);
|
||||||
|
|
||||||
|
function matches(elementA, elementBId) {
|
||||||
|
return elementA.identifier.namespace === elementBId.namespace &&
|
||||||
|
elementA.identifier.key === elementBId.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
allowDrop(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
},
|
||||||
|
moveTo(moveToIndex) {
|
||||||
|
console.log('dropped');
|
||||||
|
let composition = this.parentObject.composition;
|
||||||
|
let moveFromId = composition[this.moveFromIndex];
|
||||||
|
let deleteIndex = this.moveFromIndex;
|
||||||
|
if (moveToIndex < this.moveFromIndex) {
|
||||||
|
composition.splice(deleteIndex, 1);
|
||||||
|
composition.splice(moveToIndex, 0, moveFromId);
|
||||||
|
} else {
|
||||||
|
composition.splice(deleteIndex, 1);
|
||||||
|
composition.splice(moveToIndex, 0, moveFromId);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.openmct.objects.mutate(this.parentObject, 'composition', composition);
|
||||||
|
},
|
||||||
|
moveFrom(index){
|
||||||
|
this.moveFromIndex = index;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
this.$scope.$destroy();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
</pane>
|
</pane>
|
||||||
<pane class="c-inspector__elements"
|
<pane class="c-inspector__elements"
|
||||||
handle="before"
|
handle="before"
|
||||||
label="Elements">
|
label="Elements" v-if="isEditing">
|
||||||
<elements></elements>
|
<elements></elements>
|
||||||
</pane>
|
</pane>
|
||||||
</multipane>
|
</multipane>
|
||||||
@ -188,6 +188,9 @@
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
|
props: {
|
||||||
|
'isEditing': Boolean
|
||||||
|
},
|
||||||
components: {
|
components: {
|
||||||
multipane,
|
multipane,
|
||||||
pane,
|
pane,
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
handle="before"
|
handle="before"
|
||||||
label="Inspect"
|
label="Inspect"
|
||||||
collapsable>
|
collapsable>
|
||||||
<Inspector ref="inspector"></Inspector>
|
<Inspector :isEditing="isEditing" ref="inspector"></Inspector>
|
||||||
</pane>
|
</pane>
|
||||||
</multipane>
|
</multipane>
|
||||||
<div class="l-shell__status">
|
<div class="l-shell__status">
|
||||||
|
@ -35,6 +35,8 @@ export default {
|
|||||||
mounted() {
|
mounted() {
|
||||||
this.currentObject = this.object;
|
this.currentObject = this.object;
|
||||||
this.updateView();
|
this.updateView();
|
||||||
|
this.$el.addEventListener('dragover', this.onDragOver);
|
||||||
|
this.$el.addEventListener('drop', this.onDrop);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
clear() {
|
clear() {
|
||||||
@ -64,9 +66,34 @@ export default {
|
|||||||
this.currentView.show(this.viewContainer);
|
this.currentView.show(this.viewContainer);
|
||||||
},
|
},
|
||||||
show(object, viewKey) {
|
show(object, viewKey) {
|
||||||
|
if (this.unlisten) {
|
||||||
|
this.unlisten();
|
||||||
|
}
|
||||||
this.currentObject = object;
|
this.currentObject = object;
|
||||||
|
this.unlisten = this.openmct.objects.observe(this.currentObject, '*', (mutatedObject) => {
|
||||||
|
this.currentObject = mutatedObject;
|
||||||
|
});
|
||||||
|
|
||||||
this.viewKey = viewKey;
|
this.viewKey = viewKey;
|
||||||
this.updateView();
|
this.updateView();
|
||||||
|
},
|
||||||
|
onDragOver(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
},
|
||||||
|
onDrop(event) {
|
||||||
|
let parentObject = this.currentObject;
|
||||||
|
let childObject = JSON.parse(event.dataTransfer.getData("domainObject"));
|
||||||
|
|
||||||
|
if (this.openmct.composition.checkPolicy(parentObject, childObject)){
|
||||||
|
if (!this.openmct.editor.isEditing() && parentObject.type !== 'folder'){
|
||||||
|
this.openmct.editor.edit();
|
||||||
|
}
|
||||||
|
parentObject.composition.push(childObject.identifier);
|
||||||
|
this.openmct.objects.mutate(parentObject, 'composition', parentObject.composition);
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,14 +7,7 @@
|
|||||||
:expanded="expanded"
|
:expanded="expanded"
|
||||||
@click="toggleChildren">
|
@click="toggleChildren">
|
||||||
</view-control>
|
</view-control>
|
||||||
<a class="c-tree__item__label"
|
<object-label :domainObject="node.object" :urlLink="href"></object-label>
|
||||||
draggable="true"
|
|
||||||
@dragstart="dragStart"
|
|
||||||
:href="href">
|
|
||||||
<div class="c-tree__item__type-icon"
|
|
||||||
:class="cssClass"></div>
|
|
||||||
<div class="c-tree__item__name">{{ node.object.name }}</div>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
<ul v-if="expanded" class="c-tree">
|
<ul v-if="expanded" class="c-tree">
|
||||||
<tree-item v-for="child in children"
|
<tree-item v-for="child in children"
|
||||||
@ -27,10 +20,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import viewControl from '../controls/viewControl.vue'
|
import viewControl from '../controls/viewControl.vue';
|
||||||
|
import ObjectLabel from '../controls/ObjectLabel.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'tree-item',
|
name: 'tree-item',
|
||||||
inject: ['openmct', 'domainObject'],
|
inject: ['openmct'],
|
||||||
props: {
|
props: {
|
||||||
node: Object
|
node: Object
|
||||||
},
|
},
|
||||||
@ -40,7 +35,6 @@
|
|||||||
loaded: false,
|
loaded: false,
|
||||||
children: [],
|
children: [],
|
||||||
expanded: false,
|
expanded: false,
|
||||||
cssClass: 'icon-object-unknown',
|
|
||||||
isAlias: false
|
isAlias: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -59,20 +53,11 @@
|
|||||||
// TODO: should support drag/drop composition
|
// TODO: should support drag/drop composition
|
||||||
// TODO: set isAlias per tree-item
|
// TODO: set isAlias per tree-item
|
||||||
|
|
||||||
let type = this.openmct.types.get(this.node.object.type);
|
|
||||||
|
|
||||||
if (type.definition.cssClass) {
|
|
||||||
this.cssClass = type.definition.cssClass;
|
|
||||||
} else {
|
|
||||||
console.log("Failed to get typeDef.cssClass for object", this.node.object.name, this.node.object.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
let composition = this.openmct.composition.get(this.node.object);
|
let composition = this.openmct.composition.get(this.node.object);
|
||||||
if (!composition) {
|
if (!composition) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.hasChildren = true;
|
this.hasChildren = true;
|
||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleChildren: function () {
|
toggleChildren: function () {
|
||||||
@ -90,13 +75,11 @@
|
|||||||
})
|
})
|
||||||
.then(() => this.loaded = true);
|
.then(() => this.loaded = true);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
dragStart($event) {
|
|
||||||
$event.dataTransfer.setData("domainObject", JSON.stringify(this.node.object));
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
viewControl
|
viewControl,
|
||||||
|
ObjectLabel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -34,6 +34,7 @@ define([
|
|||||||
if (!Array.isArray(path)) {
|
if (!Array.isArray(path)) {
|
||||||
path = path.split('/');
|
path = path.split('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(path.map((keyString)=>{
|
return Promise.all(path.map((keyString)=>{
|
||||||
return openmct.objects.get(keyString);
|
return openmct.objects.get(keyString);
|
||||||
})).then((objects)=>{
|
})).then((objects)=>{
|
||||||
@ -42,6 +43,7 @@ define([
|
|||||||
}
|
}
|
||||||
|
|
||||||
let navigatedObject = objects[objects.length - 1];
|
let navigatedObject = objects[objects.length - 1];
|
||||||
|
|
||||||
// FIXME: this is a hack to support create action, intended to
|
// FIXME: this is a hack to support create action, intended to
|
||||||
// expose the current routed path. We need to rewrite the
|
// expose the current routed path. We need to rewrite the
|
||||||
// navigation service and router to expose a clear and minimal
|
// navigation service and router to expose a clear and minimal
|
||||||
|
Reference in New Issue
Block a user