Compare commits

...

14 Commits

Author SHA1 Message Date
Julie Wang
a53a669154 Addressed additional style errors. 2018-09-04 08:46:53 -04:00
Julie Wang
0602613b6e Addressed lint style issues. 2018-08-09 22:55:59 -07:00
Julie Wang
7620432388 Updated whitespace. 2018-08-09 22:10:43 -07:00
Julie Wang
fc8663c049 Reverted unecessary whitespace change. 2018-08-09 21:50:40 -07:00
Julie Wang
adfe30a891 Added comments to clarify code. 2018-08-09 21:15:54 -07:00
Wang
5218e350c3 Updates tests in locator controller. 2018-08-09 17:32:28 -07:00
Julie Wang
88615e92d2 Added tests for new folder action and locator controller. 2018-08-09 16:40:00 -07:00
Julie Wang
12477a220b testing new implementation. 2018-08-06 22:31:23 -07:00
Deep Tailor
9582fb2b06 Merge pull request #2137 from nasa/prevent-plot-accidental-remove
[Plot] Update formDomainObject on mutate
2018-07-31 12:44:51 -07:00
Pete Richards
3c075b7ff2 [Plot] pass persisted config in constructor
When a plot series is constructed, it checks to see if should set a
default interpolation based on the persisted configuration.  However,
the persisted configuration wasn't available until after construction
which resulted in the default value always being set.

Pass the persisted configuration through the constructor to ensure the
plot series can make the right decision about defaults.

Fixes #2120.
2018-07-31 12:33:10 -07:00
Deep Tailor
081edfbd70 Merge pull request #2127 from nasa/plot-requests-2126
[Plot] Prevent duplicate query on bounds change
2018-07-31 12:32:57 -07:00
Pete Richards
04cc8f7aa2 [Plot] Update formDomainObject on mutate
When a new series is added to a plot, a plot series form controller
is instantiated and passed in a domain object via scope that it will
mutate upon changes.  If a mutation results in a composition add, then
the plot series form controller needs to get a version of the domain
object with the updated composition array, which it was not previously
doing.

