mirror of
https://github.com/nasa/openmct.git
synced 2024-12-20 05:37:53 +00:00
[Import/Export] Adds Import and Export functionality
Added context actions for importing and exporting JSON representations of domain objects. Added FileInputService for triggering file picker and retrieving uploaded data. Also added a File Input form control for integration with MCTForms.
This commit is contained in:
parent
586901aee7
commit
3674808a13
@ -43,6 +43,7 @@
|
||||
openmct.install(openmct.plugins.Generator());
|
||||
openmct.install(openmct.plugins.ExampleImagery());
|
||||
openmct.install(openmct.plugins.UTCTimeSystem());
|
||||
openmct.install(openmct.plugins.ImportExport());
|
||||
openmct.install(openmct.plugins.Conductor({
|
||||
menuOptions: [
|
||||
{
|
||||
|
@ -65,6 +65,20 @@ define(['csv'], function (CSV) {
|
||||
this.saveAs(blob, filename);
|
||||
};
|
||||
|
||||
/**
|
||||
* Export an object as a JSON file. Triggers a download using the function
|
||||
* provided when the ExportService was instantiated.
|
||||
*
|
||||
* @param {Object} obj an object to be exported as JSON
|
||||
* @param {ExportOptions} [options] additional parameters for the file
|
||||
* export
|
||||
*/
|
||||
ExportService.prototype.exportJSON = function (obj, options) {
|
||||
var filename = (options && options.filename) || "test-export.json";
|
||||
var jsonText = JSON.stringify(obj);
|
||||
var blob = new Blob([jsonText], {type: "application/json"});
|
||||
this.saveAs(blob, filename);
|
||||
};
|
||||
/**
|
||||
* Additional parameters for file export.
|
||||
* @typedef ExportOptions
|
||||
|
@ -24,6 +24,8 @@ define([
|
||||
"./src/MCTForm",
|
||||
"./src/MCTToolbar",
|
||||
"./src/MCTControl",
|
||||
"./src/MCTFileInput",
|
||||
"./src/FileInputService",
|
||||
"./src/controllers/AutocompleteController",
|
||||
"./src/controllers/DateTimeController",
|
||||
"./src/controllers/CompositeController",
|
||||
@ -42,11 +44,14 @@ define([
|
||||
"text!./res/templates/controls/menu-button.html",
|
||||
"text!./res/templates/controls/dialog.html",
|
||||
"text!./res/templates/controls/radio.html",
|
||||
"text!./res/templates/controls/file-input.html",
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
MCTForm,
|
||||
MCTToolbar,
|
||||
MCTControl,
|
||||
MCTFileInput,
|
||||
FileInputService,
|
||||
AutocompleteController,
|
||||
DateTimeController,
|
||||
CompositeController,
|
||||
@ -65,6 +70,7 @@ define([
|
||||
menuButtonTemplate,
|
||||
dialogTemplate,
|
||||
radioTemplate,
|
||||
fileInputTemplate,
|
||||
legacyRegistry
|
||||
) {
|
||||
|
||||
@ -88,6 +94,13 @@ define([
|
||||
"templateLinker",
|
||||
"controls[]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "mctFileInput",
|
||||
"implementation": MCTFileInput,
|
||||
"depends": [
|
||||
"fileInputService"
|
||||
]
|
||||
}
|
||||
],
|
||||
"controls": [
|
||||
@ -142,6 +155,10 @@ define([
|
||||
{
|
||||
"key": "dialog-button",
|
||||
"template": dialogTemplate
|
||||
},
|
||||
{
|
||||
"key": "file-input",
|
||||
"template": fileInputTemplate
|
||||
}
|
||||
],
|
||||
"controllers": [
|
||||
@ -176,6 +193,14 @@ define([
|
||||
"dialogService"
|
||||
]
|
||||
}
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"provides": "fileInputService",
|
||||
"type": "provider",
|
||||
"implementation": FileInputService
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
});
|
||||
|
30
platform/forms/res/templates/controls/file-input.html
Normal file
30
platform/forms/res/templates/controls/file-input.html
Normal file
@ -0,0 +1,30 @@
|
||||
<!--
|
||||
Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
|
||||
<a class="s-button {{structure.cssClass}}"
|
||||
ng-model="ngModel[field]"
|
||||
ng-class="{ labeled: structure.text }"
|
||||
mct-file-input>
|
||||
<span class="title-label" ng-if="structure.text">
|
||||
{{structure.text}}
|
||||
</span>
|
||||
</a>
|
90
platform/forms/src/FileInputService.js
Normal file
90
platform/forms/src/FileInputService.js
Normal file
@ -0,0 +1,90 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(["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 () {
|
||||
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) {
|
||||
file = this.files[0];
|
||||
input.remove();
|
||||
if (file) {
|
||||
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;
|
||||
});
|
66
platform/forms/src/MCTFileInput.js
Normal file
66
platform/forms/src/MCTFileInput.js
Normal file
@ -0,0 +1,66 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
['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().then(function (result) {
|
||||
setText(result.name);
|
||||
scope.ngModel[scope.field] = result;
|
||||
control.$setValidity("file-input", true);
|
||||
}, function () {
|
||||
setText('Select File');
|
||||
control.$setValidity("file-input", false);
|
||||
});
|
||||
}
|
||||
|
||||
control.$setValidity("file-input", false);
|
||||
element.on('click', handleClick);
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: "A",
|
||||
require: "^form",
|
||||
link: link
|
||||
};
|
||||
}
|
||||
|
||||
return MCTFileInput;
|
||||
}
|
||||
);
|
74
platform/forms/test/FileInputServiceSpec.js
Normal file
74
platform/forms/test/FileInputServiceSpec.js
Normal file
@ -0,0 +1,74 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
["../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.andCallFake(function (event, changeHandler) {
|
||||
changeHandler.apply(mockInput);
|
||||
});
|
||||
spyOn(fileInputService, "newInput").andReturn(
|
||||
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();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
98
platform/forms/test/MCTFileInputSpec.js
Normal file
98
platform/forms/test/MCTFileInputSpec.js
Normal file
@ -0,0 +1,98 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
["../src/MCTFileInput"],
|
||||
function (MCTFileInput) {
|
||||
|
||||
describe("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.andCallFake(function (event, clickHandler) {
|
||||
clickHandler();
|
||||
});
|
||||
mockFileInputService.getInput.andReturn(
|
||||
Promise.resolve({name: "file-name", body: "file-body"})
|
||||
);
|
||||
|
||||
mctFileInput = new MCTFileInput(mockFileInputService);
|
||||
|
||||
// Need to wait for mock promise
|
||||
var init = false;
|
||||
runs(function () {
|
||||
mctFileInput.link(mockScope, element, attrs, control);
|
||||
setTimeout(function () {
|
||||
init = true;
|
||||
}, 100);
|
||||
});
|
||||
|
||||
waitsFor(function () {
|
||||
return init;
|
||||
}, "File selection should have beeen simulated");
|
||||
});
|
||||
|
||||
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 () {
|
||||
expect(control.$setValidity.callCount).toBe(2);
|
||||
expect(control.$setValidity.argsForCall[0]).toEqual(
|
||||
['file-input', false]
|
||||
);
|
||||
expect(control.$setValidity.argsForCall[1]).toEqual(
|
||||
['file-input', true]
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
76
platform/import-export/bundle.js
Normal file
76
platform/import-export/bundle.js
Normal file
@ -0,0 +1,76 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global define*/
|
||||
|
||||
define([
|
||||
"./src/actions/ExportAsJSONAction",
|
||||
"./src/actions/ImportAsJSONAction"
|
||||
], function (
|
||||
ExportAsJSONAction,
|
||||
ImportAsJSONAction
|
||||
) {
|
||||
|
||||
return function ImportExportPlugin() {
|
||||
return function (openmct) {
|
||||
ExportAsJSONAction.appliesTo = function (context) {
|
||||
return 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-save",
|
||||
"depends": [
|
||||
"exportService",
|
||||
"policyService",
|
||||
"identifierService"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "import.JSON",
|
||||
"name": "Import from JSON",
|
||||
"implementation": ImportAsJSONAction,
|
||||
"category": "contextual",
|
||||
"cssClass": "icon-download",
|
||||
"depends": [
|
||||
"exportService",
|
||||
"identifierService",
|
||||
"dialogService",
|
||||
"openmct"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
openmct.legacyRegistry.enable('platform/import-export');
|
||||
};
|
||||
};
|
||||
});
|
162
platform/import-export/src/actions/ExportAsJSONAction.js
Normal file
162
platform/import-export/src/actions/ExportAsJSONAction.js
Normal file
@ -0,0 +1,162 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([], function () {
|
||||
|
||||
/**
|
||||
* 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(
|
||||
exportService,
|
||||
policyService,
|
||||
identifierService,
|
||||
context
|
||||
) {
|
||||
|
||||
this.root = {};
|
||||
this.tree = {};
|
||||
this.calls = 0;
|
||||
this.context = context;
|
||||
this.externalIdentifiers = [];
|
||||
this.exportService = exportService;
|
||||
this.policyService = policyService;
|
||||
this.identifierService = identifierService;
|
||||
}
|
||||
|
||||
ExportAsJSONAction.prototype.perform = function () {
|
||||
this.root = this.context.domainObject;
|
||||
this.tree[this.root.getId()] = this.root.getModel();
|
||||
this.saveAs = function (completedTree) {
|
||||
this.exportService.exportJSON(
|
||||
completedTree,
|
||||
{filename: this.root.getModel().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++;
|
||||
if (parent.hasCapability('composition')) {
|
||||
parent.useCapability('composition')
|
||||
.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 (!this.tree.hasOwnProperty(child.getId())) {
|
||||
// If object is a link to something absent from
|
||||
// tree, generate new id and treat as new object
|
||||
if (this.isExternal(child, parent)) {
|
||||
this.rewriteLink(child, parent);
|
||||
} else {
|
||||
this.tree[child.getId()] = child.getModel();
|
||||
}
|
||||
this.write(child);
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
this.calls--;
|
||||
if (this.calls === 0) {
|
||||
this.saveAs(this.wrapTree());
|
||||
}
|
||||
}.bind(this));
|
||||
} else {
|
||||
this.calls--;
|
||||
if (this.calls === 0) {
|
||||
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(child.getId());
|
||||
var parentModel = parent.getModel();
|
||||
var childModel = child.getModel();
|
||||
var index = parentModel.composition.indexOf(child.getId());
|
||||
var newModel = this.copyModel(childModel);
|
||||
var newId = this.identifierService.generate();
|
||||
|
||||
newModel.location = parent.getId();
|
||||
this.tree[newId] = newModel;
|
||||
this.tree[parent.getId()] = this.copyModel(parentModel);
|
||||
this.tree[parent.getId()].composition[index] = newId;
|
||||
};
|
||||
|
||||
ExportAsJSONAction.prototype.copyModel = function (model) {
|
||||
var jsonString = JSON.stringify(model);
|
||||
return JSON.parse(jsonString);
|
||||
};
|
||||
|
||||
ExportAsJSONAction.prototype.isExternal = function (child, parent) {
|
||||
if (child.getModel().location !== parent.getId() &&
|
||||
!Object.keys(this.tree).includes(child.getModel().location) &&
|
||||
child.getId() !== this.root.getId() ||
|
||||
this.externalIdentifiers.includes(child.getId())) {
|
||||
|
||||
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.root.getId()
|
||||
};
|
||||
};
|
||||
|
||||
ExportAsJSONAction.prototype.isCreatable = function (domainObject) {
|
||||
return this.policyService.allow(
|
||||
"creation",
|
||||
domainObject.getCapability("type")
|
||||
);
|
||||
};
|
||||
|
||||
return ExportAsJSONAction;
|
||||
});
|
175
platform/import-export/src/actions/ImportAsJSONAction.js
Normal file
175
platform/import-export/src/actions/ImportAsJSONAction.js
Normal file
@ -0,0 +1,175 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(['zepto'], function ($) {
|
||||
|
||||
/**
|
||||
* 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 tree = this.generateNewIdentifiers(objTree);
|
||||
var rootId = tree.rootId;
|
||||
var rootObj = this.instantiate(tree.openmct[rootId], rootId);
|
||||
|
||||
// Instantiate all objects in tree with their newly genereated 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);
|
||||
};
|
||||
|
||||
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, index) {
|
||||
if (!tree[childId] || seen.includes(childId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
newObj = this.instantiate(tree[childId], childId);
|
||||
parent.getCapability("composition").add(newObj);
|
||||
newObj.getCapability("location")
|
||||
.setPrimaryLocation(tree[childId].location);
|
||||
this.deepInstantiate(newObj, tree, seen);
|
||||
}, this);
|
||||
}
|
||||
};
|
||||
|
||||
ImportAsJSONAction.prototype.generateNewIdentifiers = function (tree) {
|
||||
// For each domain object in the file, generate new ID, replace in tree
|
||||
Object.keys(tree.openmct).forEach(function (domainObjectId) {
|
||||
var newId = this.identifierService.generate();
|
||||
tree = this.rewriteId(domainObjectId, newId, tree);
|
||||
}, this);
|
||||
return tree;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
tree = JSON.stringify(tree).replace(new RegExp(oldID, 'g'), newID);
|
||||
return JSON.parse(tree);
|
||||
};
|
||||
|
||||
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) {
|
||||
return context.domainObject !== undefined &&
|
||||
context.domainObject.hasCapability("composition");
|
||||
};
|
||||
|
||||
return ImportAsJSONAction;
|
||||
});
|
266
platform/import-export/test/actions/ExportAsJSONActionSpec.js
Normal file
266
platform/import-export/test/actions/ExportAsJSONActionSpec.js
Normal file
@ -0,0 +1,266 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[
|
||||
"../../src/actions/ExportAsJSONAction",
|
||||
"../../../entanglement/test/DomainObjectFactory"
|
||||
],
|
||||
function (ExportAsJSONAction, domainObjectFactory) {
|
||||
|
||||
describe("The export JSON action", function () {
|
||||
|
||||
var context,
|
||||
action,
|
||||
exportService,
|
||||
identifierService,
|
||||
policyService,
|
||||
mockType,
|
||||
exportedTree;
|
||||
|
||||
beforeEach(function () {
|
||||
exportService = jasmine.createSpyObj('exportService',
|
||||
['exportJSON']);
|
||||
identifierService = jasmine.createSpyObj('identifierService',
|
||||
['generate']);
|
||||
policyService = jasmine.createSpyObj('policyService',
|
||||
['allow']);
|
||||
mockType =
|
||||
jasmine.createSpyObj('type', ['hasFeature']);
|
||||
|
||||
mockType.hasFeature.andCallFake(function (feature) {
|
||||
return feature === 'creation';
|
||||
});
|
||||
context = {};
|
||||
context.domainObject = domainObjectFactory(
|
||||
{
|
||||
name: 'test',
|
||||
id: 'someID',
|
||||
capabilities: {type: mockType}
|
||||
});
|
||||
identifierService.generate.andReturn('brandNewId');
|
||||
exportService.exportJSON.andCallFake(function (tree, options) {
|
||||
exportedTree = tree;
|
||||
});
|
||||
policyService.allow.andCallFake(function (capability, type) {
|
||||
return type.hasFeature(capability);
|
||||
});
|
||||
|
||||
action = new ExportAsJSONAction(exportService, policyService,
|
||||
identifierService, context);
|
||||
});
|
||||
|
||||
it("initializes happily", function () {
|
||||
expect(action).toBeDefined();
|
||||
});
|
||||
|
||||
it("doesn't export non-creatable objects in tree", function () {
|
||||
var nonCreatableType = {
|
||||
hasFeature :
|
||||
function (feature) {
|
||||
return feature !== 'creation';
|
||||
}
|
||||
};
|
||||
|
||||
var parentComposition =
|
||||
jasmine.createSpyObj('parentComposition', ['invoke']);
|
||||
|
||||
var parent = domainObjectFactory({
|
||||
name: 'parent',
|
||||
model: { name: 'parent', location: 'ROOT'},
|
||||
id: 'parentId',
|
||||
capabilities: {
|
||||
composition: parentComposition,
|
||||
type: mockType
|
||||
}
|
||||
});
|
||||
|
||||
var child = domainObjectFactory({
|
||||
name: 'child',
|
||||
model: { name: 'child', location: 'parentId' },
|
||||
id: 'childId',
|
||||
capabilities: {
|
||||
type: nonCreatableType
|
||||
}
|
||||
});
|
||||
|
||||
parentComposition.invoke.andReturn(
|
||||
Promise.resolve([child])
|
||||
);
|
||||
context.domainObject = parent;
|
||||
|
||||
var init = false;
|
||||
runs(function () {
|
||||
action.perform();
|
||||
setTimeout(function () {
|
||||
init = true;
|
||||
}, 100);
|
||||
});
|
||||
|
||||
waitsFor(function () {
|
||||
return init;
|
||||
}, "Exported tree sohuld have been built");
|
||||
|
||||
runs(function () {
|
||||
expect(Object.keys(action.tree).length).toBe(1);
|
||||
expect(action.tree.hasOwnProperty("parentId"))
|
||||
.toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
it("can export self-containing objects", function () {
|
||||
var infiniteParentComposition =
|
||||
jasmine.createSpyObj('infiniteParentComposition',
|
||||
['invoke']
|
||||
);
|
||||
|
||||
var infiniteChildComposition =
|
||||
jasmine.createSpyObj('infiniteChildComposition',
|
||||
['invoke']
|
||||
);
|
||||
|
||||
var parent = domainObjectFactory({
|
||||
name: 'parent',
|
||||
model: { name: 'parent', location: 'ROOT'},
|
||||
id: 'infiniteParentId',
|
||||
capabilities: {
|
||||
composition: infiniteParentComposition,
|
||||
type: mockType
|
||||
}
|
||||
});
|
||||
|
||||
var child = domainObjectFactory({
|
||||
name: 'child',
|
||||
model: { name: 'child', location: 'infiniteParentId' },
|
||||
id: 'infiniteChildId',
|
||||
capabilities: {
|
||||
composition: infiniteChildComposition,
|
||||
type: mockType
|
||||
}
|
||||
});
|
||||
|
||||
infiniteParentComposition.invoke.andReturn(
|
||||
Promise.resolve([child])
|
||||
);
|
||||
infiniteChildComposition.invoke.andReturn(
|
||||
Promise.resolve([parent])
|
||||
);
|
||||
context.domainObject = parent;
|
||||
|
||||
var init = false;
|
||||
runs(function () {
|
||||
action.perform();
|
||||
setTimeout(function () {
|
||||
init = true;
|
||||
}, 100);
|
||||
});
|
||||
|
||||
waitsFor(function () {
|
||||
return init;
|
||||
}, "Exported tree sohuld have been built");
|
||||
|
||||
runs(function () {
|
||||
expect(Object.keys(action.tree).length).toBe(2);
|
||||
expect(action.tree.hasOwnProperty("infiniteParentId"))
|
||||
.toBeTruthy();
|
||||
expect(action.tree.hasOwnProperty("infiniteChildId"))
|
||||
.toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
it("exports links to external objects as new objects", function () {
|
||||
var externallyLinkedComposition =
|
||||
jasmine.createSpyObj('externallyLinkedComposition',
|
||||
['invoke']
|
||||
);
|
||||
|
||||
var parent = domainObjectFactory({
|
||||
name: 'parent',
|
||||
model: {
|
||||
name: 'parent',
|
||||
composition: ['externalId'],
|
||||
location: 'ROOT'},
|
||||
id: 'parentId',
|
||||
capabilities: {
|
||||
composition: externallyLinkedComposition,
|
||||
type: mockType
|
||||
}
|
||||
});
|
||||
|
||||
var externalObject = domainObjectFactory({
|
||||
name: 'external',
|
||||
model: { name: 'external', location: 'outsideOfTree'},
|
||||
id: 'externalId',
|
||||
capabilities: {
|
||||
type: mockType
|
||||
}
|
||||
});
|
||||
|
||||
externallyLinkedComposition.invoke.andReturn(
|
||||
Promise.resolve([externalObject])
|
||||
);
|
||||
context.domainObject = parent;
|
||||
|
||||
var init = false;
|
||||
runs(function () {
|
||||
action.perform();
|
||||
setTimeout(function () {
|
||||
init = true;
|
||||
}, 100);
|
||||
});
|
||||
|
||||
waitsFor(function () {
|
||||
return init;
|
||||
}, "Exported tree sohuld have been built");
|
||||
|
||||
runs(function () {
|
||||
expect(Object.keys(action.tree).length).toBe(2);
|
||||
expect(action.tree.hasOwnProperty('parentId'))
|
||||
.toBeTruthy();
|
||||
expect(action.tree.hasOwnProperty('brandNewId'))
|
||||
.toBeTruthy();
|
||||
expect(action.tree.brandNewId.location).toBe('parentId');
|
||||
});
|
||||
});
|
||||
|
||||
it("exports object tree in the correct format", function () {
|
||||
var init = false;
|
||||
runs(function () {
|
||||
action.perform();
|
||||
setTimeout(function () {
|
||||
init = true;
|
||||
}, 100);
|
||||
});
|
||||
|
||||
waitsFor(function () {
|
||||
return init;
|
||||
}, "Exported tree sohuld have been built");
|
||||
|
||||
runs(function () {
|
||||
expect(Object.keys(exportedTree).length).toBe(2);
|
||||
expect(exportedTree.hasOwnProperty('openmct')).toBeTruthy();
|
||||
expect(exportedTree.hasOwnProperty('rootId')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
240
platform/import-export/test/actions/ImportAsJSONActionSpec.js
Normal file
240
platform/import-export/test/actions/ImportAsJSONActionSpec.js
Normal file
@ -0,0 +1,240 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[
|
||||
"../../src/actions/ImportAsJSONAction",
|
||||
"../../../entanglement/test/DomainObjectFactory"
|
||||
],
|
||||
function (ImportAsJSONAction, domainObjectFactory) {
|
||||
|
||||
describe("The import JSON action", function () {
|
||||
|
||||
var context = {};
|
||||
var action,
|
||||
exportService,
|
||||
identifierService,
|
||||
dialogService,
|
||||
openmct,
|
||||
mockDialog,
|
||||
compositionCapability,
|
||||
mockInstantiate,
|
||||
uniqueId,
|
||||
newObjects;
|
||||
|
||||
|
||||
beforeEach(function () {
|
||||
|
||||
uniqueId = 0;
|
||||
newObjects = [];
|
||||
openmct = {
|
||||
$injector: jasmine.createSpyObj('$injector', ['get'])
|
||||
};
|
||||
mockInstantiate = jasmine.createSpy('instantiate').andCallFake(
|
||||
function (model, id) {
|
||||
var config = {
|
||||
"model": model,
|
||||
"id": id,
|
||||
"capabilities": {}
|
||||
};
|
||||
var locationCapability = {
|
||||
setPrimaryLocation: jasmine.createSpy
|
||||
('setPrimaryLocation').andCallFake(
|
||||
function (newLocation) {
|
||||
config.model.location = newLocation;
|
||||
}
|
||||
)
|
||||
};
|
||||
config.capabilities.location = locationCapability;
|
||||
if (model.composition) {
|
||||
var compCapability =
|
||||
jasmine.createSpy('compCapability')
|
||||
.andReturn(model.composition);
|
||||
compCapability.add = jasmine.createSpy('add')
|
||||
.andCallFake(function (newObj) {
|
||||
config.model.composition.push(newObj.getId());
|
||||
});
|
||||
config.capabilities.composition = compCapability;
|
||||
}
|
||||
newObjects.push(domainObjectFactory(config));
|
||||
return domainObjectFactory(config);
|
||||
});
|
||||
openmct.$injector.get.andReturn(mockInstantiate);
|
||||
dialogService = jasmine.createSpyObj('dialogService',
|
||||
[
|
||||
'getUserInput',
|
||||
'showBlockingMessage'
|
||||
]
|
||||
);
|
||||
identifierService = jasmine.createSpyObj('identifierService',
|
||||
[
|
||||
'generate'
|
||||
]
|
||||
);
|
||||
identifierService.generate.andCallFake(function () {
|
||||
uniqueId++;
|
||||
return uniqueId;
|
||||
});
|
||||
compositionCapability = jasmine.createSpy('compositionCapability');
|
||||
mockDialog = jasmine.createSpyObj("dialog", ["dismiss"]);
|
||||
dialogService.showBlockingMessage.andReturn(mockDialog);
|
||||
|
||||
action = new ImportAsJSONAction(exportService, identifierService,
|
||||
dialogService, openmct, context);
|
||||
});
|
||||
|
||||
it("initializes happily", function () {
|
||||
expect(action).toBeDefined();
|
||||
});
|
||||
|
||||
it("only applies to objects with composition capability", function () {
|
||||
var compDomainObject = domainObjectFactory({
|
||||
name: 'compObject',
|
||||
model: { name: 'compObject'},
|
||||
capabilities: {"composition": compositionCapability}
|
||||
});
|
||||
var noCompDomainObject = domainObjectFactory();
|
||||
|
||||
context.domainObject = compDomainObject;
|
||||
expect(ImportAsJSONAction.appliesTo(context)).toBe(true);
|
||||
context.domainObject = noCompDomainObject;
|
||||
expect(ImportAsJSONAction.appliesTo(context)).toBe(false);
|
||||
});
|
||||
|
||||
it("displays error dialog on invalid file choice", function () {
|
||||
dialogService.getUserInput.andReturn(Promise.resolve(
|
||||
{
|
||||
selectFile: {
|
||||
body: JSON.stringify({badKey: "INVALID"}),
|
||||
name: "fileName"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
var init = false;
|
||||
runs(function () {
|
||||
action.perform();
|
||||
setTimeout(function () {
|
||||
init = true;
|
||||
}, 100);
|
||||
});
|
||||
|
||||
waitsFor(function () {
|
||||
return init;
|
||||
}, "Promise containing file data should have resolved");
|
||||
|
||||
runs(function () {
|
||||
expect(dialogService.getUserInput).toHaveBeenCalled();
|
||||
expect(dialogService.showBlockingMessage).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it("can import self-containing objects", function () {
|
||||
dialogService.getUserInput.andReturn(Promise.resolve(
|
||||
{
|
||||
selectFile: {
|
||||
body: JSON.stringify({
|
||||
"openmct": {
|
||||
"infiniteParent": {
|
||||
"composition": ["infinteChild"],
|
||||
"name": "1",
|
||||
"type": "folder",
|
||||
"modified": 1503598129176,
|
||||
"location": "mine",
|
||||
"persisted": 1503598129176
|
||||
},
|
||||
"infinteChild": {
|
||||
"composition": ["infiniteParent"],
|
||||
"name": "2",
|
||||
"type": "folder",
|
||||
"modified": 1503598132428,
|
||||
"location": "infiniteParent",
|
||||
"persisted": 1503598132428
|
||||
}
|
||||
},
|
||||
"rootId": "infiniteParent"
|
||||
}),
|
||||
name: "fileName"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
var init = false;
|
||||
runs(function () {
|
||||
action.perform();
|
||||
setTimeout(function () {
|
||||
init = true;
|
||||
}, 100);
|
||||
});
|
||||
|
||||
waitsFor(function () {
|
||||
return init;
|
||||
}, "Promise containing file data should have resolved");
|
||||
|
||||
runs(function () {
|
||||
expect(mockInstantiate.calls.length).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
it("assigns new ids to each imported object", function () {
|
||||
dialogService.getUserInput.andReturn(Promise.resolve(
|
||||
{
|
||||
selectFile: {
|
||||
body: JSON.stringify({
|
||||
"openmct": {
|
||||
"cce9f107-5060-4f55-8151-a00120f4222f": {
|
||||
"composition": [],
|
||||
"name": "test",
|
||||
"type": "folder",
|
||||
"modified": 1503596596639,
|
||||
"location": "mine",
|
||||
"persisted": 1503596596639
|
||||
}
|
||||
},
|
||||
"rootId": "cce9f107-5060-4f55-8151-a00120f4222f"
|
||||
}),
|
||||
name: "fileName"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
var init = false;
|
||||
runs(function () {
|
||||
action.perform();
|
||||
setTimeout(function () {
|
||||
init = true;
|
||||
}, 100);
|
||||
});
|
||||
|
||||
waitsFor(function () {
|
||||
return init;
|
||||
}, "Promise containing file data should have resolved");
|
||||
|
||||
runs(function () {
|
||||
expect(mockInstantiate.calls.length).toEqual(1);
|
||||
expect(newObjects[0].getId()).toBe('1');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
@ -26,14 +26,16 @@ define([
|
||||
'../../example/generator/plugin',
|
||||
'../../platform/features/autoflow/plugin',
|
||||
'./timeConductor/plugin',
|
||||
'../../example/imagery/plugin'
|
||||
'../../example/imagery/plugin',
|
||||
'../../platform/import-export/bundle'
|
||||
], function (
|
||||
_,
|
||||
UTCTimeSystem,
|
||||
GeneratorPlugin,
|
||||
AutoflowPlugin,
|
||||
TimeConductorPlugin,
|
||||
ExampleImagery
|
||||
ExampleImagery,
|
||||
ImportExport
|
||||
) {
|
||||
var bundleMap = {
|
||||
CouchDB: 'platform/persistence/couch',
|
||||
@ -54,6 +56,8 @@ define([
|
||||
|
||||
plugins.UTCTimeSystem = UTCTimeSystem;
|
||||
|
||||
plugins.ImportExport = ImportExport;
|
||||
|
||||
/**
|
||||
* A tabular view showing the latest values of multiple telemetry points at
|
||||
* once. Formatted so that labels and values are aligned.
|
||||
|
Loading…
Reference in New Issue
Block a user