mirror of
https://github.com/nasa/openmct.git
synced 2025-06-20 08:03:49 +00:00
[Remove] Add confirmation dialog (#1870)
* [Remove] Added confirmation dialog before the remove action is performed Addresses #563
This commit is contained in:
committed by
Andrew Henry
parent
15a75ac134
commit
a1d206bfc3
@ -188,6 +188,7 @@ define([
|
|||||||
"name": "Remove",
|
"name": "Remove",
|
||||||
"description": "Remove this object from its containing object.",
|
"description": "Remove this object from its containing object.",
|
||||||
"depends": [
|
"depends": [
|
||||||
|
"dialogService",
|
||||||
"navigationService"
|
"navigationService"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -23,9 +23,11 @@
|
|||||||
/**
|
/**
|
||||||
* Module defining RemoveAction. Created by vwoeltje on 11/17/14.
|
* Module defining RemoveAction. Created by vwoeltje on 11/17/14.
|
||||||
*/
|
*/
|
||||||
define(
|
define([
|
||||||
[],
|
'./RemoveDialog'
|
||||||
function () {
|
], function (
|
||||||
|
RemoveDialog
|
||||||
|
) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct an action which will remove the provided object manifestation.
|
* Construct an action which will remove the provided object manifestation.
|
||||||
@ -33,25 +35,27 @@ define(
|
|||||||
* is looked up via the "context" capability (so this will be the
|
* is looked up via the "context" capability (so this will be the
|
||||||
* immediate ancestor by which this specific object was reached.)
|
* immediate ancestor by which this specific object was reached.)
|
||||||
*
|
*
|
||||||
* @param {DomainObject} object the object to be removed
|
* @param {DialogService} dialogService a service which will show the dialog
|
||||||
|
* @param {NavigationService} navigationService a service that maintains the current navigation state
|
||||||
* @param {ActionContext} context the context in which this action is performed
|
* @param {ActionContext} context the context in which this action is performed
|
||||||
* @memberof platform/commonUI/edit
|
* @memberof platform/commonUI/edit
|
||||||
* @constructor
|
* @constructor
|
||||||
* @implements {Action}
|
* @implements {Action}
|
||||||
*/
|
*/
|
||||||
function RemoveAction(navigationService, context) {
|
function RemoveAction(dialogService, navigationService, context) {
|
||||||
this.domainObject = (context || {}).domainObject;
|
this.domainObject = (context || {}).domainObject;
|
||||||
|
this.dialogService = dialogService;
|
||||||
this.navigationService = navigationService;
|
this.navigationService = navigationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform this action.
|
* Perform this action.
|
||||||
* @return {Promise} a promise which will be
|
|
||||||
* fulfilled when the action has completed.
|
|
||||||
*/
|
*/
|
||||||
RemoveAction.prototype.perform = function () {
|
RemoveAction.prototype.perform = function () {
|
||||||
var navigationService = this.navigationService,
|
var dialog,
|
||||||
domainObject = this.domainObject;
|
dialogService = this.dialogService,
|
||||||
|
domainObject = this.domainObject,
|
||||||
|
navigationService = this.navigationService;
|
||||||
/*
|
/*
|
||||||
* Check whether an object ID matches the ID of the object being
|
* Check whether an object ID matches the ID of the object being
|
||||||
* removed (used to filter a parent's composition to handle the
|
* removed (used to filter a parent's composition to handle the
|
||||||
@ -111,7 +115,12 @@ define(
|
|||||||
return parent.useCapability('mutation', doMutate);
|
return parent.useCapability('mutation', doMutate);
|
||||||
}
|
}
|
||||||
|
|
||||||
return removeFromContext(domainObject);
|
/*
|
||||||
|
* Pass in the function to remove the domain object so it can be
|
||||||
|
* associated with an 'OK' button press
|
||||||
|
*/
|
||||||
|
dialog = new RemoveDialog(dialogService, domainObject, removeFromContext);
|
||||||
|
dialog.show();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Object needs to have a parent for Remove to be applicable
|
// Object needs to have a parent for Remove to be applicable
|
||||||
@ -129,5 +138,4 @@ define(
|
|||||||
};
|
};
|
||||||
|
|
||||||
return RemoveAction;
|
return RemoveAction;
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
77
platform/commonUI/edit/src/actions/RemoveDialog.js
Normal file
77
platform/commonUI/edit/src/actions/RemoveDialog.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2017, 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 () {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback removeCallback
|
||||||
|
* @param {DomainObject} domainObject the domain object to be removed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new Remove dialog.
|
||||||
|
*
|
||||||
|
* @param {DialogService} dialogService the service that shows the dialog
|
||||||
|
* @param {DomainObject} domainObject the domain object to be removed
|
||||||
|
* @param {removeCallback} removeCallback callback that handles removal of the domain object
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function RemoveDialog(dialogService, domainObject, removeCallback) {
|
||||||
|
this.dialogService = dialogService;
|
||||||
|
this.domainObject = domainObject;
|
||||||
|
this.removeCallback = removeCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a dialog to confirm the removal of a domain object.
|
||||||
|
*/
|
||||||
|
RemoveDialog.prototype.show = function () {
|
||||||
|
var dialog,
|
||||||
|
domainObject = this.domainObject,
|
||||||
|
removeCallback = this.removeCallback,
|
||||||
|
model = {
|
||||||
|
title: 'Remove ' + domainObject.getModel().name,
|
||||||
|
actionText: 'Warning! This action will permanently remove this object. Are you sure you want to continue?',
|
||||||
|
severity: 'alert',
|
||||||
|
primaryOption: {
|
||||||
|
label: 'OK',
|
||||||
|
callback: function () {
|
||||||
|
removeCallback(domainObject);
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: 'Cancel',
|
||||||
|
callback: function () {
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
dialog = this.dialogService.showBlockingMessage(model);
|
||||||
|
};
|
||||||
|
|
||||||
|
return RemoveDialog;
|
||||||
|
});
|
@ -25,50 +25,37 @@ define(
|
|||||||
function (RemoveAction) {
|
function (RemoveAction) {
|
||||||
|
|
||||||
describe("The Remove action", function () {
|
describe("The Remove action", function () {
|
||||||
var mockQ,
|
var action,
|
||||||
mockNavigationService,
|
|
||||||
mockDomainObject,
|
|
||||||
mockParent,
|
|
||||||
mockChildObject,
|
|
||||||
mockGrandchildObject,
|
|
||||||
mockRootObject,
|
|
||||||
mockContext,
|
|
||||||
mockChildContext,
|
|
||||||
mockGrandchildContext,
|
|
||||||
mockRootContext,
|
|
||||||
mockMutation,
|
|
||||||
mockType,
|
|
||||||
actionContext,
|
actionContext,
|
||||||
model,
|
|
||||||
capabilities,
|
capabilities,
|
||||||
action;
|
mockContext,
|
||||||
|
mockDialogService,
|
||||||
function mockPromise(value) {
|
mockDomainObject,
|
||||||
return {
|
mockMutation,
|
||||||
then: function (callback) {
|
mockNavigationService,
|
||||||
return mockPromise(callback(value));
|
mockParent,
|
||||||
}
|
mockType,
|
||||||
};
|
model;
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
mockDomainObject = jasmine.createSpyObj(
|
mockDomainObject = jasmine.createSpyObj(
|
||||||
"domainObject",
|
"domainObject",
|
||||||
["getId", "getCapability"]
|
["getId", "getCapability", "getModel"]
|
||||||
);
|
);
|
||||||
mockChildObject = jasmine.createSpyObj(
|
|
||||||
"domainObject",
|
mockMutation = jasmine.createSpyObj("mutation", ["invoke"]);
|
||||||
["getId", "getCapability"]
|
mockType = jasmine.createSpyObj("type", ["hasFeature"]);
|
||||||
);
|
mockType.hasFeature.and.returnValue(true);
|
||||||
mockGrandchildObject = jasmine.createSpyObj(
|
|
||||||
"domainObject",
|
capabilities = {
|
||||||
["getId", "getCapability"]
|
mutation: mockMutation,
|
||||||
);
|
type: mockType
|
||||||
mockRootObject = jasmine.createSpyObj(
|
};
|
||||||
"domainObject",
|
|
||||||
["getId", "getCapability"]
|
model = {
|
||||||
);
|
composition: ["a", "test", "b"]
|
||||||
mockQ = { when: mockPromise };
|
};
|
||||||
|
|
||||||
mockParent = {
|
mockParent = {
|
||||||
getModel: function () {
|
getModel: function () {
|
||||||
return model;
|
return model;
|
||||||
@ -80,12 +67,12 @@ define(
|
|||||||
return capabilities[k].invoke(v);
|
return capabilities[k].invoke(v);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
mockContext = jasmine.createSpyObj("context", ["getParent"]);
|
|
||||||
mockChildContext = jasmine.createSpyObj("context", ["getParent"]);
|
mockDialogService = jasmine.createSpyObj(
|
||||||
mockGrandchildContext = jasmine.createSpyObj("context", ["getParent"]);
|
"dialogService",
|
||||||
mockRootContext = jasmine.createSpyObj("context", ["getParent"]);
|
["showBlockingMessage"]
|
||||||
mockMutation = jasmine.createSpyObj("mutation", ["invoke"]);
|
);
|
||||||
mockType = jasmine.createSpyObj("type", ["hasFeature"]);
|
|
||||||
mockNavigationService = jasmine.createSpyObj(
|
mockNavigationService = jasmine.createSpyObj(
|
||||||
"navigationService",
|
"navigationService",
|
||||||
[
|
[
|
||||||
@ -97,23 +84,19 @@ define(
|
|||||||
);
|
);
|
||||||
mockNavigationService.getNavigation.and.returnValue(mockDomainObject);
|
mockNavigationService.getNavigation.and.returnValue(mockDomainObject);
|
||||||
|
|
||||||
|
mockContext = jasmine.createSpyObj("context", ["getParent"]);
|
||||||
|
mockContext.getParent.and.returnValue(mockParent);
|
||||||
|
|
||||||
mockDomainObject.getId.and.returnValue("test");
|
mockDomainObject.getId.and.returnValue("test");
|
||||||
mockDomainObject.getCapability.and.returnValue(mockContext);
|
mockDomainObject.getCapability.and.returnValue(mockContext);
|
||||||
|
mockDomainObject.getModel.and.returnValue({name: 'test object'});
|
||||||
|
|
||||||
mockContext.getParent.and.returnValue(mockParent);
|
mockContext.getParent.and.returnValue(mockParent);
|
||||||
mockType.hasFeature.and.returnValue(true);
|
mockType.hasFeature.and.returnValue(true);
|
||||||
|
|
||||||
capabilities = {
|
|
||||||
mutation: mockMutation,
|
|
||||||
type: mockType
|
|
||||||
};
|
|
||||||
model = {
|
|
||||||
composition: ["a", "test", "b"]
|
|
||||||
};
|
|
||||||
|
|
||||||
actionContext = { domainObject: mockDomainObject };
|
actionContext = { domainObject: mockDomainObject };
|
||||||
|
|
||||||
action = new RemoveAction(mockNavigationService, actionContext);
|
action = new RemoveAction(mockDialogService, mockNavigationService, actionContext);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("only applies to objects with parents", function () {
|
it("only applies to objects with parents", function () {
|
||||||
@ -127,15 +110,73 @@ define(
|
|||||||
expect(mockType.hasFeature).toHaveBeenCalledWith('creation');
|
expect(mockType.hasFeature).toHaveBeenCalledWith('creation');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("shows a blocking message dialog", function () {
|
||||||
|
mockParent = jasmine.createSpyObj(
|
||||||
|
"parent",
|
||||||
|
["getModel", "getCapability", "useCapability"]
|
||||||
|
);
|
||||||
|
|
||||||
|
action.perform();
|
||||||
|
|
||||||
|
expect(mockDialogService.showBlockingMessage).toHaveBeenCalled();
|
||||||
|
|
||||||
|
// Also check that no mutation happens at this point
|
||||||
|
expect(mockParent.useCapability).not.toHaveBeenCalledWith("mutation", jasmine.any(Function));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("after the remove callback is triggered", function () {
|
||||||
|
var mockChildContext,
|
||||||
|
mockChildObject,
|
||||||
|
mockDialogHandle,
|
||||||
|
mockGrandchildContext,
|
||||||
|
mockGrandchildObject,
|
||||||
|
mockRootContext,
|
||||||
|
mockRootObject;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockChildObject = jasmine.createSpyObj(
|
||||||
|
"domainObject",
|
||||||
|
["getId", "getCapability"]
|
||||||
|
);
|
||||||
|
|
||||||
|
mockDialogHandle = jasmine.createSpyObj(
|
||||||
|
"dialogHandle",
|
||||||
|
["dismiss"]
|
||||||
|
);
|
||||||
|
|
||||||
|
mockGrandchildObject = jasmine.createSpyObj(
|
||||||
|
"domainObject",
|
||||||
|
["getId", "getCapability"]
|
||||||
|
);
|
||||||
|
|
||||||
|
mockRootObject = jasmine.createSpyObj(
|
||||||
|
"domainObject",
|
||||||
|
["getId", "getCapability"]
|
||||||
|
);
|
||||||
|
|
||||||
|
mockChildContext = jasmine.createSpyObj("context", ["getParent"]);
|
||||||
|
mockGrandchildContext = jasmine.createSpyObj("context", ["getParent"]);
|
||||||
|
mockRootContext = jasmine.createSpyObj("context", ["getParent"]);
|
||||||
|
|
||||||
|
mockDialogService.showBlockingMessage.and.returnValue(mockDialogHandle);
|
||||||
|
});
|
||||||
|
|
||||||
it("mutates the parent when performed", function () {
|
it("mutates the parent when performed", function () {
|
||||||
action.perform();
|
action.perform();
|
||||||
|
mockDialogService.showBlockingMessage.calls.mostRecent().args[0]
|
||||||
|
.primaryOption.callback();
|
||||||
|
|
||||||
expect(mockMutation.invoke)
|
expect(mockMutation.invoke)
|
||||||
.toHaveBeenCalledWith(jasmine.any(Function));
|
.toHaveBeenCalledWith(jasmine.any(Function));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("changes composition from its mutation function", function () {
|
it("changes composition from its mutation function", function () {
|
||||||
var mutator, result;
|
var mutator, result;
|
||||||
|
|
||||||
action.perform();
|
action.perform();
|
||||||
|
mockDialogService.showBlockingMessage.calls.mostRecent().args[0]
|
||||||
|
.primaryOption.callback();
|
||||||
|
|
||||||
mutator = mockMutation.invoke.calls.mostRecent().args[0];
|
mutator = mockMutation.invoke.calls.mostRecent().args[0];
|
||||||
result = mutator(model);
|
result = mutator(model);
|
||||||
|
|
||||||
@ -171,6 +212,8 @@ define(
|
|||||||
mockType.hasFeature.and.returnValue(true);
|
mockType.hasFeature.and.returnValue(true);
|
||||||
|
|
||||||
action.perform();
|
action.perform();
|
||||||
|
mockDialogService.showBlockingMessage.calls.mostRecent().args[0]
|
||||||
|
.primaryOption.callback();
|
||||||
|
|
||||||
// Expects navigation to parent of domainObject (removed object)
|
// Expects navigation to parent of domainObject (removed object)
|
||||||
expect(mockNavigationService.setNavigation).toHaveBeenCalledWith(mockParent);
|
expect(mockNavigationService.setNavigation).toHaveBeenCalledWith(mockParent);
|
||||||
@ -199,11 +242,14 @@ define(
|
|||||||
mockType.hasFeature.and.returnValue(true);
|
mockType.hasFeature.and.returnValue(true);
|
||||||
|
|
||||||
action.perform();
|
action.perform();
|
||||||
|
mockDialogService.showBlockingMessage.calls.mostRecent().args[0]
|
||||||
|
.primaryOption.callback();
|
||||||
|
|
||||||
// Expects no navigation to occur
|
// Expects no navigation to occur
|
||||||
expect(mockNavigationService.setNavigation).not.toHaveBeenCalled();
|
expect(mockNavigationService.setNavigation).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user