Compare commits
18 Commits
tobiasbrow
...
table-row-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91a8fbeb3e | ||
|
|
534bdbae50 | ||
|
|
831873e7de | ||
|
|
622d246fdd | ||
|
|
4a1ca9f299 | ||
|
|
4e1de2678c | ||
|
|
33a4792531 | ||
|
|
37dd4856a6 | ||
|
|
6a9cf3389d | ||
|
|
9582fb2b06 | ||
|
|
3c075b7ff2 | ||
|
|
081edfbd70 | ||
|
|
04cc8f7aa2 | ||
|
|
2da2395473 | ||
|
|
a1d206bfc3 | ||
|
|
00ecd27bb3 | ||
|
|
0fa4486dcf | ||
|
|
ef9c6d5fed |
@@ -20,14 +20,8 @@ API. Open MCT is also being refactored to minimize the dependencies that using
|
||||
Open MCT imposes on developers, such as the current requirement to use
|
||||
AngularJS.
|
||||
|
||||
This new API has not yet been heavily used and is likely to contain defects.
|
||||
You can help by trying it out, and reporting any issues you encounter
|
||||
using our GitHub issue tracker. Such issues may include bugs, suggestions,
|
||||
missing documentation, or even just requests for help if you're having
|
||||
trouble.
|
||||
|
||||
We want Open MCT to be as easy to use, install, run, and develop for as
|
||||
possible, and your feedback will help us get there!
|
||||
possible, and your feedback will help us get there! Feedback can be provided via [GitHub issues](https://github.com/nasa/openmct/issues), or by emailing us at [arc-dl-openmct@nasa.gov](mailto:arc-dl-openmct@nasa.gov).
|
||||
|
||||
## Building and Running Open MCT Locally
|
||||
|
||||
|
||||
10
openmct.js
10
openmct.js
@@ -41,14 +41,14 @@ requirejs.config({
|
||||
"lodash": "bower_components/lodash/lodash",
|
||||
"d3-selection": "node_modules/d3-selection/dist/d3-selection.min",
|
||||
"d3-scale": "node_modules/d3-scale/build/d3-scale.min",
|
||||
"d3-axis": "node_modules/d3-axis/build/d3-axis.min",
|
||||
"d3-array": "node_modules/d3-array/build/d3-array.min",
|
||||
"d3-collection": "node_modules/d3-collection/build/d3-collection.min",
|
||||
"d3-axis": "node_modules/d3-axis/dist/d3-axis.min",
|
||||
"d3-array": "node_modules/d3-array/dist/d3-array.min",
|
||||
"d3-collection": "node_modules/d3-collection/dist/d3-collection.min",
|
||||
"d3-color": "node_modules/d3-color/build/d3-color.min",
|
||||
"d3-format": "node_modules/d3-format/build/d3-format.min",
|
||||
"d3-interpolate": "node_modules/d3-interpolate/build/d3-interpolate.min",
|
||||
"d3-time": "node_modules/d3-time/build/d3-time.min",
|
||||
"d3-time-format": "node_modules/d3-time-format/build/d3-time-format.min",
|
||||
"d3-time": "node_modules/d3-time/dist/d3-time.min",
|
||||
"d3-time-format": "node_modules/d3-time-format/dist/d3-time-format.min",
|
||||
"html2canvas": "node_modules/html2canvas/dist/html2canvas.min",
|
||||
"painterro": "node_modules/painterro/build/painterro.min",
|
||||
"printj": "node_modules/printj/dist/printj.min"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "openmct",
|
||||
"version": "0.14.0-SNAPSHOT",
|
||||
"description": "The Open MCT core platform",
|
||||
"description": "The Open MCT core platform.",
|
||||
"dependencies": {
|
||||
"d3-array": "1.2.x",
|
||||
"d3-axis": "1.0.x",
|
||||
|
||||
@@ -188,6 +188,7 @@ define([
|
||||
"name": "Remove",
|
||||
"description": "Remove this object from its containing object.",
|
||||
"depends": [
|
||||
"dialogService",
|
||||
"navigationService"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -23,111 +23,125 @@
|
||||
/**
|
||||
* Module defining RemoveAction. Created by vwoeltje on 11/17/14.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
define([
|
||||
'./RemoveDialog'
|
||||
], function (
|
||||
RemoveDialog
|
||||
) {
|
||||
|
||||
/**
|
||||
* Construct an action which will remove the provided object manifestation.
|
||||
* The object will be removed from its parent's composition; the parent
|
||||
* is looked up via the "context" capability (so this will be the
|
||||
* immediate ancestor by which this specific object was reached.)
|
||||
*
|
||||
* @param {DomainObject} object the object to be removed
|
||||
* @param {ActionContext} context the context in which this action is performed
|
||||
* @memberof platform/commonUI/edit
|
||||
* @constructor
|
||||
* @implements {Action}
|
||||
/**
|
||||
* Construct an action which will remove the provided object manifestation.
|
||||
* The object will be removed from its parent's composition; the parent
|
||||
* is looked up via the "context" capability (so this will be the
|
||||
* immediate ancestor by which this specific object was reached.)
|
||||
*
|
||||
* @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
|
||||
* @memberof platform/commonUI/edit
|
||||
* @constructor
|
||||
* @implements {Action}
|
||||
*/
|
||||
function RemoveAction(dialogService, navigationService, context) {
|
||||
this.domainObject = (context || {}).domainObject;
|
||||
this.dialogService = dialogService;
|
||||
this.navigationService = navigationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform this action.
|
||||
*/
|
||||
RemoveAction.prototype.perform = function (skipWarning) {
|
||||
var dialog,
|
||||
dialogService = this.dialogService,
|
||||
domainObject = this.domainObject,
|
||||
navigationService = this.navigationService;
|
||||
/*
|
||||
* Check whether an object ID matches the ID of the object being
|
||||
* removed (used to filter a parent's composition to handle the
|
||||
* removal.)
|
||||
*/
|
||||
function RemoveAction(navigationService, context) {
|
||||
this.domainObject = (context || {}).domainObject;
|
||||
this.navigationService = navigationService;
|
||||
function isNotObject(otherObjectId) {
|
||||
return otherObjectId !== domainObject.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform this action.
|
||||
* @return {Promise} a promise which will be
|
||||
* fulfilled when the action has completed.
|
||||
/*
|
||||
* Mutate a parent object such that it no longer contains the object
|
||||
* which is being removed.
|
||||
*/
|
||||
RemoveAction.prototype.perform = function () {
|
||||
var navigationService = this.navigationService,
|
||||
domainObject = this.domainObject;
|
||||
/*
|
||||
* Check whether an object ID matches the ID of the object being
|
||||
* removed (used to filter a parent's composition to handle the
|
||||
* removal.)
|
||||
*/
|
||||
function isNotObject(otherObjectId) {
|
||||
return otherObjectId !== domainObject.getId();
|
||||
}
|
||||
function doMutate(model) {
|
||||
model.composition = model.composition.filter(isNotObject);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mutate a parent object such that it no longer contains the object
|
||||
* which is being removed.
|
||||
*/
|
||||
function doMutate(model) {
|
||||
model.composition = model.composition.filter(isNotObject);
|
||||
}
|
||||
/*
|
||||
* Checks current object and ascendants of current
|
||||
* object with object being removed, if the current
|
||||
* object or any in the current object's path is being removed,
|
||||
* navigate back to parent of removed object.
|
||||
*/
|
||||
function checkObjectNavigation(object, parentObject) {
|
||||
// Traverse object starts at current location
|
||||
var traverseObject = (navigationService).getNavigation(),
|
||||
context;
|
||||
|
||||
/*
|
||||
* Checks current object and ascendants of current
|
||||
* object with object being removed, if the current
|
||||
* object or any in the current object's path is being removed,
|
||||
* navigate back to parent of removed object.
|
||||
*/
|
||||
function checkObjectNavigation(object, parentObject) {
|
||||
// Traverse object starts at current location
|
||||
var traverseObject = (navigationService).getNavigation(),
|
||||
context;
|
||||
|
||||
// Stop when object is not defined (above ROOT)
|
||||
while (traverseObject) {
|
||||
// If object currently traversed to is object being removed
|
||||
// navigate to parent of current object and then exit loop
|
||||
if (traverseObject.getId() === object.getId()) {
|
||||
navigationService.setNavigation(parentObject);
|
||||
return;
|
||||
}
|
||||
// Traverses to parent of current object, moving
|
||||
// up the ascendant path
|
||||
context = traverseObject.getCapability('context');
|
||||
traverseObject = context && context.getParent();
|
||||
// Stop when object is not defined (above ROOT)
|
||||
while (traverseObject) {
|
||||
// If object currently traversed to is object being removed
|
||||
// navigate to parent of current object and then exit loop
|
||||
if (traverseObject.getId() === object.getId()) {
|
||||
navigationService.setNavigation(parentObject);
|
||||
return;
|
||||
}
|
||||
// Traverses to parent of current object, moving
|
||||
// up the ascendant path
|
||||
context = traverseObject.getCapability('context');
|
||||
traverseObject = context && context.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the object from its parent, as identified by its context
|
||||
* capability. Based on object's location and selected object's location
|
||||
* user may be navigated to existing parent object
|
||||
*/
|
||||
function removeFromContext(object) {
|
||||
var contextCapability = object.getCapability('context'),
|
||||
parent = contextCapability.getParent();
|
||||
|
||||
// If currently within path of removed object(s),
|
||||
// navigates to existing object up tree
|
||||
checkObjectNavigation(object, parent);
|
||||
|
||||
return parent.useCapability('mutation', doMutate);
|
||||
}
|
||||
|
||||
if (skipWarning) {
|
||||
|
||||
removeFromContext(domainObject);
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Remove the object from its parent, as identified by its context
|
||||
* capability. Based on object's location and selected object's location
|
||||
* user may be navigated to existing parent object
|
||||
*/
|
||||
function removeFromContext(object) {
|
||||
var contextCapability = object.getCapability('context'),
|
||||
parent = contextCapability.getParent();
|
||||
* 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();
|
||||
}
|
||||
};
|
||||
|
||||
// If currently within path of removed object(s),
|
||||
// navigates to existing object up tree
|
||||
checkObjectNavigation(object, parent);
|
||||
// Object needs to have a parent for Remove to be applicable
|
||||
RemoveAction.appliesTo = function (context) {
|
||||
var object = (context || {}).domainObject,
|
||||
contextCapability = object && object.getCapability("context"),
|
||||
parent = contextCapability && contextCapability.getParent(),
|
||||
parentType = parent && parent.getCapability('type'),
|
||||
parentCreatable = parentType && parentType.hasFeature('creation');
|
||||
|
||||
return parent.useCapability('mutation', doMutate);
|
||||
}
|
||||
// Only creatable types should be modifiable
|
||||
return parent !== undefined &&
|
||||
Array.isArray(parent.getModel().composition) &&
|
||||
parentCreatable;
|
||||
};
|
||||
|
||||
return removeFromContext(domainObject);
|
||||
};
|
||||
|
||||
// Object needs to have a parent for Remove to be applicable
|
||||
RemoveAction.appliesTo = function (context) {
|
||||
var object = (context || {}).domainObject,
|
||||
contextCapability = object && object.getCapability("context"),
|
||||
parent = contextCapability && contextCapability.getParent(),
|
||||
parentType = parent && parent.getCapability('type'),
|
||||
parentCreatable = parentType && parentType.hasFeature('creation');
|
||||
|
||||
// Only creatable types should be modifiable
|
||||
return parent !== undefined &&
|
||||
Array.isArray(parent.getModel().composition) &&
|
||||
parentCreatable;
|
||||
};
|
||||
|
||||
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) {
|
||||
|
||||
describe("The Remove action", function () {
|
||||
var mockQ,
|
||||
mockNavigationService,
|
||||
mockDomainObject,
|
||||
mockParent,
|
||||
mockChildObject,
|
||||
mockGrandchildObject,
|
||||
mockRootObject,
|
||||
mockContext,
|
||||
mockChildContext,
|
||||
mockGrandchildContext,
|
||||
mockRootContext,
|
||||
mockMutation,
|
||||
mockType,
|
||||
var action,
|
||||
actionContext,
|
||||
model,
|
||||
capabilities,
|
||||
action;
|
||||
|
||||
function mockPromise(value) {
|
||||
return {
|
||||
then: function (callback) {
|
||||
return mockPromise(callback(value));
|
||||
}
|
||||
};
|
||||
}
|
||||
mockContext,
|
||||
mockDialogService,
|
||||
mockDomainObject,
|
||||
mockMutation,
|
||||
mockNavigationService,
|
||||
mockParent,
|
||||
mockType,
|
||||
model;
|
||||
|
||||
beforeEach(function () {
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
["getId", "getCapability"]
|
||||
["getId", "getCapability", "getModel"]
|
||||
);
|
||||
mockChildObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
["getId", "getCapability"]
|
||||
);
|
||||
mockGrandchildObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
["getId", "getCapability"]
|
||||
);
|
||||
mockRootObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
["getId", "getCapability"]
|
||||
);
|
||||
mockQ = { when: mockPromise };
|
||||
|
||||
mockMutation = jasmine.createSpyObj("mutation", ["invoke"]);
|
||||
mockType = jasmine.createSpyObj("type", ["hasFeature"]);
|
||||
mockType.hasFeature.and.returnValue(true);
|
||||
|
||||
capabilities = {
|
||||
mutation: mockMutation,
|
||||
type: mockType
|
||||
};
|
||||
|
||||
model = {
|
||||
composition: ["a", "test", "b"]
|
||||
};
|
||||
|
||||
mockParent = {
|
||||
getModel: function () {
|
||||
return model;
|
||||
@@ -80,12 +67,12 @@ define(
|
||||
return capabilities[k].invoke(v);
|
||||
}
|
||||
};
|
||||
mockContext = jasmine.createSpyObj("context", ["getParent"]);
|
||||
mockChildContext = jasmine.createSpyObj("context", ["getParent"]);
|
||||
mockGrandchildContext = jasmine.createSpyObj("context", ["getParent"]);
|
||||
mockRootContext = jasmine.createSpyObj("context", ["getParent"]);
|
||||
mockMutation = jasmine.createSpyObj("mutation", ["invoke"]);
|
||||
mockType = jasmine.createSpyObj("type", ["hasFeature"]);
|
||||
|
||||
mockDialogService = jasmine.createSpyObj(
|
||||
"dialogService",
|
||||
["showBlockingMessage"]
|
||||
);
|
||||
|
||||
mockNavigationService = jasmine.createSpyObj(
|
||||
"navigationService",
|
||||
[
|
||||
@@ -97,23 +84,19 @@ define(
|
||||
);
|
||||
mockNavigationService.getNavigation.and.returnValue(mockDomainObject);
|
||||
|
||||
mockContext = jasmine.createSpyObj("context", ["getParent"]);
|
||||
mockContext.getParent.and.returnValue(mockParent);
|
||||
|
||||
mockDomainObject.getId.and.returnValue("test");
|
||||
mockDomainObject.getCapability.and.returnValue(mockContext);
|
||||
mockDomainObject.getModel.and.returnValue({name: 'test object'});
|
||||
|
||||
mockContext.getParent.and.returnValue(mockParent);
|
||||
mockType.hasFeature.and.returnValue(true);
|
||||
|
||||
capabilities = {
|
||||
mutation: mockMutation,
|
||||
type: mockType
|
||||
};
|
||||
model = {
|
||||
composition: ["a", "test", "b"]
|
||||
};
|
||||
|
||||
actionContext = { domainObject: mockDomainObject };
|
||||
|
||||
action = new RemoveAction(mockNavigationService, actionContext);
|
||||
action = new RemoveAction(mockDialogService, mockNavigationService, actionContext);
|
||||
});
|
||||
|
||||
it("only applies to objects with parents", function () {
|
||||
@@ -127,83 +110,157 @@ define(
|
||||
expect(mockType.hasFeature).toHaveBeenCalledWith('creation');
|
||||
});
|
||||
|
||||
it("mutates the parent when performed", function () {
|
||||
action.perform();
|
||||
expect(mockMutation.invoke)
|
||||
.toHaveBeenCalledWith(jasmine.any(Function));
|
||||
});
|
||||
|
||||
it("changes composition from its mutation function", function () {
|
||||
var mutator, result;
|
||||
action.perform();
|
||||
mutator = mockMutation.invoke.calls.mostRecent().args[0];
|
||||
result = mutator(model);
|
||||
|
||||
// Should not have cancelled the mutation
|
||||
expect(result).not.toBe(false);
|
||||
|
||||
// Simulate mutate's behavior (remove can either return a
|
||||
// new model or modify this one in-place)
|
||||
result = result || model;
|
||||
|
||||
// Should have removed "test" - that was our
|
||||
// mock domain object's id.
|
||||
expect(result.composition).toEqual(["a", "b"]);
|
||||
});
|
||||
|
||||
it("removes parent of object currently navigated to", function () {
|
||||
// Navigates to child object
|
||||
mockNavigationService.getNavigation.and.returnValue(mockChildObject);
|
||||
|
||||
// Test is id of object being removed
|
||||
// Child object has different id
|
||||
mockDomainObject.getId.and.returnValue("test");
|
||||
mockChildObject.getId.and.returnValue("not test");
|
||||
|
||||
// Sets context for the child and domainObject
|
||||
mockDomainObject.getCapability.and.returnValue(mockContext);
|
||||
mockChildObject.getCapability.and.returnValue(mockChildContext);
|
||||
|
||||
// Parents of child and domainObject are set
|
||||
mockContext.getParent.and.returnValue(mockParent);
|
||||
mockChildContext.getParent.and.returnValue(mockDomainObject);
|
||||
|
||||
mockType.hasFeature.and.returnValue(true);
|
||||
it("shows a blocking message dialog", function () {
|
||||
mockParent = jasmine.createSpyObj(
|
||||
"parent",
|
||||
["getModel", "getCapability", "useCapability"]
|
||||
);
|
||||
|
||||
action.perform();
|
||||
|
||||
// Expects navigation to parent of domainObject (removed object)
|
||||
expect(mockNavigationService.setNavigation).toHaveBeenCalledWith(mockParent);
|
||||
expect(mockDialogService.showBlockingMessage).toHaveBeenCalled();
|
||||
|
||||
// Also check that no mutation happens at this point
|
||||
expect(mockParent.useCapability).not.toHaveBeenCalledWith("mutation", jasmine.any(Function));
|
||||
});
|
||||
|
||||
it("checks if removing object not in ascendent path (reaches ROOT)", function () {
|
||||
// Navigates to grandchild of ROOT
|
||||
mockNavigationService.getNavigation.and.returnValue(mockGrandchildObject);
|
||||
it("does not show a blocking message dialog when true is passed to perform", function () {
|
||||
mockParent = jasmine.createSpyObj(
|
||||
"parent",
|
||||
["getModel", "getCapability", "useCapability"]
|
||||
);
|
||||
|
||||
// domainObject (grandparent) is set as ROOT, child and grandchild
|
||||
// are set objects not being removed
|
||||
mockDomainObject.getId.and.returnValue("test 1");
|
||||
mockRootObject.getId.and.returnValue("ROOT");
|
||||
mockChildObject.getId.and.returnValue("not test 2");
|
||||
mockGrandchildObject.getId.and.returnValue("not test 3");
|
||||
action.perform(true);
|
||||
|
||||
// Sets context for the grandchild, child, and domainObject
|
||||
mockRootObject.getCapability.and.returnValue(mockRootContext);
|
||||
mockChildObject.getCapability.and.returnValue(mockChildContext);
|
||||
mockGrandchildObject.getCapability.and.returnValue(mockGrandchildContext);
|
||||
|
||||
// Parents of grandchild and child are set
|
||||
mockChildContext.getParent.and.returnValue(mockRootObject);
|
||||
mockGrandchildContext.getParent.and.returnValue(mockChildObject);
|
||||
|
||||
mockType.hasFeature.and.returnValue(true);
|
||||
|
||||
action.perform();
|
||||
|
||||
// Expects no navigation to occur
|
||||
expect(mockNavigationService.setNavigation).not.toHaveBeenCalled();
|
||||
expect(mockDialogService.showBlockingMessage).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
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 () {
|
||||
action.perform();
|
||||
mockDialogService.showBlockingMessage.calls.mostRecent().args[0]
|
||||
.primaryOption.callback();
|
||||
|
||||
expect(mockMutation.invoke)
|
||||
.toHaveBeenCalledWith(jasmine.any(Function));
|
||||
});
|
||||
|
||||
it("changes composition from its mutation function", function () {
|
||||
var mutator, result;
|
||||
|
||||
action.perform();
|
||||
mockDialogService.showBlockingMessage.calls.mostRecent().args[0]
|
||||
.primaryOption.callback();
|
||||
|
||||
mutator = mockMutation.invoke.calls.mostRecent().args[0];
|
||||
result = mutator(model);
|
||||
|
||||
// Should not have cancelled the mutation
|
||||
expect(result).not.toBe(false);
|
||||
|
||||
// Simulate mutate's behavior (remove can either return a
|
||||
// new model or modify this one in-place)
|
||||
result = result || model;
|
||||
|
||||
// Should have removed "test" - that was our
|
||||
// mock domain object's id.
|
||||
expect(result.composition).toEqual(["a", "b"]);
|
||||
});
|
||||
|
||||
it("removes parent of object currently navigated to", function () {
|
||||
// Navigates to child object
|
||||
mockNavigationService.getNavigation.and.returnValue(mockChildObject);
|
||||
|
||||
// Test is id of object being removed
|
||||
// Child object has different id
|
||||
mockDomainObject.getId.and.returnValue("test");
|
||||
mockChildObject.getId.and.returnValue("not test");
|
||||
|
||||
// Sets context for the child and domainObject
|
||||
mockDomainObject.getCapability.and.returnValue(mockContext);
|
||||
mockChildObject.getCapability.and.returnValue(mockChildContext);
|
||||
|
||||
// Parents of child and domainObject are set
|
||||
mockContext.getParent.and.returnValue(mockParent);
|
||||
mockChildContext.getParent.and.returnValue(mockDomainObject);
|
||||
|
||||
mockType.hasFeature.and.returnValue(true);
|
||||
|
||||
action.perform();
|
||||
mockDialogService.showBlockingMessage.calls.mostRecent().args[0]
|
||||
.primaryOption.callback();
|
||||
|
||||
// Expects navigation to parent of domainObject (removed object)
|
||||
expect(mockNavigationService.setNavigation).toHaveBeenCalledWith(mockParent);
|
||||
});
|
||||
|
||||
it("checks if removing object not in ascendent path (reaches ROOT)", function () {
|
||||
// Navigates to grandchild of ROOT
|
||||
mockNavigationService.getNavigation.and.returnValue(mockGrandchildObject);
|
||||
|
||||
// domainObject (grandparent) is set as ROOT, child and grandchild
|
||||
// are set objects not being removed
|
||||
mockDomainObject.getId.and.returnValue("test 1");
|
||||
mockRootObject.getId.and.returnValue("ROOT");
|
||||
mockChildObject.getId.and.returnValue("not test 2");
|
||||
mockGrandchildObject.getId.and.returnValue("not test 3");
|
||||
|
||||
// Sets context for the grandchild, child, and domainObject
|
||||
mockRootObject.getCapability.and.returnValue(mockRootContext);
|
||||
mockChildObject.getCapability.and.returnValue(mockChildContext);
|
||||
mockGrandchildObject.getCapability.and.returnValue(mockGrandchildContext);
|
||||
|
||||
// Parents of grandchild and child are set
|
||||
mockChildContext.getParent.and.returnValue(mockRootObject);
|
||||
mockGrandchildContext.getParent.and.returnValue(mockChildObject);
|
||||
|
||||
mockType.hasFeature.and.returnValue(true);
|
||||
|
||||
action.perform();
|
||||
mockDialogService.showBlockingMessage.calls.mostRecent().args[0]
|
||||
.primaryOption.callback();
|
||||
|
||||
// Expects no navigation to occur
|
||||
expect(mockNavigationService.setNavigation).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -102,14 +102,14 @@ define(
|
||||
* @returns {Action[]} an array of matching actions
|
||||
* @memberof platform/core.ActionCapability#
|
||||
*/
|
||||
ActionCapability.prototype.perform = function (context) {
|
||||
ActionCapability.prototype.perform = function (context, flag) {
|
||||
// Alias to getActions(context)[0].perform, with a
|
||||
// check for empty arrays.
|
||||
var actions = this.getActions(context);
|
||||
|
||||
return this.$q.when(
|
||||
(actions && actions.length > 0) ?
|
||||
actions[0].perform() :
|
||||
actions[0].perform(flag) :
|
||||
undefined
|
||||
);
|
||||
};
|
||||
|
||||
@@ -92,7 +92,7 @@ define(
|
||||
.then(function () {
|
||||
return object
|
||||
.getCapability('action')
|
||||
.perform('remove');
|
||||
.perform('remove', true);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -224,10 +224,11 @@ define(
|
||||
locationPromise.resolve();
|
||||
});
|
||||
|
||||
it("removes object from parent", function () {
|
||||
it("removes object from parent without user warning dialog", function () {
|
||||
expect(actionCapability.perform)
|
||||
.toHaveBeenCalledWith('remove');
|
||||
.toHaveBeenCalledWith('remove', true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -244,9 +245,9 @@ define(
|
||||
.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("removes object from parent", function () {
|
||||
it("removes object from parent without user warning dialog", function () {
|
||||
expect(actionCapability.perform)
|
||||
.toHaveBeenCalledWith('remove');
|
||||
.toHaveBeenCalledWith('remove', true);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -87,7 +87,8 @@ define(
|
||||
'setDisplayedValue',
|
||||
'subscribeToObject',
|
||||
'unsubscribe',
|
||||
'updateView'
|
||||
'updateView',
|
||||
'setSelection'
|
||||
].forEach(function (name) {
|
||||
self[name] = self[name].bind(self);
|
||||
});
|
||||
@@ -224,7 +225,7 @@ define(
|
||||
// Respond to external bounds changes
|
||||
this.openmct.time.on("bounds", updateDisplayBounds);
|
||||
|
||||
this.openmct.selection.on('change', this.setSelection.bind(this));
|
||||
this.openmct.selection.on('change', this.setSelection);
|
||||
this.$element.on('click', this.bypassSelection.bind(this));
|
||||
this.unlisten = this.openmct.objects.observe(this.newDomainObject, '*', function (obj) {
|
||||
this.newDomainObject = JSON.parse(JSON.stringify(obj));
|
||||
@@ -233,6 +234,9 @@ define(
|
||||
|
||||
this.updateElementPositions(this.newDomainObject.layoutGrid);
|
||||
refreshElements();
|
||||
|
||||
//force a click, to initialize Fixed Position Controller on SelectionAPI
|
||||
$element[0].click();
|
||||
}
|
||||
|
||||
FixedController.prototype.updateElementPositions = function (layoutGrid) {
|
||||
|
||||
@@ -35,28 +35,30 @@ mct-table {
|
||||
}
|
||||
|
||||
.mct-table {
|
||||
tr {
|
||||
display: flex; // flex-flow defaults to row nowrap (which is what we want) so no need to define
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
td, th {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
flex: 1 0 auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
thead {
|
||||
display: block;
|
||||
tr {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
th {
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tbody {
|
||||
tr {
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
display: block;
|
||||
height: 18px; // Needed when a row has empty values in its cells
|
||||
}
|
||||
|
||||
td {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ define(['lodash'], function (_) {
|
||||
copyOfChild.location = parentId;
|
||||
parent.composition[index] = copyOfChild.identifier;
|
||||
this.tree[newIdString] = copyOfChild;
|
||||
this.tree[parentId].composition[index] = newIdString;
|
||||
this.tree[parentId].composition[index] = copyOfChild.identifier;
|
||||
|
||||
return copyOfChild;
|
||||
};
|
||||
|
||||
@@ -79,16 +79,18 @@ define(['zepto'], function ($) {
|
||||
var parentModel = parent.getModel();
|
||||
var newObj;
|
||||
|
||||
seen.push(parent.getId());
|
||||
seen.push(this.getKeyString(parent.getId()));
|
||||
parentModel.composition.forEach(function (childId, index) {
|
||||
if (!tree[childId] || seen.includes(childId)) {
|
||||
var childIdString = this.getKeyString(childId);
|
||||
if (!tree[childIdString] || seen.includes(childIdString)) {
|
||||
return;
|
||||
}
|
||||
|
||||
newObj = this.instantiate(tree[childId], childId);
|
||||
parent.getCapability("composition").add(newObj);
|
||||
newObj.getCapability("location")
|
||||
.setPrimaryLocation(tree[childId].location);
|
||||
newObj = this.instantiate(tree[childIdString], childIdString);
|
||||
// New object has not been persisted yet so clear persisted
|
||||
// timestamp from copied model.
|
||||
delete newObj.getModel().persisted;
|
||||
newObj.getCapability('persistence').persist();
|
||||
this.deepInstantiate(newObj, tree, seen);
|
||||
}, this);
|
||||
}
|
||||
@@ -103,6 +105,10 @@ define(['zepto'], function ($) {
|
||||
return tree;
|
||||
};
|
||||
|
||||
ImportAsJSONAction.prototype.getKeyString = function (identifier) {
|
||||
return this.openmct.objects.makeKeyString(identifier);
|
||||
};
|
||||
|
||||
/**
|
||||
* Rewrites all instances of a given id in the tree with a newly generated
|
||||
* replacement to prevent collision.
|
||||
|
||||
@@ -47,7 +47,12 @@ define(
|
||||
uniqueId = 0;
|
||||
newObjects = [];
|
||||
openmct = {
|
||||
$injector: jasmine.createSpyObj('$injector', ['get'])
|
||||
$injector: jasmine.createSpyObj('$injector', ['get']),
|
||||
objects: {
|
||||
makeKeyString: function (identifier) {
|
||||
return identifier.key;
|
||||
}
|
||||
}
|
||||
};
|
||||
mockInstantiate = jasmine.createSpy('instantiate').and.callFake(
|
||||
function (model, id) {
|
||||
@@ -154,7 +159,7 @@ define(
|
||||
body: JSON.stringify({
|
||||
"openmct": {
|
||||
"infiniteParent": {
|
||||
"composition": ["infinteChild"],
|
||||
"composition": [{key: "infinteChild", namespace: ""}],
|
||||
"name": "1",
|
||||
"type": "folder",
|
||||
"modified": 1503598129176,
|
||||
@@ -162,7 +167,7 @@ define(
|
||||
"persisted": 1503598129176
|
||||
},
|
||||
"infinteChild": {
|
||||
"composition": ["infiniteParent"],
|
||||
"composition": [{key: "infinteParent", namespace: ""}],
|
||||
"name": "2",
|
||||
"type": "folder",
|
||||
"modified": 1503598132428,
|
||||
|
||||
@@ -83,6 +83,7 @@ define([
|
||||
|
||||
this.listenTo(this, 'change:xKey', this.onXKeyChange, this);
|
||||
this.listenTo(this, 'change:yKey', this.onYKeyChange, this);
|
||||
this.persistedConfig = options.persistedConfig;
|
||||
|
||||
Model.apply(this, arguments);
|
||||
this.onXKeyChange(this.get('xKey'));
|
||||
@@ -176,8 +177,7 @@ define([
|
||||
return;
|
||||
}
|
||||
var valueMetadata = this.metadata.value(newKey);
|
||||
var persistedConfig = this.get('persistedConfiguration');
|
||||
if (!persistedConfig || !persistedConfig.interpolate) {
|
||||
if (!this.persistedConfig || !this.persistedConfig.interpolate) {
|
||||
if (valueMetadata.format === 'enum') {
|
||||
this.set('interpolate', 'stepAfter');
|
||||
} else {
|
||||
|
||||
@@ -54,7 +54,7 @@ define([
|
||||
domainObject.configuration.series.forEach(function (seriesConfig) {
|
||||
var series = this.byIdentifier(seriesConfig.identifier);
|
||||
if (series) {
|
||||
series.set('persistedConfiguration', seriesConfig);
|
||||
series.persistedConfig = seriesConfig;
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
@@ -90,7 +90,9 @@ define([
|
||||
model: seriesConfig,
|
||||
domainObject: domainObject,
|
||||
collection: this,
|
||||
openmct: this.openmct
|
||||
openmct: this.openmct,
|
||||
persistedConfig: this.plot
|
||||
.getPersistedSeriesConfig(domainObject.identifier)
|
||||
}));
|
||||
},
|
||||
removeTelemetryObject: function (identifier) {
|
||||
|
||||
@@ -45,6 +45,7 @@ define([
|
||||
|
||||
PlotOptionsController.prototype.updateDomainObject = function (domainObject) {
|
||||
this.domainObject = domainObject;
|
||||
this.$scope.formDomainObject = domainObject;
|
||||
};
|
||||
|
||||
PlotOptionsController.prototype.destroy = function () {
|
||||
@@ -63,8 +64,7 @@ define([
|
||||
this.config = this.$scope.config = config;
|
||||
this.$scope.plotSeries = [];
|
||||
|
||||
this.domainObject = this.config.get('domainObject');
|
||||
this.$scope.formDomainObject = this.domainObject;
|
||||
this.updateDomainObject(this.config.get('domainObject'));
|
||||
this.unlisten = this.openmct.objects.observe(this.domainObject, '*', this.updateDomainObject.bind(this));
|
||||
|
||||
this.listenTo(this.$scope, '$destroy', this.destroy, this);
|
||||
|
||||
@@ -181,7 +181,9 @@ define([
|
||||
};
|
||||
this.config.xAxis.set('range', newRange);
|
||||
if (!isTick) {
|
||||
this.skipReloadOnInteraction = true;
|
||||
this.$scope.$broadcast('plot:clearHistory');
|
||||
this.skipReloadOnInteraction = false;
|
||||
this.loadMoreData(newRange, true);
|
||||
} else {
|
||||
// Drop any data that is more than 1x (max-min) before min.
|
||||
@@ -234,7 +236,9 @@ define([
|
||||
var xDisplayRange = this.config.xAxis.get('displayRange');
|
||||
var xRange = this.config.xAxis.get('range');
|
||||
|
||||
this.loadMoreData(xDisplayRange);
|
||||
if (!this.skipReloadOnInteraction) {
|
||||
this.loadMoreData(xDisplayRange);
|
||||
}
|
||||
|
||||
this.synchronized(xRange.min === xDisplayRange.min &&
|
||||
xRange.max === xDisplayRange.max);
|
||||
|
||||
10
test-main.js
10
test-main.js
@@ -67,14 +67,14 @@ requirejs.config({
|
||||
"lodash": "bower_components/lodash/lodash",
|
||||
"d3-selection": "node_modules/d3-selection/dist/d3-selection.min",
|
||||
"d3-scale": "node_modules/d3-scale/build/d3-scale.min",
|
||||
"d3-axis": "node_modules/d3-axis/build/d3-axis.min",
|
||||
"d3-array": "node_modules/d3-array/build/d3-array.min",
|
||||
"d3-collection": "node_modules/d3-collection/build/d3-collection.min",
|
||||
"d3-axis": "node_modules/d3-axis/dist/d3-axis.min",
|
||||
"d3-array": "node_modules/d3-array/dist/d3-array.min",
|
||||
"d3-collection": "node_modules/d3-collection/dist/d3-collection.min",
|
||||
"d3-color": "node_modules/d3-color/build/d3-color.min",
|
||||
"d3-format": "node_modules/d3-format/build/d3-format.min",
|
||||
"d3-interpolate": "node_modules/d3-interpolate/build/d3-interpolate.min",
|
||||
"d3-time": "node_modules/d3-time/build/d3-time.min",
|
||||
"d3-time-format": "node_modules/d3-time-format/build/d3-time-format.min",
|
||||
"d3-time": "node_modules/d3-time/dist/d3-time.min",
|
||||
"d3-time-format": "node_modules/d3-time-format/dist/d3-time-format.min",
|
||||
"html2canvas": "node_modules/html2canvas/dist/html2canvas.min",
|
||||
"painterro": "node_modules/painterro/build/painterro.min",
|
||||
"printj": "node_modules/printj/dist/printj.min"
|
||||
|
||||
Reference in New Issue
Block a user