mirror of
https://github.com/nasa/openmct.git
synced 2025-05-09 20:12:50 +00:00
Merge pull request #500 from nasa/open480
[New Edit Mode] Adding sub objects to Timelines
This commit is contained in:
commit
b0e4947bf0
@ -34,6 +34,7 @@ define([
|
|||||||
"./src/windowing/NewTabAction",
|
"./src/windowing/NewTabAction",
|
||||||
"./src/windowing/FullscreenAction",
|
"./src/windowing/FullscreenAction",
|
||||||
"./src/creation/CreateActionProvider",
|
"./src/creation/CreateActionProvider",
|
||||||
|
"./src/creation/AddActionProvider",
|
||||||
"./src/creation/CreationService",
|
"./src/creation/CreationService",
|
||||||
"./src/windowing/WindowTitler",
|
"./src/windowing/WindowTitler",
|
||||||
'legacyRegistry'
|
'legacyRegistry'
|
||||||
@ -50,6 +51,7 @@ define([
|
|||||||
NewTabAction,
|
NewTabAction,
|
||||||
FullscreenAction,
|
FullscreenAction,
|
||||||
CreateActionProvider,
|
CreateActionProvider,
|
||||||
|
AddActionProvider,
|
||||||
CreationService,
|
CreationService,
|
||||||
WindowTitler,
|
WindowTitler,
|
||||||
legacyRegistry
|
legacyRegistry
|
||||||
@ -272,6 +274,18 @@ define([
|
|||||||
"policyService"
|
"policyService"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"key": "AddActionProvider",
|
||||||
|
"provides": "actionService",
|
||||||
|
"type": "provider",
|
||||||
|
"implementation": AddActionProvider,
|
||||||
|
"depends": [
|
||||||
|
"$q",
|
||||||
|
"typeService",
|
||||||
|
"dialogService",
|
||||||
|
"policyService"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"key": "CreationService",
|
"key": "CreationService",
|
||||||
"provides": "creationService",
|
"provides": "creationService",
|
||||||
|
139
platform/commonUI/browse/src/creation/AddAction.js
Normal file
139
platform/commonUI/browse/src/creation/AddAction.js
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web 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 Web 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 define,Promise*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module defining AddAction. Created by ahenry on 01/21/16.
|
||||||
|
*/
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'./CreateWizard'
|
||||||
|
],
|
||||||
|
function (CreateWizard) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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',
|
||||||
|
glyph: type.getGlyph(),
|
||||||
|
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 addToParent (populatedObject) {
|
||||||
|
parentObject.getCapability('composition').add(populatedObject);
|
||||||
|
return parentObject.getCapability('persistence').persist().then(function(){
|
||||||
|
return parentObject;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function save(object) {
|
||||||
|
/*
|
||||||
|
It's necessary to persist the new sub-object in order
|
||||||
|
that it can be retrieved for composition in the parent.
|
||||||
|
Future refactoring that allows temporary objects to be
|
||||||
|
retrieved from object services will make this unnecessary.
|
||||||
|
*/
|
||||||
|
return object.getCapability('editor').save(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.dialogService
|
||||||
|
.getUserInput(wizard.getFormStructure(false), wizard.getInitialFormValue())
|
||||||
|
.then(populateObjectFromInput)
|
||||||
|
.then(save)
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
);
|
87
platform/commonUI/browse/src/creation/AddActionProvider.js
Normal file
87
platform/commonUI/browse/src/creation/AddActionProvider.js
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web 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 Web 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 define,Promise*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module defining AddActionProvider.js. Created by ahenry on 01/21/16.
|
||||||
|
*/
|
||||||
|
define(
|
||||||
|
["./AddAction"],
|
||||||
|
function (AddAction) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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,
|
||||||
|
self = this;
|
||||||
|
|
||||||
|
// 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 this.typeService.listTypes().filter(function (type) {
|
||||||
|
return self.policyService.allow("creation", type) && self.policyService.allow("composition", destination.getCapability('type'), type);
|
||||||
|
}).map(function (type) {
|
||||||
|
return new AddAction(
|
||||||
|
type,
|
||||||
|
destination,
|
||||||
|
context,
|
||||||
|
self.$q,
|
||||||
|
self.dialogService,
|
||||||
|
self.policyService
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return AddActionProvider;
|
||||||
|
}
|
||||||
|
);
|
@ -26,18 +26,21 @@ define(
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new CreateWizard.
|
* A class for capturing user input data from an object creation
|
||||||
|
* dialog, and populating a domain object with that data.
|
||||||
*
|
*
|
||||||
* @param {TypeImpl} type the type of domain object to be created
|
* @param {DomainObject} domainObject the newly created object to
|
||||||
|
* populate with user input
|
||||||
* @param {DomainObject} parent the domain object to serve as
|
* @param {DomainObject} parent the domain object to serve as
|
||||||
* the initial parent for the created object, in the dialog
|
* the initial parent for the created object, in the dialog
|
||||||
* @memberof platform/commonUI/browse
|
* @memberof platform/commonUI/browse
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function CreateWizard(type, parent, policyService, initialModel) {
|
function CreateWizard(domainObject, parent, policyService) {
|
||||||
this.type = type;
|
this.type = domainObject.getCapability('type');
|
||||||
this.model = initialModel || type.getInitialModel();
|
this.model = domainObject.getModel();
|
||||||
this.properties = type.getProperties();
|
this.domainObject = domainObject;
|
||||||
|
this.properties = this.type.getProperties();
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.policyService = policyService;
|
this.policyService = policyService;
|
||||||
}
|
}
|
||||||
@ -46,11 +49,14 @@ define(
|
|||||||
* Get the form model for this wizard; this is a description
|
* Get the form model for this wizard; this is a description
|
||||||
* that will be rendered to an HTML form. See the
|
* that will be rendered to an HTML form. See the
|
||||||
* platform/forms bundle
|
* platform/forms bundle
|
||||||
*
|
* @param {boolean} includeLocation if true, a 'location' section
|
||||||
|
* will be included that will allow the user to select the location
|
||||||
|
* of the newly created object, otherwise the .location property of
|
||||||
|
* the model will be used.
|
||||||
* @return {FormModel} formModel the form model to
|
* @return {FormModel} formModel the form model to
|
||||||
* show in the create dialog
|
* show in the create dialog
|
||||||
*/
|
*/
|
||||||
CreateWizard.prototype.getFormStructure = function () {
|
CreateWizard.prototype.getFormStructure = function (includeLocation) {
|
||||||
var sections = [],
|
var sections = [],
|
||||||
type = this.type,
|
type = this.type,
|
||||||
policyService = this.policyService;
|
policyService = this.policyService;
|
||||||
@ -84,12 +90,16 @@ define(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Ensure there is always a "save in" section
|
// Ensure there is always a "save in" section
|
||||||
sections.push({ name: 'Location', rows: [{
|
if (includeLocation) {
|
||||||
name: "Save In",
|
sections.push({
|
||||||
control: "locator",
|
name: 'Location', rows: [{
|
||||||
validate: validateLocation,
|
name: "Save In",
|
||||||
key: "createParent"
|
control: "locator",
|
||||||
}]});
|
validate: validateLocation,
|
||||||
|
key: "createParent"
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sections: sections,
|
sections: sections,
|
||||||
@ -97,6 +107,23 @@ define(
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given some form input values and a domain object, populate the
|
||||||
|
* domain object used to create this wizard from the given form values.
|
||||||
|
* @param formValue
|
||||||
|
* @returns {DomainObject}
|
||||||
|
*/
|
||||||
|
CreateWizard.prototype.populateObjectFromInput = function(formValue) {
|
||||||
|
var parent = this.getLocation(formValue),
|
||||||
|
formModel = this.createModel(formValue);
|
||||||
|
|
||||||
|
formModel.location = parent.getId();
|
||||||
|
this.domainObject.useCapability("mutation", function(){
|
||||||
|
return formModel;
|
||||||
|
});
|
||||||
|
return this.domainObject;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the initial value for the form being described.
|
* Get the initial value for the form being described.
|
||||||
* This will include the values for all properties described
|
* This will include the values for all properties described
|
||||||
@ -120,6 +147,7 @@ define(
|
|||||||
/**
|
/**
|
||||||
* Based on a populated form, get the domain object which
|
* Based on a populated form, get the domain object which
|
||||||
* should be used as a parent for the newly-created object.
|
* should be used as a parent for the newly-created object.
|
||||||
|
* @private
|
||||||
* @return {DomainObject}
|
* @return {DomainObject}
|
||||||
*/
|
*/
|
||||||
CreateWizard.prototype.getLocation = function (formValue) {
|
CreateWizard.prototype.getLocation = function (formValue) {
|
||||||
@ -129,6 +157,7 @@ define(
|
|||||||
/**
|
/**
|
||||||
* Create the domain object model for a newly-created object,
|
* Create the domain object model for a newly-created object,
|
||||||
* based on user input read from a formModel.
|
* based on user input read from a formModel.
|
||||||
|
* @private
|
||||||
* @return {object} the domain object model
|
* @return {object} the domain object model
|
||||||
*/
|
*/
|
||||||
CreateWizard.prototype.createModel = function (formValue) {
|
CreateWizard.prototype.createModel = function (formValue) {
|
||||||
|
137
platform/commonUI/browse/test/creation/AddActionProviderSpec.js
Normal file
137
platform/commonUI/browse/test/creation/AddActionProviderSpec.js
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web 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 Web 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 define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine,xit,xdescribe*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MCTRepresentationSpec. Created by ahenry on 01/21/14.
|
||||||
|
*/
|
||||||
|
define(
|
||||||
|
["../../src/creation/AddActionProvider"],
|
||||||
|
function (AddActionProvider) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
describe("The add action provider", function () {
|
||||||
|
var mockTypeService,
|
||||||
|
mockDialogService,
|
||||||
|
mockPolicyService,
|
||||||
|
mockCreationPolicy,
|
||||||
|
mockCompositionPolicy,
|
||||||
|
mockPolicyMap = {},
|
||||||
|
mockTypes,
|
||||||
|
mockDomainObject,
|
||||||
|
mockQ,
|
||||||
|
provider;
|
||||||
|
|
||||||
|
function createMockType(name) {
|
||||||
|
var mockType = jasmine.createSpyObj(
|
||||||
|
"type" + name,
|
||||||
|
[
|
||||||
|
"getKey",
|
||||||
|
"getGlyph",
|
||||||
|
"getName",
|
||||||
|
"getDescription",
|
||||||
|
"getProperties",
|
||||||
|
"getInitialModel",
|
||||||
|
"hasFeature"
|
||||||
|
]
|
||||||
|
);
|
||||||
|
mockType.hasFeature.andReturn(true);
|
||||||
|
mockType.getName.andReturn(name);
|
||||||
|
return mockType;
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockTypeService = jasmine.createSpyObj(
|
||||||
|
"typeService",
|
||||||
|
[ "listTypes" ]
|
||||||
|
);
|
||||||
|
mockDialogService = jasmine.createSpyObj(
|
||||||
|
"dialogService",
|
||||||
|
[ "getUserInput" ]
|
||||||
|
);
|
||||||
|
mockPolicyService = jasmine.createSpyObj(
|
||||||
|
"policyService",
|
||||||
|
[ "allow" ]
|
||||||
|
);
|
||||||
|
|
||||||
|
mockDomainObject = jasmine.createSpyObj(
|
||||||
|
"domainObject",
|
||||||
|
[ "getCapability" ]
|
||||||
|
);
|
||||||
|
|
||||||
|
//Mocking getCapability because AddActionProvider uses the
|
||||||
|
// type capability of the destination object.
|
||||||
|
mockDomainObject.getCapability.andReturn({});
|
||||||
|
|
||||||
|
mockTypes = [ "A", "B", "C" ].map(createMockType);
|
||||||
|
|
||||||
|
mockTypes.forEach(function(type){
|
||||||
|
mockPolicyMap[type.getName()] = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
mockCreationPolicy = function(type){
|
||||||
|
return mockPolicyMap[type.getName()];
|
||||||
|
};
|
||||||
|
|
||||||
|
mockCompositionPolicy = function(){
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
mockPolicyService.allow.andReturn(true);
|
||||||
|
|
||||||
|
mockTypeService.listTypes.andReturn(mockTypes);
|
||||||
|
|
||||||
|
provider = new AddActionProvider(
|
||||||
|
mockQ,
|
||||||
|
mockTypeService,
|
||||||
|
mockDialogService,
|
||||||
|
mockPolicyService
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("checks for creatability", function () {
|
||||||
|
provider.getActions({
|
||||||
|
key: "add",
|
||||||
|
domainObject: mockDomainObject
|
||||||
|
});
|
||||||
|
// Make sure it was creation which was used to check
|
||||||
|
expect(mockPolicyService.allow)
|
||||||
|
.toHaveBeenCalledWith("creation", mockTypes[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("checks for composability of type", function () {
|
||||||
|
provider.getActions({
|
||||||
|
key: "add",
|
||||||
|
domainObject: mockDomainObject
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockPolicyService.allow).toHaveBeenCalledWith(
|
||||||
|
"composition",
|
||||||
|
jasmine.any(Object),
|
||||||
|
jasmine.any(Object)
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(mockDomainObject.getCapability).toHaveBeenCalledWith('type');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
@ -32,11 +32,12 @@ define(
|
|||||||
describe("The create action provider", function () {
|
describe("The create action provider", function () {
|
||||||
var mockTypeService,
|
var mockTypeService,
|
||||||
mockDialogService,
|
mockDialogService,
|
||||||
mockCreationService,
|
mockNavigationService,
|
||||||
mockPolicyService,
|
mockPolicyService,
|
||||||
mockCreationPolicy,
|
mockCreationPolicy,
|
||||||
mockPolicyMap = {},
|
mockPolicyMap = {},
|
||||||
mockTypes,
|
mockTypes,
|
||||||
|
mockQ,
|
||||||
provider;
|
provider;
|
||||||
|
|
||||||
function createMockType(name) {
|
function createMockType(name) {
|
||||||
@ -66,9 +67,9 @@ define(
|
|||||||
"dialogService",
|
"dialogService",
|
||||||
[ "getUserInput" ]
|
[ "getUserInput" ]
|
||||||
);
|
);
|
||||||
mockCreationService = jasmine.createSpyObj(
|
mockNavigationService = jasmine.createSpyObj(
|
||||||
"creationService",
|
"navigationService",
|
||||||
[ "createObject" ]
|
[ "setNavigation" ]
|
||||||
);
|
);
|
||||||
mockPolicyService = jasmine.createSpyObj(
|
mockPolicyService = jasmine.createSpyObj(
|
||||||
"policyService",
|
"policyService",
|
||||||
@ -92,15 +93,14 @@ define(
|
|||||||
mockTypeService.listTypes.andReturn(mockTypes);
|
mockTypeService.listTypes.andReturn(mockTypes);
|
||||||
|
|
||||||
provider = new CreateActionProvider(
|
provider = new CreateActionProvider(
|
||||||
|
mockQ,
|
||||||
mockTypeService,
|
mockTypeService,
|
||||||
mockDialogService,
|
mockNavigationService,
|
||||||
mockCreationService,
|
|
||||||
mockPolicyService
|
mockPolicyService
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
//TODO: Disabled for NEM Beta
|
it("exposes one create action per type", function () {
|
||||||
xit("exposes one create action per type", function () {
|
|
||||||
expect(provider.getActions({
|
expect(provider.getActions({
|
||||||
key: "create",
|
key: "create",
|
||||||
domainObject: {}
|
domainObject: {}
|
||||||
@ -114,8 +114,7 @@ define(
|
|||||||
}).length).toEqual(0);
|
}).length).toEqual(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
//TODO: Disabled for NEM Beta
|
it("does not expose non-creatable types", function () {
|
||||||
xit("does not expose non-creatable types", function () {
|
|
||||||
// One of the types won't have the creation feature...
|
// One of the types won't have the creation feature...
|
||||||
mockPolicyMap[mockTypes[0].getName()] = false;
|
mockPolicyMap[mockTypes[0].getName()] = false;
|
||||||
// ...so it should have been filtered out.
|
// ...so it should have been filtered out.
|
||||||
|
@ -35,6 +35,7 @@ define(
|
|||||||
mockProperties,
|
mockProperties,
|
||||||
mockPolicyService,
|
mockPolicyService,
|
||||||
testModel,
|
testModel,
|
||||||
|
mockDomainObject,
|
||||||
wizard;
|
wizard;
|
||||||
|
|
||||||
function createMockProperty(name) {
|
function createMockProperty(name) {
|
||||||
@ -81,8 +82,18 @@ define(
|
|||||||
mockType.getInitialModel.andReturn(testModel);
|
mockType.getInitialModel.andReturn(testModel);
|
||||||
mockType.getProperties.andReturn(mockProperties);
|
mockType.getProperties.andReturn(mockProperties);
|
||||||
|
|
||||||
|
mockDomainObject = jasmine.createSpyObj(
|
||||||
|
'domainObject',
|
||||||
|
['getCapability', 'useCapability', 'getModel']
|
||||||
|
);
|
||||||
|
|
||||||
|
//Mocking the getCapability('type') call
|
||||||
|
mockDomainObject.getCapability.andReturn(mockType);
|
||||||
|
mockDomainObject.useCapability.andReturn();
|
||||||
|
mockDomainObject.getModel.andReturn(testModel);
|
||||||
|
|
||||||
wizard = new CreateWizard(
|
wizard = new CreateWizard(
|
||||||
mockType,
|
mockDomainObject,
|
||||||
mockParent,
|
mockParent,
|
||||||
mockPolicyService
|
mockPolicyService
|
||||||
);
|
);
|
||||||
@ -130,6 +141,18 @@ define(
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("populates the model on the associated object", function () {
|
||||||
|
var formValue = {
|
||||||
|
"A": "ValueA",
|
||||||
|
"B": "ValueB",
|
||||||
|
"C": "ValueC"
|
||||||
|
},
|
||||||
|
compareModel = wizard.createModel(formValue);
|
||||||
|
wizard.populateObjectFromInput(formValue);
|
||||||
|
expect(mockDomainObject.useCapability).toHaveBeenCalledWith('mutation', jasmine.any(Function));
|
||||||
|
expect(mockDomainObject.useCapability.mostRecentCall.args[1]()).toEqual(compareModel);
|
||||||
|
});
|
||||||
|
|
||||||
it("validates selection types using policy", function () {
|
it("validates selection types using policy", function () {
|
||||||
var mockDomainObject = jasmine.createSpyObj(
|
var mockDomainObject = jasmine.createSpyObj(
|
||||||
'domainObject',
|
'domainObject',
|
||||||
@ -139,7 +162,8 @@ define(
|
|||||||
'otherType',
|
'otherType',
|
||||||
['getKey']
|
['getKey']
|
||||||
),
|
),
|
||||||
structure = wizard.getFormStructure(),
|
//Create a form structure with location
|
||||||
|
structure = wizard.getFormStructure(true),
|
||||||
sections = structure.sections,
|
sections = structure.sections,
|
||||||
rows = structure.sections[sections.length - 1].rows,
|
rows = structure.sections[sections.length - 1].rows,
|
||||||
locationRow = rows[rows.length - 1];
|
locationRow = rows[rows.length - 1];
|
||||||
@ -156,6 +180,12 @@ define(
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("creates a form model without a location if not requested", function () {
|
||||||
|
expect(wizard.getFormStructure(false).sections.some(function(section){
|
||||||
|
return section.name === 'Location';
|
||||||
|
})).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -79,65 +79,23 @@ define(
|
|||||||
|
|
||||||
function doWizardSave(parent) {
|
function doWizardSave(parent) {
|
||||||
var context = domainObject.getCapability("context"),
|
var context = domainObject.getCapability("context"),
|
||||||
wizard = new CreateWizard(domainObject.useCapability('type'), parent, self.policyService, domainObject.getModel());
|
wizard = new CreateWizard(domainObject, parent, self.policyService);
|
||||||
|
|
||||||
function mergeObjects(fromObject, toObject){
|
|
||||||
Object.keys(fromObject).forEach(function(key) {
|
|
||||||
toObject[key] = fromObject[key];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create and persist the new object, based on user
|
|
||||||
// input.
|
|
||||||
function buildObjectFromInput(formValue) {
|
|
||||||
var parent = wizard.getLocation(formValue),
|
|
||||||
formModel = wizard.createModel(formValue);
|
|
||||||
|
|
||||||
formModel.location = parent.getId();
|
|
||||||
//Replace domain object model with model collected
|
|
||||||
// from user form.
|
|
||||||
domainObject.useCapability("mutation", function(){
|
|
||||||
//Replace object model with the model from the form
|
|
||||||
return formModel;
|
|
||||||
});
|
|
||||||
return domainObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAllComposees(domainObject){
|
|
||||||
return domainObject.useCapability('composition');
|
|
||||||
}
|
|
||||||
|
|
||||||
function addComposeesToObject(object){
|
|
||||||
return function(composees){
|
|
||||||
return self.$q.all(composees.map(function (composee) {
|
|
||||||
return object.getCapability('composition').add(composee);
|
|
||||||
})).then(resolveWith(object));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add the composees of the 'virtual' object to the
|
|
||||||
* persisted object
|
|
||||||
* @param object
|
|
||||||
* @returns {*}
|
|
||||||
*/
|
|
||||||
function composeNewObject(object){
|
|
||||||
if (self.$q.when(object.hasCapability('composition') && domainObject.hasCapability('composition'))) {
|
|
||||||
return getAllComposees(domainObject)
|
|
||||||
.then(addComposeesToObject(object));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return self.dialogService
|
return self.dialogService
|
||||||
.getUserInput(wizard.getFormStructure(), wizard.getInitialFormValue())
|
.getUserInput(wizard.getFormStructure(true), wizard.getInitialFormValue())
|
||||||
.then(buildObjectFromInput);
|
.then(function(formValue){
|
||||||
|
return wizard.populateObjectFromInput(formValue, domainObject);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function persistObject(object){
|
function persistObject(object){
|
||||||
return ((object.hasCapability('editor') && object.getCapability('editor').save(true)) ||
|
|
||||||
object.getCapability('persistence').persist())
|
//Persist first to mark dirty
|
||||||
.then(resolveWith(object));
|
return object.getCapability('persistence').persist().then(function(){
|
||||||
|
//then save permanently
|
||||||
|
return object.getCapability('editor').save();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchObject(objectId){
|
function fetchObject(objectId){
|
||||||
@ -152,7 +110,9 @@ define(
|
|||||||
|
|
||||||
function locateObjectInParent(parent){
|
function locateObjectInParent(parent){
|
||||||
parent.getCapability('composition').add(domainObject.getId());
|
parent.getCapability('composition').add(domainObject.getId());
|
||||||
return parent;
|
return parent.getCapability('persistence').persist().then(function() {
|
||||||
|
return parent;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function doNothing() {
|
function doNothing() {
|
||||||
@ -174,7 +134,6 @@ define(
|
|||||||
.then(getParent)//Parent may have changed based
|
.then(getParent)//Parent may have changed based
|
||||||
// on user selection
|
// on user selection
|
||||||
.then(locateObjectInParent)
|
.then(locateObjectInParent)
|
||||||
.then(persistObject)
|
|
||||||
.then(function(){
|
.then(function(){
|
||||||
return fetchObject(domainObject.getId());
|
return fetchObject(domainObject.getId());
|
||||||
})
|
})
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web 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 Web 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 define*/
|
||||||
|
|
||||||
|
|
||||||
|
define(
|
||||||
|
['./EditableLookupCapability'],
|
||||||
|
function (EditableLookupCapability) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for the "instantiation" capability;
|
||||||
|
* ensures that any domain objects instantiated in Edit mode
|
||||||
|
* are also wrapped as EditableDomainObjects.
|
||||||
|
*
|
||||||
|
* Meant specifically for use by EditableDomainObject and the
|
||||||
|
* associated cache; the constructor signature is particular
|
||||||
|
* to a pattern used there and may contain unused arguments.
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
|
* @implements {CompositionCapability}
|
||||||
|
*/
|
||||||
|
return function EditableInstantiationCapability(
|
||||||
|
contextCapability,
|
||||||
|
editableObject,
|
||||||
|
domainObject,
|
||||||
|
cache
|
||||||
|
) {
|
||||||
|
// This is a "lookup" style capability (it looks up other
|
||||||
|
// domain objects), but we do not want to return the same
|
||||||
|
// specific value every time (composition may change)
|
||||||
|
return new EditableLookupCapability(
|
||||||
|
contextCapability,
|
||||||
|
editableObject,
|
||||||
|
domainObject,
|
||||||
|
cache,
|
||||||
|
false // Not idempotent
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
@ -45,7 +45,8 @@ define(
|
|||||||
cache,
|
cache,
|
||||||
idempotent
|
idempotent
|
||||||
) {
|
) {
|
||||||
var capability = Object.create(contextCapability);
|
var capability = Object.create(contextCapability),
|
||||||
|
method;
|
||||||
|
|
||||||
// Check for domain object interface. If something has these
|
// Check for domain object interface. If something has these
|
||||||
// three methods, we assume it's a domain object.
|
// three methods, we assume it's a domain object.
|
||||||
@ -114,7 +115,9 @@ define(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wrap all methods; return only editable domain objects.
|
// Wrap all methods; return only editable domain objects.
|
||||||
Object.keys(contextCapability).forEach(wrapMethod);
|
for (method in contextCapability) {
|
||||||
|
wrapMethod(method);
|
||||||
|
}
|
||||||
|
|
||||||
return capability;
|
return capability;
|
||||||
};
|
};
|
||||||
|
@ -81,7 +81,8 @@ define(
|
|||||||
var domainObject = this.domainObject,
|
var domainObject = this.domainObject,
|
||||||
editableObject = this.editableObject,
|
editableObject = this.editableObject,
|
||||||
self = this,
|
self = this,
|
||||||
cache = this.cache;
|
cache = this.cache,
|
||||||
|
returnPromise;
|
||||||
|
|
||||||
// Update the underlying, "real" domain object's model
|
// Update the underlying, "real" domain object's model
|
||||||
// with changes made to the copy used for editing.
|
// with changes made to the copy used for editing.
|
||||||
@ -99,14 +100,18 @@ define(
|
|||||||
editableObject.getCapability("status").set("editing", false);
|
editableObject.getCapability("status").set("editing", false);
|
||||||
|
|
||||||
if (nonrecursive) {
|
if (nonrecursive) {
|
||||||
return resolvePromise(doMutate())
|
returnPromise = resolvePromise(doMutate())
|
||||||
.then(doPersist)
|
.then(doPersist)
|
||||||
.then(function(){
|
.then(function(){
|
||||||
self.cancel();
|
self.cancel();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return resolvePromise(cache.saveAll());
|
returnPromise = resolvePromise(cache.saveAll());
|
||||||
}
|
}
|
||||||
|
//Return the original (non-editable) object
|
||||||
|
return returnPromise.then(function() {
|
||||||
|
return domainObject.getOriginalObject ? domainObject.getOriginalObject() : domainObject;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,6 +36,7 @@ define(
|
|||||||
'../capabilities/EditableContextCapability',
|
'../capabilities/EditableContextCapability',
|
||||||
'../capabilities/EditableCompositionCapability',
|
'../capabilities/EditableCompositionCapability',
|
||||||
'../capabilities/EditableRelationshipCapability',
|
'../capabilities/EditableRelationshipCapability',
|
||||||
|
'../capabilities/EditableInstantiationCapability',
|
||||||
'../capabilities/EditorCapability',
|
'../capabilities/EditorCapability',
|
||||||
'../capabilities/EditableActionCapability',
|
'../capabilities/EditableActionCapability',
|
||||||
'./EditableDomainObjectCache'
|
'./EditableDomainObjectCache'
|
||||||
@ -45,6 +46,7 @@ define(
|
|||||||
EditableContextCapability,
|
EditableContextCapability,
|
||||||
EditableCompositionCapability,
|
EditableCompositionCapability,
|
||||||
EditableRelationshipCapability,
|
EditableRelationshipCapability,
|
||||||
|
EditableInstantiationCapability,
|
||||||
EditorCapability,
|
EditorCapability,
|
||||||
EditableActionCapability,
|
EditableActionCapability,
|
||||||
EditableDomainObjectCache
|
EditableDomainObjectCache
|
||||||
@ -56,6 +58,7 @@ define(
|
|||||||
context: EditableContextCapability,
|
context: EditableContextCapability,
|
||||||
composition: EditableCompositionCapability,
|
composition: EditableCompositionCapability,
|
||||||
relationship: EditableRelationshipCapability,
|
relationship: EditableRelationshipCapability,
|
||||||
|
instantiation: EditableInstantiationCapability,
|
||||||
editor: EditorCapability
|
editor: EditorCapability
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -118,6 +118,29 @@ define(
|
|||||||
expect(mockContext.getDomainObject.calls.length).toEqual(2);
|
expect(mockContext.getDomainObject.calls.length).toEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("wraps inherited methods", function () {
|
||||||
|
var CapabilityClass = function(){
|
||||||
|
};
|
||||||
|
CapabilityClass.prototype.inheritedMethod=function () {
|
||||||
|
return "an inherited method";
|
||||||
|
};
|
||||||
|
|
||||||
|
mockContext = new CapabilityClass();
|
||||||
|
|
||||||
|
capability = new EditableLookupCapability(
|
||||||
|
mockContext,
|
||||||
|
mockEditableObject,
|
||||||
|
mockDomainObject,
|
||||||
|
factory,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
expect(capability.inheritedMethod()).toEqual("an inherited method");
|
||||||
|
expect(capability.hasOwnProperty('inheritedMethod')).toBe(true);
|
||||||
|
// The presence of an own property indicates that the method
|
||||||
|
// has been wrapped on the object itself and this is a valid
|
||||||
|
// test that the inherited method has been wrapped.
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
@ -39,7 +39,7 @@ define(
|
|||||||
function populateActionMap(domainObject) {
|
function populateActionMap(domainObject) {
|
||||||
var actionCapability = domainObject.getCapability('action'),
|
var actionCapability = domainObject.getCapability('action'),
|
||||||
actions = actionCapability ?
|
actions = actionCapability ?
|
||||||
actionCapability.getActions('create') : [];
|
actionCapability.getActions('add') : [];
|
||||||
actions.forEach(function (action) {
|
actions.forEach(function (action) {
|
||||||
actionMap[action.getMetadata().type] = action;
|
actionMap[action.getMetadata().type] = action;
|
||||||
});
|
});
|
||||||
|
@ -74,7 +74,7 @@ define(
|
|||||||
expect(mockDomainObject.getCapability)
|
expect(mockDomainObject.getCapability)
|
||||||
.toHaveBeenCalledWith('action');
|
.toHaveBeenCalledWith('action');
|
||||||
expect(mockActionCapability.getActions)
|
expect(mockActionCapability.getActions)
|
||||||
.toHaveBeenCalledWith('create');
|
.toHaveBeenCalledWith('add');
|
||||||
});
|
});
|
||||||
|
|
||||||
it("invokes the action on the selection, if any", function () {
|
it("invokes the action on the selection, if any", function () {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user