Merge pull request #954 from nasa/open628

[Edit Mode] #628 Remove edit related concerns from Create Action
This commit is contained in:
Victor Woeltjen 2016-05-25 11:55:17 -07:00
commit 52e087d8f8
27 changed files with 317 additions and 285 deletions

View File

@ -24,23 +24,14 @@ define([
"./src/BrowseController", "./src/BrowseController",
"./src/PaneController", "./src/PaneController",
"./src/BrowseObjectController", "./src/BrowseObjectController",
"./src/creation/CreateMenuController",
"./src/creation/LocatorController",
"./src/MenuArrowController", "./src/MenuArrowController",
"./src/navigation/NavigationService", "./src/navigation/NavigationService",
"./src/creation/CreationPolicy",
"./src/navigation/NavigateAction", "./src/navigation/NavigateAction",
"./src/windowing/NewTabAction", "./src/windowing/NewTabAction",
"./src/windowing/FullscreenAction", "./src/windowing/FullscreenAction",
"./src/creation/CreateActionProvider",
"./src/creation/AddActionProvider",
"./src/creation/CreationService",
"./src/windowing/WindowTitler", "./src/windowing/WindowTitler",
"text!./res/templates/browse.html", "text!./res/templates/browse.html",
"text!./res/templates/create/locator.html",
"text!./res/templates/browse-object.html", "text!./res/templates/browse-object.html",
"text!./res/templates/create/create-button.html",
"text!./res/templates/create/create-menu.html",
"text!./res/templates/items/grid-item.html", "text!./res/templates/items/grid-item.html",
"text!./res/templates/browse/object-header.html", "text!./res/templates/browse/object-header.html",
"text!./res/templates/menu-arrow.html", "text!./res/templates/menu-arrow.html",
@ -53,23 +44,14 @@ define([
BrowseController, BrowseController,
PaneController, PaneController,
BrowseObjectController, BrowseObjectController,
CreateMenuController,
LocatorController,
MenuArrowController, MenuArrowController,
NavigationService, NavigationService,
CreationPolicy,
NavigateAction, NavigateAction,
NewTabAction, NewTabAction,
FullscreenAction, FullscreenAction,
CreateActionProvider,
AddActionProvider,
CreationService,
WindowTitler, WindowTitler,
browseTemplate, browseTemplate,
locatorTemplate,
browseObjectTemplate, browseObjectTemplate,
createButtonTemplate,
createMenuTemplate,
gridItemTemplate, gridItemTemplate,
objectHeaderTemplate, objectHeaderTemplate,
menuArrowTemplate, menuArrowTemplate,
@ -136,22 +118,6 @@ define([
"$route" "$route"
] ]
}, },
{
"key": "CreateMenuController",
"implementation": CreateMenuController,
"depends": [
"$scope"
]
},
{
"key": "LocatorController",
"implementation": LocatorController,
"depends": [
"$scope",
"$timeout",
"objectService"
]
},
{ {
"key": "MenuArrowController", "key": "MenuArrowController",
"implementation": MenuArrowController, "implementation": MenuArrowController,
@ -160,12 +126,6 @@ define([
] ]
} }
], ],
"controls": [
{
"key": "locator",
"template": locatorTemplate
}
],
"representations": [ "representations": [
{ {
"key": "view-object", "key": "view-object",
@ -181,17 +141,6 @@ define([
"view" "view"
] ]
}, },
{
"key": "create-button",
"template": createButtonTemplate
},
{
"key": "create-menu",
"template": createMenuTemplate,
"uses": [
"action"
]
},
{ {
"key": "grid-item", "key": "grid-item",
"template": gridItemTemplate, "template": gridItemTemplate,
@ -244,12 +193,6 @@ define([
"implementation": NavigationService "implementation": NavigationService
} }
], ],
"policies": [
{
"implementation": CreationPolicy,
"category": "creation"
}
],
"actions": [ "actions": [
{ {
"key": "navigate", "key": "navigate",
@ -302,42 +245,6 @@ define([
"editable": false "editable": false
} }
], ],
"components": [
{
"key": "CreateActionProvider",
"provides": "actionService",
"type": "provider",
"implementation": CreateActionProvider,
"depends": [
"$q",
"typeService",
"navigationService",
"policyService"
]
},
{
"key": "AddActionProvider",
"provides": "actionService",
"type": "provider",
"implementation": AddActionProvider,
"depends": [
"$q",
"typeService",
"dialogService",
"policyService"
]
},
{
"key": "CreationService",
"provides": "creationService",
"type": "provider",
"implementation": CreationService,
"depends": [
"$q",
"$log"
]
}
],
"runs": [ "runs": [
{ {
"implementation": WindowTitler, "implementation": WindowTitler,

View File

@ -1,130 +0,0 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/**
* MCTRepresentationSpec. Created by vwoeltje on 11/6/14.
*/
define(
["../../src/creation/CreateAction"],
function (CreateAction) {
describe("The create action", function () {
var mockType,
mockParent,
mockContext,
mockDialogService,
mockCreationService,
action;
function mockPromise(value) {
return {
then: function (callback) {
return mockPromise(callback(value));
}
};
}
beforeEach(function () {
mockType = jasmine.createSpyObj(
"type",
[
"getKey",
"getGlyph",
"getName",
"getDescription",
"getProperties",
"getInitialModel"
]
);
mockParent = jasmine.createSpyObj(
"domainObject",
[
"getId",
"getModel",
"getCapability"
]
);
mockContext = {
domainObject: mockParent
};
mockDialogService = jasmine.createSpyObj(
"dialogService",
["getUserInput"]
);
mockCreationService = jasmine.createSpyObj(
"creationService",
["createObject"]
);
mockType.getKey.andReturn("test");
mockType.getGlyph.andReturn("T");
mockType.getDescription.andReturn("a test type");
mockType.getName.andReturn("Test");
mockType.getProperties.andReturn([]);
mockType.getInitialModel.andReturn({});
mockDialogService.getUserInput.andReturn(mockPromise({}));
action = new CreateAction(
mockType,
mockParent,
mockContext,
mockDialogService,
mockCreationService
);
});
it("exposes type-appropriate metadata", function () {
var metadata = action.getMetadata();
expect(metadata.name).toEqual("Test");
expect(metadata.description).toEqual("a test type");
expect(metadata.glyph).toEqual("T");
});
//TODO: Disabled for NEM Beta
xit("invokes the creation service when performed", function () {
action.perform();
expect(mockCreationService.createObject).toHaveBeenCalledWith(
{ type: "test" },
mockParent
);
});
//TODO: Disabled for NEM Beta
xit("does not create an object if the user cancels", function () {
mockDialogService.getUserInput.andReturn({
then: function (callback, fail) {
fail();
}
});
action.perform();
expect(mockCreationService.createObject)
.not.toHaveBeenCalled();
});
});
}
);

View File

@ -43,6 +43,15 @@ define([
"./src/capabilities/EditorCapability", "./src/capabilities/EditorCapability",
"./src/capabilities/TransactionCapabilityDecorator", "./src/capabilities/TransactionCapabilityDecorator",
"./src/services/TransactionService", "./src/services/TransactionService",
"./src/creation/CreateMenuController",
"./src/creation/LocatorController",
"./src/creation/CreationPolicy",
"./src/creation/CreateActionProvider",
"./src/creation/AddActionProvider",
"./src/creation/CreationService",
"text!./res/templates/create/locator.html",
"text!./res/templates/create/create-button.html",
"text!./res/templates/create/create-menu.html",
"text!./res/templates/library.html", "text!./res/templates/library.html",
"text!./res/templates/edit-object.html", "text!./res/templates/edit-object.html",
"text!./res/templates/edit-action-buttons.html", "text!./res/templates/edit-action-buttons.html",
@ -72,6 +81,15 @@ define([
EditorCapability, EditorCapability,
TransactionCapabilityDecorator, TransactionCapabilityDecorator,
TransactionService, TransactionService,
CreateMenuController,
LocatorController,
CreationPolicy,
CreateActionProvider,
AddActionProvider,
CreationService,
locatorTemplate,
createButtonTemplate,
createMenuTemplate,
libraryTemplate, libraryTemplate,
editObjectTemplate, editObjectTemplate,
editActionButtonsTemplate, editActionButtonsTemplate,
@ -112,7 +130,23 @@ define([
"$location", "$location",
"policyService" "policyService"
] ]
} },
{
"key": "CreateMenuController",
"implementation": CreateMenuController,
"depends": [
"$scope"
]
},
{
"key": "LocatorController",
"implementation": LocatorController,
"depends": [
"$scope",
"$timeout",
"objectService"
]
},
], ],
"directives": [ "directives": [
{ {
@ -221,8 +255,11 @@ define([
"category": "navigation", "category": "navigation",
"message": "There are unsaved changes.", "message": "There are unsaved changes.",
"implementation": EditNavigationPolicy "implementation": EditNavigationPolicy
},
{
"implementation": CreationPolicy,
"category": "creation"
} }
], ],
"templates": [ "templates": [
{ {
@ -261,7 +298,18 @@ define([
{ {
"key": "topbar-edit", "key": "topbar-edit",
"template": topbarEditTemplate "template": topbarEditTemplate
} },
{
"key": "create-button",
"template": createButtonTemplate
},
{
"key": "create-menu",
"template": createMenuTemplate,
"uses": [
"action"
]
},
], ],
"components": [ "components": [
{ {
@ -282,7 +330,40 @@ define([
"$q", "$q",
"$log" "$log"
] ]
},
{
"key": "CreateActionProvider",
"provides": "actionService",
"type": "provider",
"implementation": CreateActionProvider,
"depends": [
"typeService",
"policyService"
]
},
{
"key": "AddActionProvider",
"provides": "actionService",
"type": "provider",
"implementation": AddActionProvider,
"depends": [
"$q",
"typeService",
"dialogService",
"policyService"
]
},
{
"key": "CreationService",
"provides": "creationService",
"type": "provider",
"implementation": CreationService,
"depends": [
"$q",
"$log"
]
} }
], ],
"representers": [ "representers": [
{ {
@ -316,6 +397,12 @@ define([
"transactionService" "transactionService"
] ]
} }
],
"controls": [
{
"key": "locator",
"template": locatorTemplate
}
] ]
} }
}); });

View File

@ -74,6 +74,12 @@ define(
self.domainObject.getCapability('editor').cancel(); self.domainObject.getCapability('editor').cancel();
self.navigationService.removeListener(cancelEditing); self.navigationService.removeListener(cancelEditing);
} }
//If this is not the currently navigated object, then navigate
// to it.
if (this.navigationService.getNavigation() !== this.domainObject) {
this.navigationService.setNavigation(this.domainObject);
}
this.navigationService.addListener(cancelEditing); this.navigationService.addListener(cancelEditing);
this.domainObject.useCapability("editor"); this.domainObject.useCapability("editor");
}; };

View File

@ -22,7 +22,7 @@
define( define(
['../../../browse/src/creation/CreateWizard'], ['../creation/CreateWizard'],
function (CreateWizard) { function (CreateWizard) {
/** /**

View File

@ -43,11 +43,8 @@ define(
* override this) * override this)
* @param {ActionContext} context the context in which the * @param {ActionContext} context the context in which the
* action is being performed * action is being performed
* @param {NavigationService} navigationService the navigation service,
* which handles changes in navigation. It allows the object
* being browsed/edited to be set.
*/ */
function CreateAction(type, parent, context, $q, navigationService) { function CreateAction(type, parent, context) {
this.metadata = { this.metadata = {
key: 'create', key: 'create',
glyph: type.getGlyph(), glyph: type.getGlyph(),
@ -56,24 +53,8 @@ define(
description: type.getDescription(), description: type.getDescription(),
context: context context: context
}; };
this.type = type; this.type = type;
this.parent = parent; this.parent = parent;
this.navigationService = navigationService;
this.$q = $q;
}
// Get a count of views which are not flagged as non-editable.
function countEditableViews(domainObject) {
var views = domainObject && domainObject.useCapability('view'),
count = 0;
// A view is editable unless explicitly flagged as not
(views || []).forEach(function (view) {
count += (view.editable !== false) ? 1 : 0;
});
return count;
} }
/** /**
@ -82,26 +63,31 @@ define(
*/ */
CreateAction.prototype.perform = function () { CreateAction.prototype.perform = function () {
var newModel = this.type.getInitialModel(), var newModel = this.type.getInitialModel(),
parentObject = this.navigationService.getNavigation(), newObject,
editorCapability, editAction,
newObject; editorCapability;
function onSave() {
return editorCapability.save();
}
function onCancel() {
return editorCapability.cancel();
}
newModel.type = this.type.getKey(); newModel.type = this.type.getKey();
newModel.location = parentObject.getId(); newModel.location = this.parent.getId();
newObject = parentObject.useCapability('instantiation', newModel); newObject = this.parent.useCapability('instantiation', newModel);
editorCapability = newObject.hasCapability('editor') && newObject.getCapability("editor");
editorCapability = newObject.getCapability("editor"); editAction = newObject.getCapability("action").getActions("edit")[0];
//If an edit action is available, perform it
if (countEditableViews(newObject) > 0 && newObject.hasCapability('composition')) { if (editAction) {
this.navigationService.setNavigation(newObject); return editAction.perform();
return newObject.getCapability("action").perform("edit"); } else if (editorCapability) {
} else { //otherwise, use the save action
editorCapability.edit(); editorCapability.edit();
return newObject.useCapability("action").perform("save").then(function () { return newObject.getCapability("action").perform("save").then(onSave, onCancel);
return editorCapability.save();
}, function () {
return editorCapability.cancel();
});
} }
}; };

View File

@ -44,10 +44,8 @@ define(
* introduced in this bundle), responsible for handling actual * introduced in this bundle), responsible for handling actual
* object creation. * object creation.
*/ */
function CreateActionProvider($q, typeService, navigationService, policyService) { function CreateActionProvider(typeService, policyService) {
this.typeService = typeService; this.typeService = typeService;
this.navigationService = navigationService;
this.$q = $q;
this.policyService = policyService; this.policyService = policyService;
} }
@ -72,9 +70,7 @@ define(
return new CreateAction( return new CreateAction(
type, type,
destination, destination,
context, context
self.$q,
self.navigationService
); );
}); });
}; };

View File

@ -56,7 +56,10 @@ define(
// A view is editable unless explicitly flagged as not // A view is editable unless explicitly flagged as not
(views || []).forEach(function (view) { (views || []).forEach(function (view) {
if (view.editable === true || if (view.editable === true ||
(view.key === 'plot' && type.getKey() === 'telemetry.panel')) { (view.key === 'plot' && type.getKey() === 'telemetry.panel') ||
(view.key === 'table' && type.getKey() === 'table') ||
(view.key === 'rt-table' && type.getKey() === 'rttable')
) {
count++; count++;
} }
}); });

View File

@ -29,13 +29,10 @@ define(
describe("The create action provider", function () { describe("The create action provider", function () {
var mockTypeService, var mockTypeService,
mockDialogService,
mockNavigationService,
mockPolicyService, mockPolicyService,
mockCreationPolicy, mockCreationPolicy,
mockPolicyMap = {}, mockPolicyMap = {},
mockTypes, mockTypes,
mockQ,
provider; provider;
function createMockType(name) { function createMockType(name) {
@ -61,14 +58,6 @@ define(
"typeService", "typeService",
["listTypes"] ["listTypes"]
); );
mockDialogService = jasmine.createSpyObj(
"dialogService",
["getUserInput"]
);
mockNavigationService = jasmine.createSpyObj(
"navigationService",
["setNavigation"]
);
mockPolicyService = jasmine.createSpyObj( mockPolicyService = jasmine.createSpyObj(
"policyService", "policyService",
["allow"] ["allow"]
@ -91,9 +80,7 @@ define(
mockTypeService.listTypes.andReturn(mockTypes); mockTypeService.listTypes.andReturn(mockTypes);
provider = new CreateActionProvider( provider = new CreateActionProvider(
mockQ,
mockTypeService, mockTypeService,
mockNavigationService,
mockPolicyService mockPolicyService
); );
}); });

View File

@ -0,0 +1,190 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/**
* MCTRepresentationSpec. Created by vwoeltje on 11/6/14.
*/
define(
["../../src/creation/CreateAction"],
function (CreateAction) {
describe("The create action", function () {
var mockType,
mockParent,
mockContext,
mockDomainObject,
capabilities = {},
mockEditAction,
mockSaveAction,
action;
function mockPromise(value) {
return {
then: function (callback) {
return mockPromise(callback(value));
}
};
}
beforeEach(function () {
mockType = jasmine.createSpyObj(
"type",
[
"getKey",
"getGlyph",
"getName",
"getDescription",
"getProperties",
"getInitialModel"
]
);
mockParent = jasmine.createSpyObj(
"domainObject",
[
"getId",
"getModel",
"getCapability",
"useCapability"
]
);
mockDomainObject = jasmine.createSpyObj(
"domainObject",
[
"getId",
"getModel",
"getCapability",
"hasCapability",
"useCapability"
]
);
mockDomainObject.hasCapability.andCallFake(function (name) {
return !!capabilities[name];
});
mockDomainObject.getCapability.andCallFake(function (name) {
return capabilities[name];
});
mockSaveAction = jasmine.createSpyObj(
"saveAction",
[
"perform"
]
);
capabilities.action = jasmine.createSpyObj(
"actionCapability",
[
"getActions",
"perform"
]
);
capabilities.editor = jasmine.createSpyObj(
"editorCapability",
[
"edit",
"save",
"cancel"
]
);
mockEditAction = jasmine.createSpyObj(
"editAction",
[
"perform"
]
);
mockContext = {
domainObject: mockParent
};
mockParent.useCapability.andReturn(mockDomainObject);
mockType.getKey.andReturn("test");
mockType.getGlyph.andReturn("T");
mockType.getDescription.andReturn("a test type");
mockType.getName.andReturn("Test");
mockType.getProperties.andReturn([]);
mockType.getInitialModel.andReturn({});
action = new CreateAction(
mockType,
mockParent,
mockContext
);
});
it("exposes type-appropriate metadata", function () {
var metadata = action.getMetadata();
expect(metadata.name).toEqual("Test");
expect(metadata.description).toEqual("a test type");
expect(metadata.glyph).toEqual("T");
});
describe("the perform function", function () {
beforeEach(function () {
capabilities.action.getActions.andReturn([mockEditAction]);
});
it("uses the instantiation capability when performed", function () {
action.perform();
expect(mockParent.useCapability).toHaveBeenCalledWith("instantiation", jasmine.any(Object));
});
it("uses the edit action if available", function () {
action.perform();
expect(mockEditAction.perform).toHaveBeenCalled();
});
it("uses the save action if object does not have an edit action" +
" available", function () {
capabilities.action.getActions.andReturn([]);
capabilities.action.perform.andReturn(mockPromise(undefined));
action.perform();
expect(capabilities.action.perform).toHaveBeenCalledWith("save");
});
describe("uses to editor capability", function () {
var promise = jasmine.createSpyObj("promise", ["then"]);
beforeEach(function () {
capabilities.action.getActions.andReturn([]);
capabilities.action.perform.andReturn(promise);
});
it("to save the edit if user saves dialog", function () {
action.perform();
expect(promise.then).toHaveBeenCalled();
promise.then.mostRecentCall.args[0]();
expect(capabilities.editor.save).toHaveBeenCalled();
});
it("to cancel the edit if user cancels dialog", function () {
action.perform();
promise.then.mostRecentCall.args[1]();
expect(capabilities.editor.cancel).toHaveBeenCalled();
});
});
});
});
}
);

View File

@ -133,7 +133,7 @@ define([
"telemetry" "telemetry"
], ],
"delegation": true, "delegation": true,
"editable": true "editable": false
}, },
{ {
"name": "Real-time Table", "name": "Real-time Table",
@ -144,7 +144,7 @@ define([
"telemetry" "telemetry"
], ],
"delegation": true, "delegation": true,
"editable": true "editable": false
} }
], ],
"directives": [ "directives": [