topic-form-refactor (#4478)

* Form refactor (#3816)
* New form API and associated form controls
* Actions updated to use new form API.

Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov>
Co-authored-by: charlesh88 <charles.f.hacskaylo@nasa.gov>

* Reimplementation of import export json (#4171)

Co-authored-by: Jamie V <jamie.j.vigliotta@nasa.gov>
Co-authored-by: charlesh88 <charles.f.hacskaylo@nasa.gov>
Co-authored-by: Henry Hsu <hhsu0219@gmail.com>
Co-authored-by: Andrew Henry <akhenry@gmail.com>
This commit is contained in:
Nikhil
2021-12-07 12:27:23 -08:00
committed by GitHub
parent e20c7a17d6
commit 8acbcadd5d
126 changed files with 3275 additions and 6954 deletions

View File

@@ -26,22 +26,12 @@ define([
"./src/controllers/EditObjectController",
"./src/actions/EditAndComposeAction",
"./src/actions/EditAction",
"./src/actions/PropertiesAction",
"./src/actions/SaveAction",
"./src/actions/SaveAndStopEditingAction",
"./src/actions/SaveAsAction",
"./src/actions/CancelAction",
"./src/policies/EditPersistableObjectsPolicy",
"./src/representers/EditRepresenter",
"./src/capabilities/EditorCapability",
"./src/creation/CreateMenuController",
"./src/creation/LocatorController",
"./src/creation/CreationPolicy",
"./src/creation/CreateActionProvider",
"./src/creation/CreationService",
"./res/templates/create/locator.html",
"./res/templates/create/create-button.html",
"./res/templates/create/create-menu.html",
"./res/templates/library.html",
"./res/templates/edit-object.html",
"./res/templates/edit-action-buttons.html",
@@ -52,22 +42,12 @@ define([
EditObjectController,
EditAndComposeAction,
EditAction,
PropertiesAction,
SaveAction,
SaveAndStopEditingAction,
SaveAsAction,
CancelAction,
EditPersistableObjectsPolicy,
EditRepresenter,
EditorCapability,
CreateMenuController,
LocatorController,
CreationPolicy,
CreateActionProvider,
CreationService,
locatorTemplate,
createButtonTemplate,
createMenuTemplate,
libraryTemplate,
editObjectTemplate,
editActionButtonsTemplate,
@@ -100,22 +80,6 @@ define([
"$location",
"navigationService"
]
},
{
"key": "CreateMenuController",
"implementation": CreateMenuController,
"depends": [
"$scope"
]
},
{
"key": "LocatorController",
"implementation": LocatorController,
"depends": [
"$scope",
"$timeout",
"objectService"
]
}
],
"actions": [
@@ -137,22 +101,6 @@ define([
"group": "action",
"priority": 10
},
{
"key": "properties",
"category": [
"contextual",
"view-control"
],
"implementation": PropertiesAction,
"cssClass": "major icon-pencil",
"name": "Edit Properties...",
"group": "action",
"priority": 10,
"description": "Edit properties of this object.",
"depends": [
"dialogService"
]
},
{
"key": "save-and-stop-editing",
"category": "save",
@@ -177,22 +125,6 @@ define([
"notificationService"
]
},
{
"key": "save-as",
"category": "save",
"implementation": SaveAsAction,
"name": "Save As...",
"cssClass": "icon-save labeled",
"description": "Save changes made to these objects.",
"depends": [
"$injector",
"dialogService",
"copyService",
"notificationService",
"openmct"
],
"priority": "mandatory"
},
{
"key": "cancel",
"category": "conclude-editing",
@@ -210,10 +142,6 @@ define([
"category": "action",
"implementation": EditPersistableObjectsPolicy,
"depends": ["openmct"]
},
{
"implementation": CreationPolicy,
"category": "creation"
}
],
"templates": [
@@ -243,42 +171,8 @@ define([
{
"key": "topbar-edit",
"template": topbarEditTemplate
},
{
"key": "create-button",
"template": createButtonTemplate
},
{
"key": "create-menu",
"template": createMenuTemplate,
"uses": [
"action"
]
}
],
"components": [
{
"key": "CreateActionProvider",
"provides": "actionService",
"type": "provider",
"implementation": CreateActionProvider,
"depends": [
"typeService",
"policyService"
]
},
{
"key": "CreationService",
"provides": "creationService",
"type": "provider",
"implementation": CreationService,
"depends": [
"$q",
"$log"
]
}
],
"representers": [
{
"implementation": EditRepresenter,
@@ -298,12 +192,6 @@ define([
]
}
],
"controls": [
{
"key": "locator",
"template": locatorTemplate
}
],
"runs": [
{
depends: [

View File

@@ -1,30 +0,0 @@
<!--
Open MCT, Copyright (c) 2014-2021, 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.
-->
<span ng-controller="ClickAwayController as createController">
<div class="s-menu-button major create-button" ng-click="createController.toggle()">
<span class="title-label">Create</span>
</div>
<div class="menu super-menu l-create-menu" ng-show="createController.isActive()">
<mct-representation mct-object="domainObject" key="'create-menu'">
</mct-representation>
</div>
</span>

View File

@@ -1,45 +0,0 @@
<!--
Open MCT, Copyright (c) 2014-2021, 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 class="w-menu" ng-controller="CreateMenuController">
<div class="col menu-items">
<ul>
<li ng-repeat="createAction in createActions" ng-click="createAction.perform()">
<a ng-mouseover="representation.activeMetadata = createAction.getMetadata()"
ng-mouseleave="representation.activeMetadata = undefined"
class="menu-item-a {{ createAction.getMetadata().cssClass }}">
{{createAction.getMetadata().name}}
</a>
</li>
</ul>
</div>
<div class="col menu-item-description">
<div class="desc-area icon {{ representation.activeMetadata.cssClass }}"></div>
<div class="w-title-desc">
<div class="desc-area title">
{{representation.activeMetadata.name}}
</div>
<div class="desc-area description">
{{representation.activeMetadata.description}}
</div>
</div>
</div>
</div>

View File

@@ -1,29 +0,0 @@
<!--
Open MCT, Copyright (c) 2014-2021, 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 ng-controller="LocatorController" class="selector-list">
<div class="wrapper">
<mct-representation key="'tree'"
mct-object="rootObject"
ng-model="treeModel">
</mct-representation>
</div>
</div>

View File

@@ -1,98 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
/**
* Edit the properties of a domain object. Shows a dialog
* which should display a set of properties similar to that
* shown in the Create wizard.
*/
define(
['./PropertiesDialog'],
function (PropertiesDialog) {
/**
* Implements the "Edit Properties" action, which prompts the user
* to modify a domain object's properties.
*
* @param {DialogService} dialogService a service which will show the dialog
* @param {DomainObject} object the object to be edited
* @param {ActionContext} context the context in which this action is performed
* @memberof platform/commonUI/edit
* @implements {Action}
* @constructor
*/
function PropertiesAction(dialogService, context) {
this.domainObject = (context || {}).domainObject;
this.dialogService = dialogService;
}
PropertiesAction.prototype.perform = function () {
var type = this.domainObject.getCapability('type'),
domainObject = this.domainObject,
dialogService = this.dialogService;
// Update the domain object model based on user input
function updateModel(userInput, dialog) {
return domainObject.useCapability('mutation', function (model) {
dialog.updateModel(model, userInput);
});
}
function showDialog(objType) {
// Create a dialog object to generate the form structure, etc.
var dialog =
new PropertiesDialog(objType, domainObject.getModel());
// Show the dialog
return dialogService.getUserInput(
dialog.getFormStructure(),
dialog.getInitialFormValue()
).then(function (userInput) {
// Update the model, if user input was provided
return userInput && updateModel(userInput, dialog);
});
}
return type && showDialog(type);
};
/**
* Filter this action for applicability against a given context.
* This will ensure that a domain object is present in the
* context.
*/
PropertiesAction.appliesTo = function (context, view, openmct) {
let domainObject = (context || {}).domainObject;
if (!domainObject || (domainObject.model && domainObject.model.locked)) {
return false;
}
return openmct.objects.isPersistable(domainObject.id);
};
return PropertiesAction;
}
);

View File

@@ -1,92 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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 () {
/**
* Construct a new Properties dialog.
*
* @param {TypeImpl} type the type of domain object for which properties
* will be specified
* @param {DomainObject} the object for which properties will be set
* @memberof platform/commonUI/edit
* @constructor
*/
function PropertiesDialog(type, model) {
this.type = type;
this.model = model;
this.properties = type.getProperties();
}
/**
* Get sections provided by this dialog.
* @return {FormStructure} the structure of this form
*/
PropertiesDialog.prototype.getFormStructure = function () {
return {
name: "Edit " + this.model.name,
sections: [{
name: "Properties",
rows: this.properties.map(function (property, index) {
// Property definition is same as form row definition
var row = JSON.parse(JSON.stringify(property.getDefinition()));
row.key = index;
return row;
}).filter(function (row) {
// Only show properties which are editable
return row.control;
})
}]
};
};
/**
* Get the initial state of the form shown by this dialog
* (based on the object model)
* @returns {object} initial state of the form
*/
PropertiesDialog.prototype.getInitialFormValue = function () {
var model = this.model;
// Start with initial values for properties
// Note that index needs to correlate to row.key
// from getFormStructure
return this.properties.map(function (property) {
return property.getValue(model);
});
};
/**
* Update a domain object model based on the value of a form.
*/
PropertiesDialog.prototype.updateModel = function (model, formValue) {
// Update all properties
this.properties.forEach(function (property, index) {
property.setValue(model, formValue[index]);
});
};
return PropertiesDialog;
}
);

View File

@@ -1,210 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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([
'../creation/CreateWizard',
'./SaveInProgressDialog'
],
function (
CreateWizard,
SaveInProgressDialog
) {
/**
* The "Save" action; the action triggered by clicking Save from
* Edit Mode. Exits the editing user interface and invokes object
* capabilities to persist the changes that have been made.
* @constructor
* @implements {Action}
* @memberof platform/commonUI/edit
*/
function SaveAsAction(
$injector,
dialogService,
copyService,
notificationService,
openmct,
context
) {
this.domainObject = (context || {}).domainObject;
this.injectObjectService = function () {
this.objectService = $injector.get("objectService");
};
this.dialogService = dialogService;
this.copyService = copyService;
this.notificationService = notificationService;
this.openmct = openmct;
}
/**
* @private
*/
SaveAsAction.prototype.createWizard = function (parent) {
return new CreateWizard(
this.domainObject,
parent,
this.openmct
);
};
/**
* @private
*/
SaveAsAction.prototype.getObjectService = function () {
// Lazily acquire object service (avoids cyclical dependency)
if (!this.objectService) {
this.injectObjectService();
}
return this.objectService;
};
/**
* Save changes and conclude editing.
*
* @returns {Promise} a promise that will be fulfilled when
* cancellation has completed
* @memberof platform/commonUI/edit.SaveAction#
*/
SaveAsAction.prototype.perform = function () {
return this.save();
};
/**
* @private
*/
SaveAsAction.prototype.save = function () {
var self = this,
domainObject = this.domainObject,
dialog = new SaveInProgressDialog(this.dialogService);
function doWizardSave(parent) {
var wizard = self.createWizard(parent);
return self.dialogService
.getUserInput(wizard.getFormStructure(true),
wizard.getInitialFormValue())
.then(wizard.populateObjectFromInput.bind(wizard), function (failureReason) {
return Promise.reject("user canceled");
});
}
function showBlockingDialog(object) {
dialog.show();
return object;
}
function hideBlockingDialog(object) {
dialog.hide();
return object;
}
function fetchObject(objectId) {
return self.getObjectService().getObjects([objectId]).then(function (objects) {
return objects[objectId];
});
}
function getParent(object) {
return fetchObject(object.getModel().location);
}
function saveObject(object) {
//persist the object, which adds it to the transaction and then call editor.save
return object.getCapability("persistence").persist()
.then(() => {
return self.openmct.editor.save().then(() => {
return object;
});
});
}
function addSavedObjectToParent(parent) {
return parent.getCapability("composition")
.add(domainObject)
.then(function (addedObject) {
return parent.getCapability("persistence").persist()
.then(function () {
return addedObject;
});
});
}
function indexForSearch(addedObject) {
addedObject.useCapability('mutation', (model) => {
return model;
});
return addedObject;
}
function onSuccess(object) {
self.notificationService.info("Save Succeeded");
return object;
}
function onFailure(reason) {
hideBlockingDialog();
if (reason !== "user canceled") {
self.notificationService.error("Save Failed");
}
throw reason;
}
return getParent(domainObject)
.then(doWizardSave)
.then(showBlockingDialog)
.then(saveObject)
.then(getParent)
.then(addSavedObjectToParent)
.then((addedObject) => {
return fetchObject(addedObject.getId());
})
.then(indexForSearch)
.then(hideBlockingDialog)
.then(onSuccess)
.catch(onFailure);
};
/**
* 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
*/
SaveAsAction.appliesTo = function (context) {
var domainObject = (context || {}).domainObject;
return domainObject !== undefined
&& domainObject.hasCapability('editor')
&& domainObject.getCapability('editor').isEditContextRoot()
&& domainObject.getModel().persisted === undefined;
};
return SaveAsAction;
}
);

View File

@@ -1,133 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
/**
* Module defining CreateAction. Created by vwoeltje on 11/10/14.
*/
define(
[],
function () {
/**
* The Create Action is performed to create new instances of
* domain objects of a specific type. This is the action that
* is performed when a user uses the Create menu.
*
* @memberof platform/commonUI/browse
* @implements {Action}
* @constructor
*
* @param {Type} type the type of domain object to create
* @param {DomainObject} parent the domain object that should
* act as a container for the newly-created object
* (note that the user will have an opportunity to
* override this)
* @param {ActionContext} context the context in which the
* action is being performed
*/
function CreateAction(type, parent, context, openmct) {
this.metadata = {
key: 'create',
cssClass: type.getCssClass(),
name: type.getName(),
type: type.getKey(),
description: type.getDescription(),
context: context
};
this.type = type;
this.parent = parent;
this.openmct = openmct;
}
/**
* Create a new object of the given type.
* This will prompt for user input first.
*/
CreateAction.prototype.perform = function () {
var newModel = this.type.getInitialModel(),
openmct = this.openmct,
newObject;
function onCancel() {
openmct.editor.cancel();
}
function isFirstViewEditable(domainObject, objectPath) {
let firstView = openmct.objectViews.get(domainObject, objectPath)[0];
return firstView && firstView.canEdit && firstView.canEdit(domainObject, objectPath);
}
function navigateAndEdit(object) {
let objectPath = object.getCapability('context').getPath(),
url = '#/browse/' + objectPath
.slice(1)
.map(function (o) {
return o && openmct.objects.makeKeyString(o.getId());
})
.join('/');
function editObject() {
const path = objectPath.slice(-1).map(obj => {
const objNew = obj.getCapability('adapter').invoke();
return objNew;
});
if (isFirstViewEditable(object.useCapability('adapter'), path)) {
openmct.editor.edit();
}
}
openmct.router.once('afterNavigation', editObject);
openmct.router.navigate(url);
}
newModel.type = this.type.getKey();
newModel.location = this.parent.getId();
newObject = this.parent.useCapability('instantiation', newModel);
openmct.editor.edit();
newObject.getCapability("action").perform("save-as").then(navigateAndEdit, onCancel);
// TODO: support editing object without saving object first.
// Which means we have to toggle createwizard afterwards. For now,
// We will disable this.
};
/**
* Metadata associated with a Create action.
* @typedef {ActionMetadata} CreateActionMetadata
* @property {string} type the key for the type of domain object
* to be created
*/
/**
* Get metadata about this action.
* @returns {CreateActionMetadata} metadata about this action
*/
CreateAction.prototype.getMetadata = function () {
return this.metadata;
};
return CreateAction;
}
);

View File

@@ -1,80 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
/**
* Module defining CreateActionProvider.js. Created by vwoeltje on 11/10/14.
*/
define(
["./CreateAction"],
function (CreateAction) {
/**
* The CreateActionProvider is an ActionProvider which introduces
* a Create action for each creatable domain object type.
*
* @memberof platform/commonUI/browse
* @constructor
* @implements {ActionService}
*
* @param {TypeService} typeService the type service, used to discover
* available types
* @param {DialogService} dialogService the dialog service, used by
* specific Create actions to get user input to populate the
* model of the newly-created domain object.
* @param {CreationService} creationService the creation service (also
* introduced in this bundle), responsible for handling actual
* object creation.
*/
function CreateActionProvider(typeService, policyService) {
this.typeService = typeService;
this.policyService = policyService;
}
CreateActionProvider.prototype.getActions = function (actionContext) {
var context = actionContext || {},
key = context.key,
destination = context.domainObject,
self = this;
// We only provide Create actions, and we need a
// domain object to serve as the container for the
// newly-created object (although the user may later
// make a different selection)
if (key !== 'create' || !destination) {
return [];
}
// Introduce one create action per type
return this.typeService.listTypes().filter(function (type) {
return self.policyService.allow("creation", type);
}).map(function (type) {
return new CreateAction(
type,
destination,
context
);
});
};
return CreateActionProvider;
}
);

View File

@@ -1,57 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
/**
* Module defining CreateMenuController. Created by vwoeltje on 11/10/14.
*/
define(
[],
function () {
/**
* Controller for the Create menu; maintains an up-to-date
* set of Create actions based on the currently-selected
* domain object.
*
* @memberof platform/commonUI/browse
* @constructor
*/
function CreateMenuController($scope) {
// Update the set of Create actions
function refreshActions() {
$scope.createActions = $scope.action
? $scope.action.getActions('create')
: [];
}
// Listen for new instances of the represented object's
// "action" capability. This is provided by the mct-representation
// for the Create button.
// A watch is needed here (instead of invoking action.getActions
// directly) because different action instances may be returned
// with each call.
$scope.$watch("action", refreshActions);
}
return CreateMenuController;
}
);

View File

@@ -1,186 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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 () {
/**
* A class for capturing user input data from an object creation
* dialog, and populating a domain object with that data.
*
* @param {DomainObject} domainObject the newly created object to
* populate with user input
* @param {DomainObject} parent the domain object to serve as
* the initial parent for the created object, in the dialog
* @memberof platform/commonUI/browse
* @constructor
*/
function CreateWizard(domainObject, parent, openmct) {
this.type = domainObject.getCapability('type');
this.model = domainObject.getModel();
this.domainObject = domainObject;
this.properties = this.type.getProperties();
this.parent = parent;
this.openmct = openmct;
}
/**
* Get the form model for this wizard; this is a description
* that will be rendered to an HTML form. See the
* platform/forms bundle
* @param {boolean} includeLocation if true, a 'location' section
* will be included that will allow the user to select the location
* of the newly created object, otherwise the .location property of
* the model will be used.
* @return {FormModel} formModel the form model to
* show in the create dialog
*/
CreateWizard.prototype.getFormStructure = function (includeLocation) {
var sections = [],
domainObject = this.domainObject,
self = this;
function validateLocation(parent) {
return parent && self.openmct.composition.checkPolicy(parent.useCapability('adapter'), domainObject.useCapability('adapter'));
}
sections.push({
name: "Properties",
rows: this.properties.map(function (property, index) {
// Property definition is same as form row definition
var row = JSON.parse(JSON.stringify(property.getDefinition()));
// Use index as the key into the formValue;
// this correlates to the indexing provided by
// getInitialFormValue
row.key = index;
return row;
}).filter(function (row) {
// Only show rows which have defined controls
return row && row.control;
})
});
// Ensure there is always a "save in" section
if (includeLocation) {
sections.push({
name: 'Location',
cssClass: "grows",
rows: [{
name: "Save In",
control: "locator",
validate: validateLocation.bind(this),
key: "createParent"
}]
});
}
return {
sections: sections,
name: "Create a New " + this.type.getName()
};
};
/**
* Given some form input values and a domain object, populate the
* domain object used to create this wizard from the given form values.
* @param formValue
* @returns {DomainObject}
*/
CreateWizard.prototype.populateObjectFromInput = function (formValue) {
var parent = this.getLocation(formValue),
formModel = this.createModel(formValue);
formModel.location = parent.getId();
this.updateNamespaceFromParent(parent);
this.domainObject.useCapability("mutation", function () {
return formModel;
});
return this.domainObject;
};
/** @private */
CreateWizard.prototype.updateNamespaceFromParent = function (parent) {
let childIdentifier = this.domainObject.useCapability('adapter').identifier;
let parentIdentifier = parent.useCapability('adapter').identifier;
childIdentifier.namespace = parentIdentifier.namespace;
this.domainObject.id = this.openmct.objects.makeKeyString(childIdentifier);
};
/**
* Get the initial value for the form being described.
* This will include the values for all properties described
* in the structure.
*
* @returns {object} the initial value of the form
*/
CreateWizard.prototype.getInitialFormValue = function () {
// Start with initial values for properties
var model = this.model,
formValue = this.properties.map(function (property) {
return property.getValue(model);
});
// Include the createParent
formValue.createParent = this.parent;
return formValue;
};
/**
* Based on a populated form, get the domain object which
* should be used as a parent for the newly-created object.
* @private
* @return {DomainObject}
*/
CreateWizard.prototype.getLocation = function (formValue) {
return formValue.createParent || this.parent;
};
/**
* Create the domain object model for a newly-created object,
* based on user input read from a formModel.
* @private
* @return {object} the domain object model
*/
CreateWizard.prototype.createModel = function (formValue) {
// Clone
var newModel = JSON.parse(JSON.stringify(this.model));
// Always use the type from the type definition
newModel.type = this.type.getKey();
// Update all properties
this.properties.forEach(function (property, index) {
property.setValue(newModel, formValue[index]);
});
return newModel;
};
return CreateWizard;
}
);

View File

@@ -1,43 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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 () {
/**
* A policy for determining whether objects of a given type can be
* created.
* @constructor
* @implements {Policy}
* @memberof platform/commonUI/browse
*/
function CreationPolicy() {
}
CreationPolicy.prototype.allow = function (type) {
return type.hasFeature("creation");
};
return CreationPolicy;
}
);

View File

@@ -1,107 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
/**
* Module defining CreateService. Created by vwoeltje on 11/10/14.
*/
define(
[],
function () {
var NON_PERSISTENT_WARNING =
"Tried to create an object in non-persistent container.";
/**
* The creation service is responsible for instantiating and
* persisting new domain objects. Handles all actual object
* mutation and persistence associated with domain object
* creation.
* @memberof platform/commonUI/browse
* @constructor
*/
function CreationService($q, $log) {
this.$q = $q;
this.$log = $log;
}
/**
* Create a new domain object with the provided model, as
* a member of the provided parent domain object's composition.
* This parent will additionally determine which persistence
* space an object is created within (as it is possible to
* have multiple persistence spaces attached.)
*
* Note that the model passed in for object creation may be
* modified to attach additional initial properties associated
* with domain object creation.
*
* @param {object} model the model for the newly-created
* domain object
* @param {DomainObject} parent the domain object which
* should contain the newly-created domain object
* in its composition
* @return {Promise} a promise that will resolve when the domain
* object has been created
*/
CreationService.prototype.createObject = function (model, parent) {
var persistence = parent.getCapability("persistence"),
newObject = parent.useCapability("instantiation", model),
newObjectPersistence = newObject.getCapability("persistence"),
self = this;
// Add the newly-created object's id to the parent's
// composition, so that it will subsequently appear
// as a child contained by that parent.
function addToComposition() {
var compositionCapability = parent.getCapability('composition'),
addResult = compositionCapability
&& compositionCapability.add(newObject);
return self.$q.when(addResult).then(function (result) {
if (!result) {
self.$log.error("Could not modify " + parent.getId());
return undefined;
}
return persistence.persist().then(function () {
return result;
});
});
}
// We need the parent's persistence capability to determine
// what space to create the new object's model in.
if (!persistence || !newObjectPersistence) {
self.$log.warn(NON_PERSISTENT_WARNING);
return self.$q.reject(new Error(NON_PERSISTENT_WARNING));
}
// Persist the new object, then add it to composition.
return newObjectPersistence.persist().then(addToComposition);
};
return CreationService;
}
);

View File

@@ -1,98 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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 () {
/**
* Controller for the "locator" control, which provides the
* user with the ability to select a domain object as the
* destination for a newly-created object in the Create menu.
* @memberof platform/commonUI/browse
* @constructor
*/
function LocatorController($scope, $timeout, objectService) {
// Populate values needed by the locator control. These are:
// * rootObject: The top-level object, since we want to show
// the full tree
// * treeModel: The model for the embedded tree representation,
// used for bi-directional object selection.
function setLocatingObject(domainObject, priorObject) {
var context = domainObject
&& domainObject.getCapability("context"),
contextRoot = context && context.getRoot();
if (contextRoot && contextRoot !== $scope.rootObject) {
$scope.rootObject = undefined;
// Update the displayed tree on a timeout to avoid
// an infinite digest exception.
$timeout(function () {
$scope.rootObject =
(context && context.getRoot()) || $scope.rootObject;
}, 0);
} else if (!contextRoot && !$scope.rootObject) {
// Update the displayed tree on a timeout to avoid
// an infinite digest exception.
objectService.getObjects(['ROOT'])
.then(function (objects) {
$timeout(function () {
$scope.rootObject = objects.ROOT;
}, 0);
});
}
$scope.treeModel.selectedObject = domainObject;
$scope.ngModel[$scope.field] = domainObject;
// Restrict which locations can be selected
if (domainObject
&& $scope.structure
&& $scope.structure.validate) {
if (!$scope.structure.validate(domainObject)) {
setLocatingObject(priorObject, undefined);
return;
}
}
// Set validity
if ($scope.ngModelController) {
$scope.ngModelController.$setValidity(
'composition',
Boolean($scope.treeModel.selectedObject)
);
}
}
// Initial state for the tree's model
$scope.treeModel =
{ selectedObject: $scope.ngModel[$scope.field] };
// Watch for changes from the tree
$scope.$watch("treeModel.selectedObject", setLocatingObject);
}
return LocatorController;
}
);

View File

@@ -1,110 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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/PropertiesAction'],
function (PropertiesAction) {
describe("Properties action", function () {
var capabilities, model, object, context, input, dialogService, action, openmct;
function mockPromise(value) {
return {
then: function (callback) {
return mockPromise(callback(value));
}
};
}
beforeEach(function () {
openmct = {
objects: {
isPersistable: jasmine.createSpy('isPersistable')
}
};
capabilities = {
type: {
getProperties: function () {
return [];
},
hasFeature: jasmine.createSpy('hasFeature')
},
mutation: jasmine.createSpy("mutation")
};
model = {};
input = {};
object = {
getId: function () {
return 'test-id';
},
getCapability: function (k) {
return capabilities[k];
},
getModel: function () {
return model;
},
useCapability: function (k, v) {
return capabilities[k](v);
},
hasCapability: function () {
return true;
}
};
context = {
someKey: "some value",
domainObject: object
};
dialogService = {
getUserInput: function () {
return mockPromise(input);
}
};
capabilities.type.hasFeature.and.returnValue(true);
capabilities.mutation.and.returnValue(true);
openmct.objects.isPersistable.and.returnValue(true);
action = new PropertiesAction(dialogService, context);
});
it("mutates an object when performed", function () {
action.perform();
expect(capabilities.mutation).toHaveBeenCalled();
capabilities.mutation.calls.mostRecent().args[0]({});
});
it("does not muate object upon cancel", function () {
input = undefined;
action.perform();
expect(capabilities.mutation).not.toHaveBeenCalled();
});
it("is only applicable when a domain object is in context", function () {
expect(PropertiesAction.appliesTo(context, undefined, openmct)).toBeTruthy();
expect(PropertiesAction.appliesTo({}, undefined, openmct)).toBeFalsy();
expect(openmct.objects.isPersistable).toHaveBeenCalled();
});
});
}
);

View File

@@ -1,80 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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/PropertiesDialog"],
function (PropertiesDialog) {
describe("Properties dialog", function () {
var type, properties, model, dialog;
beforeEach(function () {
type = {
getProperties: function () {
return properties;
}
};
model = { x: "initial value" };
properties = ["x", "y", "z"].map(function (k) {
return {
getValue: function (m) {
return m[k];
},
setValue: function (m, v) {
m[k] = v;
},
getDefinition: function () {
return { control: 'textfield '};
}
};
});
dialog = new PropertiesDialog(type, model);
});
it("provides sections based on type properties", function () {
expect(dialog.getFormStructure().sections[0].rows.length)
.toEqual(properties.length);
});
it("pulls initial values from object model", function () {
expect(dialog.getInitialFormValue()[0])
.toEqual("initial value");
});
it("populates models with form results", function () {
dialog.updateModel(model, [
"new value",
"other new value",
42
]);
expect(model).toEqual({
x: "new value",
y: "other new value",
z: 42
});
});
});
}
);

View File

@@ -1,249 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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/SaveAsAction"],
function (SaveAsAction) {
xdescribe("The Save As action", function () {
var mockDomainObject,
mockClonedObject,
mockEditorCapability,
mockActionCapability,
mockObjectService,
mockDialogService,
mockCopyService,
mockNotificationService,
mockParent,
actionContext,
capabilities = {},
action;
function noop() {}
function mockPromise(value) {
return (value || {}).then ? value
: {
then: function (callback) {
return mockPromise(callback(value));
},
catch: function (callback) {
return mockPromise(callback(value));
}
};
}
beforeEach(function () {
mockDomainObject = jasmine.createSpyObj(
"domainObject",
[
"getCapability",
"hasCapability",
"getModel",
"getId"
]
);
mockDomainObject.hasCapability.and.returnValue(true);
mockDomainObject.getCapability.and.callFake(function (capability) {
return capabilities[capability];
});
mockDomainObject.getModel.and.returnValue({
location: 'a',
persisted: undefined
});
mockDomainObject.getId.and.returnValue(0);
mockClonedObject = jasmine.createSpyObj(
"clonedObject",
[
"getId"
]
);
mockClonedObject.getId.and.returnValue(1);
mockParent = jasmine.createSpyObj(
"parentObject",
[
"getCapability",
"hasCapability",
"getModel"
]
);
mockEditorCapability = jasmine.createSpyObj(
"editor",
["save", "finish", "isEditContextRoot"]
);
mockEditorCapability.save.and.returnValue(mockPromise(true));
mockEditorCapability.finish.and.returnValue(mockPromise(true));
mockEditorCapability.isEditContextRoot.and.returnValue(true);
capabilities.editor = mockEditorCapability;
mockActionCapability = jasmine.createSpyObj(
"action",
["perform"]
);
capabilities.action = mockActionCapability;
mockObjectService = jasmine.createSpyObj(
"objectService",
["getObjects"]
);
mockObjectService.getObjects.and.returnValue(mockPromise({'a': mockParent}));
mockDialogService = jasmine.createSpyObj(
"dialogService",
[
"getUserInput",
"showBlockingMessage"
]
);
mockDialogService.getUserInput.and.returnValue(mockPromise(undefined));
mockCopyService = jasmine.createSpyObj(
"copyService",
[
"perform"
]
);
mockCopyService.perform.and.returnValue(mockPromise(mockClonedObject));
mockNotificationService = jasmine.createSpyObj(
"notificationService",
[
"info",
"error"
]
);
actionContext = {
domainObject: mockDomainObject
};
action = new SaveAsAction(
undefined,
undefined,
mockDialogService,
mockCopyService,
mockNotificationService,
actionContext);
spyOn(action, "getObjectService");
action.getObjectService.and.returnValue(mockObjectService);
spyOn(action, "createWizard");
action.createWizard.and.returnValue({
getFormStructure: noop,
getInitialFormValue: noop,
populateObjectFromInput: function () {
return mockDomainObject;
}
});
});
it("only applies to domain object with an editor capability", function () {
expect(SaveAsAction.appliesTo(actionContext)).toBe(true);
expect(mockDomainObject.hasCapability).toHaveBeenCalledWith("editor");
mockDomainObject.hasCapability.and.returnValue(false);
mockDomainObject.getCapability.and.returnValue(undefined);
expect(SaveAsAction.appliesTo(actionContext)).toBe(false);
});
it("only applies to domain object that has not already been"
+ " persisted", function () {
expect(SaveAsAction.appliesTo(actionContext)).toBe(true);
expect(mockDomainObject.hasCapability).toHaveBeenCalledWith("editor");
mockDomainObject.getModel.and.returnValue({persisted: 0});
expect(SaveAsAction.appliesTo(actionContext)).toBe(false);
});
it("uses the editor capability to save the object", function () {
mockEditorCapability.save.and.returnValue(Promise.resolve());
return action.perform().then(function () {
expect(mockEditorCapability.save).toHaveBeenCalled();
});
});
it("uses the editor capability to finish editing the object", function () {
return action.perform().then(function () {
expect(mockEditorCapability.finish.calls.count()).toBeGreaterThan(0);
});
});
it("returns to browse after save", function () {
spyOn(action, "save");
action.save.and.returnValue(mockPromise(mockDomainObject));
action.perform();
expect(mockActionCapability.perform).toHaveBeenCalledWith(
"navigate"
);
});
it("prompts the user for object details", function () {
action.perform();
expect(mockDialogService.getUserInput).toHaveBeenCalled();
});
describe("in order to keep the user in the loop", function () {
var mockDialogHandle;
beforeEach(function () {
mockDialogHandle = jasmine.createSpyObj("dialogHandle", ["dismiss"]);
mockDialogService.showBlockingMessage.and.returnValue(mockDialogHandle);
});
it("shows a blocking dialog indicating that saving is in progress", function () {
mockEditorCapability.save.and.returnValue(new Promise(function () {}));
action.perform();
expect(mockDialogService.showBlockingMessage).toHaveBeenCalled();
expect(mockDialogHandle.dismiss).not.toHaveBeenCalled();
});
it("hides the blocking dialog after saving finishes", function () {
return action.perform().then(function () {
expect(mockDialogService.showBlockingMessage).toHaveBeenCalled();
expect(mockDialogHandle.dismiss).toHaveBeenCalled();
});
});
it("notifies if saving succeeded", function () {
return action.perform().then(function () {
expect(mockNotificationService.info).toHaveBeenCalled();
expect(mockNotificationService.error).not.toHaveBeenCalled();
});
});
it("notifies if saving failed", function () {
mockCopyService.perform.and.returnValue(Promise.reject("some failure reason"));
action.perform().then(function () {
expect(mockNotificationService.error).toHaveBeenCalled();
expect(mockNotificationService.info).not.toHaveBeenCalled();
});
});
});
});
}
);

View File

@@ -1,118 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
/**
* MCTRepresentationSpec. Created by vwoeltje on 11/6/14.
*/
define(
["../../src/creation/CreateActionProvider"],
function (CreateActionProvider) {
describe("The create action provider", function () {
var mockTypeService,
mockPolicyService,
mockCreationPolicy,
mockPolicyMap = {},
mockTypes,
provider;
function createMockType(name) {
var mockType = jasmine.createSpyObj(
"type" + name,
[
"getKey",
"getGlyph",
"getCssClass",
"getName",
"getDescription",
"getProperties",
"getInitialModel",
"hasFeature"
]
);
mockType.hasFeature.and.returnValue(true);
mockType.getName.and.returnValue(name);
return mockType;
}
beforeEach(function () {
mockTypeService = jasmine.createSpyObj(
"typeService",
["listTypes"]
);
mockPolicyService = jasmine.createSpyObj(
"policyService",
["allow"]
);
mockTypes = ["A", "B", "C"].map(createMockType);
mockTypes.forEach(function (type) {
mockPolicyMap[type.getName()] = true;
});
mockCreationPolicy = function (type) {
return mockPolicyMap[type.getName()];
};
mockPolicyService.allow.and.callFake(function (category, type) {
return Boolean(category === "creation" && mockCreationPolicy(type));
});
mockTypeService.listTypes.and.returnValue(mockTypes);
provider = new CreateActionProvider(
mockTypeService,
mockPolicyService
);
});
it("exposes one create action per type", function () {
expect(provider.getActions({
key: "create",
domainObject: {}
}).length).toEqual(3);
});
it("exposes no non-create actions", function () {
expect(provider.getActions({
key: "somethingElse",
domainObject: {}
}).length).toEqual(0);
});
it("does not expose non-creatable types", function () {
// One of the types won't have the creation feature...
mockPolicyMap[mockTypes[0].getName()] = false;
// ...so it should have been filtered out.
expect(provider.getActions({
key: "create",
domainObject: {}
}).length).toEqual(2);
// Make sure it was creation which was used to check
expect(mockPolicyService.allow)
.toHaveBeenCalledWith("creation", mockTypes[0]);
});
});
}
);

View File

@@ -1,186 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
/**
* MCTRepresentationSpec. Created by vwoeltje on 11/6/14.
*/
define(
["../../src/creation/CreateAction"],
function (CreateAction) {
xdescribe("The create action", function () {
var mockType,
mockParent,
mockContext,
mockDomainObject,
capabilities = {},
mockEditAction,
action;
function mockPromise(value) {
return {
then: function (callback) {
return mockPromise(callback(value));
}
};
}
beforeEach(function () {
mockType = jasmine.createSpyObj(
"type",
[
"getKey",
"getGlyph",
"getCssClass",
"getName",
"getDescription",
"getProperties",
"getInitialModel"
]
);
mockParent = jasmine.createSpyObj(
"domainObject",
[
"getId",
"getModel",
"getCapability",
"useCapability"
]
);
mockDomainObject = jasmine.createSpyObj(
"domainObject",
[
"getId",
"getModel",
"getCapability",
"hasCapability",
"useCapability"
]
);
mockDomainObject.hasCapability.and.callFake(function (name) {
return Boolean(capabilities[name]);
});
mockDomainObject.getCapability.and.callFake(function (name) {
return capabilities[name];
});
capabilities.action = jasmine.createSpyObj(
"actionCapability",
[
"getActions",
"perform"
]
);
capabilities.editor = jasmine.createSpyObj(
"editorCapability",
[
"edit",
"save",
"finish"
]
);
mockEditAction = jasmine.createSpyObj(
"editAction",
[
"perform"
]
);
mockContext = {
domainObject: mockParent
};
mockParent.useCapability.and.returnValue(mockDomainObject);
mockType.getKey.and.returnValue("test");
mockType.getCssClass.and.returnValue("icon-telemetry");
mockType.getDescription.and.returnValue("a test type");
mockType.getName.and.returnValue("Test");
mockType.getProperties.and.returnValue([]);
mockType.getInitialModel.and.returnValue({});
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.cssClass).toEqual("icon-telemetry");
});
describe("the perform function", function () {
var promise = jasmine.createSpyObj("promise", ["then"]);
beforeEach(function () {
capabilities.action.getActions.and.returnValue([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-as action if object does not have an edit action"
+ " available", function () {
capabilities.action.getActions.and.returnValue([]);
capabilities.action.perform.and.returnValue(mockPromise(undefined));
capabilities.editor.save.and.returnValue(promise);
action.perform();
expect(capabilities.action.perform).toHaveBeenCalledWith("save-as");
});
describe("uses to editor capability", function () {
beforeEach(function () {
capabilities.action.getActions.and.returnValue([]);
capabilities.action.perform.and.returnValue(promise);
capabilities.editor.save.and.returnValue(promise);
});
it("to save the edit if user saves dialog", function () {
action.perform();
expect(promise.then).toHaveBeenCalled();
promise.then.calls.mostRecent().args[0]();
expect(capabilities.editor.save).toHaveBeenCalled();
});
it("to finish the edit if user cancels dialog", function () {
action.perform();
promise.then.calls.mostRecent().args[1]();
expect(capabilities.editor.finish).toHaveBeenCalled();
});
});
});
});
}
);

View File

@@ -1,65 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
/**
* MCTRepresentationSpec. Created by vwoeltje on 11/6/14.
*/
define(
["../../src/creation/CreateMenuController"],
function (CreateMenuController) {
describe("The create menu controller", function () {
var mockScope,
mockActions,
controller;
beforeEach(function () {
mockActions = jasmine.createSpyObj("action", ["getActions"]);
mockScope = jasmine.createSpyObj("$scope", ["$watch"]);
controller = new CreateMenuController(mockScope);
});
it("watches scope that may change applicable actions", function () {
// The action capability
expect(mockScope.$watch).toHaveBeenCalledWith(
"action",
jasmine.any(Function)
);
});
it("populates the scope with create actions", function () {
mockScope.action = mockActions;
mockActions.getActions.and.returnValue(["a", "b", "c"]);
// Call the watch
mockScope.$watch.calls.mostRecent().args[1]();
// Should have grouped and ungrouped actions in scope now
expect(mockScope.createActions.length).toEqual(3);
// Make sure the right action type was requested
expect(mockActions.getActions).toHaveBeenCalledWith("create");
});
});
}
);

View File

@@ -1,197 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
/**
* MCTRepresentationSpec. Created by vwoeltje on 11/6/14.
*/
define(
["../../src/creation/CreateWizard"],
function (CreateWizard) {
xdescribe("The create wizard", function () {
var mockType,
mockParent,
mockProperties,
mockPolicyService,
testModel,
mockDomainObject,
wizard;
function createMockProperty(name) {
var mockProperty = jasmine.createSpyObj(
"property" + name,
["getDefinition", "getValue", "setValue"]
);
mockProperty.getDefinition.and.returnValue({
control: "textfield"
});
mockProperty.getValue.and.returnValue(name);
return mockProperty;
}
beforeEach(function () {
mockType = jasmine.createSpyObj(
"type",
[
"getKey",
"getGlyph",
"getCssClass",
"getName",
"getDescription",
"getProperties",
"getInitialModel"
]
);
mockParent = jasmine.createSpyObj(
"domainObject",
[
"getId",
"getModel",
"getCapability"
]
);
mockProperties = ["A", "B", "C"].map(createMockProperty);
mockPolicyService = jasmine.createSpyObj('policyService', ['allow']);
testModel = { someKey: "some value" };
mockType.getKey.and.returnValue("test");
mockType.getCssClass.and.returnValue("icon-telemetry");
mockType.getDescription.and.returnValue("a test type");
mockType.getName.and.returnValue("Test");
mockType.getInitialModel.and.returnValue(testModel);
mockType.getProperties.and.returnValue(mockProperties);
mockDomainObject = jasmine.createSpyObj(
'domainObject',
['getCapability', 'useCapability', 'getModel']
);
//Mocking the getCapability('type') call
mockDomainObject.getCapability.and.returnValue(mockType);
mockDomainObject.useCapability.and.returnValue();
mockDomainObject.getModel.and.returnValue(testModel);
wizard = new CreateWizard(
mockDomainObject,
mockParent,
mockPolicyService
);
});
it("creates a form model with a Properties section", function () {
expect(wizard.getFormStructure().sections[0].name)
.toEqual("Properties");
});
it("adds one row per defined type property", function () {
// Three properties were defined in the mock type
expect(wizard.getFormStructure().sections[0].rows.length)
.toEqual(3);
});
it("interprets form data using type-defined properties", function () {
// Use key names from mock properties
wizard.createModel([
"field 0",
"field 1",
"field 2"
]);
// Should have gotten a setValue call
mockProperties.forEach(function (mockProperty, i) {
expect(mockProperty.setValue).toHaveBeenCalledWith(
{
someKey: "some value",
type: 'test'
},
"field " + i
);
});
});
it("looks up initial values from properties", function () {
var initialValue = wizard.getInitialFormValue();
expect(initialValue[0]).toEqual("A");
expect(initialValue[1]).toEqual("B");
expect(initialValue[2]).toEqual("C");
// Verify that expected argument was passed
mockProperties.forEach(function (mockProperty) {
expect(mockProperty.getValue)
.toHaveBeenCalledWith(testModel);
});
});
it("populates the model on the associated object", function () {
var formValue = {
"A": "ValueA",
"B": "ValueB",
"C": "ValueC"
},
compareModel = wizard.createModel(formValue);
//populateObjectFromInput adds a .location attribute that is not added by createModel.
compareModel.location = undefined;
wizard.populateObjectFromInput(formValue);
expect(mockDomainObject.useCapability).toHaveBeenCalledWith('mutation', jasmine.any(Function));
expect(mockDomainObject.useCapability.calls.mostRecent().args[1]()).toEqual(compareModel);
});
it("validates selection types using policy", function () {
var mockDomainObj = jasmine.createSpyObj(
'domainObject',
['getCapability']
),
mockOtherType = jasmine.createSpyObj(
'otherType',
['getKey']
),
//Create a form structure with location
structure = wizard.getFormStructure(true),
sections = structure.sections,
rows = structure.sections[sections.length - 1].rows,
locationRow = rows[rows.length - 1];
mockDomainObj.getCapability.and.returnValue(mockOtherType);
locationRow.validate(mockDomainObj);
// Should check policy to see if the user-selected location
// can actually contain objects of this type
expect(mockPolicyService.allow).toHaveBeenCalledWith(
'composition',
mockDomainObj,
mockDomainObject
);
});
it("creates a form model without a location if not requested", function () {
expect(wizard.getFormStructure(false).sections.some(function (section) {
return section.name === 'Location';
})).toEqual(false);
});
});
}
);

View File

@@ -1,51 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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/creation/CreationPolicy"],
function (CreationPolicy) {
describe("The creation policy", function () {
var mockType,
policy;
beforeEach(function () {
mockType = jasmine.createSpyObj(
'type',
['hasFeature']
);
policy = new CreationPolicy();
});
it("allows creation of types with the creation feature", function () {
mockType.hasFeature.and.returnValue(true);
expect(policy.allow(mockType)).toBeTruthy();
});
it("disallows creation of types without the creation feature", function () {
mockType.hasFeature.and.returnValue(false);
expect(policy.allow(mockType)).toBeFalsy();
});
});
}
);

View File

@@ -1,216 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
/**
* MCTRepresentationSpec. Created by vwoeltje on 11/6/14.
*/
define(
["../../src/creation/CreationService"],
function (CreationService) {
describe("The creation service", function () {
var mockQ,
mockLog,
mockParentObject,
mockNewObject,
mockMutationCapability,
mockPersistenceCapability,
mockCompositionCapability,
mockContextCapability,
mockCreationCapability,
mockCapabilities,
mockNewPersistenceCapability,
creationService;
function mockPromise(value) {
return (value && value.then) ? value : {
then: function (callback) {
return mockPromise(callback(value));
}
};
}
function mockReject(value) {
return {
then: function (callback, error) {
return mockPromise(error(value));
}
};
}
beforeEach(function () {
mockQ = {
when: mockPromise,
reject: mockReject
};
mockLog = jasmine.createSpyObj(
"$log",
["error", "warn", "info", "debug"]
);
mockParentObject = jasmine.createSpyObj(
"parentObject",
["getId", "getCapability", "useCapability"]
);
mockNewObject = jasmine.createSpyObj(
"newObject",
["getId", "getCapability", "useCapability"]
);
mockMutationCapability = jasmine.createSpyObj(
"mutation",
["invoke"]
);
mockPersistenceCapability = jasmine.createSpyObj(
"persistence",
["persist", "getSpace"]
);
mockCompositionCapability = jasmine.createSpyObj(
"composition",
["invoke", "add"]
);
mockContextCapability = jasmine.createSpyObj(
"context",
["getPath"]
);
mockCreationCapability = jasmine.createSpyObj(
"creation",
["instantiate", "invoke"]
);
mockCapabilities = {
mutation: mockMutationCapability,
persistence: mockPersistenceCapability,
composition: mockCompositionCapability,
context: mockContextCapability,
instantiation: mockCreationCapability
};
mockNewPersistenceCapability = jasmine.createSpyObj(
"new-persistence",
["persist", "getSpace"]
);
mockParentObject.getCapability.and.callFake(function (key) {
return mockCapabilities[key];
});
mockParentObject.useCapability.and.callFake(function (key, value) {
return mockCapabilities[key].invoke(value);
});
mockParentObject.getId.and.returnValue('parentId');
mockNewObject.getId.and.returnValue('newId');
mockNewObject.getCapability.and.callFake(function (c) {
return c === 'persistence'
? mockNewPersistenceCapability : undefined;
});
mockPersistenceCapability.persist
.and.returnValue(mockPromise(true));
mockNewPersistenceCapability.persist
.and.returnValue(mockPromise(true));
mockMutationCapability.invoke.and.returnValue(mockPromise(true));
mockPersistenceCapability.getSpace.and.returnValue("testSpace");
mockCompositionCapability.invoke.and.returnValue(
mockPromise([mockNewObject])
);
mockCompositionCapability.add.and.returnValue(mockPromise(true));
mockCreationCapability.instantiate.and.returnValue(mockNewObject);
mockCreationCapability.invoke.and.callFake(function (model) {
return mockCreationCapability.instantiate(model);
});
creationService = new CreationService(
mockQ,
mockLog
);
});
it("allows new objects to be created", function () {
var model = { someKey: "some value" };
creationService.createObject(model, mockParentObject);
expect(mockCreationCapability.instantiate)
.toHaveBeenCalledWith(model);
});
it("adds new objects to the parent's composition", function () {
var model = { someKey: "some value" };
creationService.createObject(model, mockParentObject);
// Verify that a new ID was added
expect(mockCompositionCapability.add)
.toHaveBeenCalledWith(mockNewObject);
});
it("provides the newly-created object", function () {
var mockDomainObject = jasmine.createSpyObj(
'newDomainObject',
['getId', 'getModel', 'getCapability']
),
mockCallback = jasmine.createSpy('callback');
// Act as if the object had been created
mockCompositionCapability.add.and.callFake(function (id) {
mockDomainObject.getId.and.returnValue(id);
mockCompositionCapability.invoke
.and.returnValue(mockPromise([mockDomainObject]));
return mockPromise(mockDomainObject);
});
// Should find it in the composition
creationService.createObject({}, mockParentObject)
.then(mockCallback);
expect(mockCallback).toHaveBeenCalledWith(mockDomainObject);
});
it("warns if parent has no persistence capability", function () {
// Callbacks
var success = jasmine.createSpy("success"),
failure = jasmine.createSpy("failure");
mockCapabilities.persistence = undefined;
creationService.createObject({}, mockParentObject).then(
success,
failure
);
// Should have warned and rejected the promise
expect(mockLog.warn).toHaveBeenCalled();
expect(success).not.toHaveBeenCalled();
expect(failure).toHaveBeenCalled();
});
it("logs an error when mutation fails", function () {
// If mutation of the parent fails, we've lost the
// created object - this is an error.
var model = { someKey: "some value" };
mockCompositionCapability.add.and.returnValue(mockPromise(false));
creationService.createObject(model, mockParentObject);
expect(mockLog.error).toHaveBeenCalled();
});
});
}
);

View File

@@ -1,171 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2021, 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.
*****************************************************************************/
/**
* MCTRepresentationSpec. Created by vwoeltje on 11/6/14.
*/
define(
["../../src/creation/LocatorController"],
function (LocatorController) {
describe("The locator controller", function () {
var mockScope,
mockTimeout,
mockDomainObject,
mockRootObject,
mockContext,
mockObjectService,
getObjectsPromise,
controller;
beforeEach(function () {
mockScope = jasmine.createSpyObj(
"$scope",
["$watch"]
);
mockTimeout = jasmine.createSpy("$timeout");
mockDomainObject = jasmine.createSpyObj(
"domainObject",
["getCapability"]
);
mockRootObject = jasmine.createSpyObj(
"rootObject",
["getCapability"]
);
mockContext = jasmine.createSpyObj(
"context",
["getRoot"]
);
mockObjectService = jasmine.createSpyObj(
"objectService",
["getObjects"]
);
getObjectsPromise = jasmine.createSpyObj(
"promise",
["then"]
);
mockDomainObject.getCapability.and.returnValue(mockContext);
mockContext.getRoot.and.returnValue(mockRootObject);
mockObjectService.getObjects.and.returnValue(getObjectsPromise);
mockScope.ngModel = {};
mockScope.field = "someField";
controller = new LocatorController(mockScope, mockTimeout, mockObjectService);
});
describe("when context is available", function () {
beforeEach(function () {
mockContext.getRoot.and.returnValue(mockRootObject);
controller = new LocatorController(mockScope, mockTimeout, mockObjectService);
});
it("adds a treeModel to scope", function () {
expect(mockScope.treeModel).toBeDefined();
});
it("watches for changes to treeModel", function () {
// This is what the embedded tree representation
// will be modifying.
expect(mockScope.$watch).toHaveBeenCalledWith(
"treeModel.selectedObject",
jasmine.any(Function)
);
});
it("changes its own model on embedded model updates", function () {
// Need to pass on selection changes as updates to
// the control's value
mockScope.$watch.calls.mostRecent().args[1](mockDomainObject);
mockTimeout.calls.mostRecent().args[0]();
expect(mockScope.ngModel.someField).toEqual(mockDomainObject);
expect(mockScope.rootObject).toEqual(mockRootObject);
// Verify that the capability we expect to have been used
// was used.
expect(mockDomainObject.getCapability)
.toHaveBeenCalledWith("context");
});
it("rejects changes which fail validation", function () {
mockScope.structure = { validate: jasmine.createSpy('validate') };
mockScope.structure.validate.and.returnValue(false);
// Pass selection change
mockScope.$watch.calls.mostRecent().args[1](mockDomainObject);
mockTimeout.calls.mostRecent().args[0]();
expect(mockScope.structure.validate).toHaveBeenCalled();
// Change should have been rejected
expect(mockScope.ngModel.someField).not.toEqual(mockDomainObject);
});
it("treats a lack of a selection as invalid", function () {
mockScope.ngModelController = jasmine.createSpyObj(
'ngModelController',
['$setValidity']
);
mockScope.$watch.calls.mostRecent().args[1](mockDomainObject);
mockTimeout.calls.mostRecent().args[0]();
expect(mockScope.ngModelController.$setValidity)
.toHaveBeenCalledWith(jasmine.any(String), true);
mockScope.$watch.calls.mostRecent().args[1](undefined);
mockTimeout.calls.mostRecent().args[0]();
expect(mockScope.ngModelController.$setValidity)
.toHaveBeenCalledWith(jasmine.any(String), false);
});
});
describe("when no context is available", function () {
var defaultRoot = "DEFAULT_ROOT";
beforeEach(function () {
mockContext.getRoot.and.returnValue(undefined);
getObjectsPromise.then.and.callFake(function (callback) {
callback({'ROOT': defaultRoot});
});
controller = new LocatorController(mockScope, mockTimeout, mockObjectService);
});
it("provides a default context where none is available", function () {
mockScope.$watch.calls.mostRecent().args[1](mockDomainObject);
mockTimeout.calls.mostRecent().args[0]();
expect(mockScope.rootObject).toBe(defaultRoot);
});
it("does not issue redundant requests for the root object", function () {
mockScope.$watch.calls.mostRecent().args[1](mockDomainObject);
mockTimeout.calls.mostRecent().args[0]();
mockScope.$watch.calls.mostRecent().args[1](undefined);
mockTimeout.calls.mostRecent().args[0]();
mockScope.$watch.calls.mostRecent().args[1](mockDomainObject);
mockTimeout.calls.mostRecent().args[0]();
expect(mockObjectService.getObjects.calls.count())
.toEqual(1);
});
});
});
}
);