This fixes #2120.
2018-07-31 12:03:49 -07:00
tobiasbrown
a1d206bfc3 [Remove] Add confirmation dialog (#1870)
* [Remove] Added confirmation dialog before the remove action is performed

Addresses #563
2018-07-27 13:54:41 -07:00
Pete Richards
ef9c6d5fed [Plot] Prevent duplicate query on bounds change
Bounds change triggers a clearing of plot history, which triggers
a user interaction change, which was triggering a second query.

This change sets a flag to prevent the requery from the user interaction on
bounds change.  This flag could potentially be reused elsewhere, e.g. if we
wanted to prevent requery when not utilizing a minmax data source.

fixes #2126
2018-07-25 11:44:14 -07:00
14 changed files with 776 additions and 232 deletions

View File

@@ -33,6 +33,7 @@ define([
"./src/actions/SaveAndStopEditingAction",
"./src/actions/SaveAsAction",
"./src/actions/CancelAction",
"./src/actions/CreateNewFolderAction",
"./src/policies/EditActionPolicy",
"./src/policies/EditPersistableObjectsPolicy",
"./src/policies/EditableLinkPolicy",
@@ -71,6 +72,7 @@ define([
SaveAndStopEditingAction,
SaveAsAction,
CancelAction,
CreateNewFolderAction,
EditActionPolicy,
EditPersistableObjectsPolicy,
EditableLinkPolicy,
@@ -145,7 +147,10 @@ define([
"depends": [
"$scope",
"$timeout",
"objectService"
"objectService",
"typeService",
"policyService",
"instantiate"
]
}
],
@@ -188,6 +193,7 @@ define([
"name": "Remove",
"description": "Remove this object from its containing object.",
"depends": [
"dialogService",
"navigationService"
]
},
@@ -241,6 +247,14 @@ define([
"cssClass": "icon-x no-label",
"description": "Discard changes made to these objects.",
"depends": []
},
{
"key": "create-new-folder",
"implementation": CreateNewFolderAction,
"description": "Creates a new folder.",
"depends": [
"typeService"
]
}
],
"policies": [

View File

@@ -0,0 +1,33 @@
<!--span
Open MCT, Copyright (c) 2014-2018, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT is licensed under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Open MCT includes source code licensed under additional open source
licenses. See the Open Source Licenses file (LICENSES.md) included with
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div name="newFolder" ng-controller="LocatorController">
<div ng-if="!createNewFolder">
<a class="s-button icon-folder-new" ng-click="createNewFolderClickHandler()" >
<span class="title-label">New Folder</span>
</a>
</div>
<div ng-if="createNewFolder">
<span><input type="text" ng-model="newFolderName" name="newFolderName"></span>
<a class="s-button" ng-click="createClickHandler()">Create</a>
<a class="s-button icon-x" ng-click="cancelClickHandler()"></a>
</div>
</div>

View File

@@ -1,5 +1,5 @@
<!--
Open MCT, Copyright (c) 2014-2018, United States Government
Open MCT, Copyright (c) 2014-2017, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
@@ -26,4 +26,22 @@
ng-model="treeModel">
</mct-representation>
</div>
<!-- Create New Folder Action -->
<div class="newFolderCreation" style="margin-top:10px; position:absolute; left:0px;">
<!-- New folder button, triggers create new folder action. -->
<div ng-show="!newFolderCreationTriggered">
<a class="s-button icon-folder-new" ng-class="{disabled: !validParent()}" ng-click="newFolderButtonClickHandler()">
<span class="text-label">New Folder</span>
</a>
</div>
<!-- Get folder name -->
<div ng-show="newFolderCreationTriggered">
<input type="text" ng-model="newFolderNameInput">
<a class="s-button" ng-class="{ disabled: !validParent() || !validFolderName() }" ng-click="newFolderCreateButtonClickHandler()">Create</a>
<a class="s-button icon-x" ng-click="newFolderCancelButtonClickHandler()"></a>
</div>
</div>
</div>

View File

@@ -0,0 +1,89 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([
],
function (
) {
/**
* The CreateNewFolderAction; action is triggered by the new folder button in the locator.
*
* @constructor
* @implements {Action}
* @memberof platform/commonUI/edit
*/
function CreateNewFolderAction(
typeService,
context
) {
this.parent = (context || {}).domainObject;
this.typeService = typeService;
this.type = typeService.getType('folder');
}
CreateNewFolderAction.prototype.perform = function (folderName) {
var parent = this.parent,
typeService = this.typeService,
newModel = this.type.getInitialModel(),
folderType = typeService.getType('folder');
newModel.type = folderType.getKey();
newModel.name = folderName;
function instantiateObject() {
var newObject = parent.useCapability('instantiation', newModel);
newObject.useCapability('mutation', function () {
newModel.location = parent.getId();
});
return addToParentAndReturn(newObject);
}
function addToParentAndReturn(newObject) {
return parent.getCapability('composition').add(newObject)
.then(function () {
return newObject;
});
}
return instantiateObject(newModel, parent);
};
/**
* Check if this action is applicable in a given context.
* This will ensure that a domain object is present in the context,
* and that this domain object is in Edit mode.
* @returns true if applicable
*/
CreateNewFolderAction.appliesTo = function (context) {
var parent = (context || {}).domainObject;
return parent && parent.hasCapability('editor');
};
return CreateNewFolderAction;
}
);

View File

@@ -23,9 +23,11 @@
/**
* 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.
@@ -33,25 +35,27 @@ define(
* 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 {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(navigationService, context) {
function RemoveAction(dialogService, navigationService, context) {
this.domainObject = (context || {}).domainObject;
this.dialogService = dialogService;
this.navigationService = navigationService;
}
/**
* Perform this action.
* @return {Promise} a promise which will be
* fulfilled when the action has completed.
*/
RemoveAction.prototype.perform = function () {
var navigationService = this.navigationService,
domainObject = this.domainObject;
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
@@ -111,7 +115,12 @@ define(
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
@@ -129,5 +138,4 @@ define(
};
return RemoveAction;
}
);
});

View 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;
});

View File

@@ -1,5 +1,5 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
@@ -31,7 +31,7 @@ define(
* @memberof platform/commonUI/browse
* @constructor
*/
function LocatorController($scope, $timeout, objectService) {
function LocatorController($scope, $timeout, objectService, typeService, policyService, instantiate) {
// Populate values needed by the locator control. These are:
// * rootObject: The top-level object, since we want to show
// the full tree
@@ -81,11 +81,64 @@ define(
!!$scope.treeModel.selectedObject
);
}
// Check if create new folder is a valid action for selected object
$scope.validParent = function () {
if ($scope.treeModel.selectedObject) {
return policyService.allow(
"composition",
$scope.treeModel.selectedObject,
instantiate(typeService.getType('folder').getInitialModel())
);
} else {
return false;
}
};
}
$scope.newFolderButtonClickHandler = function () {
$scope.newFolderCreationTriggered = true;
};
$scope.newFolderCancelButtonClickHandler = function () {
$scope.newFolderCreationTriggered = false;
resetNewFolderNameInput();
};
// Get expected input pattern for folder name
var folderNamePattern = new RegExp(
typeService.getType('folder').getProperties()[0].propertyDefinition.pattern
);
// Validate folder name externally to avoid affecting overall form validation
$scope.validFolderName = function () {
return $scope.newFolderNameInput && folderNamePattern.test($scope.newFolderNameInput);
};
function selectAndScrollToNewFolder(newFolder) {
$scope.treeModel.selectedObject = newFolder;
}
function resetNewFolderNameInput() {
$scope.newFolderNameInput = "Unnamed Folder";
$scope.newFolderCreationTriggered = false;
}
// Create new folder, update selection to new folder and reset new folder button
$scope.newFolderCreateButtonClickHandler = function () {
var createNewFolderAction = $scope.treeModel.selectedObject.getCapability('action').getActions('create-new-folder')[0];
createNewFolderAction.perform($scope.newFolderNameInput)
.then(selectAndScrollToNewFolder)
.then(resetNewFolderNameInput);
};
// Initial state for the tree's model
$scope.treeModel =
{ selectedObject: $scope.ngModel[$scope.field] };
$scope.treeModel = { selectedObject: $scope.ngModel[$scope.field] };
//Initial values for new folder action
$scope.newFolderNameInput = "Unnamed Folder";
$scope.newFolderCreationTriggered = false;
// Watch for changes from the tree
$scope.$watch("treeModel.selectedObject", setLocatingObject);

View File

@@ -0,0 +1,117 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
['../../src/actions/CreateNewFolderAction'],
function (CreateNewFolderAction) {
describe("The Create New Folder Action", function () {
var mockDomainObject,
mockNewObject,
mockType,
testModel,
mockFolderName,
mockTypeService,
mockActionContext,
mockCompositionCapability,
action;
function mockPromise(value) {
return (value && value.then) ? value : {
then: function (callback) {
return mockPromise(callback(value));
}
};
}
beforeEach(function () {
mockDomainObject = jasmine.createSpyObj(
"domainObject",
[
"getCapability",
"useCapability",
"hasCapability",
"getId"
]
);
mockNewObject = jasmine.createSpyObj(
"newObject",
[
"getCapability",
"useCapability",
"hasCapability",
"getId"
]
);
mockType = jasmine.createSpyObj(
"type",
[
"getKey",
"getInitialModel"
]
);
testModel = {
type: mockType,
name: "Name",
location: "someLocation"
};
mockFolderName = "Name";
mockTypeService = jasmine.createSpyObj(
"typeService",
["getType"]
);
mockActionContext = { domainObject: mockDomainObject };
mockCompositionCapability = jasmine.createSpyObj(
"composition",
["add"]
);
mockType.getKey.and.returnValue("test");
mockType.getInitialModel.and.returnValue(testModel);
mockDomainObject.getCapability.and.callFake(function (capability) {
return (capability === 'composition') && mockCompositionCapability;
});
mockDomainObject.hasCapability.and.returnValue(true);
mockCompositionCapability.add.and.returnValue(mockPromise(true));
mockDomainObject.useCapability.and.callFake(function (capability) {
return (capability === 'instantiation') && mockNewObject;
});
mockTypeService.getType.and.returnValue(mockType);
mockDomainObject.getId.and.returnValue("id");
action = new CreateNewFolderAction(mockTypeService, mockActionContext);
});
it("uses the instantiation capability when performed", function () {
action.perform(mockFolderName);
expect(mockDomainObject.useCapability)
.toHaveBeenCalledWith("instantiation", jasmine.any(Object));
});
it("adds new objects to the parent's composition", function () {
action.perform(mockFolderName);
expect(mockDomainObject.getCapability).toHaveBeenCalledWith("composition");
expect(mockCompositionCapability.add).toHaveBeenCalled();
});
it("is only applicable when a domain object is in context", function () {
expect(CreateNewFolderAction.appliesTo(mockActionContext)).toBeTruthy();
expect(CreateNewFolderAction.appliesTo({})).toBeFalsy();
expect(mockDomainObject.hasCapability).toHaveBeenCalledWith('editor');
});
});
}
);

View File

@@ -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,15 +110,73 @@ define(
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 () {
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);
@@ -171,6 +212,8 @@ define(
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);
@@ -199,11 +242,14 @@ define(
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();
});
});
});
}
);

