mirror of
https://github.com/nasa/openmct.git
synced 2024-12-24 15:26:39 +00:00
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:
parent
e20c7a17d6
commit
8acbcadd5d
@ -106,7 +106,7 @@ module.exports = (config) => {
|
|||||||
},
|
},
|
||||||
specReporter: {
|
specReporter: {
|
||||||
maxLogLines: 5,
|
maxLogLines: 5,
|
||||||
suppressErrorSummary: true,
|
suppressErrorSummary: false,
|
||||||
suppressFailed: false,
|
suppressFailed: false,
|
||||||
suppressPassed: false,
|
suppressPassed: false,
|
||||||
suppressSkipped: true,
|
suppressSkipped: true,
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
at runtime from the About dialog for additional information.
|
at runtime from the About dialog for additional information.
|
||||||
-->
|
-->
|
||||||
<mct-container key="c-overlay__contents">
|
<mct-container key="c-overlay__contents">
|
||||||
<div class=c-overlay__top-bar">
|
<div class="c-overlay__top-bar">
|
||||||
<div class="c-overlay__dialog-title">{{ngModel.dialog.title}}</div>
|
<div class="c-overlay__dialog-title">{{ngModel.dialog.title}}</div>
|
||||||
<div class="c-overlay__dialog-hint hint">{{ngModel.dialog.hint}}</div>
|
<div class="c-overlay__dialog-hint hint">{{ngModel.dialog.hint}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -26,22 +26,12 @@ define([
|
|||||||
"./src/controllers/EditObjectController",
|
"./src/controllers/EditObjectController",
|
||||||
"./src/actions/EditAndComposeAction",
|
"./src/actions/EditAndComposeAction",
|
||||||
"./src/actions/EditAction",
|
"./src/actions/EditAction",
|
||||||
"./src/actions/PropertiesAction",
|
|
||||||
"./src/actions/SaveAction",
|
"./src/actions/SaveAction",
|
||||||
"./src/actions/SaveAndStopEditingAction",
|
"./src/actions/SaveAndStopEditingAction",
|
||||||
"./src/actions/SaveAsAction",
|
|
||||||
"./src/actions/CancelAction",
|
"./src/actions/CancelAction",
|
||||||
"./src/policies/EditPersistableObjectsPolicy",
|
"./src/policies/EditPersistableObjectsPolicy",
|
||||||
"./src/representers/EditRepresenter",
|
"./src/representers/EditRepresenter",
|
||||||
"./src/capabilities/EditorCapability",
|
"./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/library.html",
|
||||||
"./res/templates/edit-object.html",
|
"./res/templates/edit-object.html",
|
||||||
"./res/templates/edit-action-buttons.html",
|
"./res/templates/edit-action-buttons.html",
|
||||||
@ -52,22 +42,12 @@ define([
|
|||||||
EditObjectController,
|
EditObjectController,
|
||||||
EditAndComposeAction,
|
EditAndComposeAction,
|
||||||
EditAction,
|
EditAction,
|
||||||
PropertiesAction,
|
|
||||||
SaveAction,
|
SaveAction,
|
||||||
SaveAndStopEditingAction,
|
SaveAndStopEditingAction,
|
||||||
SaveAsAction,
|
|
||||||
CancelAction,
|
CancelAction,
|
||||||
EditPersistableObjectsPolicy,
|
EditPersistableObjectsPolicy,
|
||||||
EditRepresenter,
|
EditRepresenter,
|
||||||
EditorCapability,
|
EditorCapability,
|
||||||
CreateMenuController,
|
|
||||||
LocatorController,
|
|
||||||
CreationPolicy,
|
|
||||||
CreateActionProvider,
|
|
||||||
CreationService,
|
|
||||||
locatorTemplate,
|
|
||||||
createButtonTemplate,
|
|
||||||
createMenuTemplate,
|
|
||||||
libraryTemplate,
|
libraryTemplate,
|
||||||
editObjectTemplate,
|
editObjectTemplate,
|
||||||
editActionButtonsTemplate,
|
editActionButtonsTemplate,
|
||||||
@ -100,22 +80,6 @@ define([
|
|||||||
"$location",
|
"$location",
|
||||||
"navigationService"
|
"navigationService"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "CreateMenuController",
|
|
||||||
"implementation": CreateMenuController,
|
|
||||||
"depends": [
|
|
||||||
"$scope"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "LocatorController",
|
|
||||||
"implementation": LocatorController,
|
|
||||||
"depends": [
|
|
||||||
"$scope",
|
|
||||||
"$timeout",
|
|
||||||
"objectService"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"actions": [
|
"actions": [
|
||||||
@ -137,22 +101,6 @@ define([
|
|||||||
"group": "action",
|
"group": "action",
|
||||||
"priority": 10
|
"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",
|
"key": "save-and-stop-editing",
|
||||||
"category": "save",
|
"category": "save",
|
||||||
@ -177,22 +125,6 @@ define([
|
|||||||
"notificationService"
|
"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",
|
"key": "cancel",
|
||||||
"category": "conclude-editing",
|
"category": "conclude-editing",
|
||||||
@ -210,10 +142,6 @@ define([
|
|||||||
"category": "action",
|
"category": "action",
|
||||||
"implementation": EditPersistableObjectsPolicy,
|
"implementation": EditPersistableObjectsPolicy,
|
||||||
"depends": ["openmct"]
|
"depends": ["openmct"]
|
||||||
},
|
|
||||||
{
|
|
||||||
"implementation": CreationPolicy,
|
|
||||||
"category": "creation"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"templates": [
|
"templates": [
|
||||||
@ -243,42 +171,8 @@ define([
|
|||||||
{
|
{
|
||||||
"key": "topbar-edit",
|
"key": "topbar-edit",
|
||||||
"template": topbarEditTemplate
|
"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": [
|
"representers": [
|
||||||
{
|
{
|
||||||
"implementation": EditRepresenter,
|
"implementation": EditRepresenter,
|
||||||
@ -298,12 +192,6 @@ define([
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"controls": [
|
|
||||||
{
|
|
||||||
"key": "locator",
|
|
||||||
"template": locatorTemplate
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"runs": [
|
"runs": [
|
||||||
{
|
{
|
||||||
depends: [
|
depends: [
|
||||||
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
);
|
|
@ -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;
|
|
||||||
}
|
|
||||||
);
|
|
@ -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;
|
|
||||||
}
|
|
||||||
);
|
|
@ -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;
|
|
||||||
}
|
|
||||||
);
|
|
@ -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;
|
|
||||||
}
|
|
||||||
);
|
|
@ -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;
|
|
||||||
}
|
|
||||||
);
|
|
@ -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;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
@ -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();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -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
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -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();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -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]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -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();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -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");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -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);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -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();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -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);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -21,25 +21,21 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define([
|
define([
|
||||||
"./src/actions/LinkAction",
|
|
||||||
"./src/actions/SetPrimaryLocationAction",
|
"./src/actions/SetPrimaryLocationAction",
|
||||||
"./src/services/LocatingCreationDecorator",
|
"./src/services/LocatingCreationDecorator",
|
||||||
"./src/services/LocatingObjectDecorator",
|
"./src/services/LocatingObjectDecorator",
|
||||||
"./src/policies/CopyPolicy",
|
"./src/policies/CopyPolicy",
|
||||||
"./src/policies/CrossSpacePolicy",
|
"./src/policies/CrossSpacePolicy",
|
||||||
"./src/capabilities/LocationCapability",
|
"./src/capabilities/LocationCapability",
|
||||||
"./src/services/LinkService",
|
|
||||||
"./src/services/CopyService",
|
"./src/services/CopyService",
|
||||||
"./src/services/LocationService"
|
"./src/services/LocationService"
|
||||||
], function (
|
], function (
|
||||||
LinkAction,
|
|
||||||
SetPrimaryLocationAction,
|
SetPrimaryLocationAction,
|
||||||
LocatingCreationDecorator,
|
LocatingCreationDecorator,
|
||||||
LocatingObjectDecorator,
|
LocatingObjectDecorator,
|
||||||
CopyPolicy,
|
CopyPolicy,
|
||||||
CrossSpacePolicy,
|
CrossSpacePolicy,
|
||||||
LocationCapability,
|
LocationCapability,
|
||||||
LinkService,
|
|
||||||
CopyService,
|
CopyService,
|
||||||
LocationService
|
LocationService
|
||||||
) {
|
) {
|
||||||
@ -52,21 +48,6 @@ define([
|
|||||||
"configuration": {},
|
"configuration": {},
|
||||||
"extensions": {
|
"extensions": {
|
||||||
"actions": [
|
"actions": [
|
||||||
{
|
|
||||||
"key": "link",
|
|
||||||
"name": "Create Link",
|
|
||||||
"description": "Create Link to object in another location.",
|
|
||||||
"cssClass": "icon-link",
|
|
||||||
"category": "contextual",
|
|
||||||
"group": "action",
|
|
||||||
"priority": 7,
|
|
||||||
"implementation": LinkAction,
|
|
||||||
"depends": [
|
|
||||||
"policyService",
|
|
||||||
"locationService",
|
|
||||||
"linkService"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"key": "locate",
|
"key": "locate",
|
||||||
"name": "Set Primary Location",
|
"name": "Set Primary Location",
|
||||||
@ -115,15 +96,6 @@ define([
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"services": [
|
"services": [
|
||||||
{
|
|
||||||
"key": "linkService",
|
|
||||||
"name": "Link Service",
|
|
||||||
"description": "Provides a service for linking objects",
|
|
||||||
"implementation": LinkService,
|
|
||||||
"depends": [
|
|
||||||
"openmct"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"key": "copyService",
|
"key": "copyService",
|
||||||
"name": "Copy Service",
|
"name": "Copy Service",
|
||||||
|
@ -1,71 +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 () {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LinkService provides an interface for linking objects to additional
|
|
||||||
* locations. It also provides a method for determining if an object
|
|
||||||
* can be copied to a specific location.
|
|
||||||
* @constructor
|
|
||||||
* @memberof platform/entanglement
|
|
||||||
* @implements {platform/entanglement.AbstractComposeService}
|
|
||||||
*/
|
|
||||||
function LinkService(openmct) {
|
|
||||||
this.openmct = openmct;
|
|
||||||
}
|
|
||||||
|
|
||||||
LinkService.prototype.validate = function (object, parentCandidate) {
|
|
||||||
if (!parentCandidate || !parentCandidate.getId) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parentCandidate.getId() === object.getId()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!parentCandidate.hasCapability('composition')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.openmct.composition.checkPolicy(parentCandidate.useCapability('adapter'), object.useCapability('adapter'));
|
|
||||||
};
|
|
||||||
|
|
||||||
LinkService.prototype.perform = function (object, parentObject) {
|
|
||||||
if (!this.validate(object, parentObject)) {
|
|
||||||
throw new Error(
|
|
||||||
"Tried to link objects without validating first."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return parentObject.getCapability('composition').add(object);
|
|
||||||
};
|
|
||||||
|
|
||||||
return LinkService;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
@ -1,178 +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/LinkAction',
|
|
||||||
'../services/MockLinkService',
|
|
||||||
'../DomainObjectFactory'
|
|
||||||
],
|
|
||||||
function (LinkAction, MockLinkService, domainObjectFactory) {
|
|
||||||
|
|
||||||
describe("Link Action", function () {
|
|
||||||
|
|
||||||
var linkAction,
|
|
||||||
policyService,
|
|
||||||
locationService,
|
|
||||||
locationServicePromise,
|
|
||||||
linkService,
|
|
||||||
context,
|
|
||||||
selectedObject,
|
|
||||||
selectedObjectContextCapability,
|
|
||||||
currentParent,
|
|
||||||
newParent;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
policyService = jasmine.createSpyObj(
|
|
||||||
'policyService',
|
|
||||||
['allow']
|
|
||||||
);
|
|
||||||
policyService.allow.and.returnValue(true);
|
|
||||||
|
|
||||||
selectedObjectContextCapability = jasmine.createSpyObj(
|
|
||||||
'selectedObjectContextCapability',
|
|
||||||
[
|
|
||||||
'getParent'
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
selectedObject = domainObjectFactory({
|
|
||||||
name: 'selectedObject',
|
|
||||||
model: {
|
|
||||||
name: 'selectedObject'
|
|
||||||
},
|
|
||||||
capabilities: {
|
|
||||||
context: selectedObjectContextCapability
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
currentParent = domainObjectFactory({
|
|
||||||
name: 'currentParent'
|
|
||||||
});
|
|
||||||
|
|
||||||
selectedObjectContextCapability
|
|
||||||
.getParent
|
|
||||||
.and.returnValue(currentParent);
|
|
||||||
|
|
||||||
newParent = domainObjectFactory({
|
|
||||||
name: 'newParent'
|
|
||||||
});
|
|
||||||
|
|
||||||
locationService = jasmine.createSpyObj(
|
|
||||||
'locationService',
|
|
||||||
[
|
|
||||||
'getLocationFromUser'
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
locationServicePromise = jasmine.createSpyObj(
|
|
||||||
'locationServicePromise',
|
|
||||||
[
|
|
||||||
'then'
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
locationService
|
|
||||||
.getLocationFromUser
|
|
||||||
.and.returnValue(locationServicePromise);
|
|
||||||
|
|
||||||
linkService = new MockLinkService();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("with context from context-action", function () {
|
|
||||||
beforeEach(function () {
|
|
||||||
context = {
|
|
||||||
domainObject: selectedObject
|
|
||||||
};
|
|
||||||
|
|
||||||
linkAction = new LinkAction(
|
|
||||||
policyService,
|
|
||||||
locationService,
|
|
||||||
linkService,
|
|
||||||
context
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("initializes happily", function () {
|
|
||||||
expect(linkAction).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("when performed it", function () {
|
|
||||||
beforeEach(function () {
|
|
||||||
linkAction.perform();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("prompts for location", function () {
|
|
||||||
expect(locationService.getLocationFromUser)
|
|
||||||
.toHaveBeenCalledWith(
|
|
||||||
"Link selectedObject To a New Location",
|
|
||||||
"Link To",
|
|
||||||
jasmine.any(Function),
|
|
||||||
currentParent
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("waits for location and handles cancellation by user", function () {
|
|
||||||
expect(locationServicePromise.then)
|
|
||||||
.toHaveBeenCalledWith(jasmine.any(Function), jasmine.any(Function));
|
|
||||||
});
|
|
||||||
|
|
||||||
it("links object to selected location", function () {
|
|
||||||
locationServicePromise
|
|
||||||
.then
|
|
||||||
.calls.mostRecent()
|
|
||||||
.args[0](newParent);
|
|
||||||
|
|
||||||
expect(linkService.perform)
|
|
||||||
.toHaveBeenCalledWith(selectedObject, newParent);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("with context from drag-drop", function () {
|
|
||||||
beforeEach(function () {
|
|
||||||
context = {
|
|
||||||
selectedObject: selectedObject,
|
|
||||||
domainObject: newParent
|
|
||||||
};
|
|
||||||
|
|
||||||
linkAction = new LinkAction(
|
|
||||||
policyService,
|
|
||||||
locationService,
|
|
||||||
linkService,
|
|
||||||
context
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("initializes happily", function () {
|
|
||||||
expect(linkAction).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("performs link immediately", function () {
|
|
||||||
linkAction.perform();
|
|
||||||
expect(linkService.perform)
|
|
||||||
.toHaveBeenCalledWith(selectedObject, newParent);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,215 +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/services/LinkService',
|
|
||||||
'../DomainObjectFactory',
|
|
||||||
'../ControlledPromise'
|
|
||||||
],
|
|
||||||
function (LinkService, domainObjectFactory, ControlledPromise) {
|
|
||||||
|
|
||||||
xdescribe("LinkService", function () {
|
|
||||||
|
|
||||||
var linkService,
|
|
||||||
mockPolicyService;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockPolicyService = jasmine.createSpyObj(
|
|
||||||
'policyService',
|
|
||||||
['allow']
|
|
||||||
);
|
|
||||||
mockPolicyService.allow.and.returnValue(true);
|
|
||||||
linkService = new LinkService(mockPolicyService);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("validate", function () {
|
|
||||||
|
|
||||||
var object,
|
|
||||||
parentCandidate,
|
|
||||||
validate;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
object = domainObjectFactory({
|
|
||||||
name: 'object'
|
|
||||||
});
|
|
||||||
parentCandidate = domainObjectFactory({
|
|
||||||
name: 'parentCandidate',
|
|
||||||
capabilities: {
|
|
||||||
composition: jasmine.createSpyObj(
|
|
||||||
'composition',
|
|
||||||
['invoke', 'add']
|
|
||||||
)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
validate = function () {
|
|
||||||
return linkService.validate(object, parentCandidate);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not allow invalid parentCandidate", function () {
|
|
||||||
parentCandidate = undefined;
|
|
||||||
expect(validate()).toBe(false);
|
|
||||||
parentCandidate = {};
|
|
||||||
expect(validate()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not allow parent to be object", function () {
|
|
||||||
parentCandidate.id = object.id = 'abc';
|
|
||||||
expect(validate()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not allow parent that contains object", function () {
|
|
||||||
object.id = 'abc';
|
|
||||||
parentCandidate.id = 'xyz';
|
|
||||||
parentCandidate.model.composition = ['abc'];
|
|
||||||
expect(validate()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not allow parents without composition", function () {
|
|
||||||
parentCandidate = domainObjectFactory({
|
|
||||||
name: 'parentCandidate'
|
|
||||||
});
|
|
||||||
object.id = 'abc';
|
|
||||||
parentCandidate.id = 'xyz';
|
|
||||||
parentCandidate.hasCapability.and.callFake(function (c) {
|
|
||||||
return c !== 'composition';
|
|
||||||
});
|
|
||||||
expect(validate()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("defers to policyService", function () {
|
|
||||||
beforeEach(function () {
|
|
||||||
object.id = 'abc';
|
|
||||||
object.capabilities.type = { type: 'object' };
|
|
||||||
parentCandidate.id = 'xyz';
|
|
||||||
parentCandidate.capabilities.type = {
|
|
||||||
type: 'parentCandidate'
|
|
||||||
};
|
|
||||||
parentCandidate.model.composition = [];
|
|
||||||
});
|
|
||||||
|
|
||||||
it("calls policy service with correct args", function () {
|
|
||||||
validate();
|
|
||||||
expect(mockPolicyService.allow).toHaveBeenCalledWith(
|
|
||||||
"composition",
|
|
||||||
parentCandidate,
|
|
||||||
object
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("and returns false", function () {
|
|
||||||
mockPolicyService.allow.and.returnValue(true);
|
|
||||||
expect(validate()).toBe(true);
|
|
||||||
expect(mockPolicyService.allow).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("and returns true", function () {
|
|
||||||
mockPolicyService.allow.and.returnValue(false);
|
|
||||||
expect(validate()).toBe(false);
|
|
||||||
expect(mockPolicyService.allow).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("perform", function () {
|
|
||||||
|
|
||||||
var object,
|
|
||||||
linkedObject,
|
|
||||||
parentModel,
|
|
||||||
parentObject,
|
|
||||||
compositionPromise,
|
|
||||||
addPromise,
|
|
||||||
compositionCapability;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
compositionPromise = new ControlledPromise();
|
|
||||||
addPromise = new ControlledPromise();
|
|
||||||
compositionCapability = jasmine.createSpyObj(
|
|
||||||
'compositionCapability',
|
|
||||||
['invoke', 'add']
|
|
||||||
);
|
|
||||||
compositionCapability.invoke.and.returnValue(compositionPromise);
|
|
||||||
compositionCapability.add.and.returnValue(addPromise);
|
|
||||||
parentModel = {
|
|
||||||
composition: []
|
|
||||||
};
|
|
||||||
parentObject = domainObjectFactory({
|
|
||||||
name: 'parentObject',
|
|
||||||
model: parentModel,
|
|
||||||
capabilities: {
|
|
||||||
mutation: {
|
|
||||||
invoke: function (mutator) {
|
|
||||||
mutator(parentModel);
|
|
||||||
|
|
||||||
return new ControlledPromise();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
composition: compositionCapability
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
object = domainObjectFactory({
|
|
||||||
name: 'object',
|
|
||||||
id: 'xyz'
|
|
||||||
});
|
|
||||||
|
|
||||||
linkedObject = domainObjectFactory({
|
|
||||||
name: 'object-link',
|
|
||||||
id: 'xyz'
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it("adds to the parent's composition", function () {
|
|
||||||
expect(compositionCapability.add).not.toHaveBeenCalled();
|
|
||||||
linkService.perform(object, parentObject);
|
|
||||||
expect(compositionCapability.add)
|
|
||||||
.toHaveBeenCalledWith(object);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns object representing new link", function () {
|
|
||||||
var returnPromise, whenComplete;
|
|
||||||
returnPromise = linkService.perform(object, parentObject);
|
|
||||||
whenComplete = jasmine.createSpy('whenComplete');
|
|
||||||
returnPromise.then(whenComplete);
|
|
||||||
|
|
||||||
addPromise.resolve(linkedObject);
|
|
||||||
compositionPromise.resolve([linkedObject]);
|
|
||||||
expect(whenComplete).toHaveBeenCalledWith(linkedObject);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("throws an error when performed on invalid inputs", function () {
|
|
||||||
function perform() {
|
|
||||||
linkService.perform(object, parentObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
spyOn(linkService, 'validate');
|
|
||||||
linkService.validate.and.returnValue(true);
|
|
||||||
expect(perform).not.toThrow();
|
|
||||||
linkService.validate.and.returnValue(false);
|
|
||||||
expect(perform).toThrow();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,133 +0,0 @@
|
|||||||
# Overview
|
|
||||||
|
|
||||||
This bundle contains a general implementation of forms in Open MCT.
|
|
||||||
This allows forms to be expressed using a reasonably concise declarative
|
|
||||||
syntax, and rendered as Angular templates in a consistent fashion.
|
|
||||||
|
|
||||||
# Usage
|
|
||||||
|
|
||||||
To include a form with a declarative definition, use the `mct-form`
|
|
||||||
directive, e.g.:
|
|
||||||
|
|
||||||
<mct-form ng-model="myModel" structure="myStructure" name="myForm">
|
|
||||||
</mct-form>
|
|
||||||
|
|
||||||
Using toolbars is similar:
|
|
||||||
|
|
||||||
<mct-toolbar ng-model="myModel" structure="myStructure" name="myToolbar">
|
|
||||||
</mct-toolbar>
|
|
||||||
|
|
||||||
The attributes utilized by this form are as follows:
|
|
||||||
|
|
||||||
* `ng-model`: The object which should contain the full form input. Individual
|
|
||||||
fields in this model are bound to individual controls; the names used for
|
|
||||||
these fields are provided in the form structure (see below).
|
|
||||||
* `structure`: The structure of the form; e.g. sections, rows, their names,
|
|
||||||
and so forth. The value of this attribute should be an Angular expression.
|
|
||||||
* `name`: The name in the containing scope under which to publish form
|
|
||||||
"meta-state", e.g. `$valid`, `$dirty`, etc. This is as the behavior of
|
|
||||||
`ng-form`. Passed as plain text in the attribute.
|
|
||||||
|
|
||||||
## Form structure
|
|
||||||
|
|
||||||
A form's structure is described as a JavaScript object in the following form:
|
|
||||||
|
|
||||||
{
|
|
||||||
"name": ... title to display for the form, as a string ...,
|
|
||||||
"sections": [
|
|
||||||
{
|
|
||||||
"name": ... title to display for the section ...,
|
|
||||||
"rows": [
|
|
||||||
{
|
|
||||||
"name": ... title to display for this row ...,
|
|
||||||
"control": ... symbolic key for the control ...,
|
|
||||||
"key": ... field name in ng-model ...
|
|
||||||
"pattern": ... optional, reg exp to match against ...
|
|
||||||
"required": ... optional boolean ...
|
|
||||||
"options": [
|
|
||||||
"name": ... name to display (e.g. in a select) ...,
|
|
||||||
"value": ... value to store in the model ...
|
|
||||||
]
|
|
||||||
},
|
|
||||||
... and other rows ...
|
|
||||||
]
|
|
||||||
},
|
|
||||||
... and other sections ...
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
Note that `pattern` may be specified as a string, to simplify storing
|
|
||||||
for structures as JSON when necessary. The string should be given in
|
|
||||||
a form appropriate to pass to a `RegExp` constructor.
|
|
||||||
|
|
||||||
## Toolbar structure
|
|
||||||
|
|
||||||
A toolbar's structure is described similarly to forms, except that there
|
|
||||||
is no notion of rows; instead, there are `items`.
|
|
||||||
|
|
||||||
{
|
|
||||||
"name": ... title to display for the form, as a string ...,
|
|
||||||
"sections": [
|
|
||||||
{
|
|
||||||
"name": ... title to display for the section ...,
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": ... title to display for this row ...,
|
|
||||||
"control": ... symbolic key for the control ...,
|
|
||||||
"key": ... field name in ng-model ...
|
|
||||||
"pattern": ... optional, reg exp to match against ...
|
|
||||||
"required": ... optional boolean ...
|
|
||||||
"options": [
|
|
||||||
"name": ... name to display (e.g. in a select) ...,
|
|
||||||
"value": ... value to store in the model ...
|
|
||||||
],
|
|
||||||
"disabled": ... true if control should be disabled ...
|
|
||||||
"size": ... size of the control (for textfields) ...
|
|
||||||
"click": ... function to invoke (for buttons) ...
|
|
||||||
"glyph": ... glyph to display (for buttons) ...
|
|
||||||
"text": ... text withiin control (for buttons) ...
|
|
||||||
},
|
|
||||||
... and other rows ...
|
|
||||||
]
|
|
||||||
},
|
|
||||||
... and other sections ...
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
Note that `pattern` may be specified as a string, to simplify storing
|
|
||||||
for structures as JSON when necessary. The string should be given in
|
|
||||||
a form appropriate to pass to a `RegExp` constructor.
|
|
||||||
|
|
||||||
## Adding controls
|
|
||||||
|
|
||||||
These control types are included in the forms bundle:
|
|
||||||
|
|
||||||
* `textfield`: A text input to enter plain text.
|
|
||||||
* `numberfield`: A text input to enter numbers.
|
|
||||||
* `select`: A drop-down list of options.
|
|
||||||
* `checkbox`: A box which may be checked/unchecked.
|
|
||||||
* `color`: A color picker.
|
|
||||||
* `button`: A button.
|
|
||||||
* `datetime`: An input for UTC date/time entry; gives result as a
|
|
||||||
UNIX timestamp, in milliseconds since start of 1970, UTC.
|
|
||||||
|
|
||||||
New controls may be added as extensions of the `controls` category.
|
|
||||||
Extensions of this category have two properites:
|
|
||||||
|
|
||||||
* `key`: The symbolic name for this control (matched against the
|
|
||||||
`control` field in rows of the form structure).
|
|
||||||
* `templateUrl`: The URL to the control's Angular template, relative
|
|
||||||
to the resources directory of the bundle which exposes the extension.
|
|
||||||
|
|
||||||
Within the template for a control, the following variables will be
|
|
||||||
included in scope:
|
|
||||||
|
|
||||||
* `ngModel`: The model where form input will be stored. Notably we
|
|
||||||
also need to look at `field` (see below) to determine which field
|
|
||||||
in the model should be modified.
|
|
||||||
* `ngRequired`: True if input is required.
|
|
||||||
* `ngPattern`: The pattern to match against (for text entry.)
|
|
||||||
* `options`: The options for this control, as passed from the
|
|
||||||
`options` property of an individual row.
|
|
||||||
* `field`: Name of the field in `ngModel` which will hold the value
|
|
||||||
for this control.
|
|
@ -1,202 +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/MCTForm",
|
|
||||||
"./src/MCTControl",
|
|
||||||
"./src/MCTFileInput",
|
|
||||||
"./src/FileInputService",
|
|
||||||
"./src/controllers/AutocompleteController",
|
|
||||||
"./src/controllers/DateTimeController",
|
|
||||||
"./src/controllers/CompositeController",
|
|
||||||
"./src/controllers/ColorController",
|
|
||||||
"./src/controllers/DialogButtonController",
|
|
||||||
"./res/templates/controls/autocomplete.html",
|
|
||||||
"./res/templates/controls/checkbox.html",
|
|
||||||
"./res/templates/controls/datetime.html",
|
|
||||||
"./res/templates/controls/select.html",
|
|
||||||
"./res/templates/controls/textfield.html",
|
|
||||||
"./res/templates/controls/numberfield.html",
|
|
||||||
"./res/templates/controls/textarea.html",
|
|
||||||
"./res/templates/controls/button.html",
|
|
||||||
"./res/templates/controls/color.html",
|
|
||||||
"./res/templates/controls/composite.html",
|
|
||||||
"./res/templates/controls/menu-button.html",
|
|
||||||
"./res/templates/controls/dialog.html",
|
|
||||||
"./res/templates/controls/radio.html",
|
|
||||||
"./res/templates/controls/file-input.html"
|
|
||||||
], function (
|
|
||||||
MCTForm,
|
|
||||||
MCTControl,
|
|
||||||
MCTFileInput,
|
|
||||||
FileInputService,
|
|
||||||
AutocompleteController,
|
|
||||||
DateTimeController,
|
|
||||||
CompositeController,
|
|
||||||
ColorController,
|
|
||||||
DialogButtonController,
|
|
||||||
autocompleteTemplate,
|
|
||||||
checkboxTemplate,
|
|
||||||
datetimeTemplate,
|
|
||||||
selectTemplate,
|
|
||||||
textfieldTemplate,
|
|
||||||
numberfieldTemplate,
|
|
||||||
textareaTemplate,
|
|
||||||
buttonTemplate,
|
|
||||||
colorTemplate,
|
|
||||||
compositeTemplate,
|
|
||||||
menuButtonTemplate,
|
|
||||||
dialogTemplate,
|
|
||||||
radioTemplate,
|
|
||||||
fileInputTemplate
|
|
||||||
) {
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: "platform/forms",
|
|
||||||
definition: {
|
|
||||||
"name": "MCT Forms",
|
|
||||||
"description": "Form generator; includes directive and some controls.",
|
|
||||||
"extensions": {
|
|
||||||
"directives": [
|
|
||||||
{
|
|
||||||
"key": "mctForm",
|
|
||||||
"implementation": MCTForm
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "mctControl",
|
|
||||||
"implementation": MCTControl,
|
|
||||||
"depends": [
|
|
||||||
"templateLinker",
|
|
||||||
"controls[]"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "mctFileInput",
|
|
||||||
"implementation": MCTFileInput,
|
|
||||||
"depends": [
|
|
||||||
"fileInputService"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"controls": [
|
|
||||||
{
|
|
||||||
"key": "autocomplete",
|
|
||||||
"template": autocompleteTemplate
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "checkbox",
|
|
||||||
"template": checkboxTemplate
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "radio",
|
|
||||||
"template": radioTemplate
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "datetime",
|
|
||||||
"template": datetimeTemplate
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "select",
|
|
||||||
"template": selectTemplate
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "textfield",
|
|
||||||
"template": textfieldTemplate
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "numberfield",
|
|
||||||
"template": numberfieldTemplate
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "textarea",
|
|
||||||
"template": textareaTemplate
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "button",
|
|
||||||
"template": buttonTemplate
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "color",
|
|
||||||
"template": colorTemplate
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "composite",
|
|
||||||
"template": compositeTemplate
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "menu-button",
|
|
||||||
"template": menuButtonTemplate
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "dialog-button",
|
|
||||||
"template": dialogTemplate
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "file-input",
|
|
||||||
"template": fileInputTemplate
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"controllers": [
|
|
||||||
{
|
|
||||||
"key": "AutocompleteController",
|
|
||||||
"implementation": AutocompleteController,
|
|
||||||
"depends": [
|
|
||||||
"$scope",
|
|
||||||
"$element"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "DateTimeController",
|
|
||||||
"implementation": DateTimeController,
|
|
||||||
"depends": [
|
|
||||||
"$scope"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "CompositeController",
|
|
||||||
"implementation": CompositeController
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "ColorController",
|
|
||||||
"implementation": ColorController
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "DialogButtonController",
|
|
||||||
"implementation": DialogButtonController,
|
|
||||||
"depends": [
|
|
||||||
"$scope",
|
|
||||||
"dialogService"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"components": [
|
|
||||||
{
|
|
||||||
"provides": "fileInputService",
|
|
||||||
"type": "provider",
|
|
||||||
"implementation": FileInputService
|
|
||||||
}
|
|
||||||
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
@ -1,46 +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="AutocompleteController"
|
|
||||||
class='form-control autocomplete'>
|
|
||||||
<input class="autocompleteInput"
|
|
||||||
type="text"
|
|
||||||
ng-model="ngModel[field]"
|
|
||||||
ng-change="filterOptions(ngModel[field])"
|
|
||||||
ng-click="inputClicked()"
|
|
||||||
ng-keydown="keyDown($event)"/>
|
|
||||||
<span class="icon-arrow-down"
|
|
||||||
ng-click="arrowClicked()"></span>
|
|
||||||
<div class="autocompleteOptions"
|
|
||||||
ng-init="hideOptions = true"
|
|
||||||
ng-hide="hideOptions"
|
|
||||||
mct-click-elsewhere="hideOptions = true">
|
|
||||||
<ul>
|
|
||||||
<li ng-repeat="opt in filteredOptions"
|
|
||||||
ng-click="fillInput(opt.name)"
|
|
||||||
ng-mouseover="optionMouseover(opt.optionId)"
|
|
||||||
ng-class="optionIndex === opt.optionId ? 'optionPreSelected' : ''">
|
|
||||||
<span class="optionText">{{opt.name}}</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,28 +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.
|
|
||||||
-->
|
|
||||||
<a class="s-button {{structure.cssClass}}"
|
|
||||||
ng-class="{ labeled: structure.text }"
|
|
||||||
ng-click="structure.click()">
|
|
||||||
<span class="title-label" ng-if="structure.text">
|
|
||||||
{{structure.text}}
|
|
||||||
</span>
|
|
||||||
</a>
|
|
@ -1,28 +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.
|
|
||||||
-->
|
|
||||||
<label class="checkbox custom no-text">
|
|
||||||
<input type="checkbox"
|
|
||||||
name="mctControl"
|
|
||||||
ng-model="ngModel[field]"
|
|
||||||
ng-disabled="ngDisabled">
|
|
||||||
<em></em>
|
|
||||||
</label>
|
|
@ -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.
|
|
||||||
-->
|
|
||||||
<div class="s-button s-menu-button menu-element t-color-palette {{structure.cssClass}}"
|
|
||||||
ng-controller="ClickAwayController as toggle">
|
|
||||||
|
|
||||||
<span class="l-click-area" ng-click="toggle.toggle()"></span>
|
|
||||||
<span class="color-swatch"
|
|
||||||
ng-class="{'no-selection':ngModel[field] === 'transparent'}"
|
|
||||||
ng-style="{
|
|
||||||
'background-color': ngModel[field]
|
|
||||||
}">
|
|
||||||
</span>
|
|
||||||
<span class="title-label" ng-if="structure.text">
|
|
||||||
{{structure.text}}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<div class="menu l-palette l-color-palette"
|
|
||||||
ng-controller="ColorController as colors"
|
|
||||||
ng-show="toggle.isActive()">
|
|
||||||
<div
|
|
||||||
class="l-palette-row l-option-row"
|
|
||||||
ng-if="!structure.mandatory">
|
|
||||||
<div class="l-palette-item s-palette-item no-selection {{ngModel[field] === 'transparent' ? 'selected' : '' }}"
|
|
||||||
ng-click="ngModel[field] = 'transparent'">
|
|
||||||
</div>
|
|
||||||
<span class="l-palette-item-label">None</span>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="l-palette-row"
|
|
||||||
ng-repeat="group in colors.groups()">
|
|
||||||
<div class="l-palette-item s-palette-item {{ngModel[field] === color ? 'selected' : '' }}"
|
|
||||||
ng-repeat="color in group"
|
|
||||||
ng-style="{ background: color }"
|
|
||||||
ng-click="ngModel[field] = color">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,38 +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="CompositeController as compositeCtrl">
|
|
||||||
<ng-form name="mctFormItem" ng-repeat="item in structure.items">
|
|
||||||
<div class="l-composite-control l-{{item.control}} {{item.cssClass}}">
|
|
||||||
<mct-control key="item.control"
|
|
||||||
ng-model="ngModel[field]"
|
|
||||||
ng-required="ngRequired || compositeCtrl.isNonEmpty(ngModel[field])"
|
|
||||||
ng-pattern="ngPattern"
|
|
||||||
options="item.options"
|
|
||||||
structure="item"
|
|
||||||
field="$index">
|
|
||||||
</mct-control>
|
|
||||||
<span class="composite-control-label">
|
|
||||||
{{item.name}}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</ng-form>
|
|
||||||
</span>
|
|
@ -1,83 +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='form-control complex datetime'>
|
|
||||||
|
|
||||||
<div class='field-hints'>
|
|
||||||
<span class='hint date'>Date</span>
|
|
||||||
<span class='hint time sm'>Hour</span>
|
|
||||||
<span class='hint time sm'>Min</span>
|
|
||||||
<span class='hint time sm'>Sec</span>
|
|
||||||
<span class='hint timezone'>Timezone</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<ng-form name="mctControl">
|
|
||||||
<div class='fields' ng-controller="DateTimeController">
|
|
||||||
<span class='field control date'>
|
|
||||||
<input type='text'
|
|
||||||
name='date'
|
|
||||||
placeholder="{{format}}"
|
|
||||||
ng-pattern="/\d\d\d\d-\d\d-\d\d/"
|
|
||||||
ng-model='datetime.date'
|
|
||||||
ng-required='ngRequired || partiallyComplete'/>
|
|
||||||
</span>
|
|
||||||
<span class='field control time sm'>
|
|
||||||
<input type='text'
|
|
||||||
name='hour'
|
|
||||||
maxlength='2'
|
|
||||||
min='0'
|
|
||||||
max='23'
|
|
||||||
integer
|
|
||||||
ng-pattern='/\d+/'
|
|
||||||
ng-model="datetime.hour"
|
|
||||||
ng-required='ngRequired || partiallyComplete'/>
|
|
||||||
</span>
|
|
||||||
<span class='field control time sm'>
|
|
||||||
<input type='text'
|
|
||||||
name='min'
|
|
||||||
maxlength='2'
|
|
||||||
min='0'
|
|
||||||
max='59'
|
|
||||||
integer
|
|
||||||
ng-pattern='/\d+/'
|
|
||||||
ng-model="datetime.min"
|
|
||||||
ng-required='ngRequired || partiallyComplete'/>
|
|
||||||
</span>
|
|
||||||
<span class='field control time sm'>
|
|
||||||
<input type='text'
|
|
||||||
name='sec'
|
|
||||||
maxlength='2'
|
|
||||||
min='0'
|
|
||||||
max='59'
|
|
||||||
integer
|
|
||||||
ng-pattern='/\d+/'
|
|
||||||
ng-model="datetime.sec"
|
|
||||||
ng-required='ngRequired || partiallyComplete'/>
|
|
||||||
</span>
|
|
||||||
<span class='field control timezone'>
|
|
||||||
UTC
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</ng-form>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
@ -1,26 +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="DialogButtonController as dialog">
|
|
||||||
<mct-control key="'button'"
|
|
||||||
structure="dialog.getButtonStructure()">
|
|
||||||
</mct-control>
|
|
||||||
</span>
|
|
@ -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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<button class="c-button {{structure.cssClass}}"
|
|
||||||
ng-model="ngModel[field]"
|
|
||||||
ng-class="{ labeled: structure.text }"
|
|
||||||
mct-file-input>
|
|
||||||
<span class="c-button__label" ng-if="structure.text">
|
|
||||||
{{structure.text}}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
@ -1,39 +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="s-menu-button menu-element {{ structure.cssClass }}"
|
|
||||||
ng-controller="ClickAwayController as toggle">
|
|
||||||
|
|
||||||
<span class="l-click-area" ng-click="toggle.toggle()"></span>
|
|
||||||
<span class="title-label" ng-if="structure.text">
|
|
||||||
{{structure.text}}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<div class="menu" ng-show="toggle.isActive()">
|
|
||||||
<ul>
|
|
||||||
<li ng-click="structure.click(option.key); toggle.setState(false)"
|
|
||||||
ng-repeat="option in structure.options"
|
|
||||||
class="{{ option.cssClass }}">
|
|
||||||
{{option.name}}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,34 +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 class='form-control shell'>
|
|
||||||
<span class='field control {{structure.cssClass}}'>
|
|
||||||
<input type="number"
|
|
||||||
ng-required="ngRequired"
|
|
||||||
ng-model="ngModel[field]"
|
|
||||||
ng-blur="ngBlur()"
|
|
||||||
ng-pattern="ngPattern"
|
|
||||||
min="{{structure.min}}"
|
|
||||||
max="{{structure.max}}"
|
|
||||||
step="{{structure.step}}"
|
|
||||||
name="mctControl">
|
|
||||||
</span>
|
|
||||||
</span>
|
|
@ -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.
|
|
||||||
-->
|
|
||||||
<label class="radio custom no-text">
|
|
||||||
<input type="radio"
|
|
||||||
name="mctControl"
|
|
||||||
ng-model="ngModel[field]"
|
|
||||||
ng-disabled="ngDisabled"
|
|
||||||
ng-value="structure.value">
|
|
||||||
<em></em>
|
|
||||||
</label>
|
|
@ -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.
|
|
||||||
-->
|
|
||||||
<div class='form-control select'>
|
|
||||||
<select
|
|
||||||
ng-model="ngModel[field]"
|
|
||||||
ng-options="opt.value as opt.name for opt in options"
|
|
||||||
ng-required="ngRequired"
|
|
||||||
name="mctControl">
|
|
||||||
<option value="" ng-show="!ngModel[field]">- Select One -</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
@ -1,31 +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 class='form-control shell'>
|
|
||||||
<span class='field control {{structure.cssClass}}'>
|
|
||||||
<textarea ng-required="ngRequired"
|
|
||||||
ng-model="ngModel[field]"
|
|
||||||
ng-pattern="ngPattern"
|
|
||||||
size="{{structure.size}}"
|
|
||||||
name="mctControl">
|
|
||||||
</textarea>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
@ -1,32 +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 class='form-control shell'>
|
|
||||||
<span class='field control {{structure.cssClass}}'>
|
|
||||||
<input type="text"
|
|
||||||
ng-required="ngRequired"
|
|
||||||
ng-model="ngModel[field]"
|
|
||||||
ng-blur="ngBlur()"
|
|
||||||
ng-pattern="ngPattern"
|
|
||||||
size="{{structure.size}}"
|
|
||||||
name="mctControl">
|
|
||||||
</span>
|
|
||||||
</span>
|
|
@ -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.
|
|
||||||
-->
|
|
||||||
<form name="mctForm" novalidate class="form c-form" autocomplete="off">
|
|
||||||
<span ng-repeat="section in structure.sections"
|
|
||||||
class="l-form-section c-form__section {{ section.cssClass }}">
|
|
||||||
<h2 class="c-form__header" ng-if="section.name">
|
|
||||||
{{section.name}}
|
|
||||||
</h2>
|
|
||||||
<ng-form class="form-row c-form__row validates {{ section.cssClass }}"
|
|
||||||
ng-class="{
|
|
||||||
first:$index < 1,
|
|
||||||
req: row.required,
|
|
||||||
valid: mctFormInner.$dirty && mctFormInner.$valid,
|
|
||||||
invalid: mctFormInner.$dirty && !mctFormInner.$valid,
|
|
||||||
first: $index < 1,
|
|
||||||
'l-controls-first': row.layout === 'control-first',
|
|
||||||
'l-controls-under': row.layout === 'controls-under'
|
|
||||||
}"
|
|
||||||
name="mctFormInner"
|
|
||||||
ng-repeat="row in section.rows">
|
|
||||||
<div class='c-form__row__label label flex-elem' title="{{row.description}}">
|
|
||||||
{{row.name}}
|
|
||||||
</div>
|
|
||||||
<div class='c-form__row__controls controls flex-elem'>
|
|
||||||
<div class="c-form__controls-wrapper wrapper" ng-if="row.control">
|
|
||||||
<mct-control key="row.control"
|
|
||||||
ng-model="ngModel"
|
|
||||||
ng-required="row.required"
|
|
||||||
ng-pattern="getRegExp(row.pattern)"
|
|
||||||
options="row.options"
|
|
||||||
structure="row"
|
|
||||||
field="row.key">
|
|
||||||
</mct-control>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ng-form>
|
|
||||||
</span>
|
|
||||||
</form>
|
|
@ -1,96 +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(["zepto"], function ($) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The FileInputService provides an interface for triggering a file input.
|
|
||||||
*
|
|
||||||
* @constructor
|
|
||||||
* @memberof platform/forms
|
|
||||||
*/
|
|
||||||
function FileInputService() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates, triggers, and destroys a file picker element and returns a
|
|
||||||
* promise for an object containing the chosen file's name and contents.
|
|
||||||
*
|
|
||||||
* @returns {Promise} promise for an object containing file meta-data
|
|
||||||
*/
|
|
||||||
FileInputService.prototype.getInput = function (fileType) {
|
|
||||||
var input = this.newInput();
|
|
||||||
var read = this.readFile;
|
|
||||||
var fileInfo = {};
|
|
||||||
var file;
|
|
||||||
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
input.trigger("click");
|
|
||||||
input.on('change', function (event) {
|
|
||||||
// eslint-disable-next-line no-invalid-this
|
|
||||||
file = this.files[0];
|
|
||||||
input.remove();
|
|
||||||
if (file) {
|
|
||||||
if (fileType && (!file.type || (file.type !== fileType))) {
|
|
||||||
reject("Incompatible file type");
|
|
||||||
}
|
|
||||||
|
|
||||||
read(file)
|
|
||||||
.then(function (contents) {
|
|
||||||
fileInfo.name = file.name;
|
|
||||||
fileInfo.body = contents;
|
|
||||||
resolve(fileInfo);
|
|
||||||
}, function () {
|
|
||||||
reject("File read error");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
FileInputService.prototype.readFile = function (file) {
|
|
||||||
var fileReader = new FileReader();
|
|
||||||
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
fileReader.onload = function (event) {
|
|
||||||
resolve(event.target.result);
|
|
||||||
};
|
|
||||||
|
|
||||||
fileReader.onerror = function () {
|
|
||||||
return reject(event.target.result);
|
|
||||||
};
|
|
||||||
|
|
||||||
fileReader.readAsText(file);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
FileInputService.prototype.newInput = function () {
|
|
||||||
var input = $(document.createElement('input'));
|
|
||||||
input.attr("type", "file");
|
|
||||||
input.css("display", "none");
|
|
||||||
$('body').append(input);
|
|
||||||
|
|
||||||
return input;
|
|
||||||
};
|
|
||||||
|
|
||||||
return FileInputService;
|
|
||||||
});
|
|
@ -1,103 +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 () {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The mct-control will dynamically include the control
|
|
||||||
* for a form element based on a symbolic key. Individual
|
|
||||||
* controls are defined under the extension category
|
|
||||||
* `controls`; this allows plug-ins to introduce new form
|
|
||||||
* control types while still making use of the form
|
|
||||||
* generator to ensure an overall consistent form style.
|
|
||||||
* @constructor
|
|
||||||
* @memberof platform/forms
|
|
||||||
*/
|
|
||||||
function MCTControl(templateLinker, controls) {
|
|
||||||
var controlMap = {};
|
|
||||||
|
|
||||||
// Prepopulate controlMap for easy look up by key
|
|
||||||
controls.forEach(function (control) {
|
|
||||||
controlMap[control.key] = control;
|
|
||||||
});
|
|
||||||
|
|
||||||
function link(scope, element, attrs, ngModelController) {
|
|
||||||
var changeTemplate = templateLinker.link(scope, element);
|
|
||||||
scope.$watch("key", function (key) {
|
|
||||||
changeTemplate(controlMap[key]);
|
|
||||||
});
|
|
||||||
scope.ngModelController = ngModelController;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
// Only show at the element level
|
|
||||||
restrict: "E",
|
|
||||||
|
|
||||||
// ngOptions is terminal, so we need to be higher priority
|
|
||||||
priority: 1000,
|
|
||||||
|
|
||||||
// Get the ngModelController, so that controls can set validity
|
|
||||||
require: '?ngModel',
|
|
||||||
|
|
||||||
// Link function
|
|
||||||
link: link,
|
|
||||||
|
|
||||||
// Pass through Angular's normal input field attributes
|
|
||||||
scope: {
|
|
||||||
// Used to choose which form control to use
|
|
||||||
key: "=",
|
|
||||||
|
|
||||||
// Allow controls to trigger blur-like events
|
|
||||||
ngBlur: "&",
|
|
||||||
|
|
||||||
// Allow controls to trigger blur-like events
|
|
||||||
ngMouseup: "&",
|
|
||||||
|
|
||||||
// The state of the form value itself
|
|
||||||
ngModel: "=",
|
|
||||||
|
|
||||||
// Enabled/disabled state
|
|
||||||
ngDisabled: "=",
|
|
||||||
|
|
||||||
// Whether or not input is required
|
|
||||||
ngRequired: "=",
|
|
||||||
|
|
||||||
// Pattern (for input fields)
|
|
||||||
ngPattern: "=",
|
|
||||||
|
|
||||||
// Set of choices (if any)
|
|
||||||
options: "=",
|
|
||||||
|
|
||||||
// Structure (subtree of Form Structure)
|
|
||||||
structure: "=",
|
|
||||||
|
|
||||||
// Name, as in "<input name="...
|
|
||||||
field: "="
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return MCTControl;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,68 +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(
|
|
||||||
['zepto'],
|
|
||||||
function ($) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The mct-file-input handles behavior of the file input form control.
|
|
||||||
* @constructor
|
|
||||||
* @memberof platform/forms
|
|
||||||
*/
|
|
||||||
function MCTFileInput(fileInputService) {
|
|
||||||
|
|
||||||
function link(scope, element, attrs, control) {
|
|
||||||
|
|
||||||
function setText(fileName) {
|
|
||||||
scope.structure.text = fileName.length > 20
|
|
||||||
? fileName.substr(0, 20) + "..."
|
|
||||||
: fileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleClick() {
|
|
||||||
fileInputService.getInput(scope.structure.type).then(function (result) {
|
|
||||||
setText(result.name);
|
|
||||||
scope.ngModel[scope.field] = result;
|
|
||||||
control.$setValidity("file-input", true);
|
|
||||||
scope.$digest();
|
|
||||||
}, function () {
|
|
||||||
setText('Select File');
|
|
||||||
control.$setValidity("file-input", false);
|
|
||||||
scope.$digest();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
control.$setValidity("file-input", false);
|
|
||||||
element.on('click', handleClick);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
restrict: "A",
|
|
||||||
require: "^form",
|
|
||||||
link: link
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return MCTFileInput;
|
|
||||||
}
|
|
||||||
);
|
|
@ -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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This bundle implements directives for displaying and handling forms for
|
|
||||||
* user input.
|
|
||||||
* @namespace platform/forms
|
|
||||||
*/
|
|
||||||
define(
|
|
||||||
["./controllers/FormController", "../res/templates/form.html"],
|
|
||||||
function (FormController, formTemplate) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The mct-form directive allows generation of displayable
|
|
||||||
* forms based on a declarative description of the form's
|
|
||||||
* structure.
|
|
||||||
*
|
|
||||||
* This directive accepts three attributes:
|
|
||||||
*
|
|
||||||
* * `ng-model`: The model for the form; where user input
|
|
||||||
* where be stored.
|
|
||||||
* * `structure`: The declarative structure of the form.
|
|
||||||
* Describes what controls should be shown and where
|
|
||||||
* their values should be read/written in the model.
|
|
||||||
* * `name`: The name under which to expose the form's
|
|
||||||
* dirty/valid state. This is similar to ng-form's use
|
|
||||||
* of name, except this will be made available in the
|
|
||||||
* parent scope.
|
|
||||||
*
|
|
||||||
* @memberof platform/forms
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
function MCTForm() {
|
|
||||||
return {
|
|
||||||
// Only show at the element level
|
|
||||||
restrict: "E",
|
|
||||||
|
|
||||||
// Load the forms template
|
|
||||||
template: formTemplate,
|
|
||||||
|
|
||||||
// Use FormController to populate/respond to changes in scope
|
|
||||||
controller: ['$scope', FormController],
|
|
||||||
|
|
||||||
// Initial an isolate scope
|
|
||||||
scope: {
|
|
||||||
|
|
||||||
// The model: Where form input will actually go
|
|
||||||
ngModel: "=",
|
|
||||||
|
|
||||||
// Form structure; what sections/rows to show
|
|
||||||
structure: "=",
|
|
||||||
|
|
||||||
// Name under which to publish the form
|
|
||||||
name: "@"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return MCTForm;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,140 +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 `autocomplete` form control.
|
|
||||||
*
|
|
||||||
* @memberof platform/forms
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
function AutocompleteController($scope, $element) {
|
|
||||||
|
|
||||||
var key = {
|
|
||||||
down: 40,
|
|
||||||
up: 38,
|
|
||||||
enter: 13
|
|
||||||
},
|
|
||||||
autocompleteInputElement = $element[0].getElementsByClassName('autocompleteInput')[0];
|
|
||||||
|
|
||||||
if ($scope.options[0].name) {
|
|
||||||
// If "options" include name, value pair
|
|
||||||
$scope.optionNames = $scope.options.map(function (opt) {
|
|
||||||
return opt.name;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// If options is only an array of string.
|
|
||||||
$scope.optionNames = $scope.options;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fillInputWithIndexedOption() {
|
|
||||||
if ($scope.filteredOptions[$scope.optionIndex]) {
|
|
||||||
$scope.ngModel[$scope.field] = $scope.filteredOptions[$scope.optionIndex].name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function decrementOptionIndex() {
|
|
||||||
if ($scope.optionIndex === 0) {
|
|
||||||
$scope.optionIndex = $scope.filteredOptions.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.optionIndex--;
|
|
||||||
fillInputWithIndexedOption();
|
|
||||||
}
|
|
||||||
|
|
||||||
function incrementOptionIndex() {
|
|
||||||
if ($scope.optionIndex === $scope.filteredOptions.length - 1) {
|
|
||||||
$scope.optionIndex = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.optionIndex++;
|
|
||||||
fillInputWithIndexedOption();
|
|
||||||
}
|
|
||||||
|
|
||||||
function fillInputWithString(string) {
|
|
||||||
$scope.hideOptions = true;
|
|
||||||
$scope.ngModel[$scope.field] = string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function showOptions(string) {
|
|
||||||
$scope.hideOptions = false;
|
|
||||||
$scope.filterOptions(string);
|
|
||||||
$scope.optionIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.keyDown = function ($event) {
|
|
||||||
if ($scope.filteredOptions) {
|
|
||||||
var keyCode = $event.keyCode;
|
|
||||||
switch (keyCode) {
|
|
||||||
case key.down:
|
|
||||||
incrementOptionIndex();
|
|
||||||
break;
|
|
||||||
case key.up:
|
|
||||||
$event.preventDefault(); // Prevents cursor jumping back and forth
|
|
||||||
decrementOptionIndex();
|
|
||||||
break;
|
|
||||||
case key.enter:
|
|
||||||
if ($scope.filteredOptions[$scope.optionIndex]) {
|
|
||||||
fillInputWithString($scope.filteredOptions[$scope.optionIndex].name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.filterOptions = function (string) {
|
|
||||||
$scope.hideOptions = false;
|
|
||||||
$scope.filteredOptions = $scope.optionNames.filter(function (option) {
|
|
||||||
return option.toLowerCase().indexOf(string.toLowerCase()) >= 0;
|
|
||||||
}).map(function (option, index) {
|
|
||||||
return {
|
|
||||||
optionId: index,
|
|
||||||
name: option
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.inputClicked = function () {
|
|
||||||
autocompleteInputElement.select();
|
|
||||||
showOptions(autocompleteInputElement.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.arrowClicked = function () {
|
|
||||||
autocompleteInputElement.select();
|
|
||||||
showOptions('');
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.fillInput = function (string) {
|
|
||||||
fillInputWithString(string);
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.optionMouseover = function (optionId) {
|
|
||||||
$scope.optionIndex = optionId;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return AutocompleteController;
|
|
||||||
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,104 +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 () {
|
|
||||||
|
|
||||||
var BASE_COLORS = [
|
|
||||||
[136, 32, 32],
|
|
||||||
[224, 64, 64],
|
|
||||||
[240, 160, 72],
|
|
||||||
[255, 248, 96],
|
|
||||||
[128, 240, 72],
|
|
||||||
[128, 248, 248],
|
|
||||||
[88, 144, 224],
|
|
||||||
[0, 72, 240],
|
|
||||||
[136, 80, 240],
|
|
||||||
[224, 96, 248]
|
|
||||||
],
|
|
||||||
GRADIENTS = [0.75, 0.50, 0.25, -0.25, -0.50, -0.75],
|
|
||||||
GROUPS = [];
|
|
||||||
|
|
||||||
function toWebColor(triplet) {
|
|
||||||
return '#' + triplet.map(function (v) {
|
|
||||||
return (v < 16 ? '0' : '') + v.toString(16);
|
|
||||||
}).join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
function toGradient(triplet, value) {
|
|
||||||
return triplet.map(function (v) {
|
|
||||||
return Math.round(value > 0
|
|
||||||
? (v + (255 - v) * value)
|
|
||||||
: (v * (1 + value))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function initializeGroups() {
|
|
||||||
var group;
|
|
||||||
|
|
||||||
// Ten grayscale colors
|
|
||||||
group = [];
|
|
||||||
while (group.length < 10) {
|
|
||||||
group.push(toWebColor([
|
|
||||||
Math.round(28.3333 * group.length),
|
|
||||||
Math.round(28.3333 * group.length),
|
|
||||||
Math.round(28.3333 * group.length)
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
|
|
||||||
GROUPS.push(group);
|
|
||||||
|
|
||||||
// Ten basic colors
|
|
||||||
GROUPS.push(BASE_COLORS.map(toWebColor));
|
|
||||||
|
|
||||||
// ...and some gradients of those colors
|
|
||||||
group = [];
|
|
||||||
GRADIENTS.forEach(function (v) {
|
|
||||||
group = group.concat(BASE_COLORS.map(function (c) {
|
|
||||||
return toWebColor(toGradient(c, v));
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
GROUPS.push(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ColorController() {
|
|
||||||
if (GROUPS.length === 0) {
|
|
||||||
initializeGroups();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get groups of colors to display in a color picker. These are
|
|
||||||
* given as #-prefixed color strings, in a two-dimensional array.
|
|
||||||
* Each element of the array is a group of related colors (e.g.
|
|
||||||
* grayscale colors, web colors, gradients...)
|
|
||||||
* @returns {string[][]} groups of colors
|
|
||||||
*/
|
|
||||||
ColorController.prototype.groups = function () {
|
|
||||||
return GROUPS;
|
|
||||||
};
|
|
||||||
|
|
||||||
return ColorController;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,62 +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 () {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The CompositeController supports the "composite" control type,
|
|
||||||
* which provides an array of other controls. It is used specifically
|
|
||||||
* to support validation when a particular row is not marked as
|
|
||||||
* required; in this case, empty input should be allowed, but partial
|
|
||||||
* input (where some but not all of the composite controls have been
|
|
||||||
* filled in) should be disallowed. This is enforced in the template
|
|
||||||
* by an ng-required directive, but that is supported by the
|
|
||||||
* isNonEmpty check that this controller provides.
|
|
||||||
* @memberof platform/forms
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
function CompositeController() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if an element is defined; the map step of isNonEmpty
|
|
||||||
function isDefined(element) {
|
|
||||||
return typeof element !== 'undefined';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if an array contains anything other than
|
|
||||||
* undefined elements.
|
|
||||||
* @param {Array} value the array to check
|
|
||||||
* @returns {boolean} true if any non-undefined
|
|
||||||
* element is in the array
|
|
||||||
* @memberof platform/forms.CompositeController#
|
|
||||||
*/
|
|
||||||
CompositeController.prototype.isNonEmpty = function (value) {
|
|
||||||
return Array.isArray(value) && value.some(isDefined);
|
|
||||||
};
|
|
||||||
|
|
||||||
return CompositeController;
|
|
||||||
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,108 +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(
|
|
||||||
["moment"],
|
|
||||||
function (moment) {
|
|
||||||
|
|
||||||
var DATE_FORMAT = "YYYY-MM-DD";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controller for the `datetime` form control.
|
|
||||||
* This is a composite control; it includes multiple
|
|
||||||
* input fields but outputs a single timestamp (in
|
|
||||||
* milliseconds since start of 1970) to the ngModel.
|
|
||||||
*
|
|
||||||
* @memberof platform/forms
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
function DateTimeController($scope) {
|
|
||||||
|
|
||||||
// Update the
|
|
||||||
function update() {
|
|
||||||
var date = $scope.datetime.date,
|
|
||||||
hour = $scope.datetime.hour,
|
|
||||||
min = $scope.datetime.min,
|
|
||||||
sec = $scope.datetime.sec,
|
|
||||||
fullDateTime = moment.utc(date, DATE_FORMAT)
|
|
||||||
.hour(hour || 0)
|
|
||||||
.minute(min || 0)
|
|
||||||
.second(sec || 0);
|
|
||||||
|
|
||||||
if (fullDateTime.isValid()) {
|
|
||||||
$scope.ngModel[$scope.field] = fullDateTime.valueOf();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If anything is complete, say so in scope; there are
|
|
||||||
// ng-required usages that will update off of this (to
|
|
||||||
// allow datetime to be optional while still permitting
|
|
||||||
// incomplete input)
|
|
||||||
$scope.partiallyComplete =
|
|
||||||
Object.keys($scope.datetime).some(function (key) {
|
|
||||||
return $scope.datetime[key];
|
|
||||||
});
|
|
||||||
|
|
||||||
// Treat empty input as an undefined value
|
|
||||||
if (!$scope.partiallyComplete) {
|
|
||||||
$scope.ngModel[$scope.field] = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateDateTime(value) {
|
|
||||||
var m;
|
|
||||||
if (value !== undefined) {
|
|
||||||
m = moment.utc(value);
|
|
||||||
$scope.datetime = {
|
|
||||||
date: m.format(DATE_FORMAT),
|
|
||||||
hour: m.format("H"),
|
|
||||||
min: m.format("m"),
|
|
||||||
sec: m.format("s")
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
$scope.datetime = {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ...and update form values when actual field in model changes
|
|
||||||
$scope.$watch("ngModel[field]", updateDateTime);
|
|
||||||
|
|
||||||
// Update value whenever any field changes.
|
|
||||||
$scope.$watch("datetime.date", update);
|
|
||||||
$scope.$watch("datetime.hour", update);
|
|
||||||
$scope.$watch("datetime.min", update);
|
|
||||||
$scope.$watch("datetime.sec", update);
|
|
||||||
|
|
||||||
// Expose format string for placeholder
|
|
||||||
$scope.format = DATE_FORMAT;
|
|
||||||
|
|
||||||
// Initialize forms values
|
|
||||||
updateDateTime(
|
|
||||||
($scope.ngModel && $scope.field)
|
|
||||||
? $scope.ngModel[$scope.field] : undefined
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return DateTimeController;
|
|
||||||
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
@ -1,93 +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 `dialog-button` control type. Provides
|
|
||||||
* structure for a button (embedded via the template) which
|
|
||||||
* will show a dialog for editing a single property when clicked.
|
|
||||||
* @memberof platform/forms
|
|
||||||
* @constructor
|
|
||||||
* @param $scope the control's Angular scope
|
|
||||||
* @param {DialogService} dialogService service to use to prompt
|
|
||||||
* for user input
|
|
||||||
*/
|
|
||||||
function DialogButtonController($scope, dialogService) {
|
|
||||||
var self = this,
|
|
||||||
buttonForm;
|
|
||||||
|
|
||||||
// Store the result of user input to the model
|
|
||||||
function storeResult(result) {
|
|
||||||
$scope.ngModel[$scope.field] = result[$scope.field];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prompt for user input
|
|
||||||
function showDialog() {
|
|
||||||
// Prepare initial state
|
|
||||||
var state = {};
|
|
||||||
state[$scope.field] = $scope.ngModel[$scope.field];
|
|
||||||
|
|
||||||
// Show dialog, then store user input (if any)
|
|
||||||
dialogService.getUserInput(buttonForm, state).then(storeResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh state based on structure for this control
|
|
||||||
function refreshStructure(structure) {
|
|
||||||
var row = Object.create(structure.dialog || {});
|
|
||||||
|
|
||||||
structure = structure || {};
|
|
||||||
|
|
||||||
// Add the key, to read back from that row
|
|
||||||
row.key = $scope.field;
|
|
||||||
|
|
||||||
// Prepare the structure for the button itself
|
|
||||||
self.buttonStructure = {};
|
|
||||||
self.buttonStructure.cssClass = structure.cssClass;
|
|
||||||
self.buttonStructure.name = structure.name;
|
|
||||||
self.buttonStructure.description = structure.description;
|
|
||||||
self.buttonStructure.click = showDialog;
|
|
||||||
|
|
||||||
// Prepare the form; a single row
|
|
||||||
buttonForm = {
|
|
||||||
name: structure.title,
|
|
||||||
sections: [{ rows: [row] }]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.$watch('structure', refreshStructure);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the structure for an `mct-control` of type
|
|
||||||
* `button`; a dialog will be launched when this button
|
|
||||||
* is clicked.
|
|
||||||
* @returns dialog structure
|
|
||||||
*/
|
|
||||||
DialogButtonController.prototype.getButtonStructure = function () {
|
|
||||||
return this.buttonStructure;
|
|
||||||
};
|
|
||||||
|
|
||||||
return DialogButtonController;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,77 +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 () {
|
|
||||||
|
|
||||||
// Default ng-pattern; any non whitespace
|
|
||||||
var NON_WHITESPACE = /\S/;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controller for mct-form and mct-toolbar directives.
|
|
||||||
* @memberof platform/forms
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
function FormController($scope) {
|
|
||||||
var regexps = [];
|
|
||||||
|
|
||||||
// ng-pattern seems to want a RegExp, and not a
|
|
||||||
// string (despite what documentation says) but
|
|
||||||
// we want form structure to be JSON-expressible,
|
|
||||||
// so we make RegExp's from strings as-needed
|
|
||||||
function getRegExp(pattern) {
|
|
||||||
// If undefined, don't apply a pattern
|
|
||||||
if (!pattern) {
|
|
||||||
return NON_WHITESPACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Just echo if it's already a regexp
|
|
||||||
if (pattern instanceof RegExp) {
|
|
||||||
return pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, assume a string
|
|
||||||
// Cache for easy lookup later (so we don't
|
|
||||||
// creat a new RegExp every digest cycle)
|
|
||||||
if (!regexps[pattern]) {
|
|
||||||
regexps[pattern] = new RegExp(pattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
return regexps[pattern];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Publish the form state under the requested
|
|
||||||
// name in the parent scope
|
|
||||||
$scope.$watch("mctForm", function (mctForm) {
|
|
||||||
if ($scope.name) {
|
|
||||||
$scope.$parent[$scope.name] = mctForm;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Expose the regexp lookup
|
|
||||||
$scope.getRegExp = getRegExp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FormController;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,74 +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/FileInputService"],
|
|
||||||
function (FileInputService) {
|
|
||||||
|
|
||||||
describe("The FileInputService", function () {
|
|
||||||
var fileInputService,
|
|
||||||
mockInput;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
fileInputService = new FileInputService();
|
|
||||||
mockInput = jasmine.createSpyObj('input',
|
|
||||||
[
|
|
||||||
'on',
|
|
||||||
'trigger',
|
|
||||||
'remove'
|
|
||||||
]
|
|
||||||
);
|
|
||||||
mockInput.on.and.callFake(function (event, changeHandler) {
|
|
||||||
changeHandler.apply(mockInput);
|
|
||||||
});
|
|
||||||
spyOn(fileInputService, "newInput").and.returnValue(
|
|
||||||
mockInput
|
|
||||||
);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it("can read a file", function () {
|
|
||||||
mockInput.files = [new File(["file content"], "file name")];
|
|
||||||
fileInputService.getInput().then(function (result) {
|
|
||||||
expect(result.name).toBe("file name");
|
|
||||||
expect(result.body).toBe("file content");
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(mockInput.trigger).toHaveBeenCalledWith('click');
|
|
||||||
expect(mockInput.remove).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("catches file read errors", function () {
|
|
||||||
mockInput.files = ["GARBAGE"];
|
|
||||||
fileInputService.getInput().then(
|
|
||||||
function (result) {},
|
|
||||||
function (err) {
|
|
||||||
expect(err).toBe("File read error");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(mockInput.trigger).toHaveBeenCalledWith('click');
|
|
||||||
expect(mockInput.remove).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -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(
|
|
||||||
["../src/MCTControl"],
|
|
||||||
function (MCTControl) {
|
|
||||||
|
|
||||||
describe("The mct-control directive", function () {
|
|
||||||
var testControls,
|
|
||||||
mockScope,
|
|
||||||
mockLinker,
|
|
||||||
mockChangeTemplate,
|
|
||||||
mctControl;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
testControls = [
|
|
||||||
{
|
|
||||||
key: "abc",
|
|
||||||
bundle: {
|
|
||||||
path: "a",
|
|
||||||
resources: "b"
|
|
||||||
},
|
|
||||||
templateUrl: "c/template.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "xyz",
|
|
||||||
bundle: {
|
|
||||||
path: "x",
|
|
||||||
resources: "y"
|
|
||||||
},
|
|
||||||
templateUrl: "z/template.html"
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
mockScope = jasmine.createSpyObj("$scope", ["$watch"]);
|
|
||||||
mockLinker = jasmine.createSpyObj("templateLinker", ["link"]);
|
|
||||||
mockChangeTemplate = jasmine.createSpy('changeTemplate');
|
|
||||||
mockLinker.link.and.returnValue(mockChangeTemplate);
|
|
||||||
|
|
||||||
mctControl = new MCTControl(mockLinker, testControls);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("is restricted to the element level", function () {
|
|
||||||
expect(mctControl.restrict).toEqual("E");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("watches its passed key to choose a template", function () {
|
|
||||||
mctControl.link(mockScope);
|
|
||||||
|
|
||||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
|
||||||
"key",
|
|
||||||
jasmine.any(Function)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("changes its template dynamically", function () {
|
|
||||||
mctControl.link(mockScope);
|
|
||||||
|
|
||||||
expect(mockChangeTemplate)
|
|
||||||
.not.toHaveBeenCalledWith(testControls[1]);
|
|
||||||
|
|
||||||
mockScope.key = "xyz";
|
|
||||||
mockScope.$watch.calls.mostRecent().args[1]("xyz");
|
|
||||||
|
|
||||||
// Should have communicated the template path to
|
|
||||||
// ng-include via the "inclusion" field in scope
|
|
||||||
expect(mockChangeTemplate)
|
|
||||||
.toHaveBeenCalledWith(testControls[1]);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,95 +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/MCTFileInput"],
|
|
||||||
function (MCTFileInput) {
|
|
||||||
|
|
||||||
xdescribe("The mct-file-input directive", function () {
|
|
||||||
|
|
||||||
var mockScope,
|
|
||||||
mockFileInputService,
|
|
||||||
mctFileInput,
|
|
||||||
element,
|
|
||||||
attrs,
|
|
||||||
control;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
attrs = [];
|
|
||||||
control = jasmine.createSpyObj('control', ['$setValidity']);
|
|
||||||
element = jasmine.createSpyObj('element', ['on', 'trigger']);
|
|
||||||
mockFileInputService = jasmine.createSpyObj('fileInputService',
|
|
||||||
['getInput']
|
|
||||||
);
|
|
||||||
mockScope = jasmine.createSpyObj(
|
|
||||||
'$scope',
|
|
||||||
['$watch']
|
|
||||||
);
|
|
||||||
|
|
||||||
mockScope.structure = {text: 'Select File'};
|
|
||||||
mockScope.field = "file-input";
|
|
||||||
mockScope.ngModel = {"file-input": undefined};
|
|
||||||
|
|
||||||
element.on.and.callFake(function (event, clickHandler) {
|
|
||||||
clickHandler();
|
|
||||||
});
|
|
||||||
mockFileInputService.getInput.and.returnValue(
|
|
||||||
Promise.resolve({
|
|
||||||
name: "file-name",
|
|
||||||
body: "file-body"
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
mctFileInput = new MCTFileInput(mockFileInputService);
|
|
||||||
|
|
||||||
return new Promise(function (resolve) {
|
|
||||||
mctFileInput.link(mockScope, element, attrs, control);
|
|
||||||
setTimeout(resolve, 100);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("is restricted to attributes", function () {
|
|
||||||
expect(mctFileInput.restrict).toEqual("A");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("changes button text to match file name", function () {
|
|
||||||
expect(element.on).toHaveBeenCalledWith(
|
|
||||||
'click',
|
|
||||||
jasmine.any(Function)
|
|
||||||
);
|
|
||||||
expect(mockScope.structure.text).toEqual("file-name");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("validates control on file selection", function () {
|
|
||||||
var calls = control.$setValidity.calls;
|
|
||||||
|
|
||||||
expect(calls.count()).toBe(2);
|
|
||||||
expect(calls.all()[0].args).toEqual(
|
|
||||||
['file-input', false]
|
|
||||||
);
|
|
||||||
expect(calls.all()[1].args).toEqual(
|
|
||||||
['file-input', true]
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,114 +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/MCTForm"],
|
|
||||||
function (MCTForm) {
|
|
||||||
|
|
||||||
describe("The mct-form directive", function () {
|
|
||||||
var mockScope,
|
|
||||||
mctForm;
|
|
||||||
|
|
||||||
function installController() {
|
|
||||||
var Controller = mctForm.controller[1];
|
|
||||||
|
|
||||||
return new Controller(mockScope);
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockScope = jasmine.createSpyObj("$scope", ["$watch"]);
|
|
||||||
mockScope.$parent = {};
|
|
||||||
mctForm = new MCTForm();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("is restricted to elements", function () {
|
|
||||||
expect(mctForm.restrict).toEqual("E");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("watches for changes in form by name", function () {
|
|
||||||
// mct-form needs to watch for the form by name
|
|
||||||
// in order to convey changes in $valid, $dirty, etc
|
|
||||||
// up to the parent scope.
|
|
||||||
installController();
|
|
||||||
|
|
||||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
|
||||||
"mctForm",
|
|
||||||
jasmine.any(Function)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("conveys form status to parent scope", function () {
|
|
||||||
var someState = { someKey: "some value" };
|
|
||||||
mockScope.name = "someName";
|
|
||||||
|
|
||||||
installController();
|
|
||||||
|
|
||||||
mockScope.$watch.calls.mostRecent().args[1](someState);
|
|
||||||
|
|
||||||
expect(mockScope.$parent.someName).toBe(someState);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("allows strings to be converted to RegExps", function () {
|
|
||||||
// This is needed to support ng-pattern in the template
|
|
||||||
installController();
|
|
||||||
|
|
||||||
// Should have added getRegExp to the scope,
|
|
||||||
// to convert strings to regular expressions
|
|
||||||
expect(mockScope.getRegExp("^\\d+$")).toEqual(/^\d+$/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns the same regexp instance for the same string", function () {
|
|
||||||
// Don't want new instances each digest cycle, for performance
|
|
||||||
var strRegExp = "^[a-z]\\d+$",
|
|
||||||
regExp;
|
|
||||||
|
|
||||||
// Add getRegExp to scope
|
|
||||||
installController();
|
|
||||||
regExp = mockScope.getRegExp(strRegExp);
|
|
||||||
|
|
||||||
// Same object instance each time...
|
|
||||||
expect(mockScope.getRegExp(strRegExp)).toBe(regExp);
|
|
||||||
expect(mockScope.getRegExp(strRegExp)).toBe(regExp);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("passes RegExp objects through untouched", function () {
|
|
||||||
// Permit using forms to simply provide their own RegExp object
|
|
||||||
var regExp = /^\d+[a-d]$/;
|
|
||||||
|
|
||||||
// Add getRegExp to scope
|
|
||||||
installController();
|
|
||||||
|
|
||||||
// Should have added getRegExp to the scope,
|
|
||||||
// to convert strings to regular expressions
|
|
||||||
expect(mockScope.getRegExp(regExp)).toBe(regExp);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("passes a non-whitespace regexp when no pattern is defined", function () {
|
|
||||||
// If no pattern is supplied, ng-pattern should match anything
|
|
||||||
installController();
|
|
||||||
expect(mockScope.getRegExp()).toEqual(/\S/);
|
|
||||||
expect(mockScope.getRegExp(undefined)).toEqual(/\S/);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,75 +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/controllers/AutocompleteController",
|
|
||||||
"angular"
|
|
||||||
], function (
|
|
||||||
AutocompleteController,
|
|
||||||
angular
|
|
||||||
) {
|
|
||||||
|
|
||||||
describe("The autocomplete controller", function () {
|
|
||||||
var mockScope,
|
|
||||||
mockElement,
|
|
||||||
controller;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockScope = jasmine.createSpyObj("$scope", ["$watch"]);
|
|
||||||
mockScope.options = ['Asia/Dhaka', 'UTC', 'Toronto', 'Asia/Shanghai', 'Hotel California'];
|
|
||||||
mockScope.ngModel = [null, null, null, null, null];
|
|
||||||
mockScope.field = 4;
|
|
||||||
mockElement = angular.element("<div></div>");
|
|
||||||
controller = new AutocompleteController(mockScope, mockElement);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("makes optionNames array equal to options if options is an array of string", function () {
|
|
||||||
expect(mockScope.optionNames).toEqual(mockScope.options);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("filters options by returning array containing optionId and name", function () {
|
|
||||||
mockScope.filterOptions('Asia');
|
|
||||||
var filteredOptions = [{
|
|
||||||
optionId: 0,
|
|
||||||
name: 'Asia/Dhaka'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
optionId: 1,
|
|
||||||
name: 'Asia/Shanghai'
|
|
||||||
}];
|
|
||||||
expect(mockScope.filteredOptions).toEqual(filteredOptions);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("fills input with given string", function () {
|
|
||||||
var str = "UTC";
|
|
||||||
mockScope.fillInput(str);
|
|
||||||
expect(mockScope.hideOptions).toEqual(true);
|
|
||||||
expect(mockScope.ngModel[mockScope.field]).toEqual(str);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sets a new optionIndex on mouse hover", function () {
|
|
||||||
mockScope.optionMouseover(1);
|
|
||||||
expect(mockScope.optionIndex).toEqual(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,70 +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/controllers/ColorController"],
|
|
||||||
function (ColorController) {
|
|
||||||
|
|
||||||
var COLOR_REGEX = /^#[0-9a-fA-F]{6}$/;
|
|
||||||
|
|
||||||
describe("The color picker's controller", function () {
|
|
||||||
var controller;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
controller = new ColorController();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("exposes groups of colors", function () {
|
|
||||||
var groups = controller.groups();
|
|
||||||
|
|
||||||
// Make sure that the groups array is non-empty
|
|
||||||
expect(Array.isArray(groups)).toBeTruthy();
|
|
||||||
expect(groups.length).not.toEqual(0);
|
|
||||||
|
|
||||||
groups.forEach(function (group) {
|
|
||||||
// Make sure each group is a non-empty array
|
|
||||||
expect(Array.isArray(group)).toBeTruthy();
|
|
||||||
expect(group.length).not.toEqual(0);
|
|
||||||
// Make sure they're valid web colors
|
|
||||||
group.forEach(function (color) {
|
|
||||||
expect(COLOR_REGEX.test(color)).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("exposes unique colors", function () {
|
|
||||||
var count = 0, set = {};
|
|
||||||
|
|
||||||
// Count each color, and add them to the set
|
|
||||||
controller.groups().forEach(function (group) {
|
|
||||||
group.forEach(function (color) {
|
|
||||||
count += 1;
|
|
||||||
set[color] = true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Size of set should be number of colors if all were unique
|
|
||||||
expect(Object.keys(set).length).toEqual(count);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
define(
|
|
||||||
["../../src/controllers/DateTimeController"],
|
|
||||||
function (DateTimeController) {
|
|
||||||
|
|
||||||
describe("The date-time controller", function () {
|
|
||||||
var mockScope,
|
|
||||||
controller;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockScope = jasmine.createSpyObj("$scope", ["$watch"]);
|
|
||||||
controller = new DateTimeController(mockScope);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("watches for changes in fields", function () {
|
|
||||||
["date", "hour", "min", "sec"].forEach(function (fieldName) {
|
|
||||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
|
||||||
"datetime." + fieldName,
|
|
||||||
jasmine.any(Function)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("converts date-time input into a timestamp", function () {
|
|
||||||
mockScope.ngModel = {};
|
|
||||||
mockScope.field = "test";
|
|
||||||
mockScope.datetime.date = "2014-11-28";
|
|
||||||
mockScope.datetime.hour = 22;
|
|
||||||
mockScope.datetime.min = 55;
|
|
||||||
mockScope.datetime.sec = 13;
|
|
||||||
|
|
||||||
mockScope.$watch.calls.mostRecent().args[1]();
|
|
||||||
|
|
||||||
expect(mockScope.ngModel.test).toEqual(1417215313000);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("reports when form input is partially complete", function () {
|
|
||||||
// This is needed to flag the control's state as invalid
|
|
||||||
// when it is partially complete without having it treated
|
|
||||||
// as required.
|
|
||||||
mockScope.ngModel = {};
|
|
||||||
mockScope.field = "test";
|
|
||||||
mockScope.datetime.date = "2014-11-28";
|
|
||||||
mockScope.datetime.hour = 22;
|
|
||||||
mockScope.datetime.min = 55;
|
|
||||||
// mockScope.datetime.sec = 13;
|
|
||||||
|
|
||||||
mockScope.$watch.calls.mostRecent().args[1]();
|
|
||||||
|
|
||||||
expect(mockScope.partiallyComplete).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("reports 'undefined' for empty input", function () {
|
|
||||||
mockScope.ngModel = { test: 12345 };
|
|
||||||
mockScope.field = "test";
|
|
||||||
mockScope.$watch.calls.mostRecent().args[1]();
|
|
||||||
// Clear all inputs
|
|
||||||
mockScope.datetime = {};
|
|
||||||
mockScope.$watch.calls.mostRecent().args[1]();
|
|
||||||
|
|
||||||
// Should have cleared out the time stamp
|
|
||||||
expect(mockScope.ngModel.test).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("exposes date-time format for placeholder", function () {
|
|
||||||
expect(mockScope.format).toEqual(jasmine.any(String));
|
|
||||||
expect(mockScope.format.length).toBeGreaterThan(0);
|
|
||||||
});
|
|
||||||
it("initializes form fields with values from ng-model", function () {
|
|
||||||
mockScope.ngModel = { test: 1417215313000 };
|
|
||||||
mockScope.field = "test";
|
|
||||||
mockScope.$watch.calls.all().forEach(function (call) {
|
|
||||||
if (call.args[0] === 'ngModel[field]') {
|
|
||||||
call.args[1](mockScope.ngModel.test);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
expect(mockScope.datetime).toEqual({
|
|
||||||
date: "2014-11-28",
|
|
||||||
hour: "22",
|
|
||||||
min: "55",
|
|
||||||
sec: "13"
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,135 +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/controllers/DialogButtonController"],
|
|
||||||
function (DialogButtonController) {
|
|
||||||
|
|
||||||
describe("A dialog button controller", function () {
|
|
||||||
var mockScope,
|
|
||||||
mockDialogService,
|
|
||||||
mockPromise,
|
|
||||||
testStructure,
|
|
||||||
controller;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockScope = jasmine.createSpyObj(
|
|
||||||
'$scope',
|
|
||||||
['$watch']
|
|
||||||
);
|
|
||||||
mockDialogService = jasmine.createSpyObj(
|
|
||||||
'dialogService',
|
|
||||||
['getUserInput']
|
|
||||||
);
|
|
||||||
mockPromise = jasmine.createSpyObj(
|
|
||||||
'promise',
|
|
||||||
['then']
|
|
||||||
);
|
|
||||||
testStructure = {
|
|
||||||
name: "A Test",
|
|
||||||
cssClass: "icon-T",
|
|
||||||
description: "Test description",
|
|
||||||
control: "dialog-button",
|
|
||||||
title: "Test title",
|
|
||||||
dialog: {
|
|
||||||
"control": "textfield",
|
|
||||||
"name": "Inner control"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
mockScope.field = "testKey";
|
|
||||||
mockScope.ngModel = { testKey: "initial test value" };
|
|
||||||
mockScope.structure = testStructure;
|
|
||||||
|
|
||||||
mockDialogService.getUserInput.and.returnValue(mockPromise);
|
|
||||||
|
|
||||||
controller = new DialogButtonController(
|
|
||||||
mockScope,
|
|
||||||
mockDialogService
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("provides a structure for a button control", function () {
|
|
||||||
var buttonStructure;
|
|
||||||
|
|
||||||
// Template is just a mct-control pointing to a button
|
|
||||||
// control, so this controller needs to set up all the
|
|
||||||
// logic for showing a dialog and collecting user input
|
|
||||||
// when that button gets clicked.
|
|
||||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
|
||||||
"structure", // As passed in via mct-control
|
|
||||||
jasmine.any(Function)
|
|
||||||
);
|
|
||||||
|
|
||||||
mockScope.$watch.calls.mostRecent().args[1](testStructure);
|
|
||||||
|
|
||||||
buttonStructure = controller.getButtonStructure();
|
|
||||||
expect(buttonStructure.cssClass).toEqual(testStructure.cssClass);
|
|
||||||
expect(buttonStructure.description).toEqual(testStructure.description);
|
|
||||||
expect(buttonStructure.name).toEqual(testStructure.name);
|
|
||||||
expect(buttonStructure.click).toEqual(jasmine.any(Function));
|
|
||||||
});
|
|
||||||
|
|
||||||
it("shows a dialog when clicked", function () {
|
|
||||||
mockScope.$watch.calls.mostRecent().args[1](testStructure);
|
|
||||||
// Verify precondition - no dialog shown
|
|
||||||
expect(mockDialogService.getUserInput).not.toHaveBeenCalled();
|
|
||||||
// Click!
|
|
||||||
controller.getButtonStructure().click();
|
|
||||||
// Should have shown a dialog
|
|
||||||
expect(mockDialogService.getUserInput).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("stores user input to the model", function () {
|
|
||||||
var key, input = {};
|
|
||||||
// Show dialog, click...
|
|
||||||
mockScope.$watch.calls.mostRecent().args[1](testStructure);
|
|
||||||
controller.getButtonStructure().click();
|
|
||||||
// Should be listening to 'then'
|
|
||||||
expect(mockPromise.then)
|
|
||||||
.toHaveBeenCalledWith(jasmine.any(Function));
|
|
||||||
// Find the key that the dialog should return
|
|
||||||
key = mockDialogService.getUserInput.calls.mostRecent()
|
|
||||||
.args[0].sections[0].rows[0].key;
|
|
||||||
// Provide 'user input'
|
|
||||||
input[key] = "test user input";
|
|
||||||
// Resolve the promise with it
|
|
||||||
mockPromise.then.calls.mostRecent().args[0](input);
|
|
||||||
// ... should have been placed into the model
|
|
||||||
expect(mockScope.ngModel.testKey).toEqual("test user input");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("supplies initial model state to the dialog", function () {
|
|
||||||
var key, state;
|
|
||||||
mockScope.$watch.calls.mostRecent().args[1](testStructure);
|
|
||||||
controller.getButtonStructure().click();
|
|
||||||
// Find the key that the dialog should return
|
|
||||||
key = mockDialogService.getUserInput.calls.mostRecent()
|
|
||||||
.args[0].sections[0].rows[0].key;
|
|
||||||
// Get the initial state provided to the dialog
|
|
||||||
state = mockDialogService.getUserInput.calls.mostRecent().args[1];
|
|
||||||
// Should have had value from ngModel stored to that key
|
|
||||||
expect(state[key]).toEqual("initial test value");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,87 +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/controllers/FormController"],
|
|
||||||
function (FormController) {
|
|
||||||
|
|
||||||
describe("The form controller", function () {
|
|
||||||
var mockScope,
|
|
||||||
controller;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockScope = jasmine.createSpyObj("$scope", ["$watch"]);
|
|
||||||
mockScope.$parent = {};
|
|
||||||
controller = new FormController(mockScope);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("watches for changes in form by name", function () {
|
|
||||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
|
||||||
"mctForm",
|
|
||||||
jasmine.any(Function)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("conveys form status to parent scope", function () {
|
|
||||||
var someState = { someKey: "some value" };
|
|
||||||
mockScope.name = "someName";
|
|
||||||
mockScope.$watch.calls.mostRecent().args[1](someState);
|
|
||||||
expect(mockScope.$parent.someName).toBe(someState);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("allows strings to be converted to RegExps", function () {
|
|
||||||
// Should have added getRegExp to the scope,
|
|
||||||
// to convert strings to regular expressions
|
|
||||||
expect(mockScope.getRegExp("^\\d+$")).toEqual(/^\d+$/);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns the same regexp instance for the same string", function () {
|
|
||||||
// Don't want new instances each digest cycle, for performance
|
|
||||||
var strRegExp = "^[a-z]\\d+$",
|
|
||||||
regExp;
|
|
||||||
|
|
||||||
// Add getRegExp to scope
|
|
||||||
regExp = mockScope.getRegExp(strRegExp);
|
|
||||||
|
|
||||||
// Same object instance each time...
|
|
||||||
expect(mockScope.getRegExp(strRegExp)).toBe(regExp);
|
|
||||||
expect(mockScope.getRegExp(strRegExp)).toBe(regExp);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("passes RegExp objects through untouched", function () {
|
|
||||||
// Permit using forms to simply provide their own RegExp object
|
|
||||||
var regExp = /^\d+[a-d]$/;
|
|
||||||
|
|
||||||
// Should have added getRegExp to the scope,
|
|
||||||
// to convert strings to regular expressions
|
|
||||||
expect(mockScope.getRegExp(regExp)).toBe(regExp);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("passes a non-whitespace regexp when no pattern is defined", function () {
|
|
||||||
// If no pattern is supplied, ng-pattern should match anything
|
|
||||||
expect(mockScope.getRegExp()).toEqual(/\S/);
|
|
||||||
expect(mockScope.getRegExp(undefined)).toEqual(/\S/);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,14 +0,0 @@
|
|||||||
# Import / Export Plugin
|
|
||||||
The Import/Export plugin allows objects to be exported as JSON files. This allows for sharing of objects between users
|
|
||||||
who are not using a shared persistence store. It also allows object trees to be backed up. Additionally, object trees
|
|
||||||
exported using this tool can then be exposed as read-only static root trees using the
|
|
||||||
[Static Root Plugin](../../src/plugins/staticRootPlugin/README.md).
|
|
||||||
|
|
||||||
Upon installation it will add two new context menu actions to allow import and export of objects. Initiating the Export
|
|
||||||
action on an object will produce a JSON file that includes the object and all of its composed children. Selecting Import
|
|
||||||
on an object will allow the user to import a previously exported object tree as a child of the selected object.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
```js
|
|
||||||
openmct.install(openmct.plugins.ImportExport())
|
|
||||||
```
|
|
@ -1,82 +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/ExportAsJSONAction",
|
|
||||||
"./src/actions/ImportAsJSONAction"
|
|
||||||
], function (
|
|
||||||
ExportAsJSONAction,
|
|
||||||
ImportAsJSONAction
|
|
||||||
) {
|
|
||||||
|
|
||||||
return function ImportExportPlugin() {
|
|
||||||
return function (openmct) {
|
|
||||||
ExportAsJSONAction.prototype.appliesTo = function (context) {
|
|
||||||
return this.openmct.$injector.get('policyService')
|
|
||||||
.allow("creation", context.domainObject.getCapability("type")
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
openmct.legacyRegistry.register("platform/import-export", {
|
|
||||||
"name": "Import-export plugin",
|
|
||||||
"description": "Allows importing / exporting of domain objects as JSON.",
|
|
||||||
"extensions": {
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"key": "export.JSON",
|
|
||||||
"name": "Export as JSON",
|
|
||||||
"implementation": ExportAsJSONAction,
|
|
||||||
"category": "contextual",
|
|
||||||
"cssClass": "icon-export",
|
|
||||||
"group": "json",
|
|
||||||
"priority": 2,
|
|
||||||
"depends": [
|
|
||||||
"openmct",
|
|
||||||
"exportService",
|
|
||||||
"policyService",
|
|
||||||
"identifierService",
|
|
||||||
"typeService"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "import.JSON",
|
|
||||||
"name": "Import from JSON",
|
|
||||||
"implementation": ImportAsJSONAction,
|
|
||||||
"category": "contextual",
|
|
||||||
"cssClass": "icon-import",
|
|
||||||
"group": "json",
|
|
||||||
"priority": 2,
|
|
||||||
"depends": [
|
|
||||||
"exportService",
|
|
||||||
"identifierService",
|
|
||||||
"dialogService",
|
|
||||||
"openmct"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
openmct.legacyRegistry.enable('platform/import-export');
|
|
||||||
};
|
|
||||||
};
|
|
||||||
});
|
|
@ -1,202 +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(['lodash'], function (_) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The ExportAsJSONAction is available from context menus and allows a user
|
|
||||||
* to export any creatable domain object as a JSON file.
|
|
||||||
*
|
|
||||||
* @implements {Action}
|
|
||||||
* @constructor
|
|
||||||
* @memberof platform/import-export
|
|
||||||
*/
|
|
||||||
function ExportAsJSONAction(
|
|
||||||
openmct,
|
|
||||||
exportService,
|
|
||||||
policyService,
|
|
||||||
identifierService,
|
|
||||||
typeService,
|
|
||||||
context
|
|
||||||
) {
|
|
||||||
this.openmct = openmct;
|
|
||||||
this.root = {};
|
|
||||||
this.tree = {};
|
|
||||||
this.calls = 0;
|
|
||||||
this.context = context;
|
|
||||||
this.externalIdentifiers = [];
|
|
||||||
this.exportService = exportService;
|
|
||||||
this.policyService = policyService;
|
|
||||||
this.identifierService = identifierService;
|
|
||||||
this.typeService = typeService;
|
|
||||||
|
|
||||||
this.idMap = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ExportAsJSONAction.prototype.perform = function () {
|
|
||||||
var root = this.context.domainObject.useCapability('adapter');
|
|
||||||
this.root = this.copyObject(root);
|
|
||||||
var rootId = this.getId(this.root);
|
|
||||||
this.tree[rootId] = this.root;
|
|
||||||
|
|
||||||
this.saveAs = function (completedTree) {
|
|
||||||
this.exportService.exportJSON(
|
|
||||||
completedTree,
|
|
||||||
{filename: this.root.name + '.json'}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.write(this.root);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Traverses object hierarchy and populates tree object with models and
|
|
||||||
* identifiers.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {Object} parent
|
|
||||||
*/
|
|
||||||
ExportAsJSONAction.prototype.write = function (parent) {
|
|
||||||
this.calls++;
|
|
||||||
var composition = this.openmct.composition.get(parent);
|
|
||||||
|
|
||||||
if (composition !== undefined) {
|
|
||||||
composition.load()
|
|
||||||
.then(function (children) {
|
|
||||||
children.forEach(function (child, index) {
|
|
||||||
// Only export if object is creatable
|
|
||||||
if (this.isCreatable(child)) {
|
|
||||||
// Prevents infinite export of self-contained objs
|
|
||||||
if (!Object.prototype.hasOwnProperty.call(this.tree, this.getId(child))) {
|
|
||||||
// If object is a link to something absent from
|
|
||||||
// tree, generate new id and treat as new object
|
|
||||||
if (this.isExternal(child, parent)) {
|
|
||||||
child = this.rewriteLink(child, parent);
|
|
||||||
} else {
|
|
||||||
this.tree[this.getId(child)] = child;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.write(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.bind(this));
|
|
||||||
this.calls--;
|
|
||||||
if (this.calls === 0) {
|
|
||||||
this.rewriteReferences();
|
|
||||||
this.saveAs(this.wrapTree());
|
|
||||||
}
|
|
||||||
}.bind(this));
|
|
||||||
} else {
|
|
||||||
this.calls--;
|
|
||||||
if (this.calls === 0) {
|
|
||||||
this.rewriteReferences();
|
|
||||||
this.saveAs(this.wrapTree());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exports an externally linked object as an entirely new object in the
|
|
||||||
* case where the original is not present in the exported tree.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
ExportAsJSONAction.prototype.rewriteLink = function (child, parent) {
|
|
||||||
this.externalIdentifiers.push(this.getId(child));
|
|
||||||
var index = parent.composition.findIndex(id => {
|
|
||||||
return _.isEqual(child.identifier, id);
|
|
||||||
});
|
|
||||||
var copyOfChild = this.copyObject(child);
|
|
||||||
copyOfChild.identifier.key = this.identifierService.generate();
|
|
||||||
var newIdString = this.getId(copyOfChild);
|
|
||||||
var parentId = this.getId(parent);
|
|
||||||
|
|
||||||
this.idMap[this.getId(child)] = newIdString;
|
|
||||||
copyOfChild.location = parentId;
|
|
||||||
parent.composition[index] = copyOfChild.identifier;
|
|
||||||
this.tree[newIdString] = copyOfChild;
|
|
||||||
this.tree[parentId].composition[index] = copyOfChild.identifier;
|
|
||||||
|
|
||||||
return copyOfChild;
|
|
||||||
};
|
|
||||||
|
|
||||||
ExportAsJSONAction.prototype.copyObject = function (object) {
|
|
||||||
var jsonString = JSON.stringify(object);
|
|
||||||
|
|
||||||
return JSON.parse(jsonString);
|
|
||||||
};
|
|
||||||
|
|
||||||
ExportAsJSONAction.prototype.isExternal = function (child, parent) {
|
|
||||||
if (child.location !== this.getId(parent)
|
|
||||||
&& !Object.keys(this.tree).includes(child.location)
|
|
||||||
&& this.getId(child) !== this.getId(this.root)
|
|
||||||
|| this.externalIdentifiers.includes(this.getId(child))) {
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wraps root object for identification on reimport and wraps entire
|
|
||||||
* exported JSON construct for validation.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
ExportAsJSONAction.prototype.wrapTree = function () {
|
|
||||||
return {
|
|
||||||
"openmct": this.tree,
|
|
||||||
"rootId": this.getId(this.root)
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
ExportAsJSONAction.prototype.isCreatable = function (domainObject) {
|
|
||||||
var type = this.typeService.getType(domainObject.type);
|
|
||||||
|
|
||||||
return this.policyService.allow(
|
|
||||||
"creation",
|
|
||||||
type
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
ExportAsJSONAction.prototype.getId = function (domainObject) {
|
|
||||||
return this.openmct.objects.makeKeyString(domainObject.identifier);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
ExportAsJSONAction.prototype.rewriteReferences = function () {
|
|
||||||
var treeString = JSON.stringify(this.tree);
|
|
||||||
Object.keys(this.idMap).forEach(function (oldId) {
|
|
||||||
var newId = this.idMap[oldId];
|
|
||||||
treeString = treeString.split(oldId).join(newId);
|
|
||||||
}.bind(this));
|
|
||||||
this.tree = JSON.parse(treeString);
|
|
||||||
};
|
|
||||||
|
|
||||||
return ExportAsJSONAction;
|
|
||||||
});
|
|
@ -1,238 +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(['zepto', 'objectUtils'], function ($, objectUtils) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The ImportAsJSONAction is available from context menus and allows a user
|
|
||||||
* to import a previously exported domain object into any domain object
|
|
||||||
* that has the composition capability.
|
|
||||||
*
|
|
||||||
* @implements {Action}
|
|
||||||
* @constructor
|
|
||||||
* @memberof platform/import-export
|
|
||||||
*/
|
|
||||||
function ImportAsJSONAction(
|
|
||||||
exportService,
|
|
||||||
identifierService,
|
|
||||||
dialogService,
|
|
||||||
openmct,
|
|
||||||
context
|
|
||||||
) {
|
|
||||||
|
|
||||||
this.openmct = openmct;
|
|
||||||
this.context = context;
|
|
||||||
this.exportService = exportService;
|
|
||||||
this.dialogService = dialogService;
|
|
||||||
this.identifierService = identifierService;
|
|
||||||
this.instantiate = openmct.$injector.get("instantiate");
|
|
||||||
}
|
|
||||||
|
|
||||||
ImportAsJSONAction.prototype.perform = function () {
|
|
||||||
this.dialogService.getUserInput(this.getFormModel(), {})
|
|
||||||
.then(function (form) {
|
|
||||||
var objectTree = form.selectFile.body;
|
|
||||||
if (this.validateJSON(objectTree)) {
|
|
||||||
this.importObjectTree(JSON.parse(objectTree));
|
|
||||||
} else {
|
|
||||||
this.displayError();
|
|
||||||
}
|
|
||||||
}.bind(this));
|
|
||||||
};
|
|
||||||
|
|
||||||
ImportAsJSONAction.prototype.importObjectTree = function (objTree) {
|
|
||||||
var parent = this.context.domainObject;
|
|
||||||
var namespace = parent.useCapability('adapter').identifier.namespace;
|
|
||||||
|
|
||||||
var tree = this.generateNewIdentifiers(objTree, namespace);
|
|
||||||
var rootId = tree.rootId;
|
|
||||||
|
|
||||||
var rootModel = tree.openmct[rootId];
|
|
||||||
delete rootModel.persisted;
|
|
||||||
|
|
||||||
var rootObj = this.instantiate(rootModel, rootId);
|
|
||||||
var newStyleParent = parent.useCapability('adapter');
|
|
||||||
var newStyleRootObj = rootObj.useCapability('adapter');
|
|
||||||
|
|
||||||
if (this.openmct.composition.checkPolicy(newStyleParent, newStyleRootObj)) {
|
|
||||||
// Instantiate all objects in tree with their newly generated ids,
|
|
||||||
// adding each to its rightful parent's composition
|
|
||||||
rootObj.getCapability("location").setPrimaryLocation(parent.getId());
|
|
||||||
this.deepInstantiate(rootObj, tree.openmct, []);
|
|
||||||
parent.getCapability("composition").add(rootObj);
|
|
||||||
} else {
|
|
||||||
var dialog = this.openmct.overlays.dialog({
|
|
||||||
iconClass: 'alert',
|
|
||||||
message: "We're sorry, but you cannot import that object type into this object.",
|
|
||||||
buttons: [
|
|
||||||
{
|
|
||||||
label: "Ok",
|
|
||||||
emphasis: true,
|
|
||||||
callback: function () {
|
|
||||||
dialog.dismiss();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ImportAsJSONAction.prototype.deepInstantiate = function (parent, tree, seen) {
|
|
||||||
// Traverses object tree, instantiates all domain object w/ new IDs and
|
|
||||||
// adds to parent's composition
|
|
||||||
if (parent.hasCapability("composition")) {
|
|
||||||
var parentModel = parent.getModel();
|
|
||||||
var newObj;
|
|
||||||
|
|
||||||
seen.push(parent.getId());
|
|
||||||
|
|
||||||
parentModel.composition.forEach(function (childId) {
|
|
||||||
let keystring = this.openmct.objects.makeKeyString(childId);
|
|
||||||
|
|
||||||
if (!tree[keystring] || seen.includes(keystring)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let newModel = tree[keystring];
|
|
||||||
delete newModel.persisted;
|
|
||||||
|
|
||||||
newObj = this.instantiate(newModel, keystring);
|
|
||||||
newObj.getCapability("location")
|
|
||||||
.setPrimaryLocation(tree[keystring].location);
|
|
||||||
this.deepInstantiate(newObj, tree, seen);
|
|
||||||
}, this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ImportAsJSONAction.prototype.generateNewIdentifiers = function (tree, namespace) {
|
|
||||||
// For each domain object in the file, generate new ID, replace in tree
|
|
||||||
Object.keys(tree.openmct).forEach(function (domainObjectId) {
|
|
||||||
let newId = {
|
|
||||||
namespace: namespace,
|
|
||||||
key: this.identifierService.generate()
|
|
||||||
};
|
|
||||||
|
|
||||||
let oldId = objectUtils.parseKeyString(domainObjectId);
|
|
||||||
|
|
||||||
tree = this.rewriteId(oldId, newId, tree);
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
return tree;
|
|
||||||
};
|
|
||||||
|
|
||||||
ImportAsJSONAction.prototype.getKeyString = function (identifier) {
|
|
||||||
return this.openmct.objects.makeKeyString(identifier);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rewrites all instances of a given id in the tree with a newly generated
|
|
||||||
* replacement to prevent collision.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
ImportAsJSONAction.prototype.rewriteId = function (oldId, newId, tree) {
|
|
||||||
let newIdKeyString = this.openmct.objects.makeKeyString(newId);
|
|
||||||
let oldIdKeyString = this.openmct.objects.makeKeyString(oldId);
|
|
||||||
tree = JSON.stringify(tree).replace(new RegExp(oldIdKeyString, 'g'), newIdKeyString);
|
|
||||||
|
|
||||||
return JSON.parse(tree, (key, value) => {
|
|
||||||
if (value !== undefined
|
|
||||||
&& value !== null
|
|
||||||
&& Object.prototype.hasOwnProperty.call(value, 'key')
|
|
||||||
&& Object.prototype.hasOwnProperty.call(value, 'namespace')
|
|
||||||
&& value.key === oldId.key
|
|
||||||
&& value.namespace === oldId.namespace) {
|
|
||||||
return newId;
|
|
||||||
} else {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
ImportAsJSONAction.prototype.getFormModel = function () {
|
|
||||||
return {
|
|
||||||
name: "Import as JSON",
|
|
||||||
sections: [
|
|
||||||
{
|
|
||||||
name: "Import A File",
|
|
||||||
rows: [
|
|
||||||
{
|
|
||||||
name: 'Select File',
|
|
||||||
key: 'selectFile',
|
|
||||||
control: 'file-input',
|
|
||||||
required: true,
|
|
||||||
text: 'Select File...'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
ImportAsJSONAction.prototype.validateJSON = function (jsonString) {
|
|
||||||
var json;
|
|
||||||
try {
|
|
||||||
json = JSON.parse(jsonString);
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!json.openmct || !json.rootId) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
ImportAsJSONAction.prototype.displayError = function () {
|
|
||||||
var dialog,
|
|
||||||
model = {
|
|
||||||
title: "Invalid File",
|
|
||||||
actionText: "The selected file was either invalid JSON or was "
|
|
||||||
+ "not formatted properly for import into Open MCT.",
|
|
||||||
severity: "error",
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
label: "Ok",
|
|
||||||
callback: function () {
|
|
||||||
dialog.dismiss();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
dialog = this.dialogService.showBlockingMessage(model);
|
|
||||||
};
|
|
||||||
|
|
||||||
ImportAsJSONAction.appliesTo = function (context, view, openmct) {
|
|
||||||
let domainObject = (context || {}).domainObject;
|
|
||||||
|
|
||||||
if (!domainObject || (domainObject.model && domainObject.model.locked)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let isPersistable = openmct.objects.isPersistable(domainObject.id);
|
|
||||||
let hasComposition = domainObject.hasCapability('composition');
|
|
||||||
|
|
||||||
return hasComposition && isPersistable;
|
|
||||||
};
|
|
||||||
|
|
||||||
return ImportAsJSONAction;
|
|
||||||
});
|
|
12
src/MCT.js
12
src/MCT.js
@ -46,7 +46,10 @@ define([
|
|||||||
'./plugins/licenses/plugin',
|
'./plugins/licenses/plugin',
|
||||||
'./plugins/remove/plugin',
|
'./plugins/remove/plugin',
|
||||||
'./plugins/move/plugin',
|
'./plugins/move/plugin',
|
||||||
|
'./plugins/linkAction/plugin',
|
||||||
'./plugins/duplicate/plugin',
|
'./plugins/duplicate/plugin',
|
||||||
|
'./plugins/importFromJSONAction/plugin',
|
||||||
|
'./plugins/exportAsJSONAction/plugin',
|
||||||
'vue'
|
'vue'
|
||||||
], function (
|
], function (
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
@ -74,7 +77,10 @@ define([
|
|||||||
LicensesPlugin,
|
LicensesPlugin,
|
||||||
RemoveActionPlugin,
|
RemoveActionPlugin,
|
||||||
MoveActionPlugin,
|
MoveActionPlugin,
|
||||||
|
LinkActionPlugin,
|
||||||
DuplicateActionPlugin,
|
DuplicateActionPlugin,
|
||||||
|
ImportFromJSONAction,
|
||||||
|
ExportAsJSONAction,
|
||||||
Vue
|
Vue
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
@ -254,6 +260,7 @@ define([
|
|||||||
this.priority = api.PriorityAPI;
|
this.priority = api.PriorityAPI;
|
||||||
|
|
||||||
this.router = new ApplicationRouter(this);
|
this.router = new ApplicationRouter(this);
|
||||||
|
this.forms = new api.FormsAPI.default(this);
|
||||||
|
|
||||||
this.branding = BrandingAPI.default;
|
this.branding = BrandingAPI.default;
|
||||||
|
|
||||||
@ -270,14 +277,17 @@ define([
|
|||||||
this.install(LicensesPlugin.default());
|
this.install(LicensesPlugin.default());
|
||||||
this.install(RemoveActionPlugin.default());
|
this.install(RemoveActionPlugin.default());
|
||||||
this.install(MoveActionPlugin.default());
|
this.install(MoveActionPlugin.default());
|
||||||
|
this.install(LinkActionPlugin.default());
|
||||||
this.install(DuplicateActionPlugin.default());
|
this.install(DuplicateActionPlugin.default());
|
||||||
|
this.install(ExportAsJSONAction.default());
|
||||||
|
this.install(ImportFromJSONAction.default());
|
||||||
|
this.install(this.plugins.FormActions.default());
|
||||||
this.install(this.plugins.FolderView());
|
this.install(this.plugins.FolderView());
|
||||||
this.install(this.plugins.Tabs());
|
this.install(this.plugins.Tabs());
|
||||||
this.install(ImageryPlugin.default());
|
this.install(ImageryPlugin.default());
|
||||||
this.install(this.plugins.FlexibleLayout());
|
this.install(this.plugins.FlexibleLayout());
|
||||||
this.install(this.plugins.GoToOriginalAction());
|
this.install(this.plugins.GoToOriginalAction());
|
||||||
this.install(this.plugins.OpenInNewTabAction());
|
this.install(this.plugins.OpenInNewTabAction());
|
||||||
this.install(this.plugins.ImportExport());
|
|
||||||
this.install(this.plugins.WebPage());
|
this.install(this.plugins.WebPage());
|
||||||
this.install(this.plugins.Condition());
|
this.install(this.plugins.Condition());
|
||||||
this.install(this.plugins.ConditionWidget());
|
this.install(this.plugins.ConditionWidget());
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
const INSIDE_EDIT_PATH_BLACKLIST = ["copy", "follow", "link", "locate", "move", "link"];
|
const INSIDE_EDIT_PATH_BLACKLIST = ["copy", "follow", "link", "locate", "move", "link"];
|
||||||
const OUTSIDE_EDIT_PATH_BLACKLIST = ["copy", "follow", "properties", "move", "link", "remove", "locate"];
|
const OUTSIDE_EDIT_PATH_BLACKLIST = ["copy", "follow", "move", "link", "remove", "locate"];
|
||||||
|
|
||||||
export default class LegacyContextMenuAction {
|
export default class LegacyContextMenuAction {
|
||||||
constructor(openmct, LegacyAction) {
|
constructor(openmct, LegacyAction) {
|
||||||
|
@ -21,44 +21,47 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define([
|
define([
|
||||||
'./time/TimeAPI',
|
|
||||||
'./objects/ObjectAPI',
|
|
||||||
'./composition/CompositionAPI',
|
|
||||||
'./types/TypeRegistry',
|
|
||||||
'./telemetry/TelemetryAPI',
|
|
||||||
'./indicators/IndicatorAPI',
|
|
||||||
'./notifications/NotificationAPI',
|
|
||||||
'./Editor',
|
|
||||||
'./menu/MenuAPI',
|
|
||||||
'./actions/ActionsAPI',
|
'./actions/ActionsAPI',
|
||||||
|
'./composition/CompositionAPI',
|
||||||
|
'./Editor',
|
||||||
|
'./forms/FormsAPI',
|
||||||
|
'./indicators/IndicatorAPI',
|
||||||
|
'./menu/MenuAPI',
|
||||||
|
'./notifications/NotificationAPI',
|
||||||
|
'./objects/ObjectAPI',
|
||||||
|
'./priority/PriorityAPI',
|
||||||
'./status/StatusAPI',
|
'./status/StatusAPI',
|
||||||
'./priority/PriorityAPI'
|
'./telemetry/TelemetryAPI',
|
||||||
|
'./time/TimeAPI',
|
||||||
|
'./types/TypeRegistry'
|
||||||
], function (
|
], function (
|
||||||
TimeAPI,
|
|
||||||
ObjectAPI,
|
|
||||||
CompositionAPI,
|
|
||||||
TypeRegistry,
|
|
||||||
TelemetryAPI,
|
|
||||||
IndicatorAPI,
|
|
||||||
NotificationAPI,
|
|
||||||
EditorAPI,
|
|
||||||
MenuAPI,
|
|
||||||
ActionsAPI,
|
ActionsAPI,
|
||||||
|
CompositionAPI,
|
||||||
|
EditorAPI,
|
||||||
|
FormsAPI,
|
||||||
|
IndicatorAPI,
|
||||||
|
MenuAPI,
|
||||||
|
NotificationAPI,
|
||||||
|
ObjectAPI,
|
||||||
|
PriorityAPI,
|
||||||
StatusAPI,
|
StatusAPI,
|
||||||
PriorityAPI
|
TelemetryAPI,
|
||||||
|
TimeAPI,
|
||||||
|
TypeRegistry
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
TimeAPI: TimeAPI.default,
|
|
||||||
ObjectAPI: ObjectAPI,
|
|
||||||
CompositionAPI: CompositionAPI,
|
|
||||||
TypeRegistry: TypeRegistry,
|
|
||||||
TelemetryAPI: TelemetryAPI,
|
|
||||||
IndicatorAPI: IndicatorAPI,
|
|
||||||
NotificationAPI: NotificationAPI.default,
|
|
||||||
EditorAPI: EditorAPI,
|
|
||||||
MenuAPI: MenuAPI.default,
|
|
||||||
ActionsAPI: ActionsAPI.default,
|
ActionsAPI: ActionsAPI.default,
|
||||||
|
CompositionAPI: CompositionAPI,
|
||||||
|
EditorAPI: EditorAPI,
|
||||||
|
FormsAPI: FormsAPI,
|
||||||
|
IndicatorAPI: IndicatorAPI,
|
||||||
|
MenuAPI: MenuAPI.default,
|
||||||
|
NotificationAPI: NotificationAPI.default,
|
||||||
|
ObjectAPI: ObjectAPI,
|
||||||
|
PriorityAPI: PriorityAPI.default,
|
||||||
StatusAPI: StatusAPI.default,
|
StatusAPI: StatusAPI.default,
|
||||||
PriorityAPI: PriorityAPI.default
|
TelemetryAPI: TelemetryAPI,
|
||||||
|
TimeAPI: TimeAPI.default,
|
||||||
|
TypeRegistry: TypeRegistry
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
93
src/api/forms/FormController.js
Normal file
93
src/api/forms/FormController.js
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import AutoCompleteField from './components/controls/AutoCompleteField.vue';
|
||||||
|
import ClockDisplayFormatField from './components/controls/ClockDisplayFormatField.vue';
|
||||||
|
import Datetime from './components/controls/Datetime.vue';
|
||||||
|
import FileInput from './components/controls/FileInput.vue';
|
||||||
|
import Locator from './components/controls/Locator.vue';
|
||||||
|
import NumberField from './components/controls/NumberField.vue';
|
||||||
|
import SelectField from './components/controls/SelectField.vue';
|
||||||
|
import TextAreaField from './components/controls/TextAreaField.vue';
|
||||||
|
import TextField from './components/controls/TextField.vue';
|
||||||
|
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
export const DEFAULT_CONTROLS_MAP = {
|
||||||
|
'autocomplete': AutoCompleteField,
|
||||||
|
'composite': ClockDisplayFormatField,
|
||||||
|
'datetime': Datetime,
|
||||||
|
'file-input': FileInput,
|
||||||
|
'locator': Locator,
|
||||||
|
'numberfield': NumberField,
|
||||||
|
'select': SelectField,
|
||||||
|
'textarea': TextAreaField,
|
||||||
|
'textfield': TextField
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class FormControl {
|
||||||
|
constructor(openmct) {
|
||||||
|
this.openmct = openmct;
|
||||||
|
this.controls = {};
|
||||||
|
|
||||||
|
this._addDefaultFormControls();
|
||||||
|
}
|
||||||
|
|
||||||
|
addControl(controlName, controlViewProvider) {
|
||||||
|
const control = this.controls[controlName];
|
||||||
|
if (control) {
|
||||||
|
console.warn(`Error: provided form control '${controlName}', already exists`);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.controls[controlName] = controlViewProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
getControl(controlName) {
|
||||||
|
const control = this.controls[controlName];
|
||||||
|
if (!control) {
|
||||||
|
console.error(`Error: form control '${controlName}', does not exist`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return control;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_addDefaultFormControls() {
|
||||||
|
Object.keys(DEFAULT_CONTROLS_MAP).forEach(control => {
|
||||||
|
const controlViewProvider = this._getControlViewProvider(control);
|
||||||
|
this.addControl(control, controlViewProvider);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_getControlViewProvider(control) {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
return {
|
||||||
|
show(element, model, onChange) {
|
||||||
|
const rowComponent = new Vue({
|
||||||
|
el: element,
|
||||||
|
components: {
|
||||||
|
FormControlComponent: DEFAULT_CONTROLS_MAP[control]
|
||||||
|
},
|
||||||
|
provide: {
|
||||||
|
openmct: self.openmct
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
model,
|
||||||
|
onChange
|
||||||
|
};
|
||||||
|
},
|
||||||
|
template: `<FormControlComponent :model="model" @onChange="onChange"></FormControlComponent>`
|
||||||
|
});
|
||||||
|
|
||||||
|
return rowComponent;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
185
src/api/forms/FormsAPI.js
Normal file
185
src/api/forms/FormsAPI.js
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
import FormController from './FormController';
|
||||||
|
import FormProperties from './components/FormProperties.vue';
|
||||||
|
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
export default class FormsAPI {
|
||||||
|
constructor(openmct) {
|
||||||
|
this.openmct = openmct;
|
||||||
|
this.formController = new FormController(openmct);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control View Provider definition for a form control
|
||||||
|
* @typedef ControlViewProvider
|
||||||
|
* @property {function} show a function renders view in place of given element
|
||||||
|
* This function accepts element, model and onChange function
|
||||||
|
* element - html element (place holder) to render a row view
|
||||||
|
* model - row data for rendering name, value etc for given row type
|
||||||
|
* onChange - an onChange event callback funtion to keep track of any change in value
|
||||||
|
* @property {function} destroy a callback function when a vue component gets destroyed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new form control definition with a formControlViewProvider
|
||||||
|
* this formControlViewProvider is used inside form overlay to show/render a form row
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param {String} controlName a form structure, array of section
|
||||||
|
* @param {ControlViewProvider} controlViewProvider
|
||||||
|
*/
|
||||||
|
addNewFormControl(controlName, controlViewProvider) {
|
||||||
|
this.formController.addControl(controlName, controlViewProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a ControlViewProvider for a given/stored form controlName
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param {String} controlName a form structure, array of section
|
||||||
|
* @return {ControlViewProvider}
|
||||||
|
*/
|
||||||
|
getFormControl(controlName) {
|
||||||
|
return this.formController.getControl(controlName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Section definition for formStructure
|
||||||
|
* @typedef Section
|
||||||
|
* @property {object} name Name of the section to display on Form
|
||||||
|
* @property {string} cssClass class name for styling section
|
||||||
|
* @property {array<Row>} rows collection of rows inside a section
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Row definition for Section
|
||||||
|
* @typedef Row
|
||||||
|
* @property {string} control represents type of row to render
|
||||||
|
* eg:autocomplete,composite,datetime,file-input,locator,numberfield,select,textarea,textfield
|
||||||
|
* @property {string} cssClass class name for styling this row
|
||||||
|
* @property {module:openmct.DomainObject} domainObject object to be used by row
|
||||||
|
* @property {string} key id for this row
|
||||||
|
* @property {string} name Name of the row to display on Form
|
||||||
|
* @property {module:openmct.DomainObject} parent parent object to be used by row
|
||||||
|
* @property {boolean} required is this row mandatory
|
||||||
|
* @property {function} validate a function to validate this row on any changes
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show form inside an Overlay dialog with given form structure
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @param {Array<Section>} formStructure a form structure, array of section
|
||||||
|
* @param {Object} options
|
||||||
|
* @property {HTMLElement} element Parent Element to render a Form
|
||||||
|
* @property {function} onChange a callback function when any changes detected
|
||||||
|
* @property {function} onSave a callback function when form is submitted
|
||||||
|
* @property {function} onDismiss a callback function when form is dismissed
|
||||||
|
*/
|
||||||
|
showForm(formStructure, {
|
||||||
|
element,
|
||||||
|
onChange
|
||||||
|
} = {}) {
|
||||||
|
const changes = {};
|
||||||
|
let overlay;
|
||||||
|
let onDismiss;
|
||||||
|
let onSave;
|
||||||
|
|
||||||
|
const promise = new Promise((resolve, reject) => {
|
||||||
|
onSave = onFormSave(resolve);
|
||||||
|
onDismiss = onFormDismiss(reject);
|
||||||
|
});
|
||||||
|
|
||||||
|
const vm = new Vue({
|
||||||
|
components: { FormProperties },
|
||||||
|
provide: {
|
||||||
|
openmct: this.openmct
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
formStructure,
|
||||||
|
onChange: onFormPropertyChange,
|
||||||
|
onDismiss,
|
||||||
|
onSave
|
||||||
|
};
|
||||||
|
},
|
||||||
|
template: '<FormProperties :model="formStructure" @onChange="onChange" @onDismiss="onDismiss" @onSave="onSave"></FormProperties>'
|
||||||
|
}).$mount();
|
||||||
|
|
||||||
|
const formElement = vm.$el;
|
||||||
|
if (element) {
|
||||||
|
element.append(formElement);
|
||||||
|
} else {
|
||||||
|
overlay = this.openmct.overlays.overlay({
|
||||||
|
element: vm.$el,
|
||||||
|
size: 'small',
|
||||||
|
onDestroy: () => vm.$destroy()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function onFormPropertyChange(data) {
|
||||||
|
if (onChange) {
|
||||||
|
onChange(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.model) {
|
||||||
|
const property = data.model.property;
|
||||||
|
let key = data.model.key;
|
||||||
|
|
||||||
|
if (property && property.length) {
|
||||||
|
key = property.join('.');
|
||||||
|
}
|
||||||
|
|
||||||
|
changes[key] = data.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onFormDismiss(dismiss) {
|
||||||
|
return () => {
|
||||||
|
if (element) {
|
||||||
|
formElement.remove();
|
||||||
|
} else {
|
||||||
|
overlay.dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dismiss) {
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function onFormSave(save) {
|
||||||
|
return () => {
|
||||||
|
overlay.dismiss();
|
||||||
|
|
||||||
|
if (save) {
|
||||||
|
save(changes);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
}
|
137
src/api/forms/components/FormProperties.vue
Normal file
137
src/api/forms/components/FormProperties.vue
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="c-form">
|
||||||
|
<div class="c-overlay__top-bar c-form__top-bar">
|
||||||
|
<div class="c-overlay__dialog-title">{{ model.title }}</div>
|
||||||
|
<div class="c-overlay__dialog-hint hint">All fields marked <span class="req icon-asterisk"></span> are required.</div>
|
||||||
|
</div>
|
||||||
|
<form name="mctForm"
|
||||||
|
class="c-form__contents"
|
||||||
|
autocomplete="off"
|
||||||
|
@submit.prevent
|
||||||
|
>
|
||||||
|
<div v-for="section in formSections"
|
||||||
|
:key="section.id"
|
||||||
|
class="c-form__section"
|
||||||
|
:class="section.cssClass"
|
||||||
|
>
|
||||||
|
<h2 v-if="section.name"
|
||||||
|
class="c-form__section-header"
|
||||||
|
>
|
||||||
|
{{ section.name }}
|
||||||
|
</h2>
|
||||||
|
<div v-for="(row, index) in section.rows"
|
||||||
|
:key="row.id"
|
||||||
|
class="u-contents"
|
||||||
|
>
|
||||||
|
<FormRow :css-class="section.cssClass"
|
||||||
|
:first="index < 1"
|
||||||
|
:row="row"
|
||||||
|
@onChange="onChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="mct-form__controls c-overlay__button-bar c-form__bottom-bar">
|
||||||
|
<button tabindex="0"
|
||||||
|
:disabled="isInvalid"
|
||||||
|
class="c-button c-button--major"
|
||||||
|
@click="onSave"
|
||||||
|
>
|
||||||
|
OK
|
||||||
|
</button>
|
||||||
|
<button tabindex="0"
|
||||||
|
class="c-button"
|
||||||
|
@click="onDismiss"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import FormRow from "@/api/forms/components/FormRow.vue";
|
||||||
|
import uuid from 'uuid';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
FormRow
|
||||||
|
},
|
||||||
|
inject: ['openmct'],
|
||||||
|
props: {
|
||||||
|
model: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
invalidProperties: {},
|
||||||
|
formSections: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isInvalid() {
|
||||||
|
return Object.entries(this.invalidProperties)
|
||||||
|
.some(([key, value]) => {
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.formSections = this.model.sections.map(section => {
|
||||||
|
section.id = uuid();
|
||||||
|
|
||||||
|
section.rows = section.rows.map(row => {
|
||||||
|
row.id = uuid();
|
||||||
|
|
||||||
|
return row;
|
||||||
|
});
|
||||||
|
|
||||||
|
return section;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onChange(data) {
|
||||||
|
this.$set(this.invalidProperties, data.model.key, data.invalid);
|
||||||
|
|
||||||
|
this.$emit('onChange', data);
|
||||||
|
},
|
||||||
|
onDismiss() {
|
||||||
|
this.$emit('onDismiss');
|
||||||
|
},
|
||||||
|
onSave() {
|
||||||
|
this.$emit('onSave');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
146
src/api/forms/components/FormRow.vue
Normal file
146
src/api/forms/components/FormRow.vue
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="form-row c-form__row"
|
||||||
|
:class="[{ 'first': first }]"
|
||||||
|
@onChange="onChange"
|
||||||
|
>
|
||||||
|
<div class="c-form-row__label"
|
||||||
|
:title="row.description"
|
||||||
|
>
|
||||||
|
{{ row.name }}
|
||||||
|
</div>
|
||||||
|
<div class="c-form-row__state-indicator"
|
||||||
|
:class="rowClass"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div v-if="row.control"
|
||||||
|
class="c-form-row__controls"
|
||||||
|
>
|
||||||
|
<div ref="rowElement"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'FormRow',
|
||||||
|
components: {
|
||||||
|
},
|
||||||
|
inject: ['openmct'],
|
||||||
|
props: {
|
||||||
|
cssClass: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
first: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
row: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
formControl: this.openmct.forms.getFormControl(this.row.control),
|
||||||
|
valid: undefined,
|
||||||
|
visited: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
rowClass() {
|
||||||
|
let cssClass = this.cssClass;
|
||||||
|
|
||||||
|
if (this.row.required) {
|
||||||
|
cssClass = `${cssClass} req`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.visited && this.valid !== undefined) {
|
||||||
|
if (this.valid === true) {
|
||||||
|
cssClass = `${cssClass} valid`;
|
||||||
|
} else {
|
||||||
|
cssClass = `${cssClass} invalid`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cssClass;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.row.required) {
|
||||||
|
const data = {
|
||||||
|
model: this.row,
|
||||||
|
value: this.row.value
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onChange(data, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.formControl.show(this.$refs.rowElement, this.row, this.onChange);
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
const destroy = this.formControl.destroy;
|
||||||
|
if (destroy) {
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onChange(data, visited = true) {
|
||||||
|
this.visited = visited;
|
||||||
|
this.valid = this.validateRow(data);
|
||||||
|
data.invalid = !this.valid;
|
||||||
|
|
||||||
|
this.$emit('onChange', data);
|
||||||
|
},
|
||||||
|
validateRow(data) {
|
||||||
|
let valid = true;
|
||||||
|
if (this.row.required) {
|
||||||
|
valid = data.value !== undefined
|
||||||
|
&& data.value !== null
|
||||||
|
&& data.value !== '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.row.required && !valid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pattern = data.model.pattern;
|
||||||
|
if (valid && pattern) {
|
||||||
|
const regex = new RegExp(pattern);
|
||||||
|
valid = regex.test(data.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const validate = data.model.validate;
|
||||||
|
if (valid && validate) {
|
||||||
|
valid = validate(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Boolean(valid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
181
src/api/forms/components/controls/AutoCompleteField.vue
Normal file
181
src/api/forms/components/controls/AutoCompleteField.vue
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="form-control autocomplete">
|
||||||
|
<input v-model="field"
|
||||||
|
class="autocompleteInput"
|
||||||
|
type="text"
|
||||||
|
@click="inputClicked()"
|
||||||
|
@keydown="keyDown($event)"
|
||||||
|
>
|
||||||
|
<span class="icon-arrow-down"
|
||||||
|
@click="arrowClicked()"
|
||||||
|
></span>
|
||||||
|
<div class="autocompleteOptions"
|
||||||
|
@blur="hideOptions = true"
|
||||||
|
>
|
||||||
|
<ul v-if="!hideOptions">
|
||||||
|
<li v-for="opt in filteredOptions"
|
||||||
|
:key="opt.optionId"
|
||||||
|
:class="{'optionPreSelected': optionIndex === opt.optionId}"
|
||||||
|
@click="fillInputWithString(opt.name)"
|
||||||
|
@mouseover="optionMouseover(opt.optionId)"
|
||||||
|
>
|
||||||
|
<span class="optionText">{{ opt.name }}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const key = {
|
||||||
|
down: 40,
|
||||||
|
up: 38,
|
||||||
|
enter: 13
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
model: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
hideOptions: true,
|
||||||
|
optionIndex: 0,
|
||||||
|
field: this.model.value
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
filteredOptions() {
|
||||||
|
const options = this.optionNames || [];
|
||||||
|
|
||||||
|
return options
|
||||||
|
.filter(option => {
|
||||||
|
return option.toLowerCase().indexOf(this.field.toLowerCase()) >= 0;
|
||||||
|
}).map((option, index) => {
|
||||||
|
return {
|
||||||
|
optionId: index,
|
||||||
|
name: option
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
field(newValue, oldValue) {
|
||||||
|
if (newValue !== oldValue) {
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
model: this.model,
|
||||||
|
value: newValue
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$emit('onChange', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.options = this.model.options;
|
||||||
|
this.autocompleteInputElement = this.$el.getElementsByClassName('autocompleteInput')[0];
|
||||||
|
if (this.options[0].name) {
|
||||||
|
// If "options" include name, value pair
|
||||||
|
this.optionNames = this.options.map((opt) => {
|
||||||
|
return opt.name;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// If options is only an array of string.
|
||||||
|
this.optionNames = this.options;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
decrementOptionIndex() {
|
||||||
|
if (this.optionIndex === 0) {
|
||||||
|
this.optionIndex = this.filteredOptions.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.optionIndex--;
|
||||||
|
this.scrollIntoView();
|
||||||
|
},
|
||||||
|
incrementOptionIndex() {
|
||||||
|
if (this.optionIndex === this.filteredOptions.length - 1) {
|
||||||
|
this.optionIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.optionIndex++;
|
||||||
|
this.scrollIntoView();
|
||||||
|
},
|
||||||
|
fillInputWithString(string) {
|
||||||
|
this.hideOptions = true;
|
||||||
|
this.field = string;
|
||||||
|
},
|
||||||
|
showOptions(string) {
|
||||||
|
this.hideOptions = false;
|
||||||
|
this.optionIndex = 0;
|
||||||
|
},
|
||||||
|
keyDown($event) {
|
||||||
|
if (this.filteredOptions) {
|
||||||
|
let keyCode = $event.keyCode;
|
||||||
|
switch (keyCode) {
|
||||||
|
case key.down:
|
||||||
|
this.incrementOptionIndex();
|
||||||
|
break;
|
||||||
|
case key.up:
|
||||||
|
$event.preventDefault(); // Prevents cursor jumping back and forth
|
||||||
|
this.decrementOptionIndex();
|
||||||
|
break;
|
||||||
|
case key.enter:
|
||||||
|
if (this.filteredOptions[this.optionIndex]) {
|
||||||
|
this.fillInputWithString(this.filteredOptions[this.optionIndex].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
inputClicked() {
|
||||||
|
this.autocompleteInputElement.select();
|
||||||
|
this.showOptions(this.autocompleteInputElement.value);
|
||||||
|
},
|
||||||
|
arrowClicked() {
|
||||||
|
this.autocompleteInputElement.select();
|
||||||
|
this.showOptions('');
|
||||||
|
},
|
||||||
|
optionMouseover(optionId) {
|
||||||
|
this.optionIndex = optionId;
|
||||||
|
},
|
||||||
|
scrollIntoView() {
|
||||||
|
setTimeout(() => {
|
||||||
|
const element = this.$el.querySelector('.optionPreSelected');
|
||||||
|
if (element) {
|
||||||
|
element.scrollIntoView({
|
||||||
|
behavior: 'smooth',
|
||||||
|
block: 'center',
|
||||||
|
inline: 'nearest'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
@ -0,0 +1,66 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="c-form-control--clock-display-format-fields">
|
||||||
|
<SelectField v-for="item in items"
|
||||||
|
:key="item.key"
|
||||||
|
:model="item"
|
||||||
|
@onChange="onChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SelectField from '@/api/forms/components/controls/SelectField.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
SelectField
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
model: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
items: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
const values = this.model.value || [];
|
||||||
|
this.items = this.model.items.map((item, index) => {
|
||||||
|
item.value = values[index];
|
||||||
|
item.key = `${this.model.key}.${index}`;
|
||||||
|
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onChange(data) {
|
||||||
|
this.$emit('onChange', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
57
src/api/forms/components/controls/Composite.vue
Normal file
57
src/api/forms/components/controls/Composite.vue
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<span>
|
||||||
|
<CompositeItem v-for="(item, index) in model.items"
|
||||||
|
:key="item.name"
|
||||||
|
:first="index < 1"
|
||||||
|
:value="JSON.stringify(model.value[index])"
|
||||||
|
:item="item"
|
||||||
|
@onChange="onChange"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import CompositeItem from "@/api/forms/components/controls/CompositeItem.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
CompositeItem
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
model: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.model.items.forEach((item, index) => item.key = `${this.model.key}.${index}`);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onChange(data) {
|
||||||
|
this.$emit('onChange', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
75
src/api/forms/components/controls/CompositeItem.vue
Normal file
75
src/api/forms/components/controls/CompositeItem.vue
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div :class="compositeCssClass">
|
||||||
|
<FormRow :css-class="item.cssClass"
|
||||||
|
:first="first"
|
||||||
|
:row="row"
|
||||||
|
@onChange="onChange"
|
||||||
|
/>
|
||||||
|
<span class="composite-control-label">
|
||||||
|
{{ item.name }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
FormRow: () => import('@/api/forms/components/FormRow.vue')
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
item: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
first: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default() {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
compositeCssClass() {
|
||||||
|
return `l-composite-control l-${this.item.control}`;
|
||||||
|
},
|
||||||
|
row() {
|
||||||
|
const row = this.item;
|
||||||
|
row.value = JSON.parse(this.value);
|
||||||
|
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onChange(data) {
|
||||||
|
this.$emit('onChange', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
169
src/api/forms/components/controls/Datetime.vue
Normal file
169
src/api/forms/components/controls/Datetime.vue
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="c-form-control--datetime">
|
||||||
|
<div class="hint date">Date</div>
|
||||||
|
<div class="hint time sm">Hour</div>
|
||||||
|
<div class="hint time sm">Min</div>
|
||||||
|
<div class="hint time sm">Sec</div>
|
||||||
|
<div class="hint timezone">Timezone</div>
|
||||||
|
<form ref="dateTimeForm"
|
||||||
|
prevent
|
||||||
|
class="u-contents"
|
||||||
|
>
|
||||||
|
<div class="field control date">
|
||||||
|
<input v-model="date"
|
||||||
|
:pattern="/\d{4}-\d{2}-\d{2}/"
|
||||||
|
:placeholder="format"
|
||||||
|
type="date"
|
||||||
|
name="date"
|
||||||
|
@change="onChange"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="field control hour sm">
|
||||||
|
<input v-model="hour"
|
||||||
|
:pattern="/\d+/"
|
||||||
|
type="number"
|
||||||
|
name="hour"
|
||||||
|
maxlength="10"
|
||||||
|
min="0"
|
||||||
|
max="23"
|
||||||
|
@change="onChange"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="field control min sm">
|
||||||
|
<input v-model="min"
|
||||||
|
:pattern="/\d+/"
|
||||||
|
type="number"
|
||||||
|
name="min"
|
||||||
|
maxlength="2"
|
||||||
|
min="0"
|
||||||
|
max="59"
|
||||||
|
@change="onChange"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="field control sec sm">
|
||||||
|
<input v-model="sec"
|
||||||
|
:pattern="/\d+/"
|
||||||
|
type="number"
|
||||||
|
name="sec"
|
||||||
|
maxlength="2"
|
||||||
|
min="0"
|
||||||
|
max="59"
|
||||||
|
@change="onChange"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="field control timezone">
|
||||||
|
UTC
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const DATE_FORMAT = 'YYYY-MM-DD';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
model: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
format: DATE_FORMAT,
|
||||||
|
date: '',
|
||||||
|
hour: 0,
|
||||||
|
min: 0,
|
||||||
|
sec: 0
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.formatDatetime();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
convertToDatetime(timestamp) {
|
||||||
|
const dateValue = new Date(timestamp);
|
||||||
|
const date = dateValue.toISOString().slice(0, 10);
|
||||||
|
const hour = dateValue.getUTCHours() || 0;
|
||||||
|
const min = dateValue.getUTCMinutes() || 0;
|
||||||
|
const sec = dateValue.getUTCSeconds() || 0;
|
||||||
|
|
||||||
|
return {
|
||||||
|
date,
|
||||||
|
hour,
|
||||||
|
min,
|
||||||
|
sec
|
||||||
|
};
|
||||||
|
},
|
||||||
|
convertToTimestamp() {
|
||||||
|
const date = new Date(this.date);
|
||||||
|
date.setUTCHours(this.hour || 0);
|
||||||
|
date.setUTCMinutes(this.min || 0);
|
||||||
|
date.setUTCSeconds(this.sec || 0);
|
||||||
|
|
||||||
|
return date.getTime();
|
||||||
|
},
|
||||||
|
formatDatetime(timestamp = this.model.value) {
|
||||||
|
if (!timestamp) {
|
||||||
|
this.resetValues();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const datetime = this.convertToDatetime(timestamp);
|
||||||
|
this.setDatetime(datetime.date, datetime.hour, datetime.min, datetime.sec);
|
||||||
|
},
|
||||||
|
onChange() {
|
||||||
|
const timestamp = this.convertToTimestamp();
|
||||||
|
const model = this.model;
|
||||||
|
model.validate = () => this.validate(timestamp);
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
model,
|
||||||
|
value: timestamp
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$emit('onChange', data);
|
||||||
|
},
|
||||||
|
resetValues() {
|
||||||
|
this.setDatetime();
|
||||||
|
},
|
||||||
|
setDatetime(date = '', hour = 0, min = 0, sec = 0) {
|
||||||
|
this.date = date.toString();
|
||||||
|
this.hour = hour;
|
||||||
|
this.min = min;
|
||||||
|
this.sec = sec;
|
||||||
|
},
|
||||||
|
validate(timestamp) {
|
||||||
|
const valid = timestamp > 0 && this.$refs.dateTimeForm.checkValidity();
|
||||||
|
if (!valid) {
|
||||||
|
this.$refs.dateTimeForm.reportValidity();
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
100
src/api/forms/components/controls/FileInput.vue
Normal file
100
src/api/forms/components/controls/FileInput.vue
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<span class="form-control shell">
|
||||||
|
<span class="field control"
|
||||||
|
:class="model.cssClass"
|
||||||
|
>
|
||||||
|
<input id="fileElem"
|
||||||
|
ref="fileInput"
|
||||||
|
type="file"
|
||||||
|
accept=".json"
|
||||||
|
style="display:none"
|
||||||
|
>
|
||||||
|
<button id="fileSelect"
|
||||||
|
class="c-button"
|
||||||
|
@click="selectFile"
|
||||||
|
>
|
||||||
|
{{ name }}
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
inject: ['openmct'],
|
||||||
|
props: {
|
||||||
|
model: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
fileInfo: undefined
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
name() {
|
||||||
|
const fileInfo = this.fileInfo || this.model.value;
|
||||||
|
|
||||||
|
return fileInfo && fileInfo.name || this.model.text;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.$refs.fileInput.addEventListener("change", this.handleFiles, false);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleFiles() {
|
||||||
|
const fileList = this.$refs.fileInput.files;
|
||||||
|
this.readFile(fileList[0]);
|
||||||
|
},
|
||||||
|
readFile(file) {
|
||||||
|
const self = this;
|
||||||
|
const fileReader = new FileReader();
|
||||||
|
const fileInfo = {};
|
||||||
|
fileInfo.name = file.name;
|
||||||
|
fileReader.onload = function (event) {
|
||||||
|
fileInfo.body = event.target.result;
|
||||||
|
self.fileInfo = fileInfo;
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
model: self.model,
|
||||||
|
value: fileInfo
|
||||||
|
};
|
||||||
|
self.$emit('onChange', data);
|
||||||
|
};
|
||||||
|
|
||||||
|
fileReader.onerror = function (error) {
|
||||||
|
console.error('fileReader error', error);
|
||||||
|
};
|
||||||
|
|
||||||
|
fileReader.readAsText(file);
|
||||||
|
},
|
||||||
|
selectFile() {
|
||||||
|
this.$refs.fileInput.click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
56
src/api/forms/components/controls/Locator.vue
Normal file
56
src/api/forms/components/controls/Locator.vue
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<SelectorDialogTree :ignore-type-check="true"
|
||||||
|
:css-class="`form-locator c-form-control--locator`"
|
||||||
|
:parent="model.parent"
|
||||||
|
@treeItemSelected="handleItemSelection"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SelectorDialogTree from '@/ui/components/SelectorDialogTree.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
SelectorDialogTree
|
||||||
|
},
|
||||||
|
inject: ['openmct'],
|
||||||
|
props: {
|
||||||
|
model: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleItemSelection({ parentObjectPath }) {
|
||||||
|
const data = {
|
||||||
|
model: this.model,
|
||||||
|
value: parentObjectPath
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$emit('onChange', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
63
src/api/forms/components/controls/NumberField.vue
Normal file
63
src/api/forms/components/controls/NumberField.vue
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<span class="form-control shell">
|
||||||
|
<span class="field control"
|
||||||
|
:class="model.cssClass"
|
||||||
|
>
|
||||||
|
<input v-model="field"
|
||||||
|
type="number"
|
||||||
|
:min="model.min"
|
||||||
|
:max="model.max"
|
||||||
|
:step="model.step"
|
||||||
|
@blur="blur()"
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
model: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
field: this.model.value
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
blur() {
|
||||||
|
const data = {
|
||||||
|
model: this.model,
|
||||||
|
value: this.field
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$emit('onChange', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
64
src/api/forms/components/controls/SelectField.vue
Normal file
64
src/api/forms/components/controls/SelectField.vue
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="form-control select-field">
|
||||||
|
<select v-model="selected"
|
||||||
|
required="model.required"
|
||||||
|
name="mctControl"
|
||||||
|
@change="onChange($event)"
|
||||||
|
>
|
||||||
|
<option v-for="option in model.options"
|
||||||
|
:key="option.name"
|
||||||
|
:value="option.value"
|
||||||
|
>
|
||||||
|
{{ option.name }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
model: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
selected: this.model.value
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onChange() {
|
||||||
|
const data = {
|
||||||
|
model: this.model,
|
||||||
|
value: this.selected
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$emit('onChange', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
62
src/api/forms/components/controls/TextAreaField.vue
Normal file
62
src/api/forms/components/controls/TextAreaField.vue
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<span class="form-control shell">
|
||||||
|
<span class="field control"
|
||||||
|
:class="model.cssClass"
|
||||||
|
>
|
||||||
|
<textarea v-model="field"
|
||||||
|
type="text"
|
||||||
|
:size="model.size"
|
||||||
|
@blur="blur()"
|
||||||
|
>
|
||||||
|
</textarea>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
model: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
field: this.model.value
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
blur() {
|
||||||
|
const data = {
|
||||||
|
model: this.model,
|
||||||
|
value: this.field
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$emit('onChange', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
61
src/api/forms/components/controls/TextField.vue
Normal file
61
src/api/forms/components/controls/TextField.vue
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<span class="form-control shell">
|
||||||
|
<span class="field control"
|
||||||
|
:class="model.cssClass"
|
||||||
|
>
|
||||||
|
<input v-model="field"
|
||||||
|
type="text"
|
||||||
|
:size="model.size"
|
||||||
|
@blur="blur()"
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
model: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
field: this.model.value
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
blur() {
|
||||||
|
const data = {
|
||||||
|
model: this.model,
|
||||||
|
value: this.field
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$emit('onChange', data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
@ -20,24 +20,15 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define(
|
import {saveAs} from 'file-saver/FileSaver';
|
||||||
[],
|
|
||||||
function () {
|
|
||||||
|
|
||||||
/**
|
class JSONExporter {
|
||||||
* A policy for determining whether objects of a given type can be
|
export(obj, options) {
|
||||||
* created.
|
let filename = (options && options.filename) || "test-export.json";
|
||||||
* @constructor
|
let jsonText = JSON.stringify(obj);
|
||||||
* @implements {Policy}
|
let blob = new Blob([jsonText], {type: "application/json"});
|
||||||
* @memberof platform/commonUI/browse
|
saveAs(blob, filename);
|
||||||
*/
|
|
||||||
function CreationPolicy() {
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CreationPolicy.prototype.allow = function (type) {
|
export default JSONExporter;
|
||||||
return type.hasFeature("creation");
|
|
||||||
};
|
|
||||||
|
|
||||||
return CreationPolicy;
|
|
||||||
}
|
|
||||||
);
|
|
@ -35,7 +35,6 @@ const DEFAULTS = [
|
|||||||
'platform/containment',
|
'platform/containment',
|
||||||
'platform/exporters',
|
'platform/exporters',
|
||||||
'platform/telemetry',
|
'platform/telemetry',
|
||||||
'platform/forms',
|
|
||||||
'platform/identity',
|
'platform/identity',
|
||||||
'platform/persistence/aggregator',
|
'platform/persistence/aggregator',
|
||||||
'platform/policy',
|
'platform/policy',
|
||||||
@ -73,7 +72,6 @@ define([
|
|||||||
'../platform/entanglement/bundle',
|
'../platform/entanglement/bundle',
|
||||||
'../platform/exporters/bundle',
|
'../platform/exporters/bundle',
|
||||||
'../platform/features/static-markup/bundle',
|
'../platform/features/static-markup/bundle',
|
||||||
'../platform/forms/bundle',
|
|
||||||
'../platform/framework/bundle',
|
'../platform/framework/bundle',
|
||||||
'../platform/framework/src/load/Bundle',
|
'../platform/framework/src/load/Bundle',
|
||||||
'../platform/identity/bundle',
|
'../platform/identity/bundle',
|
||||||
|
@ -101,12 +101,12 @@
|
|||||||
<script>
|
<script>
|
||||||
|
|
||||||
import StyleEditor from "./StyleEditor.vue";
|
import StyleEditor from "./StyleEditor.vue";
|
||||||
import ConditionSetSelectorDialog from "./ConditionSetSelectorDialog.vue";
|
import SelectorDialogTree from '@/ui/components/SelectorDialogTree.vue';
|
||||||
import ConditionDescription from "@/plugins/condition/components/ConditionDescription.vue";
|
import ConditionDescription from "@/plugins/condition/components/ConditionDescription.vue";
|
||||||
import ConditionError from "@/plugins/condition/components/ConditionError.vue";
|
import ConditionError from "@/plugins/condition/components/ConditionError.vue";
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import PreviewAction from "@/ui/preview/PreviewAction.js";
|
import PreviewAction from "@/ui/preview/PreviewAction.js";
|
||||||
import {getApplicableStylesForItem} from "@/plugins/condition/utils/styleUtils";
|
import { getApplicableStylesForItem } from "@/plugins/condition/utils/styleUtils";
|
||||||
import isEmpty from 'lodash/isEmpty';
|
import isEmpty from 'lodash/isEmpty';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -224,7 +224,7 @@ export default {
|
|||||||
let conditionSetDomainObject;
|
let conditionSetDomainObject;
|
||||||
let self = this;
|
let self = this;
|
||||||
|
|
||||||
function handleItemSelection(item) {
|
function handleItemSelection({ item }) {
|
||||||
if (item) {
|
if (item) {
|
||||||
conditionSetDomainObject = item;
|
conditionSetDomainObject = item;
|
||||||
}
|
}
|
||||||
@ -240,16 +240,17 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let vm = new Vue({
|
let vm = new Vue({
|
||||||
components: {ConditionSetSelectorDialog},
|
components: { SelectorDialogTree },
|
||||||
provide: {
|
provide: {
|
||||||
openmct: this.openmct
|
openmct: this.openmct
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
handleItemSelection
|
handleItemSelection,
|
||||||
|
title: 'Select Condition Set'
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
template: '<condition-set-selector-dialog @conditionSetSelected="handleItemSelection"></condition-set-selector-dialog>'
|
template: '<selector-dialog-tree :title="title" @treeItemSelected="handleItemSelection"></selector-dialog-tree>'
|
||||||
}).$mount();
|
}).$mount();
|
||||||
|
|
||||||
let overlay = this.openmct.overlays.overlay({
|
let overlay = this.openmct.overlays.overlay({
|
||||||
|
@ -127,7 +127,7 @@ import FontStyleEditor from '@/ui/inspector/styles/FontStyleEditor.vue';
|
|||||||
import StyleEditor from "./StyleEditor.vue";
|
import StyleEditor from "./StyleEditor.vue";
|
||||||
import PreviewAction from "@/ui/preview/PreviewAction.js";
|
import PreviewAction from "@/ui/preview/PreviewAction.js";
|
||||||
import { getApplicableStylesForItem, getConsolidatedStyleValues, getConditionSetIdentifierForItem } from "@/plugins/condition/utils/styleUtils";
|
import { getApplicableStylesForItem, getConsolidatedStyleValues, getConditionSetIdentifierForItem } from "@/plugins/condition/utils/styleUtils";
|
||||||
import ConditionSetSelectorDialog from "@/plugins/condition/components/inspector/ConditionSetSelectorDialog.vue";
|
import SelectorDialogTree from '@/ui/components/SelectorDialogTree.vue';
|
||||||
import ConditionError from "@/plugins/condition/components/ConditionError.vue";
|
import ConditionError from "@/plugins/condition/components/ConditionError.vue";
|
||||||
import ConditionDescription from "@/plugins/condition/components/ConditionDescription.vue";
|
import ConditionDescription from "@/plugins/condition/components/ConditionDescription.vue";
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
@ -539,7 +539,7 @@ export default {
|
|||||||
addConditionSet() {
|
addConditionSet() {
|
||||||
let conditionSetDomainObject;
|
let conditionSetDomainObject;
|
||||||
let self = this;
|
let self = this;
|
||||||
function handleItemSelection(item) {
|
function handleItemSelection({ item }) {
|
||||||
if (item) {
|
if (item) {
|
||||||
conditionSetDomainObject = item;
|
conditionSetDomainObject = item;
|
||||||
}
|
}
|
||||||
@ -556,16 +556,17 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let vm = new Vue({
|
let vm = new Vue({
|
||||||
components: {ConditionSetSelectorDialog},
|
components: { SelectorDialogTree },
|
||||||
provide: {
|
provide: {
|
||||||
openmct: this.openmct
|
openmct: this.openmct
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
handleItemSelection
|
handleItemSelection,
|
||||||
|
title: 'Select Condition Set'
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
template: '<condition-set-selector-dialog @conditionSetSelected="handleItemSelection"></condition-set-selector-dialog>'
|
template: '<SelectorDialogTree :title="title" @treeItemSelected="handleItemSelection"></SelectorDialogTree>'
|
||||||
}).$mount();
|
}).$mount();
|
||||||
|
|
||||||
let overlay = this.openmct.overlays.overlay({
|
let overlay = this.openmct.overlays.overlay({
|
||||||
|
@ -42,7 +42,7 @@ define(['lodash'], function (_) {
|
|||||||
toolbar: function (selectedObjects) {
|
toolbar: function (selectedObjects) {
|
||||||
const DIALOG_FORM = {
|
const DIALOG_FORM = {
|
||||||
'text': {
|
'text': {
|
||||||
name: "Text Element Properties",
|
title: "Text Element Properties",
|
||||||
sections: [
|
sections: [
|
||||||
{
|
{
|
||||||
rows: [
|
rows: [
|
||||||
@ -50,14 +50,15 @@ define(['lodash'], function (_) {
|
|||||||
key: "text",
|
key: "text",
|
||||||
control: "textfield",
|
control: "textfield",
|
||||||
name: "Text",
|
name: "Text",
|
||||||
required: true
|
required: true,
|
||||||
|
cssClass: "l-input-lg"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
'image': {
|
'image': {
|
||||||
name: "Image Properties",
|
title: "Image Properties",
|
||||||
sections: [
|
sections: [
|
||||||
{
|
{
|
||||||
rows: [
|
rows: [
|
||||||
@ -65,7 +66,7 @@ define(['lodash'], function (_) {
|
|||||||
key: "url",
|
key: "url",
|
||||||
control: "textfield",
|
control: "textfield",
|
||||||
name: "Image URL",
|
name: "Image URL",
|
||||||
"cssClass": "l-input-lg",
|
cssClass: "l-input-lg",
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -126,10 +127,6 @@ define(['lodash'], function (_) {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
function getUserInput(form) {
|
|
||||||
return openmct.$injector.get('dialogService').getUserInput(form, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPath(selectionPath) {
|
function getPath(selectionPath) {
|
||||||
return `configuration.items[${selectionPath[0].context.index}]`;
|
return `configuration.items[${selectionPath[0].context.index}]`;
|
||||||
}
|
}
|
||||||
@ -167,8 +164,7 @@ define(['lodash'], function (_) {
|
|||||||
let name = option.name.toLowerCase();
|
let name = option.name.toLowerCase();
|
||||||
let form = DIALOG_FORM[name];
|
let form = DIALOG_FORM[name];
|
||||||
if (form) {
|
if (form) {
|
||||||
getUserInput(form)
|
showForm(form, name, selectionPath);
|
||||||
.then(element => selectionPath[0].context.addElement(name, element));
|
|
||||||
} else {
|
} else {
|
||||||
selectionPath[0].context.addElement(name);
|
selectionPath[0].context.addElement(name);
|
||||||
}
|
}
|
||||||
@ -643,10 +639,18 @@ define(['lodash'], function (_) {
|
|||||||
&& !selectionPath[0].context.layoutItem;
|
&& !selectionPath[0].context.layoutItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showForm(formStructure, name, selectionPath) {
|
||||||
|
openmct.forms.showForm(formStructure)
|
||||||
|
.then(changes => {
|
||||||
|
selectionPath[0].context.addElement(name, changes);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (isMainLayoutSelected(selectedObjects[0])) {
|
if (isMainLayoutSelected(selectedObjects[0])) {
|
||||||
return [
|
return [
|
||||||
getToggleGridButton(selectedObjects),
|
getToggleGridButton(selectedObjects),
|
||||||
getAddButton(selectedObjects)];
|
getAddButton(selectedObjects)
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
let toolbar = {
|
let toolbar = {
|
||||||
|
@ -33,96 +33,78 @@ export default class DuplicateAction {
|
|||||||
this.openmct = openmct;
|
this.openmct = openmct;
|
||||||
}
|
}
|
||||||
|
|
||||||
async invoke(objectPath) {
|
invoke(objectPath) {
|
||||||
let duplicationTask = new DuplicateTask(this.openmct);
|
this.object = objectPath[0];
|
||||||
let originalObject = objectPath[0];
|
this.parent = objectPath[1];
|
||||||
let parent = objectPath[1];
|
|
||||||
let userInput;
|
|
||||||
|
|
||||||
try {
|
this.showForm(this.object, this.parent);
|
||||||
userInput = await this.getUserInput(originalObject, parent);
|
|
||||||
} catch (error) {
|
|
||||||
// user most likely canceled
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let newParent = userInput.location;
|
inNavigationPath() {
|
||||||
let inNavigationPath = this.inNavigationPath(originalObject);
|
return this.openmct.router.path
|
||||||
|
.some(objectInPath => this.openmct.objects.areIdsEqual(objectInPath.identifier, this.object.identifier));
|
||||||
// legacy check
|
|
||||||
if (this.isLegacyDomainObject(newParent)) {
|
|
||||||
newParent = await this.convertFromLegacy(newParent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if editing, save
|
onSave(changes) {
|
||||||
|
let inNavigationPath = this.inNavigationPath();
|
||||||
if (inNavigationPath && this.openmct.editor.isEditing()) {
|
if (inNavigationPath && this.openmct.editor.isEditing()) {
|
||||||
this.openmct.editor.save();
|
this.openmct.editor.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
// duplicate
|
let duplicationTask = new DuplicateTask(this.openmct);
|
||||||
let newObject = await duplicationTask.duplicate(originalObject, newParent);
|
if (changes.name && (changes.name !== this.object.name)) {
|
||||||
this.updateNameCheck(newObject, userInput.name);
|
duplicationTask.changeName(changes.name);
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getUserInput(originalObject, parent) {
|
const parentDomainObjectpath = changes.location || [this.parent];
|
||||||
let dialogService = this.openmct.$injector.get('dialogService');
|
const parent = parentDomainObjectpath[0];
|
||||||
let dialogForm = this.getDialogForm(originalObject, parent);
|
|
||||||
let formState = {
|
|
||||||
name: originalObject.name
|
|
||||||
};
|
|
||||||
let userInput = await dialogService.getUserInput(dialogForm, formState);
|
|
||||||
|
|
||||||
return userInput;
|
return duplicationTask.duplicate(this.object, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateNameCheck(object, name) {
|
showForm(domainObject, parentDomainObject) {
|
||||||
if (object.name !== name) {
|
const formStructure = {
|
||||||
object.name = name;
|
title: "Duplicate Item",
|
||||||
this.openmct.objects.save(object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inNavigationPath(object) {
|
|
||||||
return this.openmct.router.path
|
|
||||||
.some(objectInPath => this.openmct.objects.areIdsEqual(objectInPath.identifier, object.identifier));
|
|
||||||
}
|
|
||||||
|
|
||||||
getDialogForm(object, parent) {
|
|
||||||
return {
|
|
||||||
name: "Duplicate Item",
|
|
||||||
sections: [
|
sections: [
|
||||||
{
|
{
|
||||||
rows: [
|
rows: [
|
||||||
{
|
{
|
||||||
key: "name",
|
key: "name",
|
||||||
control: "textfield",
|
control: "textfield",
|
||||||
name: "Name",
|
name: "Title",
|
||||||
pattern: "\\S+",
|
pattern: "\\S+",
|
||||||
required: true,
|
required: true,
|
||||||
cssClass: "l-input-lg"
|
cssClass: "l-input-lg",
|
||||||
|
value: domainObject.name
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Location",
|
name: "Location",
|
||||||
cssClass: "grows",
|
cssClass: "grows",
|
||||||
control: "locator",
|
control: "locator",
|
||||||
validate: this.validate(object, parent),
|
required: true,
|
||||||
|
parent: parentDomainObject,
|
||||||
|
validate: this.validate(parentDomainObject),
|
||||||
key: 'location'
|
key: 'location'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.openmct.forms.showForm(formStructure)
|
||||||
|
.then(this.onSave.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
validate(object, currentParent) {
|
validate(currentParent) {
|
||||||
return (parentCandidate) => {
|
return (data) => {
|
||||||
let currentParentKeystring = this.openmct.objects.makeKeyString(currentParent.identifier);
|
const parentCandidatePath = data.value;
|
||||||
let parentCandidateKeystring = this.openmct.objects.makeKeyString(parentCandidate.getId());
|
const parentCandidate = parentCandidatePath[0];
|
||||||
let objectKeystring = this.openmct.objects.makeKeyString(object.identifier);
|
|
||||||
|
|
||||||
if (!parentCandidate || !currentParentKeystring) {
|
let currentParentKeystring = this.openmct.objects.makeKeyString(currentParent.identifier);
|
||||||
|
let parentCandidateKeystring = this.openmct.objects.makeKeyString(parentCandidate.identifier);
|
||||||
|
let objectKeystring = this.openmct.objects.makeKeyString(this.object.identifier);
|
||||||
|
|
||||||
|
if (!parentCandidateKeystring || !currentParentKeystring) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,24 +112,15 @@ export default class DuplicateAction {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.openmct.composition.checkPolicy(
|
const parentCandidateComposition = parentCandidate.composition;
|
||||||
parentCandidate.useCapability('adapter'),
|
if (parentCandidateComposition && parentCandidateComposition.indexOf(objectKeystring) !== -1) {
|
||||||
object
|
return false;
|
||||||
);
|
}
|
||||||
|
|
||||||
|
return parentCandidate && this.openmct.composition.checkPolicy(parentCandidate, this.object);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
isLegacyDomainObject(domainObject) {
|
|
||||||
return domainObject.getCapability !== undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
async convertFromLegacy(legacyDomainObject) {
|
|
||||||
let objectContext = legacyDomainObject.getCapability('context');
|
|
||||||
let domainObject = await this.openmct.objects.get(objectContext.domainObject.id);
|
|
||||||
|
|
||||||
return domainObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
appliesTo(objectPath) {
|
appliesTo(objectPath) {
|
||||||
let parent = objectPath[1];
|
let parent = objectPath[1];
|
||||||
let parentType = parent && this.openmct.types.get(parent.type);
|
let parentType = parent && this.openmct.types.get(parent.type);
|
||||||
|
@ -34,7 +34,6 @@ import uuid from 'uuid';
|
|||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
export default class DuplicateTask {
|
export default class DuplicateTask {
|
||||||
|
|
||||||
constructor(openmct) {
|
constructor(openmct) {
|
||||||
this.domainObject = undefined;
|
this.domainObject = undefined;
|
||||||
this.parent = undefined;
|
this.parent = undefined;
|
||||||
@ -43,10 +42,15 @@ export default class DuplicateTask {
|
|||||||
this.persisted = 0;
|
this.persisted = 0;
|
||||||
this.clones = [];
|
this.clones = [];
|
||||||
this.idMap = {};
|
this.idMap = {};
|
||||||
|
this.name = undefined;
|
||||||
|
|
||||||
this.openmct = openmct;
|
this.openmct = openmct;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changeName(name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the duplicate/copy task with the objects provided.
|
* Execute the duplicate/copy task with the objects provided.
|
||||||
* @returns {promise} Which will resolve with a clone of the object
|
* @returns {promise} Which will resolve with a clone of the object
|
||||||
@ -79,11 +83,14 @@ export default class DuplicateTask {
|
|||||||
*/
|
*/
|
||||||
async buildDuplicationPlan() {
|
async buildDuplicationPlan() {
|
||||||
let domainObjectClone = await this.duplicateObject(this.domainObject);
|
let domainObjectClone = await this.duplicateObject(this.domainObject);
|
||||||
|
|
||||||
if (domainObjectClone !== this.domainObject) {
|
if (domainObjectClone !== this.domainObject) {
|
||||||
domainObjectClone.location = this.getKeyString(this.parent);
|
domainObjectClone.location = this.getKeyString(this.parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.name) {
|
||||||
|
domainObjectClone.name = this.name;
|
||||||
|
}
|
||||||
|
|
||||||
this.firstClone = domainObjectClone;
|
this.firstClone = domainObjectClone;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
import DuplicateActionPlugin from './plugin.js';
|
import DuplicateActionPlugin from './plugin.js';
|
||||||
import DuplicateAction from './DuplicateAction.js';
|
|
||||||
import DuplicateTask from './DuplicateTask.js';
|
import DuplicateTask from './DuplicateTask.js';
|
||||||
import {
|
import {
|
||||||
createOpenMct,
|
createOpenMct,
|
||||||
@ -29,7 +28,6 @@ import {
|
|||||||
} from 'utils/testing';
|
} from 'utils/testing';
|
||||||
|
|
||||||
describe("The Duplicate Action plugin", () => {
|
describe("The Duplicate Action plugin", () => {
|
||||||
|
|
||||||
let openmct;
|
let openmct;
|
||||||
let duplicateTask;
|
let duplicateTask;
|
||||||
let childObject;
|
let childObject;
|
||||||
@ -52,6 +50,7 @@ describe("The Duplicate Action plugin", () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).folder;
|
}).folder;
|
||||||
|
|
||||||
parentObject = getMockObjects({
|
parentObject = getMockObjects({
|
||||||
objectKeyStrings: ['folder'],
|
objectKeyStrings: ['folder'],
|
||||||
overwrite: {
|
overwrite: {
|
||||||
@ -62,6 +61,7 @@ describe("The Duplicate Action plugin", () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).folder;
|
}).folder;
|
||||||
|
|
||||||
anotherParentObject = getMockObjects({
|
anotherParentObject = getMockObjects({
|
||||||
objectKeyStrings: ['folder'],
|
objectKeyStrings: ['folder'],
|
||||||
overwrite: {
|
overwrite: {
|
||||||
@ -120,7 +120,6 @@ describe("The Duplicate Action plugin", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("when moving an object to a new parent", () => {
|
describe("when moving an object to a new parent", () => {
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
duplicateTask = new DuplicateTask(openmct);
|
duplicateTask = new DuplicateTask(openmct);
|
||||||
await duplicateTask.duplicate(parentObject, anotherParentObject);
|
await duplicateTask.duplicate(parentObject, anotherParentObject);
|
||||||
@ -142,16 +141,14 @@ describe("The Duplicate Action plugin", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("when a new name is provided for the duplicated object", () => {
|
describe("when a new name is provided for the duplicated object", () => {
|
||||||
it("the name is updated", () => {
|
it("the name is updated", async () => {
|
||||||
const NEW_NAME = 'New Name';
|
const NEW_NAME = 'New Name';
|
||||||
let childName;
|
|
||||||
|
|
||||||
duplicateTask = new DuplicateAction(openmct);
|
duplicateTask = new DuplicateTask(openmct);
|
||||||
duplicateTask.updateNameCheck(parentObject, NEW_NAME);
|
duplicateTask.changeName(NEW_NAME);
|
||||||
|
const child = await duplicateTask.duplicate(childObject, anotherParentObject);
|
||||||
|
|
||||||
childName = parentObject.name;
|
expect(child.name).toEqual(NEW_NAME);
|
||||||
|
|
||||||
expect(childName).toEqual(NEW_NAME);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
202
src/plugins/exportAsJSONAction/ExportAsJSONAction.js
Normal file
202
src/plugins/exportAsJSONAction/ExportAsJSONAction.js
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
import JSONExporter from '/src/exporters/JSONExporter.js';
|
||||||
|
|
||||||
|
import _ from 'lodash';
|
||||||
|
import { saveAs } from 'saveAs';
|
||||||
|
import uuid from "uuid";
|
||||||
|
|
||||||
|
export default class ExportAsJSONAction {
|
||||||
|
constructor(openmct) {
|
||||||
|
this.openmct = openmct;
|
||||||
|
|
||||||
|
this.name = 'Export as JSON';
|
||||||
|
this.key = 'export.JSON';
|
||||||
|
this.description = '';
|
||||||
|
this.cssClass = "icon-export";
|
||||||
|
this.group = "json";
|
||||||
|
this.priority = 1;
|
||||||
|
|
||||||
|
this.externalIdentifiers = [];
|
||||||
|
this.tree = {};
|
||||||
|
this.calls = 0;
|
||||||
|
this.idMap = {};
|
||||||
|
|
||||||
|
this.JSONExportService = new JSONExporter(saveAs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {object} objectPath
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
appliesTo(objectPath) {
|
||||||
|
let domainObject = objectPath[0];
|
||||||
|
|
||||||
|
return this._isCreatable(domainObject);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {object} objectpath
|
||||||
|
*/
|
||||||
|
invoke(objectpath) {
|
||||||
|
const root = objectpath[0];
|
||||||
|
this.root = JSON.parse(JSON.stringify(root));
|
||||||
|
const rootId = this._getId(this.root);
|
||||||
|
this.tree[rootId] = this.root;
|
||||||
|
|
||||||
|
this._write(this.root);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {object} domainObject
|
||||||
|
* @returns {string} A string representation of the given identifier, including namespace and key
|
||||||
|
*/
|
||||||
|
_getId(domainObject) {
|
||||||
|
return this.openmct.objects.makeKeyString(domainObject.identifier);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {object} domainObject
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
_isCreatable(domainObject) {
|
||||||
|
const type = this.openmct.types.get(domainObject.type);
|
||||||
|
|
||||||
|
return type && type.definition.creatable;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {object} child
|
||||||
|
* @param {object} parent
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
_isLinkedObject(child, parent) {
|
||||||
|
if (child.location !== this._getId(parent)
|
||||||
|
&& !Object.keys(this.tree).includes(child.location)
|
||||||
|
&& this._getId(child) !== this._getId(this.root)
|
||||||
|
|| this.externalIdentifiers.includes(this._getId(child))) {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {object} child
|
||||||
|
* @param {object} parent
|
||||||
|
* @returns {object}
|
||||||
|
*/
|
||||||
|
_rewriteLink(child, parent) {
|
||||||
|
this.externalIdentifiers.push(this._getId(child));
|
||||||
|
const index = parent.composition.findIndex(id => {
|
||||||
|
return _.isEqual(child.identifier, id);
|
||||||
|
});
|
||||||
|
const copyOfChild = JSON.parse(JSON.stringify(child));
|
||||||
|
copyOfChild.identifier.key = uuid();
|
||||||
|
const newIdString = this._getId(copyOfChild);
|
||||||
|
const parentId = this._getId(parent);
|
||||||
|
|
||||||
|
this.idMap[this._getId(child)] = newIdString;
|
||||||
|
copyOfChild.location = parentId;
|
||||||
|
parent.composition[index] = copyOfChild.identifier;
|
||||||
|
this.tree[newIdString] = copyOfChild;
|
||||||
|
this.tree[parentId].composition[index] = copyOfChild.identifier;
|
||||||
|
|
||||||
|
return copyOfChild;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_rewriteReferences() {
|
||||||
|
let treeString = JSON.stringify(this.tree);
|
||||||
|
Object.keys(this.idMap).forEach(function (oldId) {
|
||||||
|
const newId = this.idMap[oldId];
|
||||||
|
treeString = treeString.split(oldId).join(newId);
|
||||||
|
}.bind(this));
|
||||||
|
this.tree = JSON.parse(treeString);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {object} completedTree
|
||||||
|
*/
|
||||||
|
_saveAs(completedTree) {
|
||||||
|
this.JSONExportService.export(
|
||||||
|
completedTree,
|
||||||
|
{ filename: this.root.name + '.json' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @returns {object}
|
||||||
|
*/
|
||||||
|
_wrapTree() {
|
||||||
|
return {
|
||||||
|
"openmct": this.tree,
|
||||||
|
"rootId": this._getId(this.root)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {object} parent
|
||||||
|
*/
|
||||||
|
_write(parent) {
|
||||||
|
this.calls++;
|
||||||
|
const composition = this.openmct.composition.get(parent);
|
||||||
|
if (composition !== undefined) {
|
||||||
|
composition.load()
|
||||||
|
.then((children) => {
|
||||||
|
children.forEach((child, index) => {
|
||||||
|
// Only export if object is creatable
|
||||||
|
if (this._isCreatable(child)) {
|
||||||
|
// Prevents infinite export of self-contained objs
|
||||||
|
if (!Object.prototype.hasOwnProperty.call(this.tree, this._getId(child))) {
|
||||||
|
// If object is a link to something absent from
|
||||||
|
// tree, generate new id and treat as new object
|
||||||
|
if (this._isLinkedObject(child, parent)) {
|
||||||
|
child = this._rewriteLink(child, parent);
|
||||||
|
} else {
|
||||||
|
this.tree[this._getId(child)] = child;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._write(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.calls--;
|
||||||
|
if (this.calls === 0) {
|
||||||
|
this._rewriteReferences();
|
||||||
|
this._saveAs(this._wrapTree());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.calls--;
|
||||||
|
if (this.calls === 0) {
|
||||||
|
this._rewriteReferences();
|
||||||
|
this._saveAs(this._wrapTree());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -31,16 +31,16 @@ define(
|
|||||||
|
|
||||||
describe("The export JSON action", function () {
|
describe("The export JSON action", function () {
|
||||||
|
|
||||||
var context,
|
let context;
|
||||||
action,
|
let action;
|
||||||
exportService,
|
let exportService;
|
||||||
identifierService,
|
let identifierService;
|
||||||
typeService,
|
let typeService;
|
||||||
openmct,
|
let openmct;
|
||||||
policyService,
|
let policyService;
|
||||||
mockType,
|
let mockType;
|
||||||
mockObjectProvider,
|
let mockObjectProvider;
|
||||||
exportedTree;
|
let exportedTree;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
openmct = new MCT();
|
openmct = new MCT();
|
||||||
@ -93,7 +93,7 @@ define(
|
|||||||
});
|
});
|
||||||
|
|
||||||
function invokeAdapter() {
|
function invokeAdapter() {
|
||||||
var newStyleObject = new AdapterCapability(context.domainObject).invoke();
|
let newStyleObject = new AdapterCapability(context.domainObject).invoke();
|
||||||
|
|
||||||
return newStyleObject;
|
return newStyleObject;
|
||||||
}
|
}
|
||||||
@ -103,7 +103,7 @@ define(
|
|||||||
});
|
});
|
||||||
|
|
||||||
xit("doesn't export non-creatable objects in tree", function () {
|
xit("doesn't export non-creatable objects in tree", function () {
|
||||||
var nonCreatableType = {
|
let nonCreatableType = {
|
||||||
hasFeature:
|
hasFeature:
|
||||||
function (feature) {
|
function (feature) {
|
||||||
return feature !== 'creation';
|
return feature !== 'creation';
|
||||||
@ -112,7 +112,7 @@ define(
|
|||||||
|
|
||||||
typeService.getType.and.returnValue(nonCreatableType);
|
typeService.getType.and.returnValue(nonCreatableType);
|
||||||
|
|
||||||
var parent = domainObjectFactory({
|
let parent = domainObjectFactory({
|
||||||
name: 'parent',
|
name: 'parent',
|
||||||
model: {
|
model: {
|
||||||
name: 'parent',
|
name: 'parent',
|
||||||
@ -127,7 +127,7 @@ define(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var child = {
|
let child = {
|
||||||
identifier: {
|
identifier: {
|
||||||
namespace: '',
|
namespace: '',
|
||||||
key: 'childId'
|
key: 'childId'
|
||||||
@ -150,7 +150,7 @@ define(
|
|||||||
});
|
});
|
||||||
|
|
||||||
xit("can export self-containing objects", function () {
|
xit("can export self-containing objects", function () {
|
||||||
var parent = domainObjectFactory({
|
let parent = domainObjectFactory({
|
||||||
name: 'parent',
|
name: 'parent',
|
||||||
model: {
|
model: {
|
||||||
name: 'parent',
|
name: 'parent',
|
||||||
@ -165,7 +165,7 @@ define(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var child = {
|
let child = {
|
||||||
identifier: {
|
identifier: {
|
||||||
namespace: '',
|
namespace: '',
|
||||||
key: 'infiniteChildId'
|
key: 'infiniteChildId'
|
||||||
@ -192,7 +192,7 @@ define(
|
|||||||
});
|
});
|
||||||
|
|
||||||
xit("exports links to external objects as new objects", function () {
|
xit("exports links to external objects as new objects", function () {
|
||||||
var parent = domainObjectFactory({
|
let parent = domainObjectFactory({
|
||||||
name: 'parent',
|
name: 'parent',
|
||||||
model: {
|
model: {
|
||||||
name: 'parent',
|
name: 'parent',
|
||||||
@ -207,7 +207,7 @@ define(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var externalObject = {
|
let externalObject = {
|
||||||
name: 'external',
|
name: 'external',
|
||||||
location: 'outsideOfTree',
|
location: 'outsideOfTree',
|
||||||
identifier: {
|
identifier: {
|
@ -19,30 +19,10 @@
|
|||||||
* this source code distribution or the Licensing information page available
|
* this source code distribution or the Licensing information page available
|
||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
import ExportAsJSONAction from './ExportAsJSONAction';
|
||||||
|
|
||||||
define(
|
export default function () {
|
||||||
['./AbstractComposeAction'],
|
return function (openmct) {
|
||||||
function (AbstractComposeAction) {
|
openmct.actions.register(new ExportAsJSONAction(openmct));
|
||||||
|
};
|
||||||
/**
|
}
|
||||||
* The LinkAction is available from context menus and allows a user to
|
|
||||||
* link an object to another location of their choosing.
|
|
||||||
*
|
|
||||||
* @implements {Action}
|
|
||||||
* @constructor
|
|
||||||
* @memberof platform/entanglement
|
|
||||||
*/
|
|
||||||
function LinkAction(policyService, locationService, linkService, context) {
|
|
||||||
AbstractComposeAction.apply(
|
|
||||||
this,
|
|
||||||
[policyService, locationService, linkService, context, "Link"]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
LinkAction.prototype = Object.create(AbstractComposeAction.prototype);
|
|
||||||
LinkAction.appliesTo = AbstractComposeAction.appliesTo;
|
|
||||||
|
|
||||||
return LinkAction;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
150
src/plugins/formActions/CreateAction.js
Normal file
150
src/plugins/formActions/CreateAction.js
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
import PropertiesAction from './PropertiesAction';
|
||||||
|
import CreateWizard from './CreateWizard';
|
||||||
|
|
||||||
|
import uuid from 'uuid';
|
||||||
|
|
||||||
|
export default class CreateAction extends PropertiesAction {
|
||||||
|
constructor(openmct, type, parentDomainObject) {
|
||||||
|
super(openmct);
|
||||||
|
|
||||||
|
this.type = type;
|
||||||
|
this.parentDomainObject = parentDomainObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
invoke() {
|
||||||
|
this._showCreateForm(this.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async _onSave(changes) {
|
||||||
|
let parentDomainObjectPath;
|
||||||
|
|
||||||
|
Object.entries(changes).forEach(([key, value]) => {
|
||||||
|
if (key === 'location') {
|
||||||
|
parentDomainObjectPath = value;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const properties = key.split('.');
|
||||||
|
let object = this.domainObject;
|
||||||
|
const propertiesLength = properties.length;
|
||||||
|
properties.forEach((property, index) => {
|
||||||
|
const isComplexProperty = propertiesLength > 1 && index !== propertiesLength - 1;
|
||||||
|
if (isComplexProperty && object[property] !== null) {
|
||||||
|
object = object[property];
|
||||||
|
} else {
|
||||||
|
object[property] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
object = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
const parentDomainObject = parentDomainObjectPath[0];
|
||||||
|
|
||||||
|
this.domainObject.modified = Date.now();
|
||||||
|
this.domainObject.location = this.openmct.objects.makeKeyString(parentDomainObject.identifier);
|
||||||
|
this.domainObject.identifier.namespace = parentDomainObject.identifier.namespace;
|
||||||
|
|
||||||
|
// Show saving progress dialog
|
||||||
|
let dialog = this.openmct.overlays.progressDialog({
|
||||||
|
progressPerc: 'unknown',
|
||||||
|
message: 'Do not navigate away from this page or close this browser tab while this message is displayed.',
|
||||||
|
iconClass: 'info',
|
||||||
|
title: 'Saving'
|
||||||
|
});
|
||||||
|
|
||||||
|
const success = await this.openmct.objects.save(this.domainObject);
|
||||||
|
if (success) {
|
||||||
|
const compositionCollection = await this.openmct.composition.get(parentDomainObject);
|
||||||
|
compositionCollection.add(this.domainObject);
|
||||||
|
|
||||||
|
this._navigateAndEdit(this.domainObject, parentDomainObjectPath);
|
||||||
|
|
||||||
|
this.openmct.notifications.info('Save successful');
|
||||||
|
} else {
|
||||||
|
this.openmct.notifications.error('Error saving objects');
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async _navigateAndEdit(domainObject, parentDomainObjectpath) {
|
||||||
|
let objectPath;
|
||||||
|
if (parentDomainObjectpath) {
|
||||||
|
objectPath = parentDomainObjectpath && [domainObject].concat(parentDomainObjectpath);
|
||||||
|
} else {
|
||||||
|
objectPath = await this.openmct.objects.getOriginalPath(domainObject.identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = '#/browse/' + objectPath
|
||||||
|
.map(object => object && this.openmct.objects.makeKeyString(object.identifier.key))
|
||||||
|
.reverse()
|
||||||
|
.join('/');
|
||||||
|
|
||||||
|
this.openmct.router.navigate(url);
|
||||||
|
|
||||||
|
const objectView = this.openmct.objectViews.get(domainObject, objectPath)[0];
|
||||||
|
const canEdit = objectView && objectView.canEdit && objectView.canEdit(domainObject, objectPath);
|
||||||
|
if (canEdit) {
|
||||||
|
this.openmct.editor.edit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_showCreateForm(type) {
|
||||||
|
const typeDefinition = this.openmct.types.get(type);
|
||||||
|
const definition = typeDefinition.definition;
|
||||||
|
const domainObject = {
|
||||||
|
name: `Unnamed ${definition.name}`,
|
||||||
|
type,
|
||||||
|
identifier: {
|
||||||
|
key: uuid(),
|
||||||
|
namespace: this.parentDomainObject.identifier.namespace
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.domainObject = domainObject;
|
||||||
|
|
||||||
|
if (definition.initialize) {
|
||||||
|
definition.initialize(domainObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
const createWizard = new CreateWizard(this.openmct, domainObject, this.parentDomainObject);
|
||||||
|
const formStructure = createWizard.getFormStructure(true);
|
||||||
|
formStructure.title = 'Create a New ' + definition.name;
|
||||||
|
|
||||||
|
this.openmct.forms.showForm(formStructure)
|
||||||
|
.then(this._onSave.bind(this));
|
||||||
|
}
|
||||||
|
}
|
135
src/plugins/formActions/CreateWizard.js
Normal file
135
src/plugins/formActions/CreateWizard.js
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
export default class CreateWizard {
|
||||||
|
constructor(openmct, domainObject, parent) {
|
||||||
|
this.openmct = openmct;
|
||||||
|
|
||||||
|
this.domainObject = domainObject;
|
||||||
|
this.type = openmct.types.get(domainObject.type);
|
||||||
|
|
||||||
|
this.model = domainObject;
|
||||||
|
this.parent = parent;
|
||||||
|
this.properties = this.type.definition.form || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
addNotes(sections) {
|
||||||
|
const row = {
|
||||||
|
control: 'textarea',
|
||||||
|
cssClass: 'l-input-lg',
|
||||||
|
key: 'notes',
|
||||||
|
name: 'Notes',
|
||||||
|
required: false,
|
||||||
|
value: this.domainObject.notes
|
||||||
|
};
|
||||||
|
|
||||||
|
sections.forEach(section => {
|
||||||
|
if (section.name !== 'Properties') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.rows.unshift(row);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addTitle(sections) {
|
||||||
|
const row = {
|
||||||
|
control: 'textfield',
|
||||||
|
cssClass: 'l-input-lg',
|
||||||
|
key: 'name',
|
||||||
|
name: 'Title',
|
||||||
|
pattern: `\\S+`,
|
||||||
|
required: true,
|
||||||
|
value: this.domainObject.name
|
||||||
|
};
|
||||||
|
|
||||||
|
sections.forEach(section => {
|
||||||
|
if (section.name !== 'Properties') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.rows.unshift(row);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
getFormStructure(includeLocation) {
|
||||||
|
let sections = [];
|
||||||
|
let domainObject = this.domainObject;
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
sections.push({
|
||||||
|
name: 'Properties',
|
||||||
|
rows: this.properties.map(property => {
|
||||||
|
const row = JSON.parse(JSON.stringify(property));
|
||||||
|
row.value = this.getValue(row);
|
||||||
|
|
||||||
|
return row;
|
||||||
|
}).filter(row => row && row.control)
|
||||||
|
});
|
||||||
|
|
||||||
|
this.addNotes(sections);
|
||||||
|
this.addTitle(sections);
|
||||||
|
|
||||||
|
// Ensure there is always a 'save in' section
|
||||||
|
if (includeLocation) {
|
||||||
|
function validateLocation(data) {
|
||||||
|
return self.openmct.composition.checkPolicy(data.value[0], domainObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
sections.push({
|
||||||
|
name: 'Location',
|
||||||
|
cssClass: 'grows',
|
||||||
|
rows: [{
|
||||||
|
name: 'Save In',
|
||||||
|
cssClass: 'grows',
|
||||||
|
control: 'locator',
|
||||||
|
domainObject,
|
||||||
|
required: true,
|
||||||
|
parent: this.parent,
|
||||||
|
validate: validateLocation.bind(this),
|
||||||
|
key: 'location'
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
sections
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue(row) {
|
||||||
|
if (row.property) {
|
||||||
|
return row.property.reduce((acc, property) => acc && acc[property], this.domainObject);
|
||||||
|
} else {
|
||||||
|
return this.domainObject[row.key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
102
src/plugins/formActions/EditPropertiesAction.js
Normal file
102
src/plugins/formActions/EditPropertiesAction.js
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
import PropertiesAction from './PropertiesAction';
|
||||||
|
import CreateWizard from './CreateWizard';
|
||||||
|
export default class EditPropertiesAction extends PropertiesAction {
|
||||||
|
constructor(openmct) {
|
||||||
|
super(openmct);
|
||||||
|
|
||||||
|
this.name = 'Edit Properties...';
|
||||||
|
this.key = 'properties';
|
||||||
|
this.description = 'Edit properties of this object.';
|
||||||
|
this.cssClass = 'major icon-pencil';
|
||||||
|
this.hideInDefaultMenu = true;
|
||||||
|
this.group = 'action';
|
||||||
|
this.priority = 10;
|
||||||
|
this.formProperties = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
appliesTo(objectPath) {
|
||||||
|
const definition = this._getTypeDefinition(objectPath[0].type);
|
||||||
|
|
||||||
|
return definition && definition.creatable;
|
||||||
|
}
|
||||||
|
|
||||||
|
invoke(objectPath) {
|
||||||
|
this._showEditForm(objectPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async _onSave(changes) {
|
||||||
|
Object.entries(changes).forEach(([key, value]) => {
|
||||||
|
const properties = key.split('.');
|
||||||
|
let object = this.domainObject;
|
||||||
|
const propertiesLength = properties.length;
|
||||||
|
properties.forEach((property, index) => {
|
||||||
|
const isComplexProperty = propertiesLength > 1 && index !== propertiesLength - 1;
|
||||||
|
if (isComplexProperty && object[property] !== null) {
|
||||||
|
object = object[property];
|
||||||
|
} else {
|
||||||
|
object[property] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
object = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.domainObject.modified = Date.now();
|
||||||
|
|
||||||
|
// Show saving progress dialog
|
||||||
|
let dialog = this.openmct.overlays.progressDialog({
|
||||||
|
progressPerc: 'unknown',
|
||||||
|
message: 'Do not navigate away from this page or close this browser tab while this message is displayed.',
|
||||||
|
iconClass: 'info',
|
||||||
|
title: 'Saving'
|
||||||
|
});
|
||||||
|
|
||||||
|
const success = await this.openmct.objects.save(this.domainObject);
|
||||||
|
if (success) {
|
||||||
|
this.openmct.notifications.info('Save successful');
|
||||||
|
} else {
|
||||||
|
this.openmct.notifications.error('Error saving objects');
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_showEditForm(objectPath) {
|
||||||
|
this.domainObject = objectPath[0];
|
||||||
|
|
||||||
|
const createWizard = new CreateWizard(this.openmct, this.domainObject, objectPath[1]);
|
||||||
|
const formStructure = createWizard.getFormStructure(false);
|
||||||
|
formStructure.title = 'Edit ' + this.domainObject.name;
|
||||||
|
|
||||||
|
this.openmct.forms.showForm(formStructure)
|
||||||
|
.then(this._onSave.bind(this));
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user