View File

@@ -31,26 +31,63 @@ define(
var mockScope,
mockTimeout,
mockDomainObject,
mockFolderObject,
mockRootObject,
mockContext,
mockActions,
mockObjectService,
mockTypeService,
mockType,
mockInstantiate,
mockPolicyService,
getObjectsPromise,
testModel,
capabilities,
mockCreateNewFolderAction,
mockActionCapability,
mockProperties,
controller;
beforeEach(function () {
mockScope = jasmine.createSpyObj(
"$scope",
["$watch"]
["$watch", "validParent"]
);
mockTimeout = jasmine.createSpy("$timeout");
mockInstantiate = jasmine.createSpy("instantiate");
mockDomainObject = jasmine.createSpyObj(
"domainObject",
["getCapability"]
[
"useCapability",
"getModel",
"getCapability"
]
);
mockFolderObject = jasmine.createSpyObj(
"folderObject",
[
"useCapability",
"getModel",
"getCapability"
]
);
mockCreateNewFolderAction = jasmine.createSpyObj(
"createNewFolderAction",
[
"perform"
]
);
mockRootObject = jasmine.createSpyObj(
"rootObject",
["getCapability"]
);
mockActionCapability = jasmine.createSpyObj(
"actionCapability",
[
"getActions",
"perform"
]
);
mockContext = jasmine.createSpyObj(
"context",
["getRoot"]
@@ -59,25 +96,70 @@ define(
"objectService",
["getObjects"]
);
mockTypeService = jasmine.createSpyObj(
"typeService",
["getType"]
);
mockPolicyService = jasmine.createSpyObj(
"policyService",
["allow"]
);
getObjectsPromise = jasmine.createSpyObj(
"promise",
["then"]
);
mockDomainObject.getCapability.and.returnValue(mockContext);
mockType = jasmine.createSpyObj(
"type",
[
"getKey",
"getProperties",
"getInitialModel"
]
);
testModel = { someKey: "some value" };
mockProperties = ['a', 'b', 'c'].map(function (k) {
var mockProperty = jasmine.createSpyObj(
'property-' + k,
['propertyDefinition']
);
mockProperty.propertyDefinition = {
key: "name",
pattern: "test"
};
return mockProperty;
});
capabilities = {
"action" : mockActionCapability,
"context": mockContext
};
mockActions = [mockCreateNewFolderAction];
mockContext.getRoot.and.returnValue(mockRootObject);
mockObjectService.getObjects.and.returnValue(getObjectsPromise);
mockTypeService.getType.and.callFake(function (typename) {
return mockType;
});
mockInstantiate.and.returnValue(mockFolderObject);
mockType.getKey.and.returnValue("test");
mockType.getInitialModel.and.returnValue(testModel);
mockType.getProperties.and.returnValue(mockProperties);
mockDomainObject.getCapability.and.callFake(function (capability) {
return capabilities[capability];
});
mockDomainObject.useCapability.and.returnValue();
mockDomainObject.getModel.and.returnValue(testModel);
mockFolderObject.getCapability.and.returnValue(capabilities);
mockFolderObject.useCapability.and.returnValue();
mockFolderObject.getModel.and.returnValue(testModel);
mockScope.ngModel = {};
mockScope.field = "someField";
controller = new LocatorController(mockScope, mockTimeout, mockObjectService);
controller = new LocatorController(mockScope, mockTimeout, mockObjectService, mockTypeService, mockPolicyService, mockInstantiate);
});
describe("when context is available", function () {
beforeEach(function () {
mockContext.getRoot.and.returnValue(mockRootObject);
controller = new LocatorController(mockScope, mockTimeout, mockObjectService);
controller = new LocatorController(mockScope, mockTimeout, mockObjectService, mockTypeService, mockPolicyService, mockInstantiate);
});
it("adds a treeModel to scope", function () {
@@ -145,7 +227,7 @@ define(
getObjectsPromise.then.and.callFake(function (callback) {
callback({'ROOT': defaultRoot});
});
controller = new LocatorController(mockScope, mockTimeout, mockObjectService);
controller = new LocatorController(mockScope, mockTimeout, mockObjectService, mockTypeService, mockPolicyService, mockInstantiate);
});
it("provides a default context where none is available", function () {
@@ -169,3 +251,4 @@ define(
});
}
);

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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');
if (!this.skipReloadOnInteraction) {
this.loadMoreData(xDisplayRange);
}
this.synchronized(xRange.min === xDisplayRange.min &&
xRange.max === xDisplayRange.max);